2 ******************************************************************************
4 * @file CoordinateConversions.c
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @brief General conversions with different coordinate systems.
8 * - distances in meters
9 * - altitude above WGS-84 elipsoid
11 * @see The GNU Public License (GPL) Version 3
13 *****************************************************************************/
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <pios_math.h>
32 #include "inc/CoordinateConversions.h"
34 #define MIN_ALLOWABLE_MAGNITUDE 1e-30f
37 #define equatorial_radius 6378137.0d
40 #define eccentricity 8.1819190842622e-2d
41 #define equatorial_radius_sq (equatorial_radius * equatorial_radius)
42 #define eccentricity_sq (eccentricity * eccentricity)
44 // ****** convert Lat,Lon,Alt to ECEF ************
45 void LLA2ECEF(const int32_t LLAi
[3], float ECEF
[3])
47 double sinLat
, sinLon
, cosLat
, cosLon
;
50 ((double)LLAi
[0]) * 1e-7d
,
51 ((double)LLAi
[1]) * 1e-7d
,
52 ((double)LLAi
[2]) * 1e-4d
55 sinLat
= sin(DEG2RAD_D(LLA
[0]));
56 sinLon
= sin(DEG2RAD_D(LLA
[1]));
57 cosLat
= cos(DEG2RAD_D(LLA
[0]));
58 cosLon
= cos(DEG2RAD_D(LLA
[1]));
60 N
= equatorial_radius
/ sqrt(1.0d
- eccentricity_sq
* sinLat
* sinLat
); // prime vertical radius of curvature
62 ECEF
[0] = (float)((N
+ LLA
[2]) * cosLat
* cosLon
);
63 ECEF
[1] = (float)((N
+ LLA
[2]) * cosLat
* sinLon
);
64 ECEF
[2] = (float)(((1.0d
- eccentricity_sq
) * N
+ LLA
[2]) * sinLat
);
67 // ****** convert ECEF to Lat,Lon,Alt (ITERATIVE!) *********
68 void ECEF2LLA(const float ECEF
[3], int32_t LLA
[3])
70 /* b = math.sqrt( asq * (1-esq) )
73 ep = math.sqrt((asq - bsq)/bsq)
74 p = math.sqrt( math.pow(x,2) + math.pow(y,2) )
75 th = math.atan2(a*z, b*p)
78 lat = math.atan2( (z + ep*ep *b * math.pow(math.sin(th),3) ), (p - esq*a*math.pow(math.cos(th),3)) )
79 N = a/( math.sqrt(1-esq*math.pow(math.sin(lat),2)) )
80 alt = p / math.cos(lat) - N*/
82 const double x
= ECEF
[0], y
= ECEF
[1], z
= ECEF
[2];
84 const double b
= sqrt(equatorial_radius_sq
* (1 - eccentricity_sq
));
85 const double bsq
= b
* b
;
86 const double ep
= sqrt((equatorial_radius_sq
- bsq
) / bsq
);
88 const double p
= sqrt(x
* x
+ y
* y
);
89 const double th
= atan2(equatorial_radius
* z
, b
* p
);
91 double lon
= atan2(y
, x
);
93 const double lat
= atan2(
94 (z
+ ep
* ep
* b
* pow(sin(th
), 3)),
95 (p
- eccentricity_sq
* equatorial_radius
* pow(cos(th
), 3))
97 const double N
= equatorial_radius
/ (sqrt(1 - eccentricity_sq
* pow(sin(lat
), 2)));
98 const double alt
= p
/ cos(lat
) - N
;
100 LLA
[0] = (int32_t)(RAD2DEG_D(lat
) * 1e7d
);
101 LLA
[1] = (int32_t)(RAD2DEG_D(lon
) * 1e7d
) % ((int32_t)(180 * 1e7d
));
102 LLA
[2] = (int32_t)(alt
* 1e4d
);
105 // ****** find ECEF to NED rotation matrix ********
106 void RneFromLLA(const int32_t LLAi
[3], float Rne
[3][3])
108 float sinLat
, sinLon
, cosLat
, cosLon
;
110 sinLat
= sinf(DEG2RAD((float)LLAi
[0] * 1e-7f
));
111 sinLon
= sinf(DEG2RAD((float)LLAi
[1] * 1e-7f
));
112 cosLat
= cosf(DEG2RAD((float)LLAi
[0] * 1e-7f
));
113 cosLon
= cosf(DEG2RAD((float)LLAi
[1] * 1e-7f
));
115 Rne
[0][0] = -sinLat
* cosLon
;
116 Rne
[0][1] = -sinLat
* sinLon
;
121 Rne
[2][0] = -cosLat
* cosLon
;
122 Rne
[2][1] = -cosLat
* sinLon
;
126 // ****** find roll, pitch, yaw from quaternion ********
127 void Quaternion2RPY(const float q
[4], float rpy
[3])
129 float R13
, R11
, R12
, R23
, R33
;
130 float q0s
= q
[0] * q
[0];
131 float q1s
= q
[1] * q
[1];
132 float q2s
= q
[2] * q
[2];
133 float q3s
= q
[3] * q
[3];
135 R13
= 2.0f
* (q
[1] * q
[3] - q
[0] * q
[2]);
136 R11
= q0s
+ q1s
- q2s
- q3s
;
137 R12
= 2.0f
* (q
[1] * q
[2] + q
[0] * q
[3]);
138 R23
= 2.0f
* (q
[2] * q
[3] + q
[0] * q
[1]);
139 R33
= q0s
- q1s
- q2s
+ q3s
;
141 rpy
[1] = RAD2DEG(asinf(-R13
)); // pitch always between -pi/2 to pi/2
142 rpy
[2] = RAD2DEG(atan2f(R12
, R11
));
143 rpy
[0] = RAD2DEG(atan2f(R23
, R33
));
145 // TODO: consider the cases where |R13| ~= 1, |pitch| ~= pi/2
148 // ****** find quaternion from roll, pitch, yaw ********
149 void RPY2Quaternion(const float rpy
[3], float q
[4])
151 float phi
, theta
, psi
;
152 float cphi
, sphi
, ctheta
, stheta
, cpsi
, spsi
;
154 phi
= DEG2RAD(rpy
[0] / 2);
155 theta
= DEG2RAD(rpy
[1] / 2);
156 psi
= DEG2RAD(rpy
[2] / 2);
159 ctheta
= cosf(theta
);
160 stheta
= sinf(theta
);
164 q
[0] = cphi
* ctheta
* cpsi
+ sphi
* stheta
* spsi
;
165 q
[1] = sphi
* ctheta
* cpsi
- cphi
* stheta
* spsi
;
166 q
[2] = cphi
* stheta
* cpsi
+ sphi
* ctheta
* spsi
;
167 q
[3] = cphi
* ctheta
* spsi
- sphi
* stheta
* cpsi
;
169 if (q
[0] < 0) { // q0 always positive for uniqueness
177 // ** Find Rbe, that rotates a vector from earth fixed to body frame, from quaternion **
178 void Quaternion2R(float q
[4], float Rbe
[3][3])
180 const float q0s
= q
[0] * q
[0], q1s
= q
[1] * q
[1], q2s
= q
[2] * q
[2], q3s
= q
[3] * q
[3];
182 Rbe
[0][0] = q0s
+ q1s
- q2s
- q3s
;
183 Rbe
[0][1] = 2 * (q
[1] * q
[2] + q
[0] * q
[3]);
184 Rbe
[0][2] = 2 * (q
[1] * q
[3] - q
[0] * q
[2]);
185 Rbe
[1][0] = 2 * (q
[1] * q
[2] - q
[0] * q
[3]);
186 Rbe
[1][1] = q0s
- q1s
+ q2s
- q3s
;
187 Rbe
[1][2] = 2 * (q
[2] * q
[3] + q
[0] * q
[1]);
188 Rbe
[2][0] = 2 * (q
[1] * q
[3] + q
[0] * q
[2]);
189 Rbe
[2][1] = 2 * (q
[2] * q
[3] - q
[0] * q
[1]);
190 Rbe
[2][2] = q0s
- q1s
- q2s
+ q3s
;
194 // ** Find first row of Rbe, that rotates a vector from earth fixed to body frame, from quaternion **
195 // ** This vector corresponds to the fuselage/roll vector xB **
196 void QuaternionC2xB(const float q0
, const float q1
, const float q2
, const float q3
, float x
[3])
198 const float q0s
= q0
* q0
, q1s
= q1
* q1
, q2s
= q2
* q2
, q3s
= q3
* q3
;
200 x
[0] = q0s
+ q1s
- q2s
- q3s
;
201 x
[1] = 2 * (q1
* q2
+ q0
* q3
);
202 x
[2] = 2 * (q1
* q3
- q0
* q2
);
206 void Quaternion2xB(const float q
[4], float x
[3])
208 QuaternionC2xB(q
[0], q
[1], q
[2], q
[3], x
);
212 // ** Find second row of Rbe, that rotates a vector from earth fixed to body frame, from quaternion **
213 // ** This vector corresponds to the spanwise/pitch vector yB **
214 void QuaternionC2yB(const float q0
, const float q1
, const float q2
, const float q3
, float y
[3])
216 const float q0s
= q0
* q0
, q1s
= q1
* q1
, q2s
= q2
* q2
, q3s
= q3
* q3
;
218 y
[0] = 2 * (q1
* q2
- q0
* q3
);
219 y
[1] = q0s
- q1s
+ q2s
- q3s
;
220 y
[2] = 2 * (q2
* q3
+ q0
* q1
);
224 void Quaternion2yB(const float q
[4], float y
[3])
226 QuaternionC2yB(q
[0], q
[1], q
[2], q
[3], y
);
230 // ** Find third row of Rbe, that rotates a vector from earth fixed to body frame, from quaternion **
231 // ** This vector corresponds to the vertical/yaw vector zB **
232 void QuaternionC2zB(const float q0
, const float q1
, const float q2
, const float q3
, float z
[3])
234 const float q0s
= q0
* q0
, q1s
= q1
* q1
, q2s
= q2
* q2
, q3s
= q3
* q3
;
236 z
[0] = 2 * (q1
* q3
+ q0
* q2
);
237 z
[1] = 2 * (q2
* q3
- q0
* q1
);
238 z
[2] = q0s
- q1s
- q2s
+ q3s
;
242 void Quaternion2zB(const float q
[4], float z
[3])
244 QuaternionC2zB(q
[0], q
[1], q
[2], q
[3], z
);
248 // ****** Express LLA in a local NED Base Frame ********
249 void LLA2Base(const int32_t LLAi
[3], const float BaseECEF
[3], float Rne
[3][3], float NED
[3])
253 LLA2ECEF(LLAi
, ECEF
);
254 ECEF2Base(ECEF
, BaseECEF
, Rne
, NED
);
257 // ****** Express LLA in a local NED Base Frame ********
258 void Base2LLA(const float NED
[3], const float BaseECEF
[3], float Rne
[3][3], int32_t LLAi
[3])
262 Base2ECEF(NED
, BaseECEF
, Rne
, ECEF
);
263 ECEF2LLA(ECEF
, LLAi
);
265 // ****** Express ECEF in a local NED Base Frame ********
266 void ECEF2Base(const float ECEF
[3], const float BaseECEF
[3], float Rne
[3][3], float NED
[3])
270 diff
[0] = (ECEF
[0] - BaseECEF
[0]);
271 diff
[1] = (ECEF
[1] - BaseECEF
[1]);
272 diff
[2] = (ECEF
[2] - BaseECEF
[2]);
274 NED
[0] = Rne
[0][0] * diff
[0] + Rne
[0][1] * diff
[1] + Rne
[0][2] * diff
[2];
275 NED
[1] = Rne
[1][0] * diff
[0] + Rne
[1][1] * diff
[1] + Rne
[1][2] * diff
[2];
276 NED
[2] = Rne
[2][0] * diff
[0] + Rne
[2][1] * diff
[1] + Rne
[2][2] * diff
[2];
279 // ****** Express ECEF in a local NED Base Frame ********
280 void Base2ECEF(const float NED
[3], const float BaseECEF
[3], float Rne
[3][3], float ECEF
[3])
284 diff
[0] = Rne
[0][0] * NED
[0] + Rne
[1][0] * NED
[1] + Rne
[2][0] * NED
[2];
285 diff
[1] = Rne
[0][1] * NED
[0] + Rne
[1][1] * NED
[1] + Rne
[2][1] * NED
[2];
286 diff
[2] = Rne
[0][2] * NED
[0] + Rne
[1][2] * NED
[1] + Rne
[2][2] * NED
[2];
289 ECEF
[0] = diff
[0] + BaseECEF
[0];
290 ECEF
[1] = diff
[1] + BaseECEF
[1];
291 ECEF
[2] = diff
[2] + BaseECEF
[2];
295 // ****** convert Rotation Matrix to Quaternion ********
296 // ****** if R converts from e to b, q is rotation from e to b ****
297 void R2Quaternion(float R
[3][3], float q
[4])
302 m
[0] = 1 + R
[0][0] + R
[1][1] + R
[2][2];
303 m
[1] = 1 + R
[0][0] - R
[1][1] - R
[2][2];
304 m
[2] = 1 - R
[0][0] + R
[1][1] - R
[2][2];
305 m
[3] = 1 - R
[0][0] - R
[1][1] + R
[2][2];
307 // find maximum divisor
310 for (i
= 1; i
< 4; i
++) {
316 mag
= 2 * sqrtf(mag
);
320 q
[1] = (R
[1][2] - R
[2][1]) / mag
;
321 q
[2] = (R
[2][0] - R
[0][2]) / mag
;
322 q
[3] = (R
[0][1] - R
[1][0]) / mag
;
323 } else if (index
== 1) {
325 q
[0] = (R
[1][2] - R
[2][1]) / mag
;
326 q
[2] = (R
[0][1] + R
[1][0]) / mag
;
327 q
[3] = (R
[0][2] + R
[2][0]) / mag
;
328 } else if (index
== 2) {
330 q
[0] = (R
[2][0] - R
[0][2]) / mag
;
331 q
[1] = (R
[0][1] + R
[1][0]) / mag
;
332 q
[3] = (R
[1][2] + R
[2][1]) / mag
;
335 q
[0] = (R
[0][1] - R
[1][0]) / mag
;
336 q
[1] = (R
[0][2] + R
[2][0]) / mag
;
337 q
[2] = (R
[1][2] + R
[2][1]) / mag
;
340 // q0 positive, i.e. angle between pi and -pi
349 // ****** Rotation Matrix from Two Vector Directions ********
350 // ****** given two vector directions (v1 and v2) known in two frames (b and e) find Rbe ***
351 // ****** solution is approximate if can't be exact ***
352 uint8_t RotFrom2Vectors(const float v1b
[3], const float v1e
[3], const float v2b
[3], const float v2e
[3], float Rbe
[3][3])
354 float Rib
[3][3], Rie
[3][3];
358 // identity rotation in case of error
359 for (i
= 0; i
< 3; i
++) {
360 for (j
= 0; j
< 3; j
++) {
366 // The first rows of rot matrices chosen in direction of v1
367 mag
= VectorMagnitude(v1b
);
368 if (fabsf(mag
) < MIN_ALLOWABLE_MAGNITUDE
) {
371 for (i
= 0; i
< 3; i
++) {
372 Rib
[0][i
] = v1b
[i
] / mag
;
375 mag
= VectorMagnitude(v1e
);
376 if (fabsf(mag
) < MIN_ALLOWABLE_MAGNITUDE
) {
379 for (i
= 0; i
< 3; i
++) {
380 Rie
[0][i
] = v1e
[i
] / mag
;
383 // The second rows of rot matrices chosen in direction of v1xv2
384 CrossProduct(v1b
, v2b
, &Rib
[1][0]);
385 mag
= VectorMagnitude(&Rib
[1][0]);
386 if (fabsf(mag
) < MIN_ALLOWABLE_MAGNITUDE
) {
389 for (i
= 0; i
< 3; i
++) {
390 Rib
[1][i
] = Rib
[1][i
] / mag
;
393 CrossProduct(v1e
, v2e
, &Rie
[1][0]);
394 mag
= VectorMagnitude(&Rie
[1][0]);
395 if (fabsf(mag
) < MIN_ALLOWABLE_MAGNITUDE
) {
398 for (i
= 0; i
< 3; i
++) {
399 Rie
[1][i
] = Rie
[1][i
] / mag
;
402 // The third rows of rot matrices are XxY (Row1xRow2)
403 CrossProduct(&Rib
[0][0], &Rib
[1][0], &Rib
[2][0]);
404 CrossProduct(&Rie
[0][0], &Rie
[1][0], &Rie
[2][0]);
406 // Rbe = Rbi*Rie = Rib'*Rie
407 for (i
= 0; i
< 3; i
++) {
408 for (j
= 0; j
< 3; j
++) {
410 for (k
= 0; k
< 3; k
++) {
411 Rbe
[i
][j
] += Rib
[k
][i
] * Rie
[k
][j
];
419 void Rv2Rot(float Rv
[3], float R
[3][3])
421 // Compute rotation matrix from a rotation vector
422 // To save .text space, uses Quaternion2R()
425 float angle
= VectorMagnitude(Rv
);
427 if (angle
<= 0.00048828125f
) {
428 // angle < sqrt(2*machine_epsilon(float)), so flush cos(x) to 1.0f
431 // and flush sin(x/2)/x to 0.5
435 // This prevents division by zero, while retaining full accuracy
437 q
[0] = cosf(angle
* 0.5f
);
438 float scale
= sinf(angle
* 0.5f
) / angle
;
439 q
[1] = scale
* Rv
[0];
440 q
[2] = scale
* Rv
[1];
441 q
[3] = scale
* Rv
[2];
447 // ****** Vector Cross Product ********
448 void CrossProduct(const float v1
[3], const float v2
[3], float result
[3])
450 result
[0] = v1
[1] * v2
[2] - v2
[1] * v1
[2];
451 result
[1] = v2
[0] * v1
[2] - v1
[0] * v2
[2];
452 result
[2] = v1
[0] * v2
[1] - v2
[0] * v1
[1];
455 // ****** Vector Magnitude ********
456 float VectorMagnitude(const float v
[3])
458 return sqrtf(v
[0] * v
[0] + v
[1] * v
[1] + v
[2] * v
[2]);
462 * @brief Compute the inverse of a quaternion
463 * @param [in][out] q The matrix to invert
465 void quat_inverse(float q
[4])
473 * @brief Duplicate a quaternion
474 * @param[in] q quaternion in
475 * @param[out] qnew quaternion to copy to
477 void quat_copy(const float q
[4], float qnew
[4])
486 * @brief Multiply two quaternions into a third
487 * @param[in] q1 First quaternion
488 * @param[in] q2 Second quaternion
489 * @param[out] qout Output quaternion
491 void quat_mult(const float q1
[4], const float q2
[4], float qout
[4])
493 qout
[0] = q1
[0] * q2
[0] - q1
[1] * q2
[1] - q1
[2] * q2
[2] - q1
[3] * q2
[3];
494 qout
[1] = q1
[0] * q2
[1] + q1
[1] * q2
[0] + q1
[2] * q2
[3] - q1
[3] * q2
[2];
495 qout
[2] = q1
[0] * q2
[2] - q1
[1] * q2
[3] + q1
[2] * q2
[0] + q1
[3] * q2
[1];
496 qout
[3] = q1
[0] * q2
[3] + q1
[1] * q2
[2] - q1
[2] * q2
[1] + q1
[3] * q2
[0];
500 * @brief Rotate a vector by a rotation matrix
501 * @param[in] R a three by three rotation matrix (first index is row)
502 * @param[in] vec the source vector
503 * @param[out] vec_out the output vector
505 void rot_mult(float R
[3][3], const float vec
[3], float vec_out
[3])
507 vec_out
[0] = R
[0][0] * vec
[0] + R
[0][1] * vec
[1] + R
[0][2] * vec
[2];
508 vec_out
[1] = R
[1][0] * vec
[0] + R
[1][1] * vec
[1] + R
[1][2] * vec
[2];
509 vec_out
[2] = R
[2][0] * vec
[0] + R
[2][1] * vec
[1] + R
[2][2] * vec
[2];