第4章:机器人模型与URDF——从零搭建你的第一个机器人

做机器人开发这么多年,我始终觉得URDF是入门的第一道坎。说白了,URDF就是机器人的「身份证」——它告诉系统你的机器人长什么样、关节怎么动、传感器装在哪。今天咱们就把它彻底讲透。

4.1 URDF到底是什么?

URDF全称是Unified Robot Description Format,统一机器人描述格式。它用XML语法描述机器人的物理结构。我个人习惯把它理解成「机器人的乐高说明书」——每个零件(link)怎么拼、关节(joint)怎么转,全写在这个文件里。

举个例子,一个简单的两轮机器人,URDF里会这样描述:

<robot name="my_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
    </visual>
  </link>
  
  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0.2 0.15 0" rpy="0 0 0"/>
  </joint>
</robot>

你看,结构非常清晰。一个robot根标签,里面包着若干linkjoint。每个link代表一个刚体零件,每个joint定义零件之间的连接关系。

我的小经验:刚开始写URDF时,别追求一步到位。先画一个base_link,加一个轮子,在rviz里看看效果。确认没问题了再继续加。我见过太多人一口气写几百行,结果一运行全是红色报错。

4.2 link与joint——机器人的骨骼和关节

4.2.1 link的定义

link是机器人的基本组成单元。每个link可以包含三部分信息:

  • visual:可视化外观,用于在rviz中显示
  • collision:碰撞模型,用于物理仿真和碰撞检测
  • inertial:惯性参数,包括质量、惯性矩阵等

我曾经犯过一个低级错误——只写了visual,没写collision。结果在Gazebo仿真里,机器人直接穿模到地底下。嗯,这个坑你们别踩。

<link name="arm_link">
  <visual>
    <geometry>
      <cylinder length="0.3" radius="0.05"/>
    </geometry>
    <material name="blue">
      <color rgba="0 0 1 1"/>
    </material>
  </visual>
  <collision>
    <geometry>
      <cylinder length="0.3" radius="0.05"/>
    </geometry>
  </collision>
  <inertial>
    <mass value="0.5"/>
    <inertia ixx="0.001" ixy="0" ixz="0" iyy="0.001" iyz="0" izz="0.001"/>
  </inertial>
</link>

4.2.2 joint的类型与配置

joint定义了link之间的运动关系。ROS支持6种关节类型:

类型 说明 典型应用
continuous 连续旋转关节,无角度限制 车轮、转台
revolute 旋转关节,有角度限制 机械臂关节
prismatic 平移关节,直线运动 升降台、滑轨
fixed 固定关节,两个link刚性连接 传感器支架
floating 6自由度浮动关节 无人机、水下机器人
planar 平面运动关节(2平移+1旋转) AGV底盘

你想想看,选对关节类型有多重要?我见过有人把车轮用revolute关节,结果轮子只能转180度,车直接翻了个跟头。车轮必须用continuous,这是常识。

注意:joint的origin坐标是相对于parent link的。很多新手搞反了父子关系,结果机器人零件满天飞。我的建议是:画个草图,标清楚每个零件的相对位置,再写代码。

4.3 xacro——让URDF不再臃肿

写几个link还好,要是写一个6轴机械臂,URDF文件能到上千行。这时候xacro就派上用场了。xacro是XML宏语言,说白了就是给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"/>
  
  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
      </geometry>
    </visual>
  </link>
</robot>

看到${wheel_radius}了吗?这就是变量引用。想改轮子大小?改一个地方就行。我曾经维护过一个没有用xacro的机器人模型,改个轮距要翻6个文件,改完还容易漏。用了xacro之后,爽多了。

xacro还支持宏定义,把重复的结构封装起来:

<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"/>
核心要点:xacro文件不能直接被ROS解析,需要先转换成URDF。命令是:rosrun xacro xacro.py model.xacro > model.urdf。或者用xacro model.xacro > model.urdf(ROS Noetic及以后版本)。

4.4 在rviz中显示机器人模型

写完了模型,总得看看效果吧?rviz就是那个「照妖镜」。启动rviz显示模型的步骤很简单:

  1. 先确保你的URDF文件语法正确:check_urdf model.urdf
  2. 启动rviz:rosrun rviz rviz
  3. 在rviz中,添加RobotModel显示插件
  4. 在RobotModel的属性中,设置URDF文件路径

或者更简单,直接用launch文件:

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

我第一次在rviz里看到自己写的机器人动起来时,说实话挺激动的。但更多时候是看到一堆红色报错。别慌,常见的错误就几种:

  • link名称拼写错误
  • joint的parent/child写反了
  • origin坐标计算错误
  • 缺少必要的inertial参数
调试技巧:在rviz中,可以勾选「Show Axes」来显示每个link的坐标系。如果某个link的坐标系位置不对,那肯定是joint的origin写错了。这个技巧帮我省了无数时间。

4.5 避坑指南——我踩过的那些坑

做URDF建模这几年,我总结了几条血泪教训:

  • 坐标系要统一:所有link的坐标系方向要一致。我见过有人base_link用右手系,arm_link用左手系,结果机械臂直接拧成麻花。
  • 单位要统一:URDF默认单位是米和千克。别混用厘米和毫米,否则你的机器人要么是巨无霸,要么是微缩模型。
  • 惯性参数别乱填:我曾经图省事,所有link的惯性矩阵都填0.001。结果仿真时机器人抖得像筛糠。惯性参数最好用CAD软件算出来,或者至少用近似公式估算。
  • 命名要有规律:我习惯用「部位_功能」的命名方式,比如left_arm_shoulder_joint。这样看名字就知道是哪个关节。

嗯,说了这么多,其实URDF建模就是个熟能生巧的活。多写几个模型,自然就上手了。下一章咱们聊聊如何让机器人动起来——没错,就是那个让无数人头疼的TF变换。