2、机械臂URDF模型导入:编写URDF文件、在Gazebo中加载机械臂、检查模型是否完整
好,咱们进入第二章。上一章我们把Gazebo环境搭好了,相当于有了一个舞台。这一章,我们要把主角——机械臂,请上舞台。
说白了,URDF就是机器人的“身份证”和“骨架说明书”。Gazebo不认识你买的机械臂长啥样,你得用URDF这个语言,一五一十地告诉它:这里有个关节,那里有个连杆,电机装在哪,传感器挂在哪。
我个人习惯,写URDF之前,先画个草图。哪怕用纸笔都行。把关节编号、旋转方向、连杆长度标清楚。不然写到一半,发现坐标系搞反了,那才叫头疼。
2.1 编写URDF文件:从零搭一个机械臂骨架
我们先从一个最简单的6轴机械臂开始。嗯,这里要注意,URDF的核心就是连杆(link)和关节(joint)的配对。一个关节连接两个连杆,就像人的胳膊肘连接大臂和小臂。
来看一个基础的结构:
<robot name="my_robot_arm">
<!-- 基座 -->
<link name="base_link">
<visual>
<geometry>
<box size="0.2 0.2 0.1"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
</visual>
<collision>
<geometry>
<box size="0.2 0.2 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</link>
<!-- 关节1:基座到第一段手臂 -->
<joint name="joint1" type="revolute">
<parent link="base_link"/>
<child link="link1"/>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit effort="100" velocity="1.0" lower="-3.14" upper="3.14"/>
</joint>
<link name="link1">
<visual>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
</visual>
<!-- collision 和 inertial 省略,写法同上 -->
</link>
</robot>
这段代码里,我特别想强调三点:
- visual vs collision:视觉模型可以精细,碰撞模型一定要简化。我在项目中遇到过,把碰撞模型做得跟视觉一样复杂,结果Gazebo仿真卡成PPT。用box或cylinder代替mesh,性能会好很多。
- inertial参数:这是新手最容易忽略的。没有惯性参数,模型在Gazebo里会像纸片一样飘。我建议先估算一个大概值,后面再调。
- joint的limit:effort是最大力矩,velocity是最大速度。这两个值设太小,机械臂会“无力”;设太大,仿真容易发散。我一般先设effort=100,velocity=1.0,后面根据实际表现再微调。
check_urdf命令快速检查语法错误。在终端运行check_urdf my_robot.urdf,它会告诉你哪里少了标签,哪里坐标写错了。这比直接扔进Gazebo等报错快多了。
2.2 在Gazebo中加载机械臂:让模型动起来
URDF写好了,怎么让它出现在Gazebo里?我常用的方式是通过launch文件启动。这里有个关键点:URDF本身不包含Gazebo需要的仿真参数,比如摩擦系数、电机PID。所以我们需要额外添加<gazebo>标签。
看一个典型的launch文件:
<launch>
<!-- 将URDF加载到参数服务器 -->
<param name="robot_description" textfile="$(find my_robot_description)/urdf/my_robot.urdf"/>
<!-- 启动Gazebo世界 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
</include>
<!-- 在Gazebo中生成机器人 -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model"
args="-param robot_description -urdf -model my_robot -x 0 -y 0 -z 0.1"/>
</launch>
这里有个坑,我曾经踩过:spawn_model的-z参数。如果你的基座高度是0.05米,但-z设成了0,机械臂会陷进地面一半。我建议-z设为基座高度的一半,或者直接设成0.1,确保模型稳稳站在地面上。
加载成功后,你应该能在Gazebo里看到机械臂。如果它一动不动,别慌。检查一下robot_description参数是否真的传进去了:
rosparam get /robot_description
如果输出为空,说明launch文件里路径写错了。这是我最常犯的错误——路径少写了一个斜杠。
2.3 检查模型是否完整:别让Bug过夜
模型加载进去了,怎么知道它完不完整?我有一套自己的检查流程,分享给你:
- 视觉检查:在Gazebo里旋转视角,看每个连杆是否都出现了。有没有缺失的零件?颜色对不对?
- 关节检查:在终端运行
rosservice call /gazebo/get_joint_properties "joint_name: 'joint1'",看返回值是否正常。如果返回空,说明这个关节没被Gazebo识别。 - TF树检查:运行
rosrun rqt_tf_tree rqt_tf_tree,看TF树是否完整。每个关节都应该对应一个TF变换。如果某个关节断了,说明URDF里parent和child的链接有问题。 - 物理检查:用手拖动机械臂(在Gazebo里按住Shift+鼠标左键),看关节是否按预期旋转。如果关节卡死或者乱晃,通常是
limit参数或者inertial参数设错了。
- 所有link都有visual、collision、inertial三个标签
- 所有joint的parent和child名称正确,没有拼写错误
- 关节的axis方向正确(绕X、Y还是Z轴旋转)
- 模型没有穿透地面(检查base_link的origin)
- Gazebo控制台没有红色ERROR输出
为什么会强调这些?因为URDF里一个字母错了,比如把joint1拼成jiont1,Gazebo不会报错,它只会默默地忽略这个关节。然后你调试半天,发现机械臂少了一截。嗯,这种问题我至少遇到过三次。
最后,我画了一张图,帮你理清URDF导入Gazebo的整个流程:
这张图里,我特意把“调试修正”画成了循环。因为URDF很少一次写对。我自己的记录是,一个6轴机械臂,从写URDF到能正常仿真,平均要改5-8次。别怕改,改一次就离成功近一步。
好了,这一章的内容就到这里。记住,URDF是机器人的骨架,骨架正了,后面的控制、规划才能站得稳。下一章我们会聊怎么给这个骨架加上肌肉——也就是控制器配置。