08 · TF2 坐标变换
目标
发布静态外参 base_link → sensor_link,并用 listener 查询相对位姿。
概念
机器人上每个传感器、连杆都有坐标系(frame)。TF2 维护这些坐标系之间的变换树。
base_link ──(固定外参)──► sensor_link| 名词 | 含义 |
|---|---|
frame_id | 父坐标系 |
child_frame_id | 子坐标系 |
| Static TF | 相对位姿不变(如传感器安装位置) |
| Dynamic TF | 随时间变(如轮式里程计) |
本课:传感器在车体前方 0.2 m、上方 0.1 m。
通俗理解
TF 回答的是:“这个零件相对那个零件,在空间里偏了多少、转了多少?”
车上每个传感器、轮子、雷达都有自己的坐标系。若不知道激光相对车体装在哪,就无法把激光点变到地图上。TF2 维护这棵“坐标系树”。
本课是静态外参(螺丝拧死的安装位置):base_link → sensor_link 固定为前方 0.2 m、上方 0.1 m。轮子滚动带来的位姿变化属于动态 TF,以后里程计/定位会发。
逐步推导:静态外参怎样写成齐次变换,lookup 在求什么(点击展开)
传感器相对车体:沿车头
点在传感器系是 base_link←sensor_link 就是查这条边(或链上多边连乘)。静态 TF 走 /tf_static,不随时间变。动态里程计每拍更新 odom→base_link。名字写错或 broadcaster 未起,lookup 就说 frame 不存在——不是数学错了,是树没接上。
常见疑问
Q:TF 是一种 Topic 吗?
底层会通过 /tf、/tf_static 等话题传,但你通常用 TF API(broadcast/lookup),而不是自己解析原始消息。
Q:和 URDF 什么关系?
URDF 描述机器人结构;robot_state_publisher 会根据 URDF(和关节角)自动发很多 TF。本课是手写静态 TF,帮助先建立直觉。
Q:lookup 报 frame 不存在?
多半是 broadcaster 还没起来,或父子坐标系名字写错。先让 broadcaster 稳定跑着再 lookup。
Q:为什么要学这个?
几乎所有导航、感知、标定都依赖 TF。不懂 TF,后面仿真和 Nav2 会很懵。
动手
source /opt/ros/humble/setup.bash
source $ROS_WS/install/setup.bash终端 A:
ros2 run py_learning tf_broadcaster终端 B:
ros2 run py_learning tf_listener应看到:x=0.20 y=0.00 z=0.10。
也可:
ros2 run tf2_ros tf2_echo base_link sensor_link
ros2 run tf2_tools view_frames # 生成 frames.pdf(需 graphviz)关键命令
ros2 run tf2_ros tf2_echo base_link sensor_link
ros2 topic echo /tf_static --once对照代码
| 文件 | 作用 |
|---|---|
tf_broadcaster.py | 静态 TF 发布 |
tf_listener.py | 查询变换 |
小练习
- 把传感器改到左侧(
y=0.15),重新 build 观察 listener。 - 在 RViz 里加 TF 显示(Fixed Frame =
base_link)。
验证标准(给学员与 AI)
- [ ]
tf_broadcaster显示已发布静态 TF - [ ]
tf_listener打印约x=0.20 y=0.00 z=0.10 - [ ] 或
ros2 run tf2_ros tf2_echo base_link sensor_link有输出
失败时:broadcaster 需先于 listener 稳定运行。
小结
- TF = 机器人的“空间关系说明书”。
- 先搞懂静态外参,再学动态里程计 TF。
- 下一课:09 · cmd_vel