3. 仿真环境概览

好,咱们进入正题。这一章要聊的是机器人建模的基石——URDF。说白了,URDF 就是机器人的「骨架说明书」。你想想看,要让一个虚拟的人形机器人动起来,总得先告诉仿真器它长什么样、胳膊腿怎么连吧?URDF 干的就是这个活。

我个人习惯把 URDF 看作机器人的「身份证」加「户口本」。它用 XML 格式,把机器人拆成一个个零件(连杆),再说明这些零件之间怎么活动(关节)。嗯,这里要注意:URDF 只描述运动学,不涉及动力学参数(那是后面的事)。

核心要点:URDF 是 ROS 生态中机器人建模的标准格式。它定义了机器人的几何外形、碰撞模型、惯性参数以及关节的运动范围。没有它,Rviz2 里就是一片空白。

3.1 URDF 文件结构概览

先看一个最简单的 URDF 骨架。别被 XML 标签吓到,其实结构很清晰:

<robot name="my_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.5 0.3 0.1"/>
      </geometry>
    </visual>
  </link>

  <joint name="base_to_arm" type="fixed">
    <parent link="base_link"/>
    <child link="arm_link"/>
    <origin xyz="0 0 0.2" rpy="0 0 0"/>
  </joint>

  <link name="arm_link">
    <visual>
      <geometry>
        <cylinder length="0.4" radius="0.05"/>
      </geometry>
    </visual>
  </link>
</robot>

看到没?<robot> 是根标签,里面就两样东西:<link> 和 <joint>。一个连杆配一个关节,像链条一样串起来。我在项目中遇到过新手把连杆和关节搞混——记住:连杆是实体,关节是约束。

3.2 连杆(link)的定义

每个 <link> 描述一个刚体零件。它有三个主要子标签:

子标签 作用 必填?
<visual> 可视化外观(显示用) 推荐
<collision> 碰撞检测模型(物理引擎用) 推荐
<inertial> 惯性参数(质量、转动惯量) 动力学仿真必填

visual 标签里,<geometry> 支持四种基本形状:box、cylinder、sphere、mesh。mesh 可以导入 STL 或 Collada 文件,人形机器人的复杂外形全靠它。

collision 标签我建议尽量用简单几何体代替 mesh。为什么?因为碰撞检测计算量很大,用圆柱体代替手臂,用长方体代替躯干,仿真速度能快不少。我曾经因为用了精细的 STL 做碰撞模型,结果仿真跑起来一卡一卡的……后来全换成基本几何体,流畅多了。

inertial 标签长这样:

<inertial>
  <mass value="2.5"/>
  <inertia ixx="0.01" ixy="0.0" ixz="0.0"
           iyy="0.01" iyz="0.0"
           izz="0.005"/>
</inertial>

转动惯量矩阵是对称的,所以只填 6 个独立分量。如果你不确定数值,可以用 CAD 软件算,或者先估一个大概——反正后面还要调。

3.3 关节(joint)的定义

关节决定了两个连杆之间的相对运动。URDF 支持 6 种关节类型:

类型 自由度 典型用途
fixed 0 固定连接(如摄像头支架)
revolute 1(旋转) 肘关节、膝关节
prismatic 1(平移) 伸缩机构
continuous 1(无限旋转) 车轮
planar 2(平面运动) 少见
floating 6(全自由) 基座漂浮(如无人机)

人形机器人最常用的是 revolute 关节。定义时别忘了加 <limit>:

<joint name="left_elbow" type="revolute">
  <parent link="left_upper_arm"/>
  <child link="left_forearm"/>
  <origin xyz="0 0 -0.3" rpy="0 0 0"/>
  <axis xyz="0 1 0"/>
  <limit lower="-1.57" upper="0.0" effort="30" velocity="3.14"/>
</joint>

这里 <origin> 是子连杆相对于父连杆的位姿,<axis> 是旋转轴。我踩过一个坑:axis 默认是 1 0 0(X 轴),如果忘了写,关节会朝奇怪的方向转。所以每次写关节,我都会检查三遍 axis 和 origin。

避坑指南:我曾经在定义人形机器人的髋关节时,把 origin 的 rpy 写反了顺序。结果模型在 Rviz2 里大腿直接穿模到肚子里……后来养成习惯:先写 xyz,再写 rpy,并且用 rpy="0 0 0" 验证坐标系方向。

3.4 在 Rviz2 中可视化模型

写好了 URDF,怎么看到它?Rviz2 是最直观的工具。步骤很简单:

  1. 启动 Rviz2:ros2 run rviz2 rviz2
  2. 添加 RobotModel 显示插件(Displays 面板左下角 Add → RobotModel)
  3. 在 RobotModel 属性中设置 Robot Description 为你的 URDF 话题(默认 /robot_description)
  4. 发布 URDF 到参数服务器:ros2 param set /robot_description "$(cat my_robot.urdf)"

或者更简单,用 urdf_to_graphiz 工具生成结构图:

urdf_to_graphiz my_robot.urdf

这会生成 my_robot.pdf 和 my_robot.gv,能直观看到连杆和关节的树状结构。

小技巧:如果模型在 Rviz2 里显示不全,检查两点:一是 Fixed Frame 是否设置为你的基座连杆名(比如 base_link);二是 URDF 里所有 link 的 visual 标签是否都有 geometry。我见过有人只写了 collision 没写 visual,结果模型在 Rviz2 里是隐形的。

3.5 本章知识体系

下面这张图总结了 URDF 建模的核心逻辑,从文件结构到可视化验证的完整链路:

URDF 建模知识体系 URDF 建模核心链路 URDF 文件 link(连杆) visual(外观) collision(碰撞) inertial(惯性) joint(关节) parent/child origin / axis limit / type Rviz2 可视化验证 正确显示 → 可用于仿真 树状结构,一一对应

从这张图可以看得很清楚:URDF 文件拆成 link 和 joint 两大分支,各自有子属性,最终在 Rviz2 里汇合验证。说白了,建模就是「拆零件 → 定关节 → 看效果」的循环。

3.6 常见问题与调试技巧

  • 模型在 Rviz2 里显示为红色问号:通常是 URDF 解析失败。运行 check_urdf my_robot.urdf 检查语法错误。
  • 关节旋转方向反了:检查 axis 的正方向,或者 origin 的 rpy 是否与预期一致。
  • 连杆位置不对:用 rviz2 的 TF 插件查看坐标系,确认每个 link 的坐标系原点。
  • 模型抖动:检查 collision 模型是否与 visual 模型偏差太大,或者惯性参数设置不合理。

调试利器:我习惯在 URDF 里给每个 link 加一个 <material> 颜色标签,这样在 Rviz2 里一眼就能看出哪个连杆对应哪个名字。比如躯干用红色,左臂用蓝色,右臂用绿色——视觉排查效率翻倍。