坐标系基础:全局坐标系与局部坐标系、齐次坐标、坐标变换
说到坐标系,我刚开始做机器人时,觉得这东西太简单了——不就是画个十字轴嘛。直到第一次调试实车,发现明明代码里算得好好的,车就是不走直线。查了三天,最后发现是坐标系搞混了。嗯,从那以后,我再也不敢小看坐标系了。
1. 全局坐标系 vs 局部坐标系
说白了,全局坐标系就是“世界”的参考系。你站在路边看一辆车,车的位置、朝向,都是相对于地面说的。这个地面,就是全局坐标系。
局部坐标系呢?是跟着物体走的。比如车自己的坐标系——车头方向是X轴,左侧是Y轴,向上是Z轴。车转弯时,这个坐标系也跟着转。
我习惯把全局坐标系叫“地图坐标系”,局部坐标系叫“车身坐标系”。在自动驾驶里,这两个坐标系天天打架。
举个例子。你坐在车里,手机导航告诉你“前方200米右转”。这个200米是全局坐标系下的距离。但你的方向盘怎么打?得先把全局坐标转成车身坐标,才能知道“右转”对应的是打多少度方向。
2. 齐次坐标——为什么要多一个维度?
你想想看,二维平面上的点用(x, y)表示,三维空间用(x, y, z)表示。那旋转用矩阵乘法,平移用向量加法。旋转和平移混在一起用,代码写起来特别别扭。
齐次坐标就是来解决这个问题的。它给坐标多加一个维度:二维变三维(x, y, w),三维变四维(x, y, z, w)。
我项目中遇到过最典型的场景:传感器融合。激光雷达、摄像头、IMU,每个传感器都有自己的坐标系。要把它们统一到一个坐标系下,没有齐次坐标,代码能写到崩溃。
齐次坐标的转换规则很简单:
// 普通坐标转齐次坐标
(x, y) → (x, y, 1)
// 齐次坐标转普通坐标
(x, y, w) → (x/w, y/w)
为什么要除以w?因为w=0时表示无穷远点(方向向量),w=1时表示普通点。这个设计很巧妙,你细品。
3. 坐标变换——旋转与平移矩阵
坐标变换就两件事:旋转和平移。旋转用矩阵乘法,平移用向量加法。用齐次坐标后,两者统一成矩阵乘法。
3.1 旋转矩阵
二维旋转矩阵长这样:
R(θ) = [cosθ -sinθ]
[sinθ cosθ ]
三维旋转就复杂多了。绕X轴、Y轴、Z轴分别旋转,矩阵形式不同。我建议你直接记住一个原则:旋转矩阵是正交矩阵,逆矩阵等于转置矩阵。这个性质在代码里特别有用。
3.2 平移矩阵
平移就是加一个偏移量。在齐次坐标下,平移矩阵是:
T = [1 0 0 tx]
[0 1 0 ty]
[0 0 1 tz]
[0 0 0 1 ]
tx, ty, tz就是三个方向上的平移量。
3.3 完整的变换矩阵
旋转和平移合在一起,就是4x4的齐次变换矩阵:
M = [R t]
[0 1]
其中R是3x3旋转矩阵,t是3x1平移向量。这个矩阵可以同时完成旋转和平移。
4. 知识体系总览
下面这张图,是我自己总结的坐标系知识框架。你看一眼,心里就有数了。
5. 实战中的坐标系管理
我在项目里总结了一套坐标系管理方法,分享给你:
- 统一命名规范:全局坐标系叫world,车身坐标系叫body,传感器坐标系叫sensor_xxx。代码里一眼能看出来。
- 维护变换树:所有坐标系之间的变换关系,用树形结构管理。每个节点存一个4x4矩阵。
- 写测试用例:坐标系变换最容易出bug。我习惯写单元测试,输入一个点,经过变换再逆变换,看能不能回到原点。
6. 避坑指南
我曾经在坐标系上栽过的跟头,列出来给你参考:
- 左右手坐标系混淆:有些传感器用右手系,有些用左手系。转换时一定要确认。
- 旋转顺序搞错:欧拉角的旋转顺序(XYZ、ZYX等)不同,结果天差地别。
- 忘记归一化:旋转矩阵必须是正交矩阵。数值计算误差会导致矩阵不再正交,需要定期重新归一化。
- 齐次坐标w值搞错:普通点w=1,方向向量w=0。混用了,结果会非常诡异。
嗯,坐标系基础就讲到这里。这些内容看着简单,但真到项目里,90%的bug都出在这里。你写代码时多留个心眼,能省不少调试时间。