3. 刚体运动与姿态表示:旋转矩阵、欧拉角、四元数、李群与李代数基础

各位同学,欢迎来到第三章。这一章,我们聊聊刚体运动。

做SLAM,说白了就是估计相机在空间里怎么动。相机是个刚体,它不会像橡皮泥一样变形。所以,描述它的位置和朝向,就是刚体运动的核心问题。

我个人习惯把姿态表示分成两类:一类是给人看的,比如欧拉角;另一类是给机器算的,比如旋转矩阵和四元数。至于李群和李代数,那是给优化器用的。咱们一个一个来。

3.1 旋转矩阵:最直观的数学表达

旋转矩阵,就是一个3x3的矩阵。它描述了一个坐标系相对于另一个坐标系的旋转关系。

你想想看,一个点在空间里,坐标是(x,y,z)。如果坐标系旋转了,这个点的坐标会怎么变?旋转矩阵就是干这个的。

核心性质:

  • 旋转矩阵是正交矩阵:RTR = I
  • 行列式为+1:det(R) = 1
  • 逆矩阵等于转置:R-1 = RT

我在项目中遇到过一个问题:两个旋转矩阵相乘,顺序搞反了。结果相机轨迹完全乱套。记住,矩阵乘法不满足交换律。R1 * R2 和 R2 * R1 是两码事。

3.2 欧拉角:直观但容易翻车

欧拉角用三个角度表示旋转:偏航(Yaw)、俯仰(Pitch)、滚转(Roll)。

听起来很直观对吧?但这里有个大坑——万向锁(Gimbal Lock)。

避坑指南:

我曾经在调试一个无人机姿态估计时,发现俯仰角接近90度时,偏航和滚转突然耦合了。这就是万向锁。欧拉角在SLAM里,我建议只用来做可视化,别用在核心计算里。

另外,欧拉角的定义顺序也很重要。ZYX、ZYZ、XYZ……不同顺序结果完全不同。你想想看,如果团队里有人用ZYX,有人用XYZ,那对接起来就是灾难。

3.3 四元数:SLAM的标配

四元数,说白了就是一个四维向量:q = w + xi + yj + zk。它没有万向锁问题,而且插值平滑。

在SLAM里,我几乎只用四元数做姿态优化。为什么?因为它只需要4个参数,而旋转矩阵要9个。优化时,约束条件也少很多。

我的习惯:

单位四元数表示旋转。如果四元数的模不是1,先归一化再用。我在一次轨迹评估中,因为忘了归一化,结果误差曲线全是毛刺。嗯,从那以后我写了个自动检查函数。

四元数乘法也不简单。两个四元数相乘,对应旋转的复合。顺序和矩阵一样,不能乱。

// 四元数乘法示例
// q1 * q2 表示先做q2旋转,再做q1旋转
Quaternion multiply(Quaternion q1, 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
    );
}

3.4 李群与李代数:优化的利器

这部分,很多初学者觉得抽象。我换个说法:李群是旋转矩阵的集合,李代数是旋转向量的集合。

为什么需要李代数?因为旋转矩阵有约束(正交且行列式为1),没法直接做加法优化。但李代数没有约束,可以随便加减。

你想想看,在BA(Bundle Adjustment)里,我们要优化相机位姿。如果用旋转矩阵,每次迭代都要保证矩阵是正交的,很麻烦。用李代数,直接加一个增量就行,然后通过指数映射转回旋转矩阵。

核心关系:

  • SO(3):三维旋转群(李群)
  • so(3):三维旋转的李代数
  • 指数映射:so(3) → SO(3)
  • 对数映射:SO(3) → so(3)

我在做视觉惯性里程计(VIO)时,就用李代数做位姿优化。每次迭代,计算误差的雅可比矩阵,然后更新李代数。嗯,这里要注意,雅可比矩阵的形式和扰动模型有关。我建议用右扰动模型,代码实现起来更顺手。

3.5 知识体系总览

下面这张图,是我自己总结的。它把本章的知识点串起来了。

刚体运动与姿态表示知识体系 刚体运动 姿态表示方法 旋转矩阵 (9参数) 欧拉角 (3参数) 四元数 (4参数) 李群 SO(3) ↔ 李代数 so(3) 应用:位姿优化、BA、VIO

3.6 实际应用中的选择建议

场景 推荐表示 原因
可视化调试 欧拉角 直观,容易理解
状态估计/滤波 四元数 无万向锁,插值平滑
非线性优化 李代数 无约束,便于求导
坐标变换 旋转矩阵 直接相乘,效率高

个人经验:

我在做轨迹评估时,内部计算全用四元数和李代数。只在最后输出结果时,转成欧拉角给人看。这样既保证了精度,又方便了沟通。

好了,这一章的内容就到这里。记住,姿态表示没有绝对的好坏,关键看你在什么场景下用。多动手写代码,多跑几个数据集,你自然就找到感觉了。

可可精品资料库