4. URDF建模

URDF(Unified Robot Description Format,统一机器人描述格式)是ROS2中描述机器人几何结构、关节类型与运动学属性的标准XML格式。对于机械臂而言,URDF不仅是可视化与仿真(RViz、Gazebo)的基础,更是后续运动学求解、碰撞检测与轨迹规划的数据源头。本节将围绕一个六自由度关节型机械臂,讲解URDF的完整创建流程、可视化方法以及验证手段。

4.1 核心原理:URDF的树形结构与关键标签

URDF将机械臂抽象为一棵运动学树:由<link>(刚体杆件)和<joint>(连接杆件的运动副)交替组成。每个link有且仅有一个父joint,但可以拥有多个子joint,从而形成严格的层级关系。机械臂的基座(base_link)是树的根节点,末端执行器(如tool0)是叶子节点。

理解URDF需要抓住三个核心标签:

  • <link>:描述杆件的惯性属性(<inertial>)、视觉几何(<visual>)与碰撞几何(<collision>)。视觉模型用于显示,碰撞模型用于物理仿真,两者可以不同(碰撞模型通常更简化)。
  • <joint>:定义父link与子link之间的运动关系。机械臂中常用revolute(旋转关节,有角度限位)和continuous(无限旋转关节)。必须指定origin(关节在父link坐标系中的位姿)和axis(旋转轴,在关节坐标系中定义)。
  • <material>:为视觉几何指定颜色或纹理,便于在RViz中区分不同杆件。

下面是一个典型的关节定义片段,展示了旋转关节的完整写法:

<joint name="shoulder_pan_joint" 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="150" velocity="3.2"/>
</joint>

其中origin的xyz表示关节坐标系原点在父link坐标系中的位置,rpy表示旋转(固定轴欧拉角)。axis的xyz是关节的旋转轴方向向量,必须在关节坐标系中归一化。限位参数lower/upper的单位是弧度,effort是最大力矩(N·m),velocity是最大速度(rad/s)。

坐标系约定:ROS2中遵循REP-103标准,x轴向前、y轴向左、z轴向上。机械臂的base_link通常位于安装法兰中心,z轴竖直向上。所有关节的旋转正方向遵循右手定则,即绕axis正方向逆时针旋转为正。

4.2 方法流程:从零构建六轴机械臂URDF

我们以一款典型的六自由度串联机械臂为例(结构类似UR5e),其关节配置为:肩部偏航(shoulder_pan)、肩部俯仰(shoulder_lift)、肘部俯仰(elbow)、前臂旋转(wrist_1)、腕部俯仰(wrist_2)、腕部翻转(wrist_3)。创建URDF的推荐流程如下:

  1. 确定运动学链与DH参数:先画出机械臂的关节-连杆简图,标注每个关节的旋转轴方向、连杆长度和偏置。这是URDF中origin和axis的数据来源。
  2. 创建包结构与基础文件:使用ros2 pkg create创建功能包,在urdf/目录下新建arm.urdf文件。
  3. 编写base_link与第一个关节:从基座开始,逐级向下编写。每个link的视觉几何尽量使用简单的box/cylinder/mesh组合,便于调试。
  4. 逐级添加后续link与joint:注意每个joint的parent必须是已定义的link,child是新link。保持树形结构不交叉。
  5. 添加末端执行器坐标系:在最后一个关节后添加tool0 link,用于后续运动学解算与工具坐标标定。

下面给出一个简化的URDF骨架(省略了部分视觉几何细节),展示树形结构的写法:

<robot name="six_axis_arm">
  <link name="base_link">
    <visual>
      <geometry><box size="0.2 0.2 0.1"/></geometry>
      <material name="base_mat"/>
    </visual>
  </link>

  <joint name="shoulder_pan_joint" type="revolute">
    <parent link="base_link"/>
    <child link="shoulder_link"/>
    <origin xyz="0 0 0.1" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
    <limit lower="-3.14" upper="3.14" effort="150" velocity="3.2"/>
  </joint>

  <link name="shoulder_link">
    <visual>
      <geometry><cylinder radius="0.05" length="0.3"/></geometry>
      <origin xyz="0 0 0.15" rpy="1.5708 0 0"/>
    </visual>
  </link>

  <!-- 后续关节依次类推 -->
  <joint name="shoulder_lift_joint" type="revolute">
    <parent link="shoulder_link"/>
    <child link="upper_arm_link"/>
    <origin xyz="0 0 0.3" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
    <limit lower="-2.0" upper="2.0" effort="150" velocity="3.2"/>
  </joint>
  <!-- ... 其余关节 -->
</robot>

注意:shoulder_link的视觉圆柱体绕x轴旋转了90°(rpy="1.5708 0 0"),这是因为圆柱体默认轴向是z轴,而我们需要它水平放置。这种坐标变换是URDF建模中最容易出错的地方。

4.3 可视化与验证:RViz与check_urdf

完成URDF编写后,必须经过两步验证:静态语法检查和动态可视化检查。

第一步:使用check_urdf工具。该工具会解析URDF文件并输出运动学树结构,同时报告缺失的标签或错误的坐标系引用。

# 安装工具(若未安装)
sudo apt install liburdfdom-tools

# 检查URDF文件
check_urdf arm.urdf

正常输出会显示类似如下的树形结构:

robot name is: six_axis_arm
---------- Successfully Parsed XML ---------------
root Link: base_link has 1 child(ren)
    child(1):  shoulder_link
        child(1):  upper_arm_link
            child(1):  forearm_link
                child(1):  wrist1_link
                    child(1):  wrist2_link
                        child(1):  wrist3_link
                            child(1):  tool0

如果输出中出现ERROR: Joint ... is not connected to the tree或No default value specified for joint ...,说明树形结构断裂或缺少必要属性,需要返回修改。

第二步:在RViz中可视化。需要先启动一个robot_state_publisher节点,它会读取URDF并发布各link坐标系之间的TF变换。创建launch文件或直接命令行运行:

# 启动robot_state_publisher(假设URDF路径为~/arm_ws/src/arm_description/urdf/arm.urdf)
ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:="$(cat ~/arm_ws/src/arm_description/urdf/arm.urdf)"

# 另开终端启动RViz
ros2 run rviz2 rviz2

在RViz中,将Fixed Frame设置为base_link,添加RobotModel显示组件,即可看到机械臂的三维模型。此时可以拖动关节滑块(通过joint_state_publisher发布关节角度)来验证每个关节的运动方向是否符合预期。

常见错误:如果RViz中模型显示为红色或完全不可见,通常是因为robot_description参数未正确加载,或URDF中引用了不存在的mesh文件。如果模型出现但关节运动方向相反,说明axis方向定义错误——例如绕y轴正方向旋转时,实际关节向负方向运动,需要将axis改为0 -1 0。

4.4 案例:为六轴机械臂添加碰撞模型与惯性参数

在实际工程中,仅有视觉模型是不够的。Gazebo仿真和运动规划(MoveIt)需要碰撞模型和惯性参数。碰撞模型应尽量简化,以降低碰撞检测计算量。惯性参数可以通过CAD软件计算,或使用近似估算。

以下是为upper_arm_link添加碰撞模型和惯性属性的示例:

<link name="upper_arm_link">
  <!-- 视觉模型 -->
  <visual>
    <geometry><box size="0.08 0.08 0.4"/></geometry>
    <origin xyz="0 0 0.2" rpy="0 0 0"/>
  </visual>
  <!-- 碰撞模型:使用更简单的圆柱体 -->
  <collision>
    <geometry><cylinder radius="0.06" length="0.4"/></geometry>
    <origin xyz="0 0 0.2" rpy="0 0 0"/>
  </collision>
  <!-- 惯性参数:质量、质心位置、惯性张量 -->
  <inertial>
    <mass value="4.5"/>
    <origin xyz="0 0 0.2" rpy="0 0 0"/>
    <inertia ixx="0.05" ixy="0.0" ixz="0.0"
              iyy="0.05" iyz="0.0"
              izz="0.01"/>
  </inertial>
</link>

惯性张量矩阵必须是对称正定的,且数值要合理。对于细长杆件,绕长度方向的转动惯量(izz)通常远小于绕垂直方向的转动惯量(ixx、iyy)。如果数值不合理,Gazebo仿真会出现抖动或发散。

4.5 误区与复盘:URDF建模中的典型陷阱

误区 现象 正确做法
关节origin的rpy设置错误 模型在RViz中扭曲,相邻link错位 牢记rpy是关节坐标系相对于父link坐标系的旋转,按Z-Y-X固定轴顺序理解
axis方向未归一化 check_urdf不报错,但运动学计算异常 axis向量长度必须为1,如xyz="0 0 1"
视觉几何与碰撞几何共用同一坐标系 碰撞检测不准确或仿真穿透 碰撞几何的origin应相对于link坐标系,而非视觉几何坐标系
忘记添加<material>定义 RViz中模型全白,难以区分关节 在<robot>根标签下定义material,并在visual中引用
惯性参数随意填写 Gazebo仿真中机械臂剧烈抖动 使用CAD软件测量或参考相似规格机械臂的参数

复盘建议:在完成URDF编写后,不要急于进入下一步。建议在RViz中手动旋转每个关节,逐一确认:①关节旋转方向与预期一致;②相邻link之间没有错位或穿透;③极限位置(joint limit)是否合理。这一过程虽然耗时,但能避免后续在MoveIt配置或实机调试中花费数倍时间排查问题。

验证清单:
  • check_urdf输出无ERROR,树形结构完整
  • RViz中模型显示正常,无红色警告
  • 每个关节在极限范围内运动时,link之间无干涉
  • TF树中所有坐标系均正确发布,无缺失
  • 碰撞模型与视觉模型大致吻合,无严重穿透

URDF建模是机械臂控制的基础工程,它直接决定了后续运动学解算、轨迹规划与仿真的准确性。通过本节的学习,你已经掌握了从零构建URDF、使用check_urdf和RViz进行验证的方法,并了解了碰撞模型与惯性参数的重要性。在实际项目中,建议将URDF文件纳入版本管理,并配合xacro宏定义来减少重复代码,提高模型的可维护性。