/Modules/AHRS/MadgwickAHRS.c

https://gitlab.com/krucios/Astraeus_FW · C · 278 lines · 190 code · 36 blank · 52 comment · 18 complexity · 77cc8abe24951cdbc422a8594eeb7602 MD5 · raw file

  1. //=====================================================================================================
  2. // MadgwickAHRS.c
  3. //=====================================================================================================
  4. //
  5. // Implementation of Madgwick's IMU and AHRS algorithms.
  6. // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
  7. //
  8. // Date Author Notes
  9. // 29/09/2011 SOH Madgwick Initial release
  10. // 02/10/2011 SOH Madgwick Optimised for reduced CPU load
  11. // 19/02/2012 SOH Madgwick Magnetometer measurement is normalised
  12. //
  13. //=====================================================================================================
  14. //---------------------------------------------------------------------------------------------------
  15. // Header files
  16. #include "MadgwickAHRS.h"
  17. #include <math.h>
  18. #include <Modules/Time/timer.h>
  19. //---------------------------------------------------------------------------------------------------
  20. // Definitions
  21. #define sampleFreq (MSS_TIM1_FREQ * 1.0f) // sample frequency in Hz
  22. #define betaDef (M_PI * (5.0f / 180.0f) * 0.86602540378f) // 2 * proportional gain (sqrt(3)/2)
  23. //---------------------------------------------------------------------------------------------------
  24. // Variable definitions
  25. volatile float beta = betaDef; // 2 * proportional gain (Kp)
  26. float q[4] = {1.0f, 0.0f, 0.0f, 0.0f}; // quaternion of sensor frame relative to auxiliary frame
  27. //---------------------------------------------------------------------------------------------------
  28. // Function declarations
  29. float invSqrt(float x);
  30. //====================================================================================================
  31. // Functions
  32. //---------------------------------------------------------------------------------------------------
  33. // AHRS algorithm update
  34. void MadgwickAHRSupdate(float gx, float gy, float gz,
  35. float ax, float ay, float az,
  36. float mx, float my, float mz) {
  37. float recipNorm;
  38. float s0, s1, s2, s3;
  39. float qDot1, qDot2, qDot3, qDot4;
  40. float hx, hy;
  41. float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1,
  42. _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2,
  43. q1q3, q2q2, q2q3, q3q3;
  44. // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)
  45. if ((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {
  46. MadgwickAHRSupdateIMU(gx, gy, gz, ax, ay, az);
  47. return;
  48. }
  49. // Rate of change of quaternion from gyroscope
  50. qDot1 = 0.5f * (-q[1] * gx - q[2] * gy - q[3] * gz);
  51. qDot2 = 0.5f * (q[0] * gx + q[2] * gz - q[3] * gy);
  52. qDot3 = 0.5f * (q[0] * gy - q[1] * gz + q[3] * gx);
  53. qDot4 = 0.5f * (q[0] * gz + q[1] * gy - q[2] * gx);
  54. // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
  55. if (!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
  56. // Normalise accelerometer measurement
  57. recipNorm = invSqrt(ax * ax + ay * ay + az * az);
  58. ax *= recipNorm;
  59. ay *= recipNorm;
  60. az *= recipNorm;
  61. // Normalise magnetometer measurement
  62. recipNorm = invSqrt(mx * mx + my * my + mz * mz);
  63. mx *= recipNorm;
  64. my *= recipNorm;
  65. mz *= recipNorm;
  66. // Auxiliary variables to avoid repeated arithmetic
  67. _2q0mx = 2.0f * q[0] * mx;
  68. _2q0my = 2.0f * q[0] * my;
  69. _2q0mz = 2.0f * q[0] * mz;
  70. _2q1mx = 2.0f * q[1] * mx;
  71. _2q0 = 2.0f * q[0];
  72. _2q1 = 2.0f * q[1];
  73. _2q2 = 2.0f * q[2];
  74. _2q3 = 2.0f * q[3];
  75. _2q0q2 = 2.0f * q[0] * q[2];
  76. _2q2q3 = 2.0f * q[2] * q[3];
  77. q0q0 = q[0] * q[0];
  78. q0q1 = q[0] * q[1];
  79. q0q2 = q[0] * q[2];
  80. q0q3 = q[0] * q[3];
  81. q1q1 = q[1] * q[1];
  82. q1q2 = q[1] * q[2];
  83. q1q3 = q[1] * q[3];
  84. q2q2 = q[2] * q[2];
  85. q2q3 = q[2] * q[3];
  86. q3q3 = q[3] * q[3];
  87. // Reference direction of Earth's magnetic field
  88. hx = mx * q0q0 - _2q0my * q[3] + _2q0mz * q[2] + mx * q1q1 + _2q1 * my * q[2]
  89. + _2q1 * mz * q[3] - mx * q2q2 - mx * q3q3;
  90. hy = _2q0mx * q[3] + my * q0q0 - _2q0mz * q[1] + _2q1mx * q[2] - my * q1q1
  91. + my * q2q2 + _2q2 * mz * q[3] - my * q3q3;
  92. _2bx = sqrt(hx * hx + hy * hy);
  93. _2bz = -_2q0mx * q[2] + _2q0my * q[1] + mz * q0q0 + _2q1mx * q[3] - mz * q1q1
  94. + _2q2 * my * q[3] - mz * q2q2 + mz * q3q3;
  95. _4bx = 2.0f * _2bx;
  96. _4bz = 2.0f * _2bz;
  97. // Gradient decent algorithm corrective step
  98. s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax)
  99. + _2q1 * (2.0f * q0q1 + _2q2q3 - ay)
  100. - _2bz * q[2]
  101. * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2)
  102. - mx)
  103. + (-_2bx * q[3] + _2bz * q[1])
  104. * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my)
  105. + _2bx * q[2]
  106. * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2)
  107. - mz);
  108. s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax)
  109. + _2q0 * (2.0f * q0q1 + _2q2q3 - ay)
  110. - 4.0f * q[1] * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az)
  111. + _2bz * q[3]
  112. * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2)
  113. - mx)
  114. + (_2bx * q[2] + _2bz * q[0])
  115. * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my)
  116. + (_2bx * q[3] - _4bz * q[1])
  117. * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2)
  118. - mz);
  119. s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax)
  120. + _2q3 * (2.0f * q0q1 + _2q2q3 - ay)
  121. - 4.0f * q[2] * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az)
  122. + (-_4bx * q[2] - _2bz * q[0])
  123. * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2)
  124. - mx)
  125. + (_2bx * q[1] + _2bz * q[3])
  126. * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my)
  127. + (_2bx * q[0] - _4bz * q[2])
  128. * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2)
  129. - mz);
  130. s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax)
  131. + _2q2 * (2.0f * q0q1 + _2q2q3 - ay)
  132. + (-_4bx * q[3] + _2bz * q[1])
  133. * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2)
  134. - mx)
  135. + (-_2bx * q[0] + _2bz * q[2])
  136. * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my)
  137. + _2bx * q[1]
  138. * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2)
  139. - mz);
  140. recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
  141. s0 *= recipNorm;
  142. s1 *= recipNorm;
  143. s2 *= recipNorm;
  144. s3 *= recipNorm;
  145. // Apply feedback step
  146. qDot1 -= beta * s0;
  147. qDot2 -= beta * s1;
  148. qDot3 -= beta * s2;
  149. qDot4 -= beta * s3;
  150. }
  151. // Integrate rate of change of quaternion to yield quaternion
  152. q[0] += qDot1 * (1.0f / sampleFreq);
  153. q[1] += qDot2 * (1.0f / sampleFreq);
  154. q[2] += qDot3 * (1.0f / sampleFreq);
  155. q[3] += qDot4 * (1.0f / sampleFreq);
  156. // Normalise quaternion
  157. recipNorm = invSqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
  158. q[0] *= recipNorm;
  159. q[1] *= recipNorm;
  160. q[2] *= recipNorm;
  161. q[3] *= recipNorm;
  162. }
  163. //---------------------------------------------------------------------------------------------------
  164. // IMU algorithm update
  165. void MadgwickAHRSupdateIMU(float gx, float gy, float gz,
  166. float ax, float ay, float az) {
  167. float recipNorm;
  168. float s0, s1, s2, s3;
  169. float qDot1, qDot2, qDot3, qDot4;
  170. float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2, _8q1, _8q2, q0q0, q1q1,
  171. q2q2, q3q3;
  172. // Rate of change of quaternion from gyroscope
  173. qDot1 = 0.5f * (-q[1] * gx - q[2] * gy - q[3] * gz);
  174. qDot2 = 0.5f * (q[0] * gx + q[2] * gz - q[3] * gy);
  175. qDot3 = 0.5f * (q[0] * gy - q[1] * gz + q[3] * gx);
  176. qDot4 = 0.5f * (q[0] * gz + q[1] * gy - q[2] * gx);
  177. // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
  178. if (!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
  179. // Normalise accelerometer measurement
  180. recipNorm = invSqrt(ax * ax + ay * ay + az * az);
  181. ax *= recipNorm;
  182. ay *= recipNorm;
  183. az *= recipNorm;
  184. // Auxiliary variables to avoid repeated arithmetic
  185. _2q0 = 2.0f * q[0];
  186. _2q1 = 2.0f * q[1];
  187. _2q2 = 2.0f * q[2];
  188. _2q3 = 2.0f * q[3];
  189. _4q0 = 4.0f * q[0];
  190. _4q1 = 4.0f * q[1];
  191. _4q2 = 4.0f * q[2];
  192. _8q1 = 8.0f * q[1];
  193. _8q2 = 8.0f * q[2];
  194. q0q0 = q[0] * q[0];
  195. q1q1 = q[1] * q[1];
  196. q2q2 = q[2] * q[2];
  197. q3q3 = q[3] * q[3];
  198. // Gradient decent algorithm corrective step
  199. s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;
  200. s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q[1] - _2q0 * ay - _4q1
  201. + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;
  202. s2 = 4.0f * q0q0 * q[2] + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2
  203. + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;
  204. s3 = 4.0f * q1q1 * q[3] - _2q1 * ax + 4.0f * q2q2 * q[3] - _2q2 * ay;
  205. recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
  206. s0 *= recipNorm;
  207. s1 *= recipNorm;
  208. s2 *= recipNorm;
  209. s3 *= recipNorm;
  210. // Apply feedback step
  211. qDot1 -= beta * s0;
  212. qDot2 -= beta * s1;
  213. qDot3 -= beta * s2;
  214. qDot4 -= beta * s3;
  215. }
  216. // Integrate rate of change of quaternion to yield quaternion
  217. q[0] += qDot1 * (1.0f / sampleFreq);
  218. q[1] += qDot2 * (1.0f / sampleFreq);
  219. q[2] += qDot3 * (1.0f / sampleFreq);
  220. q[3] += qDot4 * (1.0f / sampleFreq);
  221. // Normalise quaternion
  222. recipNorm = invSqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
  223. q[0] *= recipNorm;
  224. q[1] *= recipNorm;
  225. q[2] *= recipNorm;
  226. q[3] *= recipNorm;
  227. }
  228. //---------------------------------------------------------------------------------------------------
  229. // Fast inverse square-root
  230. // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
  231. float invSqrt(float x) {
  232. float halfx = 0.5f * x;
  233. float y = x;
  234. long i = *(long*) &y;
  235. i = 0x5f3759df - (i >> 1);
  236. y = *(float*) &i;
  237. y = y * (1.5f - (halfx * y * y));
  238. return y;
  239. }
  240. //====================================================================================================
  241. // END OF CODE
  242. //====================================================================================================