I bought the BNO055 "smart" IMU from Adafruit, thinking it would be a simple way to get orientation data for a small mobile robot project, but I've found the thing to be very difficult to use and nearly worthless.

It's advertised as being able to auto-calibrate, and although it does attempt to do this, I've found that the calibration doesn't hold. It continuously re-calibrates itself, and either gets stuck in an error state or find a successful calibration...but then loses it after a few seconds.

Is there anything I can do to improve its stability? Does it need to be mounted inside a special grounded housing? Is there a special incantation I should utter before powering it on?

I'm reading it from an Arduino Uno via I2C, and though the wiring and programming is relatively simple, getting it calibrated and staying calibrated I've found to be nearly impossible.

Even after the "system" flag says its fully calibrated, and I have the IMU just sitting on a table, not moving, after a minute, it loses its "system" calibration. The accelerometer, gryoscope, and magnetometer usually remain calibrated, but how can I trust them if the on-board fusion algorithm is reporting it's not ready?

If the BNO055 is a lost cause, is there anything better? I've tried several MPU-**** chips from InvenSense, but they're even worse.

  • did you follow the calibration procedure?
    – jsotola
    Jan 9, 2018 at 6:34

1 Answer 1


Try a permanent calibration. From the Adafruit forums:

You'd basically need to read and write data registers 55-6A. In both cases, you have to set the sensor in CONFIG_MODE. There's more information on page 48 of the datasheet.

The magnetometer is influenced by surrounding magnetic sources like motors. You might be able to tell the extent of the effect using the following method:

The System Calibration Status will start out at 0 and will go to 3 when the sensor is calibrated. For example, the mag calibration status will go to 3 if you do some figure 8s. If you put a piece of metal near the sensor, the calibration status will drop to 0. But when the metal is moved away, it will go back to 3. You may be able to use this value as an indicator that calibration is lost. I have found that once it's calibrated, it seems to hold calibration well.

For getting solid readings out of the gyroscope, this might be helpful advice:

I don't worry about scaling the gyro output on a per-sample basis. I simply sum the output into a 32 bit (or larger) integer register. I do subtract-out a null value at each sample, which I will talk about later. But essentially, if you sample your gyro at 1kHz, and sum the output into an accumulator, you will see that the value of that accum at any time will be directly proportional the angle of rotation. If your rate is set for 250 deg/sec, then a rotation of 180 deg will result in approximately 23330000 in the accumulator. I call that the GYRO_CAL number. So, at any given time the angle, in degrees, is deg = accum / GYRO_CAL * 180.

Since the gyro output is linear, the accumulator is insensitive to whether the rotation is fast or slow (as long as the max deg/sec isn't exceeded).

Here is my basic routine for each gyro reading:

void read_FIFO(){ sample = read_value_from_FIFO(); //read the latest z-axis sample. I use the fifo, but that isn't necessary accum += sample - null; //add the sample to the sum and subtract the null if((accum > GYRO_CAL) -= GYRO_CAL*2; //roll the accumulator at +180 deg. if((accum < -GYRO_CAL) += GYRO_CAL*2; // roll the accumulator at -180 deg. angle = accum/GYRO_CAL * 180; // convert to degrees }

I calculate the null at the beginning of each run. I sum 1000 readings and take the average. The gyro has to sit still for 3 or 4 seconds for this. The GYRO_CAL value can be calculated by summing the output while you rotate the gyro by 180 deg. Or you can sum over many turns, and divide by the number of 180 deg turns for a more accurate value.

You could probably use a 64-bit FP for the accumulator, but since arduino only supports 32 bit FP, I found it absolutely necessary to use a 32 bit integer to avoid roundoff and other errors.

If you follow that general outline, I promise you will get rock solid performance out of the gyro. There are a few other small optimizations that I make, which I can discuss later.

  • Unfortunately, there is no such feature as "permanent calibration" with the BNO055. Yes, once I obtain stable calibration parameters, I can save and later reload them. That's what that forum thread describes, and that's what I'm already doing. Unfortunately, the BNO055 continuously updates and re-calibrates itself, eventually losing these "good" values if the magnetometer encounters a little interference.
    – Cerin
    Jan 10, 2018 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.