Supplying MPU6050 data to a second Arduino using bluetooth module

Hi :slight_smile:

For a school project I am trying to do realtime gesture classification using an accelerometer and a number of example codes from Arduino and Processing.

All of the example codes work with the accelerometer directly attached to the laptop, so the values can be sent to processing and classified onthere. I want to make the part of the circuit that contains the accelerometer wireless. My plan is to have one Arduino plugged into the laptop with an RF module, and one separate Arduino attached as can be seen on the picture below, but with another RF module in order to make it wireless.

I want to then send the Accelerometer values to the Arduino that is plugged into the laptop so these values can be sent to processing and classified in real time over there.

The example code that I am using to map these values and send them to processing can be read below:

#include "MPU6050.h"
int sampleRate = 100; //samples per second
int sampleInterval = 1000000/sampleRate; //Inverse of SampleRate

long timer = micros(); //timer
MPU6050 imu;
int16_t ax, ay, az;

int ledOn = 0; //to control the LED.

void setup()
{
  Serial.begin(115200);
  Wire.begin();

  if (!imu.begin(AFS_2G, GFS_250DPS)) {
    Serial.println("MPU6050 is online...");
  }
  else {
    Serial.println("Failed to init MPU6050");
    while (true)
      ;
  }
  timer = micros();
}

void loop()
{
  if (micros() - timer >= sampleInterval) { //Timer: send sensor data in every 10ms
    timer = micros();
    if (imu.getAcc3Counts(&ax, &ay, &az)) {
      sendDataToProcessing('A', map(ax,-32768,32767,0,500));
      sendDataToProcessing('B', map(ay,-32768,32767,0,500));
      sendDataToProcessing('C', map(az,-32768,32767,0,500));
    }
  }
}

void sendDataToProcessing(char symbol, int data) {
  Serial.print(symbol);  // symbol prefix of data type
  Serial.println(data);  // the integer data with a carriage return
}

void getDataFromProcessing() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    if (inChar == 'a') { //when an 'a' charactor is received.
      ledOn = 1;
      digitalWrite(LED_BUILTIN, ledOn); //turn on the built in LED on Arduino Uno
    }
    if (inChar == 'b') { //when an 'b' charactor is received.
      ledOn = 0;
      digitalWrite(LED_BUILTIN, 0); //turn on the built in LED on Arduino Uno
    }
  }
}

The problem is that I do not know where to begin coding the transmission of the accelerometer values to the Arduino that is connected to the laptop, or whether this is even feasible, what part of the code should I keep connected to the accelerometer, and what part of the code should I keep connected to the laptop?

If anyone would be willing to help me out or knows interesting additional information or tutorials that would be great!

Thank you!

It is very simple to send data values from the accelerometer using the NRF24L01, but first you have to get all the project parts working individually, and make sure that you understand each part. One place to start would be the NRF24L01 tutorial on this web site.

It is not a good idea to arbitrarily map raw data before sending it to be processed.

I would recommend to use the HC-12 instead of the NRF24L01. It is much, much simpler to use.

I have followed the tutorial and I am now able to send messages from one Arduino to the other :slight_smile: and I will take a look at the HC-12, thank you!

What think I want to do is collect the raw accelerometer data, send it to the other Arduino and let that Arduino process the data so it can be used in the code I pasted in my post above.
The example code the teacher uses for the processing of the accelerometer data is the one below:

#define SMPLRT_DIV       0x19
#define CONFIG           0x1A
#define GYRO_CONFIG      0x1B
#define ACCEL_CONFIG     0x1C
#define I2C_MST_STATUS   0x36
#define INT_PIN_CFG      0x37
#define INT_ENABLE       0x38
#define INT_STATUS       0x3A
#define ACCEL_XOUT_H     0x3B
#define ACCEL_XOUT_L     0x3C
#define ACCEL_YOUT_H     0x3D
#define ACCEL_YOUT_L     0x3E
#define ACCEL_ZOUT_H     0x3F
#define ACCEL_ZOUT_L     0x40
#define GYRO_XOUT_H      0x43
#define GYRO_XOUT_L      0x44
#define GYRO_YOUT_H      0x45
#define GYRO_YOUT_L      0x46
#define GYRO_ZOUT_H      0x47
#define GYRO_ZOUT_L      0x48
#define PWR_MGMT_1       0x6B // Device defaults to the SLEEP mode
#define PWR_MGMT_2       0x6C
#define WHO_AM_I_MPU6050 0x75 // Should return 0x68

MPU6050::MPU6050(uint8_t address)
{
    _address = address;
}

int MPU6050::begin(mpu_accel_range arange, mpu_gyro_range grange)
{  
    uint8_t c = MPU6050::readByte(WHO_AM_I_MPU6050);  // Read WHO_AM_I register for MPU-6050

    if (c != 0x68) // WHO_AM_I should always be 0x68
        return -1;

    // get stable time source
    writeByte(PWR_MGMT_1, 0x01);  // Set clock source to be PLL with x-axis gyroscope reference, bits 2:0 = 001

    // Configure Gyro and Accelerometer
    // Disable FSYNC and set accelerometer and gyro bandwidth to 44 and 42 Hz, respectively; 
    // DLPF_CFG = bits 2:0 = 010; this sets the sample rate at 1 kHz for both
    writeByte(CONFIG, 0x03);  

    // Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
    writeByte(SMPLRT_DIV, 0x04);  // Use a 200 Hz sample rate 

    // Set gyroscope full scale range
    // Range selects FS_SEL and AFS_SEL are 0 - 3, so 2-bit values are left-shifted into positions 4:3
    c =  readByte(GYRO_CONFIG);
    writeByte(GYRO_CONFIG, c & ~0xE0); // Clear self-test bits [7:5] 
    writeByte(GYRO_CONFIG, c & ~0x18); // Clear AFS bits [4:3]
    writeByte(GYRO_CONFIG, c | grange << 3); // Set full scale range for the gyro

    // Set accelerometer configuration
    c =  readByte(ACCEL_CONFIG);
    writeByte(ACCEL_CONFIG, c & ~0xE0); // Clear self-test bits [7:5] 
    writeByte(ACCEL_CONFIG, c & ~0x18); // Clear AFS bits [4:3]
    writeByte(ACCEL_CONFIG, c | arange << 3); // Set full scale range for the accelerometer 
    // Configure Interrupts and Bypass Enable
    // Set interrupt pin active high, push-pull, and clear on read of INT_STATUS, enable I2C_BYPASS_EN so additional chips 
    // can join the I2C bus and all can be controlled by the Arduino as master
    writeByte(INT_PIN_CFG, 0x02);    
    writeByte(INT_ENABLE, 0x01);  // Enable data ready (bit 0) interrupt

    // Success!
    return 0;
}

bool MPU6050::getMotion6Counts(int16_t * ax, int16_t * ay, int16_t * az, int16_t * gx, int16_t * gy, int16_t * gz)
{
    // If data ready bit set, all data registers have new data
    if (readByte(INT_STATUS) & 0x01) {  // check if data ready interrupt

        readAccelData(ax, ay, az);  // Read the x/y/z adc values
        readGyroData(gx, gy, gz);  // Read the x/y/z adc values

        return true;
    } 

    return false;
}

bool MPU6050::getAcc3Counts(int16_t * ax, int16_t * ay, int16_t * az)
{
    // If data ready bit set, all data registers have new data
    if (readByte(INT_STATUS) & 0x01) {  // check if data ready interrupt

        readAccelData(ax, ay, az);  // Read the x/y/z adc values
        return true;
    } 

    return false;
}

bool MPU6050::getGyro3Counts(int16_t * gx, int16_t * gy, int16_t * gz)
{
    // If data ready bit set, all data registers have new data
    if (readByte(INT_STATUS) & 0x01) {  // check if data ready interrupt

        readGyroData(gx, gy, gz);  // Read the x/y/z adc values
        return true;
    } 

    return false;
}

void MPU6050::readAccelData(int16_t * ax, int16_t * ay, int16_t *az)
{
    uint8_t rawData[6];  // x/y/z accel register data stored here
    readBytes(ACCEL_XOUT_H, 6, &rawData[0]);  // Read the six raw data registers into data array
    *ax = (int16_t)((rawData[0] << 8) | rawData[1]) ;  // Turn the MSB and LSB into a signed 16-bit value
    *ay = (int16_t)((rawData[2] << 8) | rawData[3]) ;  
    *az = (int16_t)((rawData[4] << 8) | rawData[5]) ; 
}

void MPU6050::readGyroData(int16_t * gx, int16_t * gy, int16_t * gz)
{
    uint8_t rawData[6];  // x/y/z gyro register data stored here
    readBytes(GYRO_XOUT_H, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
    *gx = (int16_t)((rawData[0] << 8) | rawData[1]) ;  // Turn the MSB and LSB into a signed 16-bit value
    *gy = (int16_t)((rawData[2] << 8) | rawData[3]) ;  
    *gz = (int16_t)((rawData[4] << 8) | rawData[5]) ; 
}

void MPU6050::writeByte(uint8_t subAddress, uint8_t data)
{
    Wire.beginTransmission(_address);  // Initialize the Tx buffer
    Wire.write(subAddress);           // Put slave register address in Tx buffer
    Wire.write(data);                 // Put data in Tx buffer
    Wire.endTransmission();           // Send the Tx buffer
}

uint8_t MPU6050::readByte(uint8_t subAddress)
{
    uint8_t byte;
    readBytes(subAddress, 1, &byte);
    return byte;
}

void MPU6050::readBytes(uint8_t subAddress, uint8_t count, uint8_t * dest)
{  
    Wire.beginTransmission(_address);   // Initialize the Tx buffer
    Wire.write(subAddress);             // Put slave register address in Tx buffer
    Wire.endTransmission(false);        // Send the Tx buffer, but send a restart to keep connection alive
    uint8_t i = 0;
    Wire.requestFrom(_address, count);  // Read bytes from slave register address 
    while (Wire.available()) {
        dest[i++] = Wire.read();        // Put read results in the Rx buffer
    }
}

The problem is that the comments don't make much sense to me. I want to keep the whole code locally on the Arduino that is connected to the laptop (since this seems easiest to me), and to have only the data collection happening on a separate Arduino. I am trying to find out which part of the code(s) above I should put on the Arduino connected to the accelerometer in order to properly send the raw accelerometer data to the other Arduino that will further process it. Do you know if there is a way to do this?

That is unnecessarily complex code. This is all you need to collect the raw data from the MPU-6050.

// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(115200);
}

void loop() {
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14); // request a total of 14 registers
  int16_t t = Wire.read();
  AcX = (t << 8) | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  t = Wire.read();
  AcY = (t << 8) | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  t = Wire.read();
  AcZ = (t << 8) | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  t = Wire.read();
  Tmp = (t << 8) | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  t = Wire.read();
  GyX = (t << 8) | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  t = Wire.read();
  GyY = (t << 8) | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  t = Wire.read();
  GyZ = (t << 8) | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  t = Wire.read();
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

The code you replied does indeed seem to work well too.
I have now deleted the accelerometer code that was originally in the file (the code in post # 3), and I am now trying to work the code that you sent into the other code (the code that was sent in post # 1). When I did this I got the following code:

#include "MPU6050.h"
int sampleRate = 100; //samples per second
int sampleInterval = 1000000/sampleRate; //Inverse of SampleRate

long timer = micros(); //timer
MPU6050 imu;
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t ax, ay, az;

int ledOn = 0; //to control the LED.

void setup()
{
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(115200);
  timer = micros();
}

void loop()
{

  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14); // request a total of 14 registers
  int16_t t = Wire.read();
  ax = (t << 8) | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  t = Wire.read();
  ay = (t << 8) | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  t = Wire.read();
  az = (t << 8) | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  t = Wire.read();
  //Tmp = (t << 8) | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  //t = Wire.read();
//  GyX = (t << 8) | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
//  t = Wire.read();
//  GyY = (t << 8) | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
//  t = Wire.read();
//  GyZ = (t << 8) | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
//  t = Wire.read();
  Serial.print("ax = "); Serial.print(ax);
  Serial.print(" | ay = "); Serial.print(ay);
  Serial.print(" | az = "); Serial.print(az);
  //Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); //equation for temperature in degrees C from datasheet
//  Serial.print(" | GyX = "); Serial.print(GyX);
//  Serial.print(" | GyY = "); Serial.print(GyY);
//  Serial.print(" | GyZ = "); Serial.println(GyZ);
//  delay(333);

  if (micros() - timer >= sampleInterval) { //Timer: send sensor data in every 10ms
    timer = micros();
    if (imu.getAcc3Counts(&ax, &ay, &az)) {
      sendDataToProcessing('A', map(ax,-32768,32767,0,500));
      sendDataToProcessing('B', map(ay,-32768,32767,0,500));
      sendDataToProcessing('C', map(az,-32768,32767,0,500));
    }
  }
}

void sendDataToProcessing(char symbol, int data) {
  Serial.print(symbol);  // symbol prefix of data type
  Serial.println(data);  // the integer data with a carriage return
}

void getDataFromProcessing() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    if (inChar == 'a') { //when an 'a' charactor is received.
      ledOn = 1;
      digitalWrite(LED_BUILTIN, ledOn); //turn on the built in LED on Arduino Uno
    }
    if (inChar == 'b') { //when an 'b' charactor is received.
      ledOn = 0;
      digitalWrite(LED_BUILTIN, 0); //turn on the built in LED on Arduino Uno
    }
  }
}

Once I compile I get the error below, which I do not know how to solve, maybe I'm missing something.

/var/folders/w6/tm197zkn4yqfzxpb90cvdpdh0000gn/T//cceI0ix2.ltrans0.ltrans.o: In function global constructors keyed to 65535_0_L3_a2_2d_SerialRxTx_MPU6050.ino.cpp.o.1949': <artificial>:(.text.startup+0x96): undefined reference to MPU6050::MPU6050(unsigned char)'
/var/folders/w6/tm197zkn4yqfzxpb90cvdpdh0000gn/T//cceI0ix2.ltrans0.ltrans.o: In function `loop':

/Users/X/L3_a2_2d_SerialRxTx_MPU6050.ino:56: undefined reference to `MPU6050::getAcc3Counts(int*, int*, int*)'
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Uno.

Do you know what problem this error addresses and whether it is solvable?

The code is still trying to use the MPU6050 library, which is no longer needed.

Get rid of these lines:

#include "MPU6050.h"

MPU6050 imu;

    if (imu.getAcc3Counts(&ax, &ay, &az)) {

and fix unbalanced braces.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.