i2cdevlib
i2cdevlib copied to clipboard
MPU6050 ACC Calibration does never finish
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
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
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?
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
- gravity is removed and the initial loop attempts to tidy up the values before refining the PID Kp and Ki values.
- 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
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).
@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.
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 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.
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
@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 :)
@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 :)
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.
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
.
@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 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
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 "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
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.
Why no end
Same here: CalibrateAccel
hangs forever...
But CalibrateGyro
works.
>......
Gyro Offsets:
65061
87
13
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
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
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:
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
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
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. 😬
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.
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
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?
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"
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.