第3章 TF与机器人模型:URDF中的TF配置
说实话,URDF 和 TF 的关系,就像骨架和关节。你光有模型文件,没有正确的 TF 树,机器人就是一摊零件。我刚开始做机器人时,总觉得 URDF 里写个 <joint> 就完事了,结果一跑 robot_state_publisher,TF 树乱成一锅粥。嗯,这一章咱们就把 URDF 里的 TF 配置彻底捋清楚。
3.1 URDF 模型中的 TF 配置
URDF 里每个 <joint> 都隐含了一个 TF 父子关系。parent 和 child 就是 TF 树的父子坐标系。我个人习惯在写 URDF 时,先把坐标系画在纸上——哪怕很潦草。你想想看,如果 base_link 到 laser_frame 的偏移写反了,后面所有传感器数据都会飘。
举个例子,一个差速底盘加激光雷达:
<joint name="base_to_laser" type="fixed">
<parent link="base_link"/>
<child link="laser_frame"/>
<origin xyz="0.2 0.0 0.15" rpy="0 0 0"/>
</joint>
这段代码告诉 robot_state_publisher:laser_frame 相对于 base_link 的平移是 (0.2, 0, 0.15) 米,旋转为零。说白了,这就是一个静态 TF 广播。
3.2 joint_state_publisher 与 robot_state_publisher
这两个工具是 URDF 转 TF 的左右手。我见过不少新手把两者搞混,其实分工很明确:
| 组件 | 职责 | 发布内容 |
|---|---|---|
| robot_state_publisher | 读取 URDF,结合关节角度,发布所有 link 之间的 TF | TF (transform) + 关节状态 (joint_states) |
| joint_state_publisher | 提供关节角度值(GUI 或来自硬件/仿真) | sensor_msgs/JointState |
实际流程是:joint_state_publisher 发布关节角度 → robot_state_publisher 订阅后,根据 URDF 运动学树计算出每个 link 的位姿,再广播 TF。嗯,这里有个坑——我曾经在项目里忘了设置 use_gui 参数,结果 joint_state_publisher 直接不发布消息,TF 树缺了一大片。
joint_state_publisher_gui 手动拖动关节,验证 URDF 运动学是否正确。等确认无误再切换到硬件发布。
3.3 TF 与传感器数据融合
传感器数据要“翻译”到机器人坐标系,全靠 TF。比如激光雷达扫描的点,是在 laser_frame 下表达的。但导航栈需要的是 base_link 下的数据。这时候 tf::transform 就派上用场了。
我记得有一次调试多传感器融合,IMU 的数据总是和视觉里程计对不上。查了半天,发现 IMU 的坐标系约定和 URDF 里定义的 imu_link 差了 90 度。说白了,就是 <origin rpy="1.57 0 0"/> 写成了 0 0 0。这种问题用 tf_echo 一眼就能看出来。
rviz 的 TF 显示逐帧核对。
融合多个传感器时,TF 树会变得复杂。比如你有双目相机、IMU、激光雷达,每个传感器都有自己的坐标系。我的做法是:在 URDF 里用固定关节把它们都挂在 base_link 下,然后用 robot_state_publisher 统一管理。这样任何传感器数据都能通过 TF 变换到机器人中心。
实战要点总结:
- URDF 的 joint 就是 TF 的“静态边”,
type="fixed"对应tf_static。 - 确保
robot_state_publisher能加载你的 URDF,并且joint_state_publisher在发布有效关节值。 - 传感器融合前,先用
tf_monitor或view_frames检查 TF 树是否完整。 - 如果发现某个坐标系漂移或缺失,八成是 URDF 里的
origin写错了,或者 joint 类型不匹配。
嗯,这一章的内容其实就围绕一个核心:URDF 定义了几何和关节,robot_state_publisher 把它们变成活的 TF 树,而传感器数据融合就是在这棵树上做坐标变换。你只要把 URDF 写对,后面的工作就顺了。