教程 · 中级 · 阅读约 20 分钟
面向移动机器人的 ROS 2 TF2 坐标系
理解 ROS 2 的 TF2 变换树,以及 map、odom、base_link 和各传感器坐标系,再学会诊断缺失、过期和几何上不正确的变换。
一次激光扫描是相对激光头量的,轮子里程计的位姿是相对它自己的起始坐标系,而导航目标通常表达在一张地图里。要把它们比较起来,机器人需要在正确的时刻知道各坐标系之间的几何关系。ROS 2 的 TF2 系统负责存储并查询这棵随时间变化的变换树。
TF2 的大部分故障并不是高等数学。它们是一个缺失的父节点、一个方向搞反的变换、一个错误的时间戳,或者两个节点抢着拥有同一个坐标系关系。
用变换思考,而不是拷贝位姿
一个变换描述的是从父坐标系到子坐标系的平移和旋转。如果 base_link → laser 表示激光头在机器人底盘前方 0.20 m、上方 0.10 m 处,TF2 就能把激光测量变换到底盘坐标系。再把它和 odom → base_link 组合起来,就表达在局部里程计坐标里。
坐标系构成一棵树:每个子节点在任一时刻恰好有一个父节点。某条连接可以移动,但父子关系不能含糊。像 A → B → C → A 这样的环是无效的。
坐标系 id 是语义名,不是单位也不是数据。一个标着 laser 的点,仍然需要在它自己的测量时间戳上有一个匹配的变换。
用标准的移动机器人链
一个常见的导航树是:
map → odom → base_link → laser
→ camera_link
→ imu_link
每条连接各有分工:
- **
map → odom:**全局定位修正。定位纠正累积漂移时它可能发生变化。 - **
odom → base_link:**来自轮子/视觉/惯性里程计的平滑局部运动。它应当保持连续,但会漂移。 - **
base_link → sensor:**固定的安装几何,通常是一个静态变换。
把 map 和 odom 分开,能让全局修正发生而不让局部控制坐标系跳变。这些名字遵循 ROS 约定,但你的机器人可能会再加上 base_footprint、云台坐标系或者关节连杆。
决定每条边由谁发布
在启动节点之前先写一张归属表:
| 变换 | 典型归属者 | 类型 |
|---|---|---|
map → odom |
定位或 SLAM | 动态 |
odom → base_link |
里程计估计器 | 动态 |
base_link → laser |
机器人描述/静态广播器 | 静态 |
base_link → camera_link |
机器人描述/静态广播器 | 静态 |
每条边应当恰好由一个权威部件发布。两个发布者会产出交替或互相冲突的变换,看上去就像随机的位姿跳变。
静态变换描述的是实测的安装几何。把原点和轴朝向放在传感器模型期望的位置。相机的光学坐标系与典型机器人底盘坐标系用的轴约定不同,所以要照相应的 ROS 传感器约定来,而不是照着图纸猜。
检查活的变换树
先从命令行证据开始:
ros2 run tf2_tools view_frames
ros2 run tf2_ros tf2_echo odom base_link
ros2 run tf2_ros tf2_echo base_link laser
view_frames 生成一张图,显示连通性、发布者、更新率和时序信息。tf2_echo target source 报告把数据从源坐标系变换到目标坐标系的那个变换。把两个参数对调就看到逆变换,而这是个常见的困惑来源。
在 RViz 里要有意识地设置固定坐标系。如果固定坐标系是 map 而 map → odom 缺失,那么依赖里程计和传感器的显示就放不上去,哪怕它们自己的消息正在到达。
尊重测量时间戳
TF2 存储动态变换的历史。一条标着时刻 t 的传感器消息,应当用时刻 t 的那棵树来变换,而不是简单地用最新的那个变换。机器人一动这件事就很要紧:用一个更晚的位姿会让观测整体偏移。
所有节点用同一个时钟源。在仿真中,所有参与者必须在仿真时间上取得一致。在多台计算机上,时钟需要做到与传感器时序精度相称的同步。
“向未来外推”的错误通常意味着请求的时间戳比可用的变换更新。“向过去外推”则意味着请求的数据比 TF2 缓冲区更老。加大缓冲区也许能帮到真正延迟的数据,但它修不了时钟不一致或是在错误阶段生成的时间戳。
用简单的物理测试验证几何
数字看着合理,轴却可能是错的。一次测一个关系:
- 让机器人静止,把传感器点可视化在
base_link里。 - 在正前方放一个目标。变换后的位置应当落在预期的前向轴上。
- 原地转机器人。一个固定的世界目标在
odom里应当保持不动,除了里程计误差。 - 向前平移。传感器观测应当与底盘位姿一致地移动。
静态平移要从选定的原点量起,而不是从任意的外壳边缘。对一台平面机器人来说,一个错误的偏航符号会把扫描镜像,让墙看起来跟着车一起转。
在消费者的边界上变换数据
消费者应当说明它需要的目标坐标系,并请 TF2 变换带时间戳的数据。避免把平移和旋转的值手工拷贝进应用公式里;那会绕过时间同步、坐标系链接以及已确定四元数的处理。
如果某个变换可能比消息晚一点到达,就用 TF 感知的消息过滤器,或者用适合该节点的有界等待。不要为了等一个几何而无限期阻塞一个实时控制环。
坐标系 id 不要带前导斜杠,拼写和大小写保持一致。命名空间应当为多机器人系统做好规划,让 robot_1/base_link 和 robot_2/base_link 不可能冲突。
从错误形状诊断故障
- **两个坐标系之间连不上:**某条边缺失,或者发布者与消息里的坐标系名不一致。
- **树在两个位姿之间来回跳:**有两个节点在发布同一个子节点的变换。
- **传感器数据转了 90° 或被镜像:**静态朝向或光学坐标系约定错了。
- **数据落在运动后面:**时间戳错了、变换到得晚,或者消费者用了最新的变换。
- **机器人全局跳变而局部控制平滑:**这可能是合法的
map → odom定位修正。 - **定位一更新局部控制就跳:**一个全局位姿被错误地当成
odom → base_link发布出去了。 - **RViz 显示了消息却放不上去:**固定坐标系或树连通性错了。
差速里程计里积分出来的位姿天然提供 odom → base_link。SLAM 基础教程解释哪个全局估计器提供 map → odom,以及为什么这种分离重要。
探索关联图谱
本教程所属的搭建
包含本教程的项目和学习路线。
延伸阅读