8490|9

60

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

感谢网友(time/方)分享的9轴sensor的融合算法参考 [复制链接]

 
 欢迎测评。。。可直接下载附件, 姿态解算c代码.c (11.1 KB, 下载次数: 165)

也可以直接查看下方代码
  1. Filename:        IMUSO3.c
  2. Author:                祥 、nieyong
  3. 说明:这是Crazepony软件姿态解算融合文件,Crazepony已经不再使用DMP硬件解算
  4. Part of this algrithom is referred from pixhawk.
  5. ------------------------------------
  6. */

  7. #include "stm32f10x.h"
  8. #include "stm32f10x_it.h"
  9. #include <math.h>
  10. #include "IMU.h"
  11. #include "IMUSO3.h"

  12. //! Auxiliary variables to reduce number of repeated operations
  13. static float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;        /** quaternion of sensor frame relative to auxiliary frame */
  14. static float dq0 = 0.0f, dq1 = 0.0f, dq2 = 0.0f, dq3 = 0.0f;        /** quaternion of sensor frame relative to auxiliary frame */
  15. static float gyro_bias[3] = {0.0f, 0.0f, 0.0f}; /** bias estimation */
  16. static float q0q0, q0q1, q0q2, q0q3;
  17. static float q1q1, q1q2, q1q3;
  18. static float q2q2, q2q3;
  19. static float q3q3;
  20. static uint8_t bFilterInit = 0;

  21. //函数名:invSqrt(void)
  22. //描述:求平方根的倒数
  23. //该函数是经典的Carmack求平方根算法,效率极高,使用魔数0x5f375a86
  24. static float invSqrt(float number)
  25. {
  26.     volatile long i;
  27.     volatile float x, y;
  28.     volatile const float f = 1.5F;

  29.     x = number * 0.5F;
  30.     y = number;
  31.     i = * (( long * ) &y);
  32.     i = 0x5f375a86 - ( i >> 1 );
  33.     y = * (( float * ) &i);
  34.     y = y * ( f - ( x * y * y ) );
  35.     return y;
  36. }

  37. //! Using accelerometer, sense the gravity vector.
  38. //! Using magnetometer, sense yaw.
  39. static void NonlinearSO3AHRSinit(float ax, float ay, float az, float mx, float my, float mz)
  40. {
  41.     float initialRoll, initialPitch;
  42.     float cosRoll, sinRoll, cosPitch, sinPitch;
  43.     float magX, magY;
  44.     float initialHdg, cosHeading, sinHeading;

  45.     initialRoll = atan2(-ay, -az);
  46.     initialPitch = atan2(ax, -az);

  47.     cosRoll = cosf(initialRoll);
  48.     sinRoll = sinf(initialRoll);
  49.     cosPitch = cosf(initialPitch);
  50.     sinPitch = sinf(initialPitch);

  51.     magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch;

  52.     magY = my * cosRoll - mz * sinRoll;

  53.     initialHdg = atan2f(-magY, magX);

  54.     cosRoll = cosf(initialRoll * 0.5f);
  55.     sinRoll = sinf(initialRoll * 0.5f);

  56.     cosPitch = cosf(initialPitch * 0.5f);
  57.     sinPitch = sinf(initialPitch * 0.5f);

  58.     cosHeading = cosf(initialHdg * 0.5f);
  59.     sinHeading = sinf(initialHdg * 0.5f);

  60.     q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading;
  61.     q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading;
  62.     q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading;
  63.     q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading;

  64.     // auxillary variables to reduce number of repeated operations, for 1st pass
  65.     q0q0 = q0 * q0;
  66.     q0q1 = q0 * q1;
  67.     q0q2 = q0 * q2;
  68.     q0q3 = q0 * q3;
  69.     q1q1 = q1 * q1;
  70.     q1q2 = q1 * q2;
  71.     q1q3 = q1 * q3;
  72.     q2q2 = q2 * q2;
  73.     q2q3 = q2 * q3;
  74.     q3q3 = q3 * q3;
  75. }

  76. //函数名:NonlinearSO3AHRSupdate()
  77. //描述:姿态解算融合,是Crazepony和核心算法
  78. //使用的是Mahony互补滤波算法,没有使用Kalman滤波算法
  79. //改算法是直接参考pixhawk飞控的算法,可以在Github上看到出处
  80. //https://github.com/hsteinhaus/PX4Firmware/blob/master/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp
  81. static void NonlinearSO3AHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float twoKp, float twoKi, float dt)
  82. {
  83.         float recipNorm;
  84.         float halfex = 0.0f, halfey = 0.0f, halfez = 0.0f;

  85.         // Make filter converge to initial solution faster
  86.         // This function assumes you are in static position.
  87.         // WARNING : in case air reboot, this can cause problem. But this is very unlikely happen.
  88.         if(bFilterInit == 0) {
  89.                 NonlinearSO3AHRSinit(ax,ay,az,mx,my,mz);
  90.                 bFilterInit = 1;
  91.         }
  92.                
  93.         //! If magnetometer measurement is available, use it.
  94.         if(!((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f))) {
  95.                 float hx, hy, hz, bx, bz;
  96.                 float halfwx, halfwy, halfwz;
  97.         
  98.                 // Normalise magnetometer measurement
  99.                 // Will sqrt work better? PX4 system is powerful enough?
  100.             recipNorm = invSqrt(mx * mx + my * my + mz * mz);
  101.             mx *= recipNorm;
  102.             my *= recipNorm;
  103.             mz *= recipNorm;
  104.    
  105.             // Reference direction of Earth's magnetic field
  106.             hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
  107.             hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
  108.                         hz = 2.0f * mx * (q1q3 - q0q2) + 2.0f * my * (q2q3 + q0q1) + 2.0f * mz * (0.5f - q1q1 - q2q2);
  109.             bx = sqrt(hx * hx + hy * hy);
  110.             bz = hz;
  111.    
  112.             // Estimated direction of magnetic field
  113.             halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
  114.             halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
  115.             halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
  116.    
  117.             // Error is sum of cross product between estimated direction and measured direction of field vectors
  118.             halfex += (my * halfwz - mz * halfwy);
  119.             halfey += (mz * halfwx - mx * halfwz);
  120.             halfez += (mx * halfwy - my * halfwx);
  121.         }

  122.         //增加一个条件:  加速度的模量与G相差不远时。 0.75*G < normAcc < 1.25*G
  123.         // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
  124.         if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f)))         
  125.         {
  126.                 float halfvx, halfvy, halfvz;
  127.         
  128.                 // Normalise accelerometer measurement
  129.                 //归一化,得到单位加速度
  130.                 recipNorm = invSqrt(ax * ax + ay * ay + az * az);

  131.                 ax *= recipNorm;
  132.                 ay *= recipNorm;
  133.                 az *= recipNorm;

  134.                 // Estimated direction of gravity and magnetic field
  135.                 halfvx = q1q3 - q0q2;
  136.                 halfvy = q0q1 + q2q3;
  137.                 halfvz = q0q0 - 0.5f + q3q3;
  138.         
  139.                 // Error is sum of cross product between estimated direction and measured direction of field vectors
  140.                 halfex += ay * halfvz - az * halfvy;
  141.                 halfey += az * halfvx - ax * halfvz;
  142.                 halfez += ax * halfvy - ay * halfvx;
  143.         }

  144.         // Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
  145.         if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) {
  146.                 // Compute and apply integral feedback if enabled
  147.                 if(twoKi > 0.0f) {
  148.                         gyro_bias[0] += twoKi * halfex * dt;        // integral error scaled by Ki
  149.                         gyro_bias[1] += twoKi * halfey * dt;
  150.                         gyro_bias[2] += twoKi * halfez * dt;
  151.                         
  152.                         // apply integral feedback
  153.                         gx += gyro_bias[0];
  154.                         gy += gyro_bias[1];
  155.                         gz += gyro_bias[2];
  156.                 }
  157.                 else {
  158.                         gyro_bias[0] = 0.0f;        // prevent integral windup
  159.                         gyro_bias[1] = 0.0f;
  160.                         gyro_bias[2] = 0.0f;
  161.                 }

  162.                 // Apply proportional feedback
  163.                 gx += twoKp * halfex;
  164.                 gy += twoKp * halfey;
  165.                 gz += twoKp * halfez;
  166.         }
  167.         
  168.         // Time derivative of quaternion. q_dot = 0.5*q\otimes omega.
  169.         //! q_k = q_{k-1} + dt*\dot{q}
  170.         //! \dot{q} = 0.5*q \otimes P(\omega)
  171.         dq0 = 0.5f*(-q1 * gx - q2 * gy - q3 * gz);
  172.         dq1 = 0.5f*(q0 * gx + q2 * gz - q3 * gy);
  173.         dq2 = 0.5f*(q0 * gy - q1 * gz + q3 * gx);
  174.         dq3 = 0.5f*(q0 * gz + q1 * gy - q2 * gx);

  175.         q0 += dt*dq0;
  176.         q1 += dt*dq1;
  177.         q2 += dt*dq2;
  178.         q3 += dt*dq3;
  179.         
  180.         // Normalise quaternion
  181.         recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
  182.         q0 *= recipNorm;
  183.         q1 *= recipNorm;
  184.         q2 *= recipNorm;
  185.         q3 *= recipNorm;

  186.         // Auxiliary variables to avoid repeated arithmetic
  187.         q0q0 = q0 * q0;
  188.         q0q1 = q0 * q1;
  189.         q0q2 = q0 * q2;
  190.         q0q3 = q0 * q3;
  191.         q1q1 = q1 * q1;
  192.         q1q2 = q1 * q2;
  193.         q1q3 = q1 * q3;
  194.         q2q2 = q2 * q2;
  195.         q2q3 = q2 * q3;
  196.         q3q3 = q3 * q3;   
  197. }

  198. #define so3_comp_params_Kp 1.0f
  199. #define so3_comp_params_Ki  0.05f


  200. //函数名:IMUSO3Thread(void)
  201. //描述:姿态软件解算融合函数
  202. //该函数对姿态的融合是软件解算,Crazepony现在不使用DMP硬件解算
  203. //对应的硬件解算函数为IMU_Process()
  204. void IMUSO3Thread(void)
  205. {
  206.         //! Time constant
  207.         float dt = 0.01f;                //s
  208.         static uint32_t tPrev=0,startTime=0;        //us
  209.         uint32_t now;
  210.         uint8_t i;
  211.         
  212.         /* output euler angles */
  213.         float euler[3] = {0.0f, 0.0f, 0.0f};        //rad
  214.         
  215.         /* Initialization */
  216.         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 */
  217.         float acc[3] = {0.0f, 0.0f, 0.0f};                //m/s^2
  218.         float gyro[3] = {0.0f, 0.0f, 0.0f};                //rad/s
  219.         float mag[3] = {0.0f, 0.0f, 0.0f};               
  220.         //need to calc gyro offset before imu start working
  221.         static float gyro_offsets_sum[3]={ 0.0f, 0.0f, 0.0f };// gyro_offsets[3] = { 0.0f, 0.0f, 0.0f },
  222.         static uint16_t offset_count = 0;

  223.         now=micros();
  224.         dt=(tPrev>0)?(now-tPrev)/1000000.0f:0;
  225.         tPrev=now;
  226.         
  227.         ReadIMUSensorHandle();
  228.         
  229.         if(!imu.ready)
  230.         {
  231.                  if(startTime==0)
  232.                                 startTime=now;
  233.                                 
  234.                         gyro_offsets_sum[0] += imu.gyroRaw[0];
  235.                         gyro_offsets_sum[1] += imu.gyroRaw[1];
  236.                         gyro_offsets_sum[2] += imu.gyroRaw[2];
  237.                         offset_count++;
  238.                         
  239.                         if(now > startTime + GYRO_CALC_TIME)
  240.                         {
  241.                                         imu.gyroOffset[0] = gyro_offsets_sum[0]/offset_count;
  242.                                         imu.gyroOffset[1] = gyro_offsets_sum[1]/offset_count;
  243.                                         imu.gyroOffset[2] = gyro_offsets_sum[2]/offset_count;
  244.                                        
  245.                                         offset_count=0;
  246.                                         gyro_offsets_sum[0]=0;gyro_offsets_sum[1]=0;gyro_offsets_sum[2]=0;
  247.                                        
  248.                                         imu.ready = 1;
  249.                                         startTime=0;
  250.                                        
  251.                         }
  252.                         return;
  253.         }
  254.         

  255.         gyro[0] = imu.gyro[0] - imu.gyroOffset[0];
  256.         gyro[1] = imu.gyro[1] - imu.gyroOffset[1];
  257.         gyro[2] = imu.gyro[2] - imu.gyroOffset[2];

  258.         acc[0] = -imu.accb[0];
  259.         acc[1] = -imu.accb[1];
  260.         acc[2] = -imu.accb[2];

  261.                 // NOTE : Accelerometer is reversed.
  262.                 // Because proper mount of PX4 will give you a reversed accelerometer readings.
  263.                 NonlinearSO3AHRSupdate(gyro[0], gyro[1], gyro[2],
  264.                                                         -acc[0], -acc[1], -acc[2],
  265.                                                         mag[0], mag[1], mag[2],
  266.                                                         so3_comp_params_Kp,
  267.                                                         so3_comp_params_Ki,
  268.                                                         dt);

  269.                 // Convert q->R, This R converts inertial frame to body frame.
  270.                 Rot_matrix[0] = q0q0 + q1q1 - q2q2 - q3q3;// 11
  271.                 Rot_matrix[1] = 2.f * (q1*q2 + q0*q3);        // 12
  272.                 Rot_matrix[2] = 2.f * (q1*q3 - q0*q2);        // 13
  273.                 Rot_matrix[3] = 2.f * (q1*q2 - q0*q3);        // 21
  274.                 Rot_matrix[4] = q0q0 - q1q1 + q2q2 - q3q3;// 22
  275.                 Rot_matrix[5] = 2.f * (q2*q3 + q0*q1);        // 23
  276.                 Rot_matrix[6] = 2.f * (q1*q3 + q0*q2);        // 31
  277.                 Rot_matrix[7] = 2.f * (q2*q3 - q0*q1);        // 32
  278.                 Rot_matrix[8] = q0q0 - q1q1 - q2q2 + q3q3;// 33

  279.                 //1-2-3 Representation.
  280.                 //Equation (290)

  281.                 //Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors, James Diebel.
  282.                 // Existing PX4 EKF code was generated by MATLAB which uses coloum major order matrix.
  283.                 euler[0] = atan2f(Rot_matrix[5], Rot_matrix[8]);        //! Roll
  284.                 euler[1] = -asinf(Rot_matrix[2]);                                                                        //! Pitch
  285.                 euler[2] = atan2f(Rot_matrix[1], Rot_matrix[0]);         
  286.                
  287.                 //DCM . ground to body
  288.                 for(i=0;i<9;i++)
  289.                 {
  290.                                 *(&(imu.DCMgb[0][0]) + i)=Rot_matrix[i];
  291.                 }
  292.                
  293.                 imu.rollRad=euler[0];
  294.                 imu.pitchRad=euler[1];
  295.                 imu.yawRad=euler[2];
  296.                
  297.                 imu.roll=euler[0] * 180.0f / M_PI_F;
  298.                 imu.pitch=euler[1] * 180.0f / M_PI_F;
  299.                 imu.yaw=euler[2] * 180.0f / M_PI_F;
  300. }


复制代码


最新回复

不错  详情 回复 发表于 2018-1-18 11:51
点赞 关注(5)
个人签名ST MEMS技术讨论群:415506792
 
 

回复
举报

578

帖子

0

TA的资源

纯净的硅(初级)

沙发
 
下载下来学习一下
个人签名刻苦学习,共同进步
 
 
 

回复

5263

帖子

239

TA的资源

管理员

板凳
 
略微编辑一下,可以直接查看,也可以下载查看
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

655

帖子

29

TA的资源

版主

4
 
不错,这套代码还是使用的mahony,简单易用,不过没有交代函数的使用方法哦,9轴的原始数据是否需要变号处理,还有 float twoKp, float twoKi, float dt这几个参数的作用

点评

变号处理是指什么? 输入值的单位么?  详情 回复 发表于 2016-11-16 22:03
个人签名QQ:252669569
 
 
 

回复

821

帖子

0

TA的资源

一粒金砂(高级)

5
 
收藏了,谢谢!
 
 
 

回复

330

帖子

907

TA的资源

一粒金砂(中级)

6
 
纯干货,来看看
 
 
 

回复

60

帖子

0

TA的资源

一粒金砂(中级)

7
 
lb8820265 发表于 2016-11-15 14:49
不错,这套代码还是使用的mahony,简单易用,不过没有交代函数的使用方法哦,9轴的原始数据是否需要变号处 ...

变号处理是指什么? 输入值的单位么?

点评

嗯,既包括输入前单位的处理,也包括正负号的处理,我记得是要处理下的  详情 回复 发表于 2016-11-17 09:07
个人签名ST MEMS技术讨论群:415506792
 
 
 

回复

655

帖子

29

TA的资源

版主

8
 
jmsht33 发表于 2016-11-16 22:03
变号处理是指什么? 输入值的单位么?

嗯,既包括输入前单位的处理,也包括正负号的处理,我记得是要处理下的
个人签名QQ:252669569
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

9
 
不错
 
 
 

回复

297

帖子

0

TA的资源

一粒金砂(中级)

10
 
不错
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表