kriswiner / MPU9250

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

Should I trust the device? Low self test result #207

Open aripod opened 7 years ago

aripod commented 7 years ago

Hello Kris,

First of all thank you very much for such big effort and in advanced for taking the time to answer this.

I have ported your code to a Zynq FPGA:

void I2C_Write(XIicPs *Iic, unsigned char Address, unsigned char Register, unsigned char Value)
{
    unsigned char u8TxData[2];
    u8TxData[0] = Register;
    u8TxData[1] = Value;
    XIicPs_MasterSendPolled(Iic, u8TxData, 2, Address);
}

void I2C_read(XIicPs *Iic, unsigned char Address, unsigned char Register, unsigned char Bytes, unsigned char *Data)
{
    unsigned char u8TxData[1];
    u8TxData[0] = Register;
    XIicPs_MasterSendPolled(Iic, u8TxData, 1, Address);
    while(XIicPs_BusIsBusy(Iic));
    usleep(50000);
    XIicPs_MasterRecvPolled(Iic, Data, Bytes, Address);
}

void MPU9250_SelfTest(XIicPs *Iic, float * result)
{ // Should return percent deviation from factory trim values, +/- 14 or less deviation is a pass
    int i;
    uint8_t rawData[6] = {0, 0, 0, 0, 0, 0};
    uint8_t selfTest[6];
    int32_t gAvg[3] = {0}, aAvg[3] = {0}, aSTAvg[3] = {0}, gSTAvg[3] = {0};
    float factoryTrim[6];
    uint8_t FS = 0;

    I2C_Write(Iic, MPU9250_ADDR, SMPLRT_DIV, 0x00);     // Set gyro sample rate to 1 kHz.
    I2C_Write(Iic, MPU9250_ADDR, CONFIG, 0x02);         // Set gyro sample rate to 1 kHz and DLPF to 92 Hz.
    I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, FS<<3);   // Set full scale range for the gyro to 250 dps.
    I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG2, 0x02);  // Set accelerometer rate to 1 kHz and bandwidth to 92 Hz.
    I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0x00);   // Set full scale range for the accelerometer to 2 g.

    // Get average current values of Acclerometer and Gyroscope.
    for(i=0; i<200; i++)
    {
        I2C_read(Iic, MPU9250_ADDR, ACCEL_XOUT_H, 6, rawData);              // Read the six Acc raw data registers into data array.
        aAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;     // Turn the MSB and LSB into a signed 16-bit value
        aAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
        aAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

        I2C_read(Iic, MPU9250_ADDR, GYRO_XOUT_H, 6, rawData);               // Read the six Gyro raw data registers into data array.
        gAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;     // Turn the MSB and LSB into a signed 16-bit value
        gAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
        gAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
    }
    // Get average of 200 values and store as average current readings.
    for(i=0; i<3; i++)
    {
        aAvg[i] /= 200;
        gAvg[i] /= 200;
    }

    // Configure the Accelerometer and Gyroscope for self-test.
    I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0xE0);       // Enable self test on all three axes and set accelerometer range to +/- 2 g.
    I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, 0xE0);        // Enable self test on all three axes and set gyro range to +/- 250 degrees/s.
    usleep(25000);                                          // Delay a while to let the device stabilize.
    // Get average current values of Accelerometer and Gyroscope.
    for(i=0; i<200; i++)
    {
        I2C_read(Iic, MPU9250_ADDR, ACCEL_XOUT_H, 6, rawData);              // Read the six Acc raw data registers into data array.
        aSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;   // Turn the MSB and LSB into a signed 16-bit value
        aSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
        aSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

        I2C_read(Iic, MPU9250_ADDR, GYRO_XOUT_H, 6, rawData);               // Read the six Gyro raw data registers into data array.
        gSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;   // Turn the MSB and LSB into a signed 16-bit value
        gSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
        gSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
    }
    // Get average of 200 values and store as average current readings.
    for(i=0; i<3; i++)
    {
        aSTAvg[i] /= 200;
        gSTAvg[i] /= 200;
    }

    // Configure the Accelerometer and Gyroscope for normal operation.
    I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0x00);
    I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, 0x00);
    usleep(25000);                              // Delay a while to let the device stabilize.

    // Retrieve accelerometer and gyroscope factory Self-Test Code from USR_Reg.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_X_ACCEL, 1, &selfTest[0]);    // X-axis accel self-test results.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Y_ACCEL, 1, &selfTest[1]);    // Y-axis accel self-test results.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Z_ACCEL, 1, &selfTest[2]);    // Z-axis accel self-test results.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_X_GYRO,  1, &selfTest[3]);    // X-axis gyro self-test results.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Y_GYRO,  1, &selfTest[4]);    // Y-axis gyro self-test results.
    I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Z_GYRO,  1, &selfTest[5]);    // Z-axis gyro self-test results.

    // Retrieve factory self-test value from self-test code reads.
    factoryTrim[0] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[0] - 1.0) )); // FT[Xa] factory trim calculation
    factoryTrim[1] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[1] - 1.0) )); // FT[Ya] factory trim calculation
    factoryTrim[2] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[2] - 1.0) )); // FT[Za] factory trim calculation
    factoryTrim[3] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[3] - 1.0) )); // FT[Xg] factory trim calculation
    factoryTrim[4] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[4] - 1.0) )); // FT[Yg] factory trim calculation
    factoryTrim[5] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[5] - 1.0) )); // FT[Zg] factory trim calculation

     // Report results as a ratio of (STR - FT)/FT; the change from Factory Trim of the Self-Test Response
     // To get percent, must multiply by 100
    for (i = 0; i < 3; i++)
    {
        result[i]   = 100.0*((float)(aSTAvg[i] - aAvg[i]))/factoryTrim[i] - 100.;   // Report percent differences
        result[i+3] = 100.0*((float)(gSTAvg[i] - gAvg[i]))/factoryTrim[i+3] - 100.; // Report percent differences
    }
}

I tested the communication (like you) and I get the values that I should receive. The result of the self test is the following (terminal output):

[MPU9250] Read value in reg 0x75 is 0x71. It should be 0x71.
selfTest: [Ax, Ay, Az] = [-79.-388%, -98.-27%, -58.-327%] - [Gx, Gy, Gz] = [-77.-833%, -60.-471%, -82.-575%]

I run this a few times and the average value does not differ from these numbers.

Should I trust the device? Or this would be fixed after the calibration? I have double checked the code and it is like yours...I believe I am getting the proper values from the chip. What do you think?

One other thing is that when I check if there is new data with the INT_STATUS register, I need to add a 50us delay before I read the values from the accelerometer and gyroscope. Otherwise, I get their maximum value on all 6 registers....

Thank you very much for your help.

kriswiner commented 7 years ago

Self test is just a diagnostic, uses only LSbyte see attached.

On Fri, Nov 17, 2017 at 5:53 AM, aripod notifications@github.com wrote:

Hello Kris,

First of all thank you very much for such big effort and in advanced for taking the time to answer this.

I have ported your code to a Zynq FPGA:

void I2C_Write(XIicPs *Iic, unsigned char Address, unsigned char Register, unsigned char Value) { unsigned char u8TxData[2]; u8TxData[0] = Register; u8TxData[1] = Value; XIicPs_MasterSendPolled(Iic, u8TxData, 2, Address); }

void I2C_read(XIicPs Iic, unsigned char Address, unsigned char Register, unsigned char Bytes, unsigned char Data) { unsigned char u8TxData[1]; u8TxData[0] = Register; XIicPs_MasterSendPolled(Iic, u8TxData, 1, Address); while(XIicPs_BusIsBusy(Iic)); usleep(50000); XIicPs_MasterRecvPolled(Iic, Data, Bytes, Address); }

void MPU9250_SelfTest(XIicPs Iic, float result) { // Should return percent deviation from factory trim values, +/- 14 or less deviation is a pass int i; uint8_t rawData[6] = {0, 0, 0, 0, 0, 0}; uint8_t selfTest[6]; int32_t gAvg[3] = {0}, aAvg[3] = {0}, aSTAvg[3] = {0}, gSTAvg[3] = {0}; float factoryTrim[6]; uint8_t FS = 0;

I2C_Write(Iic, MPU9250_ADDR, SMPLRT_DIV, 0x00); // Set gyro sample rate to 1 kHz. I2C_Write(Iic, MPU9250_ADDR, CONFIG, 0x02); // Set gyro sample rate to 1 kHz and DLPF to 92 Hz. I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, FS<<3); // Set full scale range for the gyro to 250 dps. I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG2, 0x02); // Set accelerometer rate to 1 kHz and bandwidth to 92 Hz. I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0x00); // Set full scale range for the accelerometer to 2 g.

// Get average current values of Acclerometer and Gyroscope. for(i=0; i<200; i++) { I2C_read(Iic, MPU9250_ADDR, ACCEL_XOUT_H, 6, rawData); // Read the six Acc raw data registers into data array. aAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value aAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ; aAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

  I2C_read(Iic, MPU9250_ADDR, GYRO_XOUT_H, 6, rawData);               // Read the six Gyro raw data registers into data array.
  gAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;     // Turn the MSB and LSB into a signed 16-bit value
  gAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
  gAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

} // Get average of 200 values and store as average current readings. for(i=0; i<3; i++) { aAvg[i] /= 200; gAvg[i] /= 200; }

// Configure the Accelerometer and Gyroscope for self-test. I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0xE0); // Enable self test on all three axes and set accelerometer range to +/- 2 g. I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, 0xE0); // Enable self test on all three axes and set gyro range to +/- 250 degrees/s. usleep(25000); // Delay a while to let the device stabilize. // Get average current values of Accelerometer and Gyroscope. for(i=0; i<200; i++) { I2C_read(Iic, MPU9250_ADDR, ACCEL_XOUT_H, 6, rawData); // Read the six Acc raw data registers into data array. aSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value aSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ; aSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

  I2C_read(Iic, MPU9250_ADDR, GYRO_XOUT_H, 6, rawData);               // Read the six Gyro raw data registers into data array.
  gSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;   // Turn the MSB and LSB into a signed 16-bit value
  gSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
  gSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;

} // Get average of 200 values and store as average current readings. for(i=0; i<3; i++) { aSTAvg[i] /= 200; gSTAvg[i] /= 200; }

// Configure the Accelerometer and Gyroscope for normal operation. I2C_Write(Iic, MPU9250_ADDR, ACCEL_CONFIG, 0x00); I2C_Write(Iic, MPU9250_ADDR, GYRO_CONFIG, 0x00); usleep(25000); // Delay a while to let the device stabilize.

// Retrieve accelerometer and gyroscope factory Self-Test Code from USR_Reg. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_X_ACCEL, 1, &selfTest[0]); // X-axis accel self-test results. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Y_ACCEL, 1, &selfTest[1]); // Y-axis accel self-test results. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Z_ACCEL, 1, &selfTest[2]); // Z-axis accel self-test results. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_X_GYRO, 1, &selfTest[3]); // X-axis gyro self-test results. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Y_GYRO, 1, &selfTest[4]); // Y-axis gyro self-test results. I2C_read(Iic, MPU9250_ADDR, SELF_TEST_Z_GYRO, 1, &selfTest[5]); // Z-axis gyro self-test results.

// Retrieve factory self-test value from self-test code reads. factoryTrim[0] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[0] - 1.0) )); // FT[Xa] factory trim calculation factoryTrim[1] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[1] - 1.0) )); // FT[Ya] factory trim calculation factoryTrim[2] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[2] - 1.0) )); // FT[Za] factory trim calculation factoryTrim[3] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[3] - 1.0) )); // FT[Xg] factory trim calculation factoryTrim[4] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[4] - 1.0) )); // FT[Yg] factory trim calculation factoryTrim[5] = (float)(2620/1<<FS)(pow( 1.01 , ((float)selfTest[5] - 1.0) )); // FT[Zg] factory trim calculation

// Report results as a ratio of (STR - FT)/FT; the change from Factory Trim of the Self-Test Response // To get percent, must multiply by 100 for (i = 0; i < 3; i++) { result[i] = 100.0((float)(aSTAvg[i] - aAvg[i]))/factoryTrim[i] - 100.; // Report percent differences result[i+3] = 100.0((float)(gSTAvg[i] - gAvg[i]))/factoryTrim[i+3] - 100.; // Report percent differences } }

I tested the communication (like you) and I get the values that I should receive. The result of the self test is the following:

[MPU9250] Read value in reg 0x75 is 0x71. It should be 0x71. selfTest: [Ax, Ay, Az] = [-79.-388%, -98.-27%, -58.-327%] - [Gx, Gy, Gz] = [-77.-833%, -60.-471%, -82.-575%]

Should I trust the device? Or this would be fixed after the calibration? I have double checked the code and it is like yours...I believe I am getting the proper values from the chip. What do you think?

Thank you very much for your help.

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

aripod commented 7 years ago

Thank you Kris for your quick answer. I cannot see what you attached but it is clear what could be the issue for the low % with the LSB. I will proceed with the rest.

kriswiner commented 7 years ago

send me an e-mail at tleracorp@gmail.com if you want the self test application note.

On Sat, Nov 18, 2017 at 2:15 AM, aripod notifications@github.com wrote:

Thank you Kris for your quick answer. I cannot see what you attached but it is clear what could be the issue for the low % with the LSB. I will proceed with the rest.

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

aripod commented 7 years ago

Hello Kris,

Rather than keep asking you via a private e-mail, I thought it might help someone else who is facing similar issues if I post here.

I adapted the code so it is like https://github.com/kriswiner/MPU9250/blob/master/MPU9250_MS5637_AHRS_t3.ino. I gathered some samples and plot them to see if data coming from the sensor is correct. The sensor is flat on a table, motionless.

Accelerometer:

These are the plots according to all 3 different phases (on startup, after calibration and after initialization), taking 200 samples on each stage.

accelerometer These are raw values, without subtracting accelBias. (only multiplied by the aRes) They seem to be correct as the only acceleration is gravity on the Z axis. If I rotate the sensor I can see gravity on the other axis. Therefore, I could consider the accelerometer working properly, right?

Gyroscope

Same as with the accelerometer. It is divided in 3 stages with 200 samples each. gyroscope Here as the sensor is motionless, there seems to be something wrong on the Z axis. Could this already be because of the drift as the sensor has been on a long time already? I am also plotting the raw data (just multiplied by gRes).

Magnetometer

I am using the calibration function that you use to with the hard and soft iron. The output values are: magBias = {0,0,0} and magScale ={0.65555, 0.6781609, +Infinity}. And these are the plots from the raw values:

Initialization: magnetometer_init Calibration: magnetometer_calibration

The X/Y, X/Z, Y/X, Y/Z, Z/X and Z/Y should be similar to a circumference for what I've seen...but they do not look that good.....

I hope this helps a bit to figure out my issue. Thank you again for all your time and help.

kriswiner commented 7 years ago

I am not sure what your issue is but the gyro data is seriously out of whack. Are you sure you are scaling it properly? You should be seeing tens of milli dps jitter not tens of dps.

What kind of MPU9250 breakout are you using?

On Mon, Nov 27, 2017 at 2:06 AM, aripod notifications@github.com wrote:

Hello Kris,

Rather than keep asking you via a private e-mail, I thought it might help someone else who is facing similar issues if I post here.

I adapted the code so it is like https://github.com/kriswiner/ MPU9250/blob/master/MPU9250_MS5637_AHRS_t3.ino. I gathered some samples and plot them to see if data coming from the sensor is correct. The sensor is flat on a table, motionless. Accelerometer:

These are the plots according to all 3 different phases (on startup, after calibration and after initialization), taking 200 samples on each stage.

[image: accelerometer] https://ibb.co/hqFUXm These are raw values, without subtracting accelBias. (only multiplied by the aRes) They seem to be correct as the only acceleration is gravity on the Z axis. If I rotate the sensor I can see gravity on the other axis. Therefore, I could consider the accelerometer working properly, right? Gyroscope

Same as with the accelerometer. It is divided in 3 stages with 200 samples each. [image: gyroscope] https://ibb.co/h2ETQ6 Here as the sensor is motionless, there seems to be something wrong on the Z axis. Could this already be because of the drift as the sensor has been on a long time already? I am also plotting the raw data (just multiplied by gRes). Magnetometer

I am using the calibration function that you use to with the hard and soft iron. The output values are: magBias = {0,0,0} and magScale ={0.65555, 0.6781609, +Infinity}. And these are the plots from the raw values:

Initialization: [image: magnetometer_init] https://ibb.co/nLYBdR Calibration: [image: magnetometer_calibration] https://ibb.co/izzjyR

The X/Y, X/Z, Y/X, Y/Z, Z/X and Z/Y should be similar to a circumference for what I've seen...but they do not look that good.....

I hope this helps a bit to figure out my issue. Thank you again for all your time and help.

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

aripod commented 7 years ago

I am following your code so the gyro is set to 250 dps. Therefore, I am multiplying the raw data by (250.0/32768.0) all three axis...so it is strange that Gx and Gy seems fine and Gz has that variation....

I am using a cheap (Chinese I would say) MPU9250 from ebay. Could it be that it is a cheap sensor....? Same could go for the nmagnetometer?

Thanks!

kriswiner commented 7 years ago

Yes, looks like a crappy design. Try the ones at Tindie.

On Wed, Nov 29, 2017 at 12:12 AM aripod notifications@github.com wrote:

I am following your code so the gyro is set to 250 dps. Therefore, I am multiplying the raw data by (250.0/32768.0) all three axis...so it is strange that Gx and Gy seems fine and Gz has that variation....

I am using a cheap (Chinese I would say) MPU9250 from ebay https://www.ebay.com/itm/SPI-IIC-MPU-9250-9-Axis-Attitude-Gyro-Accelerator-Magnetometer-Sensor-Module-/281866691541. Could it be that it is a cheap sensor....? Same could go for the nmagnetometer?

Thanks!

— You are receiving this because you commented.

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

aripod commented 6 years ago

It seems the Chinese sensor is fine. I found a few bugs on the code and discovered that if I am going to make two consecutive reads on the sensor, I need to put a delay (~20us) so the second read does not give me trash. As far as the accelerometer and gyroscope I am getting what I should. When the sensor is flat and motionless on a table, I get 0g on Ax and Ay and 1g on Az. For Gy, Gy and Gz is 0 and when I rotate the sensor around each axis, the values change accordingly to the direction of my movement.

As far as the magnetometer, I run the calibration as your function, followed the 8 pattern to collect data and I got these graphs. One is with the sensor flat and motionless on the table and the second one I am following the same 8 pattern.

magnetometer_flat magnetometer_8_pattern

For the second graph, it does not look like it would make a 3d sphere but at least they are centered around the origin. Can I consider my magnetometer calibrated or I still should not rely on these values?

Thanks again for the help.

kriswiner commented 6 years ago

The mag does not look calibrated to me. Might need to increase the time for collecting data...

On Tue, Dec 5, 2017 at 10:17 AM, aripod notifications@github.com wrote:

I found a few bugs on the code and discovered that if I am going to make two consecutive reads on the sensor, I need to put a delay (~20us) so the second read does not give me trash. As far as the accelerometer and gyroscope I am getting what I should. When the sensor is flat and motionless on a table, I get 0g on Ax and Ay and 1g on Az. For Gy, Gy and Gz is 0 and when I rotate the sensor around each axis, the values change accordingly to the direction of my movement.

As far as the magnetometer, I run the calibration as your function, followed the 8 pattern to collect data and I got these graphs. One is with the sensor flat and motionless on the table and the second one I am following the same 8 pattern.

[image: magnetometer_flat] https://ibb.co/gGUsvG [image: magnetometer_8_pattern] https://ibb.co/jrZQFG

For the second graph, it does not look like it would make a 3d sphere but at least they are centered around the origin. Can I consider my magnetometer calibrated or I still should not rely on these values?

Thanks again for the help.

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

aripod commented 6 years ago

I am getting 1500 samples as you do in your code for calibration....I will try doubling.... Should I increase also the period of sampling? I assumed that you meant get more samples when you said increase the time for collecting data.

Then I only get 200 samples to evaluate the calibration and I follow the same 8 pattern on the 3 axis.

One silly question....I am following an 8 pattern on all 3 axis....and I am also rotating the sensor while I do this....I mean, it is not like the sensor is orthogonal to the axis while following the 8 pattern.

EDIT: I increase the delay between reads in the for cycle to obtain samples for calibration and followed an 8 pattern along the 3 axis. I got in total 1500 samples: raw.txt These are the 1500 samples that I got and use to obtain the bias for calibration. I am only collecting data on the sensor and post-processing it on octave:

raw = dlmread ('raw.txt', ',', 0, 0);

mRes = 1.499389;
magCalibration = [1.195312, 1.195312, 1.156250];

mag_max(1) = max(raw(:,1));
mag_max(2) = max(raw(:,2));
mag_max(3) = max(raw(:,3));

mag_min(1) = min(raw(:,1));
mag_min(2) = min(raw(:,2));
mag_min(3) = min(raw(:,3));

mag_bias(1) = (mag_max(1) + mag_min(1))/2;
mag_bias(2) = (mag_max(2) + mag_min(2))/2;
mag_bias(3) = (mag_max(3) + mag_min(3))/2;

magBias(1) = mag_bias(1)*mRes*magCalibration(1);
magBias(2) = mag_bias(2)*mRes*magCalibration(2);
magBias(3) = mag_bias(3)*mRes*magCalibration(3);

mag_scale(1) = (mag_max(1) - mag_min(1))/2;
mag_scale(2) = (mag_max(2) - mag_min(2))/2;
mag_scale(3) = (mag_max(3) - mag_min(3))/2;
avg_rad = (mag_scale(1) + mag_scale(2) + mag_scale(3))/3;

magScale(1) = avg_rad/mag_scale(1);
magScale(2) = avg_rad/mag_scale(2);
magScale(3) = avg_rad/mag_scale(3);

mx = raw(:,1)*mRes*magCalibration(1) - magBias(1);
my = raw(:,2)*mRes*magCalibration(2) - magBias(2);
mz = raw(:,3)*mRes*magCalibration(3) - magBias(3);

mx_raw = raw(:,1)*mRes*magCalibration(1);
my_raw = raw(:,2)*mRes*magCalibration(2);
mz_raw = raw(:,3)*mRes*magCalibration(3);

scatter(mx_raw, my_raw, [], [255,0,0]/256)
hold on
grid on
scatter(mx_raw, mz_raw, [], [0,255,0]/256)
scatter(my_raw, mz_raw, [], [0,0,255]/256)
title("Uncalibrated.");
legend("Mx/My", "Mx/Mz", "My/Mz");

figure 
scatter(mx, my, [], [255,0,0]/256)
scatter(mx, mz, [], [0,255,0]/256)
scatter(mx, my, [], [255,0,0]/256)
grid on
hold on
scatter(mx, mz, [], [0,255,0]/256)
scatter(my, mz, [], [0,0,255]/256)
title("Calibrated.");
legend("Mx/My", "Mx/Mz", "My/Mz");

I am getting these:

magnetometer_raw magnetometer_calibrated

Maybe I am not following the proper movement of the sensor to calibrate it? Or maybe I made a mistake while copying the calibration function from your sketch.

The raw data still does not look like a circumference so the calibrated data will never be centered.... but if accelerometer and gyro are ok, I believe I should expect the magnetometer to be ok too.

aripod commented 6 years ago

Second post today.... I believe I should not stay orthogonal to the axis but rotate the sensor randomly.....If I do that, I get something a bit similar to your figures from your wiki. They do not look like a circumference but is getting better than previous graphs....right?

magnetometer_uncal magnetometer_cal

EDIT: I tried again with 1500 samples and rotating the sensor in any direction slowly and I believe this looks good. You would tell me better:

magnetometer_uncal magnetometer_cal

kriswiner commented 6 years ago

You need to sample the entire response surface, the entire 3D space as much as possible.

You can test the calibration by noting the field in the z-axis whent he sensor is flat and motionless on a table. It should read somewhere around 400 milliG depending on your area of the Earth. When you turn it 180 degrees so the sensor if facing bottom it should read -400 something. You can test the other two sensor axes the same way. If the sensor response is the same magnitude but + and - then the mag response surface is centered on the origin. This doesn;t guarantee there is not elliptical distortion still present, but at least you would have gotten rind of tany large offsets.

On Wed, Dec 6, 2017 at 8:08 AM, aripod notifications@github.com wrote:

Second post today.... I believe I should not stay orthogonal to the axis but rotate the sensor randomly.....If I do that, I get something similar to your figures from your wiki https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration. They do not look like a circumference but is getting better than previous graphs....right?

[image: magnetometer_uncal] http://ibb.co/kAanfG [image: magnetometer_cal] http://ibb.co/i8fynw

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

aripod commented 6 years ago

That seems to be the hardest thing for me to achieve...cover the entire 3D space....If I change the distance from the sensor to the table when I am rotating it, the raw values change, as you can see on the top 3 images (raw values). I end up with one closer to a circle and two distinct ellipses...Therefore, in this case, I have around 400mG in Z and -400mG when I rotate 180 degrees.....but on the X and Y axis the values are greater than 400...closer to 800 I would say....

calib
free img

I am now taking samples and ploting them in real time...should my goal then be to keep capturing samples until I have 3 circumferences on the top 3 figures?

kriswiner commented 6 years ago

I hope you understand that you need to move the device in all directions. Imagine an arrow pointing from the + z-axis of the magnetometer. You have to move the device during calibration such that the arrow tip touches every point on the 3D spherical surface surrounding the centeroid of the sensor. Like make sure the arrow touches every point on the interior of a balloon with the sensor at the center of the balloon. Get it?

On Thu, Dec 7, 2017 at 7:16 AM, aripod notifications@github.com wrote:

That seems to be the hardest thing for me to achieve...cover the entire 3D space....If I change the distance from the sensor to the table when I am rotating it, the raw values change, as you can see on the top 3 images (raw values). I end up with one closer to a circle and two distinct ellipses...Therefore, in this case, I have around 400mG in Z and -400mG when I rotate 180 degrees.....but on the X and Y axis the values are greater than 400...closer to 800 I would say....

[image: calib] https://ibb.co/e0ZqKb free img https://imgbb.com/

I am now taking samples and ploting them in real time...should my gold then be to keep capturing samples until I have 3 circumferences on the top 3 figures?

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

shomedas commented 5 years ago

Even I am getting a jitter of upto 0.3 dps in the gyro readings when the gyro is stationary on the table. @aripod : How did you add a delay between two consecutive reads of the sensor to avoid reading junk values

My readings for stationary IMU on table with x pointing towards north.

ax=49.0 ay=-6.71 az=1014 mg gx=-0.11 gy=0.23 gz=-0.17 deg/s mx=-7, my = 402, mz =114

Are these ok? Why is the my max when x points north? shouldnt it be mx that should be nearly 400 when the x axis points north

My device passed the self test.

kriswiner commented 5 years ago

Magnetic field varies a lot over the Earth. The only constant is that the magnitude should be ~500 milliGauss. In my part of northern California the field is mostly down so Mz reads ~420 milliGauss. x and y are ~50 and ~200 depending on orientation. Check with you local geologic survey office to see what you should expect in your area.

How are you calibrating your sensors?

If you are removing the offset bias your gyro readings should be 0, 0, 0 and accel 0, 0 1, with maybe 10 millig jitter in the accel when the sensor is flat and motionless on a table top.

On Sun, Mar 3, 2019 at 7:12 AM shomedas notifications@github.com wrote:

Even I am getting a jitter of upto 0.3 dps in the gyro readings when the gyro is stationary on the table. @aripod https://github.com/aripod : How did you add a delay between two consecutive reads of the sensor to avoid reading junk values

My readings for stationary IMU on table with x pointing towards north.

ax=49.0 ay=-6.71 az=1014 mg gx=-0.11 gy=0.23 gz=-0.17 deg/s mx=-7, my = 402, mz =114

Are these ok? Why is the my max when x points north? shouldnt it be mx that should be nearly 400 when the x axis points north

When I point any axis towards north and then towards south

My device passed the self test.

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

shomedas commented 5 years ago

I have used your code MPU9250BasicAHRS.ino for calibration and for reading the data. I have done the magnetic calibration also using your code. the gyro calibration is with the mpu flat & stationary on a table with z axis pointing up

According to you the acceleration and the gyroscope gitter should be with tens of mg and milli dps resp. I am getting the jitter in 100s of milli dps in the gyro reading.

aripod says that adding a delay between two consecutive reads of the sensor helps to avoid reading junk values. Kindly suggest how do I add a delay in the "calibrateMPU9250" function.

kriswiner commented 5 years ago

Why aren't you using the data ready interrupt? Then no delay is needed.

On Sun, Mar 3, 2019 at 9:37 AM shomedas notifications@github.com wrote:

I have used your code MPU9250BasicAHRS.ino for calibration and for reading the data. I have done the magnetic calibration also using your code. the gyro calibration is with the mpu flat & stationary on a table with z axis pointing up

According to you the acceleration and the gyroscope gitter should be with tens of mg and milli dps resp. I am getting the jitter in 100s of milli dps in the gyro reading.

aripod says that adding a delay between two consecutive reads of the sensor helps to avoid reading junk values. Kindly suggest how do I add a delay in the "calibrateMPU9250" function.

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

shomedas commented 5 years ago

the INT_ENABLE interrupt is enabled that is set to 0x01 the initMPU function. Is there any physical connection I have to do? There is a INT pin in the board. Do I have to connect it to Ground or VCC?

My current connection Vcc- 3.3V, Gnd-0V :) SDA-A4 SCL-A5 FSYNC- GND

kriswiner commented 5 years ago

Connect INT to the MCU interrupt input pin...See Arduino.cc for how interrupts work.

On Sun, Mar 3, 2019 at 10:00 AM shomedas notifications@github.com wrote:

the INT_ENABLE interrupt is enabled that is set to 0x01 the initMPU function. Is there any physical connection I have to do? There is a INT pin in the board. Do I have to connect it to Ground or VCC?

My current connection Vcc- 3.3V, Gnd-0V :) SDA-A4 SCL-A5 FSYNC- GND

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

shomedas commented 5 years ago

what about AD0 & NCS. I read in some of your other posts that they too need to be connected.

I am using arduino uno and MPU9255

kriswiner commented 5 years ago

Ncs needs to be pulled HIGH, ado high or low as you like.

On Mon, Mar 4, 2019 at 10:43 AM shomedas notifications@github.com wrote:

what about AD0 & NCS. I read in some of your other posts that they too need to be connected.

I am using arduino uno and MPU9255

— You are receiving this because you commented.

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