MPU 9250 Calibration functions

Ive come across some potentially useful calibration commands for the MPU 9250 9DOF accelerometer that are not working as I think they should.
Im using the MPU9250-master library (MPU9250.h) on an Arduino Mega. The ifdefs for the Teensy have been commented out.

My program simply exercises the loadCalibration and saveCalibration routines from the "emprom_utils.h" library. There are no errors but the mag scale and bias values that come back after a "loadCalibration" are not the values from the saveCalibration.

Could it be the Mega is unable to use eeprom_utils do you see a problem ?

The code:

#include "MPU9250.h"
#include "eeprom_utils.h"
#include <SoftwareSerial.h>
#include <SabertoothSimplified.h>

MPU9250 mpu;
SoftwareSerial SWSerial(NOT_A_PIN, 4); //declare the Pin 4 to be used to communicate with Sabertooth
SabertoothSimplified ST(SWSerial); //open a serial COM on previously identified pin
int foo =1;


void setup()
{
    Serial.begin(115200);

    Wire.begin();
    SWSerial .begin(9600);
    delay(2000);
    mpu.setup(Wire);
    // load from eeprom
    Serial.println("LOAD calibration 3");
    loadCalibration();
    
    delay(2000);
    Serial.println("print init calibration 1");
    mpu.printCalibration();
    Serial.println(" ");    
    
    // calibrate 
    mpu.calibrateAccelGyro();
    mpu.calibrateMag();
    delay(1000);
    
    // save to eeprom
    Serial.println("SAVE calibration 2");
    saveCalibration();
    Serial.println("print calibration 2");
    mpu.printCalibration();  
    Serial.println(" ");    
           
    // load from eeprom
    Serial.println("LOAD calibration 3");
    loadCalibration();
    Serial.println("print calibration 3");
    mpu.printCalibration();
    


}

void loop()
{


}

OUTPUT:

MPU9250 WHO AM I = 71
MPU9250 is online...
AK8963 WHO AM I = 48
Calibration values:
X-Axis sensitivity adjustment value 1.22
Y-Axis sensitivity adjustment value 1.23
Z-Axis sensitivity adjustment value 1.18
X-Axis sensitivity offset value 0.00
Y-Axis sensitivity offset value 0.00
Z-Axis sensitivity offset value 0.00
LOAD calibration 3
calibrated? : NO
load default values
print init calibration 1
< calibration parameters >
accel bias [g]:
5.00, -8.00, -1.00
gyro bias [deg/s]:
1.50, -0.50, 0.70
mag bias [mG]:
186.41, -197.91, -425.55
mag scale []:
1.07, 0.95, 0.99

MPU9250 bias
x y z
-86 -37 -11 mg
-0.9 0.3 0.8 o/s
Mag Calibration: Wave device in a figure eight until done!
mag x min/max:
196
-77
mag y min/max:
179
-76
mag z min/max:
108
53
Mag Calibration done!
AK8963 mag biases (mG)
108.16, 93.79, 141.04
AK8963 mag scale (mG)
0.71, 0.76, 3.58
SAVE calibration 2
print calibration 2
< calibration parameters >
accel bias [g]:
-86.91, -37.84, -11.17
gyro bias [deg/s]:
-0.95, 0.25, 0.84
mag bias [mG]:
108.16, 93.79, 141.04
mag scale []:
0.71, 0.76, 3.58

LOAD calibration 3
calibrated? : NO
load default values
print calibration 3
< calibration parameters >
accel bias [g]:
5.00, -8.00, -1.00
gyro bias [deg/s]:
1.50, -0.50, 0.70
mag bias [mG]:
186.41, -197.91, -425.55
mag scale []:
1.07, 0.95, 0.99

buckstucky:
Ive come across some potentially useful calibration commands for the MPU 9250 9DOF accelerometer that are not working as I think they should.
Im using the MPU9250-master library (MPU9250.h) on an Arduino Mega. The ifdefs for the Teensy have been commented out.

My program simply exercises the loadCalibration and saveCalibration routines from the "emprom_utils.h" library. There are no errors but the mag scale and bias values that come back after a "loadCalibration" are not the values from the saveCalibration.

Could it be the Mega is unable to use eeprom_utils do you see a problem ?

The magnetometer offsets are stored in the AK8963 as read-only

ASAX 10H READ X-axis sensitivity adjustment value 8 Fuse ROM
ASAY 11H READ Y-axis sensitivity adjustment value 8 Fuse ROM
ASAZ 12H READ Z-axis sensitivity adjustment value 8 Fuse ROM

I am interested in how you are using the Magnetometer.
Where is this library located MPU9250.h Send me a link. I will like to see and test what you are having problems with.

I have created a calibration routine that works well with the MPU9250 for the Gyro and Accel

Modified calibration code should work with just the I2Cdev library My Full code is here

//***************************************************************************************
//**********************           Calibration Routines            **********************
//***************************************************************************************
/**
@brief      Fully calibrate Gyro from ZERO in about 6-7 Loops 600-700 readings
*/

// For MPU9250 and MPU6500
void CalibrateGyro(uint8_t Loops ) {
	double kP = 0.3;
	double kI = 90;
	float x;
	x = (100 - map(Loops, 1, 5, 20, 0)) * .01;
	kP *= x;
	kI *= x;
	PID( 0x43,  kP, kI,  Loops);
	Serial.println();
}

/**
@brief      Fully calibrate Accel from ZERO in about 6-7 Loops 600-700 readings
*/

void CalibrateAccel(uint8_t Loops ) {
	float kP = 0.3;
	float kI = 20;
	float x;
	x = (100 - map(Loops, 1, 5, 20, 0)) * .01;
	kP *= x;
	kI *= x;
	PID( 0x3B, kP, kI,  Loops);
	Serial.println();
}

Simple_MPU6050 & Simple_MPU6050::PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops) {
	uint8_t SaveAddress = (ReadAddress == 0x3B)? 0x77:0x13;
	int16_t Data;
	float Reading;
	int16_t BitZero[3];
	uint8_t shift =(SaveAddress == 0x77)?3:2;
	float Error, PTerm, ITerm[3];
	int16_t eSample;
	uint32_t eSum ;
	Serial.write('*');
	for (int i = 0; i < 3; i++) {
		I2Cdev::readWords(devAddr, SaveAddress + (i * shift), 1, &Data); // reads 1 or more 16 bit integers (Word)
		Reading = Data;// Convert int to float;
		if(SaveAddress != 0x13){
			BitZero[i] = Data & 1; // Capture Bit Zero to properly handle Accelerometer calibration
			ITerm[i] = ((float)Data) * 8;
		} else {
			ITerm[i] = ((float)Data) * 4;
		}
	}
	for (int L = 0; L < Loops; L++) {
		eSample = 0;
		for (int c = 0; c < 100; c++) {// 100 PI Calculations
			eSum = 0;
			for (int i = 0; i < 3; i++) {
				I2Cdev::readWords(devAddr, ReadAddress + (i * 2), 1, &Data); // reads 1 or more 16 bit integers (Word)
				Reading = Data;// Convert int to float;
				if ((ReadAddress == 0x3B)&&(i == 2)) Reading -= 16384;  //remove Gravity
				Error = -Reading; // PID is reverse
				eSum += (Reading < 0) ? Error : Reading; //only want Positive Numbers
				PTerm = kP * Error;
				ITerm[i] += (Error * 0.001) *  kI; // Integral term 1000 Calculations a second = 0.001
				if(SaveAddress != 0x13){ //Accellerometer
					Data = round((PTerm + ITerm[i] ) / 8);
					if(abs(Error) > 400){
						if((L+c) == 0){
							Data = 0;
							ITerm[i] = Data;
						}else if((L == 0) && (c == 1)){
							Data = Error / 8;
							ITerm[i] = Data;
						}
					}
					Data = ((Data)&0xFFFE) |BitZero[i]; // Insert Bit0 Saved at beginning
				} else Data = round((PTerm + ITerm[i] ) / 4); // Gyro
				I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1,  &Data);
			}
			if((c == 99) && eSum > 1000){
				c = 2;
				Serial.write('-');
			}
			if((eSum * ((ReadAddress == 0x3B)?.05: 1)) < 5) eSample++;// Test to see if we are really close!
			if((eSum < 100) && (c > 10) && (eSample >= 10)) break; // We have 10 really Close Calculations Cycle to Next loop
			delay(1);
		}
		Serial.write('.');
		kP *= .75;
		kI *= .75;
	}
	for (int i = 0; i < 3; i++){
		if(SaveAddress != 0x13) {
			Data = round((ITerm[i] ) / 8); //Compute PID Output
			Data = ((Data)&0xFFFE) |BitZero[i];  // Insert Bit0 Saved at beginning
		} else Data = round((ITerm[i]) / 4);
		I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1, &Data );
		// by Using ITerm value only for the final offset prevents the last reading from having and
		// influence on the offsets

	}
}

First thank you for the reply, it seems that the save calibration function as you have mentioned, does not save any thing . Take a look in the example mind you I modified it for the mega , Here is the library:
I m going to try to run your code as soon as I send this.
See attachment.

MPU9250-master.zip (23.5 KB)

buckstucky:
First, thank you for the reply, it seems that the save calibration function as you have mentioned does not save any thing. Take a look in the example mind you I modified it for the mega, Here is the library:
I m going to try to run your code as soon as I send this.
See attachment.

I also modified this library as it doesn't use the I2Cdev library
Added my calibration code as well as the supporting functions readWord and writeWord functions.
use the CalibrateGyro and CalibrateAccel functions first
then use the PrintActiveOffsets function
this will spit out:
// X Accel Y Accel Z Accel X Gyro Y Gyro Z Gyro
#define OFFSETS 123, 123, 123, 123, 123, 123
Place the #define at the top of your code
Now you can use my setOffset( OFFSETS ) ;

MPU9250 mpu;
//               X Accel  Y Accel  Z Accel   X Gyro   Y Gyro   Z Gyro
#define OFFSETS      0,      0,       0,         0,      0,       0      // replace with Your New Offsets

//.... other code....
// place this in you code where you would like the offsets to be set. 
// Note that offsets can be changed at any time and they have emediate affect on the output.
mpu.setOffset(OFFSETS);

// Remove following lines once your offsets are used above
// Each cycle tightens the PID parameters to smooth the landing of the ideal offsets.
// At some point additional loops will have no affect on the offsets.
// except for the first cycle(which could take more than 100 readings Prints a dash) Each cycle may take up to 100 reading. 
// if you only get is dashes for output (*------) your MPU error from setpoint (0) is greater than 1000 your MPU is probibly not level and the PID calibration loop can't find offsets to work.
// Periods represent calibration loops are happening (*---...............) with the settings below you should see 15 periods.
// Depending on the MPU's initial error the first cycle may take several hundered cycles before the actual calibration cycles start.
// At any point if the error is minimul, additional readings may be skipped to speed up calibration by skipping to the next cycle..
mpu.CalibrateAccel(15);// 15 cycles is excellent more or less may or maynot inprove final calibration. 
mpu.CalibrateAccel (15); // 15 cycles
mpu.PrintActiveOffsets();

Z
The attached code is NOT tested for compiling errors nor have I test it with your program and I may have made a typo or two. These errors should be minimal as I just adapted my working code to fit the template. I will be happy to help correct any compilation errors.

MPU9250.h (48.5 KB)