2. 机器人URDF模型基础
URDF,全称是Unified Robot Description Format。说白了,它就是机器人的「身份证」加「骨架图」。你要让Gazebo和MoveIt认识你的机械臂,第一步就是得用URDF把它的样子说清楚。
我个人习惯把URDF理解成「搭积木」。你定义一堆零件(link),再用关节(joint)把它们连起来。嗯,就这么简单。
2.1 URDF语法:其实就两个核心标签
URDF是基于XML的。你只要掌握两个标签,就能搞定90%的建模工作:<link> 和 <joint>。
我刚开始学的时候,总想把所有参数一次性背下来。后来发现,记住核心结构就够了,细节查文档就行。来,先看一个最简机械臂的骨架:
<robot name="simple_arm">
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.1" radius="0.05"/>
</geometry>
</visual>
</link>
<joint name="joint1" 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"/>
</joint>
<link name="arm_link">
<visual>
<geometry>
<box size="0.02 0.02 0.2"/>
</geometry>
</visual>
</link>
</robot>
你看,一个底座(base_link),一根手臂(arm_link),中间用一个旋转关节(joint1)连起来。这就是一个最简单的单关节机械臂。
2.2 link定义:视觉、碰撞、惯性三件套
每个link都有三个核心部分:visual(视觉)、collision(碰撞)、inertial(惯性)。
我在项目中遇到过一个问题:机械臂在Gazebo里仿真时,明明看着没碰到东西,却一直报碰撞。后来发现,我只定义了visual,没定义collision。Gazebo默认用visual做碰撞检测,但形状对不上。所以,collision一定要单独定义。
来看一个完整的link定义:
<link name="arm_link">
<!-- 视觉部分:你看到的样子 -->
<visual>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<geometry>
<box size="0.04 0.04 0.2"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<!-- 碰撞部分:物理引擎算碰撞用的 -->
<collision>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<geometry>
<box size="0.04 0.04 0.2"/>
</geometry>
</collision>
<!-- 惯性部分:算动力学必须的 -->
<inertial>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<mass value="0.5"/>
<inertia ixx="0.001" ixy="0" ixz="0"
iyx="0" iyy="0.001" iyz="0"
izx="0" izy="0" izz="0.001"/>
</inertial>
</link>
2.3 joint定义:关节类型与坐标系
joint是连接link的桥梁。URDF支持6种关节类型,但机械臂最常用的是这几种:
| 类型 | 说明 | 典型用途 |
|---|---|---|
| revolute | 旋转关节,有角度限制 | 肩关节、肘关节 |
| continuous | 连续旋转关节,无限制 | 腕部旋转 |
| prismatic | 平移关节 | 滑轨、升降台 |
| fixed | 固定连接 | 传感器安装座 |
joint定义里,<origin> 和 <axis> 是最容易出错的。origin定义了子link相对于父link的位置偏移。axis定义了旋转轴的方向。
举个例子:
<joint name="shoulder_pan" type="revolute">
<parent link="base_link"/>
<child link="shoulder_link"/>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="10" velocity="1"/>
</joint>
这里,shoulder_link 在 base_link 上方0.1米处,绕Z轴旋转。limit定义了关节的运动范围、最大力矩和速度。
2.4 标准机械臂URDF建模实战
好了,理论说完了。咱们动手搭一个6轴机械臂。我以常见的协作臂结构为例:
先画个结构图,让你对整个骨架有个概念:
你看,从底座到末端,一层层往上搭。每个joint连接两个link,形成一个运动链。
下面是一个完整的6轴机械臂URDF片段(只展示关键部分):
<robot name="six_axis_arm" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- 底座 -->
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.05" radius="0.08"/>
</geometry>
</visual>
</link>
<!-- 关节1:腰部旋转 -->
<joint name="joint1" type="revolute">
<parent link="base_link"/>
<child link="link1"/>
<origin xyz="0 0 0.025" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="20" velocity="1.5"/>
</joint>
<link name="link1">
<visual>
<geometry>
<box size="0.06 0.06 0.15"/>
</geometry>
</visual>
</link>
<!-- 关节2:肩部俯仰 -->
<joint name="joint2" type="revolute">
<parent link="link1"/>
<child link="link2"/>
<origin xyz="0 0 0.075" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-2.09" upper="2.09" effort="20" velocity="1.5"/>
</joint>
<!-- ... 后续关节类似,依次定义link3、link4、link5、link6 -->
<!-- 末端执行器 -->
<joint name="joint6" type="continuous">
<parent link="link5"/>
<child link="end_effector"/>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<link name="end_effector">
<visual>
<geometry>
<cylinder length="0.02" radius="0.02"/>
</geometry>
</visual>
</link>
</robot>
2.5 验证你的URDF
写完了怎么知道对不对?ROS提供了两个好用的工具:
check_urdf:检查语法错误。我每次改完URDF,第一件事就是跑这个命令。urdf_to_graphiz:生成结构图。能直观看到link和joint的层级关系。
用法很简单:
# 检查URDF
check_urdf my_arm.urdf
# 生成结构图
urdf_to_graphiz my_arm.urdf
如果一切正常,你会看到类似这样的输出:
robot name is: six_axis_arm
---------- Successfully Parsed XML ----------
root link: base_link has 1 child(ren)
child(1): link1
child(1): link2
...
嗯,看到「Successfully Parsed XML」就说明你的URDF没问题了。
好了,URDF的基础就这些。说白了就是定义好每个零件的形状、位置、质量,然后用关节把它们串起来。下一节,我们会把这个URDF加载到Gazebo里,让它动起来。
可可精品资料库