Skip to content

Commit 9f3fae8

Browse files
committed
Correct Euler (Tait Bryan) angles - see #145
1 parent b249f13 commit 9f3fae8

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

examples/Arduino/Example11_DMP_Bias_Save_Restore_ESP32/Example11_DMP_Bias_Save_Restore_ESP32.ino

+32-7
Original file line numberDiff line numberDiff line change
@@ -321,24 +321,49 @@ void loop()
321321
SERIAL_PORT.print(F(" Accuracy:"));
322322
SERIAL_PORT.println(data.Quat9.Data.Accuracy);
323323
*/
324-
324+
325+
// The ICM 20948 chip has axes y-forward, x-right and Z-up - see Figure 12:
326+
// Orientation of Axes of Sensitivity and Polarity of Rotation
327+
// in DS-000189-ICM-20948-v1.6.pdf These are the axes for gyro and accel and quat
328+
//
329+
// For conversion to roll, pitch and yaw for the equations below, the coordinate frame
330+
// must be in aircraft reference frame.
331+
//
332+
// We use the Tait Bryan angles (in terms of flight dynamics):
333+
// ref: https://en.wikipedia.org/w/index.php?title=Conversion_between_quaternions_and_Euler_angles
334+
//
335+
// Heading – ψ : rotation about the Z-axis (+/- 180 deg.)
336+
// Pitch – θ : rotation about the new Y-axis (+/- 90 deg.)
337+
// Bank – ϕ : rotation about the new X-axis (+/- 180 deg.)
338+
//
339+
// where the X-axis points forward (pin 1 on chip), Y-axis to the right and Z-axis downward.
340+
// In the conversion example above the rotation occurs in the order heading, pitch, bank.
341+
// To get the roll, pitch and yaw equations to work properly we need to exchange the axes
342+
343+
// Note when pitch approaches +/- 90 deg. the heading and bank become less meaningfull because the
344+
// device is pointing up/down. (Gimbal lock)
345+
325346
double q0 = sqrt(1.0 - ((q1 * q1) + (q2 * q2) + (q3 * q3)));
326-
double q2sqr = q2 * q2;
347+
348+
double qw = q0; // See issue #145 - thank you @Gord1
349+
double qx = q2;
350+
double qy = q1;
351+
double qz = -q3;
327352

328353
// roll (x-axis rotation)
329-
double t0 = +2.0 * (q0 * q1 + q2 * q3);
330-
double t1 = +1.0 - 2.0 * (q1 * q1 + q2sqr);
354+
double t0 = +2.0 * (qw * qx + qy * qz);
355+
double t1 = +1.0 - 2.0 * (qx * qx + qy * qy);
331356
double roll = atan2(t0, t1) * 180.0 / PI;
332357

333358
// pitch (y-axis rotation)
334-
double t2 = +2.0 * (q0 * q2 - q3 * q1);
359+
double t2 = +2.0 * (qw * qy - qx * qz);
335360
t2 = t2 > 1.0 ? 1.0 : t2;
336361
t2 = t2 < -1.0 ? -1.0 : t2;
337362
double pitch = asin(t2) * 180.0 / PI;
338363

339364
// yaw (z-axis rotation)
340-
double t3 = +2.0 * (q0 * q3 + q1 * q2);
341-
double t4 = +1.0 - 2.0 * (q2sqr + q3 * q3);
365+
double t3 = +2.0 * (qw * qz + qx * qy);
366+
double t4 = +1.0 - 2.0 * (qy * qy + qz * qz);
342367
double yaw = atan2(t3, t4) * 180.0 / PI;
343368

344369
SERIAL_PORT.print(F("Roll: "));

examples/Arduino/Example7_DMP_Quat6_EulerAngles/Example7_DMP_Quat6_EulerAngles.ino

+29-8
Original file line numberDiff line numberDiff line change
@@ -222,27 +222,48 @@ void loop()
222222
SERIAL_PORT.println(q3, 3);
223223
*/
224224

225-
// Convert the quaternions to Euler angles (roll, pitch, yaw)
226-
// https://en.wikipedia.org/w/index.php?title=Conversion_between_quaternions_and_Euler_angles&section=8#Source_code_2
225+
// The ICM 20948 chip has axes y-forward, x-right and Z-up - see Figure 12:
226+
// Orientation of Axes of Sensitivity and Polarity of Rotation
227+
// in DS-000189-ICM-20948-v1.6.pdf These are the axes for gyro and accel and quat
228+
//
229+
// For conversion to roll, pitch and yaw for the equations below, the coordinate frame
230+
// must be in aircraft reference frame.
231+
//
232+
// We use the Tait Bryan angles (in terms of flight dynamics):
233+
// ref: https://en.wikipedia.org/w/index.php?title=Conversion_between_quaternions_and_Euler_angles
234+
//
235+
// Heading – ψ : rotation about the Z-axis (+/- 180 deg.)
236+
// Pitch – θ : rotation about the new Y-axis (+/- 90 deg.)
237+
// Bank – ϕ : rotation about the new X-axis (+/- 180 deg.)
238+
//
239+
// where the X-axis points forward (pin 1 on chip), Y-axis to the right and Z-axis downward.
240+
// In the conversion example above the rotation occurs in the order heading, pitch, bank.
241+
// To get the roll, pitch and yaw equations to work properly we need to exchange the axes
242+
243+
// Note when pitch approaches +/- 90 deg. the heading and bank become less meaningfull because the
244+
// device is pointing up/down. (Gimbal lock)
227245

228246
double q0 = sqrt(1.0 - ((q1 * q1) + (q2 * q2) + (q3 * q3)));
229247

230-
double q2sqr = q2 * q2;
248+
double qw = q0; // See issue #145 - thank you @Gord1
249+
double qx = q2;
250+
double qy = q1;
251+
double qz = -q3;
231252

232253
// roll (x-axis rotation)
233-
double t0 = +2.0 * (q0 * q1 + q2 * q3);
234-
double t1 = +1.0 - 2.0 * (q1 * q1 + q2sqr);
254+
double t0 = +2.0 * (qw * qx + qy * qz);
255+
double t1 = +1.0 - 2.0 * (qx * qx + qy * qy);
235256
double roll = atan2(t0, t1) * 180.0 / PI;
236257

237258
// pitch (y-axis rotation)
238-
double t2 = +2.0 * (q0 * q2 - q3 * q1);
259+
double t2 = +2.0 * (qw * qy - qx * qz);
239260
t2 = t2 > 1.0 ? 1.0 : t2;
240261
t2 = t2 < -1.0 ? -1.0 : t2;
241262
double pitch = asin(t2) * 180.0 / PI;
242263

243264
// yaw (z-axis rotation)
244-
double t3 = +2.0 * (q0 * q3 + q1 * q2);
245-
double t4 = +1.0 - 2.0 * (q2sqr + q3 * q3);
265+
double t3 = +2.0 * (qw * qz + qx * qy);
266+
double t4 = +1.0 - 2.0 * (qy * qy + qz * qz);
246267
double yaw = atan2(t3, t4) * 180.0 / PI;
247268

248269
#ifndef QUAT_ANIMATION

0 commit comments

Comments
 (0)