[STM32F1] mpu6050卡尔曼滤波

[复制链接]
 楼主| mnynt121 发表于 2025-3-24 07:05 | 显示全部楼层 |阅读模式
  1. #include "kalman.h"
  2. #include "mpu6050.h"
  3. #include "math.h"


  4. short aacx,aacy,aacz;                /*加速度传感器原始数据*/
  5. short gyrox,gyroy,gyroz;        /*陀螺仪原始数据*/
  6. short temperature;                        /*陀螺仪温度数据*/
  7. float Accel_x;                             /*X轴加速度值暂存*/
  8. float Accel_y;                            /*Y轴加速度值暂存*/
  9. float Accel_z;                             /*Z轴加速度值暂存*/
  10. float Gyro_x;                                /*X轴陀螺仪数据暂存*/
  11. float Gyro_y;                        /*Y轴陀螺仪数据暂存*/
  12. float Gyro_z;                                 /*Z轴陀螺仪数据暂存*/
  13. float Angle_x_temp;                  /*由加速度计算的x倾斜角度*/
  14. float Angle_y_temp;                  /*由加速度计算的y倾斜角度*/
  15. float Angle_X_Final;                 /*X最终倾斜角度*/
  16. float Angle_Y_Final;                 /*Y最终倾斜角度*/

  17. /**
  18.   * [url=home.php?mod=space&uid=247401]@brief[/url]  读取数据预处理
  19.   *         
  20.   * @param  NULL
  21.   *
  22.   * @retval NULL
  23.   */
  24. void Angle_Calcu(void)         
  25. {
  26.         /*1.原始数据读取*/
  27.         float accx,accy,accz;                                                /*三方向角加速度值*/
  28.         MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        /*得到加速度传感器数据*/
  29.         MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        /*得到陀螺仪数据*/
  30.         temperature = MPU_Get_Temperature();                /*得到温度值*/
  31.         Accel_x = aacx;
  32.         Accel_y = aacy;
  33.         Accel_z = aacz;
  34.         Gyro_x  = gyrox;
  35.         Gyro_y  = gyroy;
  36.         Gyro_z  = gyroz;
  37.         
  38.         /*2.角加速度原始值处理过程*/        
  39.         /*加速度传感器配置寄存器0X1C内写入0x01,设置范围为±2g。换算关系:2^16/4 = 16384LSB/g*/
  40.         if(Accel_x<32764) accx=Accel_x/16384;
  41.         else              accx=1-(Accel_x-49152)/16384;
  42.         if(Accel_y<32764) accy=Accel_y/16384;
  43.         else              accy=1-(Accel_y-49152)/16384;
  44.         if(Accel_z<32764) accz=Accel_z/16384;
  45.         else              accz=(Accel_z-49152)/16384;
  46.         /*加速度反正切公式计算三个轴和水平面坐标系之间的夹角*/
  47.         Angle_x_temp=(atan(accy/accz))*180/3.14;
  48.         Angle_y_temp=(atan(accx/accz))*180/3.14;
  49.         /*判断计算后角度的正负号*/                                                                                       
  50.         if(Accel_x<32764) Angle_y_temp = +Angle_y_temp;
  51.         if(Accel_x>32764) Angle_y_temp = -Angle_y_temp;
  52.         if(Accel_y<32764) Angle_x_temp = +Angle_x_temp;
  53.         if(Accel_y>32764) Angle_x_temp = -Angle_x_temp;
  54.         
  55.         /*3.角速度原始值处理过程*/
  56.         /*陀螺仪配置寄存器0X1B内写入0x18,设置范围为±2000deg/s。换算关系:2^16/4000=16.4LSB/(°/S)*/
  57.         /*计算角速度*/
  58.         if(Gyro_x<32768) Gyro_x=-(Gyro_x/16.4);
  59.         if(Gyro_x>32768) Gyro_x=+(65535-Gyro_x)/16.4;
  60.         if(Gyro_y<32768) Gyro_y=-(Gyro_y/16.4);
  61.         if(Gyro_y>32768) Gyro_y=+(65535-Gyro_y)/16.4;
  62.         if(Gyro_z<32768) Gyro_z=-(Gyro_z/16.4);
  63.         if(Gyro_z>32768) Gyro_z=+(65535-Gyro_z)/16.4;
  64.         
  65.         /*4.调用卡尔曼函数*/
  66.         Kalman_Filter_X(Angle_x_temp,Gyro_x);  /*卡尔曼滤波计算X倾角*/
  67.         Kalman_Filter_Y(Angle_y_temp,Gyro_y);  /*卡尔曼滤波计算Y倾角*/                                                                                                                          
  68. }


  69. /************************ 卡尔曼参数 ****************************/               
  70. float Q_angle = 0.001;                /*角度数据置信度,角度噪声的协方差*/
  71. float Q_gyro  = 0.003;                /*角速度数据置信度,角速度噪声的协方差*/
  72. float R_angle = 0.5;                /*加速度计测量噪声的协方差*/
  73. float dt      = 0.02;                /*滤波算法计算周期,由定时器定时20ms*/
  74. char  C_0     = 1;                        /*H矩阵值*/
  75. float Q_bias, Angle_err;        /*Q_bias:陀螺仪的偏差  Angle_err:角度偏量*/
  76. float PCt_0, PCt_1, E;                /*计算的过程量*/
  77. float K_0, K_1, t_0, t_1;        /*卡尔曼增益  K_0:用于计算最优估计值  K_1:用于计算最优估计值的偏差 t_0/1:中间变量*/
  78. float P[4] ={0,0,0,0};                /*过程协方差矩阵的微分矩阵,中间变量*/
  79. float PP[2][2] = { { 1, 0 },{ 0, 1 } };/*过程协方差矩阵P*/

  80. /**
  81.   * @brief  卡尔曼函数
  82.   *         
  83.   * @param  Accel
  84.   * @param  Gyro
  85.   *
  86.   * @retval NULL
  87.   */
  88. void Kalman_Filter_X(float Accel,float Gyro)               
  89. {
  90.         /*
  91.                 步骤一,先验估计
  92.                 公式:X(k|k-1) = AX(k-1|k-1) + BU(k)
  93.                 X = (Angle,Q_bias)
  94.                 A(1,1) = 1,A(1,2) = -dt
  95.                 A(2,1) = 0,A(2,2) = 1
  96.         */        
  97.         Angle_X_Final += (Gyro - Q_bias) * dt;         /*状态方程,角度值等于上次最优角度加角速度减零漂后积分*/
  98.         
  99.         /*
  100.                 步骤二,计算过程协方差矩阵的微分矩阵
  101.                 公式:P(k|k-1)=AP(k-1|k-1)A^T + Q
  102.                 Q(1,1) = cov(Angle,Angle)        Q(1,2) = cov(Q_bias,Angle)
  103.                 Q(2,1) = cov(Angle,Q_bias)        Q(2,2) = cov(Q_bias,Q_bias)
  104.         */
  105.         P[0]= Q_angle - PP[0][1] - PP[1][0];
  106.         P[1]= -PP[1][1];                                                /*先验估计误差协方差*/
  107.         P[2]= -PP[1][1];
  108.         P[3]= Q_gyro;
  109.         PP[0][0] += P[0] * dt;   
  110.         PP[0][1] += P[1] * dt;   
  111.         PP[1][0] += P[2] * dt;
  112.         PP[1][1] += P[3] * dt;        
  113.         
  114.         /*
  115.                 步骤三,计算卡尔曼增益
  116.                 公式:Kg(k)= P(k|k-1)H^T/(HP(k|k-1)H^T+R)
  117.                 Kg = (K_0,K_1) 对应Angle,Q_bias增益
  118.                 H = (1,0)        可由z=HX+v求出z:Accel
  119.         */
  120.         PCt_0 = C_0 * PP[0][0];
  121.         PCt_1 = C_0 * PP[1][0];
  122.         E = R_angle + C_0 * PCt_0;
  123.         K_0 = PCt_0 / E;
  124.         K_1 = PCt_1 / E;
  125.         
  126.         /*
  127.                 步骤四,后验估计误差协方差
  128.                 公式:P(k|k)=(I-Kg(k)H)P(k|k-1)
  129.                 也可写为:P(k|k)=P(k|k-1)-Kg(k)HP(k|k-1)
  130.         */
  131.         t_0 = PCt_0;
  132.         t_1 = C_0 * PP[0][1];
  133.         PP[0][0] -= K_0 * t_0;               
  134.         PP[0][1] -= K_0 * t_1;
  135.         PP[1][0] -= K_1 * t_0;
  136.         PP[1][1] -= K_1 * t_1;
  137.         
  138.         /*
  139.                 步骤五,计算最优角速度值
  140.                 公式:X(k|k)= X(k|k-1)+Kg(k)(Z(k)-X(k|k-1))
  141.         */
  142.         Angle_err = Accel - Angle_X_Final;                /*Z(k)先验估计 计算角度偏差*/
  143.         Angle_X_Final += K_0 * Angle_err;                 /*后验估计,给出最优估计值*/
  144.         Q_bias        += K_1 * Angle_err;                 /*后验估计,跟新最优估计值偏差*/
  145.         Gyro_x         = Gyro - Q_bias;         
  146. }

  147. void Kalman_Filter_Y(float Accel,float Gyro)                 
  148. {
  149.         Angle_Y_Final += (Gyro - Q_bias) * dt;
  150.         P[0]=Q_angle - PP[0][1] - PP[1][0];
  151.         P[1]=-PP[1][1];
  152.         P[2]=-PP[1][1];
  153.         P[3]=Q_gyro;        
  154.         PP[0][0] += P[0] * dt;
  155.         PP[0][1] += P[1] * dt;  
  156.         PP[1][0] += P[2] * dt;
  157.         PP[1][1] += P[3] * dt;        
  158.         Angle_err = Accel - Angle_Y_Final;               
  159.         PCt_0 = C_0 * PP[0][0];
  160.         PCt_1 = C_0 * PP[1][0];        
  161.         E = R_angle + C_0 * PCt_0;        
  162.         K_0 = PCt_0 / E;
  163.         K_1 = PCt_1 / E;        
  164.         t_0 = PCt_0;
  165.         t_1 = C_0 * PP[0][1];
  166.         PP[0][0] -= K_0 * t_0;               
  167.         PP[0][1] -= K_0 * t_1;
  168.         PP[1][0] -= K_1 * t_0;
  169.         PP[1][1] -= K_1 * t_1;               
  170.         Angle_Y_Final        += K_0 * Angle_err;
  171.         Q_bias        += K_1 * Angle_err;         
  172.         Gyro_y   = Gyro - Q_bias;         
  173. }

  174. 复制代码


  175. /**
  176.   ******************************************************************************
  177.   * [url=home.php?mod=space&uid=288409]@file[/url]    main.c
  178.   * [url=home.php?mod=space&uid=187600]@author[/url]  
  179.   * [url=home.php?mod=space&uid=895143]@version[/url] V1.0
  180.   * [url=home.php?mod=space&uid=212281]@date[/url]    2023-4-7
  181.   * @brief   MPU6050陀螺仪数据解算(卡尔曼滤波)
  182.   ******************************************************************************
  183.   *
  184.   *
  185.   *
  186.   ******************************************************************************
  187.   */
  188. #include "main.h"
  189. /**
  190.   * @brief  主函数
  191.   * @param  无
  192.   * @retval 无
  193.   */
  194. int main(void)
  195. {        
  196.         SYS_Init();
  197.         while(1)
  198.         {               
  199.                 /*MPU6050数据上报*/
  200.                 DATA_Report();
  201.         }
  202. }
  203. /**
  204.   * @brief  系统初始化总函数
  205.   * @param  无
  206.   * @retval 无
  207.   */
  208. void SYS_Init(void)
  209. {
  210.         delay_init();  
  211.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  212.         uart_init(115200);
  213.         LED_Init();
  214.         MPU_Init();
  215.         /*10Khz的计数频率,计数到200为20ms*/
  216.         TIM4_Int_Init(199,7199);
  217. }
  218. /**
  219.   * @brief  MPU6050数据上报
  220.   * @param  无
  221.   * @retval 无
  222.   */
  223. void DATA_Report(void)
  224. {
  225.         /*串口发送实时俯仰角,横滚角,XYZ三轴角加速度原始值,XYZ三轴角速度原始值*/
  226.         printf("俯仰角:%.4f 横滚角:%.4f \
  227.         X加速度:%5d y加速度:%5d z加速度:%5d \
  228.         x速度:%5d y速度:%5d z速度:%5d\r\n",\
  229.         Angle_X_Final,Angle_Y_Final,aacx,aacy,aacz,\
  230.         gyrox,gyroy,gyroz);
  231.         
  232.         
  233. }


lidi911 发表于 2025-3-24 07:38 来自手机 | 显示全部楼层
MPU6050堪称MEMS六轴传感器的经典了,10多年前就在用了。
键盘手没手 发表于 2025-3-31 23:56 | 显示全部楼层
代码通过 MPU_Get_Accelerometer 和 MPU_Get_Gyroscope 函数读取 MPU6050 传感器的数据,并将原始的加速度值和陀螺仪值存储到相应的变量中。
averyleigh 发表于 2025-4-4 17:59 | 显示全部楼层
在使用 MPU6050 之前,需要对加速度计和陀螺仪进行零点校准,以消除传感器的偏置误差。可以让传感器处于静止状态,采集一段时间的数据,计算出加速度计和陀螺仪的零点偏移量,并在后续的数据处理中进行补偿。
cemaj 发表于 2025-4-5 19:20 | 显示全部楼层
消除陀螺仪的零点偏移和温度漂移。
vivilyly 发表于 2025-4-5 20:57 | 显示全部楼层
虽然欧拉角直观且易于理解,但在某些情况下(特别是当涉及到大角度旋转时),会出现万向节死锁问题。相比之下,四元数没有这个问题,并且数值稳定性更好。因此,在实现姿态融合时,推荐使用四元数来表示姿态。
chenjun89 发表于 2025-4-5 21:55 来自手机 | 显示全部楼层
卡尔曼滤波算法真的是经典啊,在很多场合都能看到应用身影。
geraldbetty 发表于 2025-4-6 07:22 | 显示全部楼层
在使用MPU6050之前,需要对传感器进行校准,以消除传感器的偏置和噪声。校准可以通过采集一段时间的静态数据,并计算平均值来实现。
loutin 发表于 2025-4-8 09:34 | 显示全部楼层
原始数据可能会受到高频噪声的影响,可以考虑应用简单的低通滤波器来平滑数据。
wwppd 发表于 2025-4-8 12:38 | 显示全部楼层
由于 MPU6050 的测量数据可能受到噪声、干扰等因素的影响,姿态融合算法需要具有一定的稳定性,能够在各种情况下保持准确的姿态估计。
mickit 发表于 2025-4-8 15:41 | 显示全部楼层
根据传感器数据的质量动态调整滤波器参数,提高系统的鲁棒性。
maqianqu 发表于 2025-4-9 20:37 | 显示全部楼层
MPU6050的加速度计和陀螺仪数据需要进行同步处理,以确保它们反映的是同一时刻的姿态信息。如果数据不同步,会导致姿态融合结果出现偏差。可以通过硬件或软件方法实现数据同步,例如使用硬件同步电路或在软件中进行时间戳匹配。
pmp 发表于 2025-4-9 23:43 | 显示全部楼层
姿态融合通常使用滤波算法来处理传感器数据,常见的滤波算法包括互补滤波、四元数滤波和卡尔曼滤波。
ulystronglll 发表于 2025-4-10 02:48 | 显示全部楼层
动态环境下的自适应调整和资源受限系统的优化实现。
claretttt 发表于 2025-4-10 13:52 | 显示全部楼层
在姿态融合中,需要使用姿态解算算法将加速度计和陀螺仪的数据转换为姿态信息,如四元数、欧拉角或旋转矩阵
timfordlare 发表于 2025-4-10 14:22 | 显示全部楼层
结合加速度计和陀螺仪的数据,以获得更准确的姿态估计。
olivem55arlowe 发表于 2025-4-10 14:56 | 显示全部楼层
融合频率应该不低于传感器的最高输出频率,以确保能够及时处理传感器数据。
mickit 发表于 2025-4-10 15:27 | 显示全部楼层
卡尔曼滤波需要估计过程噪声和观测噪声的协方差矩阵。这些矩阵的选取会影响滤波器的性能。通常需要通过实验来调整这些矩阵的参数。
lzmm 发表于 2025-4-10 15:56 | 显示全部楼层
加速度计提供的数据可以作为重力方向的观测值,用于更新姿态估计。
qiufengsd 发表于 2025-4-10 16:30 | 显示全部楼层
准确估计系统噪声和观测噪声的统计特性(如均值、方差等)对卡尔曼滤波至关重要。MPU6050的加速度计和陀螺仪数据存在噪声,需要通过实验或数据分析确定其噪声特性,以便在滤波过程中正确处理。如果噪声估计不准确,可能会使滤波结果发散或不稳定。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

3322

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部