3. 机器人模型构建:URDF模型基础、XACRO宏定义、模型可视化与调试

说到机器人仿真,第一步就是把机器人“搬”进电脑里。你想想看,没有模型,仿真跑什么呢?

我个人习惯把这一步叫做“数字孪生的起点”。说白了,就是用一种机器人能读懂的语言,把它的身体结构描述清楚。这个语言,就是 URDF。

3.1 URDF 模型基础:机器人的“骨架”

URDF,全称 Unified Robot Description Format。它基于 XML 语法,核心就两个概念:连杆(link)和关节(joint)。

  • 连杆(link):描述机器人的一个刚体部件。比如底盘、手臂、轮子。你需要定义它的几何形状、尺寸、颜色,还有最重要的——惯性参数(质量、惯性张量)。
  • 关节(joint):描述两个连杆之间的连接关系。它定义了父连杆和子连杆,以及它们之间的相对位置和运动类型。

关节的类型有几种,我列个表,你一看就明白:

关节类型 自由度 典型应用
revolute 1(旋转) 电机驱动的关节,有角度限制
continuous 1(旋转) 轮子,可以无限旋转
prismatic 1(平移) 伸缩臂、滑轨
fixed 0 两个部件刚性连接,比如相机支架
floating 6 完全自由运动,常用于移动机器人底盘

一个最简单的 URDF 文件长这样:

<robot name="my_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"/>
      <material name="blue">
        <color rgba="0 0 1 1"/>
      </material>
    </visual>
  </link>

  <joint name="base_to_wheel" type="continuous">
    <parent link="base_link"/>
    <child link="wheel_link"/>
    <origin xyz="0.2 0 0" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>
</robot>
注意: 我曾经在项目里吃过亏——URDF 的坐标系是右手系,rpy 的顺序是绕固定轴 X-Y-Z 旋转。很多人搞反了顺序,结果模型在仿真里直接“拧麻花”。一定要记住:先绕 X 轴转 roll,再绕 Y 轴转 pitch,最后绕 Z 轴转 yaw。

3.2 XACRO 宏定义:告别重复劳动

写一个简单的 URDF 还行,但要是你的机器人有 6 个一模一样的轮子,或者 4 条完全对称的腿……你想想看,复制粘贴 6 遍同样的代码?那太蠢了。

XACRO 就是来解决这个问题的。它是 URDF 的宏扩展工具,支持变量、数学运算、条件判断和宏定义。

我建议你把 XACRO 当成“函数”来用。比如定义一个轮子的宏:

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

  <xacro:macro name="wheel" params="name prefix x y z">
    <link name="${prefix}_${name}_link">
      <visual>
        <geometry>
          <cylinder radius="0.05" length="0.02"/>
        </geometry>
        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
      </visual>
    </link>

    <joint name="${prefix}_${name}_joint" type="continuous">
      <parent link="base_link"/>
      <child link="${prefix}_${name}_link"/>
      <origin xyz="${x} ${y} ${z}" rpy="0 0 0"/>
      <axis xyz="0 0 1"/>
    </joint>
  </xacro:macro>

  <xacro:wheel name="front_left" prefix="left" x="0.2" y="0.15" z="0"/>
  <xacro:wheel name="front_right" prefix="right" x="0.2" y="-0.15" z="0"/>
  <xacro:wheel name="back_left" prefix="left" x="-0.2" y="0.15" z="0"/>
  <xacro:wheel name="back_right" prefix="right" x="-0.2" y="-0.15" z="0"/>

</robot>
小技巧: 我习惯把 XACRO 文件拆成多个文件:chassis.xacro、arm.xacro、sensors.xacro,然后用 <xacro:include filename="..." /> 组合起来。这样团队协作时,每个人负责自己的模块,互不干扰。

XACRO 还支持数学运算。比如你想让两个轮子对称分布,可以直接写 ${-0.15},或者更优雅一点,定义一个变量 <xacro:property name="wheel_base" value="0.15"/>,然后到处引用。改一个值,所有地方都跟着变。

3.3 模型可视化与调试:让模型“活”起来

写完了模型,怎么知道对不对?总不能直接上真机吧?

ROS 生态里有两个好用的工具:check_urdf 和 rviz。

3.3.1 语法检查

首先,用 check_urdf 检查 URDF 文件是否有语法错误:

$ check_urdf my_robot.urdf

它会输出模型的结构树,告诉你哪个关节连哪个连杆。如果报错,多半是标签没闭合、属性名写错了,或者坐标系原点定义冲突。

3.3.2 可视化预览

然后,用 urdf_to_graphiz 生成结构图:

$ urdf_to_graphiz my_robot.urdf

它会生成一个 PDF 文件,用树状图展示整个机器人的父子关系。我每次拿到新模型,第一件事就是跑这个命令,看看关节层级是不是我想要的。

3.3.3 在 rviz 中预览

最直观的方式,还是把模型加载到 rviz 里看。写一个简单的 launch 文件:

<launch>
  <param name="robot_description" textfile="$(find my_robot_description)/urdf/my_robot.urdf"/>
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"/>
  <node name="rviz" pkg="rviz" type="rviz" args="-d $(find my_robot_description)/config/display.rviz"/>
</launch>

启动后,你就能在 rviz 里看到机器人模型了。你可以拖动关节滑块,看看运动学是否正确。我记得有一次,我写了一个六轴机械臂,在 rviz 里一拖动,发现第三个关节的运动方向反了。还好是在仿真里发现的,要是真机通电……后果不堪设想。

调试要点:
  • 检查坐标系: 每个 link 的 origin 是否合理?关节的 axis 方向对不对?
  • 检查碰撞模型: 仿真中碰撞检测用的是 <collision> 标签,它应该比 <visual> 更简化,否则计算量会很大。
  • 检查惯性参数: 质量不能为 0,惯性张量不能是零矩阵。否则仿真器会直接崩溃。

下面这张图,是我总结的模型构建与调试流程:

机器人模型构建与调试流程 1. 定义连杆(link) 2. 定义关节(joint) 3. 组合成URDF 4. check_urdf检查 5. rviz可视化预览 6. 调试修正 7. 模型就绪 提示:如果步骤6发现问题,返回步骤1或2修改,直到rviz中模型表现符合预期

嗯,这里要注意一点:URDF 只描述机器人的运动学,不包含动力学参数(比如摩擦系数、电机力矩)。如果你要做动力学仿真,还需要额外配置。不过那是后面章节的内容了。

最后,我个人的一个小习惯:每次修改模型后,都重新跑一遍 check_urdf 和 rviz 预览。别偷懒,这个习惯救过我很多次。有一次我改了一个传感器的安装位置,结果不小心把坐标系写反了,模型直接“穿模”。要是没检查就往下走,后面所有仿真数据都得作废。