3、三维空间刚体运动:旋转矩阵、四元数、李群与李代数基础

各位同学,欢迎来到第三章。这一章,我们聊聊三维空间里最基础、也最绕不开的话题——刚体运动。

说实话,我刚入行做SLAM的时候,觉得这部分就是纯数学,枯燥得很。直到有一次,我在一个AR项目里,因为四元数顺序搞反了,导致虚拟物体在天上乱飞……嗯,从那以后,我再也不敢小看这些“基础”了。

你想想看,一个机器人或者一辆自动驾驶汽车,它在三维空间里怎么知道自己“转”了、“移”了?说白了,就是描述一个物体从位置A到位置B,姿态从朝向C变成朝向D。这背后,就是旋转矩阵、四元数、李群和李代数在撑腰。

3.1 旋转矩阵:最直观,但最啰嗦

旋转矩阵,我习惯叫它“老实人”。为什么?因为它把旋转这件事,用9个数字老老实实地写出来。

一个3x3的矩阵,正交且行列式为+1,就代表一次旋转。比如绕Z轴转θ角:

R_z(θ) = [cosθ  -sinθ  0]
         [sinθ   cosθ  0]
         [0      0     1]

但问题来了——9个数字,其实只有3个自由度。冗余信息太多。而且,你连续做两次旋转,矩阵乘法一乘,数值误差慢慢累积,矩阵就不再正交了。我见过不少新手直接拿非正交矩阵去解算,结果姿态越算越歪。

⚠️ 我曾经踩过的坑: 旋转矩阵一定要定期正交化!用 SVD 分解或者 Gram-Schmidt 方法,否则你的 SLAM 地图会慢慢“拧巴”起来。

3.2 四元数:紧凑且优雅

四元数,说白了就是“旋转的复数版本”。一个四元数 q = w + xi + yj + zk,其中 w 是实部,x,y,z 是虚部。它用4个数字表示旋转,没有冗余,而且没有万向锁问题。

我个人特别喜欢四元数做插值。比如你要让相机平滑地从姿态A转到姿态B,用四元数的球面线性插值(Slerp)就非常自然。旋转矩阵做插值?那简直是一场灾难。

这里给一个常用的四元数乘法代码(C++风格):

// 四元数乘法
Quaternion operator*(const Quaternion &q1, const Quaternion &q2) {
    return Quaternion(
        q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
        q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
        q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x,
        q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w
    );
}
💡 我的习惯: 在代码里统一用 Hamilton 约定(即 i*j=k),并且始终把四元数归一化。不归一化的四元数,在 SLAM 后端优化时会带来各种奇怪的问题。

3.3 李群与李代数:优化利器

好,到这里你可能要问:旋转矩阵和四元数都能表示旋转,为什么还要搞出李群和李代数?

原因很简单——优化。SLAM 的核心是求解一个优化问题,比如最小化重投影误差。而旋转矩阵和四元数都有约束(正交、单位模长),直接在上面做梯度下降非常麻烦。

李群 SO(3) 是旋转矩阵的集合,它是一个流形。李代数 so(3) 是它的切空间,是一个三维向量空间。说白了,李代数就是“旋转的微分形式”。

我建议你这样理解:

  • SO(3):旋转矩阵,是“结果”。
  • so(3):旋转向量(轴角),是“变化量”。

优化时,我们在李代数上做加法(无约束),然后通过指数映射回到李群。这样既保证了旋转的约束,又能用常规的优化方法。

指数映射公式(Rodrigues公式):

R = exp(φ^) = I + sinθ * (n^) + (1 - cosθ) * (n^)^2

其中 φ = θ * n,n 是单位旋转轴,θ 是旋转角。

🔑 核心要点: 李代数求导比李群求导简单得多。在 SLAM 的 BA(Bundle Adjustment)中,几乎所有的旋转增量都是用李代数表示的。

3.4 知识体系总览

下面这张图,是我自己总结的本章知识结构。你可以把它当作一个“导航图”:

三维空间刚体运动表示 旋转矩阵 SO(3) 四元数 李群 / 李代数 9个元素,3自由度 正交约束 直观但冗余 需定期正交化 4个元素,无冗余 无万向锁 适合插值 需归一化 无约束优化 指数/对数映射 求导方便 BA优化核心 实际工程中: 前端用四元数做插值,后端用李代数做优化

3.5 实际工程中的选择

在 SLAM 系统里,我一般这样选:

场景 推荐表示 原因
前端里程计(帧间匹配) 四元数 轻量、易插值、无万向锁
后端图优化(BA) 李代数 so(3) 无约束、求导简单、收敛快
可视化/人机交互 旋转矩阵 直观、容易理解
传感器标定 四元数 + 李代数混合 初始化用四元数,优化用李代数
💡 避坑指南: 我曾经在写一个 VIO 系统时,把四元数的顺序搞反了(Hamilton vs JPL),结果 IMU 预积分一直发散。后来花了整整两天才定位到问题。所以,团队里一定要统一约定,并且在代码注释里写清楚!

好了,这一章的内容就到这里。三维空间刚体运动,说难不难,说简单也不简单。关键是要理解每种表示法的“性格”——旋转矩阵老实但啰嗦,四元数优雅但需要小心,李代数强大但抽象。你多写几行代码,多跑几次实验,自然就熟了。


专注资料整理