Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Reliably reloading the calibration data of IMU BNO055

  1. #1
    Junior Member
    Join Date
    May 2019
    Posts
    14

    Reliably reloading the calibration data of IMU BNO055

    Hi all,
    I am using the BNO055 IMU and the Adafruit Library.
    I want to store the calibration data and load them after the microcontroller is powered off and repowered on.
    The Adafruit Library provides an example for storing and restoring but, in actual facts, it does not work. It is always required to recalibrate the magnetometers, but even doing so, the library reperform the whole calibration including the accelerometers.

    I would like to simply restore all the calibration data (including the magnetometers) so that no calibration needs to be performed when the IMU starts.

    I have read a massive amount of posts on the argument, but I really could not figure out how to reliably load all the calibration data at boot and avoid recalibrating them.

    Is there anyone who succeeded and can please share the code?

  2. #2
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,299
    Take a look at the example sketch "restore_offsets.ino".

    That example sketch stores the calibration data in the Teensy EEPROM if the calibration data is not already stored and if it is will reload it. Good place to start.

  3. #3
    Junior Member
    Join Date
    May 2019
    Posts
    14
    I am indeed using that. It does not work, you always need to reperform the whole calibration. If I load the saved calibration stored in the EEPROM then I get readings from the IMU which are noisy and random. I need to reperform the calibration, and I want to avoid this step. Can you share your code by any chance?

  4. #4
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,299
    Well can you give me a bit more information. What Teensy are you using? You know it might not be the calibration but the environment you are in. Also not sure what you mean by noisy and random? Is the "noisy-random" from looking at data from the restore_offsets.ino sketch. One of the basic rules of the forum is to post your code, i.e., is the problem with the that particular sketch. The code I use is exactly what you see in that sketch. Are you getting the message back "Fully calibrated!" and data stored to EEPROM?

  5. #5
    Junior Member
    Join Date
    May 2019
    Posts
    14
    Quote Originally Posted by mjs513 View Post
    Well can you give me a bit more information. What Teensy are you using? You know it might not be the calibration but the environment you are in. Also not sure what you mean by noisy and random? Is the "noisy-random" from looking at data from the restore_offsets.ino sketch. One of the basic rules of the forum is to post your code, i.e., is the problem with the that particular sketch. The code I use is exactly what you see in that sketch. Are you getting the message back "Fully calibrated!" and data stored to EEPROM?
    I am using a Teensy 3.6, but the same happens for Teensy 3.2 and Arduino Uno. There is no issue with magnetic interference in my environment, I am simply using the sensor on a wooden table for the moment. By noisy-random I mean that the data start to float randomly, without any reference to the calibrated values one should expect. Yes I get the message Fully Calibrated and the data stored in the EEPROM, but as I said, after power off and power on the Teensy, when restoring the calibration I get random values that do not certainly relate to the correct orientation from the IMU when was calibrated before power off.

  6. #6
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,722
    Quote Originally Posted by frodojedi View Post
    I am using a Teensy 3.6, but the same happens for Teensy 3.2 and Arduino Uno.
    Since it does the same thing on an Arduino Uno, if you have not already done so, you might try asking about this up on the Adafruit forum...

    You might also mention things like, what version of Arduino you are using and on what... Likewise what version of Teensyduino?

    Is your library up to date with Adafruit? Are you using the Adafruit BNO055 (https://www.adafruit.com/product/2472)?

    Have you looked at Adafruit's page on device calibration? https://learn.adafruit.com/adafruit-...ce-calibration

    I have one sitting on my desk now, but I have not personally gone through all of the steps, as mainly had it to be able to test Wire library with T4, but...

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,722
    Quick update: Did you look at the FAQ page for the device? https://learn.adafruit.com/adafruit-...on-sensor/faqs


    FAQs
    by Kevin Townsend
    Can I manually set the calibration constants?

    Yes you can save and restore the calibration of the sensor, check out the restore_offsets example: https://github.com/adafruit/Adafruit_BN ... ffsets.ino

    One thing to keep in mind though is that the sensor isn't necessarily 'plug and play' with loading the calibration data, in particular the magnetometer needs to be recalibrated even if the offsets are loaded. The magnetometer calibration is very dynamic so saving the values once might not really help when they're reloaded and the EMF around the sensor has changed.

    For further details check out the datasheet and Bosch's info on the sensor for calibration info: https://www.bosch-sensortec.com/en/h...055_1/bno055_4

  8. #8
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,299
    Just tried the restore_offset sketch on the Teensy 4.0.

    On initial calibration when calibration is completed I see this:
    Code:
    Fully calibrated!
    
    --------------------------------
    
    Calibration Results: 
    
    Accelerometer: 9 -78 -5 
    Gyro: 0 -1 -1 
    Mag: -199 240 -39 
    Accel Radius: 1000
    Mag Radius: 660
    
    Storing calibration data to EEPROM...
    
    Data stored to EEPROM.
    Now if I power off and power on again:
    Code:
    Orientation Sensor Test
    Chip ID
    Switch Mode
    BNO055_SYS_TRIGGER_ADDR
    
    Found Calibration for this sensor in EEPROM.
    
    Accelerometer: 9 -78 -5 
    Gyro: 0 -1 -1 
    Mag: -199 240 -39 
    Accel Radius: 1000
    Mag Radius: 660
    
    Restoring Calibration data to the BNO055...  //Ok data stored
    
    Calibration data loaded into BNO055  // ok data transferred from EEPROM to BNO055
    ------------------------------------
    Sensor:       BNO055
    
    Driver Ver:   1
    Unique ID:    55
    Max Value:    0.00 xxx
    Min Value:    0.00 xxx
    Resolution:   0.01 xxx
    
    ------------------------------------
    
    System Status: 0x5
    Self Test:     0xF
    System Error:  0x0
    
    Move sensor slightly to calibrate magnetometers  //This is normal per the Adafruit API.
    //See @KurtE's post on mag calibration
    
    Fully calibrated!   //Mag is recalibrated on each load. 
    
    --------------------------------
    Calibration Results: 
    
    Accelerometer: 9 -78 -5 
    Gyro: 0 -1 -1 
    Mag: -199 240 -39 
    Accel Radius: 1000
    Mag Radius: 684
    
    Storing calibration data to EEPROM...    //Resaves cal data to eeprom.  
    
    Data stored to EEPROM.
    --------------------------------
    X: 125.0000	Y: 1.4375	Z: 2.6250	Sys:3 G:3 A:3 M:3
    X: 125.0000	Y: 1.4375	Z: 2.6250	Sys:3 G:3 A:3 M:3

  9. #9
    Junior Member
    Join Date
    May 2019
    Posts
    14
    Hi, thanks. Of course the answer is yes to everything. With that code when you repower on the Teensy you need to redo the WHOLE calibration, not just the magnetometers. I am asking simply to have the data loaded from EEPROM that guarantee (in absence of any magnetic interference around the sensor) the same calibrated behaviour that happened before powering it off. I am using the latest version of Teensyduino and Adafruit library.

  10. #10
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,299
    en you repower on the Teensy you need to redo the WHOLE calibration, not just the magnetometers.
    What I posted showed that all its doing is recalibrating the magnetometer when you power up. Which is just moving the sensor slightly on power up.

    As for your other question on stability data of the BNO055 after power up maybe that is a better question for the Adafruit forum.

    For reference this is the function I am using to initial the BNO055 after I upload the calibration data to the BNO055. Its a modification of the their examples.

    Code:
    void BNO055_Init() {
      
        delay(1000);
        telem.println("Orientation Sensor Test"); telem.println("");
    
        /* Initialise the sensor */
        if (!bno.begin())
        {
            /* There was a problem detecting the BNO055 ... check your connections */
            telem.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
            while (1);
        }
    
        int eeAddress = 0;
        long bnoID;
        bool foundCalib = false;
    
        EEPROM.get(eeAddress, bnoID);
    
        adafruit_bno055_offsets_t calibrationData;
        sensor_t sensor;
    
        /*
        *  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)
        {
            telem.println("\nNo Calibration Data for this sensor exists in EEPROM");
            delay(500);
        }
        else
        {
            telem.println("\nFound Calibration for this sensor in EEPROM.");
            eeAddress += sizeof(long);
            EEPROM.get(eeAddress, calibrationData);
    
            displaySensorOffsets(calibrationData);
    
            telem.println("\n\nRestoring Calibration data to the BNO055...");
            bno.setSensorOffsets(calibrationData);
    
            telem.println("\n\nCalibration data loaded into BNO055");
            foundCalib = true;
        }
    
        delay(1000);
    
        /* Display some basic information on this sensor */
        displaySensorDetails();
    
        /* Optional: Display current status */
        displaySensorStatus();
    
        bno.setExtCrystalUse(true);
    
        sensors_event_t event;
        bno.getEvent(&event);
        if (foundCalib){
            telem.println("Move sensor slightly to calibrate magnetometers");
            while (!bno.isFullyCalibrated())
            {
                bno.getEvent(&event);
                delay(BNO055_SAMPLERATE_DELAY_MS);
            }
        }
        else
        {
            telem.println("Please Calibrate Sensor: ");
            while (!bno.isFullyCalibrated())
            {
                bno.getEvent(&event);
    
                telem.print("X: ");
                telem.print(event.orientation.x, 4);
                telem.print("\tY: ");
                telem.print(event.orientation.y, 4);
                telem.print("\tZ: ");
                telem.print(event.orientation.z, 4);
    
                /* Optional: Display calibration status */
                displayCalStatus();
    
                /* New line for the next sample */
                telem.println("");
    
                /* Wait the specified delay before requesting new data */
                delay(BNO055_SAMPLERATE_DELAY_MS);
            }
        }
    
        telem.println("\nFully calibrated!");
        telem.println("--------------------------------");
        telem.println("Calibration Results: ");
        adafruit_bno055_offsets_t newCalib;
        bno.getSensorOffsets(newCalib);
        displaySensorOffsets(newCalib);
    
        telem.println("\n\nStoring calibration data to EEPROM...");
    
        eeAddress = 0;
        bno.getSensor(&sensor);
        bnoID = sensor.sensor_id;
    
        EEPROM.put(eeAddress, bnoID);
    
        eeAddress += sizeof(long);
        EEPROM.put(eeAddress, newCalib);
        telem.println("Data stored to EEPROM.");
    
        telem.println("\n--------------------------------\n");
        delay(500);
        
    }
    
    void displaySensorDetails(void)
    {
      sensor_t sensor;
      bno.getSensor(&sensor);
      telem.println("------------------------------------");
      telem.print  ("Sensor:       "); telem.println(sensor.name);
      telem.print  ("Driver Ver:   "); telem.println(sensor.version);
      telem.print  ("Unique ID:    "); telem.println(sensor.sensor_id);
      telem.print  ("Max Value:    "); telem.print(sensor.max_value); telem.println(" xxx");
      telem.print  ("Min Value:    "); telem.print(sensor.min_value); telem.println(" xxx");
      telem.print  ("Resolution:   "); telem.print(sensor.resolution); telem.println(" xxx");
      telem.println("------------------------------------");
      telem.println("");
      delay(500);
    }
    
    /**************************************************************************/
    /*
        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 telem Monitor */
      telem.println("");
      telem.print("System Status: 0x");
      telem.println(system_status, HEX);
      telem.print("Self Test:     0x");
      telem.println(self_test_results, HEX);
      telem.print("System Error:  0x");
      telem.println(system_error, HEX);
      telem.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 */
      telem.print("\t");
      if (!system)
      {
        telem.print("! ");
      }
    
      /* Display the individual values */
      telem.print("Sys:");
      telem.print(system, DEC);
      telem.print(" G:");
      telem.print(gyro, DEC);
      telem.print(" A:");
      telem.print(accel, DEC);
      telem.print(" M:");
      telem.print(mag, DEC);
    }
    
    /**************************************************************************/
    /*
        Display the raw calibration offset and radius data
        */
    /**************************************************************************/
    void displaySensorOffsets(const adafruit_bno055_offsets_t &calibData)
    {
        telem.print("Accelerometer: ");
        telem.print(calibData.accel_offset_x); telem.print(" ");
        telem.print(calibData.accel_offset_y); telem.print(" ");
        telem.print(calibData.accel_offset_z); telem.print(" ");
    
        telem.print("\nGyro: ");
        telem.print(calibData.gyro_offset_x); telem.print(" ");
        telem.print(calibData.gyro_offset_y); telem.print(" ");
        telem.print(calibData.gyro_offset_z); telem.print(" ");
    
        telem.print("\nMag: ");
        telem.print(calibData.mag_offset_x); telem.print(" ");
        telem.print(calibData.mag_offset_y); telem.print(" ");
        telem.print(calibData.mag_offset_z); telem.print(" ");
    
        telem.print("\nAccel Radius: ");
        telem.print(calibData.accel_radius);
    
        telem.print("\nMag Radius: ");
        telem.print(calibData.mag_radius);
    }
    I think this will give you the idea.

  11. #11
    Junior Member
    Join Date
    May 2019
    Posts
    14
    Quote Originally Posted by mjs513 View Post
    I think this will give you the idea.
    Hi, your code is basically identical to the one of the examples of Adafruit. Anyways I found the solution. It is enough to add a function that when reperfoming the calibration of the magnetometer, checks ONLY if the magnetometer is calibrated (while the calibration for the accelerometer and gyroscope is reloaded from the EEPROM).

    Code:
    void performMagCal(void) {
      
      uint8_t system, gyro, accel, mag;
      system = gyro = accel = mag = 0;
     
      while (mag != 3) {
        
        bno.getCalibration(&system, &gyro, &accel, &mag);
        displayCalStatus();
        Serial.println("");
      }
      
      Serial.println("\nMagnetometer calibrated!");
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •