Hello, Everyone, I created this to get a better starting point with my MPU6050 and MPU9250. It works GREAT!!!
I would like your testing feedback and advice to improve this.
Why I changed from Luis's work.
Luis Ródenas' original sketch would calculate offsets after averaging them together which gets close... But we can't quite get there.
I found that Luis' code could be improved. I am using direct feedback through the MPU's firmware to test settings and improve upon the last test. Each pass tightens up the results. after a little over 400 readings which is less than 3.5 seconds, we are almost there. +-2 (Example: offset of 100 +-2) from the best we can get.
This program uses a simple PI (PID Proportional, Integral Dirivitive) to make changes after each sample I repeat this process with smaller PID multipliers allowing for quick a fine-tuning of the results with almost identical results each time I try.
Everything quickly switches to floating point numbers during calculations for more accurate feedback through the PI loop.
Simplified MPU6050 PI loop (Clipped from my attached program):
while(x){
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
az = az - 16384; //remove Gravity
a[0] = ax;
a[1] = ay;
a[2] = az;
g[0] = gx;
g[1] = gy;
g[2] = gz;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Other Cheching stuff here
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* PI of PID Calculations */
for (int i = 0; i < 3; i++) { // PI Calculations
Error[i] = Setpoint - g[i];
PTerm[i] = kPGyro * (float)GyroTuneDirection * Error[i];
ITerm[i] += Error[i] * 0.002 * (kIGyro * (float)GyroTuneDirection); // Integral term 1000 Calculations a second = 0.001
gyro_offset[i] = (PTerm[i] + ITerm[i]); //Compute PID Output
Error[i + 3] = Setpoint - a[i] ;
PTerm[i + 3] = kPAccel * (float)AccelTuneDirection * Error[i + 3];
ITerm[i + 3] += Error[i + 3] * 0.002 * (kIAccel * (float)AccelTuneDirection); // Integral term 1000 Calculations a second = 0.001
accel_offset[i] = (PTerm[i + 3] + ITerm[i + 3] ); //Compute PID Output
}
// Set and Store Values
setOffset(round(accel_offset[0] / 8), round(accel_offset[1] / 8), round(accel_offset[2] / 8), round(gyro_offset[0] / 4), round(gyro_offset[1] / 4), round(gyro_offset[2]) / 4);
}
void setOffset(int ax_, int ay_, int az_, int gx_, int gy_, int gz_) {
mpu.setXAccelOffset(ax_);
mpu.setYAccelOffset(ay_);
mpu.setZAccelOffset(az_);
mpu.setXGyroOffset(gx_);
mpu.setYGyroOffset(gy_);
mpu.setZGyroOffset(gz_);
}
Some insights:
I discovered that you could simply start off with this and get a 100% improvement in your readings
How to make a Quick and dirty tuning that will get you closer than factory settings:
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // Get a single Set of readings while on a flat surface
az = az - 16384; //remove Gravity
mpu.setXAccelOffset(-(ax >> 3)); // Invert and Divide by 8 (1000B (8) >> 3 = 0001B (1))
mpu.setYAccelOffset(-(ay >> 3));
mpu.setZAccelOffset(-(az >> 3));
mpu.setXGyroOffset(-(gx >> 2)); // Invert and Divide by 4 (1000B (8) >> 2 = 0010B (2))
mpu.setYGyroOffset(-(gy >> 2));
mpu.setZGyroOffset(-(gz >> 2));
I discovered that you can change the offsets at any time and then get a reading with shifted/updated results!
With this in mind, we can use direct feedback to calibrate our MPU6050 and tune it to perfection!!!
Now that I'm close, I run a PI (of the PID) routine with a stepping routine (Smaller Corrections) that softens the PI loop slowing changes to help land the offsets quickly.
Please Enjoy.
Z
UPDATE!
Added MPU6050_calibration_Z_V2_3.ino This updated version provides a super quick calibration and averages 10 calibrations together to get in my opinion an excelent set of offsets.
MPU6050_calibration_Z_V2.1.ino (13.1 KB)
MPU6050_calibration_Z_V2_3.ino (16.1 KB)