Hi,
My question maybe more to do with general 3D vector maths, but any advice would be gratefully received.
I am running an Adafruit BNO085 connected to an Arduino Nano, and running the software "quaternion_yaw_pitch_roll.ino" from the Github pages relating the the BNO08x libraries for use on Arduino. It all works great and the serial monitor on the Arduino IDE churns out the yaw/pitch/roll values every 20ms or so. I am able to copy/paste the serial monitor output into Excel to analyse the numbers.
One of the tests I have done (on the bench) is to twist the BNo085 through 180degrees (clockwise), pause then twist back again. What I see on the waveforms is that the pitch waveform shows a distinct negative dip when the board is being twisted clockwise, and a distinct positive spike when returning anti-clockwise. It also apparent that the pitch value does not return to where it started, even though I have been careful to make sure that the board is in the same position.
I have repeated the test using various report outputs; the original code uses the ARVR stabilized rotation vector, I get the same oddities using the Game Rotation Vector or the 'normal' Rotation Vector.
I've attached a .jpg of the excel graph, the X axis is seconds.
I cannot understand these dips/spikes, and wonder whether there is some fundamental physics that I don't get. Can I somehow use other sensor outputs to remove these spikes ?
Any advice gratefully received.
BNo085 Yaw/Pitch interaction
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- SteveDillon
- Posts: 6
- Joined: Sun Oct 03, 2021 9:10 am
BNo085 Yaw/Pitch interaction
- Attachments
-
- PitchYawGraph.jpg (56.84 KiB) Viewed 1016 times
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: BNo085 Yaw/Pitch interaction
Could you post the code you're using (between CODE tags please)?
it looks like the value you're plotting as pitch contains a mix of rotational velocity around the yaw axis, and something else. I'm not sure what's causing the change in level between the two spikes, but quaternions carry a lot of information that isn't obvious at first glance.
For the sake of testing, what do you get if you rotate the sensor clockwise and back, then counterclockwise and back? Do the levels between the peaks make a low-high-low cycle?
it looks like the value you're plotting as pitch contains a mix of rotational velocity around the yaw axis, and something else. I'm not sure what's causing the change in level between the two spikes, but quaternions carry a lot of information that isn't obvious at first glance.
For the sake of testing, what do you get if you rotate the sensor clockwise and back, then counterclockwise and back? Do the levels between the peaks make a low-high-low cycle?
- SteveDillon
- Posts: 6
- Joined: Sun Oct 03, 2021 9:10 am
Re: BNo085 Yaw/Pitch interaction
Hi Mike,
Thanks for the reply,
the code I'm using is "quaternion_yaw_pitch_roll.ino" from the Github pages relating the the BNO08x libraries for use on Arduino
As suggested, I've performed the slow rotate 180 anti-clockwise and back, then 180 clockwise and back. The results are pretty similar to before for the anticlocwise and return section. At the start of the clockwise rotate there is no negative trough in the pitch value,but when I return back to starting position I get the same positive spike in the pitch reading. I've attached the raw .txt file generated from the Arduino code, and a snapshot of the excel graph.
The same two questions are apparent; what is causing these spikes/troughs in the pitch reading as the yaw changes, and why does the pitch reading never return to it's original position even when the hardware has returned ?
I did have a thought that maybe there is an issue with the gyro on the board - see my other post
viewtopic.php?f=19&t=183919
I've tried various other example codes, and tried all the relevent reports available from the BNo085 (different variations of the rotation vector). The effect is always there.
Any suggestions gratefully received.
Thanks for the reply,
the code I'm using is "quaternion_yaw_pitch_roll.ino" from the Github pages relating the the BNO08x libraries for use on Arduino
Code: Select all
#include <Arduino.h>
// This demo explores two reports (SH2_ARVR_STABILIZED_RV and SH2_GYRO_INTEGRATED_RV) both can be used to give
// quartenion and euler (yaw, pitch roll) angles. Toggle the FAST_MODE define to see other report.
// Note sensorValue.status gives calibration accuracy (which improves over time)
#include <Adafruit_BNO08x.h>
// For SPI mode, we need a CS pin
#define BNO08X_CS 10
#define BNO08X_INT 9
// #define FAST_MODE
// For SPI mode, we also need a RESET
//#define BNO08X_RESET 5
// but not for I2C or UART
#define BNO08X_RESET -1
struct euler_t {
float yaw;
float pitch;
float roll;
} ypr;
Adafruit_BNO08x bno08x(BNO08X_RESET);
sh2_SensorValue_t sensorValue;
#ifdef FAST_MODE
// Top frequency is reported to be 1000Hz (but freq is somewhat variable)
sh2_SensorId_t reportType = SH2_GYRO_INTEGRATED_RV;
long reportIntervalUs = 2000;
#else
// Top frequency is about 250Hz but this report is more accurate
sh2_SensorId_t reportType = SH2_ARVR_STABILIZED_RV;
long reportIntervalUs = 5000;
#endif
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");
}
}
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit BNO08x test!");
// Try to initialize!
if (!bno08x.begin_I2C()) {
//if (!bno08x.begin_UART(&Serial1)) { // Requires a device with > 300 byte UART buffer!
//if (!bno08x.begin_SPI(BNO08X_CS, BNO08X_INT)) {
Serial.println("Failed to find BNO08x chip");
while (1) { delay(10); }
}
Serial.println("BNO08x Found!");
setReports(reportType, reportIntervalUs);
Serial.println("Reading events");
delay(100);
}
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 loop() {
if (bno08x.wasReset()) {
Serial.print("sensor was reset ");
setReports(reportType, reportIntervalUs);
}
if (bno08x.getSensorEvent(&sensorValue)) {
// in this demo only one report type will be received depending on FAST_MODE define (above)
switch (sensorValue.sensorId) {
case SH2_ARVR_STABILIZED_RV:
quaternionToEulerRV(&sensorValue.un.arvrStabilizedRV, &ypr, true);
case SH2_GYRO_INTEGRATED_RV:
// faster (more noise?)
quaternionToEulerGI(&sensorValue.un.gyroIntegratedRV, &ypr, true);
break;
}
static long last = 0;
long now = micros();
Serial.print(now - last); Serial.print("\t");
last = now;
Serial.print(sensorValue.status); Serial.print("\t"); // This is accuracy in the range of 0 to 3
Serial.print(ypr.yaw); Serial.print("\t");
Serial.print(ypr.pitch); Serial.print("\t");
Serial.println(ypr.roll);
}
}
The same two questions are apparent; what is causing these spikes/troughs in the pitch reading as the yaw changes, and why does the pitch reading never return to it's original position even when the hardware has returned ?
I did have a thought that maybe there is an issue with the gyro on the board - see my other post
viewtopic.php?f=19&t=183919
I've tried various other example codes, and tried all the relevent reports available from the BNo085 (different variations of the rotation vector). The effect is always there.
Any suggestions gratefully received.
- Attachments
-
- PitchYaw2.jpg (58.03 KiB) Viewed 952 times
-
- rotate3.txt
- (318.15 KiB) Downloaded 4 times
- jps2000
- Posts: 811
- Joined: Fri Jun 02, 2017 4:12 pm
Re: BNo085 Yaw/Pitch interaction
You should activate the normal rotation vector not these one you have tried
- SteveDillon
- Posts: 6
- Joined: Sun Oct 03, 2021 9:10 am
Re: BNo085 Yaw/Pitch interaction
Hi,
Thanks for your input.
I've tried the 'normal' ROTATION_VECTOR as well as the ARVR_STABILIZED_RV, the GYRO_INTEGRATED_RV, the GEOMAGNETIC_ROTATION_VECTOR and the GAME_ROTATION_VECTOR.
The effects I am seeing are there no matter which vector I use I'm afraid.
Thanks for your input.
I've tried the 'normal' ROTATION_VECTOR as well as the ARVR_STABILIZED_RV, the GYRO_INTEGRATED_RV, the GEOMAGNETIC_ROTATION_VECTOR and the GAME_ROTATION_VECTOR.
The effects I am seeing are there no matter which vector I use I'm afraid.
- gammaburst
- Posts: 1016
- Joined: Thu Dec 31, 2015 12:06 pm
Re: BNo085 Yaw/Pitch interaction
Plotting Euler angles as 2D curves will drive you crazy! Instead, feed your Euler angles into an animated display program that rotates a familiar 3D model such as an airplane. Now when you rotate the sensor you can see what's happening.
I did that with your code, and I saw that it almost works correctly, except my airplane turns the wrong ways. I added one line at the very top of quaternionToEuler() and now it works fine for me:
float t=qi; qi=qj; qj=t; qk=-qk;
You may need different swaps and flips (or possibly none at all) depending on how you define your Euler angles. Beware that Euler angles can be very confusing to new folks.
By the way, in the switch() block, the first case seems to be missing a break statement.
I did that with your code, and I saw that it almost works correctly, except my airplane turns the wrong ways. I added one line at the very top of quaternionToEuler() and now it works fine for me:
float t=qi; qi=qj; qj=t; qk=-qk;
You may need different swaps and flips (or possibly none at all) depending on how you define your Euler angles. Beware that Euler angles can be very confusing to new folks.
By the way, in the switch() block, the first case seems to be missing a break statement.
- jps2000
- Posts: 811
- Joined: Fri Jun 02, 2017 4:12 pm
Re: BNo085 Yaw/Pitch interaction
Comprehensive Euler Angle conversions (all 12 possible) you find here:
https://github.com/jps2000/BNO080/blob/master/utilities
https://github.com/jps2000/BNO080/blob/master/utilities
- SteveDillon
- Posts: 6
- Joined: Sun Oct 03, 2021 9:10 am
Re: BNo085 Yaw/Pitch interaction
Thanks for the replies - sounds like I'm going to have to delve deeper into Euler angles and get my brain working.
Interesting about the missing break statement. I hadn't noticed at all (I guess I assumed that the code examples in the Arduino IDE were bug free and I failed to check it out properly).
Interesting about the missing break statement. I hadn't noticed at all (I guess I assumed that the code examples in the Arduino IDE were bug free and I failed to check it out properly).
- gammaburst
- Posts: 1016
- Joined: Thu Dec 31, 2015 12:06 pm
Re: BNo085 Yaw/Pitch interaction
Wait a minute! The problem could be your plotting program.
Why does each plot have two different sets of Y-axis labels?
Did it scale the pitch curve differently than the yaw curve?
Maybe the pitch angle wiggled slightly, and the plotting program exaggerated it.
Why does each plot have two different sets of Y-axis labels?
Did it scale the pitch curve differently than the yaw curve?
Maybe the pitch angle wiggled slightly, and the plotting program exaggerated it.
- SteveDillon
- Posts: 6
- Joined: Sun Oct 03, 2021 9:10 am
Re: BNo085 Yaw/Pitch interaction
Hi gammaburst,
Thanks for your reply.
The plots are basically from Excel using imported data from the Arduino/BNo085.
Yes the scale is very different between pitch and yaw. Basically I am rotating the unit by +/-180 degrees on a nominally flat surface. I would expect the pitch to vary slightly as the unit is rotated if the surface is not totally flat, but I would not expect the peaks/troughs I'm seeing (which seem to be related to the change of Yaw, rather than the absolute value of Yaw), and I would expect the pitch value to return to where it started when the unit is returned to exactly the same spot.
It is possible that these peaks/troughs are caused by a wiggle, but I've been ultra careful to avoid that possibility. Although the pitch values of a degree or so can seem pretty small, a pitch of this amount is actually pretty obvious in the real world.
Thanks for your reply.
The plots are basically from Excel using imported data from the Arduino/BNo085.
Yes the scale is very different between pitch and yaw. Basically I am rotating the unit by +/-180 degrees on a nominally flat surface. I would expect the pitch to vary slightly as the unit is rotated if the surface is not totally flat, but I would not expect the peaks/troughs I'm seeing (which seem to be related to the change of Yaw, rather than the absolute value of Yaw), and I would expect the pitch value to return to where it started when the unit is returned to exactly the same spot.
It is possible that these peaks/troughs are caused by a wiggle, but I've been ultra careful to avoid that possibility. Although the pitch values of a degree or so can seem pretty small, a pitch of this amount is actually pretty obvious in the real world.
- gammaburst
- Posts: 1016
- Joined: Thu Dec 31, 2015 12:06 pm
Re: BNo085 Yaw/Pitch interaction
The BNO085 datasheet Section 6.7 Performance Characteristics says, "In practice the rotation vector is typically accurate to 5° and the geomagnetic rotation vector to 10°. "
As you rotated the sensor you may have tilted it slightly, of course, but also the BNO's sensor imperfections and internal self-calibration/fusion algorithm cause some non-linear and non-repeatable behavior.
You could read the BNO's raw sensors and do your own calibration/fusion math, and possibly improve performance in some ways, but probably degrade it in other ways. It's a compromise design.
Better sensors cost hundreds of dollars. Nice sensors cost thousands, tens of thousands, even hundreds of thousands of dollars. And they're much larger.
Please add clear legends and units to your future plots, and always use the same scale when drawing multiple curves on one grid.
As you rotated the sensor you may have tilted it slightly, of course, but also the BNO's sensor imperfections and internal self-calibration/fusion algorithm cause some non-linear and non-repeatable behavior.
You could read the BNO's raw sensors and do your own calibration/fusion math, and possibly improve performance in some ways, but probably degrade it in other ways. It's a compromise design.
Better sensors cost hundreds of dollars. Nice sensors cost thousands, tens of thousands, even hundreds of thousands of dollars. And they're much larger.
Please add clear legends and units to your future plots, and always use the same scale when drawing multiple curves on one grid.
- jps2000
- Posts: 811
- Joined: Fri Jun 02, 2017 4:12 pm
Re: BNo085 Yaw/Pitch interaction
You have to calibrate the sensor by described movements. Important is to keep the sensor at constant temperature and to have some minutes warm up. I found it useful to let the BNO automatically store cal data every 5 minutes. (there is a command for that). Fixate the PCB with just one screw to avoid mechanical stress etc. Inside a building and close to iron (vehicle) you may have problems with the magnetometer.
https://github.com/jps2000/BNO080/blob/master/README.md
The fusion alogrithm and the means to keep calibration is the best you can have for 20 bucks. External fusion algos are definitely worse (all the Mahonys and Madgwicks). In the BNO they applied so many tricks to get best possible performance with the hardware..
All those rotating bunnys and airplanes say nothing about accurracy. Some degrees are not visible at all.
https://github.com/jps2000/BNO080/blob/master/README.md
The fusion alogrithm and the means to keep calibration is the best you can have for 20 bucks. External fusion algos are definitely worse (all the Mahonys and Madgwicks). In the BNO they applied so many tricks to get best possible performance with the hardware..
All those rotating bunnys and airplanes say nothing about accurracy. Some degrees are not visible at all.
Please be positive and constructive with your questions and comments.