第四节:传感器仿真与数据输出

传感器是机器人的眼睛和耳朵。没有它们,导航就是盲人摸象。今天我们来聊聊如何在Gazebo里把激光雷达、IMU和里程计这些传感器仿真出来,并且让数据在Rviz2里乖乖显示。

我个人习惯先把传感器模型搭好,再调参数。这样出了问题,排查起来也快。你想想看,如果传感器数据都不对,后面的定位和规划全是白搭。

核心要点:传感器仿真的本质,就是用数学模型模拟真实物理传感器的输出。Gazebo里每个传感器插件,都在做这件事。

4.1 激光雷达仿真配置

激光雷达是导航的主力传感器。我最早做项目时,用的还是单线雷达,扫一圈就一条线。现在主流是16线、32线,甚至固态激光雷达。但仿真原理都一样。

Gazebo里用 gazebo_ros_ray_sensor 或者 gazebo_ros_laserscan 插件来模拟激光雷达。我个人推荐用后者,因为它直接输出 LaserScan 消息,省去自己转换的麻烦。

下面是一个典型的激光雷达URDF配置:

<link name="laser_link">
  <visual>
    <geometry>
      <cylinder length="0.05" radius="0.03"/>
    </geometry>
    <material name="red"/>
  </visual>
</link>

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

<gazebo reference="laser_link">
  <sensor type="ray" name="head_laser">
    <pose>0 0 0 0 0 0</pose>
    <visualize>true</visualize>
    <update_rate>10</update_rate>
    <ray>
      <scan>
        <horizontal>
          <samples>360</samples>
          <resolution>1</resolution>
          <min_angle>-3.14159</min_angle>
          <max_angle>3.14159</max_angle>
        </horizontal>
      </scan>
      <range>
        <min>0.1</min>
        <max>30.0</max>
        <resolution>0.01</resolution>
      </range>
      <noise>
        <type>gaussian</type>
        <mean>0.0</mean>
        <stddev>0.01</stddev>
      </noise>
    </ray>
    <plugin name="laser_controller" filename="libgazebo_ros_laserscan.so">
      <topicName>/scan</topicName>
      <frameName>laser_link</frameName>
    </plugin>
  </sensor>
</gazebo>

这里有几个参数我特别想强调一下:

  • samples:扫描点数。360点就是每度一个点。我见过有人设成1080,精度是高,但CPU扛不住。
  • update_rate:更新频率。10Hz是常规设置,实车一般5-20Hz。
  • noise:噪声模型。真实雷达都有噪声,仿真里加一点高斯噪声,数据更真实。

小技巧:调试时把 <visualize>true</visualize> 打开,Gazebo里会显示射线。这样你能直观看到雷达扫到了什么。

4.2 IMU数据仿真

IMU提供角速度和线加速度。它不直接用于导航,但和里程计融合后,定位精度能提升不少。

Gazebo里用 gazebo_ros_imu 插件来模拟IMU。配置起来比激光雷达简单:

<gazebo reference="imu_link">
  <sensor type="imu" name="imu_sensor">
    <pose>0 0 0 0 0 0</pose>
    <update_rate>100</update_rate>
    <plugin name="imu_plugin" filename="libgazebo_ros_imu.so">
      <topicName>/imu/data</topicName>
      <frameName>imu_link</frameName>
      <initialOrientationAsReference>false</initialOrientationAsReference>
    </plugin>
  </sensor>
</gazebo>

嗯,这里要注意 initialOrientationAsReference 这个参数。如果设为true,IMU的初始朝向会被当作零位。我踩过这个坑——有一次仿真时IMU数据一直飘,查了半天才发现是这个参数没设对。

IMU的更新频率通常比激光雷达高很多。100Hz是常规值,有些高精度IMU能到200Hz。但频率越高,CPU负载越大,自己权衡。

4.3 里程计(Odometry)仿真

里程计来自轮式编码器。它告诉你机器人走了多远、转了多少角度。Gazebo里没有直接的里程计插件,但我们可以通过 gazebo_ros_diff_drive 插件来获取。

差速驱动是两轮机器人最常见的底盘形式。配置如下:

<gazebo>
  <plugin name="diff_drive_controller" filename="libgazebo_ros_diff_drive.so">
    <ros>
      <namespace>/</namespace>
    </ros>
    <updateRate>50</updateRate>
    <leftJoint>left_wheel_joint</leftJoint>
    <rightJoint>right_wheel_joint</rightJoint>
    <wheelSeparation>0.4</wheelSeparation>
    <wheelDiameter>0.2</wheelDiameter>
    <torque>20</torque>
    <commandTopic>cmd_vel</commandTopic>
    <odometryTopic>odom</odometryTopic>
    <odometryFrame>odom</odometryFrame>
    <robotBaseFrame>base_footprint</robotBaseFrame>
  </plugin>
</gazebo>

这个插件会发布 nav_msgs/Odometry 消息。它根据左右轮的速度,计算出机器人的位姿和速度。说白了,就是模拟了真实编码器的工作。

我曾经在项目里遇到过一个问题:里程计数据跳变。后来发现是 wheelSeparation 和 wheelDiameter 设错了。这两个参数必须和实际模型完全一致,否则里程计会严重失真。

避坑指南:里程计的坐标系是 odom,机器人本体坐标系是 base_footprint 或 base_link。这两个坐标系之间的变换,由里程计数据实时更新。如果坐标系关系搞错了,Rviz2里看到的机器人会到处乱飘。

4.4 在Rviz2中可视化传感器数据

数据有了,怎么看?Rviz2是ROS2的标配可视化工具。启动它很简单:

rviz2

然后手动添加显示项:

  • 激光雷达:Add → LaserScan,Topic选 /scan
  • IMU:Add → Imu,Topic选 /imu/data
  • 里程计:Add → Odometry,Topic选 /odom
  • 机器人模型:Add → RobotModel

我个人习惯把Rviz2的配置保存下来,下次直接加载:

rviz2 -d my_config.rviz

这样就不用每次重新添加了。省时间。

可视化时,有几个小细节:

  • 激光雷达的点云颜色可以调。我一般用 Intensity 模式,颜色越亮表示反射越强。
  • IMU数据默认显示为箭头。箭头方向表示加速度方向,长度表示大小。
  • 里程计显示为路径。你可以看到机器人走过的轨迹。

调试技巧:如果Rviz2里看不到数据,先检查话题是否存在:ros2 topic list。再检查话题类型:ros2 topic info /scan。最后用 ros2 topic echo /scan 看数据内容。三步排查法,基本能解决90%的问题。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。你一看就明白:

传感器仿真与数据输出知识体系 Gazebo仿真环境 物理引擎 + 传感器模型 激光雷达 (LaserScan) IMU (惯性测量单元) 里程计 (Odometry) gazebo_ros_laserscan.so gazebo_ros_imu.so gazebo_ros_diff_drive.so /scan /imu/data /odom Rviz2 可视化

从这张图可以清楚看到:Gazebo仿真环境通过传感器插件,把物理模拟数据转换成ROS2话题。Rviz2订阅这些话题,把数据可视化出来。整个链路清晰明了。

最后说一句:传感器仿真不是越复杂越好。够用就行。我见过有人把激光雷达噪声模型调得极其精细,结果导航效果反而变差了。为什么?因为真实环境中的噪声,和仿真里的噪声,永远不可能完全一样。适可而止,才是工程智慧。

可可精品资料库