
简介LIO-SAM与KITTI数据集的实践资源面向自动驾驶、机器人导航领域的SLAM研究者和工程师旨在解决激光雷达与惯性导航融合定位中的复现与调试需求。资源共42个文件压缩包约64.12MB包含C核心源码、ROS启动与配置、可视化演示图、说明文档等多种类型文件涵盖从源码构建到KITTI序列运行的关键环节并附示例说明。根目录采用liosamkitti_ws/src/LIO-SAM-master结构提供可直接编译的catkin工作空间便于对照launch文件、yaml参数和rviz配置快速启动实验。已有4255人学习下载适合希望快速上手LIO-SAM的初学者以及需要对比验证实车数据效果的中高级开发者。借助源码注释、GIF录屏和PDF解析读者可直观理解滑窗因子图优化、特征匹配、IMU预积分等模块的实现细节并据此快速定位需要修改的代码降低环境搭建与调参门槛。 做三维激光SLAM的人应该对LIO-SAM这个名字不陌生。它把IMU预积分、激光里程计、GPS因子和回环检测全部塞进一个因子图框架里做紧耦合优化在开源社区里几乎是“入门必跑”的项目之一。而KITTI作为自动驾驶领域最常用的公开数据集正好同时提供了64线点云、IMU和GPS数据把LIO-SAM需要的输入全部覆盖。这篇博客记录的是我从零开始把LIO-SAM跑在KITTI数据上的全过程包括环境配置、数据转换、参数调整、实测效果以及最后用evo做精度评估的完整链路。如果你正准备复现这个项目这篇文章应该能帮你省掉不少弯路。1. 为什么把LIO-SAM和KITTI放在一起跑1.1 LIO-SAM的系统设计它到底在优化什么LIO-SAM全称是Lidar-Inertial Odometry and Mapping出自Tixiao Shan等人发表在IROS 2020。它和更早期的LOAM系列相比核心变化是把IMU预积分结果作为因子加入因子图同时把GPS因子和回环因子也塞进同一个优化框架。激光里程计只负责帧间配准和局部特征关联而全局轨迹由因子图统一维护。这样设计最大的好处是回环检测一旦触发历史轨迹和地图都会被修正而不是像纯里程计那样一路飘下去。同样跑KITTI如果拿A-LOAM或者LEGO-LOAM来对比你能明显感觉到LIO-SAM在长距离场景下的优势。A-LOAM没有IMU融合也没有回环纯靠ICP帧间匹配遇到隧道、长直墙或者稀疏场景漂移会逐渐累积。LEGO-LOAM加了回环但IMU的融合深度不如LIO-SAM。LIO-SAM相当于把IMU、激光、GPS、回环四类信息统一在一个后端里面做全局优化鲁棒性和精度都更均衡。1.2 KITTI数据集的适配点与难点KITTI数据对做SLAM的人来说是绕不开的评测基准。它提供了64线Velodyne雷达点云、OXTS惯性导航系统的IMU数据、GPS/RTK定位数据以及相机图像。对LIO-SAM来说最理想的情况是有高频IMU比如100Hz甚至200Hz但KITTI的IMU是统一同步在10Hz左右发布的这个频率对预积分来说偏低不过实测下来依然能跑只是里程计消息更新会相对稀疏。真正麻烦的地方其实是数据格式转换。KITTI原始数据是一堆txt、png、bin文件要先转换成ROS bag再把bag里的话题名、坐标系、时间戳都对齐到LIO-SAM能接受的样子。很多人卡在这一步并不是算法跑不起来而是数据没喂对。这篇文章的重心也会放在这里。2. 环境搭建与编译部署2.1 依赖选型和编译顺序我用的环境是Ubuntu 18.04 ROS Melodic这套组合在LIO-SAM社区里最成熟遇到问题网上基本都有记录。Ubuntu 20.04 Noetic也可以但个别依赖包名不同编译报错时排查起来会多花点时间。如果你不是对ROS版本有硬性要求建议先按Melodic来。LIO-SAM的依赖主要有GTSAM、PCL、Eigen3。PCL和Eigen一般随着ROS桌面版装好了唯一容易出问题的是GTSAM。LIO-SAM官方要求GTSAM 4.0.2如果你用sudo apt install ros-melodic-gtsam大概率装到的不是这个版本会在编译阶段报一些莫名其妙的找不到符号错误。我推荐直接源码编译指定4.0.2分支git clone https://github.com/borglab/gtsam.git -b 4.0.2 cd gtsam mkdir build cd build cmake -DGTSAM_BUILD_TESTSOFF -DGTSAM_BUILD_UNSTABLEON .. make -j8 sudo make install编译GTSAM时注意如果CPU核心数不够多-j8可能会把机器拖垮建议先看下nproc再决定并发数。装完GTSAM后再编译LIO-SAMmkdir -p ~/lio_sam_ws/src cd ~/lio_sam_ws/src git clone https://github.com/TixiaoShan/LIO-SAM.git cd ~/lio_sam_ws catkin_make如果你用catkin tools也可以catkin build lio_sam。编译完成后先跑一下自带的demo bag验证安装是否成功再上KITTI数据这样排查问题会更简单。2.2 配置文件认知launch和param的对应关系LIO-SAM的launch文件是整个系统的总入口它负责加载两个关键配置文件config/params.yaml和config/config.yaml。前者是算法参数比如雷达线数、水平分辨率、外参、降采样率后者存的是话题名称。实际操作中很多人只改params.yaml里的imuTopic和lidarTopic却忽略了launch文件里已经写好的topic remap结果订阅不到数据终端报No messages on topic。建议你把roslaunch lio_sam run.launch启动后先用rostopic list确认一下LIO-SAM内部节点实际订阅的话题名再和bag里的话题名对照这一步能省下很多排查时间。3. KITTI数据预处理从原始数据到rosbag3.1 数据下载与kitti2bag转换KITTI的数据格式是典型的自动驾驶数据集格式一个序列包含同步后的点云、图像、IMU和GPS信息。要转成bag最常用的工具是kitti2bag这是一个Python包安装很简单pip install kitti2bag下载KITTI原始数据时一定要选raw_synced版本这个版本里所有传感器已经做过时间同步转出来的bag中话题时间戳是齐整的不会出现点云和IMU时间错位的问题。转换命令的形式是cd /path/to/kitti_raw kitti2bag -t 2011_09_26 -r 0005 raw_synced .命令里的-t是采集日期-r是drive编号最后的.表示输出到当前目录。转换完成后会生成一个以日期和drive命名的bag文件。转换过程可能需要几分钟因为要读取大量点云bin文件并解析成PointCloud2消息。转完之后先别急着跑用rosbag info看一下bag里的实际话题rosbag info 2011_09_26_0005.bag正常情况下你会看到这样几类话题话题名类型内容/kitti/velodyne_pointssensor_msgs/PointCloud264线激光点云/kitti/imu_raw_datasensor_msgs/ImuIMU原始数据/kitti/gps/fixsensor_msgs/NavSatFixGPS位置/kitti/oxtssensor_msgs/NavSatFix等OXTS导航数据/kitti/camera_color_leftsensor_msgs/Image左侧相机图像LIO-SAM需要的三个关键话题是/velodyne_points、/imu_correct和/gps/fix。名字对不上这是第一个需要处理的点。3.2 话题重映射与TF树补齐话题名不一致的问题最直接的做法是在launch文件里加remap。修改LIO-SAM的run.launch把LIO-SAM节点内的topic名映射到bag里实际的话题名remap fromvelodyne_points to/kitti/velodyne_points/ remap fromimu_correct to/kitti/imu_raw_data/ remap fromgps/fix to/kitti/gps/fix/如果你不想改launch也可以直接把params.yaml里的imuTopic、lidarTopic、gpsTopic改成bag里的实际话题名。两种方式效果一样但建议只用一种不要同时在launch里remap又在param里改topic名否则会出现双重映射反而订阅不到。除了话题名还有更隐蔽的坑TF树。LIO-SAM内部发布里程计TF时需要base_link到velodyne、base_link到imu的变换关系。而KITTI bag里点云的frame_id一般是velodyneIMU的frame_id是imuLIO-SAM节点启动后如果等不到变换会在终端刷错误[ERROR] Timed out waiting for transform from base_link to velodyne ...解决办法是手动广播静态TF让TF树完整起来。我习惯在launch文件里加两个静态变换发布节点node pkgtf typestatic_transform_publisher namebase_link_to_velodyne args0 0 0 0 0 0 base_link velodyne 100 / node pkgtf typestatic_transform_publisher namebase_link_to_imu args0 0 0 0 0 0 base_link imu 100 /坐标全部填0只是为了让系统跑起来对KITTI这种雷达和IMU安装在车顶且距离不远的情况近似够用。当然更严谨的做法是用KITTI官方标定文件里的外参这个放到下一节细说。4. 参数调整与运行实测4.1 传感器参数和外参配置LIO-SAM的params.yaml里有几个参数对KITTI来说必须改否则地图形态会严重不对。参数建议值原因N_SCAN64KITTI用的是Velodyne HDL-64E64线雷达Horizon_SCAN1800水平分辨率Adapt到64线雷达的角分辨率downsampleRate11表示不降采样点云密度高时建图细节更好lidarMinRange1.0KITTI雷达近处有车体噪声保留默认即可lidarMaxRange100.0默认即可savePCDDirectory改成你自己的路径否则保存地图时可能报错Horizon_SCAN这个参数很多人不注意它表示水平扫描一周分为多少份。KITTI的HDL-64E水平角分辨率约0.08度到0.17度1800这个值基本够用。如果你发现地图出现径向撕裂感可以适当提高到2048或3600。重点说说外参。params.yaml里的extrinsicTrans和extrinsicRot表示从雷达坐标系到IMU坐标系的变换。KITTI官方提供了calib_imu_to_velo.txt标定文件里面是一个3x4矩阵表示IMU到雷达的变换。LIO-SAM需要的是雷达到IMU所以严格来说需要求逆之后再填进去。实际操作中我建议分两步走第一次跑通全流程时先用单位阵近似extrinsicTrans: [0.0, 0.0, 0.0] extrinsicRot: [1, 0, 0, 0, 1, 0, 0, 0, 1]等整个系统能稳定建图了再根据标定文件把真实外参填进去。之所以这样建议是因为如果一开始外参就是错的地图出现错位时你会很难判断是外参问题还是数据预处理问题。单位阵虽然不精确但LIO-SAM的后端优化能兜住一部分误差跑通流程没问题。真实外参填进去后你会发现地图在转弯处和长直路段都会更干净。4.2 实际运行流程与现象记录一切配置就绪后启动LIO-SAMroslaunch lio_sam run.launch关键一步KITTI bag是录制数据必须让ROS使用bag里的模拟时间否则TF和时间戳会乱套。新开一个终端rosparam set use_sim_time true rosbag play --clock 2011_09_26_0005.bag如果机器性能一般建议加上-r 0.5以半速播放bag避免点云积压导致丢帧rosbag play --clock -r 0.5 2011_09_26_0005.bag运行后观察rviz你会看到点云地图逐渐展开轨迹从起点向外延伸。KITTI数据里车辆在市区巷道中穿行两边建筑和树木特征明显适合LIO-SAM发挥。如果地图出现跳变或轨迹飞掉大概率是TF树问题或者外参错误回头检查上一节的内容。4.3 开GPS和不开GPS的效果差异LIO-SAM默认在params.yaml里会给gpsTopic赋值一旦有GPS话题输入因子图里就会加入GPS位置约束。在KITTI这种有GPS真值的场景下开启GPS能明显抑制长距离累积漂移。我实测对比过一个序列关闭GPS因子时车辆左转进入长直路段后轨迹会向右侧缓慢偏移跑了大约两公里后横向误差累计到几米开启GPS后轨迹几乎贴着真值走尤其是直道部分不会出现缓慢漂移的现象。代价是偶尔会有GPS位置跳变导致地图瞬间抖动这在KITTI的市区数据里偶尔会出现因为RTK信号在某些路段会被遮挡。如果你只是想验证激光惯性里程计本身的精度可以先注释掉gpsTopic看纯紧耦合效果如果是做全局建图或者需要完整轨迹再打开GPS因子。这个开关对后续做精度对比实验很关键建议跑两遍都记录下来。5. 常见问题与排错实录5.1 编译期问题最典型的是GTSAM版本不一致。很多人在catkin_make阶段卡住终端报错内容是找不到gtsam相关头文件或者链接失败。这时不用想直接卸掉apt装的GTSAM重新源码编译4.0.2版本世界上会清净很多。还有一类问题是PCL版本冲突。如果你机器上装了多个版本的PCL编译时可能链接到错误的库报一堆模板实例化错误。这种情况建议用rosclean check确认ROS环境和系统环境必要时在干净的容器里重新搭环境。5.2 运行期问题运行期最常遇到的是TF等待超时。现象是rviz里看不到地图终端不停刷Timed out waiting for transform from base_link to velodyne。原因基本就是frame_id不匹配或缺少静态TF。优先用rosrun tf tf_echo base_link velodyne检查TF树是否存在再检查bag里PointCloud2的frame_id是不是velodyne。另一个常见问题是bag播放时间戳异常。如果你没有设置use_sim_time直接rosbag playLIO-SAM收到消息时间戳和系统当前时间差距太大会被当作过期消息丢弃。表现是地图建立了一会儿就卡住不再更新。解决办法就是上面说的先rosparam set use_sim_time true再带--clock播放。还有一类问题是内存不足导致进程被kill。KITTI点云比较密集加上LIO-SAM在局部地图里维护大量体素特征跑久了内存占用会持续上升。如果机器内存少于16G建议把downsampleRate调成2相当于对点云做降采样内存压力会小很多地图也不会肉眼可见地变差。5.3 评估阶段的问题跑完LIO-SAM之后如果你需要量化精度一般会用evo工具。LIO-SAM会发布/aft_mapped_to_init话题类型是nav_msgs/Odometry需要转成TUM格式才能和KITTI真值对比。安装evopip install evo --upgrade --no-binary evo录制位姿轨迹可以在播放bag的同时用一个节点订阅/aft_mapped_to_init保存成文本也可以用rostopic echo配合-p参数导出CSV。我这里简单记录一下用evo评估的流程# 将KITTI真值从kitti格式转成tum格式 evo_traj kitti groundtruth.txt --save_as_tum # 运行LIO-SAM并录制轨迹后用tum格式对齐评估 evo_ape tum groundtruth.tum lio_sam.tum -va --plot注意点在于KITTI真值通常只提供odometry benchmark里的pose文件如果你跑的是raw data里的某个drive需要先确认这个drive对应哪个sequence否则真值和轨迹对不上评估出来的ATE数字没有意义。如果只是验证算法跑通用evo_traj tum lio_sam.tum -p看轨迹形态是否合理就够了不必纠结数值。6. 几条跑KITTI序列的实测心得最后分享几个我在实际跑的过程中总结出来的经验不是教程里会写的那种。第一选序列很重要。KITTI raw data里不是每个drive都适合跑LIO-SAM。有的序列场景过于开阔比如高速路段雷达特征稀疏GPS又偶尔被天桥遮挡LIO-SAM跑起来轨迹会有明显波动。建议先挑市区巷道类序列比如2011_09_26的0005或0035这种两侧建筑多、特征丰富回环也多能看到LIO-SAM回环闭合后地图突然“咔”一下对齐的爽快场面。第二调试时一定要学会看终端日志。LIO-SAM运行时会输出Initialization finished、loop closure detected这类关键信息。如果你看到回环检测一直不触发先确认bag里是否真的回到了起点附近如果地图回环处出现错层可以先试着把downsampleRate调低增加匹配点云密度。第三跑KITTI这种10Hz点云数据时LIO-SAM的CPU占用会比跑自采数据更高。我建议播放bag时加上-r 0.8倍速既不会太慢浪费时间又不会因为丢帧导致结果变差。用top监控CPU如果持续跑满把rviz里不必要的显示项关掉能省不少性能。第四如果你后续要和别的方法做对比实验务必保持输入一致。比如A-LOAM跑同一份bagLIO-SAM也跑同一份bag评估指标统一用evo计算RMSE、ATE、RPE这些指标的定义别混用。KITTI上大家更习惯看相对平移误差和相对旋转误差提交对比表格时把参数和运行条件写清楚别人复现你的实验才不费力。我个人的体会是LIO-SAM在KITTI上跑通并不难难的是把数据预处理、外参、GPS开关这些细节点都理清楚。这套流程跑顺之后换到自己的机器人数据集上你会少踩很多坑。本文还有配套的精品资源点击获取