3. 机器人模型与URDF:从零搭建你的第一个机器人

各位同学,欢迎来到第三章。前两章我们把环境搭好了,概念也理清了。这一章,咱们来点实在的——亲手写出一个机器人模型。

URDF,全称是 Unified Robot Description Format。说白了,它就是机器人的「身份证」。你的机器人长什么样?有几个轮子?机械臂能转几圈?这些信息,URDF 都能描述清楚。

我个人习惯把 URDF 看作「乐高说明书」。你只需要把每个零件(link)和它们之间的连接方式(joint)写清楚,ROS 就能知道这个机器人该怎么动。

核心知识点速览

  • URDF 基础语法:link、joint、几何与可视化
  • 差速底盘模型:两轮+万向轮,经典移动机器人
  • 机械臂模型:多关节串联,从基座到末端
  • robot_state_publisher:让模型在 RViz 里动起来
URDF 知识体系 URDF 机器人模型 基础语法 link / joint / geometry 差速底盘模型 两轮驱动 + 万向轮 机械臂模型 多关节串联结构 robot_state_publisher 发布 TF + 关节状态 → RViz 可视化

3.1 URDF 基础语法:link 和 joint 的默契配合

URDF 文件本质上就是 XML。你不需要背语法,记住两个核心元素就够了:link 和 joint。

  • link:描述一个刚体部件。比如底盘、轮子、机械臂的连杆。
  • joint:描述两个 link 之间的连接关系。比如轮子怎么装在底盘上。

一个最简单的 link 长这样:

<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>
</link>

嗯,这里要注意:origin 里的 xyz 是位置,rpy 是旋转(roll, pitch, yaw)。我刚开始写 URDF 时,经常把 rpy 搞反,结果轮子在天上飞。后来养成了习惯——先在纸上画个坐标系,再填数值。

joint 的写法也不复杂:

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

我的小技巧:joint 的 type 有六种:revolute(旋转限位)、continuous(无限旋转)、prismatic(滑动)、fixed(固定)、floating(浮动)、planar(平面)。差速轮用 continuous,机械臂关节用 revolute。

3.2 创建差速底盘模型:两轮驱动,经典永不过时

差速底盘,说白了就是两个主动轮 + 一个或多个万向轮。通过控制左右轮的速度差来实现转向。我在做第一个 AGV 项目时,用的就是这种结构——简单、可靠、好调参。

一个完整的差速底盘 URDF 包含:

  • base_link:底盘主体,通常是个长方体
  • left_wheel / right_wheel:两个驱动轮,用 continuous joint 连接
  • caster_wheel:万向轮,用 fixed 或 continuous 都行

来看一个完整的底盘模型片段:

<robot name="diff_drive_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
      <material name="blue">
        <color rgba="0 0 1 1"/>
      </material>
    </visual>
  </link>

  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </visual>
  </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>

避坑指南:我曾经因为 wheel 的 origin 写错,导致轮子悬空。记住:轮子的 origin 是相对于 parent link(base_link)的。如果 base_link 厚度是 0.1,轮子半径 0.05,那 origin 的 z 值应该是 -0.05(轮子中心在底盘下表面)。

3.3 创建机械臂模型:从基座到末端执行器

机械臂的 URDF 比底盘复杂一些,因为涉及多个关节的串联。你想想看,一个 6 轴机械臂,需要 6 个 link 和 6 个 joint,每个关节都要定义旋转轴和限位。

我习惯从基座开始,一层一层往上写:

  1. base_link:固定在底盘或工作台上
  2. link1 ~ linkN:每个连杆对应一个关节
  3. end_effector:末端工具,比如夹爪或吸盘

一个两关节机械臂的示例:

<robot name="simple_arm">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.1"/>
      </geometry>
    </visual>
  </link>

  <link name="arm_link1">
    <visual>
      <geometry>
        <box size="0.03 0.03 0.2"/>
      </geometry>
      <origin xyz="0 0 0.1"/>
    </visual>
  </link>

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

经验之谈:写机械臂 URDF 时,limit 里的 effort 和 velocity 别乱填。我见过有人把 effort 写成 1000,结果仿真里关节像打了鸡血一样乱抖。先查电机手册,再填数值。

3.4 使用 robot_state_publisher:让模型活过来

URDF 写好了,怎么在 RViz 里看到它?这就需要 robot_state_publisher 了。

这个节点做两件事:

  • 读取 URDF 文件,发布到 /robot_description 话题
  • 根据关节角度,计算并发布 TF 变换

启动方式很简单:

ros2 launch robot_state_publisher robot_state_publisher.launch.py \
  urdf_file:=/path/to/your/robot.urdf

或者,你也可以在 launch 文件里直接加载:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='robot_state_publisher',
            executable='robot_state_publisher',
            arguments=['/path/to/robot.urdf']
        )
    ])

关键点:robot_state_publisher 默认从 /robot_description 话题读取 URDF。如果你用参数传文件,它会自动发布到该话题。之后 RViz 订阅这个话题,就能显示模型了。

我记得第一次在 RViz 里看到自己写的 URDF 模型动起来时,那种成就感——嗯,就像你亲手拼的乐高终于能跑了。虽然只是个方块加两个圆柱,但那一刻,你真的觉得「这是我的机器人」。

好了,这一章的内容就到这里。URDF 是机器人建模的基石,多写多练,手感自然就来了。下一章我们会聊传感器模型和 xacro——一种让 URDF 更优雅的宏语言。