3 #ifndef MAVLINK_NO_CONVERSION_HELPERS
5 /* enable math defines on Windows */
7 #ifndef _USE_MATH_DEFINES
8 #define _USE_MATH_DEFINES
14 #define M_PI_2 ((float)asin(1))
18 * @file mavlink_conversions.h
20 * These conversion functions follow the NASA rotation standards definition file
23 * Their intent is to lower the barrier for MAVLink adopters to use gimbal-lock free
24 * (both rotation matrices, sometimes called DCM, and quaternions are gimbal-lock free)
25 * rotation representations. Euler angles (roll, pitch, yaw) will be phased out of the
26 * protocol as widely as possible.
28 * @author James Goppert
29 * @author Thomas Gubler <thomasgubler@gmail.com>
34 * Converts a quaternion to a rotation matrix
36 * @param quaternion a [w, x, y, z] ordered quaternion (null-rotation being 1 0 0 0)
37 * @param dcm a 3x3 rotation matrix
39 MAVLINK_HELPER
void mavlink_quaternion_to_dcm(const float quaternion
[4], float dcm
[3][3])
41 double a
= (double)quaternion
[0];
42 double b
= (double)quaternion
[1];
43 double c
= (double)quaternion
[2];
44 double d
= (double)quaternion
[3];
49 dcm
[0][0] = aSq
+ bSq
- cSq
- dSq
;
50 dcm
[0][1] = 2 * (b
* c
- a
* d
);
51 dcm
[0][2] = 2 * (a
* c
+ b
* d
);
52 dcm
[1][0] = 2 * (b
* c
+ a
* d
);
53 dcm
[1][1] = aSq
- bSq
+ cSq
- dSq
;
54 dcm
[1][2] = 2 * (c
* d
- a
* b
);
55 dcm
[2][0] = 2 * (b
* d
- a
* c
);
56 dcm
[2][1] = 2 * (a
* b
+ c
* d
);
57 dcm
[2][2] = aSq
- bSq
- cSq
+ dSq
;
62 * Converts a rotation matrix to euler angles
64 * @param dcm a 3x3 rotation matrix
65 * @param roll the roll angle in radians
66 * @param pitch the pitch angle in radians
67 * @param yaw the yaw angle in radians
69 MAVLINK_HELPER
void mavlink_dcm_to_euler(const float dcm
[3][3], float* roll
, float* pitch
, float* yaw
)
71 float phi
, theta
, psi
;
72 theta
= asinf(-dcm
[2][0]);
74 if (fabsf(theta
- (float)M_PI_2
) < 1.0e-3f
) {
76 psi
= (atan2f(dcm
[1][2] - dcm
[0][1],
77 dcm
[0][2] + dcm
[1][1]) + phi
);
79 } else if (fabsf(theta
+ (float)M_PI_2
) < 1.0e-3f
) {
81 psi
= atan2f(dcm
[1][2] - dcm
[0][1],
82 dcm
[0][2] + dcm
[1][1] - phi
);
85 phi
= atan2f(dcm
[2][1], dcm
[2][2]);
86 psi
= atan2f(dcm
[1][0], dcm
[0][0]);
96 * Converts a quaternion to euler angles
98 * @param quaternion a [w, x, y, z] ordered quaternion (null-rotation being 1 0 0 0)
99 * @param roll the roll angle in radians
100 * @param pitch the pitch angle in radians
101 * @param yaw the yaw angle in radians
103 MAVLINK_HELPER
void mavlink_quaternion_to_euler(const float quaternion
[4], float* roll
, float* pitch
, float* yaw
)
106 mavlink_quaternion_to_dcm(quaternion
, dcm
);
107 mavlink_dcm_to_euler((const float(*)[3])dcm
, roll
, pitch
, yaw
);
112 * Converts euler angles to a quaternion
114 * @param roll the roll angle in radians
115 * @param pitch the pitch angle in radians
116 * @param yaw the yaw angle in radians
117 * @param quaternion a [w, x, y, z] ordered quaternion (null-rotation being 1 0 0 0)
119 MAVLINK_HELPER
void mavlink_euler_to_quaternion(float roll
, float pitch
, float yaw
, float quaternion
[4])
121 float cosPhi_2
= cosf(roll
/ 2);
122 float sinPhi_2
= sinf(roll
/ 2);
123 float cosTheta_2
= cosf(pitch
/ 2);
124 float sinTheta_2
= sinf(pitch
/ 2);
125 float cosPsi_2
= cosf(yaw
/ 2);
126 float sinPsi_2
= sinf(yaw
/ 2);
127 quaternion
[0] = (cosPhi_2
* cosTheta_2
* cosPsi_2
+
128 sinPhi_2
* sinTheta_2
* sinPsi_2
);
129 quaternion
[1] = (sinPhi_2
* cosTheta_2
* cosPsi_2
-
130 cosPhi_2
* sinTheta_2
* sinPsi_2
);
131 quaternion
[2] = (cosPhi_2
* sinTheta_2
* cosPsi_2
+
132 sinPhi_2
* cosTheta_2
* sinPsi_2
);
133 quaternion
[3] = (cosPhi_2
* cosTheta_2
* sinPsi_2
-
134 sinPhi_2
* sinTheta_2
* cosPsi_2
);
139 * Converts a rotation matrix to a quaternion
141 * - Shoemake, Quaternions,
142 * http://www.cs.ucr.edu/~vbz/resources/quatut.pdf
144 * @param dcm a 3x3 rotation matrix
145 * @param quaternion a [w, x, y, z] ordered quaternion (null-rotation being 1 0 0 0)
147 MAVLINK_HELPER
void mavlink_dcm_to_quaternion(const float dcm
[3][3], float quaternion
[4])
149 float tr
= dcm
[0][0] + dcm
[1][1] + dcm
[2][2];
151 float s
= sqrtf(tr
+ 1.0f
);
152 quaternion
[0] = s
* 0.5f
;
154 quaternion
[1] = (dcm
[2][1] - dcm
[1][2]) * s
;
155 quaternion
[2] = (dcm
[0][2] - dcm
[2][0]) * s
;
156 quaternion
[3] = (dcm
[1][0] - dcm
[0][1]) * s
;
158 /* Find maximum diagonal element in dcm
159 * store index in dcm_i */
162 for (i
= 1; i
< 3; i
++) {
163 if (dcm
[i
][i
] > dcm
[dcm_i
][dcm_i
]) {
168 int dcm_j
= (dcm_i
+ 1) % 3;
169 int dcm_k
= (dcm_i
+ 2) % 3;
171 float s
= sqrtf((dcm
[dcm_i
][dcm_i
] - dcm
[dcm_j
][dcm_j
] -
172 dcm
[dcm_k
][dcm_k
]) + 1.0f
);
173 quaternion
[dcm_i
+ 1] = s
* 0.5f
;
175 quaternion
[dcm_j
+ 1] = (dcm
[dcm_i
][dcm_j
] + dcm
[dcm_j
][dcm_i
]) * s
;
176 quaternion
[dcm_k
+ 1] = (dcm
[dcm_k
][dcm_i
] + dcm
[dcm_i
][dcm_k
]) * s
;
177 quaternion
[0] = (dcm
[dcm_k
][dcm_j
] - dcm
[dcm_j
][dcm_k
]) * s
;
183 * Converts euler angles to a rotation matrix
185 * @param roll the roll angle in radians
186 * @param pitch the pitch angle in radians
187 * @param yaw the yaw angle in radians
188 * @param dcm a 3x3 rotation matrix
190 MAVLINK_HELPER
void mavlink_euler_to_dcm(float roll
, float pitch
, float yaw
, float dcm
[3][3])
192 float cosPhi
= cosf(roll
);
193 float sinPhi
= sinf(roll
);
194 float cosThe
= cosf(pitch
);
195 float sinThe
= sinf(pitch
);
196 float cosPsi
= cosf(yaw
);
197 float sinPsi
= sinf(yaw
);
199 dcm
[0][0] = cosThe
* cosPsi
;
200 dcm
[0][1] = -cosPhi
* sinPsi
+ sinPhi
* sinThe
* cosPsi
;
201 dcm
[0][2] = sinPhi
* sinPsi
+ cosPhi
* sinThe
* cosPsi
;
203 dcm
[1][0] = cosThe
* sinPsi
;
204 dcm
[1][1] = cosPhi
* cosPsi
+ sinPhi
* sinThe
* sinPsi
;
205 dcm
[1][2] = -sinPhi
* cosPsi
+ cosPhi
* sinThe
* sinPsi
;
208 dcm
[2][1] = sinPhi
* cosThe
;
209 dcm
[2][2] = cosPhi
* cosThe
;
212 #endif // MAVLINK_NO_CONVERSION_HELPERS