I understand that the bno-055's internal autocalibration which runs in background cannot be switched off. I get massive heading drifting and after reading everything I could find about this I implemented my own routine to minimize this. I use the following steps in my algorithm:
1. Bno055 initialization
2. Calibration (in NDOF mode)
3. Write the calibration values (ACC, Gyro, Mag Offsets and Acc and Mag Radius bytes) in the microcontroller's (AVR) EEPROM for later use
4. find a stable position close to roll=0, pitch=0, yaw=0 on my table and log the readings
5. enter a loop where:
5.1. read the CALIB_STAT register and see if it is 0xFF (if not goto 5.1.1)
5.1.1. read EEPROM values of offsets and radii. Enter Bno055's ConfigMode. Write these saved calibration values. Reenter NDOF Mode. Blink a LED to indicate that the calib. values were reloaded.
5.2. read euler angles or raw data from sensors or whatever
I've noticed that whenever I write the offset and radius registers the CALIB_STAT register will show 0x00111111. This tells me according to the datasheet section 4.3.54 that the status of the Gyro, Acc and Mag is "calibrated" but the system's calibration status (bits 7:6) remains 0x00 "NOT CALIBRATED" . Why is that ?
What triggers the system's calibration ? According to the datasheet (same section) the status of the system calibration deppends on status of all other sensors. So why do I get 0x00111111 ? I used the value stored in this register as a trigger for reloading the initial calibration values. Eventually I made my condition: " is the current value <= Hex 3F ?" which ignores the bit 7 and 6. It works until now. But I still wanna know the reason for the described problem.
Also, would there be another method to detect when the offset and radius are getting messed up, instead of using the CALIB_Stat register ? I thought about reading only the MAG Offset and Radius cause obviously these are the most succeptible ones to distortions. This would mean only 8 read/compare/write operations instead of 22.
Another question: when going through the initial calibration process (NDOF Mode) I calibrate gyro first then the acc and the mag at the end of the routine. I'm using the calibration steps from the datasheet (and the youtoube video). After calibrating the gyro and the acc, the mag is almost always calibrated without having to do anymore movements (figure 8 or else).
If I wanna re-calibrate just one sensor, for instance the magnetometer, would this be possible ? Pause the data output, recalibrate, save the new offset/radius, resume data output.
Based on my experience of using BNO055, below are some comments.
Regarding the point of heading error and drift, there are a lot of factors which could contribute to this, due to the simple fact that the magnetic field is superposition of the earth magnetic field and many other sources of disturbances which are both unpredicatible and inconsistent in space and time. The fusion algorithm is continuously monitoring discrepancies caused by the volatile disturbances and when any such situation is detected, the calibration status is downgraded to indicate a need for calibration which is typically done through the well-known butterfly or figure-8 motions. Luckily, the algoirthm on BNO055 has a so-called FMC (Fast Mag Calibration) feature which makes this calibration much easier by elimiating the need for full figure 8 motions which might be challenging to do in certain cases. And hopefully this clarifies why there is not an option to turn off the "background calibration".
In the 9DoF sensor fusion, to reach optimal accuracy of the heading, each sensor need to be calibrated properly, and you are right that the system calibration depends on the calibration status of each sensor before it becomes HIGH status too, but even if the status of all the 3 sensors isHIGH it's not enough to establish a HIGH for the system calibration automatically, and I think it's because what the system calibration means is it's trying to fuse all sensors to work in concert and figure out any discrepancies before it's confident to say everything is working fine. For example, you might have reached a perfect calibration status at one location outdoors where the disturbances are minimal, and the calibration profiles are saved to the NVM, and when you move indoors, the superposed magnetic environment has changed dramatically, when you load the old (stale) magnetic calibration profile which has a status of HIGH, the fusion module cann't trust that right away, instead it fuses sensor data from 3 sensors together to see if all sensors can now work in concert and agreement with each other before the system calibration status could be set to HIGH. To reach a HIGH status of the system calibration, my expereince was that one simply needs to do some more mild movements of the board and in most cases, the HIGH status should be coming pretty quickly.
System calibration is running all the time in fusion lib as background routine.
When you switching to any working mode, the system calibration module starts to work and check the individual physical sensor calibration status then update its own status. If you just write all calibration parameters, not switching to any working mode, you can get system calibration level as 0.
You don't need to pause the data streaming. the calibration parameters can be read out even in any working mode.
So you can keep checking the calibration status of system calibration level and magnetic calibration level. When you found one of them drop from 3 then calibrated and back to 3 again, you can try to store all the calibration parameters for feature usage.
Thank you for your answers.
My system based on a bno055 still doesn't work as it should be. Here's a listing of my algorithm and the behaviour of the bno055 sensor.
'-------------------------------------------------------------------------------------- Call Bno_change_opr_mode(&B00000000) 'OPR_MODE= Config_mode Call Bno_change_pwr_mode(&B00000000) 'PWR Mode= Normal Waitms 200 'Select Use Ext.OSC / Perform Self Test Call Bno_write(sys_trigger , &B10000001) Waitms 1000 '====================================================================================== Call Bno_rd_unique_id Waitms 100 '-------------------------------------------------------------------------------------- 'Verify if the BNO-055 chip is present by reading Chip_id, Acc_id, Gyr_id and Mag_id 'and comparing them with the default values 'don't get out of the next loop until BNO-055 is detected While Chip_ok <> 1 Call Bno_check_chip Wend Call Bno_st_result 'Read Self_test_result Waitms 100 Call Bno_write(unit_sel , &B00000000) 'Calibration Print "starting calibration sequence.." Call Bno_change_opr_mode(&B00001100) 'OPR_MODE= Fusion_Nine_degree_of_freedom Call Bno_rd_calib_status Print "Calibrating Gyroscope " Waitms 500 While Gyr_calib_status <> 3 Call Bno_rd_calib_status Print " calib status: " ; Gyr_calib_status Waitms 250 Wend Print " Done !" Waitms 500 Print "Calibrating Accelerometer " Waitms 500 While Acc_calib_status <> 3 Call Bno_rd_calib_status Print " calib status: " ; Acc_calib_status Waitms 250 Wend Print " Done !" Waitms 500 Print "Calibrating Magnetometer " Waitms 500 While Mag_calib_status <> 3 Call Bno_rd_calib_status Print " calib status: " ; Mag_calib_status Waitms 250 Wend Print " Done !" Waitms 500 Print "Calibrating System " Waitms 500 While Sys_calib_status <> 3 Call Bno_rd_calib_status Print " calib status: " ; Sys_calib_status Waitms 250 Wend Print " Done !" Waitms 500 Print Print Call Bno_change_opr_mode(&B00000000) 'OPR_MODE= Config_mode Print "press Key2 to overwrite calibration values in EEPROM" While I <= 5 If Key2 = 0 Then Call Bno_rd_calib_profile Call Wr_eeprom_calib_profile I = 5 End If Waitms 500 Incr I Wend Print "Calibration successful !" Waitms 2000 Print "Reading Data..." Waitms 1000 Call Bno_change_opr_mode(&B00001100) 'OPR_MODE= Fusion_Nine_degree_of_freedom do Call Bno_recheck_calibration 'check Calibration to avoid drift in Acc/ Gyro/ Mag Call Bno_quat_2_roll_pitch_yaw 'Read & Convert Quaternions to Roll, Pitch, Yaw angles [dps] Waitms 20 loop end
Sub Bno_rd_calib_status If Reg_page <> 0 Then Call Bno_change_reg_page(0) 'change page_id I2cstart I2cwbyte Bno_wr_addr 'BNO-055 I2C WRITE address I2cwbyte Calib_stat 'Start from CALIB_STAT Register I2crepstart 'Repeat Start Condition I2cwbyte Bno_rd_addr 'BNO-055 I2C READ address I2crbyte Read_byte , Nack 'read EUL_Heading_MSB Calibration_status = Read_byte I2cstop Mag_calib_status.0 = Calibration_status.0 Mag_calib_status.1 = Calibration_status.1 Acc_calib_status.0 = Calibration_status.2 Acc_calib_status.1 = Calibration_status.3 Gyr_calib_status.0 = Calibration_status.4 Gyr_calib_status.1 = Calibration_status.5 Sys_calib_status.0 = Calibration_status.6 Sys_calib_status.1 = Calibration_status.7 End Sub Sub Bno_rd_calib_profile If Reg_page <> 0 Then Call Bno_change_reg_page(0) 'change page_id I2cstart I2cwbyte Bno_wr_addr 'BNO-055 I2C WRITE address I2cwbyte Acc_offset_x_lsb 'Start from ACC_OFFSET_X_LSB Register I2crepstart 'Repeat Start Condition I2cwbyte Bno_rd_addr 'BNO-055 I2C READ address 'Multiple Read: Reg &H55 to &H6A I2crbyte Read_byte , Ack 'read ACC_OFFSET_X_LSB Aox_l = Read_byte I2crbyte Read_byte , Ack 'read ACC_OFFSET_X_MSB Aox_m = Read_byte I2crbyte Read_byte , Ack 'read ACC_OFFSET_Y_LSB Aoy_l = Read_byte I2crbyte Read_byte , Ack 'read ACC_OFFSET_Y_MSB Aoy_m = Read_byte I2crbyte Read_byte , Ack 'read ACC_OFFSET_Z_LSB Aoz_l = Read_byte I2crbyte Read_byte , Ack 'read ACC_OFFSET_Z_MSB Aoz_m = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_X_LSB Mox_l = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_X_MSB Mox_m = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_Y_LSB Moy_l = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_Y_MSB Moy_m = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_Z_LSB Moz_l = Read_byte I2crbyte Read_byte , Ack 'read MAG_OFFSET_Z_MSB Moz_m = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_X_LSB Gox_l = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_X_MSB Gox_m = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_Y_LSB Goy_l = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_Y_MSB Goy_m = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_Z_LSB Goz_l = Read_byte I2crbyte Read_byte , Ack 'read GYR_OFFSET_Z_MSB Goz_m = Read_byte I2crbyte Read_byte , Ack 'read ACC_RADIUS_LSB Ar_l = Read_byte I2crbyte Read_byte , Ack 'read ACC_RADIUS_MSB Ar_m = Read_byte I2crbyte Read_byte , Ack 'read MAG_RADIUS_LSB Mr_l = Read_byte I2crbyte Read_byte , Nack 'read MAG_RADIUS_MSB. Last multiple Read operation send NACK Mr_m = Read_byte I2cstop End Sub Sub Bno_recheck_calibration ' Make sure the CALIB_STAT Register is ok ' if not reload the calibration values to avoid Acc/Gyro/Mag drift Call Bno_rd_calib_status If Calibration_status <= 62 Then 'calibration status is smaller than 0x00111111 'bit 7:6 (system calibration) are ignored here. Set Wled Call Rd_eeprom_calib_profile 'load calibration values from uC's EEPROM Call Bno_wr_calib_profile 're-write BNO-055 calibration values Call Bno_write(opr_mode , Ndof) 're-enter NDOF Fusion Mode Waitms 100 Reset Wled End If End Sub
Here's a short description of the BNO-055's behaviour:
After the initial calibration, I get correct values for the Roll, Pitch, Yaw angles (based on the quaternions). When the de-calibration occurs (usually Mag Offset and Radius) the microcontroller detects this and reloads all the calibration values (acc offset x,y,z / gyro offset x,y,z / mag offset x,y,z / acc radius x,y,z / mag radius x,y,z) from it's eeprom and writes them to the BNO's registers. I do change the operation mode to config before doing this. After reloading I change the operation mode back to NDOF Fusion, and from now on the problem begins.
I have a white LED which I use to indicate that the calibration values have been reloaded by shortly blinking once. It blinks more than 20 times then remains off for a few seconds, and then starts to blink again.
So the BNO gets his initial calibration values back but for some reason, the calibration status remains smaller than 00111111. You notice I ignore bits 6 and 7 (system calibration). It's like it won't accept the values.
I do my testing without moving the sensor too much. Sometimes it stays in the same position for a long time, nothing else is moving on the table or around it (no mag fields or other interferences) and it still becomes drifty ...
The worse part is that, the roll pitch yaw angles are false after reloading the calibration values. Not always but most of the time. Only a complete system reset would help.
So I keep the BNO board on the table, Yaw shows 150 degrees, 40 seconds later it decalibrates, I reload the calibration values several times .. because for some reason the calib_status won't get back to "11" from the first reload, and the yaw shows 24 degrees now and jumps all over the place.
Again this happens completely random.
Please help me solve this.
I tried at my side with following steps:
1. power on BNO055, after reset, power mode is normal by default.
2. switch to 9DoF mode
3. do the calibration movements and read the calibration status until it goes to 3
4. check the Euler sensor output which already have the heading, pitch, roll value as direct output
5. read out the calibration parameters (0x55 - 0x6A on page 0)
6. power reset the BNO055
7. switch to 9DoF mode, then try to read the calibration status, only gryo can goes to 3 if board is no moving.
8. switch back to configure mode, write back all the calibration parameters
9. switch back to 9DoF mode, then the calibration status are all 3
10. Read again the Euler sensor output, the output is correct (without drift and jumping)
So, from my test setup, everything looks fine. I can't reproduce your issue.
You can also compare your procedure in your code with my steps to see if you missed any step.
I found when you recheck the calibration status, you didn't make sure the sensor is in configure mode before you write back the calibration parameters.
Also, if your board is not moving, the calibration status should not drop. only reason the system calibration droped is a big distortion of magnetic field are detected and algorithm can't compensate it when board is not moving. Thus, the magnetic data will float and euler output will also become drift or jumping.