第3章:URDF机器人建模
URDF,全称是Unified Robot Description Format。说白了,它就是ROS世界里描述机器人长什么样的标准语言。你想想看,要让机器人在Gazebo里动起来,总得先告诉它:你长什么样?胳膊多长?轮子多大?传感器装在哪?这些信息,都得靠URDF来定义。
我个人习惯把URDF理解成机器人的「身份证」加「骨架图」。它用XML格式,把机器人的每个部件、每个关节都描述得清清楚楚。刚开始接触时可能会觉得标签有点多,但别急,咱们一个一个来拆解。
3.1 URDF语法基础
URDF文件本质上就是个XML文件。所以它的基本规则很简单:有根标签、有子标签、有属性。根标签是<robot>,所有内容都包在里面。
来看个最简单的例子:
<?xml version="1.0"?>
<robot name="my_robot">
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.3 0.1"/>
</geometry>
</visual>
</link>
</robot>
这段代码定义了一个叫my_robot的机器人,它只有一个部件base_link,形状是个长方体。嗯,这里要注意:size属性的三个值分别对应长、宽、高,单位是米。
3.2 link与joint定义
一个完整的机器人,不可能只有一个部件。多个部件之间怎么连接?这就用到<joint>标签了。
<link>定义的是「刚体」——也就是不会变形的部件。每个link可以包含:
- visual:视觉外观,用于显示
- collision:碰撞模型,用于物理仿真
- inertial:惯性参数,用于动力学计算
<joint>定义的是「连接关系」——两个link之间的约束。常见的joint类型有:
| 类型 | 说明 | 自由度 |
|---|---|---|
| fixed | 固定连接,不能动 | 0 |
| revolute | 旋转关节,像门轴 | 1 |
| prismatic | 滑动关节,像抽屉 | 1 |
| continuous | 无限旋转,像车轮 | 1 |
我在项目中遇到过最坑的事:把轮子关节设成了revolute,结果机器人转了几圈就卡住了。后来才意识到,车轮应该用continuous。这种细节,文档里不会特意提醒你。
来看一个带joint的完整例子:
<robot name="two_wheel_robot">
<link name="base_link">
<visual>
<geometry>
<cylinder radius="0.1" length="0.3"/>
</geometry>
</visual>
</link>
<link name="left_wheel">
<visual>
<geometry>
<cylinder radius="0.05" length="0.02"/>
</geometry>
</visual>
</link>
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 -0.15 0" rpy="0 1.57 0"/>
<axis xyz="0 0 1"/>
</joint>
</robot>
这里<origin>定义了子link相对于父link的位置偏移,rpy是旋转角度(滚转、俯仰、偏航)。<axis>指定了关节的旋转轴方向。
rpy的单位搞错了,以为是角度,结果写了个90度进去。实际上URDF里用的是弧度!1.57才是90度。这个错误让我排查了整整一个下午。
3.3 传感器模型添加
光有机械结构还不够,机器人得感知环境吧?URDF里可以添加各种传感器模型。最常见的是激光雷达和摄像头。
添加传感器其实就是在机器人上再加一个link,然后挂上对应的传感器插件。不过URDF本身只负责「外观」,传感器的「功能」要靠Gazebo插件来实现。
来看一个添加激光雷达的例子:
<link name="laser_link">
<visual>
<geometry>
<cylinder radius="0.03" length="0.05"/>
</geometry>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
</link>
<joint name="laser_joint" type="fixed">
<parent link="base_link"/>
<child link="laser_link"/>
<origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>
这样就在机器人前方0.2米、高度0.1米的位置装了个红色的小圆柱体,代表激光雷达。至于它能不能真的扫描到障碍物,那得在Gazebo里配置传感器插件才行。
3.4 可视化检查
写完了URDF,怎么知道对不对?别急着跑Gazebo,先用ROS自带的可视化工具检查一下。
我最常用的方法是:
- 用
check_urdf命令检查语法 - 用
urdf_to_graphiz生成结构图 - 在RViz里加载模型看效果
具体操作:
# 检查URDF文件语法
check_urdf my_robot.urdf
# 生成结构图(需要安装graphviz)
urdf_to_graphiz my_robot.urdf
# 在RViz中查看
roslaunch urdf_tutorial display.launch model:=my_robot.urdf
check_urdf会告诉你有没有语法错误、关节定义是否完整。urdf_to_graphiz会生成一张PDF图,清晰地展示所有link和joint的层级关系。
我个人习惯在RViz里做最终检查。因为有些问题,比如link位置不对、关节方向反了,光看代码是看不出来的。在3D视图里转一圈,问题一目了然。
下面这张图展示了URDF建模的核心流程:
URDF建模其实就是一个「搭积木」的过程。先定义一个个独立的link,然后用joint把它们连接起来,最后加上传感器。每一步都可以在RViz里实时看到效果,非常直观。
嗯,说到这我想起一个细节:很多新手会把所有link都写在一个文件里。我个人建议按功能模块拆分,比如chassis.urdf、arm.urdf、sensors.urdf,然后用<xacro:include>引入。这样后期维护起来方便得多。