第二讲:认识URDF——你的第一个机器人模型

好,咱们进入正题。上一讲我们把Gazebo环境搭起来了,但里面空荡荡的,对吧?这一讲,我们来给这个世界加点料——创建第一个机器人模型。而要做到这一点,必须先搞懂URDF。

什么是URDF?

URDF,全称是Unified Robot Description Format,统一机器人描述格式。说白了,它就是一套用来描述机器人长什么样的“语言”。

我个人习惯把URDF理解为机器人的“身份证”。它告诉系统:这个机器人有几个轮子、几个关节、每个零件多长多重、颜色是什么。Gazebo和ROS就是靠这个文件来认识你的机器人的。

我记得刚接触URDF时,觉得它不就是个XML嘛,有啥难的?结果第一次写出来的机器人,轮子长在头顶上……嗯,后来我学乖了,老老实实把每个坐标轴都画出来再动手。

核心要点:URDF是一个基于XML的文本文件,用来描述机器人的运动学、动力学和可视化信息。

URDF文件结构

URDF的结构其实很清晰,就两大核心元素:link(连杆)和joint(关节)。

  • link:机器人的刚体部件。比如底盘、轮子、摄像头支架。
  • joint:连接两个link的关节。定义它们之间的相对位置和运动方式。

你想想看,一个机器人不管多复杂,本质上就是一堆连杆通过关节连起来。就像人的手臂,上臂和前臂通过肘关节连接,对吧?

link的结构

每个link通常包含三部分信息:

部分 作用 我踩过的坑
visual 可视化外观,决定你“看到”的机器人长什么样 颜色值用RGB,但别忘了加alpha通道
collision 碰撞检测,决定机器人“碰到”东西时的边界 我曾经把collision设得比visual大一圈,结果机器人还没碰到障碍物就停下了
inertial 惯性参数,决定机器人“动起来”的物理特性 质量写错会导致机器人像纸片一样飘

joint的类型

关节有几种常见类型,我列个表给你看:

类型 说明 实际例子
fixed 固定连接,两个link之间没有相对运动 摄像头固定在支架上
revolute 旋转关节,绕一个轴转动,有角度限制 机械臂的肘关节
continuous 连续旋转关节,没有角度限制 轮子
prismatic 滑动关节,沿一个轴直线运动 升降台

避坑指南:我曾经把轮子的joint类型写成revolute,结果轮子只能转180度就卡住了。机器人原地打转,像个陀螺。后来改成continuous才正常。记住:轮子用continuous!

创建第一个机器人模型

好,理论说完了,咱们动手。下面这个例子,是一个最简单的两轮差速机器人。它只有一个底盘和两个轮子。

先看整体结构图:

两轮差速机器人URDF结构 base_link (底盘) 左轮 右轮 left_wheel_joint right_wheel_joint link: base_link, left_wheel, right_wheel joint: left_wheel_joint (continuous), right_wheel_joint (continuous) base_link → 父link,轮子 → 子link

结构很简单,对吧?底盘是父link,两个轮子通过continuous关节挂在底盘两侧。

下面就是完整的URDF代码:

<?xml version="1.0"?>
<robot name="my_first_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.2 0.5 0.8 1.0"/>
      </material>
    </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>

  <!-- 左轮 -->
  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
      <origin xyz="0 0 0" rpy="1.5708 0 0"/>
      <material name="red">
        <color rgba="0.8 0.2 0.2 1.0"/>
      </material>
    </visual>
    <collision>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="0.2"/>
      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
    </inertial>
  </link>

  <!-- 右轮 -->
  <link name="right_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
      <origin xyz="0 0 0" rpy="1.5708 0 0"/>
      <material name="red">
        <color rgba="0.8 0.2 0.2 1.0"/>
      </material>
    </visual>
    <collision>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="0.2"/>
      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
    </inertial>
  </link>

  <!-- 左轮关节 -->
  <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 name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <origin xyz="-0.2 -0.15 -0.05" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
  </joint>

</robot>

注意:origin中的xyz坐标是相对于父link的。我刚开始写的时候,把轮子的坐标写成了相对于世界坐标系,结果轮子飞到天上了。记住:子link的坐标是相对于父link的!

几个关键点

写URDF时,有几个地方特别容易出错,我单独拎出来说:

  1. 坐标轴方向:Gazebo里,x轴朝前,y轴朝左,z轴朝上。轮子的旋转轴是y轴,所以axis写的是"0 1 0"。
  2. 单位:长度用米,质量用千克。别混用,否则物理仿真会崩。
  3. inertia值:这个值不能全为0,否则Gazebo会报错。简单估算就行,不用太精确。
  4. collision和visual:可以不一样。比如visual用复杂模型,collision用简化方块,能提高仿真效率。

我的经验:刚开始学URDF时,建议先用简单的几何体(box、cylinder、sphere)搭模型。等熟悉了,再换复杂的mesh文件。我见过有人一上来就用STL文件,结果坐标对不上,折腾了两天。

好了,这一讲的内容就是这些。URDF是机器人建模的基石,别看它简单,但后面所有复杂机器人都基于这个结构。把上面这个例子跑通,你就迈出了第一步。

可可精品资料库