BNO085 calibration and performance

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
lumex
 
Posts: 52
Joined: Tue Aug 24, 2021 5:40 am

BNO085 calibration and performance

Post by lumex »

Hi,

I'm currently playing with several BNO085 IMU units (https://www.adafruit.com/product/4754), bought at the same time.

Roll and Pitch measurements are very reproducible between units, say around 1°. This is very interesting.

However, Yaw measurement has a terrible unaccuracy and, worst, it's always changing! 40° -60° 150° !
It's certainly caused by the magnetometer measurement although I'm working on a table and only my hands are moving around (no moving metallic objects, or whatever).
It may be useful to switch off magnetometer after a calibration period.

The accuracy is indicated by a value 0/1/2/3.
0 – Unreliable
1 – Low accuracy
2 – Medium accuracy
3 – High accuracy

It seems that moving the device is enough for calibrating it. Of course putting it in various orthogonal/normal positions or doing figure-eight loops can do the job.
Anyway, this accuracy reliability indicator is always changing!

I'm not sure that the BNO085 library is complete enough for fine tuning calibration the device while the BNO datasheet seems quite complete about calibration.

What performance did you get from that BNO085 as an absolute orientation sensor?
What calibration process do you follow?

According to your experience, is the Adafruit BNO085 library complete enough for fine tuning calibration?


Side question (I may open a topic for that):
The Adafruit library seems not to be able to handle more than one BNO085. Being able to change the I2C address is not a solution.
Could you tweak the library for being able to handle 2 or more devices (without any additional HW...)?


Thanks
Best regards

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: BNO085 calibration and performance

Post by jps2000 »

You may find some information here
https://github.com/jps2000/BNO080
It could be that you are lacking a good earth field indoors or you have some iron magnets or DC currents around

Gammaburst provided in this forum a code to handle 3 BNO simultaneously
viewtopic.php?f=25&t=175744&p=859684&hi ... 85#p859684

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

Yes, you may have attenuation or interference of your Earth magnetic field.
Check if an ordinary compass works properly when placed near the BNO085.
Try moving to another location, perhaps outdoors away from buildings and power lines.
Try displaying the BNO's magnetometer XYZ value, and compare it to predicted value:
https://www.ngdc.noaa.gov/geomag/calcul ... ml#igrfwmm

User avatar
lumex
 
Posts: 52
Joined: Tue Aug 24, 2021 5:40 am

Re: BNO085 calibration and performance

Post by lumex »

Thanks for your quick replies and pointers.

Regarding my side question "handling multiple BNOs" without additional HW"
I can use multiple BNOs with an I2C mux. I2C is fine.
I can read "The BNO085's overly complex communication protocol is further complicated by full-duplex SPI. etc." from Gammaburst (viewtopic.php?f=25&t=175744&p=859684&hi ... 85#p859651). This is an invitation to keep on with I2C!

Regarding my magnetic environment.
I believe it's quite stable.
Manipulating the BNOs with my hands may influence the magnetic field they measure.
However, I don't move the objects around me and I'm trying to handle the BNOs with care and distance. Or just observe them at distance.
I already measured the local earth magnetic field with a STM magnetometer (I remember it was around 40-50 uT) and I also used an ordinary compass and a smartphone compass to observe the direction of the magnetic field. It appeared to be very stable.

In my situation, with any values for the accuracy indicator between 0 and 3 for each IMU, obtained by moving them in any way (orientation, speed, rhythm), I keep on getting incoherent yaw measures with a gap of 20, 60 or 100 ° between each BNO.
Pitch and Roll have an impressive reproducibility, even when the accuracy indicator has a value of 0 or 1!
This is a so different behavior between roll&pitch and yaw. This is so strange...

Now let's have a look at one BNO magnetometer XYZ values:

Code: Select all

    Serial.print(sensorValue.un.magneticField.x);     Serial.print(" x (uT)\t");  // magfield x
    Serial.print(sensorValue.un.magneticField.y);     Serial.print(" y (uT)\t");  // magfield y
    Serial.print(sensorValue.un.magneticField.z);     Serial.print(" z (uT)\t");  // magfield z
Irrespectively of what are x y and z for the magnetometer on the board, by turning the board around each of its 3 axis, I can see values between -0.94 and 0.94 for x and y and z (sometimes -0.78/0.78 or -0.90/0.90 ...).

The library (sh2_SensorValue.h https://github.com/adafruit/Adafruit_BN ... sorValue.h) claims that values are delivered in uT:

Code: Select all

typedef struct sh2_MagneticField {
    /* Units are uTesla */
    float x;  /**< @brief [uTesla] */
    float y;  /**< @brief [uTesla] */
    float z;  /**< @brief [uTesla] */
} sh2_MagneticField_t;
These measures look weird because the magnitude of the magnetic field at the place of the BNO is supposed to be around 50 uT (20 uT North comp and 43 uT vertical comp).

What do you think about this?
Do you agree with sensorValue.un.magneticField?

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

When I request SH2_MAGNETIC_FIELD_CALIBRATED reports and read sensorValue.un.magneticField I get sensible vectors with about 32 uT magnitude.

The upshot of that multi-BNO085 forum discussion was -- even though the BNO's SPI communication is clumsy, it's faster than I2C when reading higher data rates from multiple BNO085s.

Your hands/body shouldn't disturb a magnetic field, unless you are Magneto or Iron Man.

How are you getting roll pitch yaw values? The BNO085 doesn't output Euler angles except in RVC mode.

Be sure you're reading plain "Rotation Vector" and not some other game/geomagnetic/gyro rotation vector.

Calibration: I haven't done any calibration with my BNO085. It seems to automatically figure out my environment and give me good quaternions almost right away.

Perhaps your program is broken. Can you share you code, or point to it with a URL? It should be a minimal program that demonstrates the problem, with irrelevant code removed. Also say what type of processor you're using to talk to the BNO.

A photo of your project may also be helpful. Someone may notice "Whoa, don't do THAT".

A stab in the dark: If you have a spare resistor around 2K or 3K ohms, try connecting it to SDA as an extra pullup resistor. (Leave SCL alone.) I have seen that fix some strange data problems.

User avatar
lumex
 
Posts: 52
Joined: Tue Aug 24, 2021 5:40 am

Re: BNO085 calibration and performance

Post by lumex »

My setup is exactly the same as your I2C setup with 2 or 3 or 4 BNOs.
See viewtopic.php?f=25&t=175744&p=859684&hi ... 85#p857930

MCU: M4 (Feather sense).

Concerning earth magnetic field measurement:

Code: Select all

  sh2_SensorId_t reportType = SH2_MAGNETIC_FIELD_CALIBRATED;
Without a big watch or a plate armour, the measured magnetic field is now 32-35 uT! (sensorValue.un.magneticField )
Good.


The program for delivering Euler angles is based on quaternion_yaw_pitch_roll.ino

Here is the simplified code for two BNOs (without testing sections, display and other stuff):

Code: Select all

// Euler angles from quaternion (reportType = SH2_ARVR_STABILIZED_RV)

#define TCAADDR 0x70 // TCA MUX
#define BNO08X_1_channel 0 // BNO on channel 0
#define BNO08X_2_channel 1 // BNO on channel 1
#define BNO08X_Address 0x4A // BNO I2C address
#define BNO08X_RESET -1 // useful to force BNO reset if problem (accuracy, etc.)

#define TIMEOUT_BOOT_BNO 100

#include <Wire.h>
#include <Adafruit_BNO08x.h>

struct euler_t {
  float yaw;
  float pitch;
  float roll;
} ypr_1, ypr_2, ypr_global;

Adafruit_BNO08x bno08x(BNO08X_RESET);
sh2_SensorValue_t sensorValue_1, sensorValue_2;
boolean update_sensor_1 = false;
boolean update_sensor_2 = false;

// Top frequency is about 250Hz but this report is more accurate
sh2_SensorId_t reportType = SH2_ARVR_STABILIZED_RV;
long reportIntervalUs = 15000; // trial

// I2C mux management
void tcaselect(uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void setReports(sh2_SensorId_t reportType, long report_interval) {
  Serial.println("Setting desired reports");
  tcaselect(BNO08X_1_channel);
  if (! bno08x.enableReport(reportType, report_interval)) {
    Serial.println("Could not enable stabilized remote vector on BNO_1");
  }
  tcaselect(BNO08X_2_channel);
  if (! bno08x.enableReport(reportType, report_interval)) {
    Serial.println("Could not enable stabilized remote vector on BNO_2");
  }
}

void quaternionToEuler(float qr, float qi, float qj, float qk, euler_t* ypr, bool degrees = false) {
  float sqr = sq(qr);
  float sqi = sq(qi);
  float sqj = sq(qj);
  float sqk = sq(qk);

  ypr->yaw =  atan2( 2.0 * (qi * qj + qk * qr),  (sqi - sqj - sqk + sqr));
  ypr->pitch = asin(-2.0 * (qi * qk - qj * qr) / (sqi + sqj + sqk + sqr));
  ypr->roll = atan2( 2.0 * (qj * qk + qi * qr), (-sqi - sqj + sqk + sqr));

  if (degrees) {
    ypr->yaw *= RAD_TO_DEG;
    ypr->pitch *= RAD_TO_DEG;
    ypr->roll *= RAD_TO_DEG;
  }
}

void quaternionToEulerRV(sh2_RotationVectorWAcc_t* rotational_vector, euler_t* ypr, bool degrees = false) {
  quaternionToEuler(rotational_vector->real, rotational_vector->i, rotational_vector->j, rotational_vector->k, ypr, degrees);
}

void quaternionToEulerGI(sh2_GyroIntegratedRV_t* rotational_vector, euler_t* ypr, bool degrees = false) {
  quaternionToEuler(rotational_vector->real, rotational_vector->i, rotational_vector->j, rotational_vector->k, ypr, degrees);
}

void setup(void) {

  Wire.begin();
  tcaselect(0);

  // Try to initialize BNO_1!
  tcaselect(BNO08X_1_channel);
  while (!bno08x.begin_I2C()) {
    delay(TIMEOUT_BOOT_BNO);
  }
  setReports(reportType, reportIntervalUs);
}

void loop() {

#if BNO08X_RESET != -1
  tcaselect(BNO08X_1_channel);
  if (bno08x.wasReset()) {
    setReports(reportType, reportIntervalUs);
  }
  tcaselect(BNO08X_2_channel);
  if (bno08x.wasReset()) {
    setReports(reportType, reportIntervalUs);
  }
#endif

  tcaselect(BNO08X_1_channel);
  if (bno08x.getSensorEvent(&sensorValue_1)) {
    // in this demo only one report type will be received depending on FAST_MODE define (above)
    switch (sensorValue_1.sensorId) {
      case SH2_ARVR_STABILIZED_RV:
        quaternionToEulerRV(&sensorValue_1.un.arvrStabilizedRV, &ypr_1, true);
      case SH2_GYRO_INTEGRATED_RV:
        // faster (more noise?)
        quaternionToEulerGI(&sensorValue_1.un.gyroIntegratedRV, &ypr_1, true);
        break;
    }
    update_sensor_1 = true;
  }

  tcaselect(BNO08X_2_channel);
  if (bno08x.getSensorEvent(&sensorValue_2)) {
    switch (sensorValue_2.sensorId) {
      case SH2_ARVR_STABILIZED_RV:
        quaternionToEulerRV(&sensorValue_2.un.arvrStabilizedRV, &ypr_2, true);
      case SH2_GYRO_INTEGRATED_RV:
        // faster (more noise?)
        quaternionToEulerGI(&sensorValue_2.un.gyroIntegratedRV, &ypr_2, true);
        break;
    }
    update_sensor_2 = true;
  }

  tcaselect(0);

  if (update_sensor_1 == true && update_sensor_2 == true) {

//    angComp(); // angles computation

// displaying values on serial 
    Serial.print("SENSOR_1");               Serial.print("\n");
    Serial.print(sensorValue_1.status);     Serial.print(" (Acc)\n");  // This is accuracy in the range of 0 to 3
    Serial.print(ypr_1.yaw);                Serial.print(" (yaw)\t");
    Serial.print(ypr_1.pitch);              Serial.print(" (pitch)\t");
    Serial.print(ypr_1.roll);               Serial.print(" (roll)\n");
    Serial.print("SENSOR_2");               Serial.print("\n");
    Serial.print(sensorValue_2.status);     Serial.print(" (Acc)\n");  // This is accuracy in the range of 0 to 3
    Serial.print(ypr_2.yaw);                Serial.print(" (yaw)\t");
    Serial.print(ypr_2.pitch);              Serial.print(" (pitch)\t");
    Serial.print(ypr_2.roll);               Serial.print(" (roll)\n");
    Serial.print("GLOBAL");                 Serial.print("\n");
    Serial.print(ypr_global.yaw);           Serial.print(" (yaw)\t");
    Serial.print(ypr_global.pitch);         Serial.print(" (pitch)\t");
    Serial.print(ypr_global.roll);          Serial.print(" (roll)\n");

// displaying values on screen
//
  
    update_sensor_1 = false;
    update_sensor_2 = false;
    }
}
You can see the functions quaternionToEuler and quaternionToEulerRV that I'm using.


For the absolute orientation sensor setup, I'm using:
sh2_SensorId_t reportType = SH2_ARVR_STABILIZED_RV; // ARVR-Stabilized Rotation Vector

See SH-2 Reference Manual
6.5.42 ARVR-Stabilized Rotation Vector (0x28)
The ARVR-stabilized rotation vector sensor reports the orientation of the device. Accumulated
errors are corrected while the device is in motion, which limits the appearance of discontinuities
or jumps in data. The format of the rotation vector is a unit quaternion. The Q point is 14. In
addition an estimate of the heading accuracy is reported. The units for the accuracy estimate
are radians. The Q point is 12. The report ID is 0x28.
And see Adafruit quaternion_yaw_pitch_roll.ino example.

There is a bunch of parameters in SH-2 Reference Manual. And this IMU is supposed to deliver reliable measurements for many applications (game, AR/VR stabilization, etc.)
However I think I may be misusing the Adafruit and SH-2 libraries.

What value are you using for reportType for setting up a (self calibrated) absolute orientation sensor?

Thanks

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

Uh-oh, you're talking to two BNO085s with the Adafruit library.
Last I heard, that wasn't supported and would require significant library rewrite.
Has the library status changed?
Do you see the same problems when talking to only one BNO085?

Your code seems to be missing a "break" statement in this switch case:
case SH2_ARVR_STABILIZED_RV:

I've never used those report modes. If I get a chance, I'll try them.

Here's my test code, running on a Metro M4 Express (Adafruit 3382):

Code: Select all

#include <Adafruit_BNO08x.h>

#define BNO08X_RESET 5

Adafruit_BNO08x bno08x(BNO08X_RESET);  // somehow reset pin 5 doesn't work, so I connected BNO085 RST pin to the Metro's dedicated RST pin instead

void setup(void)
{
  Serial.begin(115200);
  while (!Serial)
    delay(10);
  Serial.println("BNO08x test!");

  bno08x.begin_I2C();
  Wire.setClock(200000L);   // I2C speed, 400 kHz is a little fast for Arduino's pullups
  bno08x.enableReport(SH2_ROTATION_VECTOR, 100000);
  bno08x.enableReport(SH2_MAGNETIC_FIELD_CALIBRATED, 100000);
}

void loop()
{
  sh2_SensorValue_t sensorValue;
  if (!bno08x.getSensorEvent(&sensorValue))
    return;

  switch (sensorValue.sensorId)
  {
    case SH2_ROTATION_VECTOR:
      Serial.print("Quaternion: ");
      Serial.print(sensorValue.un.rotationVector.real,4);  Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.i,4);     Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.j,4);     Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.k,4);     Serial.println();
      break;
    case SH2_MAGNETIC_FIELD_CALIBRATED:
      Serial.print("Magnetic Field Vector: ");
      Serial.print(sensorValue.un.magneticField.x,4);  Serial.print(" ");
      Serial.print(sensorValue.un.magneticField.y,4);  Serial.print(" ");
      Serial.print(sensorValue.un.magneticField.z,4);  Serial.println();
      break;
  }
}
UPDATE

I removed all of your dual-BNO085 code, modified your print statements to work with my 3D display program, and the result is working for me with no magnetometer problems:

Code: Select all

#include <Adafruit_BNO08x.h>

#define BNO08X_RESET -1 // useful to force BNO reset if problem (accuracy, etc.)
#define TIMEOUT_BOOT_BNO 100

struct euler_t
{
  float yaw;
  float pitch;
  float roll;
} ypr_1;

Adafruit_BNO08x bno08x(BNO08X_RESET);
sh2_SensorValue_t sensorValue_1;
boolean update_sensor_1 = false;

// Top frequency is about 250Hz but this report is more accurate
sh2_SensorId_t reportType = SH2_ARVR_STABILIZED_RV;
long reportIntervalUs = 15000; // trial

void setReports(sh2_SensorId_t reportType, long report_interval)
{
  Serial.println("Setting desired reports");
  if (! bno08x.enableReport(reportType, report_interval))
  {
    Serial.println("Could not enable stabilized remote vector on BNO_1");
  }
}

void quaternionToEuler(float qr, float qi, float qj, float qk, euler_t* ypr, bool degrees = false)
{
  float sqr = sq(qr);
  float sqi = sq(qi);
  float sqj = sq(qj);
  float sqk = sq(qk);

  ypr->yaw =  atan2( 2.0 * (qi * qj + qk * qr),  (sqi - sqj - sqk + sqr));
  ypr->pitch = asin(-2.0 * (qi * qk - qj * qr) / (sqi + sqj + sqk + sqr));
  ypr->roll = atan2( 2.0 * (qj * qk + qi * qr), (-sqi - sqj + sqk + sqr));

  if (degrees)
  {
    ypr->yaw   *= RAD_TO_DEG;
    ypr->pitch *= RAD_TO_DEG;
    ypr->roll  *= RAD_TO_DEG;
  }
}

void quaternionToEulerRV(sh2_RotationVectorWAcc_t* rotational_vector, euler_t* ypr, bool degrees = false)
{
  quaternionToEuler(rotational_vector->real, rotational_vector->i, rotational_vector->j, rotational_vector->k, ypr, degrees);
}

void quaternionToEulerGI(sh2_GyroIntegratedRV_t* rotational_vector, euler_t* ypr, bool degrees = false)
{
  quaternionToEuler(rotational_vector->real, rotational_vector->i, rotational_vector->j, rotational_vector->k, ypr, degrees);
}

void setup(void)
{
  Serial.begin(115200);
  Serial.println("Setup ...");

  Wire.begin();

  while (!bno08x.begin_I2C())
    delay(TIMEOUT_BOOT_BNO);
  setReports(reportType, reportIntervalUs);
  Serial.println("Loop ...");
}

void loop()
{
  #if BNO08X_RESET != -1
  if (bno08x.wasReset())
  {
    setReports(reportType, reportIntervalUs);
  }
  #endif

  if (bno08x.getSensorEvent(&sensorValue_1))
  {
    // in this demo only one report type will be received depending on FAST_MODE define (above)
    switch (sensorValue_1.sensorId)
    {
      case SH2_ARVR_STABILIZED_RV:
        quaternionToEulerRV(&sensorValue_1.un.arvrStabilizedRV, &ypr_1, true);
        break;
      case SH2_GYRO_INTEGRATED_RV:
        // faster (more noise?)
        quaternionToEulerGI(&sensorValue_1.un.gyroIntegratedRV, &ypr_1, true);
        break;
    }
    update_sensor_1 = true;
  }

  if (update_sensor_1 == true)
  {
    Serial.print("Orientation: ");
    Serial.print(ypr_1.yaw);    Serial.print(" ");
    Serial.print(ypr_1.roll);   Serial.print(" ");
    Serial.print(ypr_1.pitch);  Serial.println();
    Serial.println("Calibration: 3 3 3 3");

    update_sensor_1 = false;
  }
}
I had to install that extra 2K pullup resistor on SDA to prevent occasional freezing.

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: BNO085 calibration and performance

Post by jps2000 »

You need to use the "normal" rotation vector (0x05) others have sometimetimes strange behaviour and are for specific purposes

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

Good contribution, thanks.

User avatar
lumex
 
Posts: 52
Joined: Tue Aug 24, 2021 5:40 am

Re: BNO085 calibration and performance

Post by lumex »

Regarding "using two BNO085s with the Adafruit library".
Yes, and because this library only supports one BNO, I had to use an I2C mux.
It works well with one or two or more BNOs.

Thanks for the missing "break" statement in "case SH2_ARVR_STABILIZED_RV:". Fixed.

Regarding the poorly reproducible yaw.
I've changed from SH2_ARVR_STABILIZED_RV (0x28) to SH2_ROTATION_VECTOR (0x05), as recommended (thanks), in the form of an additional case:

Code: Select all

      
    switch (sensorValue_1.sensorId) {
      case SH2_ROTATION_VECTOR:
        quaternionToEulerRV(&sensorValue_1.un.rotationVector, &ypr_1, true);
        break;
      case SH2_ARVR_STABILIZED_RV:
        // faster (more noise?)
        quaternionToEulerRV(&sensorValue_1.un.arvrStabilizedRV, &ypr_1, true);
        break;
      case SH2_GYRO_INTEGRATED_RV:
        // faster (more noise?)
        quaternionToEulerGI(&sensorValue_1.un.gyroIntegratedRV, &ypr_1, true);
        break;
        }
The same for BNO nbr 2.

Do you agree with quaternionToEulerRV for SH2_ROTATION_VECTOR?

As arvrStabilizedRV and rotationVector are of the same type sh2_RotationVectorWAcc_t the following computation of Euler angles is the same.

Testing setup:
2 BNOs are placed on a plane with the same orientation (edge to edge).
The plane is moved in different ways and the measurements are observed.

Result :
With a status of 3 for both BNOs :
Roll and pitch are very reproducible (and enough), say less than 1° and often just a few tenths of degrees, with a very low latency. Great.
Yaw has now a bias of about 15°, sometimes 10°. And also sometimes 30 or 40°. And not stable.

This is sometimes better than before but it is not satisfactory yet for an absolute orientation sensor.
Imagine an ARVR application where the environment would have a changing bias of 10 to 40° !

With another pair of BNOs, the bias is also 20 to 40°.

What reproducibility of measurements can you observe between two BNOs with your setup?

Concerning the status of the sensor (0 to 3) :
0 – Unreliable
1 – Accuracy low
2 – Accuracy medium
3 – Accuracy high

I can observe no predictable behavior to make it change. I just know they need to me moved.
Sometimes I move the BNO in various ways and the status stays at 0 for a long time (minutes). Sometimes it reaches 3 quite quickly (5-10 s) and stays at 3 a long time while the BNO is not moving at all (only the keyboard vibrations...).

Are you really doing nothing else that moving the BNOs to get a status of 3?
What is your experience about "status management"?

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

The library may semi-work with multiple BNO's and an I2C mux chip, but it runs slowly. It can't read much BNO data at its full speed.

Library file sh2.h defines SH2_ROTATION_VECTOR as 0x05, so that should be fine.

I don't know about "quaternionToEulerRV for SH2_ROTATION_VECTOR". If it seems to give proper results as you rotate the sensor to every wild 3D orientation (like an aerobatic airplane), then it's probably converting correctly. Beware of possible glitches/hiccups when pitch is +90 or -90 (the singularities).

I rebuilt my triple-BNO085 breadboard, loaded your original code, and changed its output strings to suit my 3D display. It seems to give good rotation vectors at the default 100 messages per second per BNO (200 messages per second total). Both BNO's output reasonable Euler angles within 2 or 3 degrees of each other as I twirl the breadboard around. Both status values are always 3. (This is the first time I've looked at the status value. I usually ignore vaguely documented status flags.)

The BNO085 datasheet says "the rotation vector is typically accurate to 5 degrees".

I don't know what's causing your bogus yaw/heading values. Metal frame building? Nearby chunk of ferrous metal or speaker magnets or motors or power wiring or inside a car? What's the "plane" you mentioned, is it steel? My test area is a wooden desk a meter away from anything like those items. I would expect your magnetometer XYZ readings, compared to that NOAA web site, would provide a clue.

Maybe your project has some accidentally magnetized components. Nuts and bolts perhaps. I use an old handheld VHS tape eraser to demagnetize things. Those erasers can be powerful so don't get too close. Keep away oh maybe a couple centimeters.
Last edited by gammaburst on Wed Aug 03, 2022 12:49 am, edited 2 times in total.

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: BNO085 calibration and performance

Post by jps2000 »

There is also a heading estimation reported in the rotation vector output. This gives an idea about yaw deviation. It should go down to some degrees after doing this figure of eight movements
I do not know how to read this with the sh2 library. In my stack it is in.
Degaussing is very important and can be done with the coil of a magnetic valve ( AC operated of course) Note that you need to replace the valve by an iron screw of about the same diameter. DO NOT operate the coil without iron core. It will even melt or burn without.
Also SMD components like resistors or capacitors, xtals can be magnetized. Metalized caps can be magnetic.
Mounting screws are also important. Use brass screw and just one per breakout to avoid mechanical tension of the board.
DC currents passing by cause also magnetic fields. You can wire the supply of motors with coaxial wire. avoid current loops.
AC fields are not so a problem because magnetometer are filtered in the magnitude of 10Hz so mains frequency interference should not be a problem.

I remember having problems with yaw when the board was laying in front of my laptop. It was the magnet that holds the screen in close position

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

Hi Lumex, If our troubleshooting tips aren't helping you, I suggest sharing a photo of your project showing its wiring and nearby objects.

An AC field can cause trouble if it's strong enough to distort/saturate the magnetometer.

I can't find any sensor bandwidth or lowpass filter specs in the Hillcrest docs. Has anyone seen them?

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: BNO085 calibration and performance

Post by jps2000 »

The BMF055 refers to a BMM150 magnetometer. They mention as standard ODR 10Hz.
I remember weakly that also the invensense devices like MPU9250 uses just 10Hz.
To my knowledge they alwas try to be << grid AC frequency. Trains use even lower frequency (16.66Hz in EU)
A magnetometer (hall) needs relatively high supply current (20mA plus) during measurement. Lower ODR helps in that respect.

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO085 calibration and performance

Post by gammaburst »

I connected a sinewave generator to a coil of wire, and then read SH2_MAGNETIC_FIELD_CALIBRATED reports at 100 Hz message rate (the BNO085's maximum rate).

I measure roughly 3dB down at 70 Hz and 6dB down at 100 Hz. Probably a first-order lowpass rolloff. Nyquist is at 50 Hz, so beware of aliasing. Perhaps lumex is seeing AC mains interference.

The BNO's internal fusion algorithm may have access to a different magnetometer sample rate, or it may do additional filtering, or not. We don't know.

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”