4 · 添加传感器与执行器

激光雷达、IMU与轮式编码器的URDF集成

好,咱们进入第四章。前面你已经有了一台能动的机器人骨架,但说实话,它还是个「盲人」——没有眼睛,没有平衡感,也不知道自己走了多远。这一章我们就给它装上传感器和执行器。我个人习惯把这一步叫做「赋予机器人知觉」。你想想看,没有激光雷达和IMU,Nav2根本没法定位和避障。所以这部分是联调的基础,也是很多新手容易出岔子的地方。

URDF 传感器集成 激光雷达 LiDAR IMU 惯性测量 轮式编码器 执行器模型 joint + link + 插件/传动

4.1 激光雷达的URDF集成

激光雷达,也就是LiDAR,是Nav2的「眼睛」。我见过不少同学直接把雷达模型往机器人顶上一放,连坐标系都歪了。结果建图全是重影。其实在URDF里加一个雷达传感器非常简单,核心就是定义一个link和一个joint,再挂上Gazebo插件。

下面是一个典型的2D激光雷达URDF片段。我用的是RPLidar A1的尺寸,但你可以换成任何雷达。

<!-- LiDAR link -->
<link name="laser_link">
  <visual>
    <geometry>
      <cylinder length="0.04" radius="0.035"/>
    </geometry>
    <material name="black"/>
  </visual>
  <collision>
    <geometry>
      <cylinder length="0.04" radius="0.035"/>
    </geometry>
  </collision>
</link>

<joint name="laser_joint" type="fixed">
  <parent link="base_link"/>
  <child link="laser_link"/>
  <origin xyz="0.12 0 0.08" rpy="0 0 0"/>
</joint>

嗯,这里要注意:origin的z值决定了雷达离地高度。如果你做的是室内机器人,0.08~0.15米比较常见。我曾经在一个项目里把雷达装歪了0.5度,结果建图时走廊总是斜的……调了我一下午。所以,装雷达一定要保证水平。

💡 个人技巧: 在Gazebo中仿真时,记得给laser_link添加gazebo_ros_ray_sensor插件。不然你的雷达在仿真里就是摆设。插件配置我一般放在单独的文件里,用xacro包含进来,保持URDF干净。

4.2 IMU的URDF集成

IMU提供角速度和加速度。Nav2的里程计融合里,IMU能大幅提升航向精度。说白了,没有IMU,你的机器人转弯时里程计容易飘。我个人习惯把IMU放在机器人的几何中心附近,这样角速度测量最准。

<link name="imu_link">
  <visual>
    <geometry>
      <box size="0.03 0.03 0.02"/>
    </geometry>
    <material name="blue"/>
  </visual>
</link>

<joint name="imu_joint" type="fixed">
  <parent link="base_link"/>
  <child link="imu_link"/>
  <origin xyz="0 0 0.04" rpy="0 0 0"/>
</joint>

你看,IMU的link通常很小,一个蓝色小方块就代表它了。实际中IMU芯片也就指甲盖大小。但坐标系一定要和base_link对齐,否则后续EKF融合会出奇怪的角度偏移。我遇到过有人把IMU装反了,roll和pitch互换,定位直接炸掉。

⚠️ 避坑指南: 我曾经在调试时发现IMU数据一直有固定偏置,查了半天,原来是URDF里IMU的origin写错了rpy,导致仿真中重力方向投影错误。所以,务必检查rpy是否全为零,除非你有意倾斜安装。

4.3 轮式编码器模型

轮式编码器其实不是「视觉」模型,而是执行器的一部分。在URDF里,我们通常用<transmission>标签把电机和车轮关节关联起来。这样Gazebo才能模拟编码器输出里程计。

来看一个典型的差速驱动轮编码器配置:

<transmission name="left_wheel_trans">
  <type>transmission_interface/SimpleTransmission</type>
  <joint name="left_wheel_joint">
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  </joint>
  <actuator name="left_wheel_motor">
    <mechanicalReduction>1</mechanicalReduction>
  </actuator>
</transmission>

这里的关键是hardwareInterface。如果你用Gazebo仿真,必须声明VelocityJointInterface,这样ros_control才能给车轮发速度指令,同时读取编码器反馈。实际机器人上可能用EffortJointInterface,但原理一样。

组件URDF元素作用
激光雷达link + joint + gazebo插件提供激光扫描数据(/scan)
IMUlink + joint + gazebo插件提供imu/data(角速度+加速度)
轮式编码器transmission + joint + hardwareInterface模拟里程计(/odom)
🔧 实战要点: 编码器模型本身不直接出现在Rviz中,但它的数据质量直接影响Nav2的定位。我建议你在URDF里为每个轮子单独定义transmission,并且减速比(mechanicalReduction)一定要和实际电机一致。之前有个学员设成了10:1但实际是30:1,结果机器人走1米,里程计显示3米,导航直接抽风。

4.4 整合到机器人模型

把上面三个传感器/执行器加进你的robot.urdf。我习惯在<robot>根标签里按顺序放:base_link → 激光雷达 → IMU → 车轮transmission。这样结构清晰。最后别忘了在Gazebo启动脚本里加载对应的控制器(比如joint_state_controller和diff_drive_controller)。

嗯,这一章的内容其实不难,但细节很多。你只要记住:每个传感器都是一个link,通过固定关节连到base_link上,然后配上对应的Gazebo插件或transmission。下次我们会在Gazebo里实际测试这些传感器是否工作正常。