3、URDF基础标签:link、joint、geometry、origin等标签详解

好,咱们今天来聊聊URDF。这东西说白了就是机器人的“骨架描述文件”。你想想看,要让一个机器人在Gazebo里动起来,总得告诉它长什么样、关节在哪、每个零件怎么连吧?URDF就是干这个的。

我个人习惯把URDF比作乐高说明书。每个零件是一个link,连接处是joint,零件的位置和朝向由origin决定,而零件的形状就是geometry。嗯,咱们一个一个拆开讲。

3.1 link标签——机器人的“骨头”

link是URDF里最基本的单元。它描述了一个刚体部件,比如底盘、轮子、摄像头支架。每个link必须有名字,而且名字在整个机器人里不能重复。

我在项目中遇到过最坑的事,就是两个link重名了,结果Gazebo直接崩溃,连个像样的报错都没有。所以命名一定要规范,比如base_link、left_wheel_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"/>
    <material name="blue">
      <color rgba="0 0 1 1"/>
    </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>

这里有三块内容:visual(视觉)、collision(碰撞)、inertial(惯性)。

  • visual:就是你能看到的样子。Gazebo里渲染用的。
  • collision:物理引擎用来算碰撞的。我建议你尽量用简单的几何体,比如盒子、圆柱,别用太复杂的网格,否则仿真跑起来卡得要命。
  • inertial:质量、惯性矩阵。这个容易被忽略,但少了它,机器人就像在太空中飘,一推就飞走了。
小技巧:如果你懒得算惯性矩阵,可以用一个近似公式。对于长方体,ixx = (1/12) * mass * (height^2 + depth^2)。我一般写个Python脚本自动生成,省事。

3.2 joint标签——机器人的“关节”

joint连接两个link,决定了它们之间的相对运动。URDF支持好几种关节类型,我列个表给你看:

类型 说明 自由度 典型用途
fixed 固定连接,不能动 0 摄像头支架、外壳
revolute 旋转关节,有角度限制 1 机械臂关节、舵机
continuous 旋转关节,无角度限制 1 轮子、转台
prismatic 平移关节,有行程限制 1 升降台、滑轨
floating 6自由度浮动关节 6 无人机、水下机器人
planar 平面运动关节 3 AGV小车(很少用)

我曾经犯过一个低级错误:给轮子用了revolute关节,结果轮子转不到一圈就被卡住了。后来才想起来,轮子应该用continuous。你想想看,车轮哪有转半圈就停的?

一个典型的joint示例:

<joint name="left_wheel_joint" type="continuous">
  <parent link="base_link"/>
  <child link="left_wheel_link"/>
  <origin xyz="-0.2 0.15 0" rpy="0 0 0"/>
  <axis xyz="0 1 0"/>
  <limit effort="10" velocity="5"/>
</joint>

注意axis标签,它定义了旋转轴。对于轮子,一般是绕Y轴转。还有limit里的effort和velocity,分别代表最大力矩和最大速度。Gazebo的物理引擎会拿这两个值来限制关节运动。

避坑指南:我曾经在joint里忘了写axis,结果轮子原地打转,机器人纹丝不动。Gazebo默认轴是Z轴,但轮子通常绕Y轴转。所以一定要显式指定。

3.3 geometry标签——形状的定义

geometry定义了link的几何形状。支持以下几种:

  • box:长方体,用size指定长宽高。
  • cylinder:圆柱体,用radius和length。
  • sphere:球体,用radius。
  • mesh:网格文件,用filename指定STL或DAE文件。

我个人建议:能用简单几何体就别用mesh。为什么呢?因为mesh文件解析起来慢,而且碰撞检测容易出问题。我在一个项目里用了带花纹的轮胎mesh,结果Gazebo跑起来一卡一卡的,换成圆柱体后瞬间流畅。

举个例子,一个圆柱体轮子:

<geometry>
  <cylinder radius="0.1" length="0.05"/>
</geometry>

嗯,就这么简单。但要注意,cylinder的轴线默认是Z轴。如果你想让轮子竖着放,就得配合origin的旋转来调整。

3.4 origin标签——位置和朝向

origin定义了link或joint相对于父级的位置和朝向。它有两个属性:

  • xyz:平移量,单位米。
  • rpy:旋转量,单位弧度。顺序是绕X轴、Y轴、Z轴。

这里有个容易搞混的地方:origin在link里和joint里的含义不同。

  • 在link的visual里,origin是相对于该link坐标系的偏移。
  • 在joint里,origin是子link相对于父link的变换。

说白了,joint里的origin决定了子零件“长”在父零件的哪个位置。

举个例子,把左轮装在底盘左侧:

<origin xyz="-0.2 0.15 0" rpy="0 0 0"/>

意思是左轮中心在底盘坐标系中,X方向向后0.2米,Y方向向左0.15米。如果你搞反了正负号,轮子就会跑到底盘里面去。我刚开始学的时候经常犯这种错,后来养成了一个习惯:画个草图,标清楚坐标系方向。

核心要点:URDF里的坐标系遵循右手定则。X向前,Y向左,Z向上。记住这个,你的机器人就不会“拧巴”。

3.5 知识体系总览

说了这么多,咱们用一张图来总结一下URDF的核心结构。下面这张SVG图展示了link和joint如何组成一个机器人树:

URDF机器人结构树 base_link left_wheel_joint right_wheel_joint left_wheel_link right_wheel_link camera_joint camera_link link joint

看到没?整个机器人就是一棵树。根节点是base_link,每个joint连接一个父link和一个子link。这种树状结构的好处是,你修改一个零件的位置,不会影响其他零件。

3.6 实战建议

最后,给你几个我在实际项目中总结出来的建议:

  1. 先画图再写代码:拿张纸画出机器人的结构树,标清楚每个link和joint的名字,以及它们之间的相对位置。这能省掉你一半的调试时间。
  2. 用xacro代替纯URDF:URDF不支持变量和数学运算,写起来很痛苦。xacro可以定义宏、做计算,代码量能减少60%。我后面会专门讲xacro。
  3. 测试每个关节:写完URDF后,用check_urdf命令检查语法,再用urdf_to_graphiz生成结构图。确保每个关节都能正确运动。
  4. 注意单位:URDF里长度单位是米,角度是弧度。我见过有人把毫米当成米,结果机器人缩成蚂蚁大小。
调试小技巧:在Gazebo里启动机器人后,用rosrun rqt_tf_tree rqt_tf_tree查看TF树。如果某个link没出现,说明joint配置有问题。这招我用了好几年,屡试不爽。

好了,URDF的基础标签就讲到这里。记住,link是骨头,joint是关节,geometry是形状,origin是位置。把这四个搞明白,你就能搭出任何机器人的骨架了。

可可精品资料库