2. 旋转矩阵参数:欧拉角、旋转矩阵与四元数的参数化表示

说到旋转参数化,我得先坦白一件事。刚入行那会儿,我觉得欧拉角就够用了,简单直观。直到有一次做无人机姿态解算,万向锁把整个系统搞崩了——嗯,从那以后我才老老实实把四元数啃下来。

今天咱们就把这三种表示法掰开揉碎。你想想看,旋转在三维空间里其实就三件事:绕哪个轴、转多少度、顺序怎么排。但不同的表示法,坑可完全不一样。

2.1 欧拉角:最直观,但最危险

欧拉角说白了就是三个角度:绕X轴转的叫滚转角(roll),绕Y轴转的叫俯仰角(pitch),绕Z轴转的叫偏航角(yaw)。

我个人习惯用ZYX顺序,也就是先绕Z轴转ψ,再绕Y轴转θ,最后绕X轴转φ。写成矩阵就是:

R = Rz(ψ) * Ry(θ) * Rx(φ)

展开之后长这样:

R = [[cosψ cosθ,  cosψ sinθ sinφ - sinψ cosφ,  cosψ sinθ cosφ + sinψ sinφ],
     [sinψ cosθ,  sinψ sinθ sinφ + cosψ cosφ,  sinψ sinθ cosφ - cosψ sinφ],
     [-sinθ,      cosθ sinφ,                    cosθ cosφ]]
⚠️ 万向锁警告

当俯仰角θ = ±90°时,cosθ = 0,你会发现滚转和偏航的旋转轴重合了。这时候系统会丢失一个自由度。我曾经在机械臂标定中踩过这个坑,手臂在奇异点附近疯狂抖动,差点把工件甩飞。

欧拉角的优势是直观,调试时看一眼数值就知道姿态大概什么样。但做插值?别想了。两个姿态之间的欧拉角插值路径会非常诡异,物体在空中翻跟头都是轻的。

2.2 旋转矩阵:计算友好,但冗余

旋转矩阵是个3×3的正交矩阵,满足RTR = I,行列式为+1。说白了,它就是把一个坐标系里的向量,映射到另一个坐标系。

我个人觉得旋转矩阵最大的好处是组合方便。你要连续旋转?直接矩阵乘法就行:

R_total = R3 * R2 * R1

但问题也很明显——9个参数,只有3个自由度。剩下的6个是约束条件。你想想看,如果因为数值误差导致矩阵不再正交,那它就不是旋转矩阵了,而是带剪切的仿射变换。

💡 我的习惯做法

每次更新旋转矩阵后,我都会做一次正交化:R ← (R * RT)-1/2 * R。虽然多了一步计算,但能避免累积误差把系统搞崩。

旋转矩阵的插值也不容易。你不能直接对9个元素做线性插值,那样得到的矩阵大概率不是正交的。得用矩阵对数映射到李代数,再插值——嗯,这就绕到四元数了。

2.3 四元数:优雅,但抽象

四元数是个超复数,形式是q = w + xi + yj + zk,其中i² = j² = k² = ijk = -1。单位四元数(模长为1)可以用来表示旋转。

为什么用四元数?三个理由:

  • 无万向锁——这是最核心的优势
  • 插值平滑——球面线性插值(SLERP)能给出最短路径
  • 计算高效——比矩阵少一半的乘法

从旋转矩阵转四元数,公式是这样的:

w = sqrt(1 + R[0][0] + R[1][1] + R[2][2]) / 2
x = (R[2][1] - R[1][2]) / (4 * w)
y = (R[0][2] - R[2][0]) / (4 * w)
z = (R[1][0] - R[0][1]) / (4 * w)
⚠️ 数值稳定性问题

当w接近0时,分母会很小,导致数值爆炸。我曾经在IMU数据融合时遇到过这个问题,解算出来的四元数直接飞了。解决办法是判断w的绝对值,如果太小就改用其他元素做分母。

四元数的乘法也很有意思。两个旋转q1和q2的复合,不是简单的元素相乘:

q = q1 * 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

注意顺序——q1 * q2表示先转q2再转q1,跟矩阵乘法是反的。这个坑我见过不少人掉进去。

2.4 三种表示法的对比

特性 欧拉角 旋转矩阵 四元数
参数数量 3 9 4
自由度 3 3(含6个约束) 3(含1个约束)
万向锁 有 无 无
插值 困难 需李代数 SLERP
计算效率 高 低 中
直观性 高 低 低
🎯 我的选择建议

做可视化调试用欧拉角,做底层计算用四元数,需要跟OpenGL/DirectX交互时转成旋转矩阵。说白了,各取所长。

2.5 知识体系结构图

旋转参数化表示知识体系 三维空间旋转 欧拉角 (3参数) ⚠️ 万向锁问题 直观易调试 旋转矩阵 (9参数) 组合方便 需正交化约束 四元数 (4参数) 无万向锁 SLERP平滑插值

这张图把三种表示法的核心特征都标出来了。你看,欧拉角在最左边,直观但有硬伤;旋转矩阵在中间,计算方便但冗余;四元数在最右边,抽象但优雅。实际项目中,我通常会在不同阶段切换使用——调试用欧拉角,核心算法用四元数,渲染用矩阵。

💡 避坑指南

我曾经在写SLAM前端时,直接用欧拉角做优化变量。结果每次迭代都要处理万向锁附近的奇异值,代码里全是if-else。后来换成四元数做优化,虽然雅可比矩阵推导麻烦了点,但再也不用担心奇异问题了。

嗯,三种表示法各有各的脾气。选对工具,你的代码能少一半的bug。

可可精品资料库