# BNO055 Quaternion to Euler

I'm using a BNO055 to detect if a device is falling over and bring it into safe mode.
I thought this would be a simple task using the nice features of the BNO055... I was wrong.
I have a problem with the Euler Y (and Z) values the BNO055 when using the standard library examples.

X-behaviour : BNO055 flat on the table, turn it clockwise. X increases from 0 to 360 during one complete revolution and then rolls over to 0 again. (That would be a behaviour I'd appreciate for Y)
Note to be more precise: once magnetic calibration has been established, values jump one-time and now the output value gives delta with respect to magnetic north instead of power-on position.
Y-behaviour : Y starts at 0. As you lift up one side of the BNO055, the Y value increases to 90 when perfectly vertical, then decreases again to 0 until perfectly upside-down. Lifting up the other side gives you 0 to -90 to 0.
Z-behaviour: Outputs similar values as Y.
(In examples above I've used integers to simplify. In reality the output values are floats that are only zero upon power-on and never go back to be completely zero. )

My project needs to detect Y angles close to 90Ā° before coming into action and I'm concerned that I could be missing a "falling-over-detection" when the device turns over very fast.
The device could be upside-down with Y values close to 0 as follows:
From a Y sequence of 70 - 74 - 78 - 83 - 87 - 86 - 82 -.. and testing for (Y > 88) you cannot tell if it passed 90 and flipped over or straightened up again.
The exact Y (and maybe Z) values at which the device goes into safety mode will need some experimentation in a next phase.

The Adafruit documentation states that Euler angles should not be used when Y or Z are over 45Ā° and one should be using quaternions.

I've been doing quite a bit of study but I found a lot of code snippets but no firm complete code that does the quaternions to (-179Ā° - 0Ā° - 180Ā°) Euler conversion. From what I understand, it seems a complex task to write and debug.
I wonder if somebody would already have gone through all this and could post working example code of quaternions to (0Ā° - 180Ā°) Euler conversion. Or has solved this problem in another way.

Side remarks:

• Since I'm concerned about Y angle, (and not navigation) I don't think that I could be running into gimball trouble.
• I don't want to use mercury switches to detect an upside-down situation given the risk, there are aluminium parts on the device and I would not be happy to be needing mercury.
• any solution without using quaternions would work for me.
• I used the unchanged Euler example code from the standard Adafruit library. I don't think it adds value to the question to repost it here.

Please describe the project that you are working on, not the issues with attempting to solve a problem using the BNO055. It is the wrong tool for the job.

It is much easier, faster and more accurate to measure tilt using an accelerometer (either the one in the BNO055, or a dedicated accelerometer sensor), rather than rely on the slow, inaccurate BNO055 3D orientation calculation. See this tutorial for how to do that. How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing-DFRobot

Note: Euler angles are particularly nasty because there are around 12 different conventions for defining them, and the order in which you apply the rotations is a critical part of the definition. So it is not easy to interpret them.

Accelerometers repond to acceleration as well as orientation, which is why a full IMU is needed to get meaningful orientation when movement is rapid.

An IMU is neither required nor desired for this application, as an object just starting to fall over is not moving rapidly.

Also, the BNO055 is hopelessly inaccurate and unstable for such use.

I donāt have a BNO055 on my desk, so I canāt confirm my code. But I have worked extensively with the BNO055 and itās adafruit library. I may have a solution for you.

The āEuler Anglesā returned by the BNO0555 are not true euler angles, because they are not tied to any of the 12 unique rotation sequences mentioned by jremington. They are āinstantaneous orientation anglesā and arenāt very useful IMO.

However, the Adafruit BNO055 library returns quaternions from the imu::Quaternion Adafruit_BNO055::getQuat() method. (just in case you want to look through the library source files to see how it works).

This stuff returned by this method is an object of class Quaternion, which is defined within the library folder under utility/quaternion.h

If you look at this file, youāll see that class Quaternion has a public method, toEuler() that returns a 3-vector set of true euler angles. Which are described below.

From quaternion.h:

``````Ā  Ā  // Returns euler angles that represent the quaternion.Ā  Angles are
Ā  Ā  // returned in rotation order and right-handed about the specified
Ā  Ā  // axes:
Ā  Ā  //
Ā  Ā  //Ā   v[0] is applied 1st about z (ie, roll)
Ā  Ā  //Ā   v[1] is applied 2nd about y (ie, pitch)
Ā  Ā  //Ā   v[2] is applied 3rd about x (ie, yaw)
Ā  Ā  //
Ā  Ā  // Note that this means result.x() is not a rotation about x;
Ā  Ā  // similarly for result.z().
``````

So if you have an Adafruit_BNO055 object in your code (for this example, weāll call it ābnoā), then you should be able to get the true Eulers by doing something like:

``````imu::Quaternion quat = bno.getQuat();

imu::Vector<3> eul = quat.toEuler();

double roll = eul.x();
double pitch = eul.y();
double yaw = eul.z();
``````

Where quat is your quaternion and eul is the 3-vector containing your euler angles.

I hope this helps.

1 Like