kriswiner / MPU9250

Arduino sketches for MPU9250 9DoF with AHRS sensor fusion
1.03k stars 471 forks source link

8 MPU9250 with I2C #186

Open MahmoudElgendy95 opened 6 years ago

MahmoudElgendy95 commented 6 years ago

hi, in my application i need to use 8 MPU9250 using I2c . I succeeded to connect to just 3 and get accurate readings from them , but when i tried to increase the number of sensors , i get wrong readings from all of them . so any advice to be able to connect the 8 together !

kriswiner commented 6 years ago

Likely the problem is the wire leads between the host MCU and MPU9250 are either too thin or too long to support I2C, which is relatively short range communication protocol.

On Wed, Sep 20, 2017 at 6:02 AM, mahmoudelgendy1995 < notifications@github.com> wrote:

hi, in my application i need to use 8 MPU9250 using I2c . I succeeded to connect to just 3 and get an accurate readings from them , but when i tried to increase the number of sensors , i get wrong readings from all of them . so any advice to be able to connect the 8 together !

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qnibgO_FT-4DpxqHu7MM7YC3qZv6ks5skQzxgaJpZM4Pd1UB .

MahmoudElgendy95 commented 6 years ago

after what long it will be considered too long for i2c bus ? and if the range is long do you think I2C multiplexer is the solution ?

kriswiner commented 6 years ago

12 inches should be fine, four feet not so much.

Use large diameter (small guage) copper wire. Might need to shield the wires with GND lines. twist SDL with VCC and twist SCL separately with GND, for example could help.

On Thu, Sep 21, 2017 at 11:51 AM, mahmoudelgendy1995 < notifications@github.com> wrote:

after what long it will be considered too long for i2c bus ? and if the range is long do you think I2C multiplexer is the solution ?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186#issuecomment-331248261, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qvuirpdX9hEG64X8FvcNxz5sT5XKks5skrBFgaJpZM4Pd1UB .

iiiBadgeriii commented 6 years ago

Hi Kris and mahmoudelgendy1995,

I am trying to do something similar here, but am unable to implement it into my code (I have read through the other issues but to no avail). Would either of you be able to share some code/explain in detail to help me?

Setup: 2 Sparkfun MPU9250s (SJ2 changed to allow AD0 to control the register from 0x68 to 0x69-verified for each IMU that this works) Teensy 3.5 (both IMUs connected to 18, 19), both connected to the same interrupt, AD0s connected to different digitalWrite pins to change HIGH/LOW separately)

Goal: multiplex 2 MPU9250s onto the same bus and Serialprint both sensor's yaw/pitch/roll outputs separately This will be used for a research project to determine angles of someone's wrist (not overly worried about yaw, but Pitch and Roll important)

Code Alterations to original Sketch: Below is to allow only one MPU to be read, and the logic for the next loop iteration. A1B0 is cast as boolean: At the beginning of Void loop(), { if(A1B0==true){ digitalWrite(adoPinA, LOW); digitalWrite(adoPinB, HIGH); A1B0 = false; } else { digitalWrite(adoPinA, HIGH); digitalWrite(adoPinB, LOW); A1B0 = true; } Below is to change what is defined for input into the filter: ` if(A1B0==true){ // Now we'll calculate the accleration value into actual g's ax = (float)MPU9250Data[0]aRes - accelBias[0]; // get actual g value, this depends on scale being set ay = (float)MPU9250Data[1]aRes - accelBias[1];
az = (float)MPU9250Data[2]*aRes - accelBias[2];

// readGyroData(gyroCount); // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second
gx = (float)MPU9250Data[4]*gRes;  // get actual gyro value, this depends on scale being set
gy = (float)MPU9250Data[5]*gRes;  
gz = (float)MPU9250Data[6]*gRes;   
}

else{
// Now we'll calculate the accleration value into actual g's
ax = (float)MPU9250Data[0]*aRes - accelBiasB[0];  // get actual g value, this depends on scale being set
ay = (float)MPU9250Data[1]*aRes - accelBiasB[1];   
az = (float)MPU9250Data[2]*aRes - accelBiasB[2];  

// readGyroData(gyroCount); // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second
gx = (float)MPU9250Data[4]*gRes;  // get actual gyro value, this depends on scale being set
gy = (float)MPU9250Data[5]*gRes;  
gz = (float)MPU9250Data[6]*gRes;   
}`

Below is to assign the values to separate variables to be printed `if (A1B0 == true) {

  pitch = -asinf(a32);

roll  = atan2f(a31, a33);

yaw   = atan2f(a12, a22);

pitch *= 180.0f / PI;

yaw   *= 180.0f / PI; 

yaw   += 2.7f; 

if(yaw < 0) yaw   += 360.0f; // Ensure yaw stays between 0 and 360

roll  *= 180.0f / PI;

}

else { pitchB = -asinf(a32);

rollB  = atan2f(a31, a33);

yawB   = atan2f(a12, a22);

pitchB *= 180.0f / PI;

yawB   *= 180.0f / PI; 

yawB   += 2.7f; /

if(yawB < 0) yawB   += 360.0f; // Ensure yaw stays between 0 and 360

rollB  *= 180.0f / PI;

}`

Then Print: if(SerialDebug) { Serial.print("YawA, PitchA, RollA: "); Serial.print(yaw, 2); Serial.print(", "); Serial.print(pitch, 2); Serial.print(", "); Serial.print(roll, 2); Serial.print("\t"); Serial.print("YawB, PitchB, RollB: "); Serial.print(yawB, 2); Serial.print(", "); Serial.print(pitchB, 2); Serial.print(", "); Serial.print(rollB, 2); Serial.print(", "); // Serial.print(digitalRead(adoPinA)); // Serial.print(", "); Serial.println(A1B0); I also copied the selfTest function and renamed it,, and changed all variables to have them store separately for both MPUs.

My thoughts: I think my error lies in using the same interrupt pin, and or not declaring a separate MPU9250Data for each separate MPU. Or honestly no idea my coding skills are limited. I'm not sure what to do next.

Any help would be greatly appreciated.

kriswiner commented 6 years ago

Where are you changing the MPU9250 address in the I2C read calls?

On Fri, Nov 17, 2017 at 10:02 AM, iiiBadgeriii notifications@github.com wrote:

Hi Kris and mahmoudelgendy1995,

I am trying to do something similar here, but am unable to implement it into my code (I have read through the other issues but to no avail). Would either of you be able to share some code/explain in detail to help me?

Setup: 2 Sparkfun MPU9250s (SJ2 changed to allow AD0 to control the register from 0x68 to 0x69-verified for each IMU that this works) Teensy 3.5 (both IMUs connected to 18, 19), both connected to the same interrupt, AD0s connected to different digitalWrite pins to change HIGH/LOW separately)

Goal: multiplex 2 MPU9250s onto the same bus and Serialprint both sensor's yaw/pitch/roll outputs separately This will be used for a research project to determine angles of someone's wrist (not overly worried about yaw, but Pitch and Roll important)

Code Alterations to original Sketch: Below is to allow only one MPU to be read, and the logic for the next loop iteration. A1B0 is cast as boolean: At the beginning of Void loop(), { if(A1B0==true){ digitalWrite(adoPinA, LOW); digitalWrite(adoPinB, HIGH); A1B0 = false; } else { digitalWrite(adoPinA, HIGH); digitalWrite(adoPinB, LOW); A1B0 = true; } Below is to change what is defined for input into the filter: ` if(A1B0==true){ // Now we'll calculate the accleration value into actual g's ax = (float)MPU9250Data[0]aRes - accelBias[0]; // get actual g value, this depends on scale being set ay = (float)MPU9250Data[1]aRes - accelBias[1]; az = (float)MPU9250Data[2]*aRes - accelBias[2];

// readGyroData(gyroCount); // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second gx = (float)MPU9250Data[4]gRes; // get actual gyro value, this depends on scale being set gy = (float)MPU9250Data[5]gRes; gz = (float)MPU9250Data[6]*gRes; }

else{ // Now we'll calculate the accleration value into actual g's ax = (float)MPU9250Data[0]aRes - accelBiasB[0]; // get actual g value, this depends on scale being set ay = (float)MPU9250Data[1]aRes - accelBiasB[1]; az = (float)MPU9250Data[2]*aRes - accelBiasB[2];

// readGyroData(gyroCount); // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second gx = (float)MPU9250Data[4]gRes; // get actual gyro value, this depends on scale being set gy = (float)MPU9250Data[5]gRes; gz = (float)MPU9250Data[6]*gRes; }`

Below is to assign the values to separate variables to be printed `if (A1B0 == true) {

pitch = -asinf(a32);

roll = atan2f(a31, a33);

yaw = atan2f(a12, a22);

pitch *= 180.0f / PI;

yaw *= 180.0f / PI;

yaw += 2.7f;

if(yaw < 0) yaw += 360.0f; // Ensure yaw stays between 0 and 360

roll *= 180.0f / PI;

}

else { pitchB = -asinf(a32);

rollB = atan2f(a31, a33);

yawB = atan2f(a12, a22);

pitchB *= 180.0f / PI;

yawB *= 180.0f / PI;

yawB += 2.7f; /

if(yawB < 0) yawB += 360.0f; // Ensure yaw stays between 0 and 360

rollB *= 180.0f / PI;

}`

Then Print: if(SerialDebug) { Serial.print("YawA, PitchA, RollA: "); Serial.print(yaw, 2); Serial.print(", "); Serial.print(pitch, 2); Serial.print(", "); Serial.print(roll, 2); Serial.print("\t"); Serial.print("YawB, PitchB, RollB: "); Serial.print(yawB, 2); Serial.print(", "); Serial.print(pitchB, 2); Serial.print(", "); Serial.print(rollB, 2); Serial.print(", "); // Serial.print(digitalRead(adoPinA)); // Serial.print(", "); Serial.println(A1B0); I also copied the selfTest function and renamed it,, and changed all variables to have them store separately for both MPUs.

My thoughts: I think my error lies in using the same interrupt pin, and or not declaring a separate MPU9250Data for each separate MPU. Or honestly no idea my coding skills are limited. I'm not sure what to do next.

Any help would be greatly appreciated.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186#issuecomment-345317930, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qlErFISfBLghmsAB6Xa0D3NhcBrNks5s3co-gaJpZM4Pd1UB .

iiiBadgeriii commented 6 years ago

Sorry if this isn't what you mean, but this is before void setup `#define ADO 0

if ADO

define MPU9250_ADDRESS 0x69 // Device address when ADO = 1

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

else

define MPU9250_ADDRESS 0x68 // Device address when ADO = 0

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

endif `

kriswiner commented 6 years ago

Not going to work then.

On Fri, Nov 17, 2017 at 10:28 AM, iiiBadgeriii notifications@github.com wrote:

Sorry if this isn't what you mean, but this is before void setup `#define ADO 0

if ADO

define MPU9250_ADDRESS 0x69 // Device address when ADO = 1

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

else

define MPU9250_ADDRESS 0x68 // Device address when ADO = 0

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

endif `

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186#issuecomment-345324311, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1quvuPVJStHWJjYtvIWNgSj9m3oJlks5s3dA8gaJpZM4Pd1UB .

iiiBadgeriii commented 6 years ago

Does it need to be moved inside of Void loop() ?

kriswiner commented 6 years ago

Need someway to change i2c adress, right?

On Fri, Nov 17, 2017 at 10:33 AM iiiBadgeriii notifications@github.com wrote:

Does it need to be moved inside of Void loop() ?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186#issuecomment-345325736, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qloO_WMwAdSrZuvmMVCcPhdQdWk6ks5s3dGLgaJpZM4Pd1UB .

iiiBadgeriii commented 6 years ago

So I guess I'm still at a loss of what to do. This is what I did and still not getting individual outputs. I removed "#define ADO 0;" and instead used int ADO = 0; Then I added this

void loop() { #if ADO #define MPU9250_ADDRESS 0x69 // Device address when ADO = 1 #define AK8963_ADDRESS 0x0C // Address of magnetometer #define MS5637_ADDRESS 0x76 // Address of altimeter #else #define MPU9250_ADDRESS 0x68 // Device address when ADO = 0 #define AK8963_ADDRESS 0x0C // Address of magnetometer #define MS5637_ADDRESS 0x76 // Address of altimeter #endif

if(ADO == 1){ digitalWrite(adoPinA, LOW); digitalWrite(adoPinB, HIGH); ADO = 0; } else { digitalWrite(adoPinA, HIGH); digitalWrite(adoPinB, LOW); ADO = 1; }

I verified? that I'm only reading one MPU at a time by byte q = readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250 Serial.print(digitalRead(adoPinA)); Serial.print(", "); Serial.print(digitalRead(adoPinB)); Serial.println(q, HEX);

This allows me to see that the different ADO pins are alternating, and always gettting a who am I of 71. When I unplug one of the MPUs, I get an alternating "71, FF, 71" both times and corresponding to either adoPinA or adoPinB respectively, depending on which one was removed. Putting either of the ADO pins directly to 3.3V also gives me this result.

Any other thoughts/hints/pointing out my naive erros on how to resolve this would be greatly appreciated.

kriswiner commented 6 years ago

This belongs outside of the main loop and setup:

if ADO

define MPU9250_ADDRESS 0x69 // Device address when ADO = 1

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

else

define MPU9250_ADDRESS 0x68 // Device address when ADO = 0

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

endif

defines don't change. How many MPU9250's do you have? Your code should do

this:

define MPU9250ADDRESS_1 0x68

define MPU9250ADDRESS_2 0x69

setup SPI initialize end setup

loop set ADO to read MPU9250ADDRESS_1 read MPU9250_1_data set ADO to read MPU9250ADDRESS_2 read MPU9250_2 data end loop

Is this really that hard?

On Fri, Nov 17, 2017 at 6:19 PM, iiiBadgeriii notifications@github.com wrote:

So I guess I'm still at a loss of what to do. This is what I did and still not getting individual outputs. I removed "#define ADO 0;" and instead used int ADO = 0; Then I added this

void loop() {

if ADO

define MPU9250_ADDRESS 0x69 // Device address when ADO = 1

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

else

define MPU9250_ADDRESS 0x68 // Device address when ADO = 0

define AK8963_ADDRESS 0x0C // Address of magnetometer

define MS5637_ADDRESS 0x76 // Address of altimeter

endif

if(ADO == 1){ digitalWrite(adoPinA, LOW); digitalWrite(adoPinB, HIGH); ADO = 0; } else { digitalWrite(adoPinA, HIGH); digitalWrite(adoPinB, LOW); ADO = 1; }

I verified? that I'm only reading one MPU at a time by byte q = readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250 Serial.print(digitalRead(adoPinA)); Serial.print(", "); Serial.print(digitalRead(adoPinB)); Serial.println(q, HEX);

This allows me to see that the different ADO pins are alternating, and always gettting a who am I of 71. When I unplug one of the MPUs, I get an alternating "71, FF, 71" both times and corresponding to either adoPinA or adoPinB respectively, depending on which one was removed.

Any other thoughts/hints/pointing out my naive erros on how to resolve this would be greatly appreciated.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/186#issuecomment-345411411, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qlaGLYoqn_THZt5e4-EsluV3og8aks5s3j61gaJpZM4Pd1UB .