URDF模型基础:文件结构、link与joint定义、标准格式与常见错误

URDF,全称是Unified Robot Description Format。说白了,它就是机器人的「身份证」加「骨架图」。你要让MoveIt认识你的机器人,第一步就得把URDF写好。

我记得刚入行那会儿,总觉得URDF就是个简单的XML文件,随便写写就行。结果呢?模型加载出来,机械臂在空中乱飘,关节转反方向……嗯,从那以后我再也不敢小看这个文件了。

核心认知:URDF不是给人类看的说明书,而是给ROS和MoveIt吃的「结构化数据」。格式错一个标签,模型就废了。

2.1 URDF文件整体结构

一个标准的URDF文件,长什么样?我直接给你看个最简框架:

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

  <joint name="joint1" type="revolute">
    <parent link="base_link"/>
    <child link="arm_link"/>
    <origin xyz="0 0 0.1" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>

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

你看,结构其实很清晰:<robot>是根节点,里面交替出现<link>和<joint>。每个link代表一个刚体部件,每个joint描述两个link之间的连接关系。

我个人习惯把URDF想象成一棵「树」:base_link是树根,关节是树枝的分叉点,link是树枝本身。你想想看,如果树根没定义好,整棵树都是歪的。

URDF 结构树(机器人描述文件骨架) <robot> <link> base_link <link> arm_link <joint> joint1 visual / collision visual / collision 关键规则: • 每个 joint 必须有且仅有一个 parent link 和一个 child link • link 可以没有 joint(如 base_link),但不能有「悬空」的 joint

2.2 link的定义与属性

link代表机器人的一个刚体部件。每个link可以包含三部分:visual(视觉)、collision(碰撞)和inertial(惯性)。

我在项目中遇到过最坑的事:只写了visual,没写collision。结果MoveIt做运动规划时,机械臂直接「穿模」了——因为碰撞检测根本没生效。

子标签 作用 是否必填 常见坑点
<visual> 定义显示用的几何形状 推荐 原点偏移导致模型显示错位
<collision> 定义碰撞检测用的几何体 强烈推荐 形状比visual大太多,规划器误判
<inertial> 定义质量、惯性矩阵 运动学仿真必填 惯性矩阵不填,仿真直接崩

我的习惯:visual和collision用完全相同的几何体和原点位置。除非你有特殊需求(比如为了简化碰撞计算),否则保持一致最安全。

来看一个完整的link示例:

<link name="forearm_link">
  <visual>
    <origin xyz="0 0 0.15" rpy="0 0 0"/>
    <geometry>
      <cylinder length="0.3" radius="0.04"/>
    </geometry>
    <material name="blue">
      <color rgba="0 0 1 1"/>
    </material>
  </visual>

  <collision>
    <origin xyz="0 0 0.15" rpy="0 0 0"/>
    <geometry>
      <cylinder length="0.3" radius="0.04"/>
    </geometry>
  </collision>

  <inertial>
    <mass value="0.5"/>
    <inertia ixx="0.001" ixy="0" ixz="0"
             iyy="0.001" iyz="0"
             izz="0.001"/>
  </inertial>
</link>

2.3 joint的定义与类型

joint是URDF的灵魂。它决定了两个link之间怎么动。ROS一共支持6种joint类型,但常用的其实就4种。

类型 运动方式 自由度 典型应用
revolute 绕轴旋转(有限角度) 1 机械臂关节
continuous 绕轴旋转(无限角度) 1 车轮、转台
prismatic 沿轴直线移动 1 滑轨、升降台
fixed 固定连接,不能动 0 传感器支架、末端工具
floating 6自由度自由运动 6 移动机器人基座(少用)
planar 平面内2平移+1旋转 3 AGV底盘(少用)

joint的核心属性有三个:parent、child和origin。origin定义了child link相对于parent link的位姿偏移。这个偏移量一旦写错,整个运动学链就全歪了。

曾经踩过的坑:我写一个六轴机械臂的URDF,第五个关节的origin.rpy写反了符号。结果仿真时机械臂末端轨迹画了个「8」字形,查了整整两天才找到问题。记住:rpy的顺序是绕固定轴X→Y→Z,不是绕自身轴!

2.4 标准格式与命名规范

URDF本身不强制命名规则,但ROS社区有约定俗成的规范。我个人建议你从一开始就遵守:

  • link命名:使用小写+下划线,如base_link、shoulder_link、forearm_link
  • joint命名:与对应的child link对应,如shoulder_joint连接shoulder_link
  • 坐标系:每个link的坐标系原点尽量放在关节轴线上
  • 单位:长度用米,角度用弧度,质量用千克

你想想看,如果命名乱七八糟,link_1、jnt_a、part_03混着用,后期调试MoveIt的时候,你根本分不清哪个是哪个。

2.5 常见错误与避坑指南

这部分是我最想跟你分享的。URDF的错误,90%都集中在下面几个地方:

错误排行榜:

  1. joint的parent/child写反——模型加载后link乱飞
  2. origin的xyz/rpy算错——关节位置偏移,运动学链断裂
  3. collision漏写——MoveIt规划时无视障碍物
  4. inertial缺失——Gazebo仿真直接报错
  5. axis方向错误——关节转动方向与预期相反

我曾经接手过一个项目,同事写的URDF里,所有joint的parent和child都写反了。结果base_link成了最末端的叶子节点,整个树结构倒过来了。MoveIt加载后,机械臂的末端执行器「长」在了基座上。

调试小技巧:用check_urdf命令检查语法,用urdf_to_graphiz生成结构图。这两个工具能帮你快速定位90%的格式错误。

还有一个容易忽略的点:浮点数精度。URDF里不要写0.0000001这种极小的值,MoveIt的数值求解器可能会因为精度问题卡住。我一般把小于1e-6的值直接写成0。

嗯,URDF的基础就这些。记住一句话:URDF写得越规范,后面MoveIt调得越省心。别图省事跳过collision或inertial,后面补的代价比一开始写好要大得多。