当前位置:   article > 正文

【51单片机快速入门指南】4.3.2: MPU6050:一阶互补滤波、二阶互补滤波和卡尔曼滤波获取欧拉角_卡尔曼mpu6050

卡尔曼mpu6050
目录
  • 源码
  • MPU6050_Filter.c
  • MPU6050_Filter.h
  • 使用方法
  • 测试程序
  • 一阶互补滤波
  • 效果
  • 二阶互补滤波
  • 效果
  • 卡尔曼滤波
  • 效果
  • 总结

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
上位机:Vofa+ 1.3.10


参考资料:
MPU6050数据采集及其意义和滤波(一阶互补滤波、二阶互补滤波、卡尔曼滤波)—— 275891381
关于MPU6050姿态解算的一阶互补滤波方法(从原理到代码实现) —— 可以叫我马同学
姿态融合的一阶互补滤波、二阶互补滤波、卡尔曼滤波核心程序 —— 卖硬件的

源码

       stdint.h【51单片机快速入门指南】1:基础知识和工程创建
       软件I2C程序见【51单片机快速入门指南】4: 软件 I2C
       串口部分见【51单片机快速入门指南】3.3:USART 串口通信
       MPU6050.c、MPU6050.h见【51单片机快速入门指南】4.3: I2C读取MPU6050陀螺仪的原始数据

MPU6050_Filter.c

  1. #include "MPU6050.h"
  2. #include <math.h>
  3. #include "./MPU6050/MPU6050_Filter.h"
  4. #define PI 3.141592653589793
  5. float Delta_t = 1;
  6. float GYRO_K = 1;
  7. #define First_Order_Filter_Tau 0.075
  8. float First_Order_k = 1;
  9. void MPU6050_Filter_Init(float loop_ms)
  10. {
  11. Delta_t = loop_ms/1000.;
  12. First_Order_k = First_Order_Filter_Tau / (First_Order_Filter_Tau + Delta_t);
  13. switch((MPU_Read_Byte(MPU_GYRO_CFG_REG) >> 3) & 3)
  14. {
  15. case 0:
  16. GYRO_K = 131;
  17. break;
  18. case 1:
  19. GYRO_K = 65.5;
  20. break;
  21. case 2:
  22. GYRO_K = 32.8;
  23. break;
  24. case 3:
  25. GYRO_K = 16.4;
  26. break;
  27. }
  28. }
  29. float First_Order_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, float * angle2)
  30. {
  31. *angle2 = First_Order_k * (*angle2 + (-gyro2 / GYRO_K) * Delta_t) + (1 - First_Order_k) * (atan2(acc1, acc3) * 180 / PI);
  32. return *angle2;
  33. }
  34. #define Second_Order_Filter_k 5
  35. float Second_Order_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, Second_Order_Filter* filter)
  36. {
  37. float angle_m = atan2(acc1, acc3) * 180 / PI;
  38. float gyro_m = -gyro2 / GYRO_K;
  39. float x1, x2;
  40. x1 = (angle_m - filter->angle) * Second_Order_Filter_k * Second_Order_Filter_k;
  41. filter->y = filter->y + x1 * Delta_t;
  42. x2 = filter->y + 2 * Second_Order_Filter_k * (angle_m - filter->angle) + gyro_m;
  43. filter->angle = filter->angle + x2 * Delta_t;
  44. return filter->angle;
  45. }
  46. #define Q_angle 0.05
  47. #define Q_gyro 0.0003
  48. #define R_angle 0.01
  49. float MPU_Kalman_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, MPU_Kalman_Filter* filter)
  50. {
  51. float newAngle = atan2(acc1, acc3) * 180 / PI;
  52. float newRate = -gyro2 / GYRO_K;
  53. float E;
  54. float K_0, K_1;
  55. float Angle_err_x;
  56. filter->angle += Delta_t * (newRate - filter->Q_bias_x);
  57. filter->P_00 += - Delta_t * (filter->P_10 + filter->P_01) + Q_angle * Delta_t;
  58. filter->P_01 += - Delta_t * filter->P_11;
  59. filter->P_10 += - Delta_t * filter->P_11;
  60. filter->P_11 += + Q_gyro * Delta_t;
  61. Angle_err_x = newAngle - filter->angle;
  62. E = filter->P_00 + R_angle;
  63. K_0 = filter->P_00 / E;
  64. K_1 = filter->P_10 / E;
  65. filter->angle += K_0 * Angle_err_x;
  66. filter->Q_bias_x += K_1 * Angle_err_x;
  67. filter->P_00 -= K_0 * filter->P_00;
  68. filter->P_01 -= K_0 * filter->P_01;
  69. filter->P_10 -= K_1 * filter->P_00;
  70. filter->P_11 -= K_1 * filter->P_01;
  71. return filter->angle;
  72. }

MPU6050_Filter.h

  1. #ifndef MPU6050_Filter_H_
  2. #define MPU6050_Filter_H_
  3. typedef struct
  4. {
  5. float y;
  6. float angle;
  7. }Second_Order_Filter;
  8. typedef struct
  9. {
  10. float P_00, P_01, P_10, P_11;
  11. float Q_bias_x;
  12. float angle;
  13. }MPU_Kalman_Filter;
  14. void MPU6050_Filter_Init(float loop_ms);
  15. float First_Order_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, float * angle2);
  16. float Second_Order_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, Second_Order_Filter* filter);
  17. float MPU_Kalman_Filter_Calc(int16_t acc1, int16_t acc3, int16_t gyro2, MPU_Kalman_Filter* filter);
  18. #endif

使用方法

       先调用MPU6050_Filter_Init(dt),参数为一次循环的时间,单位为ms
       再使用滤波函数。

测试程序

       生成的程序较大,对于89C52,需要注释掉没用到的函数。

一阶互补滤波

  1. #include <STC89C5xRC.H>
  2. #include "intrins.h"
  3. #include "stdint.h"
  4. #include "USART.h"
  5. #include "./MPU6050/MPU6050.h"
  6. #include "./MPU6050/MPU6050_Filter.h"
  7. void Delay1ms() //@11.0592MHz
  8. {
  9. unsigned char i, j;
  10. _nop_();
  11. i = 2;
  12. j = 199;
  13. do
  14. {
  15. while (--j);
  16. } while (--i);
  17. }
  18. void Delay_ms(int i)
  19. {
  20. while(i--)
  21. Delay1ms();
  22. }
  23. void main(void)
  24. {
  25. int16_t aacx,aacy,aacz; //加速度传感器原始数据
  26. int16_t gyrox,gyroy,gyroz; //陀螺仪原始数据
  27. float anglex = 0;
  28. float angley = 0;
  29. float anglez = 0;
  30. USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 57600, DOUBLE_BAUD_ENABLE, USART_TIMER_1);
  31. MPU_Init();
  32. MPU6050_Filter_Init(47);
  33. while(1)
  34. {
  35. MPU_Get_Accelerometer(&aacx, &aacy, &aacz); //得到加速度传感器数据
  36. MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz); //得到陀螺仪数据
  37. printf("%f, " , First_Order_Filter(aacy, aacz, gyrox, &anglex));
  38. printf("%f, " , First_Order_Filter(aacx, aacz, gyroy, &angley));
  39. printf("%f\r\n",First_Order_Filter(aacx, aacy, gyroz, &anglez));
  40. }
  41. }
效果

       只看了俯仰和滚转
       First_Order_Filter_Tau 要根据需要调节,我这里取First_Order_Filter_Tau = 0.075
在这里插入图片描述
在这里插入图片描述

二阶互补滤波

  1. #include <STC89C5xRC.H>
  2. #include "intrins.h"
  3. #include "stdint.h"
  4. #include "USART.h"
  5. #include "./MPU6050/MPU6050.h"
  6. #include "./MPU6050/MPU6050_Filter.h"
  7. void Delay1ms() //@11.0592MHz
  8. {
  9. unsigned char i, j;
  10. _nop_();
  11. i = 2;
  12. j = 199;
  13. do
  14. {
  15. while (--j);
  16. } while (--i);
  17. }
  18. void Delay_ms(int i)
  19. {
  20. while(i--)
  21. Delay1ms();
  22. }
  23. Second_Order_Filter anglex = {0, 0}, angley = {0, 0}, anglez = {0, 0};
  24. void main(void)
  25. {
  26. int16_t aacx,aacy,aacz; //加速度传感器原始数据
  27. int16_t gyrox,gyroy,gyroz; //陀螺仪原始数据
  28. USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 57600, DOUBLE_BAUD_ENABLE, USART_TIMER_1);
  29. MPU_Init();
  30. MPU6050_Filter_Init(56);
  31. while(1)
  32. {
  33. MPU_Get_Accelerometer(&aacx, &aacy, &aacz); //得到加速度传感器数据
  34. MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz); //得到陀螺仪数据
  35. printf("%f, " , Second_Order_Filter_Calc(aacy, aacz, gyrox, &anglex));
  36. printf("%f, " , Second_Order_Filter_Calc(aacx, aacz, gyroy, &angley));
  37. printf("%f\r\n",Second_Order_Filter_Calc(aacx, aacy, gyroz, &anglez));
  38. }
  39. }
效果

       只看了俯仰和滚转
       Second_Order_Filter_k根据需要,越大跟随越快,越小越平滑
       (我参考的大佬有取0.8的,有取10的,我这里取5)。
       要根据需要调节
在这里插入图片描述

卡尔曼滤波

  1. #include <STC89C5xRC.H>
  2. #include "intrins.h"
  3. #include "stdint.h"
  4. #include "USART.h"
  5. #include "./MPU6050/MPU6050.h"
  6. #include "./MPU6050/MPU6050_Filter.h"
  7. void Delay1ms() //@11.0592MHz
  8. {
  9. unsigned char i, j;
  10. _nop_();
  11. i = 2;
  12. j = 199;
  13. do
  14. {
  15. while (--j);
  16. } while (--i);
  17. }
  18. void Delay_ms(int i)
  19. {
  20. while(i--)
  21. Delay1ms();
  22. }
  23. MPU_Kalman_Filter anglex = {0};
  24. MPU_Kalman_Filter angley = {0};
  25. MPU_Kalman_Filter anglez = {0};
  26. void main(void)
  27. {
  28. int16_t aacx,aacy,aacz; //加速度传感器原始数据
  29. int16_t gyrox,gyroy,gyroz; //陀螺仪原始数据
  30. USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 57600, DOUBLE_BAUD_ENABLE, USART_TIMER_1);
  31. MPU_Init();
  32. MPU6050_Filter_Init(76);
  33. while(1)
  34. {
  35. MPU_Get_Accelerometer(&aacx, &aacy, &aacz); //得到加速度传感器数据
  36. MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz); //得到陀螺仪数据
  37. printf("%f, " , MPU_Kalman_Filter_Calc(aacy, aacz, gyrox, &anglex));
  38. printf("%f, " , MPU_Kalman_Filter_Calc(aacx, aacz, gyroy, &angley));
  39. printf("%f\r\n",MPU_Kalman_Filter_Calc(aacx, aacy, gyroz, &anglez));
  40. }
  41. }
效果

       只看了俯仰和滚转
       Q参数:过程噪声协方差 Q参数调滤波后的曲线平滑程度,Q越小越平滑;
       R参数:观测噪声协方差 R参数调整滤波后的曲线与实测曲线的相近程度,R越小越接近(收敛越快)
       我参考的大佬有取0.01,0.0003,0.01的,也有取0.001,0.005,0.5的
       我这里取
       Q_angle=0.05
       Q_gyro=0.0003
       R_angle=0.01
       要根据需要调节

suhetao/stm32f4_mpu9250中有大神对EKF / UKF / CKF / SRCKF的实现,感兴趣的可以看看。
在这里插入图片描述

总结

       由于每种滤波器的参数都会极大地影响该滤波器的性能(一阶滤波、二阶滤波各一个参数,卡尔曼滤波三个参数),因此难以互相比较,我建议根据单片机的资源、性能选择要用的滤波器,调参时配合上位机观察立方体的效果和对应波形

【51单片机快速入门指南】4.3.2: MPU6050:一阶互补滤波、二阶互补滤波和卡尔曼滤波获取欧拉角-CSDN博客

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

闽ICP备14008679号