前言
上一篇博客对基于卡尔曼滤波器的姿态解算进行了一定程度的公式推导,这篇博客将进行算法公式的代码实现,并对姿态解算效果进行效果演示。
考虑到有一些单片机上无法直接进行矩阵运算,因此本篇博客的主要内容之一就是将矩阵运算拆解成方程组形式。
公式解析
-
s t e p 1 step1 step1:获取欧拉角的导数
[ ϕ ˙ θ ˙ ψ ˙ ] = [ 1 S ϕ T θ C ϕ T θ 0 C ϕ − S ϕ 0 S ϕ / C θ C ϕ / C θ ] [ p q r ] \begin{array}{ll} {\left[\begin{array}{c} \dot{\boldsymbol{\phi}} \\ \dot{\boldsymbol{\theta}} \\ \dot{\boldsymbol{\psi}} \end{array}\right]=\left[\begin{array}{ccc} 1 & S_{\phi} T_{\theta} & C_{\phi} T_{\theta} \\ 0 & C_{\phi} & -S_{\phi} \\ 0 & S_{\phi} / C_{\theta} & C_{\phi} / C_{\theta} \end{array}\right]\left[\begin{array}{c} p \\ q \\ r \end{array}\right]} \end{array} ϕ˙θ˙ψ˙ = 100SϕTθCϕSϕ/CθCϕTθ−SϕCϕ/Cθ pqr
其中, [ p q r ] \begin{bmatrix}p\\q\\r\end{bmatrix} pqr 是陀螺仪角速度数据。
整理成离散形式的方程组为:
{ ϕ k ˙ = p k + S ϕ k T θ k q k + C ϕ k T θ k r k θ k ˙ = C ϕ k q k − S ϕ k r k ψ k ˙ = S ϕ k q k / C θ k + C ϕ k r k / C θ k (1) \left\{ \begin{aligned} & \dot{\boldsymbol{\phi_{k}}} = p_{k}+S_{\phi_{k}}T_{\theta_{k}}q_{k}+C_{\phi_{k}}T_{\theta_{k}}r_{k}\\ & \dot{\boldsymbol{\theta_{k}}} = C_{\phi_{k}}q_{k}-S_{\phi_{k}}r_{k}\\ & \dot{\boldsymbol{\psi_{k}}}= S_{\phi_{k}}q_{k}/C_{\theta_{k}}+C_{\phi_{k}}r_{k}/C_{\theta_{k}}\\ \end{aligned} \right. \tag{1} ⎩ ⎨ ⎧ϕk˙=pk+SϕkTθkqk+CϕkTθkrkθk˙=Cϕkqk−Sϕkrkψk˙=Sϕkqk/Cθk+Cϕkrk/Cθk(1) -
s t e p 2 step2 step2:先验估计
[ ϕ ^ k + 1 − θ ^ k + 1 − ψ ^ k + 1 − ] = [ 1 0 0 0 1 0 0 0 1 ] [ ϕ ^ k θ ^ k ψ ^ k ] + [ T 0 0 0 T 0 0 0 T ] [ ϕ k ˙ θ k ˙ ψ k ˙ ] \begin{bmatrix}\boldsymbol{\hat{\phi}_{k+1}^{-}} \\ \boldsymbol{\hat{\theta}_{k+1}^{-}} \\ \boldsymbol{\hat{\psi}_{k+1}^{-}}\end{bmatrix} \ =\begin{bmatrix}1 & 0&0 \\ 0&1&0 \\ 0&0&1\end{bmatrix}\ \begin{bmatrix}\boldsymbol{\hat{\phi}_{k}} \\ \boldsymbol{\hat{\theta}_{k}} \\ \boldsymbol{\hat{\psi}_{k}}\end{bmatrix}\ +\begin{bmatrix}T & 0&0 \\ 0&T&0 \\ 0&0&T\end{bmatrix}\ \begin{bmatrix}\dot{\boldsymbol{\phi_{k}}} \\ \dot{\boldsymbol{\theta_{k}}} \\ \dot{\boldsymbol{\psi_{k}}}\end{bmatrix} ϕ^k+1−θ^k+1−ψ^k+1− = 100010001 ϕ^kθ^kψ^k + T000T000T ϕk˙θk˙ψk˙
整理成离散形式的方程组
{ ϕ ^ k + 1 − = ϕ ^ k + T ϕ k ˙ θ ^ k + 1 − = θ ^ k + T θ k ˙ ψ ^ k + 1 − = ψ ^ k + T ψ k ˙ (2) \left\{ \begin{aligned} & \boldsymbol{\hat{\phi}_{k+1}^{-}} = \boldsymbol{\hat{\phi}_{k}} + T\dot{\boldsymbol{\phi_{k}}}\\ &\boldsymbol{\hat{\theta}_{k+1}^{-}} = \boldsymbol{\hat{\theta}_{k}} + T\dot{\boldsymbol{\theta_{k}}} \\ &\boldsymbol{\hat{\psi}_{k+1}^{-}}=\boldsymbol{\hat{\psi}_{k}}+T\dot{\boldsymbol{\psi_{k}}}\\ \end{aligned} \right. \tag{2} ⎩ ⎨ ⎧ϕ^k+1−=ϕ^k+Tϕk˙θ^k+1−=θ^k+Tθk˙ψ^k+1−=ψ^k+Tψk˙(2) -
s t e p 3 step3 step3:先验估计误差协方差矩阵(
矩阵A是单位矩阵
)
P k + 1 − = A P k A T + Q P_{k+1}^{-}=A P_{k} A^{T}+Q Pk+1−=APkAT+Q
令系统噪声协方差矩阵 Q = [ q ϕ 0 0 0 q θ 0 0 0 q ψ ] Q=\begin{bmatrix}q_{\phi}&0&0\\0&q_{\theta}&0\\0&0&q_{\psi}\end{bmatrix} Q= qϕ000qθ000qψ ,先验估计误差协方差矩阵为 P k − = [ p ϕ , k − 0 0 0 p θ , k − 0 0 0 p ψ , k − ] P_{k}^{-}=\begin{bmatrix}p_{\phi,k}^{-}&0&0\\0&p_{\theta,k}^{-}&0\\0&0&p_{\psi,k}^{-}\end{bmatrix} Pk−= pϕ,k−000pθ,k−000pψ,k− ,后验估计误差协方差矩阵为 P k = [ p ϕ , k 0 0 0 p θ , k 0 0 0 p ψ , k ] P_{k}=\begin{bmatrix}p_{\phi,k}&0&0\\0&p_{\theta,k}&0\\0&0&p_{\psi,k}\end{bmatrix} Pk= pϕ,k000pθ,k000pψ,k ,则得到
{ p ϕ , k + 1 − = p ϕ , k + q ϕ p θ , k + 1 − = p θ , k + q θ p ψ , k + 1 − = p ψ , k + q ψ (3) \left\{ \begin{aligned} & p_{\phi,k+1}^{-} = p_{\phi,k} + q_{\phi}\\ & p_{\theta,k+1}^{-} = p_{\theta,k} + q_{\theta}\\ & p_{\psi,k+1}^{-} = p_{\psi,k} + q_{\psi}\\ \end{aligned} \right. \tag{3} ⎩ ⎨ ⎧pϕ,k+1−=pϕ,k+qϕpθ,k+1−=pθ,k+qθpψ,k+1−=pψ,k+qψ(3) -
s t e p 4 step4 step4:卡尔曼增益矩阵计算(
矩阵除法即乘以矩阵的逆
)
K k + 1 = P k + 1 − H T H P k + 1 − H T + R K_{k+1}=\frac{P_{k+1}^{-}H^{T}}{HP_{k+1}^{-}H^{T}+R} Kk+1=HPk+1−HT+RPk+1−HT
其中, H = [ 1 0 0 0 1 0 0 0 0 ] H = \begin{bmatrix}1 &0&0\\0&1&0\\0&0&0\end{bmatrix} H= 100010000 ,令测量噪声协方差矩阵 R = [ r ϕ 0 0 0 r θ 0 0 0 r ψ ] R=\begin{bmatrix}r_{\phi}&0&0\\0&r_{\theta}&0\\0&0&r_{\psi}\end{bmatrix} R= rϕ000rθ000rψ ,令卡尔曼增益矩阵 K k = [ k 1 , k 0 0 0 k 2 , k 0 0 0 k 3 , k ] K_{k}=\begin{bmatrix}k_{1,k}&0&0\\0&k_{2,k}&0\\0&0&k_{3,k}\end{bmatrix} Kk= k1,k000k2,k000k3,k ,则得到:
{ k 1 , k + 1 = p ϕ , k + 1 − / ( p ϕ , k + 1 − + r ϕ ) k 2 , k + 1 = p θ , k + 1 − / ( p θ , k + 1 − + r θ ) k 3 , k + 1 = 0 (4) \left\{ \begin{aligned} & k_{1,k+1}=p_{\phi,k+1}^{-}/(p_{\phi,k+1}^{-}+r_{\phi})\\ & k_{2,k+1}=p_{\theta,k+1}^{-}/(p_{\theta,k+1}^{-}+r_{\theta})\\ & k_{3,k+1}=0\\ \end{aligned} \right. \tag{4} ⎩ ⎨ ⎧k1,k+1=pϕ,k+1−/(pϕ,k+1−+rϕ)k2,k+1=pθ,k+1−/(pθ,k+1−+rθ)k3,k+1=0(4) -
s t e p 5 step5 step5:获取欧拉角测量值
令 z k = [ ϕ m , k θ m , k ψ m , k ] z_{k} = \begin{bmatrix}\phi_{m,k}\\\theta_{m,k}\\\psi_{m,k}\end{bmatrix} zk= ϕm,kθm,kψm,k ,则得到:
{ ϕ m , k = a t a n ( a y / a z ) θ m , k = − a t a n ( a x / a y 2 + a z 2 ) ψ m , k = 0 (5) \left\{ \begin{aligned} & \phi_{m,k}=atan(a_{y}/a_{z})\\ & \theta_{m,k}=-atan(a_{x}/\sqrt{a_{y}^{2}+a_{z}^{2}})\\ & \psi_{m,k}=0\\ \end{aligned} \right. \tag{5} ⎩ ⎨ ⎧ϕm,k=atan(ay/az)θm,k=−atan(ax/ay2+az2)ψm,k=0(5)
其中, [ a x a y a z ] \begin{bmatrix}a_{x}\\a_{y}\\a_{z}\end{bmatrix} axayaz 是三轴加速度计数据。 -
s t e p 6 step6 step6:后验估计计算
x ^ k + 1 = x ^ k + 1 − + K k + 1 ( z k + 1 − H x ^ k + 1 − ) \hat{x}_{k+1}=\hat{x}_{k+1}^{-}+K_{k+1}(z_{k+1}-H\hat{x}_{k+1}^{-}) x^k+1=x^k+1−+Kk+1(zk+1−Hx^k+1−)
令后验估计状态为 [ ϕ ^ k + 1 θ ^ k + 1 ψ ^ k + 1 ] \begin{bmatrix}\boldsymbol{\hat{\phi}_{k+1}}\\\boldsymbol{\hat{\theta}_{k+1}}\\\boldsymbol{\hat{\psi}_{k+1}}\end{bmatrix} ϕ^k+1θ^k+1ψ^k+1 ,可得到:
{ ϕ ^ k + 1 = ( 1 − k 1 , k + 1 ) ϕ ^ k + 1 − + k 1 , k + 1 ϕ m , k + 1 θ ^ k + 1 = ( 1 − k 2 , k + 1 ) θ ^ k + 1 − + k 2 , k + 1 θ m , k + 1 ψ ^ k + 1 = ψ ^ k + 1 − (6) \left\{ \begin{aligned} & \boldsymbol{\hat{\phi}_{k+1}}=(1-k_{1,k+1})\boldsymbol{\hat{\phi}_{k+1}^{-}}+k_{1,k+1}\phi_{m,k+1}\\ & \boldsymbol{\hat{\theta}_{k+1}}=(1-k_{2,k+1})\boldsymbol{\hat{\theta}_{k+1}^{-}}+k_{2,k+1}\theta_{m,k+1}\\ & \boldsymbol{\hat{\psi}_{k+1}}=\boldsymbol{\hat{\psi}_{k+1}^{-}}\\ \end{aligned} \right. \tag{6} ⎩ ⎨ ⎧ϕ^k+1=(1−k1,k+1)ϕ^k+1−+k1,k+1ϕm,k+1θ^k+1=(1−k2,k+1)θ^k+1−+k2,k+1θm,k+1ψ^k+1=ψ^k+1−(6)
从这组方程里可以看出航向角漂移问题的来源。
-
s t e p 7 step7 step7:后验估计误差协方差矩阵
P k + 1 = ( I − K k + 1 H ) P k + 1 − P_{k+1}=(I-K_{k+1}H)P_{k+1}^{-} Pk+1=(I−Kk+1H)Pk+1−
可以得到:
{ p ϕ , k + 1 = ( 1 − k 1 , k + 1 ) p ϕ , k + 1 − p θ , k + 1 = ( 1 − k 2 , k + 1 ) p θ , k + 1 − p ψ , k + 1 = p ψ , k + 1 − (7) \left\{ \begin{aligned} & p_{\phi,k+1} = (1-k_{1,k+1})p_{\phi,k+1}^{-}\\ & p_{\theta,k+1} = (1-k_{2,k+1})p_{\theta,k+1}^{-}\\ & p_{\psi,k+1} = p_{\psi,k+1}^{-}\\ \end{aligned} \right. \tag{7} ⎩ ⎨ ⎧pϕ,k+1=(1−k1,k+1)pϕ,k+1−pθ,k+1=(1−k2,k+1)pθ,k+1−pψ,k+1=pψ,k+1−(7)
代码实现
- 函数接口说明
函数输入参数:
g x , g y , g z gx,gy,gz gx,gy,gz:陀螺仪角速度数据,单位: r a d / s rad/s rad/s;
a x , a y , a z ax,ay,az ax,ay,az:加速度计数据,单位不管;
要将六轴传感器中的角速度坐标系和加速度坐标系对应上,统一方向。
#include <math.h>
float roll = 0,pitch = 0,yaw = 0;
//euro angle
static float Xk_[3] = {0};
//Prior estimation
static float Xk[3] = {0};
//Posterior estimation
static float Uk[3] = {0};
//system input
static float Zk[3] = {0};
//measure status
static float Pk[3] = {1,1,1};
//Posteriori estimation error covariance
static float Pk_[3] = {0};
//Prior estimation error covariance
static float K[3] = {0};
//kalman gain
static float Q[3] = {1,1,1};
//System noise covariance
static float R[3] = {1,1,1};
//Measure noise covariance
static float T = 0.002f;
//Discrete time
//attitude solution by kalman filter
void kalman_filter_attitude_solution(float gx,float gy,float gz,float ax,float ay,float az)
{
Uk[0] = gx + sin(Xk[0]) * tan(Xk[1]) * gy + cos(Xk[0]) * tan(Xk[1]) * gz;
Uk[1] = cos(Xk[0]) * gy - sin(Xk[0]) * gz;
Uk[2] = sin(Xk[0]) * gy / cos(Xk[1]) + cos(Xk[0]) * gz / cos(Xk[1]);
//step1 - system input
Xk_[0] = Xk[0] + T * Uk[0];
Xk_[1] = Xk[1] + T * Uk[1];
Xk_[2] = Xk[2] + T * Uk[2];
//step2 - Prior estimation
Pk_[0] = Pk[0] + Q[0];
Pk_[1] = Pk[1] + Q[1];
Pk_[2] = Pk[2] + Q[2];
//step3 - Prior estimation error covariance
K[0] = Pk_[0] / (Pk_[0] + R[0]);
K[1] = Pk_[1] / (Pk_[1] + R[1]);
K[2] = 0;
//step4 - kalman gain
Zk[0] = atan( ay / az );
Zk[1] = -atan( ax / (sqrt( ay * ay + az * az )));
Zk[2] = 0;
//step5 - measure data
Xk[0] = (1 - K[0]) * Xk_[0] + K[0] * Zk[0];
Xk[1] = (1 - K[1]) * Xk_[1] + K[1] * Zk[1];
Xk[2] = Xk_[2];
//step6 - Posterior estimation
Pk[0] = (1 - K[0]) * Pk_[0];
Pk[1] = (1 - K[1]) * Pk_[1];
Pk[2] = Pk_[2];
//step7 - Posteriori estimation error covariance
roll = Xk[0] / 3.141f * 180.f;
pitch = Xk[1] / 3.141f * 180.f;
yaw = Xk[2] / 3.141f * 180.f;
//calculate the angle,unit: degree
}
效果演示
本博客采用匿名飞控板 + 匿名上位机来展示姿态解算效果不是广告,刚好手上有一块。
姿态解算
总结
- 基于卡尔曼滤波器的姿态解算能够获得准确的姿态角,但是由于测量数据无法对航向角
yaw
进行校正,导致航向角在一定时间累积误差后会出现漂移问题。这种漂移问题在振动大,电磁干扰大的环境下将更为明显。 - 可以通过初始化时计算平均偏移量来做一定的偏置补偿,但仅能减缓漂移的速度,无法完全抑制。
- 下一期博客的内容,将针对航向角漂移问题,引入磁力计传感来解决。
若有需要源代码工程可私信我