i2cdevlib icon indicating copy to clipboard operation
i2cdevlib copied to clipboard

MPU6050 ACC Calibration does never finish

Open hschwane opened this issue 4 years ago • 40 comments

Hi,

when running the dmp examples, calibration never finishes (infinite "*" are printed). Commenting out the mpu.CalibrateAccel(6); makes it run fine. However then it is not calibrated i guess? Any ideas?

Edit: I'm using an arduino Nano and an MPU6050

hschwane avatar Mar 03 '20 16:03 hschwane

So it seems Acceleration offsets are not stored. This code:

    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1688); // 1688 factory default for my test chip
    mpu.PrintActiveOffsets();

results in

//           X Accel  Y Accel  Z Accel   X Gyro   Y Gyro   Z Gyro
//OFFSETS        0,       0,       0,     220,      76,     -85

hschwane avatar Mar 03 '20 17:03 hschwane

I'm having the same problem. I cannot get get the offsets using IMU_Zero either because of the issue. eSum in PID function is about 2000 to 7000 and is just oscillating there.

EDIT: Here is a take from the MPU6050_raw:

a/g:	432	416	17420	1	8	7
a/g:	456	440	17332	-9	0	17
a/g:	440	412	17276	0	-53	1
a/g:	436	376	17372	1	-9	15
a/g:	452	352	17388	3	9	7

The sensor is completely on flat surface and not moving/turning. If I understand correctly, the first 2 should be near zero like the gyro readings and third about 16384?

t8kana00 avatar Mar 05 '20 00:03 t8kana00

I created the PID routine. can you describe the position of the MPU6050, is it flat with gravity down?

Notes: What happens in the program

  1. gravity is removed and the initial loop attempts to tidy up the values before refining the PID Kp and Ki values.
  2. Once the values reach an acceptable level one that can be calibrated we tighten up the PID loop and land the offsets. mpu.CalibrateAccel( Times to tighten up the PID );
  • If the values never reach the acceptable level we can't discover the offsets.

requirements: Gravity must be down. leaning or other positions don't work for calibration.

Possible solution: If you must start with it leaning initially run the accelerometer calibration flat and use the values generated to initiate the accelerometer from this point on. Don't try to calibrate it if it is not level.

accelerometer 432 416 17420 Gyro 1 8 7

The goal of the PID is to have the values as close to zero as possible with the exception of Z

Ideal: The PID routine is attempting to find this. accelerometer 0 0 1G Gyro 0 0 0

Z

ZHomeSlice avatar Mar 05 '20 03:03 ZHomeSlice

It was not moving with gravity down. Well i think it is down. I will try again in different orientations next week. However, it seems even manual setting the offsets will not store them correctly (see my answer above).

hschwane avatar Mar 05 '20 10:03 hschwane

@ZHomeSlice The sensor is quite flat on the table, but I really cannot get it to be flat any more accurately than that. Does the PID function really require it to be completely flat and gravity be only on the Z axis?

I am not really an expert on any of this, but maybe If I could set the accelerometer offsets, it could solve the issue.

I'd like to also point out, that I am too unable to set the acceleration offsets on the sensor.

For example for XA_OFFSET_H the code tries to access register in 0x77 and it does not seem to work. If you switch it to 0x06, it manages to write to the register and read it, but then you get just 32767 from the x acceleration. I tried with the register 0x06 and I wrote -8000 there and then I got like -8000 from the x acceleration, but If I wrote -2000 to the same register, x acceleration just gives the maximum 32767

Debugging this is beyond me.

EDIT: Well, I just found out the required offsets. Btw, the register seems to be wrong on the code. This line: uint8_t SaveAddress = ((getDeviceID() < 0x38 )? MPU6050_RA_XA_OFFS_H:0x77); // MPU6050,MPU9150 Vs MPU6500,MPU9250 results in 0x77 for me, which is wrong. It should be the MPU6050_RA_XA_OFFS_H aka 0x06. Same for the other offsets. The PID also has this problem, trying to write in the wrong register, at least in my sensor (GY-521).

I found out the initial offsets by laying it on my table and then setting the offset to 32767. Then it just looped down and decremented that value until acceleration for that axis was around zero. For Z axis, I first removed gravity and then did the same. My complete offsets are

mpu.setXGyroOffset(-21);
mpu.setYGyroOffset(-17);
mpu.setZGyroOffset(-58);
mpu.setXAccelOffset(-6989);
mpu.setYAccelOffset(-7580);
mpu.setZAccelOffset(9726);

Now the PID function is lighting fast and is optimizing my offsets even more.

t8kana00 avatar Mar 06 '20 21:03 t8kana00

if we are not able to save to the chip this would prevent calibration from occurring

MPU6050_RA_XA_OFFS_H:0x77 is for the MPU9250 This checks the deviceID to test this. Otherwise, it defaults to MPU6050_RA_XA_OFFS_H aka 0x06

Now the PID function is lighting fast and is optimizing my offsets even more.

good to know that you can correct this by getting closer to the ideal offsets.

using your even more optimized offsets will improve things to a greater extent

Your offsets are the most extreme to date that I've seen.

ZHomeSlice avatar Mar 07 '20 00:03 ZHomeSlice

@ZHomeSlice Yeah, that line of code should work. Upon investigation, my DeviceID is 0x39. It should be 0x34. I forgot, that I had that problem before and I just bypassed it in the code. I know this is not the issue for this, but would you happen to have any idea, why my GY-521 is reporting itself as 0x39 on start? It's i2c address is still the 0x68, and the documentation is clear that the DeviceID is supposed to be upper 6 bits of the MPU-60X0’s 7-bit i2c address, which it clearly is not in my case.

t8kana00 avatar Mar 07 '20 01:03 t8kana00

DeviceID is supposed to be upper 6 bits of the MPU-60X0’s 7-bit i2c address, which it clearly is not in my case.

not sure if this answers your question

This register is used to verify the identity of the device. The contents of WHO_AM_I are the upper 6 bits of the MPU-60X0’s 7-bit I2C address. The least significant bit of the MPU-60X0’s I2C address is determined by the value of the AD0 pin. The value of the AD0 pin is not reflected in this register. The default value of the register is 0x68. Bits 0 and 7 are reserved. (Hard coded to 0)

Z

ZHomeSlice avatar Mar 07 '20 18:03 ZHomeSlice

@t8kana00

Yeah, that line of code should work. Upon investigation, my DeviceID is 0x39. It should be 0x34. I forgot, that I had that problem before and I just bypassed it in the code. I know this is not the issue for this, but would you happen to have any idea, why my GY-521 is reporting itself as 0x39 on start? It's i2c address is still the 0x68, and the documentation is clear that the DeviceID is supposed to be upper 6 bits of the MPU-60X0’s 7-bit i2c address, which it clearly is not in my case.

Probably the reason why you're seeing different DeviceID is that either the chip is counterfeit or failed factory validation and should have scrapped. However, nothing goes to waste in China and they use the scrapped parts usually on boards like GY-521. The MPU-6050 design is relatively old already and I would be amazed if Chinese would have copied that.

Could the chip measurements be drifting way too much to cause calibration routine not to finish?

I recently bought MPU-6050 sensor boards from local supplier here in Finland for a quite hefty price and got these GY-521 boards. Bought 6 boards and all the boards are reporting different value on WHO_AM_I register :)

jaisoh avatar Mar 19 '20 20:03 jaisoh

@ZHomeSlice Yeah, that line of code should work. Upon investigation, my DeviceID is 0x39. It should be 0x34. I forgot, that I had that problem before and I just bypassed it in the code. I know this is not the issue for this, but would you happen to have any idea, why my GY-521 is reporting itself as 0x39 on start? It's i2c address is still the 0x68, and the documentation is clear that the DeviceID is supposed to be upper 6 bits of the MPU-60X0’s 7-bit i2c address, which it clearly is not in my case.

Hey, I'm having the same issue you did. Were you able to resolve it?

Any help would be much appreciated :)

BazingaBazinga avatar Apr 28 '20 16:04 BazingaBazinga

I was able to overcome the issue by swapping the non-working module with a working one :)

Didn't bother to try to figure out could the faulty modules be used.. I can always order 20 new modules from china for 10eur and probably 30% of those will work. Still cheaper than buying the modules from western markets.

jaisoh avatar Apr 30 '20 06:04 jaisoh

Thanks for the input. I got back to working on this again and found a workaround for the problem. Same as @t8kana00 my device id was 0x39 I tried to use setDeviceID() to set it to 0x34 but that had no effect. So instead I modified the getDeviceID() in MPU6050.cpp to always return 0x34. Now calibration runs fine and I can execute all the examples. I hope it does not break anything else.

Edit: not sure if this issue can be closed or if you want to provide an override switch for future version of the library? Like #define MPU6050_FORCE_ID0x34.

hschwane avatar May 12 '20 11:05 hschwane

@jaisoh , Thanks for the hint, I just received a new MPU-6050 from adafruit with Qwiic connecotrs, to ensure the hardware quality. It works compared to the cheap board I soldered myself. I don't want to draw conclusions to fast on what to buy. The cheap MPU6050 was returning values via (raw values and processed by the DMP6) though the calibration was infinite.

sylvanoMTL avatar Aug 11 '20 20:08 sylvanoMTL

@sylvanoMTL Some insight into my PID calibration routine that might help. The PI of (PID) routine that is used gathers direct feedback and makes instantaneous adjustments to the offsets. The goal is to make the raw values as close to zero as possible. I have noticed that some of my MPU6050's are way off initially compared to others. This requires the MPU6050 to be flat. the main reason is that gravity must be properly removed from the Z access and not be influencing the X or Y accesses. This is the main cause of infinite calibration failures. The second is because the MPPU is so far off initially that it just won't get close for the PID to start grabbing good values to use. For the Second instance. try setting offsets that are close before running calibration. The PID will always use existing offsets as a starting point to speed up the process. so use any of the older averaging (SLOW) calibration routines to fine the average error for offset and set it first then even if the MPU is way off the PID can avoid tripping up and achieve your calibration.

Z

ZHomeSlice avatar Aug 12 '20 11:08 ZHomeSlice

I have this issue too on my MPU6050.

The error is always to high if((c == 99) && eSum > 1000){ // Error is still too great to continue I never get out from the loop.

By putting it flat should Z axis face ground? because why are you removing gravity from X not from Z? 0x3B is ACCEL_XOUT_H if ((ReadAddress == 0x3B)&&(i == 2)) Reading -= 16384; //remove Gravity

Any other advice how to exit endless loop?

JuMalIO avatar Dec 10 '20 16:12 JuMalIO

@JuMalIO "I never get out from the loop."

This is caused by one of the readings, never approaching zero. The idea is to bring everything as close to zero as possible. Your reading is still on one of the sensors is still > 1000 which is way off. without this reaching zero (+-50) your mpu will never read properly.

Causes:

  • The MPU6050 must be flat to calibrate. I remove gravity from the Z access if gravity is present on any other accelerometer, not only do we remove gravity from the wrong sensor but gravity is distorting the other sensor and calibration becomes impossible.
  • You may also have calibration settings already in place that could cause your MPU to struggle to find good readings. make sure your initial calibration settings are all zeros. I noticed this once with an odd mpu for a batch of 10. I altered the calibration routine to accommodate this, with only 10 mpu6050's to play with I'm sure other issues could arise.
  • Last your MPU is damaged.

Calibration is done by removing adjusting the offsets little by little "sliding"(using a PID loop) the readings into perfection. thousands of readings and adjustments take place! three every millisecond! once all readings reach close to zero we are calibrated.

You will get a printout of the calibration offsets upon success. you can use them by setting them at the beginning of your program. additional calibration runs will go super fast. additionally setting the correct offsets may even allow you to skip further calibrations depending on your needs (Note: temperature affects calibration)

Z

ZHomeSlice avatar Dec 11 '20 14:12 ZHomeSlice

same issue here.

I ordered 3 differently branded MPU6050 from 2 German suppliers (4 each so had some HW to do cross-validation). I checked for the IDs and found out that every batch had its own (got x39, x34 and xC). I ignored testConnection() like #428 suggested and tried calibrating.

Only for boards with ID x34 the calibration loop returned. For all others loop ran 20min+ until I aborted (then inserted the then calculated values and tried again but same issue). All boards were placed in the same way on the same vertically aligned surface.

degdion avatar Aug 23 '21 13:08 degdion

immagine Why no end immagine

Same here: CalibrateAccel hangs forever... But CalibrateGyro works.

>......

Gyro Offsets:
65061
87
13

dentex avatar Sep 16 '21 18:09 dentex

Wow. Reading here the https://github.com/jrowberg/i2cdevlib/issues/520#issuecomment-595971151, I changed the line: https://github.com/jrowberg/i2cdevlib/blob/e2bef30642685443d2f3a88fa210b6977e78d7bf/Arduino/MPU6050/MPU6050.cpp#L3293 to be: uint8_t SaveAddress = (ReadAddress == 0x3B)? 0x06:0x13; (the address for my chip is 0x68). ...and if I'm not missing anything, the calibration now works.

>........>........

Accel Offsets:
59851
60551
10034

Gyro Offsets:
65060
88
13

dentex avatar Sep 16 '21 19:09 dentex

@dentex Making this change and why something else would work better... from: uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13; to: uint8_t SaveAddress = (ReadAddress == 0x3B)? 0x06:0x13;

I developed the PID-based calibration routine. the MPU6050, mpu9150, mpu9155 has a different location to save the Accelerometer calibration values than the other mpu's So here is a breakdown as to what is happening.

if (ReadAddress == 0x3B){    // We are reading accelerator values. We need to save them to XA_OFFSET_H (starting address) which changes between mpu models
    if (getDeviceID() < 0x38){  // are we using a mpu6050, mpu9150, mpu9155 or is it something else like mpu6500, mpu9250, mpu9255
        SaveAddress = 0x06;  //https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6500-Register-Map2.pdf  page 8
   } else {
       SaveAddress = 0x77;  //https://invensense.tdk.com/wp-content/uploads/2015/02/RM-MPU-9250A-00-v1.6.pdf  page 9
   }
   SaveAddress = 0x13; // We are reading Gyro Values
}

A better resolution to your issue will be to determining what model and device id are you getting for your MPU? I only had a few to try so I'm sure there could be some I missed. Z

ZHomeSlice avatar Sep 23 '21 15:09 ZHomeSlice

Yeah I understood the line uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13 and what I meant is that although I have a mpu6050, it was picking up 0x77 as SaveAddress, that doesn't work.

What works is 0x06.

0x77, if I got it correctly, is for the mpu6500.

Interestingly, reading the PDF page you mentioned, it seems that 0x06 is used by the 6500 when in MPU-6050 compatible mode...

A photo of my board: photo_2021-09-23_20-53-03

dentex avatar Sep 23 '21 19:09 dentex

0x06 is for the MPU's that use the 6050 gyro and accelerometer chip and the 0x77 is for the MPU's that use the 6500 chip the question is your MPU6050 device id isn't less than 38 so what is it? Z

ZHomeSlice avatar Sep 24 '21 01:09 ZHomeSlice

the question is your MPU6050 device id isn't less than 38 so what is it?

As I wrote here is 0x68.

dentex avatar Sep 24 '21 13:09 dentex

According to the code provided by Jeff, We should see a 0x34 from the mpu6050

/** Verify the I2C connection.
 * Make sure the device is connected and responds as expected.
 * @return True if connection is valid, false otherwise
 */
bool MPU6050::testConnection() {
    return getDeviceID() == 0x34;
}
// WHO_AM_I register

/** Get Device ID.
 * This register is used to verify the identity of the device (0b110100, 0x34).
 * @return Device ID (6 bits only! should be 0x34)
 * @see MPU6050_RA_WHO_AM_I
 * @see MPU6050_WHO_AM_I_BIT
 * @see MPU6050_WHO_AM_I_LENGTH
 */
uint8_t MPU6050::getDeviceID() {
    I2Cdev::readBits(devAddr, MPU6050_RA_WHO_AM_I, MPU6050_WHO_AM_I_BIT, MPU6050_WHO_AM_I_LENGTH, buffer);
    return buffer[0];
}

Z

ZHomeSlice avatar Sep 24 '21 15:09 ZHomeSlice

For what it's worth, I only ever encountered the 0x68 byte in my tests and development usage, but that ended way back in 2012 or 2013. It's easily possible that there are other IDs at this point which apply even to the same devices--maybe newer hardware revisions or something--and I don't know about them. 😬

jrowberg avatar Sep 25 '21 02:09 jrowberg

It's easily possible that there are other IDs at this point which apply even to the same devices

Maybe the device's ID (and the chip model) can be made configurable? Since it's used in more than one place in the library... but now it's hardcoded.

dentex avatar Sep 25 '21 05:09 dentex

Register Map and Descriptions
Revision 4.0
-----------------------------------
Register 117 – Who Am I
Name: WHOAMI
Serial IF: READ
Reset value: 0x70
This register is used to verify the identity of the device. The contents of WHO_AM_I is an 8-bit device
ID. The default value of the register is 0x70 for MPU-6500. This is different from the I2C address of
the device as seen on the slave I2C controller by the applications processor. The I2C address of the
MPU-6500 is 0x68 or 0x69 depending upon the value driven on AD0 pin.

WHO_AM_I[6:1]   

The WHO_AM_I[6:1] represents 6 bits starting at bit 1 0b110100, 0x34

now if you go and get the older documentation

Register Map and Descriptions
Revision 2.1
---------------------------------
the register is `WHOAMI[7:0] 

the WHOAMI[7:0] represents 7 bits starting at bit 0 0b1101000, 0x68

#define MPU6050_WHO_AM_I_BIT 6 #define MPU6050_WHO_AM_I_LENGTH 6

/** Read multiple bits from an 8-bit device register.
 * @param devAddr I2C slave device address
 * @param regAddr Register regAddr to read from
 * @param bitStart First bit position to read (0-7)
 * @param length Number of bits to read (not more than 8)
 * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05)
 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
 * @return Status of read operation (true = success)
 */
int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) {
    // 01101001 read byte
    // 76543210 bit numbers
    //    xxx   args: bitStart=4, length=3
    //    010   masked
    //   -> 010 shifted
    uint8_t count, b;
    if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) {
        uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
        b &= mask;
        b >>= (bitStart - length + 1);
        *data = b;
    }
    return count;
}

How it works :)

#define MPU6050_WHO_AM_I_BIT        6
#define MPU6050_WHO_AM_I_LENGTH     6

The start bit is 6 with a length of 6 76543210 Bit positions 01111110 is created by uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); ?110100X // Value stored in the MPU6050 read only WHO_AM_I register bit 7 I assume is zero X changes depending upon pin AD0 state 01101000 Stored in variable b with the line b &= mask; See: https://www.arduino.cc/reference/tr/language/structure/bitwise-operators/bitwiseand/ 00110100 shifted by 1 to the right b >>= (bitStart - length + 1);
0b110100 == 0x34 or decimal value of 52

So the max the WHO_AM_I value could be is 0b111111 which would equal the decimal value of 63 or 0x3F

now I have a question: MPU6050_WHO_AM_I_LENGTH = ? this should be 6 MPU6050_WHO_AM_I_BIT = ? this should be 6 Z

ZHomeSlice avatar Sep 26 '21 01:09 ZHomeSlice

I have a chip with a DeviceID of 0xC, and setting SaveAddress to 0x77 makes calibration work correctly. Because of this, it may be worth replacing uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13; with uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 && getDeviceID() != 0xC)? 0x06:0x77):0x13;

I only have one of these 0xC chips to test with, so I am not able to check whether this change works for other chips like this. If anyone else has some of these, could you please test this change?

andreigerashchenko avatar Jan 29 '23 21:01 andreigerashchenko

I have been sitting with this for a while now and I cannot get past the CalibrateGyro function. So I would be grateful if someone had some insight in what I can do. Some info what I have done:

  • I have the MPU6050 flat on the table with the text up.
  • It is able to get past the CalibrateAccel.
  • Thee DeviceID is 0x34.
  • When I check the eSum values in the MPU6050.cpp, it goes from 30 000 -> 6 000 and the jumps up to 30 000 again. I tried changing the c-value to 500, but it does not help as the the values seem to be periodic.
  • When I run the MPU6050_raw, I get consistent values of "a/g: 20 -156 16464 2318 372 32767"

adamahl avatar Apr 04 '23 12:04 adamahl

I am facing an issue: by singing the same code, a few MPU6050 are getting calibrated and a few don't I change the value from replacing uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13; with uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 && getDeviceID() != 0xC)? 0x06:0x77):0x13;

it started the calibration but it led nowhere can anyone help me with this (https://github.com/andreigerashchenko) I am adding some screenshots related to that. Screenshot 2023-07-03 at 3 59 20 PM Screenshot 2023-07-03 at 4 06 40 PM

Prathamesh08glovatrix avatar Jul 03 '23 10:07 Prathamesh08glovatrix