MahonyAHRS.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. //=============================================================================================
  2. // MahonyAHRS.c
  3. //=============================================================================================
  4. //
  5. // Madgwick's implementation of Mayhony's AHRS algorithm.
  6. // See: http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/
  7. //
  8. // From the x-io website "Open-source resources available on this website are
  9. // provided under the GNU General Public Licence unless an alternative licence
  10. // is provided in source."
  11. //
  12. // Date Author Notes
  13. // 29/09/2011 SOH Madgwick Initial release
  14. // 02/10/2011 SOH Madgwick Optimised for reduced CPU load
  15. //
  16. // Algorithm paper:
  17. // http://ieeexplore.ieee.org/xpl/login.jsp?tp=&arnumber=4608934&url=http%3A%2F%2Fieeexplore.ieee.org%2Fstamp%2Fstamp.jsp%3Ftp%3D%26arnumber%3D4608934
  18. //
  19. //=============================================================================================
  20. //-------------------------------------------------------------------------------------------
  21. // Header files
  22. #include "MahonyAHRS.h"
  23. #include "bll_imu.h"
  24. #include <math.h>
  25. #include "system.h"
  26. //-------------------------------------------------------------------------------------------
  27. // Definitions
  28. float twoKi; // 2 * integral gain (Ki)
  29. float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame
  30. float integralFBx, integralFBy, integralFBz; // integral error terms scaled by Ki
  31. float invSampleFreq;
  32. float roll;
  33. float pitch, yaw;
  34. char anglesComputed;
  35. #define twoKpDef (20.0f * 0.5f) // 2 * proportional gain
  36. #define twoKiDef (0.0f * 1.0f) // 2 * integral gain
  37. void Mahony_Init(float sampleFrequency)
  38. {
  39. twoKi = twoKiDef; // 2 * integral gain (Ki)
  40. q0 = 1.0f;
  41. q1 = 0.0f;
  42. q2 = 0.0f;
  43. q3 = 0.0f;
  44. integralFBx = 0.0f;
  45. integralFBy = 0.0f;
  46. integralFBz = 0.0f;
  47. anglesComputed = 0;
  48. invSampleFreq = 1.0f / sampleFrequency;
  49. }
  50. float Mahony_invSqrt(float x)
  51. {
  52. float halfx = 0.5f * x;
  53. float y = x;
  54. long i = *(long*)&y;
  55. i = 0x5f3759df - (i>>1);
  56. y = *(float*)&i;
  57. y = y * (1.5f - (halfx * y * y));
  58. y = y * (1.5f - (halfx * y * y));
  59. return y;
  60. }
  61. void Mahony_update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz)
  62. {
  63. float recipNorm;
  64. float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
  65. float hx, hy, bx, bz;
  66. float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz;
  67. float halfex, halfey, halfez;
  68. float qa, qb, qc;
  69. // Compute feedback only if accelerometer measurement valid
  70. // (avoids NaN in accelerometer normalisation)
  71. if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
  72. // Normalise accelerometer measurement
  73. recipNorm = Mahony_invSqrt(ax * ax + ay * ay + az * az);
  74. ax *= recipNorm;
  75. ay *= recipNorm;
  76. az *= recipNorm;
  77. // Normalise magnetometer measurement
  78. recipNorm = Mahony_invSqrt(mx * mx + my * my + mz * mz);
  79. mx *= recipNorm;
  80. my *= recipNorm;
  81. mz *= recipNorm;
  82. // Auxiliary variables to avoid repeated arithmetic
  83. q0q0 = q0 * q0;
  84. q0q1 = q0 * q1;
  85. q0q2 = q0 * q2;
  86. q0q3 = q0 * q3;
  87. q1q1 = q1 * q1;
  88. q1q2 = q1 * q2;
  89. q1q3 = q1 * q3;
  90. q2q2 = q2 * q2;
  91. q2q3 = q2 * q3;
  92. q3q3 = q3 * q3;
  93. // Reference direction of Earth's magnetic field
  94. hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
  95. hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
  96. bx = sqrtf(hx * hx + hy * hy);
  97. bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2));
  98. // Estimated direction of gravity and magnetic field
  99. halfvx = q1q3 - q0q2;
  100. halfvy = q0q1 + q2q3;
  101. halfvz = q0q0 - 0.5f + q3q3;
  102. halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
  103. halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
  104. halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
  105. // Error is sum of cross product between estimated direction
  106. // and measured direction of field vectors
  107. halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy);
  108. halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz);
  109. halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx);
  110. // Compute and apply integral feedback if enabled
  111. if(twoKi > 0.0f) {
  112. // integral error scaled by Ki
  113. integralFBx += twoKi * halfex * invSampleFreq;
  114. integralFBy += twoKi * halfey * invSampleFreq;
  115. integralFBz += twoKi * halfez * invSampleFreq;
  116. gx += integralFBx; // apply integral feedback
  117. gy += integralFBy;
  118. gz += integralFBz;
  119. } else {
  120. integralFBx = 0.0f; // prevent integral windup
  121. integralFBy = 0.0f;
  122. integralFBz = 0.0f;
  123. }
  124. // Apply proportional feedback
  125. gx += twoKpDef * halfex;
  126. gy += twoKpDef * halfey;
  127. gz += twoKpDef * halfez;
  128. }
  129. // Integrate rate of change of quaternion
  130. gx *= (0.5f * invSampleFreq); // pre-multiply common factors
  131. gy *= (0.5f * invSampleFreq);
  132. gz *= (0.5f * invSampleFreq);
  133. qa = q0;
  134. qb = q1;
  135. qc = q2;
  136. q0 += (-qb * gx - qc * gy - q3 * gz);
  137. q1 += (qa * gx + qc * gz - q3 * gy);
  138. q2 += (qa * gy - qb * gz + q3 * gx);
  139. q3 += (qa * gz + qb * gy - qc * gx);
  140. // Normalise quaternion
  141. recipNorm = Mahony_invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
  142. q0 *= recipNorm;
  143. q1 *= recipNorm;
  144. q2 *= recipNorm;
  145. q3 *= recipNorm;
  146. anglesComputed = 0;
  147. }
  148. void Mahony_computeAngles()
  149. {
  150. roll = atan2f(q0*q1 + q2*q3, 0.5f - q1*q1 - q2*q2);
  151. // pitch = asinf(-2.0f * (q1*q3 - q0*q2));
  152. // yaw = atan2f(q1*q2 + q0*q3, 0.5f - q2*q2 - q3*q3);
  153. anglesComputed = 1;
  154. }
  155. float getRoll() {
  156. if (!anglesComputed) Mahony_computeAngles();
  157. return roll * 57.29578f;
  158. }
  159. float getPitch() {
  160. if (!anglesComputed) Mahony_computeAngles();
  161. return pitch * 57.29578f;
  162. }
  163. float getYaw() {
  164. if (!anglesComputed) Mahony_computeAngles();
  165. return yaw * 57.29578f;
  166. }
  167. static float acc_x,acc_y,acc_z;
  168. static float groy_x,groy_y,groy_z;
  169. static float mag_x,mag_y,mag_z;
  170. extern unsigned int send_bytes_client(unsigned char *bytes, uint16_t len);
  171. void Mahony_send_ANO(uint8_t fun,uint8_t* p,int len)
  172. {
  173. uint8_t buf[256];
  174. int L=0;
  175. uint8_t ver = 0;
  176. buf[L] = 0xAA; ver += buf[L++];
  177. buf[L] = 0x05; ver += buf[L++];
  178. buf[L] = 0xAF; ver += buf[L++];
  179. buf[L] = fun; ver += buf[L++];
  180. buf[L] = len; ver += buf[L++];
  181. for(int i=0;i<len;i++){
  182. buf[L] = p[i]; ver += buf[L++];
  183. }
  184. buf[L++] = ver;
  185. send_bytes_client(buf,L);
  186. // unsigned char buf[255];
  187. // unsigned char ver=0;
  188. // unsigned char i,L=0,Len=len+5;
  189. //
  190. // buf[L]=0xAA; ver+=buf[L++]; // 头
  191. // buf[L]=Len; ver+=buf[L++]; //1位长度
  192. // buf[L]=~Len; ver+=buf[L++]; // 1位长度反码
  193. // buf[L]=fun; ver+=buf[L++]; //1命令
  194. // for(i=0;i<len; i++){ buf[L]=p[i];ver+=buf[L++];} //数据
  195. // buf[L++]=ver; //效验
  196. // #if DEBUG_BLE_Client
  197. // SEGGER_RTT_printf(0,"Tx_BLE_Client:"); for(int i=0;i<L;i++){SEGGER_RTT_printf(0,"%02X ",buf[i]);} SEGGER_RTT_printf(0,"\r\n");
  198. // #endif
  199. // send_bytes_client(buf,L); //压入发送缓存
  200. }
  201. //void Mahony_send_ANO_STATUS(void)
  202. //{
  203. // uint8_t buf[256];
  204. // uint8_t L=0;
  205. //
  206. // int16_t rol = (int16_t)(getRoll()*100);
  207. // int16_t pitch = (int16_t)(getPitch()*100);
  208. // int16_t yaw = (int16_t)(getYaw()*100);
  209. //// int32_t dis = IMU_GetDistand();
  210. // //SEGGER_RTT_printf(0,"rol=%d,pitch=%d,yaw=%d\n",rol,pitch,yaw);
  211. // buf[L++] = (uint8_t)(rol>>8);
  212. // buf[L++] = (uint8_t)(rol>>0);
  213. // buf[L++] = (uint8_t)(pitch>>8);
  214. // buf[L++] = (uint8_t)(pitch>>0);
  215. // buf[L++] = (uint8_t)(yaw>>8);
  216. // buf[L++] = (uint8_t)(yaw>>0);
  217. //// buf[L++] = (uint8_t)(dis>>24);
  218. //// buf[L++] = (uint8_t)(dis>>16);
  219. //// buf[L++] = (uint8_t)(dis>>8);
  220. //// buf[L++] = (uint8_t)(dis>>0);
  221. //// if(dis<500&&pitch>-4000) buf[L++] = 1;
  222. //// else buf[L++] = 0;
  223. //// buf[L++] = 0;
  224. //// buf[L++] = 0;
  225. // buf[L++] = 0;
  226. // buf[L++] = 0;
  227. // buf[L++] = 0;
  228. // buf[L++] = 0;
  229. // buf[L++] = 0;
  230. // buf[L++] = 0;
  231. // buf[L++] = 0;
  232. // Mahony_send_ANO(0x01,buf,L);
  233. //}
  234. //void Mahony_send_ANO_SENSER(int16_t gx, int16_t gy, int16_t gz, int16_t ax, int16_t ay, int16_t az, int16_t mx, int16_t my, int16_t mz)
  235. //{
  236. // uint8_t buf[256];
  237. // uint8_t L=0;
  238. //
  239. // buf[L++] = (uint8_t)(ax>>8);
  240. // buf[L++] = (uint8_t)(ax>>0);
  241. // buf[L++] = (uint8_t)(ay>>8);
  242. // buf[L++] = (uint8_t)(ay>>0);
  243. // buf[L++] = (uint8_t)(az>>8);
  244. // buf[L++] = (uint8_t)(az>>0);
  245. //
  246. // buf[L++] = (uint8_t)(gx>>8);
  247. // buf[L++] = (uint8_t)(gx>>0);
  248. // buf[L++] = (uint8_t)(gy>>8);
  249. // buf[L++] = (uint8_t)(gy>>0);
  250. // buf[L++] = (uint8_t)(gz>>8);
  251. // buf[L++] = (uint8_t)(gz>>0);
  252. //
  253. // buf[L++] = (uint8_t)(mx>>8);
  254. // buf[L++] = (uint8_t)(mx>>0);
  255. // buf[L++] = (uint8_t)(my>>8);
  256. // buf[L++] = (uint8_t)(my>>0);
  257. // buf[L++] = (uint8_t)(mz>>8);
  258. // buf[L++] = (uint8_t)(mz>>0);
  259. // Mahony_send_ANO(0x02,buf,L);
  260. //}
  261. //void Mahony_send_My_SENSER(int16_t gx, int16_t gy, int16_t gz, int16_t ax, int16_t ay, int16_t az, int16_t mx, int16_t my, int16_t mz)
  262. //{
  263. // uint8_t buf[256];
  264. // uint8_t L=0;
  265. //
  266. // int16_t _q0 = (int16_t)(q0*100);
  267. // int16_t _q1 = (int16_t)(q1*100);
  268. // int16_t _q2 = (int16_t)(q2*100);
  269. // int16_t _q3 = (int16_t)(q3*100);
  270. // int16_t rol = (int16_t)(getRoll()*100);
  271. // int16_t pit = (int16_t)(getPitch()*100);
  272. // int16_t yaw = (int16_t)(getYaw()*100);
  273. // int16_t ds = 3210;
  274. // int16_t pf = 12;
  275. // int16_t pb = 34;
  276. // int16_t ptx = 56;
  277. // int16_t pty = 78;
  278. // int16_t ptz = 90;
  279. //
  280. //
  281. // buf[L++] = (uint8_t)(ax>>8);
  282. // buf[L++] = (uint8_t)(ax>>0);
  283. // buf[L++] = (uint8_t)(ay>>8);
  284. // buf[L++] = (uint8_t)(ay>>0);
  285. // buf[L++] = (uint8_t)(az>>8);
  286. // buf[L++] = (uint8_t)(az>>0);
  287. //
  288. // buf[L++] = (uint8_t)(gx>>8);
  289. // buf[L++] = (uint8_t)(gx>>0);
  290. // buf[L++] = (uint8_t)(gy>>8);
  291. // buf[L++] = (uint8_t)(gy>>0);
  292. // buf[L++] = (uint8_t)(gz>>8);
  293. // buf[L++] = (uint8_t)(gz>>0);
  294. //
  295. // buf[L++] = (uint8_t)(mx>>8);
  296. // buf[L++] = (uint8_t)(mx>>0);
  297. // buf[L++] = (uint8_t)(my>>8);
  298. // buf[L++] = (uint8_t)(my>>0);
  299. // buf[L++] = (uint8_t)(mz>>8);
  300. // buf[L++] = (uint8_t)(mz>>0);
  301. //
  302. // buf[L++] = (uint8_t)(pf>>8);
  303. // buf[L++] = (uint8_t)(pf>>0);
  304. //
  305. // buf[L++] = (uint8_t)(pb>>8);
  306. // buf[L++] = (uint8_t)(pb>>0);
  307. //
  308. // buf[L++] = (uint8_t)(ds>>8);
  309. // buf[L++] = (uint8_t)(ds>>0);
  310. //
  311. // buf[L++] = (uint8_t)(rol>>8);
  312. // buf[L++] = (uint8_t)(rol>>0);
  313. //
  314. // buf[L++] = (uint8_t)(pit>>8);
  315. // buf[L++] = (uint8_t)(pit>>0);
  316. //
  317. // buf[L++] = (uint8_t)(yaw>>8);
  318. // buf[L++] = (uint8_t)(yaw>>0);
  319. //
  320. // buf[L++] = (uint8_t)(ptx>>8);
  321. // buf[L++] = (uint8_t)(ptx>>0);
  322. //
  323. // buf[L++] = (uint8_t)(pty>>8);
  324. // buf[L++] = (uint8_t)(pty>>0);
  325. //
  326. // buf[L++] = (uint8_t)(ptz>>8);
  327. // buf[L++] = (uint8_t)(ptz>>0);
  328. //
  329. // buf[L++] = (uint8_t)(_q0>>8);
  330. // buf[L++] = (uint8_t)(_q0>>0);
  331. //
  332. // buf[L++] = (uint8_t)(_q1>>8);
  333. // buf[L++] = (uint8_t)(_q1>>0);
  334. //
  335. // buf[L++] = (uint8_t)(_q2>>8);
  336. // buf[L++] = (uint8_t)(_q2>>0);
  337. //
  338. // buf[L++] = (uint8_t)(_q3>>8);
  339. // buf[L++] = (uint8_t)(_q3>>0);
  340. // Mahony_send_ANO(0xEE,buf,L);
  341. //}
  342. //void Mahony_process(int16_t gx, int16_t gy, int16_t gz, int16_t ax, int16_t ay, int16_t az, int16_t mx, int16_t my, int16_t mz)
  343. //{
  344. // static uint8_t tt = 0;
  345. // acc_x = ax/4096.0f;
  346. // acc_y = ay/4096.0f;
  347. // acc_z = az/4096.0f;
  348. //
  349. // int16_t rol = (int16_t)(getRoll()*100);
  350. //
  351. // Mahony_update(groy_x,groy_y,groy_z,acc_x,acc_y,acc_z,mag_x,mag_y,mag_z);
  352. //// DEBUG_LOG("rol :%d\r\n", rol);
  353. // if(++tt>=10){tt = 0;
  354. // Mahony_send_ANO_STATUS();
  355. // Mahony_send_ANO_SENSER(gx,gy,gz,ax,ay,az,mx,my,mz);
  356. //// Mahony_send_My_SENSER(gx,gy,gz,ax,ay,az,mx,my,mz);
  357. // }
  358. //}
  359. void Mahony_process(int16_t gx, int16_t gy, int16_t gz, int16_t ax, int16_t ay, int16_t az, int16_t mx, int16_t my, int16_t mz)
  360. {
  361. acc_x = ax/4096.0f;
  362. acc_y = ay/4096.0f;
  363. acc_z = az/4096.0f;
  364. Mahony_update(groy_x,groy_y,groy_z,acc_x,acc_y,acc_z,mag_x,mag_y,mag_z);
  365. }
  366. //============================================================================================
  367. // END OF CODE
  368. //============================================================================================