第3章 · 机器人URDF模型基础
URDF,全称 Unified Robot Description Format,是 ROS 生态里描述机器人结构的“通用语言”。说白了,它就是一套 XML 标签,用来告诉系统:你的机器人长什么样、关节在哪、连杆怎么连。我刚开始接触 MoveIt 时,觉得 URDF 就是个“模型文件”,后来踩了不少坑才明白——URDF 是运动规划的基石,写不好后面全是白搭。
3.1 URDF 语法与核心标签
URDF 文件以 <robot> 为根标签,里面主要就两样东西:link 和 joint。你可以把 link 想象成机器人的“骨头”,joint 就是连接骨头的“关节”。
💡 我的习惯:写 URDF 之前,先在纸上画一个连杆关节图。哪怕只有三个关节,画清楚父子关系能省一半调试时间。
一个典型的 link 包含视觉、碰撞和惯性参数。joint 则定义运动类型和父子关系。下面这张表是我经常翻看的速查:
| 标签 | 属性/子标签 | 说明 |
|---|---|---|
<link> | <visual>, <collision>, <inertial> | 描述连杆的外观、碰撞模型、质量与惯性张量 |
<joint> | type (revolute, prismatic, fixed…), <parent>, <child>, <origin>, <axis>, <limit> | 定义关节类型、运动轴、位置极限 |
<geometry> | <box>, <cylinder>, <sphere>, <mesh> | 几何形状,mesh 可加载 STL/DAE 文件 |
嗯,这里要注意:<origin> 的 xyz 和 rpy 是相对于父连杆的变换,很多人把 rpy 顺序搞反,结果模型在 RViz 里扭成麻花。我曾经因为一个 joint 的 rpy 写成了 “0 0 1.57” 而不是 “0 0 1.5708”,导致末端执行器偏了 90 度,查了半小时……
3.2 创建一个简单的机械臂 URDF
我们直接上手。假设做一个两自由度的串联臂:基座 → 肩关节 → 上臂 → 肘关节 → 前臂。下面是一个极简但完整的 URDF 片段:
<robot name="simple_arm">
<link name="base_link">
<visual>
<geometry><box size="0.2 0.2 0.1"/></geometry>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
</visual>
</link>
<joint name="shoulder_joint" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="10" velocity="1"/>
</joint>
<link name="upper_arm">
<visual>
<geometry><cylinder radius="0.04" length="0.3"/></geometry>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
</visual>
</link>
<joint name="elbow_joint" type="revolute">
<parent link="upper_arm"/>
<child link="forearm"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-2.0" upper="2.0" effort="8" velocity="1"/>
</joint>
<link name="forearm">
<visual>
<geometry><box size="0.05 0.05 0.25"/></geometry>
<origin xyz="0 0 0.125" rpy="0 0 0"/>
</visual>
</link>
</robot>
✏️ 避坑指南:我曾经把 <limit> 的 effort 写得太小,结果仿真时关节一动就报错“effort exceeded”。其实 effort 单位是 N·m,对于小臂设 10 就够,别照搬工业机器人动辄几百的值。
你想想看,这个 URDF 里每个 joint 都指定了 parent 和 child,ROS 的 robot_state_publisher 就是靠这个树状结构发布 tf 变换。如果关节类型是 fixed,那就相当于一个刚性连接,不会动。
3.3 在 RViz 中可视化 URDF 模型
写好了 URDF,怎么看到它?我建议用 urdf_tutorial 包里的 display.launch,或者自己写一个简单的 launch 文件:
<launch>
<param name="robot_description" textfile="$(find your_pkg)/urdf/simple_arm.urdf"/>
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"/>
<node name="joint_state_publisher_gui" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui"/>
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find your_pkg)/config/display.rviz"/>
</launch>
启动后,你会看到 RViz 里出现你的机械臂。拖动关节滑块,模型实时响应。我个人习惯在 RViz 里添加 “RobotModel” 显示,并把 “Fixed Frame” 设为 base_link。如果模型没出现,八成是 robot_description 参数没加载成功,或者 joint 的 parent/child 拼写不一致。
⚠️ 注意:URDF 中所有 link 名称必须唯一,joint 名称也必须唯一。我曾经把两个 link 都命名为 “link1”,结果 robot_state_publisher 直接崩溃,连错误日志都不明显。检查了半小时才发现是重名。
还有一个小技巧:在 RViz 里勾选 “Show Axes” 可以查看每个 link 的坐标系方向。如果你发现某个关节旋转方向反了,检查 joint 的 <axis> 正负号。比如绕 Y 轴旋转,xyz="0 1 0" 和 "0 -1 0" 方向完全相反。
🔧 我个人的工作流:每次修改 URDF 后,不急着跑 MoveIt,先在 RViz 里用 joint_state_publisher_gui 手动转一转每个关节。看看运动范围是否合理,连杆有没有穿插。这一步能过滤掉 80% 的模型错误。
最后说一句,URDF 虽然基础,但它是 MoveIt 配置包(SRDF)的输入。嗯,模型能在 RViz 里正常显示、关节能平滑运动,就算过关了。