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,后面根据实际表现再微调。
小技巧:写URDF时,可以用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过夜

模型加载进去了,怎么知道它完不完整?我有一套自己的检查流程,分享给你:

  1. 视觉检查:在Gazebo里旋转视角,看每个连杆是否都出现了。有没有缺失的零件?颜色对不对?
  2. 关节检查:在终端运行rosservice call /gazebo/get_joint_properties "joint_name: 'joint1'",看返回值是否正常。如果返回空,说明这个关节没被Gazebo识别。
  3. TF树检查:运行rosrun rqt_tf_tree rqt_tf_tree,看TF树是否完整。每个关节都应该对应一个TF变换。如果某个关节断了,说明URDF里parent和child的链接有问题。
  4. 物理检查:用手拖动机械臂(在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的XML解析器对中文支持很差,轻则乱码,重则直接崩溃。所有注释请用英文。

最后,我画了一张图,帮你理清URDF导入Gazebo的整个流程:

URDF导入Gazebo核心流程 1. 编写URDF 定义link/joint 2. 添加Gazebo标签 摩擦/PID/传动 3. launch启动 加载到参数服务器 4. spawn_model 在Gazebo中生成 5. 检查模型 TF树/关节属性 6. 调试修正 修改URDF/参数 发现问题?返回修改URDF,重新spawn 关键:每一步都要验证,不要跳过检查环节

这张图里,我特意把“调试修正”画成了循环。因为URDF很少一次写对。我自己的记录是,一个6轴机械臂,从写URDF到能正常仿真,平均要改5-8次。别怕改,改一次就离成功近一步。

好了,这一章的内容就到这里。记住,URDF是机器人的骨架,骨架正了,后面的控制、规划才能站得稳。下一章我们会聊怎么给这个骨架加上肌肉——也就是控制器配置。

可可精品资料库