三维空间刚体运动(下):四元数与李群李代数

好,咱们接着聊。上一节我们把旋转矩阵和欧拉角掰扯清楚了,这一节要啃两块硬骨头——四元数和李群李代数。

说实话,我刚入行那会儿,看到四元数这四个字就头大。什么 i、j、k,还满足 i² = j² = k² = ijk = -1,这玩意儿是数学老师喝多了编出来的吧?后来在项目里被欧拉角万向锁坑过一次,才老老实实把四元数捡起来学。嗯,真香。

一、四元数的定义与基本运算

四元数,说白了就是一个扩展版的复数。复数有一个实部一个虚部,四元数有一个实部三个虚部:

q = w + xi + yj + zk

其中 w 是实部,x、y、z 是虚部。i、j、k 满足:

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

你看,ijk 的乘法规则其实跟三维向量的叉积很像。我个人习惯把四元数记作 q = [w, v],其中 v = (x, y, z) 是向量部分。

1. 四元数的加减法

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

q1 ± q2 = (w1 ± w2) + (x1 ± x2)i + (y1 ± y2)j + (z1 ± z2)k

2. 四元数的乘法

这个稍微复杂点。两个四元数相乘,结果还是四元数:

q1 * q2 = (w1*w2 - v1·v2) + (w1*v2 + w2*v1 + v1×v2)

注意,这里出现了点积和叉积。所以四元数乘法不满足交换律——q1*q2 ≠ q2*q1。我在项目里调试IMU姿态解算时,就因为这个顺序搞反过,结果姿态飞了半小时才反应过来。

3. 共轭与模长

四元数的共轭就是把虚部取反:

q* = w - xi - yj - zk

模长就是各分量平方和开根号:

||q|| = sqrt(w² + x² + y² + z²)

单位四元数的模长为1,旋转四元数必须是单位四元数。这个坑我踩过——归一化忘做了,结果旋转完点云全飘到天上去。

⚠️ 避坑指南:每次更新完四元数,记得做归一化!数值误差会慢慢让模长偏离1,累积多了姿态就崩了。

二、四元数与旋转矩阵的相互转换

为什么我们要用四元数?因为它在插值和避免万向锁方面比欧拉角强太多。但实际工程中,我们经常需要在四元数和旋转矩阵之间来回切换。

1. 四元数 → 旋转矩阵

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

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

这个公式看着吓人,其实你写代码时直接套公式就行。我一般会封装成一个函数,每次调用前检查一下四元数模长是否接近1。

2. 旋转矩阵 → 四元数

反过来稍微麻烦点。从旋转矩阵 R 的迹(trace)出发:

tr = R[0][0] + R[1][1] + R[2][2]
w = sqrt(tr + 1) / 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)

注意,当 tr 接近 -1 时,w 会接近0,这时候除法会出问题。我建议用 Shepperd 方法做数值稳定处理,网上有现成代码。

💡 个人经验:在点云配准中,我习惯用四元数做优化变量,最后再转成旋转矩阵去应用。因为四元数只有4个参数,且没有奇异性,优化起来更稳定。

三、李群 SO(3) 与李代数 so(3) 简介

好,接下来是重头戏——李群和李代数。别被名字吓到,这东西在SLAM里天天用。

1. 什么是李群 SO(3)?

SO(3) 就是所有旋转矩阵的集合。它满足:

  • R 是 3×3 矩阵
  • RᵀR = I(正交性)
  • det(R) = 1(右手系)

SO(3) 是一个群,因为旋转矩阵乘法封闭、有逆元、有单位元。但它不是向量空间——你不能把两个旋转矩阵加起来再期望它还是个旋转矩阵。

2. 李代数 so(3) 是什么?

so(3) 是 SO(3) 在单位元处的切空间。说白了,就是旋转矩阵的「导数」或「微小变化量」。so(3) 中的元素是 3×3 的反对称矩阵:

ω^ = | 0   -ωz  ωy |
     | ωz   0   -ωx |
     | -ωy  ωx   0  |

其中 ω = (ωx, ωy, ωz) 就是三维向量,对应旋转轴方向,模长对应旋转速度。

3. 指数映射与对数映射

SO(3) 和 so(3) 之间通过指数映射和对数映射相互转换:

  • 指数映射:从 so(3) → SO(3),即从角速度到旋转矩阵
  • 对数映射:从 SO(3) → so(3),即从旋转矩阵到角速度

指数映射的公式就是罗德里格斯公式:

R = exp(θ·n^) = I + sinθ·n^ + (1-cosθ)·(n^)²

其中 θ 是旋转角度,n 是单位旋转轴。

🔑 核心思想:在SLAM优化中,我们通常用李代数 so(3) 来表示旋转的增量,因为它是向量空间,可以直接做加法、求导。优化完再通过指数映射转回 SO(3)。

4. 为什么SLAM里要用李群李代数?

你想想看,如果我们直接用旋转矩阵做优化,每次迭代都要保证 RᵀR = I,这约束太强了。而用李代数,我们只需要优化一个三维向量,没有任何约束,优化完再映射回旋转矩阵就行。

我在做VIO(视觉惯性里程计)时,后端优化用的就是 so(3) 参数化。每次迭代更新 δω,然后通过指数映射更新旋转矩阵。这样既保证了旋转矩阵的正交性,又让优化变得简单。

⚠️ 注意:指数映射在 θ 接近 0 时是数值稳定的,但当 θ 接近 π 时会有奇异性。实际工程中,如果遇到大角度旋转,建议用四元数做中间过渡。

四、知识体系总览

为了让你更直观地理解这一章的知识结构,我画了一张图:

三维空间刚体运动(下)知识体系 四元数 • 定义:w + xi + yj + zk • 乘法:点积+叉积 • 共轭与模长 • 单位四元数表示旋转 • 插值(Slerp) 相互转换 • 四元数 → 旋转矩阵 • 旋转矩阵 → 四元数 • 数值稳定性处理 • Shepperd方法 • 工程应用场景 李群 SO(3) 与 so(3) • SO(3):旋转矩阵集合 • so(3):反对称矩阵 • 指数映射:so(3)→SO(3) • 对数映射:SO(3)→so(3) • SLAM优化中的应用 核心思想 四元数用于表示和插值旋转,李代数用于优化和求导 SLAM 实战应用 IMU姿态解算 · 点云配准 · 视觉里程计 · 后端图优化 四元数做状态表示,李代数做增量更新

这张图把三个核心概念的关系理清楚了。四元数和旋转矩阵可以互相转换,而李群李代数为我们提供了在优化中处理旋转的数学工具。

我个人觉得,学这部分内容最好的方式就是动手写代码。把四元数乘法、旋转矩阵转换、指数映射这些函数自己实现一遍,比看十遍书都管用。我在做第一个SLAM项目时,就是一边写代码一边理解这些概念的。

嗯,这一节的内容就到这儿。记住:四元数管表示,李代数管优化,两者配合才能打好SLAM的基础。