4. Link详解:惯性属性、碰撞属性、视觉属性

各位好,我是你们的机器人建模课讲师。今天咱们深入聊聊 Link 这个家伙。你想想看,一个机器人模型里,Link 就是每一块“骨头”——底盘、手臂连杆、摄像头支架,全是它。URDF 里 Link 有三个核心属性:视觉 (visual)、碰撞 (collision) 和 惯性 (inertial)。很多人只把视觉画得漂漂亮亮,结果仿真一跑就穿模,或者动力学直接崩了。嗯,这里要注意,三个属性各有各的活儿,一个都不能少。

Link 三大属性 Link 机器人连杆 视觉 visual 几何 + 材质 碰撞 collision 物理边界 惯性 inertial 质量 + 惯量张量 每个属性都包含 origin / geometry / 特定参数

4.1 视觉属性 (visual) —— 面子工程,但必须做

视觉属性决定了机器人“长什么样”。说白了就是给 Link 套上一层皮,让它在 Rviz 或 Gazebo 里能被看到。我个人习惯把视觉几何做得稍微精细一点,方便调试时一眼认出哪个零件是哪个。

标准结构:
<link name="base_link">
  <visual>
    <origin xyz="0 0 0" rpy="0 0 0"/>
    <geometry>
      <box size="0.4 0.3 0.1"/>
    </geometry>
    <material name="blue">
      <color rgba="0 0 0.8 1"/>
    </material>
  </visual>
</link>

这里 origin 是视觉网格相对于 Link 坐标系的偏移。我记得有一次把 rpy 写成了 90 度,结果整个底盘在 Rviz 里是侧着飞的……排查了半天,最后发现是视觉原点没对齐。所以,视觉原点一定要和碰撞、惯性保持一致,否则你看到的和仿真算的不是同一个东西。

4.2 碰撞属性 (collision) —— 物理世界的硬边界

碰撞属性才是仿真引擎真正“摸得到”的几何。你视觉画得再花哨,碰撞体如果是个大箱子,那机器人就真的像个箱子一样去撞墙。我建议碰撞体尽量用简单的形状——盒子、圆柱、球体。为什么?因为复杂网格会让碰撞检测慢得像蜗牛。

避坑指南: 我曾经给一个机械臂的连杆用了 STL 网格做碰撞,结果 Gazebo 每步仿真都卡成 PPT。后来换成圆柱 + 盒子的组合,速度直接快了 10 倍。记住:碰撞几何越简单,仿真越流畅。
<collision>
  <origin xyz="0 0 0" rpy="0 0 0"/>
  <geometry>
    <cylinder radius="0.15" length="0.4"/>
  </geometry>
</collision>

你可能会问:碰撞体的 origin 和视觉的 origin 必须一模一样吗?不一定,但强烈建议保持一致。否则你看到机械臂还没碰到东西,仿真里已经撞上了——这种“灵异事件”我调过不止一次。

4.3 惯性属性 (inertial) —— 动力学的心脏

惯性属性是 Link 的“体重”和“转动惯量”。没有它,机器人就像在太空中飘——完全不受重力影响。URDF 里惯性包括质量 mass 和惯量张量 inertia(ixx, ixy, ixz, iyy, iyz, izz)。

⚠️ 常见翻车点: 很多人把惯量张量全填 0,或者随便写个对角线。结果机器人一跑就疯狂抖动,甚至直接炸飞。惯性参数必须符合物理,至少用 平行轴定理 估算一下。
<inertial>
  <origin xyz="0 0 0" rpy="0 0 0"/>
  <mass value="2.5"/>
  <inertia ixx="0.03" ixy="0" ixz="0"
            iyy="0.04" iyz="0"
            izz="0.03"/>
</inertial>

举个例子:一个 0.4m×0.3m×0.1m 的盒子,质量 2.5kg,质心在几何中心。那惯量大概就是上面那个数值。你可以用在线惯量计算器算一下,别凭感觉填。

4.4 三个属性的协作关系

视觉、碰撞、惯性,三者各自独立,但共用同一个 Link 坐标系。我习惯把它们写在一起,方便对照:

属性作用域推荐复杂度常见错误
visual可视化显示中等(可带材质)origin 偏移导致显示错位
collision物理碰撞检测尽量简单使用复杂网格导致仿真卡顿
inertial动力学计算精确估算惯量全零或随意填写

你想想看,如果视觉是个精细的机械臂模型,碰撞却是个大球,那仿真时机械臂还没碰到桌子,球就先撞上了——这显然不对。所以三个属性的几何中心最好重合,或者至少保证碰撞包络能真实反映机器人的外形。

我的个人习惯: 先写碰撞,再写视觉,最后补惯性。碰撞决定了机器人怎么和世界交互,视觉只是给人看的,惯性则是让机器人“有重量”。顺序对了,思路就顺了。

4.5 一个完整的 Link 示例

下面我把三个属性拼在一起,这是一个简单的机器人底盘 Link:

<link name="chassis">
  <visual>
    <origin xyz="0 0 0.05" rpy="0 0 0"/>
    <geometry>
      <box size="0.5 0.4 0.1"/>
    </geometry>
    <material name="dark_gray">
      <color rgba="0.2 0.2 0.2 1"/>
    </material>
  </visual>

  <collision>
    <origin xyz="0 0 0.05" rpy="0 0 0"/>
    <geometry>
      <box size="0.5 0.4 0.1"/>
    </geometry>
  </collision>

  <inertial>
    <origin xyz="0 0 0.05" rpy="0 0 0"/>
    <mass value="3.0"/>
    <inertia ixx="0.04" ixy="0" ixz="0"
              iyy="0.06" iyz="0"
              izz="0.04"/>
  </inertial>
</link>

注意这里 origin 的 z 偏移了 0.05,因为盒子的高度是 0.1,质心在几何中心,所以把原点抬高一半。嗯,这种细节最容易忘,但忘了机器人就“陷地”了。

好了,关于 Link 的三个属性就聊到这儿。视觉是面子,碰撞是里子,惯性是底子。三者配合好,你的 URDF 模型才算真正“活”了。下一章我们会讲 Joint,但今天先把 Link 吃透——毕竟关节连的就是这些 Link 嘛。