数学基础(一):空间描述与变换

各位同学好,我是你们的轨迹规划讲师。今天咱们聊聊数学基础——说白了,就是怎么在三维空间里描述一个物体在哪儿、朝哪儿看。

我记得刚入行那会儿,总觉得数学是纸上谈兵。直到第一次调机械臂,明明算好了角度,结果末端执行器直接怼到工件上去了。嗯,从那以后,我再也不敢小看这些矩阵和四元数了。

位置与姿态:描述一个刚体的“身份证”

想象一下,你手里拿着一个手机。它在空间中的状态,其实就两件事:位置(在哪儿)和姿态(朝哪儿)。

  • 位置:用三维坐标 (x, y, z) 表示,相对于某个参考坐标系。
  • 姿态:描述物体坐标轴相对于参考坐标系的指向。

位置好理解,姿态才是坑。我见过不少新手,把姿态和旋转混为一谈,结果程序跑起来,机器人转得跟陀螺似的。

核心概念:一个刚体在空间中的完整状态 = 位置矢量 + 姿态矩阵。缺一不可。

旋转矩阵:最直观,但最“贵”

旋转矩阵 R 是一个 3×3 的正交矩阵,行列式为 +1。它的每一列,就是物体坐标系各轴在参考系中的投影。

// 绕 Z 轴旋转 θ 角的旋转矩阵
R_z(θ) = [
  [cosθ, -sinθ, 0],
  [sinθ,  cosθ, 0],
  [0,      0,    1]
]

旋转矩阵的好处是直观,组合旋转就是矩阵乘法。但坏处也很明显——9 个元素,只有 3 个自由度,冗余严重。而且连续旋转时,矩阵乘法计算量大,还容易累积数值误差。

我的习惯:在需要频繁进行坐标变换的底层代码里,我尽量用旋转矩阵。因为它的数值稳定性最好,不容易出现万向锁之类的问题。

齐次变换矩阵:把旋转和平移打包

实际工程中,我们经常需要同时处理旋转和平移。齐次变换矩阵 T 就是干这个的——它是一个 4×4 的矩阵,把旋转矩阵 R 和平移向量 t 塞到一起。

T = [ R   t ]
    [ 0ᵀ  1 ]

// 例如:先绕 Z 轴转 30°,再沿 X 轴移动 5 个单位
T = [
  [0.866, -0.5, 0, 5],
  [0.5,   0.866, 0, 0],
  [0,     0,    1, 0],
  [0,     0,    0, 1]
]

为什么用齐次?因为你可以把多次变换连乘成一个矩阵,一次算完。这在轨迹规划里太重要了——你想想看,机械臂从基座到末端,中间经过好几个关节,每个关节都有自己的变换。用齐次矩阵,一次乘法就能算出末端位姿。

我曾经踩过的坑:齐次变换矩阵的乘法顺序是左乘还是右乘,取决于你用的是固定坐标系还是动坐标系。我当年在项目里搞反了,结果机械臂画了个八字形,差点把旁边的传感器撞坏。记住:左乘是相对于固定坐标系,右乘是相对于当前坐标系。

欧拉角:直观但“有毒”

欧拉角用三个角度(比如滚转、俯仰、偏航)来描述姿态。听起来很简单,对吧?

但问题来了:

  • 顺序依赖:XYZ、ZYX、ZYZ……不同顺序,结果完全不同。
  • 万向锁:当中间角接近 ±90° 时,会丢失一个自由度。我在做无人机仿真时就遇到过——飞机垂直俯冲时,偏航和滚转突然分不清了,控制直接炸掉。
表示方法 优点 缺点
旋转矩阵 数值稳定,无奇异性 冗余参数,计算量大
欧拉角 直观,参数少 万向锁,顺序依赖
四元数 无奇异性,插值平滑 不够直观,需归一化

四元数:轨迹规划的“瑞士军刀”

四元数 q = w + xi + yj + zk,其中 w 是实部,(x, y, z) 是虚部,且满足 w² + x² + y² + z² = 1。

为什么轨迹规划偏爱四元数?

  • 无万向锁:随便你怎么转,不会丢自由度。
  • 平滑插值:球面线性插值(SLERP)可以生成平滑的旋转过渡。
  • 计算高效:比旋转矩阵少一半的乘法。
// 四元数乘法(表示旋转组合)
q_result = q1 * q2

// 用四元数旋转一个向量 v
v_rotated = q * v * q_conjugate

// SLERP 插值
q(t) = (q1 * sin((1-t)Ω) + q2 * sin(tΩ)) / sin(Ω)

我个人的建议:在轨迹规划中,内部计算全部用四元数。只在用户界面或调试时,才把四元数转成欧拉角给人看。这样既避免了万向锁,又保持了直观性。

知识体系总览

下面这张图,是我自己总结的空间描述与变换的知识结构。你可以把它当作本章的“地图”。

空间描述与变换知识体系 空间描述与变换 位置与姿态 旋转表示 齐次变换 旋转矩阵 欧拉角 四元数 正交矩阵 万向锁 SLERP插值 4×4矩阵 💡 工程建议 内部计算用四元数,人机交互用欧拉角,底层坐标变换用齐次矩阵

实际工程中的选择策略

说了这么多,到底该用哪个?我根据自己的项目经验,总结了一个简单的选择原则:

  1. 做底层驱动或实时控制:用旋转矩阵。数值稳定性是第一位的。
  2. 做轨迹规划或动画插值:用四元数。SLERP 平滑,无奇异性。
  3. 做用户界面或调试显示:用欧拉角。人看得懂。
  4. 做多坐标系变换链:用齐次变换矩阵。一次乘法搞定所有变换。

特别注意:四元数必须保持单位长度。我在一个项目里忘了归一化,结果旋转越来越“飘”,最后物体直接穿模了。每次更新四元数后,记得做一次归一化:q = q / norm(q)。