4、URDF模型基础:URDF文件结构、link与joint的定义、可视化URDF模型
各位同学,欢迎来到第四章。从这一章开始,我们就要亲手搭建机器人的“骨架”了。
URDF,全称是Unified Robot Description Format,统一机器人描述格式。说白了,它就是一套用XML语言写的“机器人说明书”。你想想看,我们要在Gazebo里仿真一个机器人,总得告诉它:你长什么样?胳膊多长?关节能怎么动?这些信息,全都写在URDF文件里。
我个人习惯把URDF比作机器人的“身份证”加“体检报告”。它既描述了你的静态结构(link),也描述了你的活动能力(joint)。没有它,Gazebo里就是一团空气。
核心要点:URDF是ROS和Gazebo世界的“通用语言”。你写的每一个link和joint,最终都会变成仿真世界里的实体。
4.1 URDF文件结构:一棵倒着长的树
URDF文件的结构,其实就是一个树形结构。根节点在最上面,然后分叉出各种枝干。我刚开始学的时候,总觉得这玩意儿很抽象,后来在项目里调试一个六轴机械臂,天天跟这棵树打交道,才彻底搞明白。
一个标准的URDF文件,最外层是<robot>标签,里面包含两部分核心内容:link(连杆)和joint(关节)。
下面这张图,是我用SVG画的URDF结构逻辑图,你看一眼就明白了:
嗯,这里要注意:joint 必须连接两个 link,一个叫 parent(父连杆),一个叫 child(子连杆)。整个机器人就是靠这种父子关系,一层层搭起来的。
4.2 link的定义:机器人的每一块骨头
link 就是机器人的一个刚体部件。比如一个机械臂的基座、一个轮子、一个摄像头支架,都是一个 link。
每个 link 有三个核心属性需要定义:
| 属性 | 作用 | 必填 |
|---|---|---|
| visual | 视觉外观,决定你“看到”的样子 | 推荐 |
| collision | 碰撞模型,决定物理接触边界 | 推荐 |
| inertial | 惯性参数,决定质量、转动惯量 | 必须 |
来看一个最简单的 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>
这段代码定义了一个长0.4米、宽0.3米、高0.1米的蓝色盒子,质量2公斤。我在项目中遇到过一个问题:有人只写了visual,没写collision,结果仿真时机器人直接穿模到地底下去了。所以,collision 一定要写,哪怕形状跟visual一样。
小技巧:visual和collision的几何形状可以不一样。比如你为了视觉好看,用了一个复杂的mesh模型,但碰撞模型可以用一个简单的长方体代替,这样仿真计算会快很多。
4.3 joint的定义:机器人的关节
joint 定义了 link 之间的连接方式和相对运动。URDF 支持六种关节类型:
| 类型 | 说明 | 自由度 |
|---|---|---|
| revolute | 旋转关节,有限角度 | 1 |
| continuous | 连续旋转关节,无角度限制 | 1 |
| prismatic | 平移关节,直线运动 | 1 |
| fixed | 固定关节,两个link焊死 | 0 |
| floating | 浮动关节,6自由度 | 6 |
| planar | 平面关节,在平面内运动 | 3 |
最常用的是 revolute 和 fixed。来看一个旋转关节的例子:
<joint name="arm_joint" type="revolute">
<parent link="base_link"/>
<child link="arm_link"/>
<origin xyz="0.2 0 0.05" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>
这里我解释几个关键点:
- origin:关节原点在父link坐标系中的位置和姿态。说白了,就是关节长在父link的哪个位置。
- axis:旋转轴的方向。xyz=(0,0,1)表示绕Z轴旋转。
- limit:关节的运动范围。lower和upper是角度限制(弧度),effort是最大力矩,velocity是最大速度。
我曾经犯过一个低级错误:把origin的rpy写成了"0 0 0",结果关节朝向完全不对,机械臂直接扭成了麻花。后来排查了半天才发现,原来是坐标系理解错了。所以,写joint之前,先在纸上画清楚坐标系,这个习惯帮我省了不少时间。
注意:joint的origin是相对于parent link的坐标系。而link内部的visual和collision的origin,是相对于link自身的坐标系。这两个别搞混了,我见过太多人在这里栽跟头。
4.4 可视化URDF模型:眼见为实
写完了URDF文件,怎么知道对不对?别急着跑Gazebo,先用ROS自带的可视化工具检查一下。
最常用的命令是 urdf_to_graphiz 和 check_urdf:
# 检查URDF语法
check_urdf my_robot.urdf
# 生成结构图
urdf_to_graphiz my_robot.urdf
check_urdf 会告诉你有没有语法错误,比如标签没闭合、属性值写错了之类的。urdf_to_graphiz 会生成一张PDF图,把机器人的树形结构画得清清楚楚。
我个人更推荐用 RViz 来可视化:
# 启动一个空的RViz
rosrun rviz rviz
# 在RViz中,添加RobotModel显示插件
# 然后在URDF参数中填入你的URDF文件路径
在RViz里,你可以旋转、缩放、查看每个link的坐标系。我记得有一次调试一个四轮小车,四个轮子的joint方向总是对不上,就是在RViz里一个一个坐标系看过去,才发现有一个轮子的axis写反了。
调试技巧:在RViz中勾选“Show Axes”,每个link都会显示自己的坐标系。红色是X轴,绿色是Y轴,蓝色是Z轴。一眼就能看出关节朝向对不对。
还有一个在线工具叫 URDF Viz(你可以在浏览器里搜到),直接把URDF代码粘贴进去,就能看到3D模型。适合快速验证,不用启动ROS环境。
4.5 一个完整的URDF示例
最后,我放一个完整的、最简单的URDF文件。这是一个两连杆的机械臂:
<?xml version="1.0"?>
<robot name="simple_arm">
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.1" radius="0.05"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<material name="gray">
<color rgba="0.5 0.5 0.5 1"/>
</material>
</visual>
</link>
<link name="arm_link">
<visual>
<geometry>
<box size="0.02 0.02 0.3"/>
</geometry>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
</link>
<joint name="base_to_arm" type="revolute">
<parent link="base_link"/>
<child link="arm_link"/>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="5" velocity="1.0"/>
</joint>
</robot>
这个例子虽然简单,但五脏俱全。一个灰色的圆柱底座,上面连着一根红色的细长臂,关节可以绕Z轴旋转。你把它保存成 simple_arm.urdf,然后用 check_urdf 检查一下,再用RViz看看效果。
嗯,URDF的基础就这些。说白了,就是link加joint,一层层搭积木。下一节我们会在这个基础上,加入更多的细节,让机器人变得更真实。