卡尔曼滤波在陀螺仪角度获取中的运用(最大可能解决MPU6050零漂问题)

前言:相信使用过MPU6050的人都会发现此陀螺仪(角度传感器)存在零点漂移的现象。我在网上查找了好多解决零点漂移的方法,大多数网友提供的方法都是对陀螺仪采集到的数据进行一些数据的处理,包括一些滤波算法的运用。在经过长时间的尝试后,我觉得使用卡尔曼滤波算法效果比较好,因此我将通过此文来记录卡尔曼滤波算法在解决陀螺仪零漂问题的运用。

同时为了方便读者移植,我会在文章末尾附上工程链接,需要的读者请自取。有关陀螺仪的工作原理驱动代码,读者可以参考这篇文章:STM32MPU6050角度的读取(STM32驱动MPU6050)-CSDN博客

废话不多说,直接对相关代码进行讲解:

filter.c

#include "filter.h"
/**************************************************************************
Function: Simple Kalman filter
Input   : acceleration、angular velocity
Output  : none
函数功能:获取x轴角度简易卡尔曼滤波
入口参数:加速度获取的角度、角速度
返回  值:x轴角速度
**************************************************************************/
float dt=0.005;		  //每5ms进行一次滤波                 
float Kalman_Filter_x(float Accel,float Gyro)		
{
	static float angle_dot;
	static float angle;
	float Q_angle=0.001; // 过程噪声的协方差
	float Q_gyro=0.003;	//0.003 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
	float R_angle=0.5;		// 测量噪声的协方差 既测量偏差
	char  C_0 = 1;
	static float Q_bias, Angle_err;
	static float PCt_0, PCt_1, E;
	static float K_0, K_1, t_0, t_1;
	static float Pdot[4] ={0,0,0,0};
	static float PP[2][2] = { { 1, 0 },{ 0, 1 } };
	angle+=(Gyro - Q_bias) * dt; //先验估计
	Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分

	Pdot[1]=-PP[1][1];
	Pdot[2]=-PP[1][1];
	Pdot[3]=Q_gyro;
	PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
	PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差
	PP[1][0] += Pdot[2] * dt;
	PP[1][1] += Pdot[3] * dt;
		
	Angle_err = Accel - angle;	//zk-先验估计
	
	PCt_0 = C_0 * PP[0][0];
	PCt_1 = C_0 * PP[1][0];
	
	E = R_angle + C_0 * PCt_0;
	
	K_0 = PCt_0 / E;
	K_1 = PCt_1 / E;
	
	t_0 = PCt_0;
	t_1 = C_0 * PP[0][1];

	PP[0][0] -= K_0 * t_0;		 //后验估计误差协方差
	PP[0][1] -= K_0 * t_1;
	PP[1][0] -= K_1 * t_0;
	PP[1][1] -= K_1 * t_1;
		
	angle	+= K_0 * Angle_err;	 //后验估计
	Q_bias	+= K_1 * Angle_err;	 //后验估计
	angle_dot   = Gyro - Q_bias;	 //输出值(后验估计)的微分=角速度
	return angle;
}
/**************************************************************************
Function: First order complementary filtering
Input   : acceleration、angular velocity
Output  : none
函数功能:一阶互补滤波
入口参数:加速度获取的角度、角速度
返回  值:x轴角速度
**************************************************************************/
float Complementary_Filter_x(float angle_m, float gyro_m)
{
	 static float angle;
	 float K1 =0.02; 
	 angle = K1 * angle_m+ (1-K1) * (angle + gyro_m * dt);
	 return angle;
}
/**************************************************************************
Function: Simple Kalman filter
Input   : acceleration、angular velocity
Output  : none
函数功能:获取y轴角度简易卡尔曼滤波
入口参数:加速度获取的角度、角速度
返回  值:y轴角速度
**************************************************************************/
float Kalman_Filter_y(float Accel,float Gyro)		
{
	static float angle_dot;
	static float angle;
	float Q_angle=0.001; // 过程噪声的协方差
	float Q_gyro=0.003;	//0.003 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
	float R_angle=0.5;		// 测量噪声的协方差 既测量偏差
	char  C_0 = 1;
	static float Q_bias, Angle_err;
	static float PCt_0, PCt_1, E;
	static float K_0, K_1, t_0, t_1;
	static float Pdot[4] ={0,0,0,0};
	static float PP[2][2] = { { 1, 0 },{ 0, 1 } };
	angle+=(Gyro - Q_bias) * dt; //先验估计
	Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分
	Pdot[1]=-PP[1][1];
	Pdot[2]=-PP[1][1];
	Pdot[3]=Q_gyro;
	PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
	PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差
	PP[1][0] += Pdot[2] * dt;
	PP[1][1] += Pdot[3] * dt;
	Angle_err = Accel - angle;	//zk-先验估计
	
	PCt_0 = C_0 * PP[0][0];
	PCt_1 = C_0 * PP[1][0];
	
	E = R_angle + C_0 * PCt_0;
	
	K_0 = PCt_0 / E;
	K_1 = PCt_1 / E;
	
	t_0 = PCt_0;
	t_1 = C_0 * PP[0][1];

	PP[0][0] -= K_0 * t_0;		 //后验估计误差协方差
	PP[0][1] -= K_0 * t_1;
	PP[1][0] -= K_1 * t_0;
	PP[1][1] -= K_1 * t_1;
		
	angle	+= K_0 * Angle_err;	   //后验估计
	Q_bias	+= K_1 * Angle_err;	 //后验估计
	angle_dot   = Gyro - Q_bias;	//输出值(后验估计)的微分=角速度
	return angle;
}
/**************************************************************************
Function: First order complementary filtering
Input   : acceleration、angular velocity
Output  : none
函数功能:一阶互补滤波
入口参数:加速度获取的角度、角速度
返回  值:y轴角速度
**************************************************************************/
float Complementary_Filter_y(float angle_m, float gyro_m)
{
	 static float angle;
	 float K1 =0.02; 
   angle = K1 * angle_m+ (1-K1) * (angle + gyro_m * dt);
	 return angle;
}


filter.h

#ifndef __FILTER_H
#define __FILTER_H
float Kalman_Filter_x(float Accel,float Gyro);		
float Complementary_Filter_x(float angle_m, float gyro_m);
float Kalman_Filter_y(float Accel,float Gyro);		
float Complementary_Filter_y(float angle_m, float gyro_m);

#endif

以上的卡尔曼滤波算法不仅适用于陀螺仪角度数据的处理,同时对于其他的传感器数据处理也依然适用。

这是此篇的陀螺仪卡尔曼滤波算法移植的完整工程:

链接:https://pan.baidu.com/s/19RWpXG7qykLwCFcjoLgLIQ?pwd=zxf1 
提取码:zxf1 
--来自百度网盘超级会员V3的分享

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在使用卡尔曼滤波解决MPU6050陀螺仪、加速度计和原始数据零点漂移等问题时,需要先对MPU6050进行初始化,然后读取原始数据,将其转换为物理量,再进行卡尔曼滤波。 以下是一个简单的MPU6050卡尔曼滤波的C语言实现,适配STM32F103ZET6单片机,供参考: ```c #include "stm32f10x.h" #include "mpu6050.h" #include "kalman.h" //卡尔曼滤波器 Kalman_t kalman; int main(void) { //初始化MPU6050 MPU6050_Init(); //初始化卡尔曼滤波器 Kalman_Init(&kalman, 0.001, 0.01, 0.1); while(1) { //读取原始数据 int16_t acc_x_raw, acc_y_raw, acc_z_raw; int16_t gyro_x_raw, gyro_y_raw, gyro_z_raw; MPU6050_GetRawAccelGyro(&acc_x_raw, &acc_y_raw, &acc_z_raw, &gyro_x_raw, &gyro_y_raw, &gyro_z_raw); //转换为物理量 float acc_x = acc_x_raw / 16384.0; float acc_y = acc_y_raw / 16384.0; float acc_z = acc_z_raw / 16384.0; float gyro_x = gyro_x_raw / 131.0; float gyro_y = gyro_y_raw / 131.0; float gyro_z = gyro_z_raw / 131.0; //卡尔曼滤波 float acc_x_filtered = Kalman_Update(&kalman, acc_x, gyro_x); float acc_y_filtered = Kalman_Update(&kalman, acc_y, gyro_y); float acc_z_filtered = Kalman_Update(&kalman, acc_z, gyro_z); //处理结果 //... } return 0; } ``` 需要注意的是,MPU6050的读取、转换和卡尔曼滤波的具体实现需要根据具体的需求进行调整。此外,卡尔曼滤波的参数选择也需要根据具体问题进行调整,例如过程噪声方差、测量噪声方差等等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小_扫地僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值