arduino 自平衡小车3\对mpu6050获得的X轴角度和角速度进行卡尔曼滤波
程序员文章站
2022-07-12 10:19:50
...
对mpu6050获得的X轴角度和角速度进行卡尔曼滤波
mpu6050得到的角度值有些值的偏差较大,为了使平衡小车更加稳定,需要对获得的角度进行优化,使用 卡尔曼滤波,代码如下:
#include <MPU6050.h> //MPU6050的库文件
#include <Wire.h> //IIC通讯库文件
MPU6050 mpu6050; //实例化一个MPU6050对象,对象名称为mpu6050
int16_t ax, ay, az, gx, gy, gz; //定义三轴加速度,三轴陀螺仪的变量
float Angle;
float Gyro_x,Gyro_y,Gyro_z; //用于陀螺仪算出的各轴角速度
///////////////////////Kalman_Filter////////////////////////////
float Q_angle = 0.001; //陀螺仪噪声的协方差
float Q_gyro = 0.1; //陀螺仪漂移噪声的协方差
float R_angle = 0.5; //加速度计的协方差
char C_0 = 1;
float dt = 0.005; //dt的取值为滤波器采样时间
float K1 = 0.05; // 含有卡尔曼增益的函数,用于计算最优估计值的偏差
float K_0,K_1,t_0,t_1;
float angle_err;
float q_bias; //陀螺仪漂移
float accelz = 0;
float angle;
float angle_speed;
float Pdot[4] = { 0, 0, 0, 0};
float P[2][2] = {{ 1, 0 }, { 0, 1 }};
float PCt_0, PCt_1, E;
//////////////////////Kalman_Filter/////////////////////////
void setup()
{
// 加入I2C总线
Wire.begin(); //加入 I2C 总线序列
Serial.begin(9600); //开启串口,设置波特率为9600
delay(1500);
mpu6050.initialize(); //初始化MPU6050
delay(2);
}
void loop()
{
Serial.print("Angle = ");
Serial.print(Angle);
Serial.print(" K_angle = ");
Serial.println(angle);
Serial.print("Gyro_x = ");
Serial.print(Gyro_x);
Serial.print(" K_Gyro_x = ");
Serial.println(angle_speed);
mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //IIC获取MPU6050六轴数据 ax ay az gx gy gz
angle_calculate(ax, ay, az, gx, gy, gz, dt, Q_angle, Q_gyro, R_angle, C_0, K1); //获取angle 角度和卡曼滤波
}
/////////////////////////////倾角计算///////////////////////
void angle_calculate(int16_t ax,int16_t ay,int16_t az,int16_t gx,int16_t gy,int16_t gz,float dt,float Q_angle,float Q_gyro,float R_angle,float C_0,float K1)
{
Angle = atan2(ay , az) * (180/ PI); //弧度转角度计算公式,负号为方向处理
Gyro_x = gx / 131; //陀螺仪计算的X轴角速度,负号为方向处理
Kalman_Filter(Angle, Gyro_x); //卡曼滤波
}
////////////////////////////////////////////////////////////////
///////////////////////////////KalmanFilter/////////////////////
void Kalman_Filter(double angle_m, double gyro_m)
{
angle += (gyro_m - q_bias) * dt; //先验估计
angle_err = angle_m - angle;
Pdot[0] = Q_angle - P[0][1] - P[1][0]; //先验估计误差协方差的微分
Pdot[1] = - P[1][1];
Pdot[2] = - P[1][1];
Pdot[3] = Q_gyro;
P[0][0] += Pdot[0] * dt; //先验估计误差协方差微分的积分
P[0][1] += Pdot[1] * dt;
P[1][0] += Pdot[2] * dt;
P[1][1] += Pdot[3] * dt;
//矩阵乘法的中间变量
PCt_0 = C_0 * P[0][0];
PCt_1 = C_0 * P[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 * P[0][1];
P[0][0] -= K_0 * t_0; //后验估计误差协方差
P[0][1] -= K_0 * t_1;
P[1][0] -= K_1 * t_0;
P[1][1] -= K_1 * t_1;
q_bias += K_1 * angle_err; //后验估计
angle_speed = gyro_m - q_bias; //输出值的微分,得出最优角速度
angle += K_0 * angle_err; ////后验估计,得出最优角度
}