|
本帖最后由 wujohn 于 2013-7-31 10:25 编辑
输入为陀螺仪的角度值和加速度计的角速度,由卡尔曼知识可知,卡尔曼滤波器最重要的是对预测值的协方差(Q),和测量值的协方差(R)进行估计,当我赋值Q=0.001,R=0.5时输出到滤波器的角度和输出角度波形如下:
Q=0.001,R=0.5.png
此时输出波形一直在0点左右,我的初始预测值为0;但是由卡尔曼原理可知,预测值会不断根据最后输出值更新,也就是说输出值对测量值有一个跟踪过程,但是我这个一直在0点左右,我的猜想是我的预测值没有更新,于是我对Q,R做了下面
改动,其他值不变
Q=0.9,R=0.5波形如下:
Q=0.9,R=0.5.png
当Q=1.5,R=0.5时波形如下:
Q=1.5,R=0.5.png
,做到这一步后我又去看了一下原理
Q/(Q+R)的值就是卡尔曼增益的收敛值,比如其值为0.2,那么卡尔曼增益会向0.2收敛(对于0.2的含义解释一下,比如预测角度值是5度,角度测量值是10度,那么最优化角度为:5+0.2*(10-5)=6。从这里可以看出,卡尔曼增益越小,说明预测值越可靠,最优化角度越接近预测值;相反的,卡尔曼增益越大,说明测量值越可靠,最优化角度越接近测量值)。
总结一下:
两个疑问;第一由上面的三个波形是否可以说明我的预测值没有更新??第二:当Q=1.5,R=0.5时此时滤波器设置是否合理??
最后附上代码:
#include"includes.h"
//******卡尔曼参数************
////******kalman参数************
float Gyro_y; //Y轴陀螺仪数据暂存
float Angle; //小车最终倾斜角度
float code Q_angle=1.5;
float code Q_gyro=0.003;
float code R_angle=0.5;
float code dt=0.01; //dt为kalman滤波器采样时间;
char code C_0 = 1;
float xdata Q_bias, Angle_err;//
float xdata PCt_0, PCt_1, E;
float xdata K_0, K_1, t_0, t_1;
float xdata Pdot[4] ={0,0,0,0};
float xdata PP[2][2] = { { 1, 0 },{ 0, 1 } };
//*********************************************************
// 卡尔曼滤波
// 卡尔曼滤波
//*********************************************************
//Kalman滤波,20MHz的处理时间约0.77ms;
void Kalman_Filter(float Accel,float Gyro)
{
Angle+=(Gyro-Q_bias)* dt; //第一步为卡尔曼第一个方程X(k|k-1)=A X(k-1|k-1)+B U(k) ……….. (1)
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; //后验估计
Gyro_y = Gyro - Q_bias; //输出值(后验估计)的微分=角速度
}
void main ()
{
float Angle_accel_x,Palstance_gyro_x;
float PWM; //综合PWM计算
Init_PWM();
Init_Motor();
LCD_Init();
InitMPU6050();
Chuankou_Init();
Delay200ms( );
while(1)
{
Angle_accel_x=Read_Acc_x( );
Display_dec(0x80,Angle_accel_x);
Palstance_gyro_x=Read_Gry_x( );
Display_dec(0x90,Palstance_gyro_x);
//-------卡尔曼滤波融合-----------------------
Kalman_Filter(Angle_accel_x,Palstance_gyro_x); //卡尔曼滤波计算倾角
Display_dec(0x84,Angle);
Display_dec(0x94,Gyro_y);
Send_data((int)Angle_accel_x);
Send_data((int)Angle);
Send_data((int)Palstance_gyro_x);
Send_data((int)Gyro_y);
PWM = 4.7*Angle + 0*Gyro_y; //PID:角速度和角度
// PPWM_R =PWM;
// PPWM_L =PWM;
if(Angle_accel_x<-40||Angle_accel_x>40) //角度过大,关闭电机
{
PWM=0;
}
Display_dec(0x88,PWM);
PWM_Motor(PWM,PWM);
}
} |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|