2、URDF基础回顾:文件结构、link与joint、坐标系与变换树

URDF,全称是 Unified Robot Description Format。说白了,它就是用来描述机器人长什么样、关节怎么动的一套 XML 语法。我刚开始接触机器人时,觉得这玩意儿就是个“零件清单”,后来踩了不少坑才明白——它其实是整个机器人系统的“骨架”和“神经”。

这一章,我们快速过一遍 URDF 的核心概念。如果你已经熟悉,可以当复习;如果你是新手,我建议你跟着代码敲一遍。

2.1 URDF 文件结构:从根到叶

一个标准的 URDF 文件,结构其实很清晰。它就像一棵树,根节点是 <robot>,下面挂着 <link> 和 <joint>。我习惯把 link 想象成“骨头”,joint 想象成“关节”。

<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.15" rpy="0 0 0"/>
  </joint>

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

你看,结构就这么简单。但要注意,每个 link 必须有唯一的 name,joint 也一样。我曾经在项目里因为两个 link 重名,Gazebo 直接崩溃,查了半天才发现是命名冲突。

我的习惯:命名时用“部位_功能”的格式,比如 left_wheel_link、arm_joint_1。这样后期维护时,一眼就能看出是哪个零件。

2.2 link 与 joint 的定义

2.2.1 link:机器人的“骨头”

link 描述的是刚体部分。它有三个主要子标签:visual(视觉)、collision(碰撞)、inertial(惯性)。

标签 作用 必填?
visual 定义外观,用于 Rviz 显示 推荐有
collision 定义碰撞模型,用于物理引擎 推荐有
inertial 定义质量、惯性矩阵 运动学仿真可选,动力学必填

嗯,这里要注意:visual 和 collision 可以不一样。比如一个复杂的机械臂,visual 用精细的 STL 模型,collision 用简单的圆柱体或长方体。这样显示好看,碰撞计算又快。

我曾经踩过的坑:做多机器人协同搬运时,忘了给一个 link 加 collision,结果 Gazebo 里两个机器人直接“穿模”了。物理引擎没有碰撞模型,就等于没有实体。

2.2.2 joint:机器人的“关节”

joint 连接两个 link,并定义它们之间的相对运动。URDF 支持 6 种 joint 类型:

类型 自由度 典型用途
fixed 0 固定连接,比如底座与支架
revolute 1(旋转) 电机驱动的旋转关节,有角度限制
continuous 1(旋转) 无限制旋转,比如车轮
prismatic 1(平移) 直线滑动关节,比如伸缩臂
floating 6 完全自由,常用于移动机器人底盘
planar 3(平面运动) 在平面上移动,比如 AGV

joint 里最重要的三个子标签:parent、child、origin。parent 是上一级 link,child 是下一级 link。origin 定义了 child link 相对于 parent link 的位置和姿态。

<joint name="arm_joint" type="revolute">
  <parent link="base_link"/>
  <child link="arm_link"/>
  <origin xyz="0.1 0 0.2" rpy="0 0 0"/>
  <axis xyz="0 0 1"/>
  <limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>

你看,axis 定义了旋转轴方向,limit 限制了角度范围。我建议你每次写完 joint,都手动算一下 origin 的坐标,别完全依赖可视化工具——有时候工具会骗人。

2.3 坐标系与变换树

URDF 里每个 link 都有自己的坐标系。这些坐标系通过 joint 连接起来,就形成了一棵“变换树”(Transform Tree)。

为什么会这样?因为机器人运动时,每个关节的角度变化,都会影响后续所有 link 的位置。变换树就是用来追踪这种“连锁反应”的。

核心原则:每个 link 的坐标系原点,默认在它的几何中心。但你可以通过 joint 的 origin 来调整相对位置。记住,子 link 的坐标是相对于父 link 的。

举个例子:一个两轮差速机器人,base_link 在底盘中心,左轮 left_wheel_link 的 origin 是 xyz="0 0.2 0",意思是左轮中心在 base_link 的 Y 轴正方向 0.2 米处。

嗯,这里要特别提醒:变换树必须是树状结构,不能有环。也就是说,一个 link 只能有一个父 link,不能有两个。我在做多机器人协同抓取时,曾经试图让两个机械臂共享一个末端执行器,结果 TF 树直接报错——因为一个 link 不能有两个爹。

2.4 标准标签详解

除了上面提到的,还有几个标签你一定会用到:

  • <geometry>:支持 box、cylinder、sphere、mesh。mesh 可以加载 STL 或 DAE 文件。
  • <material>:定义颜色或纹理。比如 <color rgba="1 0 0 1"/> 就是红色。
  • <inertial>:包含 <mass> 和 <inertia>。惯性矩阵 ixx、iyy、izz 等,如果不知道怎么算,可以用 SolidWorks 或 Fusion 360 导出。
  • <transmission>:定义关节与执行器之间的传动关系,用于 Gazebo 仿真。
我的建议:刚开始做 URDF 时,先用简单的几何体(box、cylinder)代替复杂 mesh。等运动学验证通过后,再替换成精细模型。这样调试速度快很多。

2.5 知识体系总览

下面这张图,帮你把本章的核心逻辑串起来:

URDF 核心知识体系 URDF 核心知识体系 URDF 文件 link(骨头) joint(关节) 变换树(TF) visual collision inertial parent/child origin axis / limit 树状结构,无环 坐标系相对父 link 核心原则:link 是刚体,joint 定义运动,变换树追踪所有坐标关系。三者缺一不可。 多机器人协同中,每个机器人都有自己的 URDF 和 TF 树,通过全局坐标系连接。

这张图把 URDF 的三大核心——link、joint、变换树——以及它们各自的子标签都串起来了。你写 URDF 时,就按这个结构来组织代码,不会乱。

2.6 避坑指南

最后,分享几个我实际项目中遇到的坑:

  • 坐标系方向搞反:有一次我把 rpy="1.57 0 0" 写成了 rpy="0 1.57 0",结果机械臂在 Rviz 里直接“拧麻花”。建议用 tf2_echo 工具实时查看坐标变换。
  • 惯性参数乱填:动力学仿真时,如果惯性矩阵填错,机器人会“飘”起来。我一般用 CAD 软件导出,或者用 urdf_sim_tutorial 里的估算脚本。
  • joint 类型选错:车轮应该用 continuous,结果我用了 revolute,导致车轮只能转 180 度。嗯,这种低级错误,犯过一次就记住了。
重要提醒:URDF 不支持闭环结构(比如平行四边形机构)。如果你需要闭环,可以考虑用 SDF 格式,或者在 URDF 里用 fixed joint 加虚拟 link 来近似。