前言
- 第一篇博客对基于卡尔曼滤波器的姿态解算进行了原理简述和公式推导,传送门
- 第二篇博客在第一篇的基础上实现代码并观察解算效果,传送门
- 在第二篇博客中,提到了由于重力加速度数据无法对航向角
yaw
进行标定,导致陀螺仪数据噪声会在姿态解算过程中累积误差,使航向角yaw
漂移。 - 本博客将引入磁力计传感器,来对航向角
yaw
进行标定,并介绍相关原理和公式推导过程。
磁力计传感器
原理
磁力计又称电子罗盘,其与指南针原理相似,都是通过地球磁场信息来确定惯性系方向。
磁感线从地磁南极指向地磁北极,而磁力计会将经过其的磁感线分解为机体系
X
Y
Z
XYZ
XYZ三个轴的分量。利用这组数据,与加速度计类似的原理,用来对航向角进行标定,从而获得准确且稳定的航向信息,最终解决航向角漂移问题。
问题
磁力计本身是由三组霍尔元件堆叠而成,因此由于设计或加工等问题,常常会出现磁力计输出数据不对称的问题。
- 地球磁场向量在惯性系 中是一个固定的向量,因此当机体系转动时,在理想情况下,磁力计三轴数据应始终位于一个中心点在坐标原点的球面上。
- 但实际上磁力计三轴数据输出产生的面是一个中心点不在坐标原点的椭球面,并且根据不同的芯片情况和工况环境,产生的椭球面不同。
因此在进行数据读取后需要对三轴磁力计数据进行归一化处理,后续详述。
磁力计标定航向角原理
惯性系定义
通常,惯性系的
X
Y
Z
XYZ
XYZ轴分别对应北东天,即惯性系
X
X
X轴指向北,
Y
Y
Y轴指向东,
Z
Z
Z轴指向天。因此,地球磁感线方向向量始终在惯性系平面
X
O
Z
XOZ
XOZ中磁感线始终由南指向北
,其在
X
X
X轴和
Z
Z
Z轴的分量比例取决于在地球的位置:
- 若在地球赤道附近,则 X X X轴占比较大;
- 若在南北极附近,则 Z Z Z轴占比较大;
综上,通常定义正北方向为零度航向角,即 y a w = 0 yaw=0 yaw=0,并以右手法则判定正负方向。
公式推导
不考虑磁场干扰,设地球磁场在惯性系下的向量为
[
m
e
,
x
0
m
e
,
z
]
\begin{bmatrix}m_{e,x}\\0\\m_{e,z}\end{bmatrix}
me,x0me,z
,经过坐标系变换得到机体系下的向量
[
m
b
,
x
m
b
,
y
m
b
,
z
]
\begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix}
mb,xmb,ymb,z
,其中从惯性系到机体系的坐标系变换矩阵
R
R
R定义为:
R
=
R
X
(
ϕ
)
R
Y
(
θ
)
R
Z
(
ψ
)
=
[
C
ψ
C
θ
S
ψ
C
θ
−
S
θ
C
ψ
S
θ
S
ϕ
−
S
ψ
C
ϕ
S
ψ
S
θ
S
ϕ
+
C
ψ
C
ϕ
C
θ
S
ϕ
C
ψ
S
θ
C
ϕ
+
S
ψ
S
ϕ
S
ψ
S
θ
C
ϕ
−
C
ψ
S
ϕ
C
θ
C
ϕ
]
(1)
\boldsymbol{R}=\boldsymbol{R_{X}(\phi)}\boldsymbol{R_{Y}(\theta)}\boldsymbol{R_{Z}(\psi)}=\left[\begin{array}{ccc} C_{\psi} C_{\theta} & S_{\psi} C_{\theta} &-S_{\theta} \\ C_{\psi} S_{\theta} S_{\phi}-S_{\psi} C_{\phi} & S_{\psi} S_{\theta} S_{\phi}+C_{\psi} C_{\phi} & C_{\theta} S_{\phi} \\ C_{\psi} S_{\theta} C_{\phi}+S_{\psi} S_{\phi} &S_{\psi} S_{\theta} C_{\phi}-C_{\psi} S_{\phi}& C_{\theta} C_{\phi} \end{array}\right] \tag{1}
R=RX(ϕ)RY(θ)RZ(ψ)=
CψCθCψSθSϕ−SψCϕCψSθCϕ+SψSϕSψCθSψSθSϕ+CψCϕSψSθCϕ−CψSϕ−SθCθSϕCθCϕ
(1)
其中,
R
Z
(
ψ
)
=
[
c
o
s
ψ
s
i
n
ψ
0
−
s
i
n
ψ
c
o
s
ψ
0
0
0
1
]
(2)
\boldsymbol{R_{Z}(\psi)}= \begin{bmatrix} cos\boldsymbol{\psi} & sin\boldsymbol{\psi} &0\\ -sin\boldsymbol{\psi} &cos\boldsymbol{\psi} &0 \\ 0 &0 &1\end{bmatrix} \tag{2}
RZ(ψ)=
cosψ−sinψ0sinψcosψ0001
(2)
R
Y
(
θ
)
=
[
c
o
s
θ
0
−
s
i
n
θ
0
1
0
s
i
n
θ
0
c
o
s
θ
]
(3)
\boldsymbol{R_{Y}(\theta)}= \begin{bmatrix} cos\boldsymbol{\theta}& 0&-sin\boldsymbol{\theta}\\ 0 &1 &0 \\ sin\boldsymbol{\theta} &0 &cos\boldsymbol{\theta}\end{bmatrix} \tag{3}
RY(θ)=
cosθ0sinθ010−sinθ0cosθ
(3)
R
X
(
ϕ
)
=
[
1
0
0
0
c
o
s
ϕ
s
i
n
ϕ
0
−
s
i
n
ϕ
c
o
s
ϕ
]
(4)
\boldsymbol{R_{X}(\phi)}= \begin{bmatrix} 1 &0 &0\\ 0&cos\boldsymbol{\phi}& sin\boldsymbol{\phi}\\ 0 &-sin\boldsymbol{\phi} &cos\boldsymbol{\phi}\end{bmatrix} \tag{4}
RX(ϕ)=
1000cosϕ−sinϕ0sinϕcosϕ
(4)
好了,有了上面这些前提,我要开始表演(公式推导)了
根据上述描述,满足以下关系:
[
m
b
,
x
m
b
,
y
m
b
,
z
]
=
R
[
m
e
,
x
0
m
e
,
z
]
=
R
X
(
ϕ
)
R
Y
(
θ
)
R
Z
(
ψ
)
[
m
e
,
x
0
m
e
,
z
]
(5)
\begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} = \boldsymbol{R}\begin{bmatrix}m_{e,x}\\0\\m_{e,z}\end{bmatrix}=\boldsymbol{R_{X}(\phi)}\boldsymbol{R_{Y}(\theta)}\boldsymbol{R_{Z}(\psi)}\begin{bmatrix}m_{e,x}\\0\\m_{e,z}\end{bmatrix} \tag{5}
mb,xmb,ymb,z
=R
me,x0me,z
=RX(ϕ)RY(θ)RZ(ψ)
me,x0me,z
(5)
由于坐标系是按顺序绕轴转动的,而此时磁力计数据的目标是为了解算得到航向角
ψ
\boldsymbol{\psi}
ψ,因此我们如果能得到惯性系下磁力数据绕
Z
Z
Z轴转动
ψ
\boldsymbol{\psi}
ψ角后的向量
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix}
mZ,xmZ,ymZ,z
,满足以下关系
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
=
R
Z
(
ψ
)
[
m
e
,
x
0
m
e
,
z
]
(6)
\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix} =\boldsymbol{R_{Z}(\psi)}\begin{bmatrix}m_{e,x}\\0\\m_{e,z}\end{bmatrix} \tag{6}
mZ,xmZ,ymZ,z
=RZ(ψ)
me,x0me,z
(6)
根据坐标系变换的几何关系,可以得到以下关系,
ψ
=
a
t
a
n
(
m
Z
,
x
/
m
Z
,
y
)
(7)
\boldsymbol{\psi}=atan(m_{Z,x}/m_{Z,y}) \tag{7}
ψ=atan(mZ,x/mZ,y)(7)
由 公式5 和 公式6 可以得到:
[
m
b
,
x
m
b
,
y
m
b
,
z
]
=
R
X
(
ϕ
)
R
Y
(
θ
)
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
(8)
\begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} =\boldsymbol{R_{X}(\phi)}\boldsymbol{R_{Y}(\theta)}\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix} \tag{8}
mb,xmb,ymb,z
=RX(ϕ)RY(θ)
mZ,xmZ,ymZ,z
(8)
整理后得到:
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
=
R
Y
−
1
(
θ
)
R
X
−
1
(
ϕ
)
[
m
b
,
x
m
b
,
y
m
b
,
z
]
(9)
\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix}=\boldsymbol{R_{Y}^{-1}(\theta)}\boldsymbol{R_{X}^{-1}(\phi)}\begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} \tag{9}
mZ,xmZ,ymZ,z
=RY−1(θ)RX−1(ϕ)
mb,xmb,ymb,z
(9)
由 公式3 和 公式4 所得这几个旋转变换矩阵都是正交矩阵
R
Y
−
1
(
θ
)
=
R
Y
T
(
θ
)
=
[
c
o
s
θ
0
s
i
n
θ
0
1
0
−
s
i
n
θ
0
c
o
s
θ
]
(10)
\boldsymbol{R_{Y}^{-1}(\theta)}=\boldsymbol{R_{Y}^{T}(\theta)}=\begin{bmatrix} cos\boldsymbol{\theta}& 0&sin\boldsymbol{\theta}\\ 0 &1 &0 \\ -sin\boldsymbol{\theta} &0 &cos\boldsymbol{\theta}\end{bmatrix} \tag{10}
RY−1(θ)=RYT(θ)=
cosθ0−sinθ010sinθ0cosθ
(10)
R
X
−
1
(
ϕ
)
=
R
X
T
(
ϕ
)
=
[
1
0
0
0
c
o
s
ϕ
−
s
i
n
ϕ
0
s
i
n
ϕ
c
o
s
ϕ
]
(11)
\boldsymbol{R_{X}^{-1}(\phi)}=\boldsymbol{R_{X}^{T}(\phi)}=\begin{bmatrix} 1 &0 &0\\ 0&cos\boldsymbol{\phi}& -sin\boldsymbol{\phi}\\ 0 &sin\boldsymbol{\phi} &cos\boldsymbol{\phi}\end{bmatrix} \tag{11}
RX−1(ϕ)=RXT(ϕ)=
1000cosϕsinϕ0−sinϕcosϕ
(11)
将 公式10 和 公式11 代入 公式9,得到:
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
=
[
c
o
s
θ
0
s
i
n
θ
0
1
0
−
s
i
n
θ
0
c
o
s
θ
]
[
1
0
0
0
c
o
s
ϕ
−
s
i
n
ϕ
0
s
i
n
ϕ
c
o
s
ϕ
]
[
m
b
,
x
m
b
,
y
m
b
,
z
]
(12)
\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix}=\begin{bmatrix} cos\boldsymbol{\theta}& 0&sin\boldsymbol{\theta}\\ 0 &1 &0 \\ -sin\boldsymbol{\theta} &0 &cos\boldsymbol{\theta}\end{bmatrix} \begin{bmatrix} 1 &0 &0\\ 0&cos\boldsymbol{\phi}& -sin\boldsymbol{\phi}\\ 0 &sin\boldsymbol{\phi} &cos\boldsymbol{\phi}\end{bmatrix} \begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} \tag{12}
mZ,xmZ,ymZ,z
=
cosθ0−sinθ010sinθ0cosθ
1000cosϕsinϕ0−sinϕcosϕ
mb,xmb,ymb,z
(12)
整理为:
[
m
Z
,
x
m
Z
,
y
m
Z
,
z
]
=
[
C
θ
S
θ
S
ϕ
S
θ
C
ϕ
0
C
ϕ
−
S
ϕ
−
S
θ
C
θ
S
ϕ
C
θ
C
ϕ
]
[
m
b
,
x
m
b
,
y
m
b
,
z
]
(13)
\begin{bmatrix}m_{Z,x}\\m_{Z,y}\\m_{Z,z}\end{bmatrix}=\begin{bmatrix} C_{\boldsymbol{\theta}}& S_{\boldsymbol{\theta}}S_{\boldsymbol{\phi}}&S_{\boldsymbol{\theta}}C_{\boldsymbol{\phi}}\\ 0 &C_{\boldsymbol{\phi}} &-S_{\boldsymbol{\phi}} \\ -S_{\boldsymbol{\theta}} &C_{\boldsymbol{\theta}}S_{\boldsymbol{\phi}} &C_{\boldsymbol{\theta}}C_{\boldsymbol{\phi}}\end{bmatrix} \begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} \tag{13}
mZ,xmZ,ymZ,z
=
Cθ0−SθSθSϕCϕCθSϕSθCϕ−SϕCθCϕ
mb,xmb,ymb,z
(13)
代码实现
-
s
t
e
p
1
step1
step1:读取并处理磁力计数据
令读取到的磁力计原始数据为 [ m r a w , x m r a w , y m r a w , z ] \begin{bmatrix}m_{raw,x}\\m_{raw,y}\\m_{raw,z}\end{bmatrix} mraw,xmraw,ymraw,z ,分别绕 X , Y , Z X,Y,Z X,Y,Z轴完整旋转一圈,记录各轴上的最大及最小值,记为 [ m m a x , x m m a x , y m m a x , z ] \begin{bmatrix}m_{max,x}\\m_{max,y}\\m_{max,z}\end{bmatrix} mmax,xmmax,ymmax,z 和 [ m m i n , x m m i n , y m m i n , z ] \begin{bmatrix}m_{min,x}\\m_{min,y}\\m_{min,z}\end{bmatrix} mmin,xmmin,ymmin,z ,设校准后的磁力计数据为 [ m b , x m b , y m b , z ] \begin{bmatrix}m_{b,x}\\m_{b,y}\\m_{b,z}\end{bmatrix} mb,xmb,ymb,z ,满足以下关系:
{ m b , x = ( m r a w , x − ( m m a x , x + m m i n , x ) / 2 ) / ( m m a x , x − m m i n , x ) / 2 ) m b , y = ( m r a w , y − ( m m a x , y + m m i n , y ) / 2 ) / ( m m a x , y − m m i n , y ) / 2 ) m b , z = ( m r a w , z − ( m m a x , z + m m i n , z ) / 2 ) / ( m m a x , z − m m i n , z ) / 2 ) \left\{ \begin{aligned} &m_{b,x} = (m_{raw,x} - (m_{max,x}+m_{min,x})/2) / (m_{max,x}-m_{min,x})/2)\\ &m_{b,y} = (m_{raw,y} - (m_{max,y}+m_{min,y})/2) / (m_{max,y}-m_{min,y})/2)\\ &m_{b,z} = (m_{raw,z} - (m_{max,z}+m_{min,z})/2) / (m_{max,z}-m_{min,z})/2)\\ \end{aligned} \right. ⎩ ⎨ ⎧mb,x=(mraw,x−(mmax,x+mmin,x)/2)/(mmax,x−mmin,x)/2)mb,y=(mraw,y−(mmax,y+mmin,y)/2)/(mmax,y−mmin,y)/2)mb,z=(mraw,z−(mmax,z+mmin,z)/2)/(mmax,z−mmin,z)/2) -
s
t
e
p
2
step2
step2:计算由磁力计解算到的航向角
由 公式13 可得
{ m Z , x = C θ m b , x + S θ S ϕ m b , y + S θ C ϕ m b , z m Z , y = C ϕ m b , y − S ϕ m b , z m Z , z = − S θ m b , x + C θ S ϕ m b , y + C θ C ϕ m b , z (14) \left\{ \begin{aligned} & m_{Z,x} = C_{\boldsymbol{\theta}}m_{b,x} + S_{\boldsymbol{\theta}}S_{\boldsymbol{\phi}}m_{b,y}+S_{\boldsymbol{\theta}}C_{\boldsymbol{\phi}}m_{b,z}\\ & m_{Z,y} = C_{\boldsymbol{\phi}}m_{b,y}-S_{\boldsymbol{\phi}}m_{b,z}\\ & m_{Z,z} = -S_{\boldsymbol{\theta}}m_{b,x}+C_{\boldsymbol{\theta}}S_{\boldsymbol{\phi}}m_{b,y}+C_{\boldsymbol{\theta}}C_{\boldsymbol{\phi}}m_{b,z}\\ \end{aligned} \right. \tag{14} ⎩ ⎨ ⎧mZ,x=Cθmb,x+SθSϕmb,y+SθCϕmb,zmZ,y=Cϕmb,y−Sϕmb,zmZ,z=−Sθmb,x+CθSϕmb,y+CθCϕmb,z(14)
由 公式7 得到航向角在卡尔曼滤波器中的测量值,即:
ψ m , k = a t a n ( m Z , x / m Z , y ) (15) \psi_{m,k}=atan(m_{Z,x}/m_{Z,y}) \tag{15} ψm,k=atan(mZ,x/mZ,y)(15)
在上一篇的基础上修改测量状态向量 z k z_{k} zk以及测量矩阵 H H H,即令
{ ϕ 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 = a t a n ( m Z , y / m Z , x ) (16) \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}=atan(m_{Z,y}/m_{Z,x})\\ \end{aligned} \right. \tag{16} ⎩ ⎨ ⎧ϕm,k=atan(ay/az)θm,k=−atan(ax/ay2+az2)ψm,k=atan(mZ,y/mZ,x)(16)
H = [ 1 0 0 0 1 0 0 0 1 ] (17) H = \begin{bmatrix}1 &0&0\\0&1&0\\0&0&1\end{bmatrix} \tag{17} H= 100010001 (17) -
s
t
e
p
3
step3
step3:完成卡尔曼滤波计算
(为了方便大家不用在第二篇博客和第三篇博客中来回切,把第二篇中的结论直接贴出来,推导细节不懂可以回去翻一翻。)
一、陀螺仪数据计算欧拉角变化率
{ ϕ 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 \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. ⎩ ⎨ ⎧ϕk˙=pk+SϕkTθkqk+CϕkTθkrkθk˙=Cϕkqk−Sϕkrkψk˙=Sϕkqk/Cθk+Cϕkrk/Cθk
二、先验估计计算
{ ϕ ^ k + 1 − = ϕ ^ k + T ϕ k ˙ θ ^ k + 1 − = θ ^ k + T θ k ˙ ψ ^ k + 1 − = ψ ^ k + T ψ k ˙ \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. ⎩ ⎨ ⎧ϕ^k+1−=ϕ^k+Tϕk˙θ^k+1−=θ^k+Tθk˙ψ^k+1−=ψ^k+Tψk˙
三、先验估计误差协方差矩阵计算
{ p ϕ , k + 1 − = p ϕ , k + q ϕ p θ , k + 1 − = p θ , k + q θ p ψ , k + 1 − = p ψ , k + q ψ \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. ⎩ ⎨ ⎧pϕ,k+1−=pϕ,k+qϕpθ,k+1−=pθ,k+qθpψ,k+1−=pψ,k+qψ
四、卡尔曼增益矩阵计算
{ 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 = p ψ , k + 1 − / ( p ψ , k + 1 − + r ψ ) \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}=p_{\psi,k+1}^{-}/(p_{\psi,k+1}^{-}+r_{\psi})\\ \end{aligned} \right. ⎩ ⎨ ⎧k1,k+1=pϕ,k+1−/(pϕ,k+1−+rϕ)k2,k+1=pθ,k+1−/(pθ,k+1−+rθ)k3,k+1=pψ,k+1−/(pψ,k+1−+rψ)
五、后验估计计算(测量状态向量参考公式16)
{ ϕ ^ 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 = ( 1 − k 3 , k + 1 ) ψ ^ k + 1 − + k 3 , k + 1 ψ m , k + 1 \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}}=(1-k_{3,k+1})\boldsymbol{\hat{\psi}_{k+1}^{-}}+k_{3,k+1}\psi_{m,k+1}\\ \end{aligned} \right. ⎩ ⎨ ⎧ϕ^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=(1−k3,k+1)ψ^k+1−+k3,k+1ψm,k+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 = ( 1 − k 3 , k + 1 ) p ψ , k + 1 − \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} = (1-k_{3,k+1})p_{\psi,k+1}^{-}\\ \end{aligned} \right. ⎩ ⎨ ⎧pϕ,k+1=(1−k1,k+1)pϕ,k+1−pθ,k+1=(1−k2,k+1)pθ,k+1−pψ,k+1=(1−k3,k+1)pψ,k+1−
将上述步骤通过C语言实现
- 函数接口说明
函数输入参数:
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:加速度计数据,单位不管;
m x , m y , m z mx,my,mz mx,my,mz:磁力计数据,单位不管;
注意:要将三组传感器的坐标系对应上,统一方向。
#include <math.h>
#include <float.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
//float mx_max = FLT_MIN,mx_min = FLT_MAX;
float mx_max = 30.0f,mx_min = -24.9f;
//Maximum and minimum values of magnetometer X-axis
//float my_max = FLT_MIN,my_min = FLT_MAX;
float my_max = 25.2f,my_min = -30.15f;
//Maximum and minimum values of magnetometer Y-axis
//float mz_max = FLT_MIN,mz_min = FLT_MAX;
float mz_max = 33.3f,mz_min = -23.25f;
//Maximum and minimum values of magnetometer Z-axis
//attitude solution by kalman filter
void kalman_filter_attitude_solution_calibyaw(float gx,float gy,float gz,float ax,float ay,float az,float mx,float my,float mz)
{
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];
if( Xk_[2] > 3.141f ) //if it is greater than PI
{
Xk_[2] -= - 3.141f * 2.f;
}
else if( Xk_[2] < -3.141f ) //if it is less than -PI
{
Xk_[2] += 3.141f * 2.f;
}
//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] = Pk_[2] / (Pk_[2] + R[2]);
//step4 - kalman gain
float mbx,mby,mbz;
float mZx,mZy,mZz;
mbx = (mx - (mx_max + mx_min)/2.f) / ((mx_max - mx_min)/2.f);
mby = (my - (my_max + my_min)/2.f) / ((my_max - my_min)/2.f);
mbz = (mz - (mz_max + mz_min)/2.f) / ((mz_max - mz_min)/2.f);
mZx = cos(Xk[1]) * mbx + sin(Xk[1]) * sin(Xk[0]) * mby + sin(Xk[1]) * cos(Xk[0]) * mbz;
mZy = cos(Xk[0]) * mby - sin(Xk[0]) * mbz;
mZz = -sin(Xk[1]) * mbx + cos(Xk[1]) * sin(Xk[0]) * mby + cos(Xk[1]) * cos(Xk[0]) * mbz;
//step5 - calculation yaw by magnetometer data
Zk[0] = atan( ay / az );
Zk[1] = -atan( ax / (sqrt( ay * ay + az * az )));
Zk[2] = atan2( mZy , mZx );
//step6 - 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] = (1 - K[2]) * Xk_[2] + K[2] * Zk[2];
//step6 - Posterior estimation
Pk[0] = (1 - K[0]) * Pk_[0];
Pk[1] = (1 - K[1]) * Pk_[1];
Pk[2] = (1 - K[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
}
总结
基于卡尔曼滤波器的姿态解算加入磁力计能够通过地球磁场方向标定航向角,与无磁力计的解算相比,有以下区别:
- 无磁力计在每次上电时都会以当前位置为0°航向角,即无论以哪个方向上电,解算的航向角
yaw
均为0,即一个相对的航向信息。 - 带磁力计的姿态解算,则会在上电后得到一个固定的角度值,即一个绝对的航向信息。
博客中的基于卡尔曼滤波器姿态解算实现代码,更多是为了展示推导信息,因此没有更好的优化的代码实现,读者可以根据实际使用场景来进行优化。
相比于其他的惯性导航姿态解算算法如Mahony姿态解算,基于卡尔曼滤波器计算较为复杂,占用的算力资源较大,使用效率低。`