4、激光雷达Gazebo插件:gazebo_plugins的Laser传感器配置、修改SDF/URDF模型文件、可视化雷达数据(rviz2)
好,咱们进入正题。这一章要解决一个核心问题:怎么让Gazebo里的虚拟激光雷达真正转起来,并且把数据送到ROS 2里,最后在rviz2上看到那熟悉的点云。
说白了,就是给仿真机器人装上一双「电子眼」。我刚开始搞仿真的时候,以为加个雷达模型就行了,结果折腾半天,Gazebo里啥数据都没有。后来才明白,缺的是那个关键的「插件」——它才是连接仿真世界和ROS 2的桥梁。
核心逻辑:Gazebo负责物理仿真,但本身不发布ROS话题。gazebo_plugins就像个翻译官,把Gazebo内部的激光数据打包成ROS 2的
4.1 gazebo_plugins的Laser传感器配置
Gazebo官方提供了一套插件库,叫gazebo_plugins。咱们要用的激光雷达插件,全名是libgazebo_ros_ray_sensor.so。嗯,名字有点长,但记住它就行。
配置这个插件,通常是在URDF或SDF文件里加一段XML。我个人习惯把它放在标签里,这样跟机器人模型的视觉、碰撞属性分开,结构更清晰。
下面是一个最基础的配置模板,我直接贴出来:
<gazebo reference="laser_link">
<sensor type="ray" name="head_laser">
<pose>0 0 0 0 0 0</pose>
<visualize>false</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>10.0</max>
<resolution>0.01</resolution>
</range>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.01</stddev>
</noise>
</ray>
<plugin name="gazebo_ros_ray_sensor" filename="libgazebo_ros_ray_sensor.so">
<ros>
<namespace>/</namespace>
<remapping>~/out:=scan</remapping>
</ros>
<output_type>sensor_msgs/LaserScan</output_type>
<frame_name>laser_link</frame_name>
</plugin>
</sensor>
</gazebo>
这里有几个参数,我重点说一下:
- samples:水平扫描的点数。360点就是每度一个点,精度够用。我曾经为了省性能设成180,结果建图时墙角老是缺一块。
- min_angle / max_angle:扫描范围,单位是弧度。±π就是360度全覆盖。如果你用单线雷达,比如只有270度视野,就改成对应的弧度值。
- update_rate:更新频率。10Hz是常规设置,跑导航够用了。设太高(比如50Hz)反而容易把CPU吃满。
- noise:噪声模型。仿真里加一点高斯噪声,数据会更真实。stddev设0.01,相当于1cm的误差,比较贴近真实雷达。
小技巧:调试阶段可以把<visualize>设为true,这样Gazebo里会画出激光射线,方便你确认雷达朝向和范围对不对。正式跑的时候再关掉,省资源。
4.2 修改SDF/URDF模型文件
有了插件配置,还得把它塞进机器人模型里。URDF和SDF两种格式我都用过,这里分别说一下。
4.2.1 在URDF中添加
URDF是ROS 1时代的主流,ROS 2也兼容。你需要在标签内,先定义好雷达的link和joint:
<link name="laser_link">
<visual>
<geometry>
<cylinder length="0.05" radius="0.03"/>
</geometry>
<material name="red"/>
</visual>
<collision>
<geometry>
<cylinder length="0.05" radius="0.03"/>
</geometry>
</collision>
</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>
然后,把上一节的配置块直接追加到文件末尾。注意reference="laser_link"要跟link的名字一致。
4.2.2 在SDF中添加
SDF是Gazebo的原生格式,功能更强大。如果你用spawn_entity.py加载模型,SDF会更方便。结构类似,但标签略有不同:
<model name="my_robot">
<link name="laser_link">
<visual>...</visual>
<collision>...</collision>
<sensor name="head_laser" type="ray">
<!-- 这里直接嵌入传感器配置 -->
<ray>...</ray>
<plugin>...</plugin>
</sensor>
</link>
</model>
我个人更推荐用URDF + 扩展的方式。原因很简单:URDF的生态更成熟,很多现成的机器人模型(比如TurtleBot3)都是这么干的,你抄作业也方便。
注意:URDF文件里,标签必须放在标签内部,但可以放在所有link和joint之后。另外,别忘了在launch文件里加载gazebo_ros2_control和robot_state_publisher,否则雷达的tf树会断掉。
4.3 可视化雷达数据(rviz2)
配置写好了,模型加载了,怎么知道雷达有没有在工作?打开rviz2看一眼就知道了。
启动rviz2的命令很简单:
rviz2
然后在界面里:
- 点击左下角的「Add」按钮。
- 在弹出窗口里选择「By topic」标签页。
- 找到
/scan话题,类型是sensor_msgs/LaserScan。 - 双击它,或者选中后点「OK」。
这时候你应该能看到一圈红色的点,那就是激光雷达的数据。如果看不到,检查以下几点:
- Fixed Frame:在rviz2左上角的「Global Options」里,把Fixed Frame设为
laser_link或base_link。默认是map,仿真里没有map帧,所以会报错。 - 话题名是否匹配:确认你的插件里
<remapping>~/out:=scan</remapping>写对了。如果话题名不对,rviz2里看不到数据。 - 雷达是否被遮挡:Gazebo里如果雷达被机器人自己的模型挡住了,射线会打在自己身上。我遇到过一回,折腾半天才发现是雷达装在了底盘内部。
调试技巧:在终端里执行ros2 topic echo /scan,如果能刷出数据,说明雷达插件工作正常。如果没数据,先检查Gazebo是否在运行,再检查插件是否加载成功(看Gazebo启动时的日志)。
4.4 本章知识体系
下面这张图,帮你把整个流程串起来:
从图里可以看得很清楚:模型文件定义雷达的物理属性,插件负责把仿真数据转成ROS话题,最后rviz2负责展示。这三者缺一不可。
4.5 常见问题与避坑
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| rviz2里看不到/scan话题 | 插件未加载或话题名不匹配 | 检查Gazebo启动日志,确认libgazebo_ros_ray_sensor.so加载成功;检查remapping配置 |
| 雷达数据全是inf或nan | 雷达被自身模型遮挡,或超出量程 | 调整雷达安装位置;检查<min>和<max>范围 |
| Gazebo启动报错:找不到插件 | gazebo_plugins包未安装 | 执行sudo apt install ros-humble-gazebo-ros-pkgs |
| 雷达数据更新很慢 | update_rate设置过低 |
提高到10Hz或20Hz;同时检查CPU负载 |
我曾经踩过一个坑:在URDF里把雷达的写错了,导致雷达装在底盘下面。结果Gazebo里雷达射线全打在地面上,rviz2里看到一圈密密麻麻的点,但就是没有障碍物信息。后来用visualize=true一看,才发现射线全朝下。所以,调试时一定要开可视化,一眼就能看出问题。