想象一下,你手里拿着一个魔方,想描述它从初始状态旋转到了什么样子。你可以说“先向右转90度,再向上翻90度”——这就是欧拉角的思路。而旋转矩阵则像一张精确的“方向说明书”,告诉你魔方上每一个面的新朝向。在机器人导航中,我们需要用数学语言精确描述这种旋转。
旋转矩阵是一个3x3的矩阵,它的核心思想是:一个坐标系相对于另一个坐标系的旋转,可以通过一个矩阵乘法来表示。这个矩阵的每一列,都代表了新坐标系的一个轴(X, Y, Z)在原坐标系下的方向余弦。
假设我们有一个世界坐标系 {W},一个机器人坐标系 {R}。{R}相对于{W}的旋转矩阵 R 满足一个关键性质:它将一个在{R}中表示的向量,变换到在{W}中表示。
关键点:旋转矩阵的每一列,就是旋转后新坐标系的X轴、Y轴、Z轴在原坐标系下的单位向量。因此,这个矩阵是正交矩阵,它的逆等于它的转置(R-1 = RT),且行列式为1。
让我们用一个具体的例子来构建旋转矩阵。考虑机器人绕世界坐标系的Z轴旋转了角度θ。旋转后,机器人自身的X轴和Y轴方向改变了,但Z轴方向不变。
根据几何关系,我们可以写出旋转后{R}的各个轴在{W}下的坐标:
将这三个列向量组合起来,就得到了绕Z轴旋转的旋转矩阵:
// 绕Z轴旋转θ角的旋转矩阵 R_z(θ)
R_z(θ) = [ cosθ, -sinθ, 0;
sinθ, cosθ, 0;
0, 0, 1 ]
同理,我们可以推导出绕X轴和Y轴旋转的基本旋转矩阵。这三个矩阵是构建所有复杂旋转的基础。
| 旋转轴 | 旋转矩阵 | 示意图(想象从轴正方向看向原点) |
|---|---|---|
| 绕X轴旋转 α | R_x(α) = [1, 0, 0; 0, cosα, -sinα; 0, sinα, cosα] | Y轴转向Z轴 |
| 绕Y轴旋转 β | R_y(β) = [cosβ, 0, sinβ; 0, 1, 0; -sinβ, 0, cosβ] | Z轴转向X轴 |
| 绕Z轴旋转 γ | R_z(γ) = [cosγ, -sinγ, 0; sinγ, cosγ, 0; 0, 0, 1] | X轴转向Y轴 |
如果说旋转矩阵是精确的“说明书”,那么欧拉角就是通俗的“口头指令”。它用三个连续的绕自身坐标轴的旋转角度来描述姿态,非常符合人类的直观想象。
欧拉角的核心在于旋转顺序。你不能只说“绕X、Y、Z轴分别转α、β、γ度”,必须明确先转哪个轴,再转哪个轴。最常见的顺序是ZYX(也常被称为“偏航-俯仰-滚转”,即yaw-pitch-roll)。
在航空航天和移动机器人中,ZYX顺序被广泛使用:
在实际的机器人系统中,我们经常需要在旋转矩阵和欧拉角之间进行转换。传感器(如IMU)可能输出欧拉角,而运动学计算则需要使用旋转矩阵。
从欧拉角到旋转矩阵:根据指定的旋转顺序,将对应的基本旋转矩阵按顺序相乘。对于ZYX顺序(偏航ψ,俯仰θ,滚转φ):
R = R_z(ψ) * R_y(θ) * R_x(φ)
// 将三个基本矩阵代入并相乘,得到最终的3x3矩阵
从旋转矩阵到欧拉角:这个过程称为“提取”欧拉角,需要根据旋转矩阵的元素反解出角度。对于ZYX顺序,公式如下(假设cosθ ≠ 0):
θ = arcsin(-R[2,0]) // 俯仰角
ψ = atan2(R[1,0]/cosθ, R[0,0]/cosθ) // 偏航角
φ = atan2(R[2,1]/cosθ, R[2,2]/cosθ) // 滚转角
编者提示:在从旋转矩阵提取欧拉角时,要特别注意万向节死锁问题。当俯仰角θ为±90度时,cosθ=0,上述公式中的分母为零,偏航角ψ和滚转角φ失去唯一解(它们的变化效果相同)。这是欧拉角表示法的固有缺陷。在实际编程中,调用数学库函数(如scipy.spatial.transform.Rotation或Eigen库的转换函数)时,这些库通常会处理死锁情况,返回一个合理的解,但你需要意识到此时姿态信息有损失。
两种表示法各有优劣,没有绝对的好坏,只有适合的场景。
| 特性 | 旋转矩阵 | 欧拉角 |
|---|---|---|
| 直观性 | 差,难以直接理解姿态 | 极好,三个角度一目了然 |
| 唯一性 | 唯一(特殊正交矩阵) | 不唯一(存在多解和万向节死锁) |
| 计算 | 矩阵乘法,计算量稍大(9个数) | 角度计算,简单快速(3个数) |
| 插值 | 不能直接对矩阵元素插值 | 可直接对角插值,但路径可能不自然 |
| 适用场景 | 连续变换、复合旋转、理论推导 | 姿态显示、简单控制指令、传感器原始数据 |
我在一个机械臂项目中踩过坑:上位机界面用欧拉角让用户设置末端姿态,而下位机运动学求解器使用旋转矩阵。由于没有统一约定旋转顺序(是ZYX还是XYZ?),导致设置的角度和实际运动方向对不上。最后我们强制规定整个项目全部使用ZYX顺序,并在所有接口文档中明确标注,问题才得以解决。
假设一个机器人初始朝向与世界坐标系一致。现在它执行了以下动作:先绕自身Z轴(偏航)旋转30度,再绕新的Y轴(俯仰)旋转45度,最后绕最新的X轴(滚转)旋转60度(ZYX顺序)。
这个练习能让你深刻理解旋转顺序的重要性以及矩阵乘法的不可交换性。