4、坐标变换基础:机器人坐标系定义与TF树
各位同学好,我是你们的老朋友。今天我们来聊聊坐标变换——说白了,就是让机器人知道「我在哪,要去哪,周围有啥」。这玩意儿是避障算法的地基,地基不稳,上面盖多高的楼都得塌。
我记得刚入行那会儿,有个项目机器人总撞墙。排查了三天,最后发现是odom和map坐标系搞混了。嗯,从那以后,我再也不敢小看坐标变换了。
4.1 机器人三大坐标系
ROS里定义了三个核心坐标系,我习惯把它们比作「身份证」「导航仪」和「世界地图」。
| 坐标系 | 作用 | 特点 |
|---|---|---|
| base_link | 机器人本体坐标系 | 原点在机器人中心,随机器人移动 |
| odom | 里程计坐标系 | 基于传感器积分,局部稳定但会漂移 |
| map | 全局地图坐标系 | 固定不变,用于全局定位 |
核心关系:map → odom → base_link,这是一个单向的树状结构。
你想想看,base_link是跟着机器人跑的,odom是里程计算出来的相对位置,map是全局固定的。三者之间通过TF树连接起来。
4.2 TF树概念
TF(Transform)树,说白了就是坐标系之间的「关系网」。每个坐标系是一个节点,变换关系是边。
我在项目中遇到过最典型的坑:TF树断链。有一次机器人定位突然跳变,查了半天,发现是某个子坐标系没有发布TF。机器人以为自己瞬移了,吓得我赶紧补上了广播。
避坑指南:我曾经在调试时发现,TF树的更新频率必须高于控制频率。否则机器人会拿到过时的坐标数据,撞墙是迟早的事。
TF树的特点:
- 有向无环图(DAG)结构
- 每个坐标系只有一个父节点
- 变换关系包含平移和旋转
- 支持时间戳,可以查询历史变换
4.3 欧拉角与四元数
说到旋转表示,我刚开始做机器人时只用欧拉角,因为直观。但后来发现,万向锁这玩意儿太坑了——你明明想转X轴,结果Y轴也跟着动了。
欧拉角:绕三个轴依次旋转,常用RPY(Roll滚转、Pitch俯仰、Yaw偏航)。
四元数:用四个数表示旋转,避免了万向锁。形式是 q = w + xi + yj + zk。
注意:欧拉角虽然直观,但做插值和组合时容易出问题。我建议在内部计算时统一用四元数,只在人机交互时转成欧拉角。
举个例子,把欧拉角转成四元数:
# Python示例:欧拉角转四元数
import tf.transformations as tft
roll, pitch, yaw = 0.1, 0.2, 0.3
quat = tft.quaternion_from_euler(roll, pitch, yaw)
print(quat) # [x, y, z, w]
4.4 齐次变换矩阵
齐次变换矩阵,说白了就是把旋转和平移打包成一个4x4矩阵。这样你只需要做矩阵乘法,就能完成坐标变换。
形式是这样的:
| R t |
| 0 1 |
其中R是3x3旋转矩阵,t是3x1平移向量。
我记得有一次做多传感器融合,需要把激光雷达的数据从传感器坐标系转到base_link。用齐次变换矩阵,一行代码搞定:
# 齐次变换示例
import numpy as np
T = np.array([[0.707, -0.707, 0, 0.1],
[0.707, 0.707, 0, 0.2],
[0, 0, 1, 0.3],
[0, 0, 0, 1 ]])
point_sensor = np.array([1.0, 0.0, 0.0, 1.0])
point_base = T @ point_sensor
print(point_base[:3]) # 变换后的坐标
为什么要用齐次坐标?因为你可以把多次变换串联起来,比如 T_map_base = T_map_odom * T_odom_base。这样一次矩阵乘法,就能从base_link直接变换到map。
4.5 知识体系总览
下面这张图,是我自己总结的坐标变换知识体系。你看一遍,心里就有谱了。
嗯,看到这张图,你应该能理解坐标变换在整个避障系统中的位置了。它不是孤立的知识点,而是连接传感器、控制、规划的桥梁。
我的建议:刚开始学的时候,别急着搞复杂的数学推导。先在ROS里跑一遍tf_echo,看看坐标系之间的变换关系。亲手操作一遍,比看十遍书都管用。
好了,这一章的内容就到这里。坐标变换是基础中的基础,后面讲避障算法时,我们会反复用到这些概念。你先把这些吃透,后面就轻松了。