update credits
[librepilot.git] / flight / libraries / CoordinateConversions.c
blob0b166f9271adba1e6f63f4e100a6204ad577b65d
1 /**
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.
7 * - all angles in deg
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
23 * for more details.
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
30 #include <stdint.h>
31 #include <pios_math.h>
32 #include "inc/CoordinateConversions.h"
34 #define MIN_ALLOWABLE_MAGNITUDE 1e-30f
36 // Equatorial Radius
37 #define equatorial_radius 6378137.0d
39 // Eccentricity
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;
48 double N;
49 double LLA[3] = {
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) )
71 bsq = b*b
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)
77 lon = math.atan2(y,x)
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;
117 Rne[0][2] = cosLat;
118 Rne[1][0] = -sinLon;
119 Rne[1][1] = cosLon;
120 Rne[1][2] = 0;
121 Rne[2][0] = -cosLat * cosLon;
122 Rne[2][1] = -cosLat * sinLon;
123 Rne[2][2] = -sinLat;
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);
157 cphi = cosf(phi);
158 sphi = sinf(phi);
159 ctheta = cosf(theta);
160 stheta = sinf(theta);
161 cpsi = cosf(psi);
162 spsi = sinf(psi);
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
170 q[0] = -q[0];
171 q[1] = -q[1];
172 q[2] = -q[2];
173 q[3] = -q[3];
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])
251 float ECEF[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])
260 float ECEF[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])
268 float diff[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])
282 float diff[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])
299 float m[4], mag;
300 uint8_t index, i;
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
308 index = 0;
309 mag = m[0];
310 for (i = 1; i < 4; i++) {
311 if (m[i] > mag) {
312 mag = m[i];
313 index = i;
316 mag = 2 * sqrtf(mag);
318 if (index == 0) {
319 q[0] = mag / 4;
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) {
324 q[1] = mag / 4;
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) {
329 q[2] = mag / 4;
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;
333 } else {
334 q[3] = mag / 4;
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
341 if (q[0] < 0) {
342 q[0] = -q[0];
343 q[1] = -q[1];
344 q[2] = -q[2];
345 q[3] = -q[3];
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];
355 float mag;
356 uint8_t i, j, k;
358 // identity rotation in case of error
359 for (i = 0; i < 3; i++) {
360 for (j = 0; j < 3; j++) {
361 Rbe[i][j] = 0;
363 Rbe[i][i] = 1;
366 // The first rows of rot matrices chosen in direction of v1
367 mag = VectorMagnitude(v1b);
368 if (fabsf(mag) < MIN_ALLOWABLE_MAGNITUDE) {
369 return -1;
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) {
377 return -1;
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) {
387 return -1;
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) {
396 return -1;
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++) {
409 Rbe[i][j] = 0;
410 for (k = 0; k < 3; k++) {
411 Rbe[i][j] += Rib[k][i] * Rie[k][j];
416 return 1;
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()
423 float q[4];
425 float angle = VectorMagnitude(Rv);
427 if (angle <= 0.00048828125f) {
428 // angle < sqrt(2*machine_epsilon(float)), so flush cos(x) to 1.0f
429 q[0] = 1.0f;
431 // and flush sin(x/2)/x to 0.5
432 q[1] = 0.5f * Rv[0];
433 q[2] = 0.5f * Rv[1];
434 q[3] = 0.5f * Rv[2];
435 // This prevents division by zero, while retaining full accuracy
436 } else {
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];
444 Quaternion2R(q, R);
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])
467 q[1] = -q[1];
468 q[2] = -q[2];
469 q[3] = -q[3];
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])
479 qnew[0] = q[0];
480 qnew[1] = q[1];
481 qnew[2] = q[2];
482 qnew[3] = q[3];
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];