3. 坐标系与坐标变换:全局坐标系、局部坐标系、齐次变换矩阵
各位同学,欢迎来到第三章。这一章,我们聊聊坐标系。
说实话,我刚入行做机器人路径规划那会儿,觉得坐标系这东西太简单了。不就是X、Y、Z三个轴嘛,谁不会啊?结果第一次做AGV(自动导引车)项目,小车死活走不对路线,折腾了两天才发现——我把全局坐标和局部坐标搞混了。嗯,从那以后,我再也不敢小看坐标系了。
3.1 为什么需要坐标系?
你想想看,机器人要完成从A点到B点的任务,它得知道两件事:
- 我在哪儿?——这是定位问题
- 目标在哪儿?——这是目标描述问题
这两个问题,都离不开坐标系。说白了,坐标系就是给空间中的点一个「身份证号」,让机器人能精确地知道每个位置。
核心概念:坐标系是描述物体位置和姿态的基准。没有坐标系,路径规划就是空中楼阁。
3.2 全局坐标系(World Coordinate System)
全局坐标系,也叫世界坐标系。它是固定不变的,是整个地图的「绝对参考系」。
我习惯把全局坐标系想象成一张地图的经纬度。不管你在北京的哪个角落,天安门广场的经纬度是固定的。同样,在机器人世界里,全局坐标系的原点和方向一旦定义好,就不再改变。
全局坐标系的特点:
- 固定不变,不随机器人移动而改变
- 所有物体(障碍物、目标点、机器人自身)都可以用全局坐标描述
- 通常以地图的某个角落或中心为原点
举个例子,假设我们的仓库地图是20米×30米,我一般会把原点设在左下角:
// 全局坐标系下的点
Point robotPosition = {x: 5.0, y: 3.0}; // 机器人位置
Point targetPosition = {x: 15.0, y: 25.0}; // 目标位置
Point obstaclePosition = {x: 10.0, y: 12.0}; // 障碍物位置
3.3 局部坐标系(Local Coordinate System)
局部坐标系就不一样了。它是「跟着机器人走的」。机器人往左转,它的局部坐标系也跟着往左转。
为什么要搞个局部坐标系?因为机器人身上的传感器(激光雷达、摄像头)都是装在它自己身上的。传感器看到的东西,天然就是局部坐标。
我的经验:做路径规划时,全局规划用全局坐标,局部规划用局部坐标。千万别混用!我曾经在一个项目中,直接把激光雷达的局部数据当成全局数据用,结果机器人对着墙就撞上去了……
局部坐标系的特点:
- 原点在机器人中心(或传感器安装位置)
- 方向随机器人旋转而旋转
- 通常X轴指向机器人前进方向,Y轴指向左侧
来看个具体的例子。假设机器人前方2米处有个障碍物:
// 局部坐标系下(机器人自身视角)
Point obstacleInLocal = {x: 2.0, y: 0.0}; // 正前方2米
// 如果机器人全局位置是(5,3),朝向是90度(朝北)
// 那么障碍物的全局坐标是多少?
// 这就需要坐标变换了!
3.4 齐次变换矩阵(Homogeneous Transformation Matrix)
好,关键来了。怎么把局部坐标变成全局坐标?或者反过来?
答案就是——齐次变换矩阵。
我第一次看到这个名词时,觉得好高大上。其实说白了,它就是一张「翻译表」,能把一个坐标系下的坐标,翻译到另一个坐标系下。
齐次变换矩阵的形式:
| R(3x3) t(3x1) |
| 0 0 0 1 |
其中:
R —— 旋转矩阵(描述两个坐标系之间的旋转关系)
t —— 平移向量(描述两个坐标系原点之间的偏移)
举个例子,假设机器人全局位置是(5, 3),朝向是0度(朝东)。那么从局部到全局的变换矩阵就是:
// 2D情况下的齐次变换矩阵
| cos(0) -sin(0) 5 |
| sin(0) cos(0) 3 |
| 0 0 1 |
// 简化后:
| 1 0 5 |
| 0 1 3 |
| 0 0 1 |
用这个矩阵,就可以把局部坐标(2, 0)变成全局坐标:
| 1 0 5 | | 2 | | 7 |
| 0 1 3 | × | 0 | = | 3 |
| 0 0 1 | | 1 | | 1 |
// 所以局部坐标(2,0) → 全局坐标(7,3)
关键理解:齐次变换矩阵把「旋转」和「平移」统一到了一个矩阵里。这样,多次变换就可以通过矩阵乘法串联起来,非常优雅。
3.5 坐标变换的链式法则
实际项目中,坐标变换往往不是一步到位的。比如:
- 激光雷达看到障碍物 → 得到传感器局部坐标
- 传感器装在机器人上 → 需要转到机器人坐标系
- 机器人在全局地图中 → 需要转到全局坐标系
这就形成了变换链:
T_global = T_robot_to_global × T_sensor_to_robot × P_sensor
其中:
P_sensor —— 传感器坐标系下的点
T_sensor_to_robot —— 传感器到机器人的变换
T_robot_to_global —— 机器人到全局的变换
避坑指南:我曾经犯过一个错误——把变换顺序搞反了。记住,矩阵乘法不满足交换律!先旋转后平移,和先平移后旋转,结果完全不同。一定要按照「从右到左」的顺序读变换链。
3.6 实践中的坐标系管理
做实际项目时,我建议你养成几个好习惯:
- 统一命名规范——比如用
_w表示全局坐标,_l表示局部坐标 - 画坐标系图——每次做变换前,先在纸上画清楚各个坐标系的关系
- 写单元测试——用已知点验证变换矩阵是否正确
下面是我常用的一个坐标系管理类模板:
class CoordinateManager {
public:
// 局部坐标转全局坐标
Point localToGlobal(const Point& localPoint) {
// 使用齐次变换矩阵
return transformMatrix * localPoint;
}
// 全局坐标转局部坐标
Point globalToLocal(const Point& globalPoint) {
// 使用逆矩阵
return inverseTransformMatrix * globalPoint;
}
private:
Matrix4x4 transformMatrix; // 变换矩阵
Matrix4x4 inverseTransformMatrix; // 逆变换矩阵
};
3.7 小结
这一章的内容,说白了就是三件事:
- 全局坐标系——固定不变,地图的绝对参考
- 局部坐标系——跟着机器人走,传感器的天然视角
- 齐次变换矩阵——连接两个坐标系的桥梁
我个人觉得,坐标系和坐标变换是路径规划中最基础也最容易出错的地方。你想想看,如果连「我在哪儿」都搞不清楚,后面的路径规划再漂亮也是白搭。
下一章,我们会把这些知识用起来,开始真正规划路径。到时候你会发现,今天学的这些变换,就是整个路径规划大厦的地基。
小练习:假设机器人全局位置是(10, 5),朝向是45度。激光雷达在机器人前方0.5米处,检测到一个障碍物在雷达坐标系下的位置是(1, 0)。请计算障碍物的全局坐标。
提示:先做传感器到机器人的变换,再做机器人到全局的变换。