2. URDF核心标签详解:<link>、<visual>、<collision> 与 <inertial>
上一章我们搭好了 URDF 的基本骨架,知道了 link 和 joint 是机器人的「骨头」和「关节」。但光有骨头可不够——你得告诉 ROS:这个零件长什么样?撞到东西怎么办?重心在哪?
说白了,<link> 标签才是真正定义「一个刚体」全部物理属性的地方。我刚开始学的时候,以为随便写个 box 就能跑,结果一仿真机器人直接飞了……嗯,后来才明白,惯性参数没配好,物理引擎会给你「惊喜」。
2.1 <link> 标签——机器人的「骨头」
每个 link 代表一个刚体。你可以把它想象成一块铁疙瘩——不会变形,不会自己动。在 URDF 里,link 必须有一个名字,而且名字要唯一。
<link name="base_link">
<!-- 这里放 visual, collision, inertial -->
</link>
我个人习惯把 base_link 作为机器人的根坐标系。你想想看,如果连根都没有,后面的关节往哪挂?
2.2 <visual> 属性——让机器人「看得见」
<visual> 定义的是「看起来什么样」。它不影响物理碰撞,只影响显示。说白了就是给机器人穿衣服。
<link name="arm_link">
<visual>
<origin xyz="0 0 0.5" rpy="0 0 0"/>
<geometry>
<cylinder length="1.0" radius="0.1"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
</link>
这里有个坑:<origin> 的 rpy 是绕固定轴旋转的,顺序是 Z-Y-X。我在项目里见过有人把 rpy 写反了,结果机械臂在 Rviz 里扭成了麻花……
2.3 <collision> 属性——让机器人「有边界」
<collision> 是给碰撞检测用的。它和 <visual> 结构几乎一样,但几何体可以更简化。为什么?因为碰撞检测算的是「有没有碰到」,不需要精细到每个螺丝孔。
<collision>
<origin xyz="0 0 0.5" rpy="0 0 0"/>
<geometry>
<cylinder length="1.0" radius="0.12"/>
</geometry>
</collision>
注意看,我把 radius 从 0.1 加到了 0.12。这是故意的——给碰撞包络留一点余量,防止因为视觉误差导致「看起来没碰到,实际上卡住了」。我曾经在产线上遇到过这种情况,机器人抓取时老是报碰撞,后来发现 collision 和 visual 完全一样,稍微放大一点就好了。
2.4 <inertial> 惯性参数配置——让机器人「有重量」
这是最容易忽略、也最容易出问题的地方。没有惯性参数,机器人就像纸糊的一样——仿真里一碰就飞,或者根本动不了。
<inertial>
<mass value="2.0"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0"
iyy="0.01" iyz="0.0"
izz="0.01"/>
<origin xyz="0 0 0.25" rpy="0 0 0"/>
</inertial>
这里有几个关键点:
- mass:质量,单位 kg。别写太大也别写太小,真实机器人多少就写多少。
- inertia:惯性张量,6 个独立分量(ixx, ixy, ixz, iyy, iyz, izz)。对于简单几何体,可以用公式估算。
- origin:质心位置。默认是 link 坐标系原点,但实际质心往往不在那里。
你可能会问:「惯性张量怎么算?」嗯,对于圆柱体,绕轴线的转动惯量是 ½ m r²,垂直轴线的是 ¼ m r² + 1/12 m l²。我一般写个小脚本算,或者直接用 SolidWorks 导出。
2.5 完整示例:一个带视觉、碰撞和惯性的 link
<link name="shoulder_link">
<visual>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<geometry>
<box size="0.2 0.2 0.6"/>
</geometry>
<material name="red">
<color rgba="0.8 0.2 0.1 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<geometry>
<box size="0.22 0.22 0.62"/>
</geometry>
</collision>
<inertial>
<mass value="3.5"/>
<inertia ixx="0.05" ixy="0.0" ixz="0.0"
iyy="0.05" iyz="0.0"
izz="0.02"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
</inertial>
</link>
这个 shoulder_link 是一个长方体,视觉尺寸 0.2×0.2×0.6,碰撞稍微大一圈,质量 3.5kg,质心在几何中心。你看,其实没那么复杂。
2.6 常见错误与避坑
- 忘记写 <inertial>:ROS 不会报错,但 Gazebo 会直接忽略这个 link,导致仿真异常。
- 惯性张量全零:物理引擎会除零崩溃。我见过有人从网上复制代码,ixx=0 没改,结果一运行就段错误。
- collision 比 visual 小:这会导致「视觉上没碰到,但碰撞检测已经触发了」,反过来也可能漏检。建议 collision 比 visual 大 5%~10%。
- origin 的 rpy 乱写:尤其是旋转顺序搞错。记住:URDF 里 rpy 是绕固定轴 Z-Y-X 旋转。
check_urdf 命令可以快速验证语法。再用 urdf_to_graphiz 生成结构图,一眼就能看出 link 和 joint 的关系对不对。
好了,这一章的内容就是这些。<link> 标签虽然基础,但它是整个 URDF 的基石。下一章我们会聊关节——让这些刚体真正动起来。