4. URDF模型构建:从零搭建你的机械臂“骨架”

URDF,全称是Unified Robot Description Format。说白了,它就是机器人的“身份证”。ROS2靠它知道你的机械臂长什么样、关节在哪、能怎么动。

我记得刚入行那会儿,总觉得URDF就是个XML文件,随便写写就行。结果第一次在RViz里加载模型,整个机械臂拧成一团麻花……嗯,从那以后我再也不敢小看这个文件了。

核心要点:URDF定义了机器人的运动学树——从基座到末端执行器,每个连杆(link)和关节(joint)都必须严格按父子关系排列。

4.1 连杆与关节:机械臂的“骨头”和“关节”

一个机械臂模型,本质上就是一堆连杆通过关节串起来。每个连杆有几何形状、尺寸、颜色;每个关节决定相邻两个连杆的相对运动方式。

先看一个最简单的连杆定义:

<link name="base_link">
  <visual>
    <geometry>
      <box size="0.2 0.2 0.1"/>
    </geometry>
    <origin xyz="0 0 0" rpy="0 0 0"/>
    <material name="blue">
      <color rgba="0 0 1 1"/>
    </material>
  </visual>
</link>

这里我习惯把visual标签放在最前面,因为它最直观——你一眼就能看到这个连杆长什么样。但实际项目中,碰撞参数和惯性参数才是真正决定机器人能不能跑起来的关键。

关节的定义稍微复杂一点:

<joint name="joint1" type="revolute">
  <parent link="base_link"/>
  <child link="link1"/>
  <origin xyz="0 0 0.1" rpy="0 0 0"/>
  <axis xyz="0 0 1"/>
  <limit lower="-3.14" upper="3.14" effort="10" velocity="1"/>
</joint>

注意origin的位置——它是关节相对于父连杆的变换。我曾经在这里栽过跟头:把xyz写成了相对于子连杆,结果模型在RViz里直接飞出去了。

我的习惯:先画一张连杆-关节树形图,标清楚每个关节的原点和旋转轴,再动手写URDF。磨刀不误砍柴工。

4.2 使用xacro:告别重复劳动

写几个连杆还行,但六轴机械臂写下来,你会发现大量重复代码——每个连杆的碰撞参数、惯性矩阵几乎一样,只是尺寸不同。

xacro(XML Macros)就是来解决这个问题的。它让你可以定义变量、写宏、做数学运算。

举个例子,定义一个通用的连杆宏:

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="my_arm">

  <xacro:macro name="link_with_inertia" params="name length radius color">
    <link name="${name}">
      <visual>
        <geometry>
          <cylinder length="${length}" radius="${radius}"/>
        </geometry>
        <material name="${color}">
          <color rgba="0 0 1 1"/>
        </material>
      </visual>
      <collision>
        <geometry>
          <cylinder length="${length}" radius="${radius}"/>
        </geometry>
      </collision>
      <inertial>
        <mass value="1.0"/>
        <inertia ixx="0.1" ixy="0" ixz="0"
                  iyy="0.1" iyz="0"
                  izz="0.1"/>
      </inertial>
    </link>
  </xacro:macro>

  <xacro:link_with_inertia name="link1" length="0.3" radius="0.05" color="red"/>
  <xacro:link_with_inertia name="link2" length="0.25" radius="0.04" color="green"/>

</robot>

你看,原来要写几十行的代码,现在几行就搞定了。我个人建议把所有连杆的惯性参数也做成宏参数,因为不同连杆的质量分布差异很大,统一写死容易出问题。

避坑指南:xacro文件里不要用中文注释!ROS2的XML解析器对中文支持不好,我曾经因为一个中文分号,排查了整整一下午。

4.3 在RViz中可视化:眼见为实

模型写好了,怎么验证?RViz就是你的“照妖镜”。

启动命令很简单:

# 先安装必要工具
sudo apt install ros-humble-joint-state-publisher ros-humble-robot-state-publisher

# 启动RViz并加载模型
ros2 launch urdf_tutorial display.launch.py model:=my_arm.urdf

如果用的是xacro文件,需要先转换成URDF:

ros2 run xacro xacro my_arm.xacro > my_arm.urdf

在RViz里,你可以做三件事:

  • 检查模型结构——每个连杆是否在正确位置,关节轴方向对不对
  • 手动拖动关节——通过Joint State Publisher面板,拖动滑块看运动范围
  • 查看TF树——确认父子关系是否和设计一致

我记得有一次,模型在RViz里显示正常,但一跑运动规划就报错。后来发现是碰撞模型比可视化模型大了一圈,导致自碰撞检测一直失败。所以,可视化没问题不代表模型就对了。

调试技巧:在RViz里把RobotModel的Alpha值调到0.5,半透明显示,这样能同时看到内部结构和碰撞体。

4.4 添加碰撞与惯性参数:让模型“真实”起来

可视化参数只是“面子”,碰撞和惯性参数才是“里子”。没有它们,运动规划、动力学仿真全都跑不起来。

碰撞参数决定了机器人在运动规划中如何检测自碰撞和环境碰撞。我一般直接用可视化几何体的简化版本——比如把复杂的网格模型简化成圆柱或长方体,计算量小很多。

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

惯性参数是动力学仿真的基础。每个连杆都需要指定质量和惯性张量矩阵。这里有个常见的误区:

参数 含义 常见错误
mass 连杆质量(kg) 忘记加单位,默认是kg但写成了g
ixx/iyy/izz 绕x/y/z轴的转动惯量 数值数量级错误,差几个量级
ixy/ixz/iyz 惯性积 非对称连杆直接填0,导致动力学失真

对于规则形状(圆柱、长方体),惯性张量可以用公式计算。我习惯写一个Python脚本自动算,省得手算出错。

重要提醒:惯性矩阵必须是正定的(所有特征值大于0)。如果填错了,Gazebo仿真会直接崩溃,连错误日志都不给。

4.5 本章知识体系总览

下面这张图总结了URDF模型构建的核心流程和各个模块的关系:

URDF模型构建知识体系 URDF模型文件 连杆 (link) 关节 (joint) xacro宏优化 visual可视化 collision碰撞 inertial惯性 parent/child origin/axis limit/effort 变量定义与数学运算 宏封装与参数化 文件包含与复用 RViz可视化验证 → 调整参数 → 迭代优化

从这张图可以看得很清楚:URDF模型不是一蹴而就的。你需要先搭好连杆和关节的骨架,再用xacro优化代码结构,最后通过RViz反复验证和调整。每一步都踩实了,后面的运动控制才能跑得稳。

我的经验:一个高质量的URDF模型,至少需要迭代3-5轮。第一轮搭结构,第二轮调碰撞,第三轮校准惯性参数。别指望一次搞定。