Interpreting quaternions. Inertial navigation systems

Everyone good time of day!
I ask for your help in, first of all, understanding what to do next. I didn’t think there would be so many problems, to be honest :slight_smile:
So. I continue to “create” an inertial navigation system on arduino nano 33 BLE. I managed to calibrate the IMU well, as well as learn how to correctly handle the Madgwick filter (library SensorFusion (GitHub - aster94/SensorFusion: A simple implementation of some complex Sensor Fusion algorithms)). I now have the quaternion string-vector of the current arduino orientation at any time (Q = [q0 q1 q2 q2]).
I spent more than a week understanding what quaternion is (having viewed a bunch of sites and forums), and what can be done with it, but I never found the answer to the general question - how to interpret these four values ​ ​? How to get roll, yaw and pitch angles from this (or, better, a radius vector of direction)? On the Internet, it is proposed to calculate Euler angles, calling them roll, yaw and pitch, but there is a huge problem in this - when any angle reaches a value of 90 degrees, the angle responsible, for example, for roll, begins to show yaw, and so on. I don’t understand why this happens, frankly - should it be, or is it a mistake made by the author of the library. If so, then the Euler angles are NOT roll, pitch and yaw, and its need some other representation of orientation.
Finally, my second main question is what to do in the end? I understand that from the accelerometer readings at each step you need to subtract g, for which you need to know the orientation of the IMU in space, but is that all? What else do I not know about inertial navigation in this context?
I would be incredibly grateful for any help!
P.S. The Majwick filter in my case also relies on magnetometer data, so the quaternion (as I understand it) always shows absolute values ​ ​ of angles (relative to the local magnetic north and the known “down” direction).
Excuse me for my English (translator used) :smiley:

You don’t. If you’re very close to (1,0,0,0), q1 will change linearly with roll/2, q2 will change linearly with pitch/2 and q3 with yaw/2. q0 will always be the square root of 1 minus the sum of squares of the other components, because ‖q‖₂ = 1 at all times.
Unless your angles are really small and you only have roll, pitch or yaw, you cannot really interpret the quaternion components on sight.

Quaternions encode rotations, not an absolute angle or direction. If you want a vector to point in a direction, you have to start with a reference vector (e.g. (0 0 1), i.e. pointing up) and rotate this vector by the quaternion.

Are you referring to Gimbal lock - Wikipedia? This is exactly the problem you’re trying to avoid by using quaternions in the first place. Converting the quaternion to Euler angles is not an issue, as long as you don’t manipulate them. For your sensor fusion algorithms and state estimation, you should use quaternions, not Euler angles.

1 Like

Keep in mind that the orientation defined by q={1,0,0,0] depends entirely on how the axes of the 9DOF sensor are interpreted and aligned.

Many people find the Tait-Bryan angle conversion convenient, if you need angles. This is the formulation I use, where the standard orientation (X North, Y West, Z up) corresponds to q={1,0,0,0}:

      // Define Tait-Bryan angles.
      // Standard sensor orientation : X magnetic North, Y West, Z Up (NWU)
      // this code corrects for magnetic declination.
      // Pitch is angle between sensor x-axis and Earth ground plane, toward the
      // Earth is positive, up toward the sky is negative. Roll is angle between
      // sensor y-axis and Earth ground plane, y-axis up is positive roll.
      // Tait-Bryan angles as well as Euler angles are
      // non-commutative; that is, the get the correct orientation the rotations
      // must be applied in the correct order.
      // which has additional links.
      roll  = atan2((q[0] * q[1] + q[2] * q[3]), 0.5 - (q[1] * q[1] + q[2] * q[2]));
      pitch = asin(2.0 * (q[0] * q[2] - q[1] * q[3]));
      yaw   = atan2((q[1] * q[2] + q[0] * q[3]), 0.5 - ( q[2] * q[2] + q[3] * q[3]));
      // to degrees
      yaw   *= 180.0 / PI;
      pitch *= 180.0 / PI;
      roll *= 180.0 / PI;

      //conventional nav, yaw increases CW from North, corrected for local magnetic declination

      yaw = -(yaw + declination);
      if (yaw < 0) yaw += 360.0;
      if (yaw >= 360.0) yaw -= 360.0;
1 Like

Thank you so much for your help! I was able to understand the question:)