4. 旋转表示方法(下):四元数基础、四元数运算、四元数与旋转矩阵的转换、各种表示方法的优缺点对比

好,我们接着聊旋转表示。上一节我们把欧拉角和旋转矩阵讲透了,这一节轮到四元数了。

说实话,我刚入行时看到四元数就头疼。什么 i、j、k 的平方等于 -1,这不是复数吗?怎么跟旋转扯上关系了?后来在项目里被欧拉角万向锁坑过几次,才老老实实把四元数啃下来。嗯,今天我就把这块硬骨头给你拆碎了讲。

4.1 四元数基础

四元数,说白了就是一个超复数。它由一个实部和三个虚部组成:

q = w + xi + yj + zk

其中 i、j、k 满足:

i² = j² = k² = ijk = -1
ij = k, ji = -k
jk = i, kj = -i
ki = j, ik = -j

你想想看,这跟三维空间中的叉积是不是很像?没错,四元数天生就是为三维旋转准备的。

我们通常把四元数写成标量-向量形式:

q = [w, v]  其中 v = (x, y, z)

w 是实部,v 是虚部向量。单位四元数(模长为1)可以用来表示旋转。

核心理解: 单位四元数 q = [cos(θ/2), n·sin(θ/2)] 表示绕单位轴 n 旋转 θ 角度。注意是半角!

为什么会是半角?我记得第一次推导这个公式时也懵了。简单说,因为四元数旋转是通过 q·p·q⁻¹ 这种双乘操作实现的,半角刚好让两次乘法凑出完整角度。

4.2 四元数运算

四元数的运算其实不复杂,就是记住几条规则。我在项目中经常用到的有这些:

4.2.1 加减法

对应分量相加减,跟向量一样:

q₁ ± q₂ = (w₁ ± w₂) + (x₁ ± x₂)i + (y₁ ± y₂)j + (z₁ ± z₂)k

4.2.2 乘法

这个要小心,四元数乘法不满足交换律。我刚开始写代码时经常搞反顺序,结果旋转方向全错了。

q₁ · q₂ = (w₁w₂ - v₁·v₂) + (w₁v₂ + w₂v₁ + v₁×v₂)

写成代码就是:

def quaternion_multiply(q1, q2):
    w1, x1, y1, z1 = q1
    w2, x2, y2, z2 = q2
    w = w1*w2 - x1*x2 - y1*y2 - z1*z2
    x = w1*x2 + x1*w2 + y1*z2 - z1*y2
    y = w1*y2 - x1*z2 + y1*w2 + z1*x2
    z = w1*z2 + x1*y2 - y1*x2 + z1*w2
    return [w, x, y, z]

4.2.3 共轭与模长

共轭:q* = w - xi - yj - zk
模长:||q|| = sqrt(w² + x² + y² + z²)

单位四元数的模长为1,它的逆等于共轭:q⁻¹ = q*

个人习惯: 每次做四元数运算前,我都会先归一化一下。数值误差累积起来,四元数会慢慢偏离单位长度,导致旋转变形。这个坑我踩过,后来养成了习惯。

4.3 四元数与旋转矩阵的转换

这部分是标定中的高频操作。传感器输出的姿态可能是四元数,也可能是旋转矩阵,你得能在两者间自由切换。

4.3.1 四元数 → 旋转矩阵

给定单位四元数 q = (w, x, y, z),对应的旋转矩阵为:

R = | 1-2y²-2z²   2xy-2wz     2xz+2wy   |
    | 2xy+2wz      1-2x²-2z²   2yz-2wx   |
    | 2xz-2wy      2yz+2wx     1-2x²-2y² |

这个公式看着长,其实有规律。我一般记成:对角线是 1 减去两倍的另外两个虚部平方和,非对角线是 2×(对应项乘积) 再加减 2w×另一个分量。

4.3.2 旋转矩阵 → 四元数

反过来稍微麻烦点。从旋转矩阵 R 的元素反推四元数:

w = sqrt(1 + R₁₁ + R₂₂ + R₃₃) / 2
x = (R₃₂ - R₂₃) / (4w)
y = (R₁₃ - R₃₁) / (4w)
z = (R₂₁ - R₁₂) / (4w)

注意: 当 w 接近 0 时,分母会很小,数值不稳定。我曾经在嵌入式平台上遇到过这个问题,后来改用 Shepperd 方法处理奇异情况。简单说就是选最大的那个分量作为主元来计算。

4.4 各种表示方法的优缺点对比

做了这么多年多传感器融合,我总结了一张对比表,你直接拿去用:

表示方法 优点 缺点 适用场景
旋转矩阵 直观、容易组合、无奇异 9个参数冗余、计算量大 底层图形渲染、刚体变换
欧拉角 最直观、3个参数 万向锁、顺序依赖、插值困难 人机交互、简单姿态显示
四元数 无奇异、4个参数、易插值 不够直观、半角概念难理解 SLAM、姿态估计、传感器融合
轴角 最物理、3个参数 0°时奇异、组合复杂 旋转表示、李群李代数

我个人在标定工作中,内部计算一律用四元数,只在最后给用户展示时转成欧拉角。为什么?因为四元数做插值和滤波太方便了。比如你要平滑两个姿态之间的过渡,用四元数球面线性插值(Slerp)就行,旋转矩阵和欧拉角都做不到这么优雅。

避坑指南: 我曾经在融合IMU和视觉数据时,直接用欧拉角做卡尔曼滤波。结果在俯仰角接近90°时,滤波器直接炸了。后来换成四元数状态表示,问题迎刃而解。记住:只要涉及连续旋转估计,优先选四元数。

4.5 本章知识体系

下面这张图帮你理清四元数在整个旋转表示体系中的位置:

旋转表示方法知识体系 旋转矩阵 9参数,无奇异 欧拉角 3参数,有万向锁 四元数 4参数,无奇异 轴角 3参数,0°奇异 q = w + xi + yj + zk 四元数运算 加减 · 乘法 · 共轭 · 模长 ↔ 旋转矩阵转换 双向映射 · 数值稳定 SLAM / 传感器融合 插值 · 滤波 · 优化 核心结论:内部计算用四元数,展示用欧拉角 标定工作中优先选择四元数进行状态估计和优化

嗯,四元数这块内容确实需要多花点时间消化。不过一旦你理解了它的几何意义,就会发现它比旋转矩阵和欧拉角好用得多。下一节我们开始讲多传感器标定中最重要的工具——李群与李代数,到时候你会更深刻地体会到四元数的价值。

我的建议: 如果你刚开始接触四元数,别急着背公式。先写一个小程序,用四元数旋转一个三维点,看看效果。亲手验证一下 q·p·q⁻¹ 确实能把点转过去,比看十遍公式都管用。

可可精品资料库