kriswiner / MPU9250

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

reading data from magnatometer from two MPU9250 #205

Open munirfarzeen opened 6 years ago

munirfarzeen commented 6 years ago

hi, im trying to to connect two MPU9250 to ardinuo. I have been successfully been able to connect the both imu. But im having trouble accessing the magnetometer reading from the imu. Im confuse how to acesss the device and than mag register. it has address 0x0c below is the code. ` Wire.begin(); Serial.begin(38400); pinMode(intPin, INPUT); digitalWrite(intPin, LOW); pinMode(myLed, OUTPUT); digitalWrite(myLed, HIGH);

// Read the WHO_AM_I register, this is a good test of communication 
byte c1 = readByte(address_1, WHO_AM_I_MPU9250);  // Read WHO_AM_I register for MPU-9250

Serial.print("MPU9250 one "); Serial.print("I AM "); Serial.print(c1, HEX); Serial.print(" I should be "); Serial.println(0x71, HEX); delay(1000);

if (c1 == 0x71) // WHO_AM_I should always be 0x68

{
Serial.println("MPU9250 one is online...");

    MPU9250SelfTest(address_1,SelfTest1); // Start by performing self test and reporting values
    Serial.print("x-axis self test: acceleration trim within : "); Serial.print(SelfTest1[0],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: acceleration trim within : "); Serial.print(SelfTest1[1],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: acceleration trim within : "); Serial.print(SelfTest1[2],1); Serial.println("% of factory value");
    Serial.print("x-axis self test: gyration trim within : "); Serial.print(SelfTest1[3],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: gyration trim within : "); Serial.print(SelfTest1[4],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: gyration trim within : "); Serial.print(SelfTest1[5],1); Serial.println("% of factory value");

} else { Serial.print("Could not connect to MPU9250 one: 0x"); Serial.println(c1, HEX); while(1) ; // Loop forever if communication doesn't happen } calibrateMPU9250(address_1,gyroBias_1, accelBias_1); // Calibrate gyro and accelerometers, load biases in bias registers delay(1000); initMPU9250(address_1); Serial.println("MPU9250 one initialized for active data mode...."); // Initialize device for active mode read of acclerometer, gyroscope, and temperature

// Read the WHO_AM_I register of the magnetometer, this is a good test of communication byte d = readByte(AK8963_ADDRESS, AK8963_WHO_AM_I); // Read WHO_AM_I register for AK8963 Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX); Serial.print(" I should be "); Serial.println(0x48, HEX); delay(1000);
initAK8963(address_1,magCalibration_1); Serial.println("AK8963 initialized for active data mode...."); // Serial.println(magCalibration_1[0]); Serial.println(","); Serial.println(magCalibration_1[1]); Serial.println(","); Serial.println(magCalibration_1[2]); getMres(); byte c2 = readByte(address_2, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250 Serial.print("MPU9250 TWO "); Serial.print("I AM "); Serial.print(c2, HEX); Serial.print(" I should be "); Serial.println(0x71, HEX); delay(1000);

if (c2 == 0x71) // WHO_AM_I should always be 0x68

{
Serial.println("MPU9250 two is online...");

    MPU9250SelfTest(address_2,SelfTest2); // Start by performing self test and reporting values
    Serial.print("x-axis self test: acceleration trim within : "); Serial.print(SelfTest2[0],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: acceleration trim within : "); Serial.print(SelfTest2[1],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: acceleration trim within : "); Serial.print(SelfTest2[2],1); Serial.println("% of factory value");
    Serial.print("x-axis self test: gyration trim within : "); Serial.print(SelfTest2[3],1); Serial.println("% of factory value");
    Serial.print("y-axis self test: gyration trim within : "); Serial.print(SelfTest2[4],1); Serial.println("% of factory value");
    Serial.print("z-axis self test: gyration trim within : "); Serial.print(SelfTest2[5],1); Serial.println("% of factory value");

} else { Serial.print("Could not connect to MPU9250 two: 0x"); Serial.println(c2, HEX); while(1) ; // Loop forever if communication doesn't happen }

calibrateMPU9250(address_2,gyroBias_2, accelBias_2); // Calibrate gyro and accelerometers, load biases in bias registers
delay(1000); 

// uncomment for calibration of magnetometer
 //  magcalMPU9250(magbias_1, magScale_1);
   //Serial.println("AK8963 mag biases (mG)"); Serial.println(magbias[0]); Serial.println(magbias[1]); Serial.println(magbias[2]); 
   //Serial.println("AK8963 mag scale (mG)"); Serial.println(magScale[0]); Serial.println(magScale[1]); Serial.println(magScale[2]); 
   //delay(2000); // add delay to see results before serial spew of dat
 initMPU9250(address_2); 

Serial.println("MPU9250 two initialized for active data mode...."); // Initialize device for active mode read of acclerometer, gyroscope, and temperature byte d1 = readByte(AK8963_ADDRESS, AK8963_WHO_AM_I); // Read WHO_AM_I register for AK8963 Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX); Serial.print(" I should be "); Serial.println(0x48, HEX); delay(1000);
initAK8963(address_2,magCalibration_2); Serial.println("AK8963 initialized for active data mode...."); // Serial.println(magCalibration_2[0]); Serial.println(","); Serial.println(magCalibration_2[1]); Serial.println(","); Serial.println(magCalibration_2[2]); getMres(); // uncomment for calibration of magnetometer // magcalMPU9250(magbias_2, magScale_2); //Serial.println("AK8963 mag biases (mG)"); Serial.println(magbias_2[0]); Serial.println(magbias_2[1]); Serial.println(magbias_2[2]); //Serial.println("AK8963 mag scale (mG)"); Serial.println(magScale_2[0]); Serial.println(magScale_2[1]); Serial.println(magScale_2[2]); //delay(2000); // add delay to see results before serial spew of dat delay(1000);

}`

kriswiner commented 6 years ago

enable 0x68 pass through disable 0x69 pass throough read 0x68 and 0x0c

disable 0x68 pass through enable 0x69 passthrough read 0x69 and 0x0c

On Mon, Nov 13, 2017 at 11:49 PM, likui01 notifications@github.com wrote:

hi, im trying to to connect two MPU9250 to ardinuo. I have been successfully been able to connect the both imu. But im having trouble accessing the magnetometer reading from the imu. Im confuse how to acesss the device and than mag register. it has address 0x0c below is the code. ` Wire.begin(); Serial.begin(38400); pinMode(intPin, INPUT); digitalWrite(intPin, LOW); pinMode(myLed, OUTPUT); digitalWrite(myLed, HIGH);

// Read the WHO_AM_I register, this is a good test of communication byte c1 = readByte(address_1, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250

Serial.print("MPU9250 one "); Serial.print("I AM "); Serial.print(c1, HEX); Serial.print(" I should be "); Serial.println(0x71, HEX); delay(1000);

if (c1 == 0x71) // WHO_AM_I should always be 0x68

{ Serial.println("MPU9250 one is online...");

MPU9250SelfTest(address_1,SelfTest1); // Start by performing self test and reporting values Serial.print("x-axis self test: acceleration trim within : "); Serial.print(SelfTest1[0],1); Serial.println("% of factory value"); Serial.print("y-axis self test: acceleration trim within : "); Serial.print(SelfTest1[1],1); Serial.println("% of factory value"); Serial.print("z-axis self test: acceleration trim within : "); Serial.print(SelfTest1[2],1); Serial.println("% of factory value"); Serial.print("x-axis self test: gyration trim within : "); Serial.print(SelfTest1[3],1); Serial.println("% of factory value"); Serial.print("y-axis self test: gyration trim within : "); Serial.print(SelfTest1[4],1); Serial.println("% of factory value"); Serial.print("z-axis self test: gyration trim within : "); Serial.print(SelfTest1[5],1); Serial.println("% of factory value");

} else { Serial.print("Could not connect to MPU9250 one: 0x"); Serial.println(c1, HEX); while(1) ; // Loop forever if communication doesn't happen } calibrateMPU9250(address_1,gyroBias_1, accelBias_1); // Calibrate gyro and accelerometers, load biases in bias registers delay(1000); initMPU9250(address_1); Serial.println("MPU9250 one initialized for active data mode...."); // Initialize device for active mode read of acclerometer, gyroscope, and temperature

// Read the WHO_AM_I register of the magnetometer, this is a good test of communication byte d = readByte(AK8963_ADDRESS, AK8963_WHO_AM_I); // Read WHO_AM_I register for AK8963 Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX); Serial.print(" I should be "); Serial.println(0x48, HEX); delay(1000); initAK8963(address_1,magCalibration_1); Serial.println("AK8963 initialized for active data mode...."); // Serial.println(magCalibration_1[0]); Serial.println(","); Serial.println(magCalibration_1[1]); Serial.println(","); Serial.println(magCalibration_1[2]); getMres(); byte c2 = readByte(address_2, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250 Serial.print("MPU9250 TWO "); Serial.print("I AM "); Serial.print(c2, HEX); Serial.print(" I should be "); Serial.println(0x71, HEX); delay(1000);

if (c2 == 0x71) // WHO_AM_I should always be 0x68

{ Serial.println("MPU9250 two is online...");

MPU9250SelfTest(address_2,SelfTest2); // Start by performing self test and reporting values Serial.print("x-axis self test: acceleration trim within : "); Serial.print(SelfTest2[0],1); Serial.println("% of factory value"); Serial.print("y-axis self test: acceleration trim within : "); Serial.print(SelfTest2[1],1); Serial.println("% of factory value"); Serial.print("z-axis self test: acceleration trim within : "); Serial.print(SelfTest2[2],1); Serial.println("% of factory value"); Serial.print("x-axis self test: gyration trim within : "); Serial.print(SelfTest2[3],1); Serial.println("% of factory value"); Serial.print("y-axis self test: gyration trim within : "); Serial.print(SelfTest2[4],1); Serial.println("% of factory value"); Serial.print("z-axis self test: gyration trim within : "); Serial.print(SelfTest2[5],1); Serial.println("% of factory value");

} else { Serial.print("Could not connect to MPU9250 two: 0x"); Serial.println(c2, HEX); while(1) ; // Loop forever if communication doesn't happen }

calibrateMPU9250(address_2,gyroBias_2, accelBias_2); // Calibrate gyro and accelerometers, load biases in bias registers delay(1000);

// uncomment for calibration of magnetometer // magcalMPU9250(magbias_1, magScale_1); //Serial.println("AK8963 mag biases (mG)"); Serial.println(magbias[0]); Serial.println(magbias[1]); Serial.println(magbias[2]); //Serial.println("AK8963 mag scale (mG)"); Serial.println(magScale[0]); Serial.println(magScale[1]); Serial.println(magScale[2]); //delay(2000); // add delay to see results before serial spew of dat initMPU9250(address_2);

Serial.println("MPU9250 two initialized for active data mode...."); // Initialize device for active mode read of acclerometer, gyroscope, and temperature byte d1 = readByte(AK8963_ADDRESS, AK8963_WHO_AM_I); // Read WHO_AM_I register for AK8963 Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX); Serial.print(" I should be "); Serial.println(0x48, HEX); delay(1000); initAK8963(address_2,magCalibration_2); Serial.println("AK8963 initialized for active data mode...."); // Serial.println(magCalibration_2[0]); Serial.println(","); Serial.println(magCalibration_2[1]); Serial.println(","); Serial.println(magCalibration_2[2]); getMres(); // uncomment for calibration of magnetometer // magcalMPU9250(magbias_2, magScale_2); //Serial.println("AK8963 mag biases (mG)"); Serial.println(magbias_2[0]); Serial.println(magbias_2[1]); Serial.println(magbias_2[2]); //Serial.println("AK8963 mag scale (mG)"); Serial.println(magScale_2[0]); Serial.println(magScale_2[1]); Serial.println(magScale_2[2]); //delay(2000); // add delay to see results before serial spew of dat delay(1000);

}`

— 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/205, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qvdCyRKTIchjDVUxxTYd98h8JIrRks5s2UYagaJpZM4Qc7a2 .

munirfarzeen commented 6 years ago

hi, I enabled and disabled the reg 37, im confuse do i have to enable and disable bit for reg 36 too? could you please give more detail? thank you

kriswiner commented 6 years ago

You first...

On Mon, Nov 20, 2017 at 3:29 AM, likui01 notifications@github.com wrote:

hi, I enabled and disabled the reg 37, im confuse do i have to enable and disable bit for reg 36 too? could you please give more detail? thank you

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

munirfarzeen commented 6 years ago

first what? Or is it you F****?

kriswiner commented 6 years ago

I don't know what you are doing so I can't help you without some detail.

First piece of advice, check the data sheet and register map.

On Mon, Nov 20, 2017 at 9:47 AM, likui01 notifications@github.com wrote:

first what? Or is it you F****?

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

munirfarzeen commented 6 years ago

okay let me explain again. I am trying to connect two MPU9250 to single ardiuno board. i am using I2C protocol to communicate. I have one device of address 0x68 and other 0x69. i edited your code to read from two IMUs. I have been able to read correctly from accelero and gyro. For both of MPUs. the problem is when i try to read from magnetometer .
so to read from magno I enable the int_CFG reg for first MPU, than send address 0C to read from AK863 and than disable it. and do that for second MPU. but somewhere i am making mistake. I am getting garbage values. this the sample code

void initAK8963( uint8_t address, float * destination) { writeByte(address, INT_PIN_CFG, 0x22);
writeByte(address, INT_ENABLE, 0x01); // Enable data ready (bit 0) interrupt delay(100); // First extract the factory calibration for each magnetometer axis uint8_t rawData[3]; // x/y/z gyro calibration data stored here writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10); writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode delay(10); readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, &rawData[0]); // Read the x-, y-, and z-axis calibration values destination[0] = (float)(rawData[0] - 128)/256. + 1.; // Return x-axis sensitivity adjustment values, etc. destination[1] = (float)(rawData[1] - 128)/256. + 1.;
destination[2] = (float)(rawData[2] - 128)/256. + 1.; writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10); // Configure the magnetometer for continuous read and highest resolution // set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register, // and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates writeByte(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR delay(10); writeByte(address, INT_PIN_CFG, 0x00);
//writeByte(address, INT_ENABLE, 0x00); // Enable data ready (bit 0) interrupt delay(100); }

kriswiner commented 6 years ago

This is the right strategy then.

On Mon, Nov 20, 2017 at 10:09 AM, likui01 notifications@github.com wrote:

okay let me explain again. I am trying to connect two MPU9250 to single ardiuno board. i am using I2C protocol to communicate. I have one device of address 0x68 and other 0x69. i edited your code to read from two IMUs. I have been able to read correctly from accelero and gyro. For both of MPUs. the problem is when i try to read from magnetometer . so to read from magno I enable the int_CFG reg for first MPU, than send address 0C to read from AK863 and than disable it. and do that for second MPU. but somewhere i am making mistake. I am getting garbage values. this the sample code void initAK8963( uint8_t address, float * destination) { writeByte(address, INT_PIN_CFG, 0x22); writeByte(address, INT_ENABLE, 0x01); // Enable data ready (bit 0) interrupt delay(100); // First extract the factory calibration for each magnetometer axis uint8_t rawData[3]; // x/y/z gyro calibration data stored here writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer delay(10); writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode delay(10); readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, &rawData[0]); // Read the x-, y-, and z-axis calibration values destination[0] = (float)(rawData[0] - 128)/256. + 1.; // Return x-axis sensitivity adjustment values, etc. destination[1] = (float)(rawData[1] - 128)/256. + 1.; destination[2] = (float)(rawData[2] - 128)/256. + 1.; writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer delay(10); // Configure the magnetometer for continuous read and highest resolution // set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register, // and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates writeByte(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR delay(10); writeByte(address, INT_PIN_CFG, 0x00); //writeByte(address, INT_ENABLE, 0x00); // Enable data ready (bit 0) interrupt delay(100); }

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

munirfarzeen commented 6 years ago

so why is it not working?

munirfarzeen commented 6 years ago

both MPU show same roll pitch yaw, like its reading from same magnometer.

kriswiner commented 6 years ago

Because it probably is. You'll have to manage the addressing properly to get this to work. Just bookkeeping really...

On Mon, Nov 20, 2017 at 10:12 AM, likui01 notifications@github.com wrote:

both MPU show same roll pitch yaw, like its reading from same magnometer.

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

mmmatjaz commented 6 years ago

I managed to do what likui is attempting and I'm finding that the performance is very bad. It seems it takes quite a bit of time to turn the passthrough mode on and off, therefore this doesn't seem to be a good strategy. My understanding was the MPU can behave as master - what is the point then if it can't poll the magnetometer and serve the data through its own registers?

kriswiner commented 6 years ago

It can manage the mag through its own registers. Look here for an example:

https://github.com/kriswiner/MPU9250brianc118/blob/master/MPU9250.cpp

On Wed, Jan 3, 2018 at 9:46 AM, Matjaž Ogrinc notifications@github.com wrote:

I managed to do what likui is attempting and I'm finding that the performance is very bad. It seems it takes quite a bit of time to turn the passthrough mode on and off, therefore this doesn't seem to be a good strategy. My understanding was the MPU can behave as master - what is the point then if it can't poll the magnetometer and serve the data through its own registers?

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

mmmatjaz commented 6 years ago

Ah yes, I suppose there is no other choice if using SPI. Thanks, I'll try to transfer this procedure to my i2c code.

kriswiner commented 6 years ago

This should work, but I have never been successful with I2C but I didn't try too hard. A better solution would be to use two of these:

https://www.tindie.com/products/onehorse/ultimate-sensor-fusion-solution/?pt=ac_prod_search

and two I2C ports of a Teensy or Butterfly. This is what we do when we want to measure joint angles, etc.

On Wed, Jan 3, 2018 at 10:35 AM, Matjaž Ogrinc notifications@github.com wrote:

Ah yes, I suppose there is no other choice if using SPI. Thanks, I'll try to transfer this procedure to my i2c code.

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

biomedicalengg commented 5 years ago

hello @kriswiner I'm making a smart walker and I need to measure the compass using the magnetometer with the mpu-9250. I don't know how, can you help me?

kriswiner commented 5 years ago

Plenty of sketches on my github repository showing how. Or are you asking for paid consulting service here?

On Thu, Jun 13, 2019 at 9:39 AM biomedicalengg notifications@github.com wrote:

hello @kriswiner https://github.com/kriswiner I'm making a smart walker and I need to measure the compass using the magnetometer with the mpu-9250. I don't know how, can you help me?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/205?email_source=notifications&email_token=ABTDLKRUSFDDKWBSKWFZE5TP2JZ5XA5CNFSM4EDTW23KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXUJGGQ#issuecomment-501781274, or mute the thread https://github.com/notifications/unsubscribe-auth/ABTDLKRQOT4RCRDB4O2H2RDP2JZ5XANCNFSM4EDTW23A .