第二章:机器人模型与URDF——从结构到实战

大家好,我是你们的老朋友。今天咱们聊聊URDF,也就是机器人描述文件。说实话,我刚入行那会儿,看到URDF文件里密密麻麻的XML标签,头都大了。但后来我发现,这东西说白了就是个「机器人简历」——告诉系统你的机器人长什么样、关节怎么动、哪里是眼睛哪里是腿。

核心认知:URDF不是代码,是数据。它描述的是机器人的「静态结构」和「运动学属性」。你想想看,没有它,仿真器连你的机器人有几个轮子都不知道。

2.1 URDF文件结构解析

一个标准的URDF文件,核心就两个东西:link(连杆)和joint(关节)。我习惯把link想象成骨头,joint想象成关节。骨头本身不会动,关节决定了骨头之间怎么动。

来看一个最简单的例子——一个两轮差速底盘:

<robot name="my_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 0 0"/>
    </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>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="-0.15 -0.2 0" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
  </joint>
</robot>

嗯,这里要注意几个关键点:

  • visual:只管「看起来什么样」,不影响物理碰撞。我曾经见过有人把视觉模型做得特别精细,结果仿真卡成PPT——其实碰撞模型用个方块就够了。
  • collision:这才是物理引擎真正用的形状。我建议能简单就简单,别搞复杂。
  • inertial:惯性参数。很多人忽略这个,结果仿真里机器人飘得像气球。质量给个大概值就行,惯性矩阵用ixx=iyy=izz=0.01这种近似值也能跑。

我的小技巧:写URDF时,先画个草图,标清楚每个link的坐标系原点。不然你写出来的关节位置,很可能机器人是「拧着」的。

2.2 从SolidWorks导出URDF

手工写URDF?对于简单机器人还行。但如果你用的是SolidWorks画的复杂模型,手写会疯掉的。好在有插件——sw2urdf,能一键导出。

我当年第一次用这个插件,导出后加载到仿真里,机器人直接散架了。后来发现是坐标系没对齐。这里分享几个避坑点:

  1. 先定义好基准坐标系:在SolidWorks里,把每个零件的原点对齐到关节轴线上。我习惯把base_link的原点放在地面投影中心。
  2. 关节类型别选错:旋转关节选revolute,轮子选continuous,滑动关节选prismatic。选错了仿真里关节会乱转。
  3. 导出后检查一下:用check_urdf命令验证。我每次导出后必做这步,能发现90%的问题。

我曾经踩过的坑:导出时忘了勾选「使用STL文件」,结果导出了巨大的DAE文件,加载一次要5分钟。后来我统一用STL,文件小、加载快,而且碰撞检测更稳定。

导出后的文件结构大概是这样的:

my_robot/
├── urdf/
│   └── my_robot.urdf
├── meshes/
│   ├── base_link.stl
│   ├── left_wheel.stl
│   └── right_wheel.stl
├── launch/
│   └── display.launch
└── config/
    └── joint_limits.yaml

你想想看,有了这个结构,你只需要改改display.launch里的路径,就能在RViz里看到你的机器人了。

2.3 在仿真中加载自定义机器人

有了URDF文件,怎么把它弄到Gazebo或RViz里?我一般用launch文件搞定。来看一个典型的加载脚本:

<launch>
  <!-- 加载URDF到参数服务器 -->
  <param name="robot_description" 
         textfile="$(find my_robot)/urdf/my_robot.urdf"/>

  <!-- 启动机器人状态发布器 -->
  <node name="robot_state_publisher" 
        pkg="robot_state_publisher" 
        type="robot_state_publisher"/>

  <!-- 启动RViz -->
  <node name="rviz" pkg="rviz" type="rviz" 
        args="-d $(find my_robot)/config/display.rviz"/>
</launch>

这里有个关键点:robot_state_publisher会读取robot_description参数,然后发布TF变换。没有它,你的机器人就是一坨静止的模型。

实战经验:我第一次加载自定义机器人时,RViz里啥都没有。后来发现是robot_description参数名写错了——少了个下划线。这种低级错误,我犯了不下三次。所以建议你每次改完URDF,先用rosparam get /robot_description看看参数有没有正确加载。

如果你要在Gazebo里仿真,还需要额外加一个gazebo_ros_control插件。这个插件负责把ROS的关节指令转成Gazebo的物理力。我习惯在URDF里这样写:

<gazebo>
  <plugin name="gazebo_ros_control" 
          filename="libgazebo_ros_control.so">
    <robotNamespace>/my_robot</robotNamespace>
  </plugin>
</gazebo>

嗯,这里要注意:插件里的robotNamespace要和你的launch文件里的命名空间一致。不然控制指令发不到Gazebo里。

2.4 本章知识体系

为了让你更直观地理解URDF的整个工作流,我画了张图:

URDF工作流全景图 1. 设计机器人结构 SolidWorks / 手绘草图 2. 导出URDF sw2urdf插件 / 手动编写 3. 验证URDF check_urdf / 可视化检查 4. 加载到仿真 launch文件 + RViz/Gazebo 5. 调试与优化 调整关节参数 / 惯性参数 6. 迁移到真机 修改参数 / 硬件适配 每个步骤都可能回退到上一步,尤其是第3步验证失败时 迭代优化循环

这张图展示了我个人总结的URDF工作流。你会发现,从设计到真机部署,中间有验证和调试两个关键环节。我见过太多人跳过验证,直接加载到仿真里,结果机器人姿态不对,又回头改URDF——白白浪费半天时间。

我的建议:每次修改URDF后,先用check_urdf检查语法,再用urdf_to_graphiz生成结构图。看一眼图,你就能发现关节父子关系有没有搞错。

好了,关于URDF的核心内容就这些。说白了,它就是机器人的「骨架描述」。你掌握了link和joint的写法,学会了从SolidWorks导出,再配合launch文件加载到仿真里,就已经能应付90%的场景了。剩下的10%,是在真机迁移时才会遇到的坑——比如关节限位不一致、惯性参数需要实测校准。这些我们后面章节再细聊。

可可精品资料库