3. 机器人模型基础:URDF模型结构、Xacro宏定义、传感器与执行器配置、模型可视化与调试

做具身智能,第一件事是什么?不是写算法,不是调参数,而是先把你的机器人「描述清楚」。

你想想看,仿真环境不认识你的机器人长什么样、关节在哪、传感器装在哪。你得给它一份「说明书」。这份说明书,就是 URDF。

我刚开始接触这个的时候,觉得 URDF 不就是个 XML 嘛,写起来应该不难。结果第一次把模型丢进 Gazebo,机器人直接在地上劈了个叉——关节限位写反了。嗯,从那以后我再也不敢小看这个「说明书」了。

3.1 URDF 模型结构:机器人的「骨架」

URDF(Unified Robot Description Format)说白了就是用 XML 描述机器人的运动学树。核心就两个元素:link 和 joint。

  • link:机器人的刚体部件。比如底盘、手臂连杆、轮子。每个 link 有视觉、碰撞、惯性三个属性。
  • joint:连接两个 link 的关节。定义了父子关系、类型(旋转、滑动、固定)、限位、原点偏移。

我习惯把 URDF 想象成一棵倒挂的树。根节点通常是 base_link,然后通过 joint 挂上轮子、挂上躯干、挂上手臂。每个 link 只能有一个父 joint,但可以有多个子 joint。

核心原则:URDF 只描述运动学,不描述动力学。关节的摩擦、阻尼、电机特性,那是后面要加的东西。

来看一个最简单的两轮底盘 URDF 片段:

<robot name="simple_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 0 0"/>
    </visual>
    <collision>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="2.0"/>
      <inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
    </inertial>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="-0.15 -0.2 -0.05" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
  </joint>
</robot>

注意几个坑:origin 是子 link 相对于父 joint 的偏移,不是相对于父 link。我见过有人把这两个搞混,结果轮子飞到天上去了。

3.2 Xacro 宏定义:别再复制粘贴了

写一个简单的底盘还好,要是写一个六轴机械臂,每个 link 和 joint 都手写?那得写到天荒地老。而且一旦要改轮子半径,你得改多少个地方?

Xacro(XML Macros)就是来解决这个问题的。它让你定义变量、写宏、做数学运算。说白了,就是给 URDF 加了个「预处理」阶段。

我的习惯:把所有可调参数(轮距、轴距、连杆长度、关节限位)都定义成 xacro 属性。这样调参的时候改一个地方就行,不用满文件找数字。

举个例子,定义一个轮子的宏:

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

  <xacro:property name="wheel_radius" value="0.1"/>
  <xacro:property name="wheel_width" value="0.05"/>

  <xacro:macro name="wheel" params="name prefix">
    <link name="${prefix}_${name}_wheel">
      <visual>
        <geometry>
          <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
      </visual>
    </link>
  </xacro:macro>

  <xacro:wheel name="left" prefix="front"/>
  <xacro:wheel name="right" prefix="front"/>
</robot>

看到没?${wheel_radius} 引用属性,${name} 和 ${prefix} 是宏参数。这样你定义一次,后面想生成多少个轮子都行。

我曾经维护过一个六足机器人的 URDF,48 个关节,手写的话光 joint 定义就得 500 行。用 xacro 宏,一个腿的宏写一次,循环调用 6 次,总共不到 100 行。改腿长?改一个属性就行。

3.3 传感器与执行器配置

光有骨架还不够。你的机器人得「感知」和「行动」。这就需要在 URDF 里挂载传感器和执行器。

传感器在 URDF 里也是 link,只不过它通常是一个「虚拟 link」,不参与碰撞。常见的传感器包括:

传感器类型 URDF 配置要点 常见坑点
激光雷达 (LiDAR) 挂载为 link,指定安装位置和朝向 原点偏移算错,导致点云偏移
深度相机 (RGB-D) 需要定义视觉 mesh 和光学坐标系 光学坐标系和视觉坐标系没对齐
IMU 通常放在 base_link 或躯干中心 安装位置偏离质心,数据有偏置
力/力矩传感器 放在关节处,作为虚拟 link 需要配合 <gazebo> 标签启用

注意:URDF 本身不定义传感器的「数据输出」。它只定义传感器的「物理位置和外观」。传感器怎么发数据、发什么话题,那是后面通过插件或驱动来配置的。

执行器就是关节的驱动。在 URDF 里,你通过 <transmission> 标签把 joint 和 actuator 关联起来:

<transmission name="left_wheel_trans">
  <type>transmission_interface/SimpleTransmission</type>
  <joint name="left_wheel_joint">
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  </joint>
  <actuator name="left_wheel_motor">
    <mechanicalReduction>1</mechanicalReduction>
  </actuator>
</transmission>

这里 hardwareInterface 决定了这个关节是位置控制、速度控制还是力矩控制。我建议一开始都用速度接口,调试起来最直观。

3.4 模型可视化与调试

模型写完了,怎么知道对不对?别直接扔进仿真,先可视化检查。

我最常用的工具是 RViz。加载 URDF 模型,几秒钟就能看到 3D 渲染。你可以旋转、缩放、查看每个 link 和 joint 的坐标系。

调试步骤我一般这么走:

  1. 检查模型是否加载成功:在终端运行 check_urdf my_robot.urdf,它会告诉你语法错误和结构问题。
  2. 在 RViz 中查看:添加 RobotModel 显示,看每个 link 的位置和朝向对不对。
  3. 检查关节运动:用 joint_state_publisher 手动拖动关节,看运动学是否正确。
  4. 检查碰撞模型:把 collision 显示打开,看碰撞体是否和视觉模型匹配。
  5. 检查惯性参数:用 urdf_to_graphiz 生成树状图,确认父子关系。

避坑指南:我曾经有一次模型在 RViz 里看着完美,一进 Gazebo 就乱抖。查了半天,发现是惯性矩阵填了全零。记住,惯性矩阵不能为零,否则物理引擎会崩溃。

下面这张图是我自己总结的 URDF 调试流程,每次遇到模型问题就按这个走:

URDF 模型调试流程 编写 URDF / Xacro check_urdf 语法检查 RViz 加载 RobotModel 检查视觉/碰撞对齐 joint_state_publisher 测试 检查惯性参数 urdf_to_graphiz 树结构 进入仿真联调 每个步骤发现问题,返回第一步修改,不要跳过任何检查

还有一个实用技巧:用 roslaunch urdf_tutorial display.launch model:=my_robot.urdf 可以快速启动 RViz 并加载模型,省去手动配置的麻烦。

调试的时候,我建议你重点关注三个东西:

  • 坐标系:每个 link 的 origin 是不是你想要的?用 RViz 的 TF 显示功能看坐标轴方向。
  • 关节限位:旋转关节的 lower 和 upper 有没有写反?我犯过这个错。
  • 碰撞体简化:碰撞模型尽量用 box、cylinder、sphere 组合,别用复杂 mesh。物理引擎算起来快很多。

重要提醒:URDF 里的单位是米和弧度。如果你从 SolidWorks 导出的模型单位是毫米,记得除以 1000。不然你的机器人会变成「巨无霸」。

好了,模型基础就这些。写 URDF 就像搭积木,一开始慢一点,把每个 link 和 joint 的关系理清楚。后面调试导航、做仿真联调的时候,你会发现模型越扎实,后面越省心。