MPU-9250 Attitude Heading Reference System AHRS. Calibration and Data Readings

OK guys, this is a tricky one.....ive been on it for days and am running into more and more stones, so im sure this will be interesting to anyone trying to work an AHRS.

What i have so far is an MPU9250 running on an Arduino Nano via I2C and a Kris Winer Code, only adopted to accept my MPU on another I2C adress (0x73 iso 0x71). Data is put out via serial to SerialPlot.
For those unfarmiliar with his code, it has many calibration options, bias settings and other things coded that accually make it rather easy to use. BUT.....i'm not at all happy with my results.

(I have also downloaded the Bolder Flight code, but it does not provide pitch and roll and yaw indications.)

Setup: The sensor is mounted to a box to enable better rotation around the corners of the block.

Orientation: x North, y West, flat on table.
Value readings: Pitch 0, Roll 0, Heading -70 (So far so good, only heading somewhere else)

Moving the sensor around fixed y-axis -> Pitching up x-axis to 45deg

Expecting: Pitch 45, Roll 0, Heading -70
Actual: Pitch 0, Roll 45, Heading +90

Observation: Slight jitter in X axis despite multiple smooth tries. Heading jumps parallel to roll significantly. After setting the sensor back to level the heading drifts slowly back to original value.

Next move:

Moving the sensor around fixed x-axis -> Rolling y-axis to 45deg

Expecting: Pitch 0, Roll 45, Heading -70
Actual: Pitch 45, Roll 0, Heading -20

Observation: Virtually no jitter on x axis, this is probably induced by me moving it. Heading moves instantaneous and in paralell.

Next move:

Putting the sensor with X pointing straight up and Y pointing west.

Expecting: Pitch 90, Roll 0, Heading ?
Actual: Pitch 0, Roll 90, Heading drifting at 20 deg/s

I have then turned the sensor 90deg westward and repeated.
Expecting: Pitch 0, Roll 0, Heading -160
Actual: Pitch 0, Roll 0, Heading +20

Moving the sensor around fixed y-axis -> Pitching up x-axis to 45deg

Expecting: Pitch 45, Roll 0, Heading +20
Actual: Pitch 0, Roll 45, Heading +50

Observation: Same as before. Heading is severly less influenced than when facing north.

Last move:

Moving the sensor around fixed x-axis -> Rolling y-axis to 45deg

Expecting: Pitch 0, Roll 45, Heading +20
Actual: Pitch 45, Roll 0, Heading 0

Observation: Same as before. Heading is severly less influenced than when facing north.


What do i take from this? Heading seems to work in 90 degree steps for the tested orientations. It is not calibrated "Facing North". However it is severely influenced by pitching and rolling motions. Influence varies with actual heading.

Pitch and Roll are changed according to labeling.

Is this a calibration issue or a code issue? The calibration according code has been performed.....

What does "a Kris Winer Code" mean? Post your code, using code tags.

The sensor has to be calibrated in the environment in which it is used. If it is properly calibrated and there are no magnetic fields or iron-containing materials nearby, yaw should read 0 degrees when the sensor is flat on the table and X is pointing to magnetic North. That is not the case, so it is not properly calibrated. Did you use magnetized or steel screws to mount the sensor?

If you then rotate the sensor about the Z axis, flat on the table, the yaw output should move smoothly from 0 to 359 degrees (unless you have neglected to properly perform the -180 to 180 conversion).

Putting the sensor with X pointing straight up and Y pointing west.

Look up "gimbal lock". This is a known problem with any angular system of orientation, and why quaternions are commonly used to represent body orientation.

Finally, keep in mind that there are six different definitions of Euler angles, and two ways to define a positive rotation. The order of applying rotations about axes matters!

To make sense out of what the sensor is reporting, you MUST know which definitions the software is using.

Kris Winer has published a library for the MPU-9250. You can cet the full library and examples through the arduino library management. It can be found searching "Sparkfun MPU-9250" as the only result.

It can also be found here on github:

I am using this library almost unchanged so far.
I believe it also works with quarternions, as it includes a such called library.

I have found out the heading deflection error. Just a designation issue (90 deg off), which also caused the swapping of roll and pitch. It now shows heading correctly if moved just in one plane. Also pitch and roll are now displayed according designation.

Pitch and Roll still remain with their strong influence on each other and on heading.

The code i am using is included in the samples and is called the MPU-9250BasicAHRS_I2C
It exceeds the the 9000 character limit, please take it from the library.

Environment: It is currently mounted on a cardboard box using paper tape. It is on an otherwise empty table in my dining room, sitting 10" (25cm) from the arduino and about twice that distance from my laptop.

Tried as attachment…

MPU9250.cpp (36.3 KB)

MPU9250.h (10.6 KB)

MPU9250BasicAHRS_I2C.ino (20.7 KB)

It would be a great idea to read through the material on Kris Winer's web pages, so that you have some basic understanding of what you are doing. Also please go through this primer, so that you understand Euler angles.

Pitch and Roll still remain with their strong influence on each other and on heading.

Of course they do. The angles interact, and the order that the rotations are performed MATTERS.

A rotation of 90 degrees about X, followed by a rotation of 90 degrees about Y, results in a completely different orientation than rotating by Y then X. In order to understand the results of the AHRS, you MUST understand the basic definitions of the angular system and the order in which the operations are applied.

Note that this program line overrides any magnetometer calibration you might have performed:

   // Get magnetometer calibration from AK8963 ROM
    myIMU.initAK8963(myIMU.factoryMagCalibration);

and, you don't execute any other calibration routines, because that line is commented out. So, your magnetometer is not properly calibrated.

    // The next call delays for 4 seconds, and then records about 15 seconds of
    // data to calculate bias and scale.
//    myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale);

That was a good step......but also increased my confusion.

First of all i have un-commented the magCal line, so it does run through the full routine. since the initAK order comes before the magCal, it should be overruled by the calibration routine? My heading indications in just one plane are accually quite usable, so i cant be all that bad.....

Ive tried to figure out how the eulers and quartenions work exactly. I think i understand the basic functions, but the math behind it needs a bulb that is brighter than mine is. Rotational matrixes quickly let me disconnect.
What i have found out: Euler angles make sense for smaller pitch and roll values, but get worse towards the vertical. Here it can only be overcome by using quarternions. Quarternions can be converted to eulers, but the gimbal lock problem persists.

My guess is that the Winer code is doing this in this code part:

  MahonyQuaternionUpdate(myIMU.ax, myIMU.ay, myIMU.az, myIMU.gx * DEG_TO_RAD,
                         myIMU.gy * DEG_TO_RAD, myIMU.gz * DEG_TO_RAD, myIMU.my,
                         myIMU.mx, myIMU.mz, myIMU.deltat);


    myIMU.delt_t = millis() - myIMU.count;



      myIMU.count = millis();


      myIMU.yaw   = atan2(2.0f * (*(getQ()+1) * *(getQ()+2) + *getQ()
                    * *(getQ()+3)), *getQ() * *getQ() + *(getQ()+1)
                    * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) - *(getQ()+3)
                    * *(getQ()+3));
      myIMU.pitch = -asin(2.0f * (*(getQ()+1) * *(getQ()+3) - *getQ()
                    * *(getQ()+2)));
      myIMU.roll  = atan2(2.0f * (*getQ() * *(getQ()+1) + *(getQ()+2)
                    * *(getQ()+3)), *getQ() * *getQ() - *(getQ()+1)
                    * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) + *(getQ()+3)
                    * *(getQ()+3));
      myIMU.pitch *= RAD_TO_DEG;
      myIMU.yaw   *= RAD_TO_DEG;

      myIMU.yaw  -= 0;
      myIMU.roll *= RAD_TO_DEG;


       // Serial.print("Yaw, Pitch, Roll: ");
        Serial.print(myIMU.yaw, 2);
        Serial.print(", ");
        Serial.print(myIMU.pitch, 2);
        Serial.print(", ");
        Serial.println(myIMU.roll, 2);

One of my first parts of confusion is the Quarternion matrix, which sequences ax, ay, az, gx, gy, gz, but then proceeds with my, mx and mz....i dont make much sense of that. Changing it to x,y, and z sequence does not improve anything, it just makes the drifting of the heading after pitching slower.

My understanding of the code is that it should output not euler angles, but actual angles. See also this in the code:

Define output variables from updated quaternion---these are Tait-Bryan
// angles, commonly used in aircraft orientation. In this coordinate system,
// the positive z-axis is down toward Earth. Yaw is the angle between Sensor
// x-axis and Earth magnetic North (or true North if corrected for local
// declination, looking down on the sensor positive yaw is counterclockwise.
// Pitch is angle between sensor x-axis and Earth ground plane, toward the
// Earth is positive, up toward the sky is negative. Roll is angle between
// sensor y-axis and Earth ground plane, y-axis up is positive roll. These
// arise from the definition of the homogeneous rotation matrix constructed
// from quaternions. Tait-Bryan angles as well as Euler angles are
// non-commutative; that is, the get the correct orientation the rotations
// must be applied in the correct order which for this configuration is yaw,
// pitch, and then roll.
// For more see
// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
// which has additional links.

Bottom line: i still cant figure out where the mistake is.
I have found this on youtube: Open Source IMU and AHRS Algorithm with x-IMU - YouTube
I followed the link towards a code which i have also found in modified form in the other mpu thread by Idahowalker. It contains a mahoney quarternion.....but....how do i take data from this?

My understanding of the code is that it should output not euler angles, but actual angles.

There is no such thing as "actual angles", just different conventions for applying rotations, and all angle systems have the same basic problems, such as gimbal lock.

If the output of the AHRS is useful to you, like determining which direction the craft is moving, or if it is level, great.

jremington:
There is no such thing as "actual angles", just different conventions for applying rotations, and all angle systems have the same basic problems, such as gimbal lock.

If the output of the AHRS is useful to you, like determining which direction the craft is moving, or if it is level, great.

Thats the point: the output is not useful, and i dont understand why, because the description says it should be.
The description is stating that heading is the difference between the x axis towards north. This should be totally free of influence of rotation around this axis, but it is not. Theres a significant impact. So my best guess is that the code itself is wrong, my sensor deliveres in another convention or scaling as the code works with, or my calibration is crap. Either way i am not progressing at all, so im looking for help.

Lets try putting my question in other words:
I want to try to get a small artificial horizon to function in a model airplane. It will be driven by stepper motors, all controlled by the arduino. The data origin should be my MPU.
What i need as output:

Pitch value: Angle between X Axis and Ground reference plane. Should be 0 sitting level, increasing to 90 when going vertical, and returning back down to 0 transitioning to "inverted".
Aditionally i will need a true/false statement if the z axis is above or below the horizon (sensor inverted/upright)

Roll value: Angle between Y Axis and Ground reference plane. Should be 0 for level, moving to 180 rolling to inverted the one way, then "jumping" to -179 for further roll, returning back to zero. Will be blocked out near vertical pitch and replaced with a stepper rule for the motors according to the true/false statement from pitch.

Heading value: Angle between projected X Axis onto Ground reference plane, in relation to magnetic north. Scale from 0 to 359, then jumping back to 0. With pitch close to 90, replaced by projected Z axis to magnetic north.

The Question is: If i have the quaternion code running, what do i need to do to find an angle between any axis and any plane, without having influence from other axis motions?

Heading value: Angle between projected X Axis onto Ground reference plane, in relation to magnetic north.

Suppose the X axis is along the aircraft body and the aircraft is flying straight up. What is the heading?

what do i need to do to find an angle between any axis and any plane, without having influence from other axis motions?

Please explain how you define the axis and the plane.

So my best guess is that the code itself is wrong, my sensor deliveres in another convention or scaling as the code works with, or my calibration is crap.

Please post your current code, post the results of the sensor calibration, and the output of the code for the sensor held in one or more well defined orientations.

The "How to use this forum" post gives clear advice on how to take best advantage of the forum.

jremington:
Suppose the X axis is along the aircraft body and the aircraft is flying straight up. What is the heading?
Please explain how you define the axis and the plane.

Idea: Flying straight up (Pitch >= 89deg or so) i freeze roll, and replace heading by Z-axis projection onto ground plane. This should solve gimbal lock and give rotation info going vertical.

Axis/plane definition:
ground plane: x-y-plane of aircraft sitting straight and level on ground
z-axis: perpendicular to ground plane of airplane on ground, tied to aircraft on ground
x-axis: nose to tail axis
y-axis: wingtip-to-wingtip

I am purposely asking for a general conversion recipie, so i can calculate any (dynamic) axis to any (static) plane, and not just copy and paste. I am however not smart enough to work out the 4 dimensional math myself…

jremington:
Please post your current code, post the results of the sensor calibration, and the output of the code for the sensor held in one or more well defined orientations.

Current code attached, output of the calibration routine:

MPU9250 I AM 0x73 I should be 0x71
MPU9250 is online…
x-axis self test: acceleration trim within : 0.2% of factory value
y-axis self test: acceleration trim within : 3.8% of factory value
z-axis self test: acceleration trim within : 9.1% of factory value
x-axis self test: gyration trim within : -3.4% of factory value
y-axis self test: gyration trim within : -1.3% of factory value
z-axis self test: gyration trim within : -0.9% of factory value
MPU9250 initialized for active data mode…
AK8963 I AM 0x48 I should be 0x48
AK8963 initialized for active data mode…
X-Axis factory sensitivity adjustment value 1.21
Y-Axis factory sensitivity adjustment value 1.21
Z-Axis factory sensitivity adjustment value 1.16
Mag Calibration: Wave device in a figure 8 until done!
4 seconds to get ready followed by 15 seconds of sampling)
Mag Calibration done!
AK8963 mag biases (mG)
-121.26
-222.61
-225.15
AK8963 mag scale (mG)
0.99
1.16
0.89
Magnetometer:
X-Axis sensitivity adjustment value 1.21
Y-Axis sensitivity adjustment value 1.21
Z-Axis sensitivity adjustment value 1.16

StepperWithMPU9250.ino (9.62 KB)

Currently sitting ober the stuff i am getting from my sensor and not stepping ahead....

Does anyone have Experience with MovSens LLC and their Track IMU?

It looks great on youtube and on the homepage, BUT: the codes that are referenced are no longer available, and their TrackIMU software is not installable. Error 1925 insufficient rights. Try again as Administrator (I am god on my laptop....)

Their software seems to be a great way to convert IMU data to the orientation, and might help me figure out how conversion works....

Does anyone have it running? Or had experience or contact?

If you don't mind spending some dollars, then VectorNav has worked well for me. But that is a device good enough to use as the input for an autopilot.

"Some dollars" is a relative term. If its aviation grade stuff it gets expeeensive fast. I'm looking at no more than $100 im willing to spend on the entire project....thats why i went for arduino and breakout boards.
They look like they will blow that budget just on connectors :slight_smile:

Since i dont want to threadjack another one, im pulling this one back up.

Thanks to jremington and his superb analysis the sensor is now working perfectly. Now i have 2 more topics to work out:

-First is the calibration. It has been emphasized a lot how important the calibration is. I have noticed too that without the calibration run, or when calibrating without moving the sensor, the results are fairly useless. The BNO055 sensor uses a continuous datastream to capture and maintain calibration. On the Code for the MPU9250 i can only find the startup-calibration.
Is it possible to once do the full calibration on all sensors, and then save the values either to the eeprom, or embed them in the code? So a full new calibration in the same environment will not be neccessary again? My sensor will be installed in a rather large, bulky and heavy airplane. Hauling it in circles and figure eights will be hard enough to do once, but at each powerup is not what i want to do long-term.

And the second question concerns the much-feared gimbal-lock:
-Once passing about 80-85deg pitch, the roll and heading readings become hypersensitive and jumpy, which is logical. In order to overcome this on my 3-axis controlled horizon, i will need to implement a logic that will lock one of the signals in place, and put the second signal under control of an alternative rotation source. My selected solution is to use the same function that produces heading.....just on another axis. With x pointing nearly straight up, both y and z operate near the horizon line, and should output a very good roll indication.
Now the big question: How can i modify the quarternion heading formula to output the same reading as "yaw", just using the Z instead of X axis?

myIMU.yaw = atan2(2.0f * (*(getQ()+1) * *(getQ()+2) + *getQ()

  • *(getQ()+3)), *getQ() * *getQ() + *(getQ()+1)
  • *(getQ()+1) - *(getQ()+2) * *(getQ()+2) - *(getQ()+3)
  • *(getQ()+3));

This does it for X.....

save the values either to the eeprom, or embed them in the code

Both are easy and about equivalent.

How can i modify the quarternion heading formula to output the same reading as "yaw", just using the Z instead of X axis?

The only option is to go through the math and write a new conversion formula. The easiest way to do that is to permute the sensor axes appropriately (using right handed operations), which requires a clear understanding of how those axes are defined with respect to the Earth in the original code: X = magnetic North, Y = West, Z = Up.

Note that the magnetometer in the MPU-9250 has different axial assignments than the accel/gyro, and both have to be swapped differently (while continuing to agree with the Earth reference above).

OK, i think i've solved the gimbal situation. What i wanted to do mechanically by deactivating either yaw or roll axis can be done mathmatically, by having one of the 2 values maintain its last reading, and the other working on a combination of the 2 jumpy readings (addition upon pitch-up, subtraction upon pitch-down). This produces smooth signals for the remaining channel of the gimbal.

I've started to work on the calibration memory, and have read my way into the eeprom.read and write functions, but am not all too clear about what values i really need to store.
My idea is as follows:
-I want to start the IMU reading only the calibration values stored in the EEPROM, and use these. Upun pressing a button, a new calibration routine should start, taking the current values of the accelerometers, doing a new series of 8s for the magnetic readings, and saving that calibration data in the eeprom for future startups. Then restart using these new values.
Reason for this: I can orient the model straight and level for calibration, and on future startups it can be sitting in any attitude on the ground and still find the correct "level" position. For axample a taildragger airplane (P-51, F-4U Corsair, P-40 Kittyhawk...) will usually start up in a nose-high attitude....

After studying the calibration routine i BELIEVE i have all values that are set in the routine:

gyroBias[0,1,2]
gyroScale[0,1,2]

accelBias[0,1,2]
accelScale[0,1,2]

magBias[0,1,2]
magScale[0,1,2]

Am i missing something?

OK, accelScale and gyroScale dont exist in that designation, but it works pretty well with the other values.

I am now having issues storing them on the eeprom.
The numbers i am getting are floats in the range of +/-300.00 (2 decimal values)
I need to store 12 of them…while i have no issues reading and writing whole numbers 0-255, i cannot get a float to eeprom and back, nonoftheless 12 of them.

This is the code i have tried now:

#include <EEPROM.h> 

float number1 = 12345.789;
float number2 = -985.4321;

//This function will write a 4 byte (32bit) float to the eeprom at
//the specified address to adress + 3.
void EEPROMWritefloat(int address, float value)
      {
      //Decomposition from a float to 4 bytes by using bitshift.
      //One = Most significant -> Four = Least significant byte
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);

      //Write the 4 bytes into the eeprom memory.
      EEPROM.write(address, four);
      EEPROM.write(address + 1, three);
      EEPROM.write(address + 2, two);
      EEPROM.write(address + 3, one);
      }

//This function will return a 4 byte (32bit) float from the eeprom
//at the specified address to adress + 3.
float EEPROMReadfloat(long address)
      {
      //Read the 4 bytes from the eeprom memory.
      long four = EEPROM.read(address);
      long three = EEPROM.read(address + 1);
      long two = EEPROM.read(address + 2);
      long one = EEPROM.read(address + 3);

      //Return the recomposed long by using bitshift.
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
      }

void setup()
      {
      Serial.begin(9600);
      }

void loop()
      {
      //Adding a delay in order to have the time to open the
      //Arduino serial monitor.
      delay(5000);

      //Starting at the first byte on the eeprom.
      long address=0;

      //Writing first long.
      EEPROMWritefloat(address, number1);
      address+=4;
      //Writing second long.
      EEPROMWritefloat(address, number2);
      address+=4;


      Serial.println("If numbers are equals, it's working !");
      Serial.print(number1);
      Serial.print(" and ");
      //Readind and sending first long.
      Serial.println(EEPROMReadfloat(0));

      Serial.print(number2);
      Serial.print(" and ");
      //Readind and sending second long.
      Serial.println(EEPROMReadfloat(4));
      }

OK i have been able to partially solve my problem.....but have opened up a totally new problem!

I am now using EEPROMPut and EEPROMGet to write the calibration data to the eeprom.

void calibrate() {


  myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);
  myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale);

  EEPROM.put(0, myIMU.accelBias[0]);
  EEPROM.put(4, myIMU.accelBias[1]);
  EEPROM.put(8, myIMU.accelBias[2]);
  
  EEPROM.put(16, myIMU.gyroBias[0]);
  EEPROM.put(24, myIMU.gyroBias[1]);
  EEPROM.put(32, myIMU.gyroBias[2]);
  
  EEPROM.put(40, myIMU.magBias[0]);
  EEPROM.put(48, myIMU.magBias[1]);
  EEPROM.put(56, myIMU.magBias[2]);
  
  EEPROM.put(64, myIMU.magScale[0]);
  EEPROM.put(72, myIMU.magScale[1]);
  EEPROM.put(80, myIMU.magScale[2]);

 
  
}

This code is run ONLY if a calibration is asked, and should put the cal data on the EEPROM.
During normal startup, i set the values using this code in the "setup":

EEPROM.get(0, myIMU.accelBias[0]);   //0.13;
EEPROM.get(4, myIMU.accelBias[1]);   //0.11;
EEPROM.get(8, myIMU.accelBias[2]);   //-0.05;

EEPROM.get(16, myIMU.gyroBias[0]);   //0.36;
EEPROM.get(24, myIMU.gyroBias[1]);   //-0.12;
EEPROM.get(32, myIMU.gyroBias[2]);   //-0.89;

EEPROM.get(40, myIMU.magBias[0]);   //-63.34;
EEPROM.get(48, myIMU.magBias[1]);   //-251.56;
EEPROM.get(56, myIMU.magBias[2]);   //-225.15;

EEPROM.get(64, myIMU.magScale[0]);   //1.17;
EEPROM.get(72, myIMU.magScale[1]);   //0.99;
EEPROM.get(80, myIMU.magScale[2]);   //0.88;

Commented out you see the values i am expecting, which are usually the results of calibration.

If i serialprint my biases and scales i get following readback:

0.14
0.10
-0.05
0.38
-0.11
-1.00
5559.74
5833.02
5623.62
nan
nan
nan

As you can see the Gyro and Accel Biases read in OK, the mag bias and mag scale output total nonsense.

Can anyone see where i went wrong?
Are the outputs of mag not float?

jremington, this might be another problem for you....

I was able to localize the problem:

The library order myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias); works fine when i put it in a seperate void order as described in my most recent post.

If i do the same with the myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale); , it delivers:

Mag Calibration: Wave device in a figure 8 until done!
4 seconds to get ready followed by 15 seconds of sampling)
Mag Calibration done!
AK8963 mag biases (mG)
5559.74
5833.02
5623.62
AK8963 mag scale (mG)
nan
nan
nan

The same holds true if i take the basic code from the SparkFun Library, and put the myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale); in an if clause.

int cal=1;

if (cal=1) {

  myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale);
      Serial.println("AK8963 mag biases (mG)");
    Serial.println(myIMU.magBias[0]);
    Serial.println(myIMU.magBias[1]);
    Serial.println(myIMU.magBias[2]);

    Serial.println("AK8963 mag scale (mG)");
    Serial.println(myIMU.magScale[0]);
    Serial.println(myIMU.magScale[1]);
    Serial.println(myIMU.magScale[2]);

  cal=0;
}

Baam, i get the same nonsense readings. Nothing changes, except the if clause. As soon as the MagCal is not run in the root setup, it delivers nonsene!

One thing i did notice:

The myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias) order shows up in orange in the IDE just like a regular order does. The myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale) stays all black. I suppose it is not recognized as a valid order and this is also a reason why it is not working? Another bug?

OK im about ready to give up.

As a last resort i tried copying the code of the magCal order into the calibrate function. This apparently corrupted the entire library, and nothing is working anymore. It now sends compiling errors…

Attached modified library…(code exceeds 9000 signs again)

MPU9250.cpp (40.2 KB)

MPU9250.h (10.6 KB)