3、机械臂URDF模型解析:URDF语法、link与joint定义、在Rviz中可视化。

URDF,全称是 Unified Robot Description Format。说白了,它就是ROS世界里描述机器人长什么样的标准语言。你想想看,要让机械臂在Rviz里动起来,总得告诉系统它有几个关节、几根连杆、长什么形状吧?URDF就是干这个的。

我个人习惯,每次开始一个新机械臂项目,第一件事就是先把URDF搭起来。哪怕后面要改,也得先有个骨架。今天我们就来拆解这个骨架。

3.1 URDF的语法基础:XML标签

URDF本质上是XML文件。所以它的语法就是标签套标签。根标签是 <robot>,里面再放 <link> 和 <joint>。

一个最简单的URDF骨架长这样:

<robot name="my_arm">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.2 0.2 0.1"/>
      </geometry>
    </visual>
  </link>

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

嗯,这里要注意:<robot> 标签的 name 属性不能乱写,它会在后续的命名空间里出现。我见过有人把名字写成带空格的,结果编译直接报错。

3.2 link:机械臂的每一块骨头

每个 <link> 代表一个刚体部件。比如底座、大臂、小臂、末端执行器。每个link里可以定义三部分:视觉(visual)、碰撞(collision)、惯性(inertial)。

子标签 作用 是否必须
<visual> 定义显示用的几何形状和颜色 推荐有
<collision> 定义碰撞检测用的几何体 推荐有
<inertial> 定义质量、质心、惯性张量 仿真必须

我在项目中遇到过一个问题:visual和collision用了不同的几何体,结果Rviz里看着没撞上,但Gazebo里机械臂直接穿模了。后来我学乖了,除非有特殊优化需求,否则visual和collision用同一套几何体。

几何体支持三种基本形状:

  • <box>:长方体,用size指定长宽高
  • <cylinder>:圆柱体,用radius和length
  • <sphere>:球体,用radius
  • <mesh>:导入STL或DAE文件,最常用
我的习惯: 原型阶段用box和cylinder快速搭骨架,等机械臂结构定型了再换成mesh文件。这样迭代速度快很多。

3.3 joint:关节的定义与类型

joint把两个link连接起来。每个joint必须指定parent和child。方向是从parent指向child。

ROS2支持6种关节类型,但机械臂常用的就下面几种:

类型 说明 自由度 机械臂场景
revolute 旋转关节,有角度限制 1 肩关节、肘关节
continuous 无限旋转关节 1 末端旋转
prismatic 平移关节 1 伸缩臂
fixed 固定连接 0 传感器安装座

定义joint时,<origin> 和 <axis> 是最容易出错的。origin定义的是child link相对于parent link的位姿。axis定义旋转轴或平移方向。

<joint name="shoulder_pan" type="revolute">
  <parent link="base_link"/>
  <child link="shoulder_link"/>
  <origin xyz="0 0 0.15" rpy="0 0 0"/>
  <axis xyz="0 0 1"/>
  <limit lower="-3.14" upper="3.14" effort="100" velocity="1.0"/>
</joint>
曾经踩过的坑: 我曾经把origin的rpy写成了"0 0 90",结果机械臂在Rviz里直接歪了90度。找了半天才发现rpy的单位是弧度,不是角度。记住:rpy用弧度,别用度。

3.4 坐标系与变换树

URDF里每个link都有一个自己的坐标系。joint的origin定义了子link坐标系相对于父link坐标系的变换。这些变换串起来,就形成了TF树。

为什么这个重要?因为Rviz里显示机械臂,靠的就是TF树。如果某个joint的origin写错了,整个机械臂的位姿都会乱掉。

我个人习惯,在写URDF之前,先在纸上画一遍坐标系。标出每个joint的原点位置和旋转轴方向。画清楚了再写代码,基本不会出错。

3.5 在Rviz中可视化

URDF写好了,怎么验证?直接扔进Rviz看。

步骤很简单:

  1. 启动Rviz:rviz2
  2. 添加RobotModel显示插件
  3. 在Description话题里填入你的URDF内容

但更推荐的做法是用 robot_state_publisher 节点。它会自动读取URDF并发布TF和关节状态。

# 启动robot_state_publisher
ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:=<你的urdf文件路径>

然后在Rviz里添加RobotModel,把Description话题设为 /robot_description。这时候你应该能看到机械臂的模型了。

调试技巧: 如果Rviz里看不到模型,先检查终端有没有报错。最常见的错误是URDF语法错误,比如标签没闭合、属性名拼错。用 check_urdf 工具可以快速验证:check_urdf your_robot.urdf。

3.6 本章知识体系

下面这张图总结了URDF的核心结构:

URDF 核心结构图 <robot> <link> <joint> visual / collision / inertial parent / child / origin / axis link 定义刚体,joint 定义连接关系 多个 link + joint 串联形成运动链 Rviz 可视化依赖 TF 树 每个 joint 的 origin 决定坐标系变换

3.7 常见错误与避坑指南

写URDF的时候,有几个坑我几乎每次都会遇到:

  • 标签大小写:URDF标签名全是小写,<Link> 不行,必须是 <link>
  • joint的parent和child写反:这会导致TF树断裂,Rviz里模型散架
  • 缺少limit标签:revolute和prismatic关节必须加limit,否则报错
  • mesh路径错误:用相对路径时,要确保启动节点的工作目录正确
曾经踩过的坑: 有一次我写了一个6轴机械臂的URDF,在Rviz里怎么看怎么不对劲——关节顺序反了。查了半天,发现是joint的child link命名搞混了。从那以后,我养成了一个习惯:每个link和joint的名字都按层级编号,比如 link_1、link_2、joint_1_2,一眼就能看出谁是谁。

好了,URDF的基础就这些。你写的时候,记住一句话:link是骨头,joint是关节,origin是位置,axis是方向。把这四个东西搞清楚了,机械臂的模型就搭起来了。