ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

从walking_dataset到MID360:ROS2下LIO-SAM建图全流程解析

从walking_dataset到MID360:ROS2下LIO-SAM建图全流程解析 手里这份walking_dataset我翻来覆去跑过好几遍每次换SLAM框架都要把它拿出来遛一遛。它是典型的手持低速场景人拎着设备在室内走廊里走点云稀疏、运动平缓、回环极少看起来简单实际特别考验激光惯性里程计的初始化稳定性和参数耐性。这次我从ROS2 humble把LIO-SAM完整跑通从walking_dataset的数据集回放一路推到Livox MID360真机建图顺手把仿真环境里的坑也记录了一遍。这个组合是目前入门激光SLAM最值得复现的一条路线因为LIO-SAM的代码结构干净MID360又是现在最容易买到、资料最多的混合固态雷达ROS2版驱动和依赖也足够成熟。如果你刚装好ROS2、准备搞LIO-SAM但不知道从哪下手或者是装完驱动后建图总飘、地图拉花这篇内容应该能帮你省掉几周的排查时间。1. 项目盘点walking_dataset、MID360和LIO-SAM ROS2为什么能凑到一起1.1 walking_dataset到底在考什么很多人第一次听到walking_dataset会以为它是某个官方标准数据集其实它就是一类“手持设备边走路边采集”的室内场景数据的统称最常见的形式是包含一个激光雷达点云topic和一个IMU数据topic的rosbag包。这类数据的难点很有意思人走路的速度很慢平均不到1m/s但会产生持续的、无规律的抖动和转向这对纯激光里程计来说并不友好。因为激光帧之间的位移变化小特征匹配的约束会比较弱一旦IMU的bias估计不准或者点云去畸变做得不好轨迹就会慢慢“飘”起来。更麻烦的是室内走廊这种环境两侧墙面高度相似长直走廊几乎没有回环一旦累积漂移后面再想靠闭环拉回来都不可能。所以在跑LIO-SAM之前拿一份walking_dataset先去“验货”是正确的思路。它的数据量不大bag播放一遍也就几分钟参数调错了重新来成本也低。等这套数据能稳定出图、轨迹不飞再上MID360真机心态会稳很多。很多新手一上来就直接拿真机测结果地图飘了都不知道是驱动问题、外参问题还是算法问题。1.2 MID360在LIO-SAM里的定位MID360是Livox的一款360度混合固态雷达最核心的几个参数是视场角360度乘59度测量距离40米精度大概2厘米内置一个200Hz的IMU。它和传统机械雷达最本质的区别是采用非重复扫描方式也就是说每一帧点云在空间里的分布是动态变化的不会像机械雷达那样固定扫描线。这个特性对LIO-SAM这类基于特征优化的算法其实很友好。因为LIO-SAM在提取角点和平面点时用的是体素下采样后计算曲率的方式非重复扫描让点云在局部区域内分布更均匀平面点拟合出来的法向量也就更稳。但同时它也带来一个麻烦不同帧之间看到的点几乎不会重叠所以传统的“帧到帧配准”思路在MID360上并不好用LIO-SAM的速度框架需要完全依赖IMU预积分来提供初值。这就解释了为什么外参不准、IMU噪声参数设置不对时MID360上跑LIO-SAM会格外容易飘。另外一个需要注意的是MID360的量程虽然标称40米但在室内环境下实际有效距离会受墙体材质、入射角影响往往只有十几米到二十几米而且近处点云密度非常高。如果参数文件里把最小距离(lidarMinRange)设置得太大会丢掉很多近处的有效特征走廊环境下很容易出现“特征不足”导致定位发散的情况。1.3 LIO-SAM的ROS2移植版选型说明原版LIO-SAM是基于ROS1开发的Tixiao Shan的代码仓库在很长一段时间内只维护ROS1版本。但现在ROS1已经逐渐退出主流Ubuntu 22.04上基本都转向ROS2 humble所以社区里催生了不少ROS2移植版。我这次用的是社区维护的ROS2版本它在源码结构上尽量保持了原版模块划分同时把topic通信、参数读取、launch文件全部改成了ROS2风格。选它的原因主要有三点一是长时间维护humble下的编译问题基本都处理过二是它把MID360的内置IMU参数做了适配不用自己再去瞎调三是它的launch文件写得很清晰方便新手通过读launch来理解整个系统怎么串起来的。如果实在不想用社区版本也可以自己把ROS1版手动移植过来但那就意味着要处理rospy/roscpp的API替换、tf2_ros的写法差异、以及launch文件的完整重写工作量相当大。对绝大多数人来说选一个成熟的移植版把精力放在参数理解和算法原理上性价比高得多。2. 环境搭建与驱动编译这一步踩的坑最多2.1 ROS2 humble环境准备LIO-SAM ROS2版对ROS2版本没有特别苛刻的要求但有长期维护、资料最多的还是humble。如果你是Ubuntu 22.04直接装humble就对了。同一套流程在foxy上也能跑但中间遇到依赖报错时能搜到的解决方案数量会差一个量级。安装ROS2 humble本身不难难的是把源配好、避免网络问题。我个人建议先配好国内镜像然后安装桌面版。装好之后必须确认环境变量已经写入bashrc很多新手在编译时报“command not found: ros2”八成就是忘了source。编译整个LIO-SAM工作空间之前最好先跑一下ros2 run turtlesim或小乌龟示例确认系统本身没问题否则后面出了问题很难分清是环境问题还是代码问题。2.2 编译livox_ros_driver2驱动MID360在ROS2下用的是Livox官方驱动livox_ros_driver2这个驱动和老的livox_ros_driver不是同一个包下载和launch方式都不一样不要搞混。cd ~/ros2_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd ~/ros2_ws colcon build --symlink-install --packages-select livox_ros_driver2 source install/setup.bash编译完成后先用MID360自带的launch验证雷达能否正常工作ros2 launch livox_ros_driver2 rviz_MID360.launch.py如果能正常看到点云说明驱动OK。这个launch默认发布的点云topic是/livox/lidarIMU topic是/livox/imuframe_id默认是livox_frame。这几个信息后面配置LIO-SAM时全都要用到最好先用ros2 topic echo确认一遍。有个很实际的问题是livox_ros_driver2编译时默认需要C17如果你的环境里还有其他老代码依赖C14整个工作空间一起编译可能会报一堆莫名其妙的错误。建议把livox_ros_driver2和LIO-SAM放同一个工作空间单独分区或者用--packages-select指定编译尽量不要和一堆旧包混在一起。2.3 LIO-SAM ROS2移植版的编译编译LIO-SAM ROS2版需要三个关键依赖PCL、GTSAM、OpenCV。PCL用来做点云处理和特征提取GTSAM用来做因子图优化OpenCV则是在图像投影环节用到的。sudo apt install ros-humble-pcl-ros ros-humble-cv-bridge ros-humble-image-transport sudo apt install libgtsam-dev libopencv-dev依赖装好后把LIO-SAM源码放进工作空间cd ~/ros2_ws/src git clone https://github.com/srvanderplas/LIO-SAM-ROS2.git cd ~/ros2_ws colcon build --symlink-install source install/setup.bash这里特别提醒一个坑GTSAM的版本会影响建图结果。用系统自带的libgtsam-dev通常问题不大但如果你之前为了跑其他SLAM项目手动编译过GTSAM版本不一致会导致链接到错误库建图时会出现莫名的优化失败。遇到这种情况直接卸载手动编译的版本重新装系统库最省事。OpenCV版本方面humble自带的是OpenCV 4.xLIO-SAM只用到了基础的数据结构不会有太大问题。如果编译时报找不到opencv2的头文件多半是没有安装libopencv-dev而不是代码问题。2.4 从rosbag到话题映射第一步最容易搞错拿到walking_dataset之后第一步不是急着播放而是先看清bag里有什么ros2 bag info walking_dataset.bag正常情况下会看到类似下面的信息Topics: /points_raw sensor_msgs/PointCloud2 /imu/data sensor_msgs/Imu但很多数据集里的topic名并不统一有的叫/livox/lidar有的叫/velodyne_points也有的叫/cloud_registered。LIO-SAM ROS2版默认订阅的是/points_raw和/imu/data如果和bag里的名字对不上页面上的点云就是空的。解决方式有两种一种是在launch文件里用ROS2的remap参数另一种是改params.yaml里的topic名字。我建议优先用remap因为这样不用改源码后续切MID360时只需要改launch里的映射关系就行。Node( packagelio_sam, executablelio_sam_imuPreintegration, parameters[params_file], remappings{ imu/data: /imu/data, imu/data_pose: /imu/data_pose } )先用ros2 run打开一个节点再用ros2 node list、ros2 topic list对比基本就能定位问题出在哪个环节。3. walking_dataset跑通全流程参数调对才能真正“跑通”3.1 启动顺序与Launch拆解LIO-SAM ROS2版的launch文件把所有节点串在了一起整个系统主要由五个节点组成pointcloud_preprocess点云预处理负责体素下采样、计算角点和平面点image_projection点云投影成深度图配合IMU做运动补偿feature_extraction从投影后的点云里提取边缘特征和平面特征imu_preintegrationIMU预积分为优化提供运动初值map_optimization因子图优化、回环检测、发布最终轨迹和地图启动方式很简单ros2 launch lio_sam lio_sam.launch.py然后在另一个终端播放bagros2 bag play walking_dataset.bag第一次跑建议加个慢放参数ros2 bag play walking_dataset.bag --rate 0.5这样在rviz2里可以看清楚每一帧点云和轨迹的变化不至于一眨眼就飞出去了。有个经验启动launch后不要急着play先等几秒钟让IMU预积分节点积累几帧数据再去播放bag。否则系统刚开始还没有IMU初值点云一进来容易出现短暂的位姿跳变看起来就像初始化失败实际上只是时序问题。3.2 参数文件里决定成败的几行打开params.yaml你第一眼会看到一大堆参数眼花缭乱。但真正决定生死的是这么几行lio_sam: useImu: true useOdom: false useGPS: false imuGravity: 9.80511 lidarMinRange: 1.0 lidarMaxRange: 100.0 edgeThreshold: 1.0 surfThreshold: 0.1 loopClosureEnableFlag: false imuAccNoise: 3.9939570888238808e-03 imuGyrNoise: 1.5636343949698187e-03 imuAccBiasN: 6.4356659353532566e-05 imuGyrBiasN: 3.5640318696367613e-05先看imuGravity。这个值在不同城市是有细微差别的但绝大多数情况下用9.80511不会有问题如果建出来的地图整体朝一个方向倾斜优先检查是不是重力加速度设错了。再看lidarMinRangeMID360的近处点云非常密集如果设置成1.0意味着雷达1米范围内所有的点全被丢掉在室内狭窄走廊里很容易造成特征不足。loopClosureEnableFlag这个参数我建议在跑walking_dataset时先关掉也就是设置成false。为什么因为手持数据集本身回环极少而且你第一次跑的目标是先把里程计调稳如果开着回环检测一旦在走廊尽头错误检测到一个“回环”反而会把原本还不错的轨迹硬拉歪。等里程计稳定了再把回环打开去看看效果。edgeThreshold和surfThreshold分别控制角点和平面点的提取阈值。阈值越小提取的特征越多但噪声也越多阈值越大特征越少但越稳定。在walking_dataset这种室内场景下surfThreshold可以稍微调小一点因为墙面和地面提供了丰富的平面特征多提取一些平面点对定位稳定性很有帮助。3.3 第一次跑通后怎么判断结果好坏点云能出来不代表真的“跑通了”得看几个关键指标。最直观的是在rviz2里看odometry轨迹好的轨迹应该贴地、平滑和人的行走路径一致不会出现上下跳动或者突然的直角转弯。其次看全局地图的清晰度墙面的重影越少越好如果墙面出现明显的“双层墙”效果说明角点配准有问题或者外参不对。还有一个经常被忽视的点看IMU预积分后的速度反馈。在rviz2里把/lio_sam/mapping/odometry和/lio_sam/imu/odometry两个topic同时显示出来如果两条轨迹的偏差随时间越来越大说明IMU和点云之间的外参或者时间同步存在隐性错误这种误差在短时间看不出来跑个几分钟就会暴露。walking_dataset这种数据跑完后生成的轨迹应该是闭合度很高的。如果走了半天轨迹长度和别人参考的路径差很多大概率是IMU的scale没校准好需要回过去检查IMU的加速度计噪声参数。4. 迁移到MID360真机建图从数据集到实战的跳跃4.1 从话题到坐标系的第一次对齐walking_dataset跑通后把LIO-SAM切到MID360真机最核心的变化是话题来源从rosbag变成了驱动。理论上只需要把launch里的topic映射改掉就行但实际操作中坐标系的问题才是大头。先启动MID360驱动ros2 launch livox_ros_driver2 rviz_MID360.launch.py然后用ros2 topic echo /livox/lidar --once确认frame_id。有的版本里frame_id是livox_frame有的版本里可能是body或者laser这个值必须和LIO-SAM参数文件里设置的lidar frame一致。如果对不上即使点云数据进来了tf树也连不上rviz里直接看不到任何东西。MID360的坐标系定义是x轴向前、y轴向左、z轴向上IMU内置在雷达内部坐标系和雷达坐标系基本对齐。LIO-SAM里默认的外参是单位矩阵加小偏移在MID360上可以直接用但这一步千万不要想当然。最好在装雷达之前先用手晃一晃设备看rviz里IMU的加速度计和角速度计是否和实际运动方向一致。方向反了的话LIO-SAM会在几秒内直接发散而且不会给你任何报错提示。4.2 迁移MID360时的参数调整表把walking_dataset的参数平移过来后至少要改动下面这些地方参数walking_dataset常用值MID360建议值调整原因lidarMinRange1.00.5MID360近处点云密度高保留近处特征防止狭窄环境特征缺失lidarMaxRange100.040.0MID360量程40米更远的点基本是噪声downsampleResolution0.10.1-0.2保持0.1精度高但计算压力大0.2更流畅imuAccNoise3.99e-035.0e-03MID360的IMU噪声略大需要放宽imuGyrNoise1.56e-032.5e-03陀螺仪噪声同样需要适应imuRPYWeight0.010.01-0.05这个值影响IMU和点云的置信度权重edgeThreshold1.01.0-2.0非重复扫描下角点噪声多适当调高减少误匹配这里最值得说的是imuRPYWeight。它决定了优化时IMU的姿态观测起多大作用。在MID360上如果这个值设置得太小系统过于信任点云配准在快速旋转时容易出现掉姿态如果设置得太大系统又会被IMU的漂移带着走长走廊场景下地图会慢慢弯曲。我实测下来放到0.03左右是个比较舒服的折中但不同环境的差异很大需要现场试。另外MID360的点云频率默认是10HzIMU频率是200Hz这个频率比很多机械雷达低。LIO-SAM的image_projection节点会按频率去处理点云帧如果你的机器性能不足处理器跟不上10Hz的点云处理频率会出现丢帧现象表现为地图上有明显的“断层”。这种情况下可以牺牲一点精度把downsampleResolution从0.1升到0.15或者关闭回环检测降低计算量。4.3 真机建图流程和地图保存真机操作和数据集回放最大的区别是你要同时管住设备和系统。手持MID360建图时走姿要尽量平稳转弯要慢不要做原地快速旋转。快速旋转时点云畸变很严重即使有IMU补偿也容易造成特征匹配错误。保存地图是整个流程里最容易让新手懵的一步。LIO-SAM本身并不会主动输出一份完整的pcd文件原始代码里只有全局地图的topic发布。我常用的办法是在map_optimization节点的源码里找到保存地图的函数加上PCL的保存接口让它每隔一段时间或者按键盘触发保存。简单来说就是在run()函数里监听一个键盘事件触发后把globalMap点云用pcl::io::savePCDFileBinary保存下来再手动把pcd转成las或者直接用CloudCompare看。如果你不想改源码也可以在rviz2里订阅/lio_sam/mapping/global_map这个topic然后用RViz的截图功能记录当前视图但这样保存的不是可用的点云数据只能当轨迹检查用没法做后处理。5. 仿真扩展把LIO-SAM塞进Gazebo来一场“假建图”5.1 仿真需要什么传感器模型标题里提到仿真我认为最实用的含义是在Gazebo里搭一个仿真环境让LIO-SAM先跑一遍验证算法在虚拟环境下的表现再决定是否上真机。这样可以避开真机调试的高成本和风险。要在Gazebo里驱动LIO-SAM关键的传感器模型有两个一个是激光雷达模型一个是IMU模型。Gazebo自带的gazebo_ros_ray_sensor插件可以发布sensor_msgs/PointCloud2格式的点云gazebo_ros_imu插件可以发布sensor_msgs/Imu格式的数据。URDF里加入激光雷达和IMU插件的写法大致如下gazebo referencelaser_link sensor typegpu_ray namelidar_sensor pose0 0 0 0 0 0/pose update_rate10/update_rate ray scan horizontal samples360/samples resolution1/resolution min_angle-3.14159/min_angle max_angle3.14159/max_angle /horizontal /scan range min0.5/min max40.0/max resolution0.01/resolution /range /ray plugin namelaser_controller filenamelibgazebo_ros_ray_sensor.so ros remapping~/out:/points_raw/remapping /ros /plugin /sensor /gazebo5.2 把Gazebo话题接到LIO-SAMGazebo仿真最麻烦的地方在于话题名的对应关系。不同插件发布出来的topic名千奇百怪而LIO-SAM只认/points_raw和/imu/data。老老实实用remap是最稳妥的。在launch文件里把LIO-SAM的topic remap到Gazebo实际发布的话题上。如果Gazebo里雷达发布的固定频率是10HzIMU是200HzLIO-SAM的IMU预积分节点会正常工作但如果Gazebo的IMU只有50Hz预积分效果会变差地图精度也会明显下降。所以在仿真里IMU频率一定要设置到100Hz以上这一点和真机是一致的。还有一个差别是Gazebo里的激光雷达模型比较理想化点云没有真实雷达的噪声和混合固态扫描特性。LIO-SAM在仿真里跑得很漂亮不代表在真机上也能照样跑好仿真的价值主要是验证系统集成和数据流打通而不是验证算法鲁棒性。5.3 仿真中容易忽略的时间戳坑仿真中一个很隐蔽的坑是时间戳不一致。Gazebo的传感器插件默认使用的是仿真时间但LIO-SAM节点默认使用它们各自收到的消息时间戳。如果同一帧点云和IMU消息之间的时间戳跨度过大IMU预积分的时间对不上系统就会出现“里程计突然跳变”的怪问题。解决办法是保证仿真启动时同步使用仿真时钟让所有节点都基于同一个时钟源。在launch里给每个节点设置use_sim_time参数为True这是Gazebo下唯一能让LIO-SAM稳定跑起来的办法。很多人在仿真里跑了半天地图乱飞查来查去最后发现就是没有开启sim time。6. 实测中最容易翻车的问题与排查方法6.1 问题速查表我在整个过程中遇到的问题不少整理成一张速查表方便你按图索骥现象可能原因处理方法rviz2里看不到点云frame_id不匹配或topic没映射用ros2 topic echo确认实际topic和frame_id修launch里的remap点云出来但轨迹原地不动IMU数据没进入预积分节点检查/imu/data话题是否有数据用ros2 topic hz确认频率地图出现重影/双层墙点云外参或IMU外参不准重新标定雷达与IMU之间的外参重点检查旋转矩阵跑着跑着轨迹突然飞走时间戳不同步或处理器掉帧打开use_sim_time(仿真)降低downsampleResolution长时间静止但地图还在漂IMU bias没收敛或参数太紧等待初始化完成后再移动适当放宽imuAccBiasN长走廊地图逐渐弯曲回环太少、IMU置信度过高调低imuRPYWeight或开启回环检测地图保存不下来源码里没实现保存功能在map_optimization里加PCL保存接口6.2 时间戳问题看起来像算法问题实际是数据问题好几个朋友在群里问我LIO-SAM的轨迹为什么会突然跳一下然后继续跑。这种问题99%是时间戳不同步。在数据集回放场景下bag里的每条消息都有自己的时间戳播放时如果你用--rate加速ROS2会有一定的时延补偿但如果机器性能不够处理不过来就会出现点云和IMU消息之间的时间差被拉大的情况。一个非常有效的排查方法是先让LIO-SAM停下来用ros2 topic hz分别确认/points_raw和/imu/data的频率是否稳定。如果点云频率忽高忽低或者IMU频率经常出现大于10ms的跳变系统输出的轨迹基本无法保证质量。这种时候最简单的做法就是把bag的播放速率降到0.5让系统有足够时间去处理每一帧。真机场景更要注意MID360驱动默认点云频率是10Hz但如果你电脑后台开着太多可视化窗口CPU占用过高导致节点处理不过来最容易表现出的症状就是“地图像被切了一刀”这其实不是算法崩了而是处理速度跟不上。6.3 外参误差漂移的隐形杀手LIO-SAM对雷达和IMU外参的依赖程度比你想象的要高。MID360虽然IMU内置在雷达内部官方给了标称外参但每一台设备的安装都可能有微小的角度偏差尤其是绕重力方向的旋转对建图影响最大。怎么判断外参有没有误差做一个简单的实验把设备放在桌面上静置30秒看LIO-SAM输出的轨迹。如果轨迹在静止状态下画出一个小圆弧或者不断朝一个方向缓慢移动说明外参的旋转部分有偏差。偏差越大这个轨迹的半径越小也越容易在后续运动中放大成大幅度的漂移。如果外参标定比较复杂临时可以调整参数文件里的extrinsicRot矩阵。但我的建议是如果你只是做建图不是做高精度定位微小的外参误差可以通过IMU预积分和配准过程中的联合优化在一定程度上补偿掉只有在快速运动或者长时间运行后误差才会变得明显。所以先别急着标定把基础的噪声参数调好再说。6.4 一个容易被忽视的“坑”特征提取门槛最后分享一个我自己的实操心得walking_dataset这类室内数据和MID360真机数据在特征分布上的差异非常大。室内走廊里平面点占绝对主导角点很少而MID360在室外场景下树枝、车辆边缘会给出大量角点。如果在室内跑得好好的参数拿到室外直接变得不稳定先别怀疑算法检查一下feature_extraction输出的特征点数量。在rviz2里把/lio_sam/feature/cloud_corner和/lio_sam/feature/cloud_surface两个topic显示出来正常情况下应该看到均匀分布的两种特征点。如果发现某一类特征点明显过多或过少回到params.yaml去调整edgeThreshold和surfThreshold直到两类特征的比例大致平衡。这个方法在数据集和真机之间切换的时候特别好用因为我自己的经验是每次换了雷达或者换了场景最先漂移的原因都不是参数文件里那些看似高深的噪声系数而是特征提取的门槛没跟上新场景的数据分布。先把特征点调“好看”了后面所有问题都会简单一半。说实话LIO-SAM这套代码本身不复杂真正让人头疼的都藏在数据流和参数细节里。如果你能把walking_dataset跑通、再顺利切到MID360真机上建出一张稳定的地图你对ROS2的话题通信、坐标系关系、IMU预积分原理的理解会比看十几遍教程都要深刻。至少我现在每次遇到新的雷达或者新的场景都会先把这套流程完整走一遍再说它能帮你快速判断问题到底出在传感器、驱动还是算法本身。
返回列表