当前位置:   article > 正文

九轴融合--备忘_imu九轴融合后,yaw乱飘

imu九轴融合后,yaw乱飘
  1. //! Auxiliary variables to reduce number of repeated operations
  2. static float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
  3. static float dq0 = 0.0f, dq1 = 0.0f, dq2 = 0.0f, dq3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
  4. static float gyro_bias[3] = {0.0f, 0.0f, 0.0f}; /** bias estimation */
  5. static float q0q0, q0q1, q0q2, q0q3;
  6. static float q1q1, q1q2, q1q3;
  7. static float q2q2, q2q3;
  8. static float q3q3;
  9. static uint8_t bFilterInit = 0;
  10. imu_t imu= {0};
  11. //函数名:invSqrt(void)
  12. //描述:求平方根的倒数
  13. //该函数是经典的Carmack求平方根算法,效率极高,使用魔数0x5f375a86
  14. static float invSqrt(float number)
  15. {
  16. volatile long i;
  17. volatile float x, y;
  18. volatile const float f = 1.5F;
  19. x = number * 0.5F;
  20. y = number;
  21. i = * (( long * ) &y);
  22. i = 0x5f375a86 - ( i >> 1 );
  23. y = * (( float * ) &i);
  24. y = y * ( f - ( x * y * y ) );
  25. return y;
  26. }
  27. //四元数初始化
  28. //
  29. static void MahonyAHRSinit(float ax, float ay, float az, float mx, float my, float mz)
  30. {
  31. float initialRoll, initialPitch;
  32. float cosRoll, sinRoll, cosPitch, sinPitch;
  33. float magX, magY;
  34. float initialHdg, cosHeading, sinHeading;
  35. initialRoll = atan2(-ay, -az);
  36. initialPitch = atan2(ax, -az);
  37. // initialRoll = atan2(ay, az);
  38. // initialPitch = -asin(ax);
  39. cosRoll = cosf(initialRoll);
  40. sinRoll = sinf(initialRoll);
  41. cosPitch = cosf(initialPitch);
  42. sinPitch = sinf(initialPitch);
  43. magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch;
  44. magY = my * cosRoll - mz * sinRoll;
  45. initialHdg = atan2f(-magY, magX);
  46. // magX = mx * cosRoll + my * sinRoll * sinPitch + mz * cosPitch * sinRoll;
  47. // magY = my * cosPitch - mz * sinPitch ;
  48. // initialHdg = -atan2f(magY, magX);
  49. cosRoll = cosf(initialRoll * 0.5f);
  50. sinRoll = sinf(initialRoll * 0.5f);
  51. cosPitch = cosf(initialPitch * 0.5f);
  52. sinPitch = sinf(initialPitch * 0.5f);
  53. cosHeading = cosf(initialHdg * 0.5f);
  54. sinHeading = sinf(initialHdg * 0.5f);
  55. q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading;
  56. q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading;
  57. q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading;
  58. q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading;
  59. // auxillary variables to reduce number of repeated operations, for 1st pass
  60. q0q0 = q0 * q0;
  61. q0q1 = q0 * q1;
  62. q0q2 = q0 * q2;
  63. q0q3 = q0 * q3;
  64. q1q1 = q1 * q1;
  65. q1q2 = q1 * q2;
  66. q1q3 = q1 * q3;
  67. q2q2 = q2 * q2;
  68. q2q3 = q2 * q3;
  69. q3q3 = q3 * q3;
  70. }
  71. //函数名:MahonyAHRSupdate()
  72. //描述:姿态解算融合,是Crazepony和核心算法
  73. //使用的是Mahony互补滤波算法,没有使用Kalman滤波算法
  74. //改算法是直接参考pixhawk飞控的算法,可以在Github上看到出处
  75. //https://github.com/hsteinhaus/PX4Firmware/blob/master/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp
  76. static void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float twoKp, float twoKi, float dt)
  77. {
  78. float recipNorm;
  79. float halfex = 0.0f, halfey = 0.0f, halfez = 0.0f;
  80. // Make filter converge to initial solution faster
  81. // This function assumes you are in static position.
  82. // WARNING : in case air reboot, this can cause problem. But this is very unlikely happen.
  83. if(bFilterInit == 0) {
  84. MahonyAHRSinit(ax,ay,az,mx,my,mz);
  85. bFilterInit = 1;
  86. }
  87. //! If magnetometer measurement is available, use it.
  88. if(!((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f))) { //磁场数据融合,数据归一,数据模型坐标系矩阵转置惯性坐标系,处理 理想水平面y轴分量为0,在转回,最后向量叉乘误差积分
  89. float hx, hy, hz, bx, bz;
  90. float halfwx, halfwy, halfwz;
  91. // Normalise magnetometer measurement
  92. // Will sqrt work better? PX4 system is powerful enough?
  93. recipNorm = invSqrt(mx * mx + my * my + mz * mz);
  94. mx *= recipNorm;
  95. my *= recipNorm;
  96. mz *= recipNorm;
  97. // Reference direction of Earth's magnetic field
  98. hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
  99. hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
  100. hz = 2.0f * mx * (q1q3 - q0q2) + 2.0f * my * (q2q3 + q0q1) + 2.0f * mz * (0.5f - q1q1 - q2q2);
  101. bx = sqrt(hx * hx + hy * hy);
  102. bz = hz;
  103. // Estimated direction of magnetic field
  104. halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
  105. halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
  106. halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
  107. // Error is sum of cross product between estimated direction and measured direction of field vectors
  108. halfex += (my * halfwz - mz * halfwy);
  109. halfey += (mz * halfwx - mx * halfwz);
  110. halfez += (mx * halfwy - my * halfwx);
  111. }
  112. // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
  113. if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) //加速度数据融合,数据归一,矩阵转置模型坐标系,最后向量叉乘误差积分
  114. {
  115. float halfvx, halfvy, halfvz;
  116. // Normalise accelerometer measurement
  117. //归一化,得到单位加速度
  118. recipNorm = invSqrt(ax * ax + ay * ay + az * az);
  119. ax *= recipNorm;
  120. ay *= recipNorm;
  121. az *= recipNorm;
  122. // Estimated direction of gravity and magnetic field
  123. halfvx = q1q3 - q0q2;
  124. halfvy = q0q1 + q2q3;
  125. halfvz = q0q0 - 0.5f + q3q3;
  126. // Error is sum of cross product between estimated direction and measured direction of field vectors
  127. halfex += ay * halfvz - az * halfvy;
  128. halfey += az * halfvx - ax * halfvz;
  129. halfez += ax * halfvy - ay * halfvx;
  130. }
  131. // Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
  132. if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) { //角速度计误差补偿
  133. // Compute and apply integral feedback if enabled
  134. if(twoKi > 0.0f) {
  135. gyro_bias[0] += twoKi * halfex * dt; // integral error scaled by Ki
  136. gyro_bias[1] += twoKi * halfey * dt;
  137. gyro_bias[2] += twoKi * halfez * dt;
  138. // apply integral feedback
  139. gx += gyro_bias[0];
  140. gy += gyro_bias[1];
  141. gz += gyro_bias[2];
  142. }
  143. else {
  144. gyro_bias[0] = 0.0f; // prevent integral windup
  145. gyro_bias[1] = 0.0f;
  146. gyro_bias[2] = 0.0f;
  147. }
  148. // Apply proportional feedback
  149. gx += twoKp * halfex;
  150. gy += twoKp * halfey;
  151. gz += twoKp * halfez;
  152. }
  153. // Time derivative of quaternion. q_dot = 0.5*q\otimes omega.
  154. //! q_k = q_{k-1} + dt*\dot{q}
  155. //! \dot{q} = 0.5*q \otimes P(\omega)
  156. dq0 = 0.5f*(-q1 * gx - q2 * gy - q3 * gz);
  157. dq1 = 0.5f*(q0 * gx + q2 * gz - q3 * gy);
  158. dq2 = 0.5f*(q0 * gy - q1 * gz + q3 * gx);
  159. dq3 = 0.5f*(q0 * gz + q1 * gy - q2 * gx);
  160. q0 += dt*dq0;
  161. q1 += dt*dq1;
  162. q2 += dt*dq2;
  163. q3 += dt*dq3;
  164. // Normalise quaternion
  165. recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
  166. q0 *= recipNorm;
  167. q1 *= recipNorm;
  168. q2 *= recipNorm;
  169. q3 *= recipNorm;
  170. // Auxiliary variables to avoid repeated arithmetic
  171. q0q0 = q0 * q0;
  172. q0q1 = q0 * q1;
  173. q0q2 = q0 * q2;
  174. q0q3 = q0 * q3;
  175. q1q1 = q1 * q1;
  176. q1q2 = q1 * q2;
  177. q1q3 = q1 * q3;
  178. q2q2 = q2 * q2;
  179. q2q3 = q2 * q3;
  180. q3q3 = q3 * q3;
  181. }
  182. #define Kp 2.0f //加速度权重,越大收敛越快
  183. #define Ki 0.005f //误差积分增益
  184. //函数名: MahonyAHRSThread(void)
  185. //描述:姿态软件解算融合函数
  186. //该函数对姿态的融合是软件解算,
  187. void MahonyAHRSThread(void)
  188. {
  189. //! Time constant
  190. volatile float dt = 0.005f; //s
  191. static uint32_t tPrev=0; //us
  192. uint32_t now;
  193. uint8_t i;
  194. /* output euler angles */
  195. float euler[3] = {0.0f, 0.0f, 0.0f}; //rad
  196. /* Initialization */
  197. float Rot_matrix[9] = {1.f, 0.0f, 0.0f, 0.0f, 1.f, 0.0f, 0.0f, 0.0f, 1.f }; /**< init: identity matrix */
  198. float acc[3] = {0.0f, 0.0f, 0.0f}; //m/s^2
  199. float gyro[3] = {0.0f, 0.0f, 0.0f}; //rad/s
  200. float mag[3] = {0.0f, 0.0f, 0.0f};
  201. static float gyro_offsets_sum[3]= { 0.0f, 0.0f, 0.0f }; // gyro_offsets[3] = { 0.0f, 0.0f, 0.0f },
  202. static uint16_t offset_count = 0;
  203. // if(ReadIMUSensorHandle())return;//原始数据并滤波
  204. // now= (u32)CPU_TS32_to_uSec(CPU_TS_TmrRd());
  205. // dt=(tPrev>0)?(now-tPrev)/1000000.0f:0; //时间
  206. // tPrev=now;
  207. //
  208. gyro[0] = imu.gyro[0] ;
  209. gyro[1] = imu.gyro[1] ;
  210. gyro[2] = imu.gyro[2] ;
  211. acc[0] = imu.accb[0];
  212. acc[1] = imu.accb[1];
  213. acc[2] = imu.accb[2];
  214. mag[0] = imu.mag[0];
  215. mag[1] = imu.mag[1];
  216. mag[2] = imu.mag[2];
  217. // NOTE : Accelerometer is reversed.
  218. // Because proper mount of PX4 will give you a reversed accelerometer readings.
  219. MahonyAHRSupdate(gyro[0], gyro[1], gyro[2],
  220. acc[0], acc[1], acc[2],
  221. mag[0], mag[1], mag[2],
  222. Kp,Ki,dt);
  223. // Convert q->R, This R converts inertial frame to body frame.
  224. Rot_matrix[0] = q0q0 + q1q1 - q2q2 - q3q3;// 11
  225. Rot_matrix[1] = 2.f * (q1*q2 + q0*q3); // 12
  226. Rot_matrix[2] = 2.f * (q1*q3 - q0*q2); // 13
  227. Rot_matrix[3] = 2.f * (q1*q2 - q0*q3); // 21
  228. Rot_matrix[4] = q0q0 - q1q1 + q2q2 - q3q3;// 22
  229. Rot_matrix[5] = 2.f * (q2*q3 + q0*q1); // 23
  230. Rot_matrix[6] = 2.f * (q1*q3 + q0*q2); // 31
  231. Rot_matrix[7] = 2.f * (q2*q3 - q0*q1); // 32
  232. Rot_matrix[8] = q0q0 - q1q1 - q2q2 + q3q3;// 33
  233. //1-2-3 Representation.
  234. //Equation (290)
  235. //Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors, James Diebel.
  236. // Existing PX4 EKF code was generated by MATLAB which uses coloum major order matrix.
  237. euler[0] = atan2f(Rot_matrix[5], Rot_matrix[8]); //! Roll
  238. euler[1] = -asinf(Rot_matrix[2]); //! Pitch
  239. euler[2] = atan2f(Rot_matrix[1], Rot_matrix[0]);
  240. //DCM . ground to body
  241. for(i=0; i<9; i++)
  242. {
  243. *(&(imu.DCMgb[0][0]) + i)=Rot_matrix[i];
  244. }
  245. imu.rollRad=euler[0];
  246. imu.pitchRad=euler[1];
  247. imu.yawRad=euler[2];
  248. imu.roll=euler[0] * 180.0f / M_PI_F;
  249. imu.pitch=euler[1] * 180.0f / M_PI_F;
  250. imu.yaw=euler[2] * 180.0f / M_PI_F;
  251. ahrseuler[GyrIdx-1][0] = imu.roll;
  252. ahrseuler[GyrIdx-1][1] = imu.pitch;
  253. ahrseuler[GyrIdx-1][2] = imu.yaw;
  254. }
  255. #define SENSOR_MAX_G 2.0f //constant g //
  256. #define SENSOR_MAX_W 2000.0f //deg/s
  257. #define ACC_SCALE (SENSOR_MAX_G/32768.0f)
  258. #define GYRO_SCALE (SENSOR_MAX_W/32768.0f)
  259. #define MAG_SCALE (0.15f)

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/623496
推荐阅读
相关标签
  

闽ICP备14008679号