2026/10/28 7:56:17

ROS2 Humble Gazebo多线激光雷达仿真:从fishbot_description到点云可视化

ROS2 Humble Gazebo多线激光雷达仿真:从fishbot_description到点云可视化 简介这份资源是面向ROS2机器人开发初学者与仿真研究者的Gazebo多线激光雷达仿真示例工程基于ROS2 Humble与Ubuntu 22.04搭建重点提供带多线激光雷达传感器的机器人模型及配套仿真配置可用于地图构建、定位导航等感知算法的验证与学习。压缩包共30个文件约62KB以12个xacro机器人描述文件、4个Python脚本、2个yaml参数配置为主另含world仿真场景、sdf与urdf模型、rviz可视化配置、launch启动文件及说明文档结构紧凑、模块划分清晰。其中fishbot_description完整给出机器人本体描述方便快速理解模型组成并在此基础上二次修改。资源附有安装运行说明与附赠文档对参数和模块均有解释即便背景不深的用户也能顺利跑通仿真。目前已有50人学习适合想入门ROS2与Gazebo联合仿真的开发者参考实践。1. 从 fishbot_description 说起一套能跑起来的多线激光雷达仿真到底长什么样很多人第一次在 ROS2 Humble 上折腾 Gazebo 多线激光雷达卡住的地方往往不是算法而是环境本身Ubuntu 22.04 装完Gazebo 能打开机器人模型也能显示但一加雷达插件要么话题没数据要么点云稀稀拉拉像坏了一样。这个标题讲的工程本质就是把「fishbot_description 机器人描述 Gazebo 仿真配置 多线激光雷达插件」这三件事串成一条能复现的链路让你在本地把一台带多线雷达的差速小车跑起来并且能在 RViz2 里看到可用的点云。它适合两类人一类是刚学完 ROS2 话题、服务、动作想找个真实项目练手的另一类是要做 SLAM、建图、导航验证但手头没有实体雷达想先用仿真把算法跑通的。核心不是把模型画得多好看而是让雷达数据在 Gazebo 里真实产生、在 RViz2 里正确显示、能被后续节点订阅。下面按「模型怎么描述 → 仿真怎么配 → 雷达怎么出数据 → 坑在哪」的顺序讲透。2. fishbot_description 的 URDF/Xacro 结构机器人描述文件怎么组织才不返工2.1 为什么用 Xacro 而不是裸 URDF裸 URDF 写多线雷达机器人会非常痛苦底盘、左右轮、万向轮、雷达支架、雷达本体每个 link 都要写 visual、collision、inertial重复度极高。Xacro 提供宏、参数、数学运算和文件包含能把「一个轮子」抽象成宏左右轮只改参数。常见做法是把描述文件拆成几个 xacro 文件用xacro:include组合主文件只负责拼装和调用。我一般会这样分fishbot_base.xacro放底盘和轮子fishbot_lidar.xacro放雷达和支架fishbot.gazebo.xacro放 Gazebo 专用标签插件、材质、摩擦系数最后fishbot.urdf.xacro把它们 include 进来。这样改雷达型号时只动一个文件不会把底盘参数带崩。2.2 一个可复用的雷达 link 与 joint 写法下面这段是雷达本体加支架的最小写法注意inertial不能省Gazebo 里没有惯量会导致模型抖动甚至飞出去。!-- fishbot_lidar.xacro -- robot xmlns:xacrohttp://www.ros.org/wiki/xacro xacro:property namelidar_radius value0.04/ xacro:property namelidar_height value0.05/ xacro:property namelidar_mass value0.1/ link namelidar_link visual geometry cylinder radius${lidar_radius} length${lidar_height}/ /geometry material nameblack/ /visual collision geometry cylinder radius${lidar_radius} length${lidar_height}/ /geometry /collision inertial mass value${lidar_mass}/ inertia ixx${lidar_mass*0.001} ixy0 ixz0 iyy${lidar_mass*0.001} iyz0 izz${lidar_mass*0.0005}/ /inertial /link joint namelidar_joint typefixed parent linkbase_link/ child linklidar_link/ origin xyz0 0 0.12 rpy0 0 0/ /joint /robot逻辑说明lidar_link用圆柱近似雷达外形inertial里的惯量按圆柱近似公式给一个量级正确的值即可仿真不要求精确。joint用fixed类型因为雷达相对底盘不动。参数说明lidar_radius和lidar_height决定雷达在 RViz2 里的显示大小也影响 Gazebo 碰撞体origin的 z 值要和底盘高度匹配否则雷达会陷进底盘或悬空。2.3 在主 xacro 里拼装并验证主文件负责 include 和调用写完先用xacro命令转一次 URDF确认没有语法错误再进 Gazebo。# 把 xacro 转成 urdf检查语法 xacro fishbot.urdf.xacro /tmp/fishbot.urdf # 用 check_urdf 验证结构 check_urdf /tmp/fishbot.urdf逻辑说明xacro命令会展开所有宏和 include任何拼写错误、参数缺失都会在这一步报出来比在 Gazebo 里看黑屏快得多。check_urdf会检查 link 和 joint 的树结构是否合法。参数说明如果输出里出现No such file检查 include 路径如果check_urdf报root link问题检查是否有多个根 link。提示每次改完 xacro 都先跑一遍这两条命令能省掉大量在 Gazebo 里反复重启的时间。3. Gazebo 仿真配置把模型、世界和插件接起来3.1 世界文件与模型加载方式Gazebo 启动时需要知道两件事世界长什么样机器人怎么进来。常见做法是写一个.world文件里面放地面、光源然后通过 launch 文件把机器人模型 spawn 进去。世界文件不需要很复杂一个ground_plane加一个sun就够跑雷达。!-- worlds/fishbot.world -- sdf version1.6 world namedefault include urimodel://ground_plane/uri /include include urimodel://sun/uri /include /world /sdf逻辑说明include直接引用 Gazebo 自带模型库不用自己建地面。参数说明world name可以自定义但 launch 文件里要对应如果后续要加障碍物在world里继续 include 或直接写 model。3.2 launch 文件里 spawn 模型与加载插件launch 文件是整条链路的粘合剂启动 Gazebo、加载世界、把机器人描述转成参数、spawn 模型、启动 robot_state_publisher。# launch/fishbot_gazebo.launch.py import os from launch import LaunchDescription from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory def generate_launch_description(): pkg_share get_package_share_directory(fishbot_description) gazebo_ros_share get_package_share_directory(gazebo_ros) # 读取 xacro 并转成 urdf 字符串 urdf_file os.path.join(pkg_share, urdf, fishbot.urdf.xacro) robot_desc os.popen(fxacro {urdf_file}).read() return LaunchDescription([ # 启动 gazebo加载自定义世界 IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(gazebo_ros_share, launch, gazebo.launch.py) ), launch_arguments{world: os.path.join(pkg_share, worlds, fishbot.world)}.items() ), # 发布机器人描述 Node( packagerobot_state_publisher, executablerobot_state_publisher, parameters[{robot_description: robot_desc}] ), # spawn 模型到 gazebo Node( packagegazebo_ros, executablespawn_entity.py, arguments[-topic, robot_description, -entity, fishbot] ), ])逻辑说明gazebo.launch.py是 gazebo_ros 包自带的启动文件传world参数就能加载自定义世界。robot_state_publisher订阅robot_description并发布 TF。spawn_entity.py从robot_description话题读取模型并生成到 Gazebo。参数说明-entity是模型在 Gazebo 里的名字重复 spawn 同名模型会报错-topic必须和 robot_state_publisher 发布的话题一致。3.3 多线雷达插件怎么配以 ray 传感器为例Gazebo 里多线雷达靠ray传感器实现关键参数是samples每线采样数、min_angle/max_angle水平范围、vertical相关参数线数和垂直范围。下面是一个 16 线雷达的插件配置片段放在fishbot.gazebo.xacro里。gazebo referencelidar_link sensor typeray namelidar_sensor pose0 0 0 0 0 0/pose visualizetrue/visualize update_rate10/update_rate ray scan horizontal samples360/samples resolution1/resolution min_angle-3.14159/min_angle max_angle3.14159/max_angle /horizontal vertical samples16/samples resolution1/resolution min_angle-0.2618/min_angle max_angle0.2618/max_angle /vertical /scan range min0.1/min max30.0/max resolution0.01/resolution /range /ray plugin namelidar_controller filenamelibgazebo_ros_ray_sensor.so ros remapping~/out:scan/remapping /ros output_typesensor_msgs/PointCloud2/output_type frame_namelidar_link/frame_name /plugin /sensor /gazebo逻辑说明horizontal的samples决定一圈多少个点360 表示 1 度一个点vertical的samples就是线数16 表示 16 线。min_angle/max_angle用弧度垂直范围 ±0.2618 约等于 ±15 度。output_type选PointCloud2才能出三维点云选LaserScan只能出单线。参数说明update_rate是雷达频率10 表示 10Hzrange的max决定最远探测距离设太大仿真会变慢frame_name必须和 URDF 里的 link 名一致否则 RViz2 里点云位置会错。注意visualize设为 true 会在 Gazebo 里画出射线调试时有用但线数多时会明显拖慢仿真正式跑建议关掉。4. 从 Gazebo 到 RViz2点云话题、TF 与显示排查4.1 确认话题和消息类型模型跑起来后第一件事是确认雷达话题真的在发数据。# 列出所有话题 ros2 topic list # 查看 scan 话题的消息类型和频率 ros2 topic info /scan ros2 topic hz /scan # 看一帧数据 ros2 topic echo /scan --once逻辑说明topic list里应该能看到/scantopic info会显示类型是sensor_msgs/msg/PointCloud2。topic hz如果一直没输出说明插件没加载成功或话题名不对。参数说明如果话题名不是/scan检查插件里的remapping如果类型是LaserScan说明output_type配错了。4.2 RViz2 里正确显示点云的三步RViz2 显示点云翻车九成是 Fixed Frame 和 TF 的问题。按下面三步走第一步启动 RViz2把 Fixed Frame 改成base_link或lidar_link不要用map因为仿真里没有 map 到 base 的 TF。第二步Add 一个 PointCloud2 显示Topic 选/scanStyle 选 PointsSize 调小一点比如 0.01。第三步如果点云不显示先看 RViz2 左下角有没有 TF 报错再用命令确认 TF 树。# 查看 TF 树 ros2 run tf2_tools view_frames # 手动查两个 frame 之间的变换 ros2 run tf2_ros tf2_echo base_link lidar_link逻辑说明view_frames会生成一个 pdf能看到所有 frame 的连接关系。tf2_echo如果一直输出Translation和Rotation说明 TF 正常如果报Invalid frame ID说明某个 frame 没发布。参数说明base_link和lidar_link必须都在 TF 树里且lidar_link是base_link的子节点。4.3 点云稀疏或缺失的常见参数调整如果点云看起来只有几条线或者范围明显不对优先查三个参数samples、min_angle/max_angle、range的max。samples太小会导致一圈点数不够看起来像断线角度范围写错会导致只扫一半max太小会导致远处点直接消失。改完参数后不需要重新编译但要重启 Gazebo 让插件重新加载。5. 避坑与排查多线雷达仿真里最容易翻车的 5 个点现象一Gazebo 里模型加载了但/scan话题不存在。原因插件没被 Gazebo 识别通常是filename写错或gazebo_ros包没装全。 解决确认libgazebo_ros_ray_sensor.so存在用ros2 pkg prefix gazebo_ros找到路径检查gazebo_ros是否通过apt正确安装。现象二点云在 RViz2 里位置偏移或者跟着机器人乱飞。原因frame_name和 URDF 里的 link 名不一致或者 TF 没发布。 解决把插件里的frame_name改成和 URDF 完全一致的 link 名再用tf2_echo确认该 link 在 TF 树里。现象三Gazebo 启动后机器人直接掉下去或抖动。原因inertial缺失或质量、惯量设成 0。 解决每个 link 都要有inertial质量给一个合理值惯量按几何体近似给不要留空。现象四点云频率很低仿真卡顿。原因samples和线数太大或者visualize开着。 解决先把visualize关掉再把samples从 360 降到 180 试线数按实际需要设不要盲目上 32 线、64 线。现象五ros2 topic hz /scan有频率但 RViz2 里就是看不到点。原因RViz2 的 Fixed Frame 设成了map而仿真里没有map到base_link的 TF。 解决把 Fixed Frame 改成base_link或lidar_link再检查 PointCloud2 的 Topic 和 Style 设置。6. 进阶技巧用参数化 xacro 快速切换雷达线数并验证数据质量真正做项目时你不会只跑一种雷达。今天验证 16 线明天可能要对比 32 线如果每次都手改插件参数很容易改漏。我的习惯是把线数、采样数、角度范围全部抽成 xacro 参数用命令行传参生成不同配置。!-- 在 fishbot_lidar.xacro 顶部定义可覆盖参数 -- xacro:arg namelidar_lines default16/ xacro:arg namelidar_samples default360/ xacro:property namelidar_lines value$(arg lidar_lines)/ xacro:property namelidar_samples value$(arg lidar_samples)/然后在插件里引用这些属性vertical samples${lidar_lines}/samples min_angle-0.2618/min_angle max_angle0.2618/max_angle /vertical horizontal samples${lidar_samples}/samples min_angle-3.14159/min_angle max_angle3.14159/max_angle /horizontal生成时直接传参xacro fishbot.urdf.xacro lidar_lines:32 lidar_samples:720 /tmp/fishbot_32.urdf逻辑说明xacro:arg定义外部可传参数xacro:property把它变成内部属性插件里用${}引用。这样一套描述文件能生成多种雷达配置。参数说明lidar_lines控制垂直采样数即线数lidar_samples控制水平一圈点数线数和采样数越大仿真越吃 CPU建议先小后大逐步验证。验证数据质量时我一般会订阅/scan并统计一帧的点数和理论值对比。16 线 × 360 采样理论上是 5760 个点实际会因为遮挡和距离限制少一些。如果差太多就回去查range的max和角度范围。这个习惯帮我省过很多次「以为雷达坏了其实只是参数写错」的后悔药。最后说个血泪经验每次改完 xacro 和插件先跑xacro转 URDF 确认语法再启动 Gazebo最后用ros2 topic hz和 RViz2 双重确认。不要一上来就开 RViz2 盯着看那样出了问题你根本不知道是模型、插件还是显示配置的锅。希望帮到你。本文还有配套的精品资源点击获取