第3章 Link详解:视觉、碰撞、惯性

兄弟们,今天咱们来啃一块硬骨头——<link> 标签。你想想看,一个机器人模型里最核心的零件就是这些连杆。没有它们,关节连个屁啊。我刚开始学URDF的时候,以为link就是个几何壳子,后来被物理仿真狠狠教育了一顿……嗯,这一章咱们就把视觉、碰撞、惯性这三个属性彻底聊透。

🔗 link 核心三属性 视觉 visual 碰撞 collision 惯性 inertial 显示外观 物理边界 质量/惯量

3.1 视觉属性 —— 让机器人“有模有样”

<visual> 说白了就是给机器人穿衣服。你模型再漂亮,没有视觉标签,在Rviz里就是一团灰。我个人习惯把视觉几何和碰撞几何分开写,这样调试的时候能快速定位问题。

标准结构:
<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.4 0.8 1.0"/>
        </material>
    </visual>
</link>

这里 <origin> 控制视觉网格相对于link坐标系的偏移。我记得有一次把视觉原点设错了,机器人看起来在漂移,查了半天才发现是rpy写成了“0.1 0 0”——差之毫厘,谬以千里。

3.2 碰撞属性 —— 物理引擎的“硬边界”

碰撞模型决定了你的机器人在Gazebo里会不会卡进地板,或者两个连杆能不能互相穿透。你想想看,如果碰撞模型比视觉模型还精细,仿真性能会直线下降。我建议碰撞几何尽量用简单形状:盒子、圆柱、球体。

避坑指南: 我曾经给一个机械臂的连杆用了非常精细的mesh做碰撞,结果Gazebo直接卡成PPT。后来换成圆柱体,速度飞起,而且碰撞检测一点问题没有。
<collision>
    <origin xyz="0 0 0" rpy="0 0 0"/>
    <geometry>
        <cylinder radius="0.05" length="0.3"/>
    </geometry>
</collision>

注意:碰撞属性里的 <origin> 和视觉里的可以不同。比如你视觉模型是个复杂的L形支架,但碰撞模型可以用两个盒子拼起来。这样做既保证视觉真实,又让物理计算轻快。

3.3 惯性属性 —— 动力学计算的灵魂

惯性参数是URDF里最容易被忽略、但影响最大的部分。没有惯性数据,机器人就像在太空中飘——关节一动就飞了。惯性矩阵 <inertia> 包含 ixx, ixy, ixz, iyy, iyz, izz 六个分量。

⚠️ 重要提醒: 质量 <mass> 必须大于0,惯性矩阵必须正定。我曾经见过有人把ixx写成0,结果仿真直接崩溃。如果你不确定惯性值,可以用urdf_to_graphviz配合check_urdf做初步验证。
<inertial>
    <origin xyz="0 0 0" rpy="0 0 0"/>
    <mass value="1.5"/>
    <inertia ixx="0.01" ixy="0" ixz="0"
             iyy="0.01" iyz="0"
             izz="0.01"/>
</inertial>

对于简单几何体,你可以用公式估算惯性。比如一个实心圆柱绕中心轴的惯量是 ½ m r²。我个人习惯先用SolidWorks或Fusion360导出惯性值,再手动微调。但如果你只是做移动底盘,用近似值也问题不大。

3.4 三个属性的协作关系

一个完整的link通常同时包含visual、collision、inertial。它们各自独立,但共同决定了机器人的“长相、碰撞、手感”。我见过很多新手只写visual,结果一进Gazebo就穿模。记住:仿真看collision,显示看visual,动力学看inertial。

属性主要用途性能影响推荐做法
visualRviz显示、视觉反馈低(仅渲染)可用复杂mesh
collision物理碰撞、接触检测高(每帧计算)用简单几何体
inertial动力学、力矩计算中(影响控制)尽量精确

我的经验: 在项目初期,我会把collision和visual设成一样,快速验证运动学。等进入动力学调试阶段,再单独优化collision和inertial。这样迭代效率最高。

3.5 一个完整的link示例

下面是一个机器人手臂连杆的完整定义。注意origin在不同属性里可以不同——比如视觉里把模型稍微旋转一点,但碰撞保持标准姿态。

<link name="arm_link">
    <visual>
        <origin xyz="0 0 0.15" rpy="0 0 0"/>
        <geometry>
            <mesh filename="package://robot_description/meshes/arm.stl"/>
        </geometry>
        <material name="gray"/>
    </visual>
    <collision>
        <origin xyz="0 0 0.15" rpy="0 0 0"/>
        <geometry>
            <box size="0.08 0.08 0.3"/>
        </geometry>
    </collision>
    <inertial>
        <origin xyz="0 0 0.15" rpy="0 0 0"/>
        <mass value="0.8"/>
        <inertia ixx="0.003" ixy="0" ixz="0"
                 iyy="0.003" iyz="0"
                 izz="0.001"/>
    </inertial>
</link>

看到没?三个属性的origin完全一致,这样质心、视觉中心、碰撞中心都在同一个点。但如果你有特殊需求,比如视觉模型需要偏移,完全可以单独调。只是别搞混了坐标系。

小技巧: 用 check_urdf 命令可以快速检查link是否缺少必要属性。我每次写完URDF都会跑一遍,避免低级错误。