★基于陀螺仪及加速度计信号融合的姿态角度测量
2卡尔曼滤波融合过程
首先建立系统的状态方程和测量方程.由于倾角和倾角角速度存在导数关系,系统倾斜真实角度 可以用来做一个状态向量.在该系统中,采用加速度计估计出陀螺仪常值偏差b,以此偏差作为状态向量得到相应的状态方程和观测方程:
X(K)=[10 -T1]X(K-1)+ [T 0]Tωgyro(k-1)+[wg (k)T 0]T
Z(K)= [1 0]Y(K)+wa(K)
式中,ωgyro为包含固定偏差的陀螺仪输出角速度,Z(K)为加速度计经处理后得到的角度值,wg为陀螺仪测量噪声,wa为加速度计测量噪声,wg与wa相互独立,此处假设二者为满足正态分布的白色噪声,令T为系统采样周期,其中:
X(K-1) =[φ b ]T φ :陀螺仪经过积分后的角度
Y(K) = [∅ b]T ∅:加速度计计算得到的角度
其中b为陀螺仪漂移误差。同时,要估算k时刻的实际角度,就必须根据k-1时刻的角度值,再根据预测得到的k时刻的角度值得到k时刻的高斯噪声的方差,在此基础之上卡尔曼滤波器进行递归运算直至估算出最优的角度值.在此,须知道系统过程噪声协方差阵Q以及测量误差的协方差矩阵R,对卡尔曼滤波器进行校正.Q与R矩阵的形式如下:
Q=[q_acce0 0q_gryo] R=[r_acce]
式中,q_acce和q_gyro分别是加速度计和陀螺仪测量的协方差, 其数值代表卡尔曼滤波器对其传感器数据的信任程度,值越小,表明信任程度越高.在该系统中陀螺仪的值更为接近准确值,因此取q_gyro的值大于q_acce的值.
当前状态:
X(k|k-1)=AX(k-1|k-1)+BTU(k) (公式1)
式中,A=[10 -T1] ,B= [T 0],X(k|k-1)是利用k预测的结果, X(k-1|k-1)是k-1时刻的最优结果.
则有对应于 X(k|k-1) 的协方差为:
P(k|k-1)=AP(k-1|k-1)AT+Q (公式2)
式中,P(k-1|k-1)是X(k-1|k-1)对应的协方差,AT表示A的转置矩阵,Q是系统过程的协方差.式子(1)、 (2)即对系统的状态更新.
则状态k的最优化估算值X(k|k):
X(k|k)=X(k|k-1)+K(k)(Z(k)-HX(k|k-1)) (公式3)
其中 H= [1 0].
K 为卡尔曼增益(KalmanGain):
K(k)=P(k|k-1)HT/(HP(k|k-1)HT+R) (公式4)
此时, 我们已经得到了k状态下最优的估算值X(k|k).但是为了使卡尔曼滤波器不断的运行下去直到找到最优的角度值, 我们还要更新
k状态下 X(k|k)的协方差:
P(k|k)=[I-K(k)H]P(k|k-1)[I-K(k)H]T+ K(k)RK(k)T(公式5)
可改写为:
P(k|k)=[I-K(k)H]P(k|k-1) (公式6)
其中,公式(5)和公式(6)均为更新协方差,公式(6)计算量相对较小,但不能保证计算出的P(k|k)是对称的,公式(5)的适用范围较广。I为单位矩阵, 对于本系统则有:
I=[10 01] 当系统进入k+1状态时, P(k|k)就是式子(2)的P(k-1|k-1).(3)、(4)、(5)式为卡尔曼滤波器状态更新方程.计算完时间更新方程和测量更新方程后, 再次重复上一次计算得到的后验估计, 作为下一次计算的先验估计, 这样,周而复始、循环反复地运算下去直至找到最优的结果.
2、卡尔曼滤波代码:
#define T 0.005
float A[2][2]={{1,-T},{0,1}}; //系统系数
float B[2]={T,0},H[2]={1,0}; //系统系数
float Last_result; //上一次的角度值
float Bias_angle; //陀螺仪积分出的角度相对于加速度计的偏移量
float Now_Groy_palstance; //当前包含固定偏差的陀螺仪输出角速度
float Gyro_measure_noise; //为陀螺仪测量噪声
float Acceleration_measure_noise; //为加速度计测量噪声
float Measure; //当前的测量值
floatQ[2][2]={{0.00000003,0},{0,0.00000001}},R=0.5;
//系统过程噪声协方差阵Q以及测量误差的协方差矩阵R
float Now_measure_result[2]; //当前预测结果
float Now_best_result[2]; //当前最优化估算值
float Now_covariance[2][2]; //对应于Now_measure_result的协方差
floatlast_covariance[2][2]={{0.005,0.005},{0.005,0.005}}
//对应于Last_best_result的协方差
float Kalman_Gain[2]; //卡尔曼增益
float I[2][2]={{1,0},{0,1}}; //I为单位阵
float Real_angle;
void Kalman_LvBo()
{
float P[2][2],K[2],D[2][2],S[2][2]; //过渡矩阵
Now_Groy_palstance=(Gyro_X); //陀螺仪角速度
Last_result=Now_best_result[0]; //Ψ
Bias_angle=Now_best_result[1]; //b
//测量方程 Z(K)
Measure=angle; //加速度角度
//公式(1) 当前状态方程 X(K|K-1)
Now_measure_result[0]= A[0][0]*Last_result+A[0][1]* Bias_angle+B[0]*Now_Groy_palstance+Gyro_measure_noise*T;
Now_measure_result[1]=A[1][0]*Last_result+A[1][1]* Bias_angle;
//公式(2) 当前状态协方差 P(K/K-1)
P[0][0]=A[0][0]*last_covariance[0][0]+A[0][1]*last_covariance[1][0];
P[0][1]=A[0][0]*last_covariance[0][1]+A[0][1]*last_covariance[1][1];
P[1][0]=A[1][0]*last_covariance[0][0]+A[1][1]*last_covariance[1][0];
P[1][1]=A[1][0]*last_covariance[0][1]+A[1][1]*last_covariance[1][1];
Now_covariance[0][0]=P[0][0]*A[0][0]+P[0][1]*A[0][1]+Q[0][0];
Now_covariance[0][1]=P[0][0]*A[1][0]+P[0][1]*A[1][1]+Q[0][1];
Now_covariance[1][0]=P[1][0]*A[0][0]+P[1][1]*A[0][1]+Q[1][0];
Now_covariance[1][1]=P[1][0]*A[1][0]+P[1][1]*A[1][1]+Q[1][1];
//公式(4) 卡尔曼增益
K[0]=H[0]*Now_covariance[0][0]+H[1]*Now_covariance[1][0];
K[1]=H[0]*Now_covariance[0][1]+H[1]*Now_covariance[1][1];
Kalman_Gain[0]=(Now_covariance[0][0]*H[0]+Now_covariance[0][1]*H[1])/(H[0]*K[0]+H[1]*K[1]+R);
Kalman_Gain[1]=(Now_covariance[1][0]*H[0]+Now_covariance[1][1]*H[1])/(H[0]*K[0]+H[1]*K[1]+R);
//公式(3) 最优化估算值 X(K|K)
Now_best_result[0]=Now_measure_result[0]+Kalman_Gain[0]*(Measure-(H[0]*Now_measure_result[0]+H[1]*Now_measure_result[1]));
Now_best_result[1]=Now_measure_result[1]+Kalman_Gain[1]*(Measure-(H[0]*Now_measure_result[0]+H[1]*Now_measure_result[1]));
//公式(5) 更新当前状态的协方差 P(K|K)
D[0][0]=I[0][0]-Kalman_Gain[0]*H[0];
D[0][1]=I[0][1]-Kalman_Gain[0]*H[1];
D[1][0]=I[1][0]-Kalman_Gain[1]*H[0];
D[1][1]=I[1][1]-Kalman_Gain[1]*H[1];
S[0][0]=D[0][0]*Now_covariance[0][0]+D[0][1]*Now_covariance[1][0];
S[0][1]=D[0][0]*Now_covariance[0][1]+D[0][1]*Now_covariance[1][1];
S[1][0]=D[1][0]*Now_covariance[0][0]+D[1][1]*Now_covariance[1][0];
S[1][1]=D[1][0]*Now_covariance[0][1]+D[1][1]*Now_covariance[1][1];
last_covariance[0][0]=S[0][0]*D[0][0]+S[0][1]*D[0][1]+Kalman_Gain[0]*Kalman_Gain[0]*R;
last_covariance[0][1]=S[0][0]*D[1][0]+S[0][1]*D[1][1]+Kalman_Gain[0]*Kalman_Gain[1]*R;
last_covariance[1][0]=S[1][0]*D[0][0]+S[1][1]*D[0][1]+Kalman_Gain[1]*Kalman_Gain[0]*R;
last_covariance[1][1]=S[1][0]*D[1][0]+S[1][1]*D[1][1]+Kalman_Gain[1]*Kalman_Gain[1]*R;
Real_angle=Now_best_result[0]; //输出最终角度
}