3. 旋转与平移:旋转矩阵、欧拉角、四元数、平移向量、齐次坐标与变换矩阵

说到外参标定,绕不开的就是旋转和平移。说白了,我们要描述两个坐标系之间怎么转、怎么挪。我刚开始做SLAM那会儿,觉得这些数学工具就是些公式,后来踩坑多了才明白——选错表达方式,轻则代码跑不通,重则定位直接炸掉。

这一节,我把最常用的几种表达方式掰开揉碎讲清楚。你想想看,一个IMU和相机的相对位姿,你用什么来表示?旋转矩阵?四元数?还是欧拉角?各有各的脾气。

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

旋转矩阵是个3x3的方阵,记作 R。它描述了一个坐标系相对于另一个坐标系的朝向。比如,相机坐标系到IMU坐标系的旋转,就可以用一个R来表示。

它的好处是直观。一个点p在相机系下的坐标是p_c,在IMU系下就是 p_i = R * p_c。直接矩阵乘法,干净利落。

但坏处也很明显——冗余。9个元素,实际上只有3个自由度。你想想,每次优化要维护9个参数,还得保证它是正交矩阵(R^T R = I),这约束条件写起来就够烦的。

我在项目中遇到过:有一次做手眼标定,直接用旋转矩阵做优化变量。结果迭代几次后矩阵不再正交,投影出来的点全歪了。后来我学乖了,要么用四元数,要么加正交约束。

3.2 欧拉角:直观但小心万向锁

欧拉角用三个角度表示旋转:绕X轴转多少(roll)、绕Y轴转多少(pitch)、绕Z轴转多少(yaw)。

这玩意儿在调试时特别方便。我跟算法同事沟通时,常说“相机绕Z轴偏了5度”,而不是说“四元数的实部是多少”。

但欧拉角有个臭名昭著的问题——万向锁。当pitch接近±90度时,roll和yaw会变得无法区分。说白了,你丢失了一个自由度。

我曾经在无人机飞控里见过这问题。飞机垂直爬升时,姿态解算突然跳变,差点炸机。从那以后,我在任何需要连续旋转估计的场景里,都优先用四元数。

3.3 四元数:SLAMer的标配

四元数是个超复数,形式是 q = w + xi + yj + zk,其中 w 是实部,x,y,z 是虚部。它用4个参数表示旋转,没有冗余,也没有万向锁。

我个人习惯用四元数做状态估计。为什么呢?

  • 紧凑:4个参数,比旋转矩阵的9个少一半多
  • 无奇异性:不会像欧拉角那样突然死掉
  • 容易插值:做平滑旋转时,球面线性插值(SLERP)非常自然

但四元数也有坑。比如,q 和 -q 表示同一个旋转。你优化时如果不加约束,它可能在正负之间来回跳。嗯,这里要注意,通常我们会固定实部为正,或者在代价函数里加个符号约束。

// 四元数乘法表示旋转叠加
// q1 表示从A到B的旋转,q2 表示从B到C的旋转
// 那么从A到C的旋转是 q = q2 * q1
Eigen::Quaterniond q1(0.707, 0.707, 0, 0); // 绕Z轴转90度
Eigen::Quaterniond q2(1, 0, 0, 0);          // 单位四元数
Eigen::Quaterniond q = q2 * q1;
// 注意:Eigen中四元数乘法顺序是 q2 * q1,不是 q1 * q2

3.4 平移向量:简单但别搞错坐标系

平移向量 t 就是个3维向量,表示从一个坐标系原点到另一个坐标系原点的位移。比如,t 表示相机原点在IMU坐标系下的位置。

这里最容易犯的错误是——平移向量是在哪个坐标系下表达的?

我见过有人把平移向量直接当成“从A到B的向量”,结果坐标变换时符号搞反。记住:平移向量通常是在目标坐标系下表达的。比如,从相机系到IMU系的变换,平移向量 t 是在IMU系下的相机位置。

一个小技巧:写代码时,把平移向量的含义写在注释里。比如 // t: camera position in IMU frame。这样三个月后回来看代码,不会骂自己。

3.5 齐次坐标与变换矩阵:把旋转和平移打包

齐次坐标就是在普通3D坐标后面加个1,变成4维向量 [x, y, z, 1]^T。变换矩阵 T 是个4x4矩阵,左上角3x3是旋转矩阵R,右上角3x1是平移向量t,最后一行是 [0, 0, 0, 1]。

为什么要这么搞?因为这样可以把旋转和平移合并成一次矩阵乘法:

| R  t |   | p |   | R*p + t |
| 0  1 | * | 1 | = |   1     |

说白了,一次乘法搞定坐标变换。而且多个变换可以连乘:T13 = T12 * T23。这在做传感器融合时特别有用——把IMU、相机、激光雷达的位姿串成一条链。

我在做多传感器标定时,习惯把所有外参都存成4x4的变换矩阵。这样不管是正向变换还是反向变换,直接求逆就行(T的逆就是 [R^T, -R^T * t; 0, 1])。

3.6 知识体系总览

下面这张图把几种表达方式的关系画清楚了。你一看就明白,它们之间可以互相转换,但各有适用场景。

旋转与平移表达方式 旋转矩阵 R 3x3,9参数,直观 欧拉角 (r,p,y) 3参数,直观,有万向锁 四元数 q 4参数,无奇异性 平移向量 t 3参数,注意坐标系 变换矩阵 T 4x4,R+t打包 齐次坐标 4D向量,方便乘法 可转换 可转换 组合 组合 配合使用 核心:旋转用四元数,调试用欧拉角,变换用齐次矩阵

3.7 实际标定中的选择建议

说了这么多,到底怎么选?我根据自己的经验,给个实用建议:

场景 推荐表达 原因
状态估计(EKF/图优化) 四元数 无奇异性,紧凑,容易做误差状态
手眼标定 变换矩阵 T 方便连乘和求逆,AX=XB形式直接解
调试可视化 欧拉角 一眼看出偏了多少度
坐标变换计算 齐次坐标 一次乘法搞定,代码简洁
存储/传输 四元数+平移向量 7个浮点数,比4x4矩阵省空间

我个人习惯:在代码内部统一用四元数+平移向量做优化,只在输出和调试时转成欧拉角或变换矩阵。这样既避免了万向锁,又方便人看。

好了,旋转和平移的数学工具就这些。你只要记住——四元数做优化,欧拉角做调试,变换矩阵做计算。下次标定时,别再被这些表达方式绕晕了。

可可精品资料库