移动机器人与无人机领域,姿态估计是一项基础的技术,其目标是确定机器人在三维空间中的朝向与姿态,通常表示为滚转角(Roll)、俯仰角(Pitch)和偏航角(Yaw)。
IMU传感器特性
姿态估计通常依赖于惯性测量单元 (IMU),主要包含以下两种传感器。
加速度计(Accelerometer) :重力和运动加速度。
优点 :长期来看没有累积误差,低频特性好,可以提供绝对基准(Roll 和 Pitch)。
缺点 :对高频振动和运动加速度非常敏感,短期内噪声很大。
陀螺仪(Gyroscope) :测量机体绕各轴的角速度。
优点 :动态响应快,高频特性好,短期测量非常精确,不受外界振动影响。
缺点 :存在固有的零偏(Bias),对角速度进行积分时,零偏会随时间不断累积,导致姿态计算发生 “漂移”。
互补滤波的核心思想
利用陀螺仪的积分来获取短期的高频姿态变化(快速响应)。
利用加速度计测量的重力方向来校正陀螺仪的低频漂移(消除累积误差)。
Mahony 算法
Mahony 互补滤波算法是由 Robert Mahony 等人提出的一种基于特殊正交群 SO(3) 及其李代数的非线性互补滤波器。它使用四元数来表示姿态,并利用 PI(比例-积分)控制器来融合传感器数据。
对比 EKF(扩展卡尔曼滤波) :Mahony 算法计算量极小,非常适合在计算资源受限的嵌入式系统上运行,对于一般的机器人姿态估计已足够精确
对比 EKF(扩展卡尔曼滤波) :Mahony 算法参数更直观。———— Madgwick 基于梯度下降法进行优化。
数学基础
坐标系约定
要描述姿态,我们需要定义两个坐标系,并描述它们之间的旋转关系:
机体坐标系(Body Frame, b b b 系) :固联在机器人上的坐标系。本代码中采用 FLU(前-左-上,Forward-Left-Up) 约定。即 X 轴指向机头前方,Y 轴指 向机身左侧,Z 轴指向上方。
导航坐标系(Navigation Frame, n n n 系) :固定在地球上的参考系。与 FLU 机体系对应的导航系通常是 ENU(东-北-天,East-North-Up) 。在这个约定下,重力向量方向是沿着 Z 轴负方向,但在很多飞控习惯中,为方便计算,重力向量常被表示为 g n = [ 0 , 0 , 1 ] T g_n = [0, 0, 1]^T g n = [ 0 , 0 , 1 ] T (归一化),具体取决于代码的投影假设。
姿态估计的目的就是求出从 导航系到机体系 (或反过来)的旋转转换关系。
旋转矩阵
方向余弦矩阵(Direction Cosine Matrix, DCM) 是一种 3 × 3 3 \times 3 3 × 3 的正交矩阵 R R R ,满足 R T R = I R^T R = I R T R = I 且 det ( R ) = 1 \det(R) = 1 det ( R ) = 1 。
它可以将一个向量从导航系 n n n 旋转到机体系 b b b :
v b = R n b ⋅ v n v_b = R_n^b \cdot v_n v b = R n b ⋅ v n
绕各个基本坐标轴的旋转矩阵如下(遵循右手螺旋定则):
绕 X 轴旋转 ϕ \phi ϕ (Roll):
R x ( ϕ ) = [ 1 0 0 0 cos ϕ sin ϕ 0 − sin ϕ cos ϕ ] R_x(\phi) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\phi & \sin\phi \\ 0 & -\sin\phi & \cos\phi \end{bmatrix} R x ( ϕ ) = 1 0 0 0 cos ϕ − sin ϕ 0 sin ϕ cos ϕ
绕 Y 轴旋转 θ \theta θ (Pitch):
R y ( θ ) = [ cos θ 0 − sin θ 0 1 0 sin θ 0 cos θ ] R_y(\theta) = \begin{bmatrix} \cos\theta & 0 & -\sin\theta \\ 0 & 1 & 0 \\ \sin\theta & 0 & \cos\theta \end{bmatrix} R y ( θ ) = cos θ 0 sin θ 0 1 0 − sin θ 0 cos θ
绕 Z 轴旋转 ψ \psi ψ (Yaw):
R z ( ψ ) = [ cos ψ sin ψ 0 − sin ψ cos ψ 0 0 0 1 ] R_z(\psi) = \begin{bmatrix} \cos\psi & \sin\psi & 0 \\ -\sin\psi & \cos\psi & 0 \\ 0 & 0 & 1 \end{bmatrix} R z ( ψ ) = cos ψ − sin ψ 0 sin ψ cos ψ 0 0 0 1
复合旋转 通常按照特定的顺序进行,如 ZYX 顺序 ,则总的旋转矩阵为:
R = R x ( ϕ ) R y ( θ ) R z ( ψ ) R = R_x(\phi) R_y(\theta) R_z(\psi) R = R x ( ϕ ) R y ( θ ) R z ( ψ )
欧拉角
欧拉角是最直观的姿态表示方法,由三次绕不同轴的旋转角度组成:
Roll (ϕ \phi ϕ ) :翻滚角,绕 X 轴的旋转。
Pitch (θ \theta θ ) :俯仰角,绕 Y 轴的旋转。
Yaw (ψ \psi ψ ) :偏航角,绕 Z 轴的旋转。
万向锁问题(Gimbal Lock) :
当 θ = ± 90 ∘ \theta = \pm 90^\circ θ = ± 9 0 ∘ 时(即机头垂直朝上或朝下),第一次绕 Z 轴的旋转和第三次绕 X 轴的旋转实际上是在同一个物理平面上进行的。 此时系统丢失了一个自由度,无法区分 Roll 和 Yaw,导致数学上的奇点。我们需要引入四元数来进行姿态解算,避免在极端姿态下算法崩溃。
四元数
四元数(Quaternion)是复数的扩展,形式为:
q = q 0 + q 1 i + q 2 j + q 3 k q = q_0 + q_1 i + q_2 j + q_3 k q = q 0 + q 1 i + q 2 j + q 3 k
其中 q 0 q_0 q 0 是标量部分, ( q 1 , q 2 , q 3 ) (q_1, q_2, q_3) ( q 1 , q 2 , q 3 ) 是向量部分。
满足基本虚数单位规则:
i 2 = j 2 = k 2 = i j k = − 1 i^2 = j^2 = k^2 = ijk = -1 i 2 = j 2 = k 2 = ijk = − 1
四元数也可以写成向量形式: q = [ q 0 , q 1 , q 2 , q 3 ] T q = [q_0, q_1, q_2, q_3]^T q = [ q 0 , q 1 , q 2 , q 3 ] T 。
基本运算
加法 :按分量相加。
乘法(Hamilton积) :设 p = [ p 0 , p ] , q = [ q 0 , q ] p = [p_0, \mathbf{p}], q = [q_0, \mathbf{q}] p = [ p 0 , p ] , q = [ q 0 , q ] ,则
p ⊗ q = [ p 0 q 0 − p ⋅ q , p 0 q + q 0 p + p × q ] p \otimes q = [p_0 q_0 - \mathbf{p} \cdot \mathbf{q}, \quad p_0 \mathbf{q} + q_0 \mathbf{p} + \mathbf{p} \times \mathbf{q}] p ⊗ q = [ p 0 q 0 − p ⋅ q , p 0 q + q 0 p + p × q ]
展开后是一个复杂的矩阵乘积过程。注意四元数乘法 不满足交换律 。
共轭(Conjugate) : q ∗ = q 0 − q 1 i − q 2 j − q 3 k q^* = q_0 - q_1 i - q_2 j - q_3 k q ∗ = q 0 − q 1 i − q 2 j − q 3 k
模(Norm) : ∣ q ∣ = q 0 2 + q 1 2 + q 2 2 + q 3 2 |q| = \sqrt{q_0^2 + q_1^2 + q_2^2 + q_3^2} ∣ q ∣ = q 0 2 + q 1 2 + q 2 2 + q 3 2
逆(Inverse) : q − 1 = q ∗ ∣ q ∣ 2 q^{-1} = \frac{q^*}{|q|^2} q − 1 = ∣ q ∣ 2 q ∗
单位四元数约束 :表示旋转的四元数必须满足 ∣ q ∣ = 1 |q| = 1 ∣ q ∣ = 1 。此时 q − 1 = q ∗ q^{-1} = q^* q − 1 = q ∗ 。
四元数表示旋转
任何一个绕单位轴 u = [ u x , u y , u z ] \mathbf{u} = [u_x, u_y, u_z] u = [ u x , u y , u z ] 旋转角度 θ \theta θ 的操作,可以用一个单位四元数表示:
q = cos ( θ 2 ) + sin ( θ 2 ) ( u x i + u y j + u z k ) q = \cos(\frac{\theta}{2}) + \sin(\frac{\theta}{2}) (u_x i + u_y j + u_z k) q = cos ( 2 θ ) + sin ( 2 θ ) ( u x i + u y j + u z k )
将一个纯向量 v = [ 0 , v x , v y , v z ] \mathbf{v} = [0, v_x, v_y, v_z] v = [ 0 , v x , v y , v z ] 进行旋转,操作为:
v ′ = q ⊗ v ⊗ q ∗ \mathbf{v}' = q \otimes \mathbf{v} \otimes q^* v ′ = q ⊗ v ⊗ q ∗
四元数 → \rightarrow → DCM 转换
通过上述旋转公式,可以推导出四元数对应的 3 × 3 3 \times 3 3 × 3 旋转矩阵(从导航系到机体系):
R ( q ) = [ q 0 2 + q 1 2 − q 2 2 − q 3 2 2 ( q 1 q 2 + q 0 q 3 ) 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 1 q 2 − q 0 q 3 ) q 0 2 − q 1 2 + q 2 2 − q 3 2 2 ( q 2 q 3 + q 0 q 1 ) 2 ( q 1 q 3 + q 0 q 2 ) 2 ( q 2 q 3 − q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2 ] R(q) = \begin{bmatrix}
q_0^2+q_1^2-q_2^2-q_3^2 & 2(q_1q_2 + q_0q_3) & 2(q_1q_3 - q_0q_2) \\
2(q_1q_2 - q_0q_3) & q_0^2-q_1^2+q_2^2-q_3^2 & 2(q_2q_3 + q_0q_1) \\
2(q_1q_3 + q_0q_2) & 2(q_2q_3 - q_0q_1) & q_0^2-q_1^2-q_2^2+q_3^2
\end{bmatrix} R ( q ) = q 0 2 + q 1 2 − q 2 2 − q 3 2 2 ( q 1 q 2 − q 0 q 3 ) 2 ( q 1 q 3 + q 0 q 2 ) 2 ( q 1 q 2 + q 0 q 3 ) q 0 2 − q 1 2 + q 2 2 − q 3 2 2 ( q 2 q 3 − q 0 q 1 ) 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 2 q 3 + q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2
注意,由于 ∣ q ∣ = 1 |q| = 1 ∣ q ∣ = 1 ,对角线元素可以化简。特别是矩阵的 第三列 :
R c o l 3 = [ 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 2 q 3 + q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2 ] R_{col3} = \begin{bmatrix} 2(q_1q_3 - q_0q_2) \\ 2(q_2q_3 + q_0q_1) \\ q_0^2-q_1^2-q_2^2+q_3^2 \end{bmatrix} R co l 3 = 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 2 q 3 + q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2
这正是导航系中的重力向量 g n = [ 0 , 0 , 1 ] T g_n = [0, 0, 1]^T g n = [ 0 , 0 , 1 ] T 旋转到机体系后的投影!这点在后面的重力估计中极其重要。
四元数 → \rightarrow → 欧拉角转换
将上述 R ( q ) R(q) R ( q ) 与由 ZYX 欧拉角构造的 DCM 相对应,可求解出欧拉角:
ϕ = atan2 ( 2 ( q 0 q 1 + q 2 q 3 ) , 1 − 2 ( q 1 2 + q 2 2 ) ) \phi = \text{atan2}(2(q_0q_1 + q_2q_3), 1 - 2(q_1^2 + q_2^2)) ϕ = atan2 ( 2 ( q 0 q 1 + q 2 q 3 ) , 1 − 2 ( q 1 2 + q 2 2 ))
θ = arcsin ( 2 ( q 0 q 2 − q 3 q 1 ) ) \theta = \arcsin(2(q_0q_2 - q_3q_1)) θ = arcsin ( 2 ( q 0 q 2 − q 3 q 1 ))
ψ = atan2 ( 2 ( q 0 q 3 + q 1 q 2 ) , 1 − 2 ( q 2 2 + q 3 2 ) ) \psi = \text{atan2}(2(q_0q_3 + q_1q_2), 1 - 2(q_2^2 + q_3^2)) ψ = atan2 ( 2 ( q 0 q 3 + q 1 q 2 ) , 1 − 2 ( q 2 2 + q 3 2 ))
四元数微分方程
我们要利用陀螺仪测量的角速度 ω = [ ω x , ω y , ω z ] \boldsymbol{\omega} = [\omega_x, \omega_y, \omega_z] ω = [ ω x , ω y , ω z ] 来更新姿态。
构造纯四元数 ω q = 0 + ω x i + ω y j + ω z k \omega_q = 0 + \omega_x i + \omega_y j + \omega_z k ω q = 0 + ω x i + ω y j + ω z k 。
根据刚体运动学,单位四元数对时间的导数为:
q ˙ = 1 2 q ⊗ ω q \dot{q} = \frac{1}{2} q \otimes \omega_q q ˙ = 2 1 q ⊗ ω q
展开 Hamilton 积,得到微分方程的矩阵形式:
[ q 0 ˙ q 1 ˙ q 2 ˙ q 3 ˙ ] = 1 2 [ 0 − ω x − ω y − ω z ω x 0 ω z − ω y ω y − ω z 0 ω x ω z ω y − ω x 0 ] [ q 0 q 1 q 2 q 3 ] \begin{bmatrix} \dot{q_0} \\ \dot{q_1} \\ \dot{q_2} \\ \dot{q_3} \end{bmatrix} = \frac{1}{2} \begin{bmatrix} 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{bmatrix} \begin{bmatrix} q_0 \\ q_1 \\ q_2 \\ q_3 \end{bmatrix} q 0 ˙ q 1 ˙ q 2 ˙ q 3 ˙ = 2 1 0 ω x ω y ω z − ω x 0 − ω z ω y − ω y ω z 0 − ω x − ω z − ω y ω x 0 q 0 q 1 q 2 q 3
分量形式即为代码中使用的更新公式的基础:
q 0 ˙ = 1 2 ( − q 1 ω x − q 2 ω y − q 3 ω z ) \dot{q_0} = \frac{1}{2}(-q_1\omega_x - q_2\omega_y - q_3\omega_z) q 0 ˙ = 2 1 ( − q 1 ω x − q 2 ω y − q 3 ω z )
q 1 ˙ = 1 2 ( q 0 ω x + q 2 ω z − q 3 ω y ) \dot{q_1} = \frac{1}{2}( q_0\omega_x + q_2\omega_z - q_3\omega_y) q 1 ˙ = 2 1 ( q 0 ω x + q 2 ω z − q 3 ω y )
q 2 ˙ = 1 2 ( q 0 ω y − q 1 ω z + q 3 ω x ) \dot{q_2} = \frac{1}{2}( q_0\omega_y - q_1\omega_z + q_3\omega_x) q 2 ˙ = 2 1 ( q 0 ω y − q 1 ω z + q 3 ω x )
q 3 ˙ = 1 2 ( q 0 ω z + q 1 ω y − q 2 ω x ) \dot{q_3} = \frac{1}{2}( q_0\omega_z + q_1\omega_y - q_2\omega_x) q 3 ˙ = 2 1 ( q 0 ω z + q 1 ω y − q 2 ω x )
Mahony 互补滤波原理
问题建模
目标 :从 IMU 的加速度和角速度数据,估计当前的单位四元数 q q q 。
测量数据 :
加速度计: a m e a s = [ a x , a y , a z ] \mathbf{a}_{meas} = [a_x, a_y, a_z] a m e a s = [ a x , a y , a z ] (归一化后)。它近似代表了机体系下的“反重力”方向。
陀螺仪: ω g y r o = [ ω x , ω y , ω z ] \boldsymbol{\omega}_{gyro} = [\omega_x, \omega_y, \omega_z] ω g yro = [ ω x , ω y , ω z ] 。
重力方向估计
我们利用 上一时刻的姿态估计值 q q q ,将导航系下的重力向量 g n = [ 0 , 0 , 1 ] T g_n = [0, 0, 1]^T g n = [ 0 , 0 , 1 ] T 旋转到当前的机体系下,得到估计的重力向量 v h a t \mathbf{v}_{hat} v ha t 。
根据 2.4.4 节中的矩阵推导, v h a t \mathbf{v}_{hat} v ha t 等于 DCM 的第三列:
v h a t = [ 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 2 q 3 + q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2 ] \mathbf{v}_{hat} = \begin{bmatrix} 2(q_1q_3 - q_0q_2) \\ 2(q_2q_3 + q_0q_1) \\ q_0^2-q_1^2-q_2^2+q_3^2 \end{bmatrix} v ha t = 2 ( q 1 q 3 − q 0 q 2 ) 2 ( q 2 q 3 + q 0 q 1 ) q 0 2 − q 1 2 − q 2 2 + q 3 2
为了节省乘法运算,Mahony 将上式整体提取了因子 2,方便与设定的增益 towKp,towKi 合并吸收
halfvx = q1_ * q3_ - q0_ * q2_ ;
halfvy = q0_ * q1_ + q2_ * q3_ ;
halfvz = q0_ * q0_ - 0.5f + q3_ * q3_ ;
这里 halfvz 是这么推导的
1 2 ( q 0 2 + q 3 2 − ( q 1 2 + q 2 2 ) ) = ( q 0 2 + q 3 2 ) − 1 2 ( q 0 2 + q 1 2 + q 2 2 + q 3 2 ) = q 0 2 + q 3 2 − 0.5 \begin{aligned}
\frac{1}{2}\bigl(q_0^2+q_3^2 - (q_1^2+q_2^2)\bigr)
&= (q_0^2+q_3^2) - \frac{1}{2}\bigl(q_0^2+q_1^2+q_2^2+q_3^2\bigr) \\
&= q_0^2+q_3^2-0.5
\end{aligned} 2 1 ( q 0 2 + q 3 2 − ( q 1 2 + q 2 2 ) ) = ( q 0 2 + q 3 2 ) − 2 1 ( q 0 2 + q 1 2 + q 2 2 + q 3 2 ) = q 0 2 + q 3 2 − 0.5
误差度量:叉积
现在我们在机体系下有了两个方向向量:
测量重力 :归一化后的 a m e a s = [ a x , a y , a z ] \mathbf{a}_{meas} = [a_x, a_y, a_z] a m e a s = [ a x , a y , a z ]