1

Board: ESP32

Script: restore_offsets.ino from Adafruit's BNO055 library

The only difference is I am storing the information in ESP's NVS using the Preferences Library

Code

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <Preferences.h>


/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (1000)

Adafruit_BNO055 bno = Adafruit_BNO055(1390);

Preferences Calibration;

/**************************************************************************/
/*
    Display some basic info about the sensor status
    */
/**************************************************************************/
void displaySensorStatus(void)
{
    /* Get the system status values (mostly for debugging purposes) */
    uint8_t system_status, self_test_results, system_error;
    system_status = self_test_results = system_error = 0;
    bno.getSystemStatus(&system_status, &self_test_results, &system_error);

    /* Display the results in the Serial Monitor */
    Serial.println("");
    Serial.print("System Status: 0x");
    Serial.println(system_status, HEX);
    Serial.print("Self Test:     0x");
    Serial.println(self_test_results, HEX);
    Serial.print("System Error:  0x");
    Serial.println(system_error, HEX);
    Serial.println("");
    delay(500);
}

/**************************************************************************/
/*
    Display sensor calibration status
    */
/**************************************************************************/
void displayCalStatus(void)
{
    /* Get the four calibration values (0..3) */
    /* Any sensor data reporting 0 should be ignored, */
    /* 3 means 'fully calibrated" */
    uint8_t system, gyro, accel, mag;
    system = gyro = accel = mag = 0;
    bno.getCalibration(&system, &gyro, &accel, &mag);

    /* The data should be ignored until the system calibration is > 0 */
    Serial.print("\t");
    if (!system)
    {
        Serial.print("! ");
    }

    /* Display the individual values */
    Serial.print("Sys:");
    Serial.print(system, DEC);
    Serial.print(" G:");
    Serial.print(gyro, DEC);
    Serial.print(" A:");
    Serial.print(accel, DEC);
    Serial.print(" M:");
    Serial.print(mag, DEC);
}

/**************************************************************************/
/*
    Display the raw calibration offset and radius data
    */
/**************************************************************************/
void displaySensorOffsets(const adafruit_bno055_offsets_t &calibData)
{
    Serial.print("Accelerometer: ");
    Serial.print(calibData.accel_offset_x); Serial.print(" ");
    Serial.print(calibData.accel_offset_y); Serial.print(" ");
    Serial.print(calibData.accel_offset_z); Serial.print(" ");

    Serial.print("\nGyro: ");
    Serial.print(calibData.gyro_offset_x); Serial.print(" ");
    Serial.print(calibData.gyro_offset_y); Serial.print(" ");
    Serial.print(calibData.gyro_offset_z); Serial.print(" ");

    Serial.print("\nMag: ");
    Serial.print(calibData.mag_offset_x); Serial.print(" ");
    Serial.print(calibData.mag_offset_y); Serial.print(" ");
    Serial.print(calibData.mag_offset_z); Serial.print(" ");

    Serial.print("\nAccel Radius: ");
    Serial.print(calibData.accel_radius);

    Serial.print("\nMag Radius: ");
    Serial.print(calibData.mag_radius);
}


/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
    */
/**************************************************************************/
void setup(void)
{
    Wire.begin(13, 16, 400000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("Orientation Sensor Test"); Serial.println("");

    /* Initialise the sensor */
    if (!bno.begin())
    {
        /* There was a problem detecting the BNO055 ... check your connections */
        Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
        while (1);
    }

    Calibration.begin("offsets", false);
    adafruit_bno055_offsets_t calibrationData;
    sensor_t sensor;

    int32_t bnoID = Calibration.getInt("bnoID");
     bool foundCalib = false;
    /*
    *  Look for the sensor's unique ID at the beginning oF EEPROM.
    *  This isn't foolproof, but it's better than nothing.
    */
    bno.getSensor(&sensor);
    if (bnoID != sensor.sensor_id)
    {
        Serial.println("\nNo Calibration Data for this sensor exists in NVS");
        delay(500);
    }
    else
    {
        Serial.println("\nFound Calibration for this sensor in NVS.");

        // Accelerometer offsets
        calibrationData.accel_offset_x = Calibration.getInt("acc_off_x");
        calibrationData.accel_offset_y = Calibration.getInt("acc_off_y");
        calibrationData.accel_offset_z = Calibration.getInt("acc_off_z");

        // Gyroscrope offsets
        calibrationData.gyro_offset_x = Calibration.getInt("gyr_off_x");
        calibrationData.gyro_offset_y = Calibration.getInt("gyr_off_y");
        calibrationData.gyro_offset_z = Calibration.getInt("gyr_off_z");

        // Magnetometer offsets
        calibrationData.mag_offset_x = Calibration.getInt("mag_off_x");
        calibrationData.mag_offset_y = Calibration.getInt("mag_off_y");
        calibrationData.mag_offset_z = Calibration.getInt("mag_off_z"); 

        displaySensorOffsets(calibrationData);

        Serial.println("\n\nRestoring Calibration data to the BNO055...");
        bno.setSensorOffsets(calibrationData);

        Serial.println("\n\nCalibration data loaded into BNO055");
        foundCalib = true;
    }

    delay(1000);

    /* Display some basic information on this sensor */
//    displaySensorDetails();

    /* Optional: Display current status */
    displaySensorStatus();

   //Crystal must be configured AFTER loading calibration data into BNO055.
    bno.setExtCrystalUse(true);

    sensors_event_t event;
    bno.getEvent(&event);
    if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }
    else
    {
        Serial.println("Please Calibrate Sensor: ");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);

            Serial.print("X: ");
            Serial.print(event.orientation.x, 4);
            Serial.print("\tY: ");
            Serial.print(event.orientation.y, 4);
            Serial.print("\tZ: ");
            Serial.print(event.orientation.z, 4);

            /* Optional: Display calibration status */
            displayCalStatus();

            /* New line for the next sample */
            Serial.println("");

            /* Wait the specified delay before requesting new data */
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

    Serial.println("\nFully calibrated!");
    Serial.println("--------------------------------");
    Serial.println("Calibration Results: ");
    adafruit_bno055_offsets_t newCalib;
    bno.getSensorOffsets(newCalib);
    displaySensorOffsets(newCalib);

    Serial.println("\n\nStoring calibration data to NVS...");

    bno.getSensor(&sensor);
    bnoID = sensor.sensor_id;
    // enter the Sensor ID
    Calibration.putInt("bnoID", bnoID);

    // store new Accelerometer offsets
    Calibration.putInt("acc_off_x", newCalib.accel_offset_x);
    Calibration.putInt("acc_off_y", newCalib.accel_offset_y);
    Calibration.putInt("acc_off_z", newCalib.accel_offset_z);

    // store new Gyroscope offsets
    Calibration.putInt("gyr_off_x", newCalib.gyro_offset_x);
    Calibration.putInt("gyr_off_y", newCalib.gyro_offset_y);
    Calibration.putInt("gyr_off_z", newCalib.gyro_offset_z);

    // store new Magnetometer offsets
    Calibration.putInt("mag_off_x", newCalib.mag_offset_x);
    Calibration.putInt("mag_off_y", newCalib.mag_offset_y);
    Calibration.putInt("mag_off_z", newCalib.mag_offset_z);
    Serial.println("Data stored to NVS..");

    Serial.println("\n--------------------------------\n");
    delay(500);
}

void loop() {
    /* Get a new sensor event */
    sensors_event_t event;
    bno.getEvent(&event);

    /* Display the floating point data */
    Serial.print("X: ");
    Serial.print(event.orientation.x, 4);
    Serial.print("\tY: ");
    Serial.print(event.orientation.y, 4);
    Serial.print("\tZ: ");
    Serial.print(event.orientation.z, 4);

    /* Optional: Display calibration status */
    displayCalStatus();

    /* Optional: Display sensor status (debug only) */
    displaySensorStatus();

    /* New line for the next sample */
    Serial.println("");

    /* Wait the specified delay before requesting new data */
    delay(BNO055_SAMPLERATE_DELAY_MS);
}

The only difference in the code is instead of passing the offset struct I save information individually using putInt method

steps

  1. I calibrate the sensor connected via I2C
  2. Once the calibration is done store it into NVS
  3. Observe values for a bit
  4. Restart the node and retreive the offsets from NVS

Problem

The calibration offsets are stored into the BNO and it takes hella time in the following block:

   if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

I added the displayCalStatus to see the values of the accelerometer, gyroscope and magnetometer and all values within the block are Zero.

Doesn't this defy the whole idea of storing offsets in the first place if the values are all zero?

Output from board

Found Calibration for this sensor in NVS.
Accelerometer: 19 -10 4 
Gyro: -3 -4 9 
Mag: 589 986 1473 
Accel Radius: 0
Mag Radius: 0

Restoring Calibration data to the BNO055...


Calibration data loaded into BNO055

System Status: 0x0
Self Test:     0xF
System Error:  0x0

Move sensor slightly to calibrate magnetometers
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0

As you can observe the calibration are all set to 0 and I have to do the whole thing again. why ?

  • Should we assume that there are non-zero calibration offsets that are returned, that they are correctly saved in NVS, and that they are correctly retrieved from NVS? Have you verified all of that, so that the only issue is that you are certain that you "saved" non-zero offests to the sensor and it's still returning zero offsets when read back? – jose can u c Oct 12 '18 at 13:07
  • I can assure you that the values are non-zero. I am pretty sure the values retreived are also non-zero from NVS. However I can perform tests again and edit the question with more concrete values to support the assumption. – Shan-Desai Oct 12 '18 at 13:11
  • I only ask because concrete values are the only way members of the community have to evaluate the problem. – jose can u c Oct 12 '18 at 13:13
  • 1
    I will get back at reproducing the query and edit the question with all relevant outputs from the node and bno055 – Shan-Desai Oct 12 '18 at 13:17
  • @josecanuc I have added the log from my board – Shan-Desai Oct 16 '18 at 12:37
1
+50

The displayCalStatus() function shows the status of the calibration, not the offsets or current sensor values. With calibration in progress the status is zero. Once the calibration of a sensor is complete, the status is 3. The sensor starts the calibration itself with first movements after power up.

The set offsets are used after power-up only until the initial automatic calibration finished.

from datasheet:

Once the device is calibrated, the calibration profile can be reused to get the correct orientation data immediately after ‘Power of Reset’. However, once the sensor enters the internal calibration routine, the calibration profile is overwritten with the newly obtained sensor offsets and sensor radius.

  • Is there way to avoid entering the internal calibration routine of the BNO055? – Shan-Desai Oct 19 '18 at 9:09
  • no. why is it a problem for you? it happens in the background. the sensors work all the time. the remembered offsets are good to have better values for first readings – Juraj Oct 19 '18 at 9:18
  • The problem is that once the offsets are restored, I calibrate the magnetometer because it is very easy, but the while loop doesn't come out easily. I have to do all the calibration techniques all together. – Shan-Desai Oct 19 '18 at 9:34
  • 1
    but in your sketch you can do what you want. the offsets sketch is an example. I would ignore the calibration. The sensor handles it. After power-up make same movements and the sensor calibrates itself. – Juraj Oct 19 '18 at 9:41
  • I think I will give give your stuff a try. – Shan-Desai Oct 19 '18 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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