3、传感器仿真与数据获取:激光雷达、IMU、里程计仿真,话题数据可视化

传感器仿真,说白了就是给机器人装上一双“虚拟的眼睛和耳朵”。

我刚开始做导航时,总觉得真机跑起来才叫真实。后来发现,在仿真里把传感器调明白了,真机调试时间能省下一大半。你想想看,真机撞一次墙要花多少时间修车?仿真里撞一百次也就点一下重置。

这一章,我们就来搞定三个核心传感器:激光雷达、IMU、里程计。我会带着你从仿真配置到数据获取,再到可视化验证,把整个链路走通。

3.1 激光雷达仿真:从配置到点云数据

激光雷达是导航的“眼睛”。它通过发射激光束,测量周围物体的距离,生成点云数据。导航里的建图、定位、避障,都离不开它。

3.1.1 仿真模型选择

Gazebo 里常用的激光雷达模型有两种:

模型 特点 适用场景
gpu_laser 基于 GPU 加速,性能好,精度高 复杂环境、高帧率需求
ray 基于 CPU 射线追踪,配置简单 简单场景、低配机器

我个人习惯用 gpu_laser。虽然配置稍微复杂一点,但点云质量好很多。有一次我在项目里用 ray 模型,结果在走廊尽头老是检测不到墙壁,换了 gpu_laser 就正常了。

3.1.2 URDF 配置示例

下面是一个典型的激光雷达 URDF 配置。注意看 <gazebo> 标签里的插件部分,那是仿真驱动的关键。

<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.2 0 0.1" rpy="0 0 0"/>
</joint>

<gazebo reference="laser_link">
    <sensor type="gpu_ray" name="head_laser">
        <pose>0.2 0 0.1 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.10</min>
                <max>30.0</max>
                <resolution>0.01</resolution>
            </range>
        </ray>
        <plugin name="laser_controller" filename="libgazebo_ros_gpu_laser.so">
            <topicName>/scan</topicName>
            <frameName>laser_link</frameName>
        </plugin>
    </sensor>
</gazebo>
小技巧: samples 参数控制扫描线数。360 线就是每度一条线。如果你只是做避障,180 线也够用,能省不少计算资源。

3.1.3 数据获取与验证

启动仿真后,激光雷达数据会发布到 /scan 话题。你可以用命令行看一眼:

rostopic echo /scan

输出会是一大串数据。别慌,我们关心几个关键字段:

  • angle_min / angle_max:扫描角度范围,单位弧度
  • ranges:距离数组,每个角度对应的距离值
  • intensities:反射强度,有些场景下有用

我曾经踩过一个坑:仿真里激光雷达数据一切正常,但真机上就是读不到。查了半天,发现是 frame_id 没对上。嗯,这里要注意,frameName 必须和 URDF 里的 link 名称一致。

3.2 IMU 仿真:角速度与加速度数据

IMU 提供机器人的角速度和线加速度。导航里用它来做姿态估计和航迹推算。说白了,就是告诉机器人“我现在是歪的还是正的”。

3.2.1 IMU 仿真配置

IMU 的仿真配置比激光雷达简单。Gazebo 自带的 libgazebo_ros_imu.so 插件就能搞定。

<gazebo reference="imu_link">
    <sensor type="imu" name="imu_sensor">
        <pose>0 0 0 0 0 0</pose>
        <update_rate>50</update_rate>
        <plugin name="imu_controller" filename="libgazebo_ros_imu.so">
            <topicName>/imu/data</topicName>
            <frameName>imu_link</frameName>
            <bodyName>base_link</bodyName>
        </plugin>
    </sensor>
</gazebo>
注意: IMU 的 update_rate 不要设得太高。50Hz 已经够用。我曾经设到 200Hz,结果 CPU 直接拉满,仿真卡成幻灯片。

3.2.2 数据解读

IMU 数据发布在 /imu/data 话题。核心数据包括:

  • orientation:四元数表示的姿态
  • angular_velocity:角速度 (rad/s)
  • linear_acceleration:线加速度 (m/s²)

你可以在 Rviz 里添加一个 Imu 显示,直观地看到 IMU 的朝向变化。我个人习惯先用手推一下机器人模型,看 IMU 数据是不是跟着动。如果不动,八成是 bodyName 配错了。

3.3 里程计仿真:轮式编码器数据

里程计是导航的“腿”。它通过轮子转动的圈数,估算机器人走了多远、转了多少。虽然长时间会有累积误差,但短距离内非常可靠。

3.3.1 差速驱动模型

大多数机器人用的是差速驱动模型。两个轮子独立驱动,通过转速差实现转向。里程计的计算公式很简单:

v = (v_left + v_right) / 2
ω = (v_right - v_left) / wheel_separation

其中 v_left 和 v_right 是左右轮的速度,wheel_separation 是轮距。

3.3.2 Gazebo 插件配置

Gazebo 里用 libgazebo_ros_diff_drive.so 插件来模拟差速驱动和里程计。

<gazebo>
    <plugin name="diff_drive_controller" filename="libgazebo_ros_diff_drive.so">
        <leftJoint>left_wheel_joint</leftJoint>
        <rightJoint>right_wheel_joint</rightJoint>
        <wheelSeparation>0.4</wheelSeparation>
        <wheelDiameter>0.2</wheelDiameter>
        <topicName>/odom</topicName>
        <frameName>odom</frameName>
        <childFrameName>base_footprint</childFrameName>
    </plugin>
</gazebo>
关键参数: wheelSeparation 和 wheelDiameter 必须和实际模型一致。差一点,里程计就会偏。我在项目里吃过这个亏,机器人走直线走着走着就歪了,查了半天发现是轮径写错了 1 厘米。

3.4 话题数据可视化

数据有了,怎么看?Rviz 是 ROS 生态里最常用的可视化工具。我们一步步来。

3.4.1 启动 Rviz

rosrun rviz rviz

启动后,界面是空的。你需要手动添加显示项。

3.4.2 添加显示项

传感器 显示类型 话题
激光雷达 LaserScan /scan
IMU Imu /imu/data
里程计 Odometry /odom
机器人模型 RobotModel /robot_description

添加步骤很简单:

  1. 点击左下角 Add 按钮
  2. 选择对应的显示类型
  3. 在 Topic 下拉框里选择正确的话题

你想想看,如果所有数据都能在 Rviz 里看到,是不是比看命令行舒服多了?

3.4.3 可视化效果验证

启动仿真后,你应该能看到:

  • 激光雷达点云:围绕机器人一圈的白色点阵
  • IMU 姿态:一个彩色坐标系,随机器人转动
  • 里程计轨迹:一条绿色的路径线

如果某个数据没显示,先检查话题名对不对。用 rostopic list 看看当前有哪些话题。我曾经花了半小时找问题,结果发现是 /scan 写成了 /scann。多了一个 n,数据就是出不来。

3.5 本章知识体系

下面这张图总结了三个传感器的仿真链路和数据流向。你可以把它当作一个快速参考。

传感器仿真与数据获取链路 激光雷达仿真 gpu_laser / ray 模型 话题: /scan IMU 仿真 libgazebo_ros_imu.so 话题: /imu/data 里程计仿真 差速驱动插件 话题: /odom Rviz 可视化验证 💡 验证要点 1. 激光雷达点云是否覆盖 360° 无空洞 2. IMU 姿态是否随机器人转动实时更新 3. 里程计轨迹是否平滑、无跳变
我的经验: 可视化验证是排查问题最快的方式。如果激光雷达点云有空洞,检查 min_angle 和 max_angle 是不是覆盖了全范围。如果里程计轨迹跳变,检查轮距和轮径参数。别问我怎么知道的,都是血泪教训。

好了,三个传感器的仿真配置和数据获取,我们已经走了一遍。从激光雷达到 IMU 再到里程计,每一步都有对应的配置方法和验证手段。你可以在自己的仿真环境里试试,把这三个传感器都跑起来,然后在 Rviz 里看到它们的数据。