3、机器人URDF模型:URDF语法、link与joint定义、标准机器人模型示例

说到机器人建模,URDF 是绕不开的第一道坎。我刚开始接触 ROS 时,觉得这玩意儿不就是个 XML 嘛,随便写写就行。结果第一次在仿真里看到机器人胳膊拧成麻花,我才意识到——URDF 里的每一个数字,都决定了你的机器人能不能好好干活。

说白了,URDF 就是机器人的「骨架说明书」。它告诉系统:你有几个部件、它们长什么样、怎么连在一起的。没有它,MoveIt 根本不知道你要控制什么。

3.1 URDF 语法基础

URDF 基于 XML 格式,核心就两个东西:link 和 joint。一个描述「刚体部件」,一个描述「连接关系」。我习惯把 link 想象成骨头,joint 想象成关节。

核心原则:每个 link 必须有且只有一个 parent joint(根 link 除外)。joint 连接两个 link,形成树状结构。不能有闭环——至少原生 URDF 不行。

来看一个最简的 URDF 骨架:

<robot name="my_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
    </visual>
  </link>

  <joint name="base_to_arm" type="fixed">
    <parent link="base_link"/>
    <child link="arm_link"/>
    <origin xyz="0 0 0.05"/>
  </joint>

  <link name="arm_link">
    <visual>
      <geometry>
        <cylinder length="0.3" radius="0.02"/>
      </geometry>
    </visual>
  </link>
</robot>

嗯,这里要注意:origin 定义的是 child link 相对于 parent link 的位置偏移。我见过不少新手把坐标写反,结果机器人部件满天飞。

3.2 link 定义详解

一个完整的 link 包含三部分:视觉(visual)、碰撞(collision)、惯性(inertial)。

元素 作用 是否必须
visual 显示用的几何形状和颜色 推荐有
collision 物理碰撞检测用的形状 运动规划必须
inertial 质量、惯性矩阵 动力学仿真必须

我的经验:visual 和 collision 可以不一样。比如一个复杂的机械臂末端,visual 用精细的 STL 模型,collision 用简单的圆柱或长方体。这样仿真跑得快,看着也漂亮。

惯性参数最容易出错。我曾经在项目里忘了给某个 link 加 inertial,结果 MoveIt 规划出来的轨迹像喝醉了一样。后来养成了习惯:每个 link 写完立刻补上惯性数据。

<link name="arm_link">
  <inertial>
    <mass value="1.5"/>
    <inertia ixx="0.01" ixy="0" ixz="0"
             iyy="0.01" iyz="0"
             izz="0.005"/>
  </inertial>
  <visual>
    <geometry>
      <cylinder length="0.3" radius="0.02"/>
    </geometry>
    <material name="blue">
      <color rgba="0 0 1 1"/>
    </material>
  </visual>
  <collision>
    <geometry>
      <cylinder length="0.3" radius="0.02"/>
    </geometry>
  </collision>
</link>

3.3 joint 定义详解

joint 的类型决定了机器人的自由度。ROS2 里常用的有五种:

  • revolute:旋转关节,有角度限制。比如肘关节。
  • continuous:无限旋转关节。比如车轮。
  • prismatic:平移关节。比如滑轨。
  • fixed:固定连接。两个 link 焊死了。
  • floating:6 自由度浮动。一般不用在机械臂上。

你想想看,如果选错了 joint 类型,MoveIt 会怎么处理?它要么报错,要么生成完全错误的轨迹。我见过有人把旋转关节写成 prismatic,结果机械臂「伸缩」着去抓东西——画面太美不敢看。

<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="20" velocity="1.0"/>
</joint>

axis 定义旋转轴方向,limit 里的 effort 和 velocity 是给运动规划用的约束。我建议一开始就把限位设得保守一点,等调试好了再放开。否则机器人撞到东西,哭都来不及。

3.4 标准机器人模型示例

下面是一个简化的 2 自由度机械臂 URDF。我拿它当模板用了好几年:

<robot name="simple_arm">
  <link name="base">
    <visual>
      <geometry><box size="0.2 0.2 0.05"/></geometry>
      <material name="gray"/>
    </visual>
  </link>

  <joint name="joint1" type="revolute">
    <parent link="base"/>
    <child link="link1"/>
    <origin xyz="0 0 0.025"/>
    <axis xyz="0 0 1"/>
    <limit lower="-1.57" upper="1.57" effort="10" velocity="0.5"/>
  </joint>

  <link name="link1">
    <visual>
      <geometry><box size="0.03 0.03 0.2"/></geometry>
      <material name="blue"/>
    </visual>
  </link>

  <joint name="joint2" type="revolute">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0 0 0.1"/>
    <axis xyz="0 1 0"/>
    <limit lower="-2.0" upper="2.0" effort="8" velocity="0.5"/>
  </joint>

  <link name="link2">
    <visual>
      <geometry><box size="0.03 0.03 0.15"/></geometry>
      <material name="red"/>
    </visual>
  </link>
</robot>

避坑指南:我曾经在写 joint 的 origin 时,忘了把 child link 的坐标系原点对齐到关节位置。结果机械臂在仿真里像断了线的木偶。记住:origin 是 child link 相对于 parent link 的变换,不是关节本身的位置。

3.5 URDF 知识体系总览

下面这张图是我自己总结的 URDF 结构,每次写模型前都会瞄一眼:

robot link(刚体部件) joint(连接关系) visual collision inertial parent/child origin axis 树状结构:每个 joint 连接一个 parent link 和一个 child link 不允许出现闭环(除非使用 xacro 或 ros2_control 扩展) joint 类型速查 revolute → 有限旋转 continuous → 无限旋转 prismatic → 平移 fixed → 固定连接 floating → 6自由度

3.6 调试 URDF 的小技巧

写完 URDF 别急着跑 MoveIt。先用 check_urdf 工具检查语法:

# 安装工具
sudo apt install liburdfdom-tools

# 检查 URDF 文件
check_urdf my_robot.urdf

然后在 Rviz 里可视化看看:

# 启动 robot_state_publisher
ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:=$(cat my_robot.urdf)

# 启动 Rviz 查看
ros2 run rviz2 rviz2

我个人习惯在 Rviz 里把机器人转一圈,看看每个 joint 的运动方向对不对。如果发现某个关节反了,改 axis 或者 origin 的 rpy 就行。

实用技巧:用 urdf_to_graphviz 可以把 URDF 转成树状图,一眼看出父子关系对不对。命令:urdf_to_graphviz my_robot.urdf

URDF 是 ROS2 机器人建模的基石。写的时候多花点心思,后面 MoveIt 配置、运动规划、仿真调试都会顺畅很多。别像我当年那样,为了省事随便写写,结果 debug 花了两天——得不偿失。