兄弟们,搞过激光SLAM的应该都有体会:算法写好了,想在真机上跑一把,光硬件调试就能磨掉你一周的耐心。Mid360这颗雷达本身不贵,但你要给它配个好点的机载电脑、调好驱动、标定外参,再找个有特征、不炸场的室内外环境,这一套下来,FAST-LIO2还没上场,人先被环境劝退了。所以我折腾了一圈之后,干脆直接在Gazebo里搭了一个Livox Mid360的仿真平台,把FAST-LIO2的整套测试流程都搬到仿真里跑。这玩意儿能解决什么问题?很简单:环境可控、成本为零、姿势随便换,传感器参数随时改。不管你是刚入门想复现FAST-LIO2,还是想研究不同雷达参数对定位精度的影响,这套方案都适合你。
我写这篇东西,不是给你贴一段官方wiki,而是把我踩过的坑、查过的源码、试过的参数都摊开讲清楚。你照着我这个流程走,最快一个下午就能让FAST-LIO2在Gazebo里跑起来,还能自己改雷达配置做各种实验。
1. 先搞清楚:仿真平台到底该解决什么问题
很多人一上来就急着装环境、跑包,结果跑起来之后发现点云是畸形的、坐标系全乱、tf报错刷屏,然后就开始怀疑人生。这里我想先聊两句思路,因为这比装任何软件都重要。
1.1 做激光SLAM仿真,本质是在模拟什么
FAST-LIO2这类算法,核心输入只有两样东西:高频IMU数据和雷达点云。算法做的事情就是拿IMU做运动预测,拿点云做迭代更新。所以仿真平台要解决的,本质就是两个问题:怎么让雷达在虚拟世界里"看见"东西,以及怎么让IMU数据跟虚拟运动对得上。
很多人忽略的是,仿真里最容易出问题的不是雷达本身,而是时间戳和坐标系。Gazebo里每个传感器都带自己的时间戳,FAST-LIO2对IMU和雷达的时间同步很敏感,差个几十毫秒,点云就会飘。我见过不少人仿真点云一塌糊涂,查了半天发现是Gazebo仿真时间跑得比CPU快,导致IMU回调堆积。这些问题,你如果心里没底,后面大概率会踩。
1.2 为什么选Mid360做仿真对象,而不是64线机械雷达
Mid360这款雷达在仿真里特别"友好"。它的视场角是竖直方向60度、水平360度,但每帧点云是非重复扫描的,也就是说每一帧点云覆盖的区域会随时间变化累积。Gazebo里模拟这种非重复扫描,实际是通过持续旋转的采样图案实现的,效果非常接近于真实雷达的点云分布。
对比一下传统的Velodyne VLP-16仿真模型,最核心的差异在于:VLP-16只有16个固定的扫描环,点云稀疏但规整;Mid360的点云更“散”,但视场角更大,对近距离环境的感知明显更强。FAST-LIO2在低线数雷达上的表现本来就不错,换成Mid360的模型之后,你会发现它对稀疏特征的敏感度更高,算法里那个迭代更新部分跑得更“用力”。这正好能帮你暴露一些在理想点云下发现不了的问题。
1.3 这套方案的适用范围与局限性
先说实话,仿真平台跑FAST-LIO2,验证的是算法逻辑和参数调优,不是替代真机验证。Gazebo用的物理引擎再怎么调,也不可能完美复现真实雷达的噪声特征、IMU的零偏漂移、或者点云在强光下的退化问题。
但它的优势也极其明显:你可以秒切环境、随时改雷达安装角度、故意给IMU加噪声、测试不同算法的鲁棒性。甚至你可以把Gazebo的场景换成一片没有任何特征的平地,看看FAST-LIO2多久会挂掉,这种实验在真机上做一次的成本,够你在仿真里做一百次。
所以我给你的建议是:仿真平台用来做算法迭代和参数调优,真机只做最终确认。这样效率最高,钱包也最稳。
2. 环境准备与基础搭建:Ubuntu 22.04 + ROS 2 Humble + Gazebo
我推荐直接上Ubuntu 22.04搭配ROS 2 Humble,别再用ROS 1 Noetic了。FAST-LIO2官方仓库虽然历史版本是基于ROS 1开发的,但现在大部分分支都已经迁移到ROS 2,而且ROS 2在时间同步、多线程处理上明显更适合跑这种强实时性算法。你要是还在纠结用哪个版本,我一句话:新项目一律ROS 2,能省掉很多后面的兼容性痛苦。
2.1 系统与ROS安装:别再手动折腾依赖
Ubuntu 22.04装ROS 2 Humble,官方文档写得很全,但手动一步步装下来,尤其在网络不太稳定的情况下,能把人折磨疯。我个人的建议是直接用鱼香ROS的一键安装脚本,这东西在圈子里已经算得上是标配工具了。它会把ROS本体、依赖、pip源、系统依赖全部处理完,中间几乎不需要干预。
小鱼ROS一键安装的好处不光在于快,更关键的是它做了很多“隐性修复”。比如他会帮你装好rosdep的依赖数据库,否则你后面编译FAST-LIO2的时候,rosdep install那一步就可能卡半天。我实测下来,用一键安装脚本之后,整个环境初始化时间从一下午缩短到二十分钟以内。
装完之后,确认一下环境变量是否写入~/.bashrc,然后终端里敲ros2 --version,能输出版本号就说明ROS 2装好了。这里有个小坑:很多教程会让你在/opt/ros/humble/setup.bash前面加source,但一键安装脚本一般会自动处理,你只需确认自己的~/.bashrc里没有重复source两遍导致环境变量混乱。
2.2 Gazebo版本选择:Gazebo Classic与Ignition怎么选
很多人问Gazebo 11和Ignition Gazebo到底有什么区别。以ROS 2 Humble为基准,原生的gazebo_ros_pkgs支持的是Gazebo Classic(Gazebo 11),而Ignition Gazebo(也就是现在的Gazebo Garden、Fortress)对应的是ros_gz那套桥接方案。
这里我强烈建议你选Gazebo Classic 11,原因有三:
- 第一,FAST-LIO2相关的仿真脚本绝大多数都是基于Classic写的,你拿过来就能直接用,不用改。
- 第二,
gazebo_ros_pkgs在Classic下的生态成熟度更高,传感器插件、曲线插件都是一键接入。 - 第三,市面上能找到的教程、示例世界文件,90%都是Classic格式,遇到问题好查资料。
如果你是Ubuntu 22.04 + ROS 2 Humble,安装指令就是简单的:
sudo apt install ros-humble-gazebo-ros-pkgs它会自动把Gazebo 11和对应的ROS 2接口包装好。装完以后,终端输入gazebo如果能起来一个空世界,说明基础环境已经通了。注意,如果打开Gazebo后渲染黑屏或者卡死,多半是显卡驱动问题,或者是OpenGL版本太低,这个后面常见问题部分我会专门讲。
2.3 创建工作空间与基础验证
环境装好之后,先别急着拉算法代码,我们需要先建一个干净的工作空间,用来放雷达模型、URDF文件和GPS等辅助文件。
mkdir -p ~/mid360_ws/src cd ~/mid360_ws colcon build --symlink-install--symlink-install这个参数特别重要,它会让你的Python脚本和配置文件以软链接方式安装,你改完代码不用重新build,刷新一下节点就生效。对做仿真调试来说,这个特性省下的编译等待时间不是一星半点。
建完工作空间,顺手装一个robot_state_publisher和joint_state_publisher,后面发布URDF机器人的tf树要用。
sudo apt install ros-humble-robot-state-publisher ros-humble-joint-state-publisher装好后,我们就可以开始进入仿真雷达模型的核心工程了。
3. 搭建Livox Mid360雷达的Gazebo模型
这一部分是整个仿真平台的灵魂。我看到很多人直接在公园里的模型包里找Mid360的现成模型,但说真的,那些模型不是参数不对,就是坐标系歪的。最好还是自己从零写一套URDF,这样你能完全掌控雷达的安装角度、点云频率、噪声参数,后面做FAST-LIO2测试才有意义。
3.1 从Blender导出还是直接写URDF
搜索热词里有人提到“Blender导出Gazebo模型”,这是个可行路子,但对雷达这种简单几何体来说,完全是杀鸡用牛刀。Mid360的外形就是一个圆柱体加顶盖,你直接用URDF里的<mesh>标签指向一个简单的STL文件,或者干脆用<box>、<cylinder>这些基础形状组合,Gazebo渲染出来效果完全够用,还省去一堆Dae纹理转格式的麻烦。
我的建议是:雷达外壳用STL模型(网上能找到Mid360的简化版模型),底座和安装支架用基础几何体。这样模型简单直观,后续改尺寸、调安装高度都方便。
3.2 URDF文件核心:坐标系与雷达光学中心
写URDF最重要的一件事就是坐标系的定义。FAST-LIO2默认认为雷达坐标系的原点位于激光发射中心,Z轴朝上,X轴朝前。你在仿真里如果不把雷达link的坐标系设对,后面的tf树就会乱成一锅粥。
下面是一个标准的Mid360雷达link定义,我直接贴我调试好的版本:
<link name="mid360_link"> <visual> <geometry> <mesh filename="package://mid360_description/meshes/mid360.stl" /> </geometry> <origin xyz="0 0 0" rpy="0 0 0" /> </visual> <collision> <geometry> <mesh filename="package://mid360_description/meshes/mid360.stl" /> </geometry> </collision> <inertial> <mass value="0.265" /> <inertia ixx="0.001" ixy="0.0" ixz="0.0" iyy="0.001" iyz="0.0" izz="0.001" /> </inertial> </link> <gazebo reference="mid360_link"> <sensor type="gpu_ray" name="mid360_sensor"> <update_rate>10</update_rate> <visualize>true</visualize> <pose>0 0 0 0 0 0</pose> <plugin filename="libgazebo_ros_ray_sensor.so" name="gazebo_ros_mid360"> <ros> <namespace>/mid360</namespace> <remapping>~/out:=pointcloud</remapping> </ros> <output_type>sensor_msgs/msg/PointCloud2</output_type> <min_range>0.1</min_range> <max_range>40.0</max_range> <noise_mean>0.0</noise_mean> <noise_stddev>0.01</noise_stddev> </plugin> </sensor> </gazebo>这个文件里,重点是gpu_ray传感器类型。用GPU射线插件去模拟雷达点云,速度远快于原来的CPU版ray插件,在复杂环境里跑FAST-LIO2不卡顿。output_type一定要设成PointCloud2,因为FAST-LIO2订阅的就是sensor_msgs/PointCloud2格式。如果你想跟一些老代码兼容,也可以改成sensor_msgs/msg/LaserScan,但那样会丢失三维信息,不推荐。
3.3 发射线束参数配置:如何模拟Mid360的非重复扫描
Mid360的真实扫描特性是非重复扫描,也就是说雷达内部的棱镜在不断改变扫描图案,时间越长覆盖密度越高。在Gazebo里精确复现这个特性很困难,但我们可以用多组环线近似。
如果你想完全按手写的3D射线配置来做,可以把<samples>设置成一个比较大的值,然后通过<scan>标签里的<horizontal>和<vertical>配置视场角。Mid360的竖直视场角是-7度到52度,水平是360度。我实测下来,用下面这组参数效果最接近:
<scan> <horizontal> <samples>360</samples> <resolution>1</resolution> <min_angle>0</min_angle> <max_angle>6.283185</max_angle> </horizontal> <vertical> <samples>64</samples> <resolution>1</resolution> <min_angle>-0.12217</min_angle> <max_angle>0.90757</max_angle> </vertical> </scan>这里samples=360,表示水平一圈采360个点;vertical的samples=64,表示竖直方向分64层。角度范围就是用弧度表示的-7度和52度。这样一帧点云就是360×64=23040个点,跟真机Mid360每帧的点云量在一个量级上。
注意,这里的<resolution>不是角度分辨率,而是采样步长,一般设1就行。如果你把samples调太高,比如1920×128,GPU射线插件的计算量会暴涨,FAST-LIO2的运行频率会被拖垮。先用23040个点跑通,后面要调精度再慢慢加。
3.4 给Gazebo模型加上IMU:时间同步的关键
FAST-LIO2是紧耦合雷达惯性里程计,没有IMU数据它直接罢工。所以仿真里必须加一个IMU传感器,而且要保证IMU的频率、噪声特征和真实型号对得上。
Mid360内置的IMU频率是200Hz,我在URDF里也保持一致:
<gazebo reference="base_link"> <sensor type="imu" name="mid360_imu"> <update_rate>200</update_rate> <always_on>true</always_on> <plugin filename="libgazebo_ros_imu_sensor.so" name="mid360_imu_plugin"> <ros> <namespace>/mid360</namespace> <remapping>~/out:=imu</remapping> </ros> <initial_orientation_as_reference>false</initial_orientation_as_reference> </plugin> </sensor> </gazebo>update_rate=200这个值不要随意改。FAST-LIO2内部对IMU频率有预设,你如果改成100Hz,虽然也能跑,但初始化收敛可能会变慢,特别是快速旋转的时候。initial_orientation_as_reference设为false是为了让IMU输出原始的角速度和线加速度,不做任何重力对齐处理,这样算法那边处理起来更干净。
另一个容易踩的坑是IMU噪声参数。Gazebo默认的IMU插件输出的是无噪声的完美数据,但FAST-LIO2的真实输入是有噪声的。如果你仿真里IMU数据太平滑,算法会进入一个“虚假自信”状态,噪声方差调得很小,一旦你后面换到真机上就各种发散。所以建议给IMU加上一定的高斯噪声,在插件里加<noise type="gaussian"><mean>0.0</mean><stddev>0.001</stddev></noise>,这样跑出来的轨迹才有参考价值。
3.5 把雷达和IMU组装进机器人模型
雷达和IMU通常不是单独悬挂在空间中的,它们需要装在一个机器人本体上。我在仿真里用一个简单的四轮小车模型作为载体,把Mid360放在车顶前方,IMU放在雷达下方,这样tf树就是odom --> base_link --> mid360_link。
给一个最简单的机器人底盘URDF片段,四轮差速模型:
<link name="base_link"> <visual> <geometry> <box size="0.5 0.4 0.15" /> </geometry> <origin xyz="0 0 0.1" rpy="0 0 0" /> </visual> <collision> <geometry> <box size="0.5 0.4 0.15" /> </geometry> </collision> <inertial> <mass value="5.0" /> <inertia ixx="0.1" ixy="0.0" ixz="0.0" iyy="0.1" iyz="0.0" izz="0.1" /> </inertial> </link> <joint name="base_to_mid360" type="fixed"> <parent link="base_link"/> <child link="mid360_link"/> <origin xyz="0.25 0 0.25" rpy="0 0 0" /> </joint>base_to_mid360这个fixed joint的xyz表示雷达装在底盘前方0.25米、高度0.25米处。这个安装位置对FAST-LIO2的影响很大:如果雷达装得太低、太靠内,车体自身会遮挡大量点云,前端特征减少,定位精度会明显下降;装得太高又影响车辆的稳定性。0.25米是我试过比较均衡的位置。
组装好URDF后,用robot_state_publisher来发布tf树。在launch文件里加上:
<node pkg="robot_state_publisher" exec="robot_state_publisher"> <param name="robot_description" value="$(command 'xacro $(find-pkg-share mid360_description)/urdf/robot.xacro')" /> </node>这样你的车载雷达模型才算完整接入ROS 2。
4. 搭建测试环境与启动FAST-LIO2仿真
有了雷达和车体模型,下面一步就是把它们一起丢进Gazebo世界,然后让FAST-LIO2跑起来。
4.1 选择适合SLAM测试的仿真世界
FAST-LIO2这类基于特征点的雷达惯性里程计,对环境特征的要求非常挑剔。你如果把它丢进一个纯白的空房间,它可能一开始就崩了,因为雷达扫到的全是平面,没有角点特征。
我目前在用的两个环境,效果都还可以:
- 官方示例环境:Gazebo自带的那几个室内世界场景,包含墙壁、障碍物、桌椅模型,特征足够丰富。但需要注意,这些世界文件里有些模型的面片法线反了,会导致射线穿透,点云出现黑洞。
- 自建简易仓库环境:用
building_editor工具画一个20m×30m的仓库,里面放一些货架、柱子和箱子。这种规整环境特别适合做FAST-LIO2的前端特征调试,因为地上的线、墙面的柱子能提供大量稳定的平面角点。
如果你需要更精细的场景,也可以用Blender建模后导出,再通过Gazebo的<include>标签加载。但我个人建议前期不要浪费时间在场景搭建上,用现成世界文件先跑通管线再说。
4.2 编写launch文件:启动世界、机器人、FAST-LIO2节点
这是整个仿真平台的核心,一步到位把Gazebo、机器人模型、FAST-LIO2全部拉起来。我直接贴我的launch文件,里面加了详细的注释,你按需修改物理路径。
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_gazebo_ros = get_package_share_directory('gazebo_ros') pkg_mid360 = get_package_share_directory('mid360_description') world_file = os.path.join(pkg_mid360, 'worlds', 'test_world.world') return LaunchDescription([ IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(pkg_gazebo_ros, 'launch', 'gazebo.launch.py') ), launch_arguments={'world': world_file}.items(), ), Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[{'robot_description': open( os.path.join(pkg_mid360, 'urdf', 'robot.urdf') ).read()}], output='screen', ), Node( package='gazebo_ros', executable='spawn_entity.py', arguments=['-topic', 'robot_description', '-entity', 'mid360_robot'], output='screen', ), Node( package='fast_lio2', executable='fastlio2_mid360', name='fastlio2_mid360', output='screen', parameters=[os.path.join(pkg_mid360, 'config', 'mid360.yaml')], ), ])这里面的fastlio2_mid360是FAST-LIO2编译后生成的可执行文件,名字取决于你拉取的仓库分支。有些仓库的可执行文件名是fastlio2,你launch文件里要做相应调整。
启动之后,等几秒钟,用ros2 topic hz /mid360/pointcloud检查点云频率。如果你的电脑GPU支持加速,频率应该稳定在10Hz左右。再检查/mid360/imu,频率应该在200Hz。这两个话题正常之后,FAST-LIO2才能往下走初始化流程。
4.3 FAST-LIO2核心参数配置:别用默认值
FAST-LIO2仓库自带的mid360.yaml配置文件,默认参数是针对真机调出来的。你可以直接用,但跑起来你会发现一些问题。我挑几个用得上的核心参数讲一下,这些都是我在仿真里来回调出来的经验值:
common: lid_topic: "/mid360/pointcloud" imu_topic: "/mid360/imu" time_sync_en: false time_offset: 0.0 scan_line: 64time_sync_en这个参数我建议设成false。在Gazebo仿真里,传感器时间戳都是由仿真时钟统一驱动的,硬件时间同步问题不存在,打开这个选项反而会因为时间戳差值阈限太严导致丢帧。scan_line这个值必须跟你的竖直采样线束一致,上面URDF里我设的是64,这里也要保持64。
接下来是激光雷达的外参配置,也就是IMU到雷达的坐标变换:
calib: extrinsic_T: [-0.011, 0.020, -0.072] extrinsic_R: [1, 0, 0, 0, 1, 0, 0, 0, 1]这个值表示在IMU坐标系下,雷达光心的位置。在仿真里,如果你把IMU和雷达放在同一个link里,位置应该是0,0,0,旋转矩阵是单位阵。但如果你的IMU是单独一个link,并且跟雷达之间有固定joint偏移,就必须把偏移量填进来。填错的话,点云和IMU数据融合时会明显出现拖影,跑起来非常明显。
滤波器的噪声参数,也是值得调的。仿真环境里没有真机的震动、电气干扰,但你的算法如果太信任IMU,在Gazebo模型稍微碰撞一下时就会剧烈发散。建议把过程噪声稍微调大一点:
filter: acc_cov: 0.1 gyr_cov: 0.1 b_gyr_cov: 0.0001 b_acc_cov: 0.0001注意,acc_cov=0.1和gyr_cov=0.1是我在仿真里调出来的相对保守值。你如果想模拟更差的IMU,把它加到0.5甚至1.0都行,只要别让算法完全发散就行。
4.4 用键盘控制小车运动开始测试
FAST-LIO2本身不做运动控制,你要让它在仿真环境里动起来,得手动发一个速度指令。我一般用一个teleop_twist_keyboard节点控制小车前后左右转:
ros2 run teleop_twist_keyboard teleop_twist_keyboard如果你没装这个包,用以下命令安装:
sudo apt install ros-humble-teleop-twist-keyboard启动之后,终端会显示按键说明。i键前进、k键后退、j和l左右转。控制小车在环境里转两圈,让FAST-LIO2完成初始化。初始化成功的标志是终端里出现类似“Initialization finished”的日志,然后用ros2 topic echo /Odometry就能看到实时输出的里程计位姿。
这里有个很重要的经验:初始化阶段不要猛打方向盘。FAST-LIO2的初始化需要足够的平移和旋转激励,但它对初值非常敏感,上来就急转弯很容易让优化掉到局部最优,初始化出来的外参直接偏掉。我建议先匀速直线走几秒,再缓慢转弯,给它足够的时间把状态估计拉回来。
5. 数据分析:怎么判断定位效果到底行不行
仿真跑通只是第一步,你后面要调整参数、对比不同配置,就得学会看定位结果的好坏。每次改完参数后,光用眼睛在Rviz里看轨迹,容易陷入“看起来还行”的错觉。
5.1 Rviz显示点云和轨迹:必要的可视化配置
在Rviz里,你至少需要添加这几个显示项:
- PointCloud2(话题名
/mid360/pointcloud),用于看实时点云; - Odometry(话题名
/Odometry),用于显示FAST-LIO2输出的中心位置; - Path(话题名
/path),用于显示累积轨迹; - TF,用于观察各个坐标系之间的变换关系。
对于FAST-LIO2的Rviz配置,它的path话题是/path,这是系统内部发布的一个nav_msgs/Path,直接订阅即可。在仿真里,如果轨迹明显偏离地面,或者路径出现“撞墙穿模”,那就是定位崩了。
5.2 轨迹精度比较:仿真里怎么量化误差
这是很关键的一点。在真机上做精度评估非常麻烦,你要用动捕系统或者高精度地图做ground truth,而在Gazebo里,模型真正的位姿是已知的——模型在Gazebo世界中的坐标和朝向,可以从Gazebo的/gazebo/model_states话题读取。这就相当于天然给你一个高精度真值。
我通常的做法是录一段包,一方面保存FAST-LIO2输出的位姿,另一方面保存/gazebo/model_states里的真值位姿,然后用EVO这个工具做误差评估。EVO可以自动对齐时间戳,计算ATE和RPE,两条指令就能出结果:
evo_ape bag output.bag /Odometry /gazebo/model_states -a evo_rpe bag output.bag /Odometry /gazebo/model_states -a注意,/gazebo/model_states不是ROS 2标准的Odometry消息,不能直接丢给EVO。你需要写一个十几行的节点把它转成nav_msgs/Odometry,然后再评估。这个转换节点不难,核心就是读出model_states里你机器人模型的名字对应的pose,填到Odometry消息里。
这样跑出来的ATE(绝对轨迹误差)如果小于0.1米,说明你的参数基本合格;如果在0.5米以上,那就得回头检查外参或者点云配置了。
5.3 不同参数下的对比实验怎么做
在仿真里最容易做的实验,就是雷达安装高度对比、噪声强度对比、扫描频率对比。我做过一组安装高度实验:把雷达离地高度从0.15米加到0.4米,同一段轨迹,ATE从0.08米降到0.04米。原因很简单,雷达装高之后,近处的平面特征减少,远处的角点特征更多、更稳定,FAST-LIO2的迭代更新不容易被异常值带偏。
这类实验在真机上做至少得拆装几小时雷达,在仿真里改个URDF里的xyz参数,重新spawn一下模型,一分钟就能跑一组。这就是仿真的最大价值:你可以把时间花在分析结果上,而不是花在实验准备上。
6. 常见问题与排查技巧实录
这部分是我最想写的一节,因为那些报错信息你自己搜半天搜不到答案,我这里直接给你一个速查表。这些都是我在这个平台上踩过的坑,都给你列出来。
6.1 Gazebo启动就黑屏或崩溃
最常见的问题。分两种情况:
- 启动时黑屏无反应:基本是OpenGL渲染问题。Gazebo 11在虚拟机或远程桌面里特别容易出现。解决方法是设置环境变量
export LIBGL_ALWAYS_SOFTWARE=1,强制软件渲染。但这个方案对性能影响很大,点云频率会掉一半。更好的方案是用支持GPU透传的宿主机。 - 启动后窗口闪退:检查
.gazebo目录下是否有损坏的缓存文件。直接删掉~/.gazebo/cache再重启。
6.2 点云话题有数据,但Rviz里看不见点云
这个问题通常不是雷达插件的问题,而是坐标Frame ID没对上。FAST-LIO2发布的点云topic的frame_id是livox_frame,而gpu_ray插件默认frame_id是sensor_frame。解决方案是把URDF里的sensor的<frame_name>标签改成livox_frame:
<sensor type="gpu_ray" name="mid360_sensor"> <pose>0 0 0 0 0 0</pose> <frame_name>livox_frame</frame_name> ... </sensor>Rviz里如果还是看不到,把Global Options里的Fixed Frame改成livox_frame,看一秒钟有没有点云。如果还是没有,再检查topic的qos设置,FAST-LIO2内部可能是用BestEffortQoS,某些版本需要你在Rviz里把Topic的Reliability也改成BestEffort。
6.3 点云出现穿透,能看见模型后面的物体
在Gazebo仿真里,射线传感器是对场景里所有碰撞几何体做检测的。如果点云能穿透墙壁,说明那个模型只画了视觉Mesh,没写Collision属性。Gazebo的射线传感器不会跟visual几何体交互,只跟collision几何体交互。解决办法是在那些模型文件的URDF/SDF里补充<collision>块,或者干脆替换成Gazebo自带的带有碰撞属性的简单模型。
我之前用了一个别人做的仓库模型,结果雷达直接把货架后面的墙也扫出来了,路径扭曲得一塌糊涂。最后换成自己画的几个箱子,问题才解决。
6.4 FAST-LIO2初始化失败或运行中发散
初始化失败的常见原因有三个:
- IMU频率对不上:检查
/mid360/imu的实际频率,如果不是200Hz,算法内部的时间累积误差会迅速放大。 - 点云频率太低:如果你用CPU版ray插件,点云可能只有2~3Hz,IMU在两次点云之间已经积分出一大段误差,初始化自然失败。改用
gpu_ray能解决大半性能问题。 - 运动激励不足:小车没有动起来,或者只做了纯平移没有旋转,导致优化问题退化。解决方法是手动控制小车走一个“Z”字形,给它足够的激励。
运行中发散的话,先看Rviz里IMU的加速度和角速度曲线有没有异常跳变。在Gazebo里,如果你的机器人撞到了障碍物,物理引擎会瞬间产生很大的加速度反馈,FAST-LIO2看到这个异常值,如果滤波器增益不够高,很容易直接把状态估计撞飞。这种情况就正常Reset,然后控制小车避障就行。
6.5 常见问题速查表
| 现象 | 原因 | 解决方案 |
|---|---|---|
| Gazebo黑屏 | OpenGL渲染问题 | 设LIBGL_ALWAYS_SOFTWARE=1或用物理GPU |
| 点云topic无输出 | 传感器插件没有正确加载 | 检查URDF的<plugin>标签和libgazebo_ros_ray_sensor.so是否存在 |
| 点云有数据但Rviz不显示 | Frame ID不一致或QoS不匹配 | 设置frame_name=livox_frame,Rviz里改BestEffort |
| 点云穿透墙壁 | 模型只有visual没有collision | 给模型添加<collision>块 |
| IMU数据频率不对 | update_rate设置错误 | 确认URDF中update_rate=200 |
| FAST-LIO2初始化失败 | 运动激励不足 | 手动控制小车走“Z”字形 |
| 轨迹明显漂移 | 外参标定错误 | 检查extrinsic_T是否与URDF中的joint位置一致 |
6.6 性能优化:怎么让仿真跑得更丝滑
Gazebo仿真跑FAST-LIO2,吃的是CPU多核能力和GPU渲染能力。我实测用i7-12700H + RTX 3060 Laptop这个配置,跑10Hz点云 + 200Hz IMU + FAST-LIO2全流程,CPU占用大概70%,能稳定跑。如果你的机器配置一般,可以试试这几个优化方法:
- 降低竖直方向
samples,从64降到32,点云量减半,FAST-LIO2照跑,精度损失不大。 - 把Gazebo的
<real_time_update_rate>从默认的1000调到500,减少物理引擎的计算压力。 - 关掉Rviz里不太必要的显示项,尤其是TF和模型Mesh,这些渲染开销很大。
最后再分享一个小技巧
仿真平台搭好之后,你完全可以给Gazebo世界文件里添加一批带有二维码图案的模型,或者不规则形状的障碍物,模拟真实仓库场景。对FAST-LIO2这种纯几何特征算法来说,这些图案不影响点云,但对后面想叠加视觉算法或者做多传感器融合的人,这些视觉特征就是基础。我当时把平台扩展成了支持相机、IMU、雷达三模态同步采集,后期加视觉导航算法就直接在仿真里先验证,省了特别多事。
折腾这个平台前前后后花了我大概一个多星期,其中一半时间浪费在查那些报错信息上。现在想想,如果一开始就按这套流程来,第一天就能跑通。希望这篇东西能帮你少走几段弯路,有问题也欢迎在评论区交流,你跑的版本、用的设备不一样,遇到的问题大概率也是千奇百怪,但仿真这东西,只要你耐着性子一个个拆解,总能跑起来。