/branches/full-calibration/flight/Libraries/CoordinateConversions.c

https://github.com/CorvusCorax/my_OpenPilot_mods · C · 217 lines · 141 code · 32 blank · 44 comment · 4 complexity · 02b2a198137929f22d79a082027210b3 MD5 · raw file

  1. /**
  2. ******************************************************************************
  3. *
  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
  10. *
  11. * @see The GNU Public License (GPL) Version 3
  12. *
  13. *****************************************************************************/
  14. /*
  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.
  19. *
  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.
  24. *
  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
  28. */
  29. #include <math.h>
  30. #include <stdint.h>
  31. #include "CoordinateConversions.h"
  32. #define RAD2DEG (180.0/M_PI)
  33. #define DEG2RAD (M_PI/180.0)
  34. // ****** convert Lat,Lon,Alt to ECEF ************
  35. void LLA2ECEF(double LLA[3], double ECEF[3])
  36. {
  37. const double a = 6378137.0; // Equatorial Radius
  38. const double e = 8.1819190842622e-2; // Eccentricity
  39. double sinLat, sinLon, cosLat, cosLon;
  40. double N;
  41. sinLat = sin(DEG2RAD * LLA[0]);
  42. sinLon = sin(DEG2RAD * LLA[1]);
  43. cosLat = cos(DEG2RAD * LLA[0]);
  44. cosLon = cos(DEG2RAD * LLA[1]);
  45. N = a / sqrt(1.0 - e * e * sinLat * sinLat); //prime vertical radius of curvature
  46. ECEF[0] = (N + LLA[2]) * cosLat * cosLon;
  47. ECEF[1] = (N + LLA[2]) * cosLat * sinLon;
  48. ECEF[2] = ((1 - e * e) * N + LLA[2]) * sinLat;
  49. }
  50. // ****** convert ECEF to Lat,Lon,Alt (ITERATIVE!) *********
  51. uint16_t ECEF2LLA(double ECEF[3], double LLA[3])
  52. {
  53. /**
  54. * LLA parameter is used to prime the iteration.
  55. * A position within 1 meter of the specified LLA
  56. * will be calculated within at most 3 iterations.
  57. * If unknown: Call with any valid LLA coordinate
  58. * will compute within at most 5 iterations.
  59. * Suggestion: [0,0,0]
  60. **/
  61. const double a = 6378137.0; // Equatorial Radius
  62. const double e = 8.1819190842622e-2; // Eccentricity
  63. double x = ECEF[0], y = ECEF[1], z = ECEF[2];
  64. double Lat, N, NplusH, delta, esLat;
  65. uint16_t iter;
  66. #define MAX_ITER 10 // should not take more than 5 for valid coordinates
  67. #define ACCURACY 1.0e-11 // used to be e-14, but we don't need sub micrometer exact calculations
  68. LLA[1] = RAD2DEG * atan2(y, x);
  69. Lat = DEG2RAD * LLA[0];
  70. esLat = e * sin(Lat);
  71. N = a / sqrt(1 - esLat * esLat);
  72. NplusH = N + LLA[2];
  73. delta = 1;
  74. iter = 0;
  75. while (((delta > ACCURACY) || (delta < -ACCURACY))
  76. && (iter < MAX_ITER)) {
  77. delta = Lat - atan(z / (sqrt(x * x + y * y) * (1 - (N * e * e / NplusH))));
  78. Lat = Lat - delta;
  79. esLat = e * sin(Lat);
  80. N = a / sqrt(1 - esLat * esLat);
  81. NplusH = sqrt(x * x + y * y) / cos(Lat);
  82. iter += 1;
  83. }
  84. LLA[0] = RAD2DEG * Lat;
  85. LLA[2] = NplusH - N;
  86. return (iter < MAX_ITER);
  87. }
  88. // ****** find ECEF to NED rotation matrix ********
  89. void RneFromLLA(double LLA[3], float Rne[3][3])
  90. {
  91. float sinLat, sinLon, cosLat, cosLon;
  92. sinLat = (float)sin(DEG2RAD * LLA[0]);
  93. sinLon = (float)sin(DEG2RAD * LLA[1]);
  94. cosLat = (float)cos(DEG2RAD * LLA[0]);
  95. cosLon = (float)cos(DEG2RAD * LLA[1]);
  96. Rne[0][0] = -sinLat * cosLon;
  97. Rne[0][1] = -sinLat * sinLon;
  98. Rne[0][2] = cosLat;
  99. Rne[1][0] = -sinLon;
  100. Rne[1][1] = cosLon;
  101. Rne[1][2] = 0;
  102. Rne[2][0] = -cosLat * cosLon;
  103. Rne[2][1] = -cosLat * sinLon;
  104. Rne[2][2] = -sinLat;
  105. }
  106. // ****** find roll, pitch, yaw from quaternion ********
  107. void Quaternion2RPY(float q[4], float rpy[3])
  108. {
  109. float R13, R11, R12, R23, R33;
  110. float q0s = q[0] * q[0];
  111. float q1s = q[1] * q[1];
  112. float q2s = q[2] * q[2];
  113. float q3s = q[3] * q[3];
  114. R13 = 2 * (q[1] * q[3] - q[0] * q[2]);
  115. R11 = q0s + q1s - q2s - q3s;
  116. R12 = 2 * (q[1] * q[2] + q[0] * q[3]);
  117. R23 = 2 * (q[2] * q[3] + q[0] * q[1]);
  118. R33 = q0s - q1s - q2s + q3s;
  119. rpy[1] = RAD2DEG * asinf(-R13); // pitch always between -pi/2 to pi/2
  120. rpy[2] = RAD2DEG * atan2f(R12, R11);
  121. rpy[0] = RAD2DEG * atan2f(R23, R33);
  122. }
  123. // ****** find quaternion from roll, pitch, yaw ********
  124. void RPY2Quaternion(float rpy[3], float q[4])
  125. {
  126. float phi, theta, psi;
  127. float cphi, sphi, ctheta, stheta, cpsi, spsi;
  128. phi = DEG2RAD * rpy[0] / 2;
  129. theta = DEG2RAD * rpy[1] / 2;
  130. psi = DEG2RAD * rpy[2] / 2;
  131. cphi = cosf(phi);
  132. sphi = sinf(phi);
  133. ctheta = cosf(theta);
  134. stheta = sinf(theta);
  135. cpsi = cosf(psi);
  136. spsi = sinf(psi);
  137. q[0] = cphi * ctheta * cpsi + sphi * stheta * spsi;
  138. q[1] = sphi * ctheta * cpsi - cphi * stheta * spsi;
  139. q[2] = cphi * stheta * cpsi + sphi * ctheta * spsi;
  140. q[3] = cphi * ctheta * spsi - sphi * stheta * cpsi;
  141. if (q[0] < 0) { // q0 always positive for uniqueness
  142. q[0] = -q[0];
  143. q[1] = -q[1];
  144. q[2] = -q[2];
  145. q[3] = -q[3];
  146. }
  147. }
  148. //** Find Rbe, that rotates a vector from earth fixed to body frame, from quaternion **
  149. void Quaternion2R(float q[4], float Rbe[3][3])
  150. {
  151. float q0s = q[0] * q[0], q1s = q[1] * q[1], q2s = q[2] * q[2], q3s = q[3] * q[3];
  152. Rbe[0][0] = q0s + q1s - q2s - q3s;
  153. Rbe[0][1] = 2 * (q[1] * q[2] + q[0] * q[3]);
  154. Rbe[0][2] = 2 * (q[1] * q[3] - q[0] * q[2]);
  155. Rbe[1][0] = 2 * (q[1] * q[2] - q[0] * q[3]);
  156. Rbe[1][1] = q0s - q1s + q2s - q3s;
  157. Rbe[1][2] = 2 * (q[2] * q[3] + q[0] * q[1]);
  158. Rbe[2][0] = 2 * (q[1] * q[3] + q[0] * q[2]);
  159. Rbe[2][1] = 2 * (q[2] * q[3] - q[0] * q[1]);
  160. Rbe[2][2] = q0s - q1s - q2s + q3s;
  161. }
  162. // ****** Express LLA in a local NED Base Frame ********
  163. void LLA2Base(double LLA[3], double BaseECEF[3], float Rne[3][3], float NED[3])
  164. {
  165. double ECEF[3];
  166. float diff[3];
  167. LLA2ECEF(LLA, ECEF);
  168. diff[0] = (float)(ECEF[0] - BaseECEF[0]);
  169. diff[1] = (float)(ECEF[1] - BaseECEF[1]);
  170. diff[2] = (float)(ECEF[2] - BaseECEF[2]);
  171. NED[0] = Rne[0][0] * diff[0] + Rne[0][1] * diff[1] + Rne[0][2] * diff[2];
  172. NED[1] = Rne[1][0] * diff[0] + Rne[1][1] * diff[1] + Rne[1][2] * diff[2];
  173. NED[2] = Rne[2][0] * diff[0] + Rne[2][1] * diff[1] + Rne[2][2] * diff[2];
  174. }
  175. // ****** Express ECEF in a local NED Base Frame ********
  176. void ECEF2Base(double ECEF[3], double BaseECEF[3], float Rne[3][3], float NED[3])
  177. {
  178. float diff[3];
  179. diff[0] = (float)(ECEF[0] - BaseECEF[0]);
  180. diff[1] = (float)(ECEF[1] - BaseECEF[1]);
  181. diff[2] = (float)(ECEF[2] - BaseECEF[2]);
  182. NED[0] = Rne[0][0] * diff[0] + Rne[0][1] * diff[1] + Rne[0][2] * diff[2];
  183. NED[1] = Rne[1][0] * diff[0] + Rne[1][1] * diff[1] + Rne[1][2] * diff[2];
  184. NED[2] = Rne[2][0] * diff[0] + Rne[2][1] * diff[1] + Rne[2][2] * diff[2];
  185. }