Go Down

Topic: How to use I2C to call accelerometer data from 2 Grove IMU 9DoF v2.0 Sensors? (Read 346 times) previous topic - next topic

ChrisSimons

Hi all,

I'm currently working on a project to calculate and output the angle made at the knee by the upper and lower leg. I am doing this by using Grove IMU 9Dof v2.0 sensors (library here: https://raw.githubusercontent.com/SeeedDocument/Grove-IMU_9DOF_v2.0/master/res/Grove_IMU_9DOF_9250.zip ) one on the thigh and one on the shin and using the angles created between the sensor and the vertical axis to calculate the angle of each limb.

I currently have data outputting from 1 sensor, but I'm unsure how to get data from both simultaneously. I have no experience with I2C before and dont know how to code the 2 different sensors.

Below is the code I currently have, which reads data from only 1 sensor.

I used the example code that came with the library so there may be redundent parts of the code.

I really have 2 questions, how to alter this code to allow for reading from 2 sensors (addresses of 0x68 and 0x69), and how to change the code to get rid of extra variables that aren't used.

Any help or advice would be greatly appreciated!

Code: [Select]
#include "Wire.h"
#include "Math.h"
#include "I2Cdev.h"
#include "MPU9250.h"

MPU9250 accelgyro;
I2Cdev I2C_M;

uint8_t buffer_m[6];

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];
float angle[3];

//#define sample_num_mdate  5000

void setup() {
  // join I2C bus
  Wire.begin();
  // initialise serial communication
  // 38400 chosen for high baud rate
  Serial.begin(38400);
  accelgyro.initialize();
}

void loop()
{
 getAccel_Data();
 getAngle();
 Serial.println(angle[1]);
 delay(50);
}

void getAccel_Data(void)
{
  accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
  Axyz[1] = (double) ay / 16384;
}

void getAngle(void)
{
  getAccel_Data();
  float angley = acos(Axyz[1]/1);
  angle[1] = (double) 180 * angley / PI;
}

PaulS

If you have more than one I2C device, you need to change the I2C address of one of them. Does the MPU9050 allow you to do that? If so, have you done that? If you have, then you need to create an instance of the MPU9050 with a different constructor, where you can define the address to use.
The art of getting good answers lies in asking good questions.

jremington

Quote
I'm unsure how to get data from both simultaneously
You can't. You have to read one sensor, then the other.

You will have to change the I2C device address of one of the sensors. To do that, connect the module AD0 pin to 3.3V, and that device will respond to address 0x69.

ChrisSimons

I have changed the address of one by soldering a conection to change it as instructed the way I currently have the sensors wired as follows SCL to A5, SDA to A4, GND to GND and VCC to 3.3V. I should point out I am using the Arduino Nano board.

you need to create an instance of the MPU9050 with a different constructor, where you can define the address to use.
How do I do this?

PaulS

Quote
How do I do this?
Beats me. You didn't post a link to the library you are using, so I can't tell you how to use it.
The art of getting good answers lies in asking good questions.

ChrisSimons

Apologies I thought I had, here are the links to where I got the library from

http://wiki.seeedstudio.com/Grove-IMU_9DOF_v2.0/

https://raw.githubusercontent.com/SeeedDocument/Grove-IMU_9DOF_v2.0/master/res/Grove_IMU_9DOF_9250.zip


PaulS

Code: [Select]
class MPU9250 {
    public:
        MPU9250();
        MPU9250(uint8_t address);

There are two constructors. To use the default address,

Code: [Select]
   MPU9050 defaultAddress;

To use an alternate address:

Code: [Select]
   MPU9050 otherAddress(theOtherAddress);

Then, call initialize() on both instances. To read from either one, use getMotion9() on the appropriate instance.
The art of getting good answers lies in asking good questions.

ChrisSimons

I believe the addresses work because I got no error messages for those, thank you for that!
I don't think I've done the rest of it right though, I have the initialize as:
Code: [Select]

initialize(0x69);
initialize(0x68);


I also tried
Code: [Select]
int(0x69);

I tried google and the search function on this forum to find an answer but I don't really know what to search to find the right answer and couldn't find anything about initialize().
I got the following error messages if they are helpful.

Code: [Select]

Arduino: 1.8.9 (Windows Store 1.8.21.0) (Windows 10), Board: "Arduino Nano, ATmega328P"

Sensor_sketch_5:9:11: error: expected constructor, destructor, or type conversion before '(' token

initialize(0x69);

          ^

Sensor_sketch_5:10:11: error: expected constructor, destructor, or type conversion before '(' token

initialize(0x68);

          ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAccel_Data()':

Sensor_sketch_5:50:28: error: no matching function for call to 'MPU9250::getMotion9(int)'

  accelgyro.getMotion9(0x69);

                           ^

In file included from D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:4:0:

D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250/MPU9250.h:586:14: note: candidate: void MPU9250::getMotion9(int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*)

        void getMotion9(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz, int16_t* mx, int16_t* my, int16_t* mz);

             ^

D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250/MPU9250.h:586:14: note:   candidate expects 9 arguments, 1 provided

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAccel_Data()':

Sensor_sketch_5:54:6: error: redefinition of 'void getAccel_Data()'

void getAccel_Data(void)//0x68

     ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:48:6: note: 'void getAccel_Data()' previously defined here

void getAccel_Data(void)//0x69

     ^

Sensor_sketch_5:56:28: error: no matching function for call to 'MPU9250::getMotion9(int)'

  accelgyro.getMotion9(0x68);

                           ^

In file included from D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:4:0:

D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250/MPU9250.h:586:14: note: candidate: void MPU9250::getMotion9(int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*, int16_t*)

        void getMotion9(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz, int16_t* mx, int16_t* my, int16_t* mz);

             ^

D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250/MPU9250.h:586:14: note:   candidate expects 9 arguments, 1 provided

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAngle()':

Sensor_sketch_5:61:21: error: too many arguments to function 'void getAccel_Data()'

  getAccel_Data(0x69);

                    ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:48:6: note: declared here

void getAccel_Data(void)//0x69

     ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAngle()':

Sensor_sketch_5:66:6: error: redefinition of 'void getAngle()'

void getAngle(void) //0x68

     ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:59:6: note: 'void getAngle()' previously defined here

void getAngle(void) //0x69

     ^

Sensor_sketch_5:68:21: error: too many arguments to function 'void getAccel_Data()'

  getAccel_Data(0x68);

                    ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:48:6: note: declared here

void getAccel_Data(void)//0x69

     ^

Using library Wire at version 1.0 in folder: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.21.0_x86__mdqgnx93n4wtt\hardware\arduino\avr\libraries\Wire
Using library Grove_IMU_9DOF_9250 in folder: D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250 (legacy)
exit status 1
expected constructor, destructor, or type conversion before '(' token

PaulS

Quote
I don't think I've done that right
initialize() does not take an address. The instance KNOWS the address, if you have defined the instances correctly.

If you have two sensors, with addresses 0x68 (the default address) and 0x69, you should have:

Code: [Select]
MPU9050 One;
MPU9050 Two(0x69);

.
.
.

   One.initialize();
   Two.initialize();

.
.
.

   One.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

   // Use the data from One

   Two.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

   // Use the data from Two
The art of getting good answers lies in asking good questions.

ChrisSimons

I copied that formatting
Code: [Select]
MPU9250 One;
MPU9250 Two(0x69);

One.initialize();
Two.initialize();

but got the following error message

Code: [Select]
Sensor_sketch_5:9:1: error: 'One' does not name a type

 One.initialize();

 ^

Sensor_sketch_5:10:1: error: 'Two' does not name a type

 Two.initialize();


I couldn't really understand the solutions I found online

jremington


ChrisSimons

Apologies for the delay,

Here is the code in its current state
Code: [Select]

#include "Wire.h"
#include "Math.h"
#include "I2Cdev.h"
#include "MPU9250.h"

MPU9250 One;
MPU9250 Two(0x69);

One.initialize();
Two.initialize();

MPU9250 accelgyro;
I2Cdev I2C_M;

uint8_t buffer_m[6];

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];
float angle[3];

//#define sample_num_mdate  5000

void setup() {
  // join I2C bus
  Wire.begin();
  // initialise serial communication
  // 38400 chosen for high baud rate
  Serial.begin(38400);
  accelgyro.initialize();
}

void loop()
{
 getAccel_Data();
 getAngle();
 Serial.println(angle[1]);
 delay(50);
}

void One.getAccel_Data(void)//0x68
{
  One.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

   // Use the data from One

  Axyz[1] = (double) ay / 16384;
}

void Two.getAccel_Data(void)//0x69
{
  Two.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
  Axyz[1] = (double) ay / 16384;
}
void getAngle(void) //0x69
{
  One.getAccel_Data();
  float angley = acos(Axyz[1]/1);
  angle[1] = (double) 180 * angley / PI;
}

void getAngle(void) //0x68
{
  Two.getAccel_Data();
  float angley = acos(Axyz[1]/1);
  angle[1] = (double) 180 * angley / PI;
}


and here are the error messages

Code: [Select]


 One.initialize();

 ^

Sensor_sketch_5:10:1: error: 'Two' does not name a type

 Two.initialize();

 ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void loop()':

Sensor_sketch_5:42:16: error: 'getAccel_Data' was not declared in this scope

  getAccel_Data();

                ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: At global scope:

Sensor_sketch_5:48:9: error: expected initializer before '.' token

 void One.getAccel_Data(void)//0x68

         ^

Sensor_sketch_5:57:9: error: expected initializer before '.' token

 void Two.getAccel_Data(void)//0x69

         ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAngle()':

Sensor_sketch_5:64:7: error: 'class MPU9250' has no member named 'getAccel_Data'

   One.getAccel_Data();

       ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: In function 'void getAngle()':

Sensor_sketch_5:69:6: error: redefinition of 'void getAngle()'

 void getAngle(void) //0x68

      ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino:62:6: note: 'void getAngle()' previously defined here

 void getAngle(void) //0x69

      ^

Sensor_sketch_5:71:7: error: 'class MPU9250' has no member named 'getAccel_Data'

   Two.getAccel_Data();

       ^

Using library Wire at version 1.0 in folder: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.21.0_x86__mdqgnx93n4wtt\hardware\arduino\avr\libraries\Wire
Using library Grove_IMU_9DOF_9250 in folder: D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250 (legacy)
exit status 1
'One' does not name a type


jremington

Put these in setup()
Code: [Select]

One.initialize();
Two.initialize();


Remove this line, and remove the corresponding initialize() in setup()
Code: [Select]
MPU9250 accelgyro;
Code: [Select]
  accelgyro.initialize();

ChrisSimons

That seemed to fix the initialization part, thank you for that.

I'm still having errors with the looped part of the code however, code:

Code: [Select]


void setup()
{
  One.initialize();
  Two.initialize();
  
  // join I2C bus
  Wire.begin();
  // initialise serial communication
  // 38400 chosen for high baud rate
  Serial.begin(38400);
}

void loop()
{
 One.getAccel_Data();
 Two.getAccel_Data();
 getAngle();
 Serial.println(angle[1]);
 delay(50);
}

void One.getAccel_Data(void)//0x68
{
  One.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

   // Use the data from One

  Axyz[1] = (double) ay / 16384;
}

void Two.getAccel_Data(void)//0x69
{
  Two.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
  Axyz[1] = (double) ay / 16384;
}
void One.getAngle(void) //0x68
{
  One.getAccel_Data();
  float angley = acos(Axyz[1]/1);
  angle[1] = (double) 180 * angley / PI;
}

void Two.getAngle(void) //0x69
{
  Two.getAccel_Data();
  float angley = acos(Axyz[1]/1);
  angle[1] = (double) 180 * angley / PI;
}


and errors

Code: [Select]


Sensor_sketch_5:41:6: error: 'class MPU9250' has no member named 'getAccel_Data'

  One.getAccel_Data();

      ^

Sensor_sketch_5:42:6: error: 'class MPU9250' has no member named 'getAccel_Data'

  Two.getAccel_Data();

      ^

Sensor_sketch_5:43:11: error: 'getAngle' was not declared in this scope

  getAngle();

           ^

D:\Chris\Documents\Arduino\Sensor_sketch_5\Sensor_sketch_5.ino: At global scope:

Sensor_sketch_5:48:9: error: expected initializer before '.' token

 void One.getAccel_Data(void)//0x68

         ^

Sensor_sketch_5:57:9: error: expected initializer before '.' token

 void Two.getAccel_Data(void)//0x69

         ^

Sensor_sketch_5:62:9: error: expected initializer before '.' token

 void One.getAngle(void) //0x68

         ^

Sensor_sketch_5:69:9: error: expected initializer before '.' token

 void Two.getAngle(void) //0x69

         ^

Using library Wire at version 1.0 in folder: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.21.0_x86__mdqgnx93n4wtt\hardware\arduino\avr\libraries\Wire
Using library Grove_IMU_9DOF_9250 in folder: D:\Chris\Documents\Arduino\libraries\Grove_IMU_9DOF_9250 (legacy)
exit status 1
'class MPU9250' has no member named 'getAccel_Data'



jremington

The error message is self explanatory.

Check which function calls are available in the library you included. getAccel_Data is not one of them.

Go Up