本文介绍一篇 关于IMU
标定的经典论文,论文收录于 ICRA14,在论文中作者介绍了如何不适用外部设备标定 IMU 加速度和角速度偏差、尺度系数、轴偏移参数
。
论文链接:https://readpaper.com/paper/2021503353、https://readpaper.com/paper/2211578699
项目链接:https://github.com/JzHuai0108/imu_tk_matlab
1. Sensor Error Model
首先介绍传感器误差模型
,令
a
O
\mathbf{a}^{O}
aO 表示为理想情况
下的加速度数据,
a
S
\mathbf{a}^{S}
aS 表示为实际
的加速度数据,
T
a
=
[
1
−
α
y
z
α
z
y
0
1
−
α
z
x
0
0
1
]
\mathbf{T}^{a}=\left[\begin{array}{ccc}1 & -\alpha_{y z} & \alpha_{z y} \\ 0 & 1 & -\alpha_{z x} \\ 0 & 0 & 1\end{array}\right]
Ta=⎣⎡100−αyz10αzy−αzx1⎦⎤ 表示从
a
S
\mathbf{a}^{S}
aS 到
a
O
\mathbf{a}^{O}
aO 的旋转变换。
b
a
=
[
b
x
a
b
y
a
b
z
a
]
\mathbf{b}^{a}=\left[\begin{array}{l}b_{x}^{a} \\ b_{y}^{a} \\ b_{z}^{a}\end{array}\right]
ba=⎣⎡bxabyabza⎦⎤ 为加速度偏差,
K
a
=
[
s
x
a
0
0
0
s
y
a
0
0
0
s
z
a
]
\mathbf{K}^{a}=\left[\begin{array}{ccc}s_{x}^{a} & 0 & 0 \\ 0 & s_{y}^{a} & 0 \\ 0 & 0 & s_{z}^{a}\end{array}\right]
Ka=⎣⎡sxa000sya000sza⎦⎤ 为加速度尺度系数,
ν
a
\boldsymbol{\nu}^{a}
νa 为加速度测量噪声,则可以得到加速度误差模型
:
a
O
=
T
a
K
a
(
a
S
+
b
a
+
ν
a
)
\mathbf{a}^{O}=\mathbf{T}^{a} \mathbf{K}^{a}\left(\mathbf{a}^{S}+\mathbf{b}^{a}+\boldsymbol{\nu}^{a}\right)
aO=TaKa(aS+ba+νa)
同样也可以得到角速度误差模型
,令
T
g
=
[
1
−
γ
y
z
γ
z
y
γ
x
z
1
−
γ
z
x
−
γ
x
y
γ
y
x
1
]
\mathbf{T}^{g}=\left[\begin{array}{ccc}1 & -\gamma_{y z} & \gamma_{z y} \\ \gamma_{x z} & 1 & -\gamma_{z x} \\ -\gamma_{x y} & \gamma_{y x} & 1\end{array}\right]
Tg=⎣⎡1γxz−γxy−γyz1γyxγzy−γzx1⎦⎤,
K
g
=
[
s
x
g
0
0
0
s
y
g
0
0
0
s
z
g
]
\mathbf{K}^{g}=\left[\begin{array}{ccc}s_{x}^{g} & 0 & 0 \\ 0 & s_{y}^{g} & 0 \\ 0 & 0 & s_{z}^{g}\end{array}\right]
Kg=⎣⎡sxg000syg000szg⎦⎤,
b
g
=
[
b
x
g
b
y
g
b
z
g
]
\mathbf{b}^{g}=\left[\begin{array}{l}b_{x}^{g} \\ b_{y}^{g} \\ b_{z}^{g}\end{array}\right]
bg=⎣⎡bxgbygbzg⎦⎤,
ν
g
\boldsymbol{\nu}^{g}
νg 为角速度测量噪声,则角速度误差模型
为:
ω O = T g K g ( ω S + b g + ν g ) \boldsymbol{\omega}^{O}=\mathbf{T}^{g} \mathbf{K}^{g}\left(\boldsymbol{\omega}^{S}+\mathbf{b}^{g}+\boldsymbol{\nu}^{g}\right) ωO=TgKg(ωS+bg+νg)
2. Basic Calibration Framework
加速度标定我们需要估计的未知参数为:
θ
a
c
c
=
[
α
y
z
,
α
z
y
,
α
z
x
,
s
x
a
,
s
y
a
,
s
z
a
,
b
x
a
,
b
y
a
,
b
z
a
]
\theta^{a c c}=\left[\alpha_{y z}, \alpha_{z y}, \alpha_{z x}, s_{x}^{a}, s_{y}^{a}, s_{z}^{a}, b_{x}^{a}, b_{y}^{a}, b_{z}^{a}\right]
θacc=[αyz,αzy,αzx,sxa,sya,sza,bxa,bya,bza]
此时我们可以忽略测量噪声,则加速度误差模型简化为:
a
O
=
T
a
K
a
(
a
S
+
b
a
)
\mathbf{a}^{O}=\mathbf{T}^{a} \mathbf{K}^{a}\left(\mathbf{a}^{S}+\mathbf{b}^{a}\right)
aO=TaKa(aS+ba)
正如在传统的多位置策略中,我们将 IMU
置于
M
M
M 个不同的位置,在每一个静止周期内读取加速度测量值
a
k
S
\mathbf{a}^{S}_{k}
akS,我们可以使用以下损失函数来估计加速度误差模型参数:
L
(
θ
a
c
c
)
=
∑
k
=
1
M
(
∥
g
∥
2
−
∥
h
(
a
k
S
,
θ
a
c
c
)
∥
2
)
2
\mathbf{L}\left(\boldsymbol{\theta}^{a c c}\right)=\sum_{k=1}^{M}\left(\|\mathbf{g}\|^{2}-\left\|h\left(\mathbf{a}_{k}^{S}, \boldsymbol{\theta}^{a c c}\right)\right\|^{2}\right)^{2}
L(θacc)=k=1∑M(∥g∥2−∥∥h(akS,θacc)∥∥2)2
其中,
∣
∣
g
∥
||\mathbf{g}\|
∣∣g∥ 是当地重力加速度幅值
。损失函数程序为:
function [res_vector] = accCostFunctLSQNONLIN(E, a_hat, magnitude)
misalignmentMatrix = [1, -E(1), E(2); 0, 1, -E(3); 0, 0, 1];
scalingMtrix = diag([E(4), E(5), E(6)]);
a_bar = misalignmentMatrix*scalingMtrix*(a_hat + (diag([E(7), E(8), E(9)])*ones(3, size(a_hat,2))));
% Magnitude taken from tables
if(nargin<3)
magnitude = 9.81744;
end
residuals = zeros(length(a_bar(1,:)), 1);
for i = 1:length(a_bar(1,:))
residuals(i,1) = (magnitude^2 - (a_bar(1,i)^2 + a_bar(2,i)^2 + a_bar(3,i)^2))^2;
end
res_vector = residuals;
end
我们使用同样的静止周期来标定陀螺仪。在这里我们通过对初始静止时刻角速度值求平均来得到角速度偏差
。这样我们需要求解的参数简化为:
θ
g
y
r
o
=
[
γ
y
z
,
γ
z
y
,
γ
x
z
,
γ
z
x
,
γ
x
y
,
γ
y
x
,
s
x
g
,
s
y
g
,
s
z
g
]
\boldsymbol{\theta}^{g y r o}=\left[\gamma_{y z}, \gamma_{z y}, \gamma_{x z}, \gamma_{z x}, \gamma_{x y}, \gamma_{y x}, s_{x}^{g}, s_{y}^{g}, s_{z}^{g}\right]
θgyro=[γyz,γzy,γxz,γzx,γxy,γyx,sxg,syg,szg]
我们使用标定后的加速度数据作为参考,给定一个初始的重力向量,对角速度数据进行积分,我们可以估计最终的重力向量
,则损失函数可以写为:
L
(
θ
g
y
r
o
)
=
∑
k
=
2
M
∥
u
a
,
k
−
u
g
,
k
∥
2
\mathbf{L}\left(\boldsymbol{\theta}^{g y r o}\right)=\sum_{k=2}^{M}\left\|\mathbf{u}_{a, k}-\mathbf{u}_{g, k}\right\|^{2}
L(θgyro)=k=2∑M∥ua,k−ug,k∥2
其中,
u
a
,
k
\mathbf{u}_{a, k}
ua,k 是标定后的加速度向量,
u
g
,
k
\mathbf{u}_{g, k}
ug,k 是估计后的重力向量。角速度积分这里使用的是 RK4
,不过目前 IMU
的采样频率都很高了,一般很少再使用了。
3. Calibration Procedure
A. Static Detector
IMU
标定的准确性非常依赖于静止和运动时间间隔的准确区分,为了标定加速度计我们使用静止周期
,标定陀螺仪我们使用两个静态周期之间的动态时间间隔。我们这里使用基于方差的静止检测器
,对于时间周期长度
t
w
a
i
t
t_{wait}
twait 秒,我们有加速度
(
a
x
t
,
a
y
t
,
a
z
t
)
\left(\mathbf{a}_{x}^{t}, \mathbf{a}_{y}^{t}, \mathbf{a}_{z}^{t}\right)
(axt,ayt,azt),然后我们计算标准差:
ς
(
t
)
=
[
var
t
w
(
a
x
t
)
]
2
+
[
var
t
w
(
a
y
t
)
]
2
+
[
var
t
w
(
a
z
t
)
]
2
\varsigma(t)=\sqrt{\left[\operatorname{var}_{t_{w}}\left(\mathbf{a}_{x}^{t}\right)\right]^{2}+\left[\operatorname{var}_{t_{w}}\left(\mathbf{a}_{y}^{t}\right)\right]^{2}+\left[\operatorname{var}_{t_{w}}\left(\mathbf{a}_{z}^{t}\right)\right]^{2}}
ς(t)=[vartw(axt)]2+[vartw(ayt)]2+[vartw(azt)]2
我们通过比较方标准差 ς ( t ) \varsigma(t) ς(t) 是否大于某一阈值来区分静止和运动状态。我们将初始方差 ς i n i t \varsigma_{init} ςinit 扩大整数倍来作为阈值。下图是静止检测器的检测结果,这里整数倍为6倍。
B. Runge-Kutta Integration
下面简单介绍下四阶龙格库塔法,这里主要用在陀螺仪的标定。四元数微分方程为:
f
(
q
,
t
)
=
q
˙
=
1
2
Ω
(
ω
(
t
)
)
q
\mathbf{f}(\mathbf{q}, t)=\dot{\mathbf{q}}=\frac{1}{2} \boldsymbol{\Omega}(\boldsymbol{\omega}(t)) \mathbf{q}
f(q,t)=q˙=21Ω(ω(t))q
其中,
Ω
(
ω
)
\Omega(\boldsymbol{\omega})
Ω(ω) 是一个反对称矩阵,形式为:
Ω
(
ω
)
=
[
0
−
ω
x
−
ω
y
−
ω
z
ω
x
0
ω
z
−
ω
y
ω
y
−
ω
z
0
ω
x
ω
z
ω
y
−
ω
x
0
]
\boldsymbol{\Omega}(\boldsymbol{\omega})=\left[\begin{array}{cccc} 0 & -\omega_{x} & -\omega_{y} & -\omega_{z} \\ \omega_{x} & 0 & \omega_{z} & -\omega_{y} \\ \omega_{y} & -\omega_{z} & 0 & \omega_{x} \\ \omega_{z} & \omega_{y} & -\omega_{x} & 0 \end{array}\right]
Ω(ω)=⎣⎢⎢⎡0ωxωyωz−ωx0−ωzωy−ωyωz0−ωx−ωz−ωyωx0⎦⎥⎥⎤
四阶龙格库塔法原理为:
q
k
+
1
=
q
k
+
Δ
t
1
6
(
k
1
+
2
k
2
+
2
k
3
+
k
4
)
k
i
=
f
(
q
(
i
)
,
t
k
+
c
i
Δ
t
)
,
for
i
=
1
q
(
i
)
=
q
k
,
for
i
>
1
q
(
i
)
=
q
k
+
Δ
t
∑
j
=
1
i
−
1
a
i
j
k
j
,
\begin{array}{ll} \mathbf{q}_{k+1}=\mathbf{q}_{k}+\Delta t \frac{1}{6}\left(\mathbf{k}_{1}+2 \mathbf{k}_{2}+2 \mathbf{k}_{3}+\mathbf{k}_{4}\right) \\ \mathbf{k}_{i}=\mathbf{f}\left(\mathbf{q}^{(i)}, t_{k}+c_{i} \Delta t\right), & \text { for } i=1 \\ \mathbf{q}^{(i)}=\mathbf{q}_{k}, & \text { for } i>1 \\ \mathbf{q}^{(i)}=\mathbf{q}_{k}+\Delta t \sum_{j=1}^{i-1} a_{i j} \mathbf{k}_{j}, & \end{array}
qk+1=qk+Δt61(k1+2k2+2k3+k4)ki=f(q(i),tk+ciΔt),q(i)=qk,q(i)=qk+Δt∑j=1i−1aijkj, for i=1 for i>1
各个参数为:
c
1
=
0
,
c
2
=
1
2
,
c
3
=
1
2
,
c
4
=
1
a
21
=
1
2
,
a
31
=
0
,
a
41
=
0
a
32
=
1
2
,
a
42
=
0
,
a
43
=
1
\begin{gathered} c_{1}=0, \quad c_{2}=\frac{1}{2}, \quad c_{3}=\frac{1}{2}, \quad c_{4}=1 \\ a_{21}=\frac{1}{2}, \quad a_{31}=0, \quad a_{41}=0 \\ a_{32}=\frac{1}{2}, \quad a_{42}=0, \quad a_{43}=1 \end{gathered}
c1=0,c2=21,c3=21,c4=1a21=21,a31=0,a41=0a32=21,a42=0,a43=1
最终得到积分后的四元数,还需要再转化为单位四元数,整个RK4
程序为:
function [R] = rotationRK4(omega, dt)
omega_x = omega(1,:);
omega_y = omega(2,:);
omega_z = omega(3,:);
num_samples = length(omega_x);
q_k = fromOmegaToQ([omega_x(1); omega_y(1); omega_z(1)], [dt])';
q_next_k = q_k; % was [0; 0; 0; 0]; changed by Huai
for i = 1:num_samples - 1
% first Runge-Kutta coefficient
q_i_1 = q_k;
OMEGA_omega_t_k = ...
[0 -omega_x(i) -omega_y(i) -omega_z(i);
omega_x(i) 0 omega_z(i) -omega_y(i);
omega_y(i) -omega_z(i) 0 omega_x(i);
omega_z(i) omega_y(i) -omega_x(i) 0 ];
k_1 = (1/2)*OMEGA_omega_t_k*q_i_1;
% second Runge-Kutta coefficient
q_i_2 = q_k + dt*(1/2)*k_1;
OMEGA_omega_t_k_plus_half_dt = ...
[0 -(omega_x(i) + omega_x(i + 1))/2 -(omega_y(i) + omega_y(i + 1))/2 -(omega_z(i) + omega_z(i + 1))/2;
(omega_x(i) + omega_x(i + 1))/2 0 (omega_z(i) + omega_z(i + 1))/2 -(omega_y(i) + omega_y(i + 1))/2;
(omega_y(i) + omega_y(i + 1))/2 -(omega_z(i) + omega_z(i + 1))/2 0 (omega_x(i) + omega_x(i + 1))/2;
(omega_z(i) + omega_z(i + 1))/2 (omega_y(i) + omega_y(i + 1))/2 -(omega_x(i) + omega_x(i + 1))/2 0 ];
k_2 = (1/2)*OMEGA_omega_t_k_plus_half_dt*q_i_2;
% third Runge-Kutta coefficient
q_i_3 = q_k + dt*(1/2)*k_2;
OMEGA_omega_t_k_plus_half_dt = ...
[0 -(omega_x(i) + omega_x(i + 1))/2 -(omega_y(i) + omega_y(i + 1))/2 -(omega_z(i) + omega_z(i + 1))/2;
(omega_x(i) + omega_x(i + 1))/2 0 (omega_z(i) + omega_z(i + 1))/2 -(omega_y(i) + omega_y(i + 1))/2;
(omega_y(i) + omega_y(i + 1))/2 -(omega_z(i) + omega_z(i + 1))/2 0 (omega_x(i) + omega_x(i + 1))/2;
(omega_z(i) + omega_z(i + 1))/2 (omega_y(i) + omega_y(i + 1))/2 -(omega_x(i) + omega_x(i + 1))/2 0 ];
k_3 = (1/2)*OMEGA_omega_t_k_plus_half_dt*q_i_3;
% forth Runge-Kutta coefficient
q_i_4 = q_k + dt*1*k_3;
OMEGA_omega_t_k_plus_dt = ...
[0 -omega_x(i + 1) -omega_y(i + 1) -omega_z(i + 1);
omega_x(i + 1) 0 omega_z(i + 1) -omega_y(i + 1);
omega_y(i + 1) -omega_z(i + 1) 0 omega_x(i + 1);
omega_z(i + 1) omega_y(i + 1) -omega_x(i + 1) 0 ];
k_4 = (1/2)*OMEGA_omega_t_k_plus_dt*q_i_4;
q_next_k = q_k + dt*((1/6)*k_1 + (1/3)*k_2 + (1/3)*k_3 + (1/6)*k_4);
q_next_k = q_next_k/norm(q_next_k);
q_k = q_next_k;
end
R = inv(fromQtoR(q_next_k));
end
C. Complete Procedure
为了避免标定参数估计中的不可观察性,至少需要收集IMU
9个不同姿态的数据,姿态数越多,标定结果越准确。整个标定算法如下,需要知道采集好的加速度数据
a
S
\mathbf{a}^{S}
aS 和角速度数据
ω
S
\boldsymbol{\omega}^{S}
ωS,初始静止时间
T
i
n
i
t
T_{init}
Tinit,以及运动后的静止时间
t
w
a
i
t
t_{wait}
twait。
- 首先根据初始时间计算陀螺仪偏差 b g \boldsymbol{b}^g bg;
- 根据计算后的陀螺仪偏差得到无偏角速度数据 ω b i a s f r e e S \boldsymbol{\omega}^{S}_{biasfree} ωbiasfreeS;
- 计算初始协方差 ς i n i t \varsigma_{init} ςinit ;
- 设 i = 1 : k i=1:k i=1:k ,根据等待时间 t w a i t t_{wait} twait 和阈值计算静止间隔、再根据静止间隔 t w a i t t_{wait} twait 和加速度数据得到估计参数;
- 最后选取
残差最小对应的参数为加速度标定参数
,然后再使用同样的静止周期计算陀螺仪标定参数;