简介:本资源是为适配KITTI数据集深度定制的LIO-SAM改进版本,面向自动驾驶、SLAM算法研究与多传感器融合定位方向的研究生、工程师及进阶开发者,解决原始LIO-SAM在KITTI真实城市场景下点云-IMU同步偏差大、初始化不稳定及城市道路特征稀疏导致建图漂移等问题。压缩包共44个文件,含5个launch启动配置、4个核心cpp源码、3个conf/yaml参数文件、8个png/gif效果可视化图、1个Dockerfile容器化支持及完整ROS工作空间结构(含msg、srv、xacro、rviz等标准模块),整体76.06MB,结构规范、开箱即用。已有1059人学习下载,资源提供完整可运行的MY-LIO-SAM-main工程目录,涵盖KITTI专用数据读取接口、坐标系对齐修正、IMU预积分适配及配套README.md说明,便于快速复现实验、对比原版性能并开展算法调优。
1. 项目概述:当LIO-SAM遇上KITTI
最近在折腾LIO-SAM这个激光惯性里程计框架,想用它来处理经典的KITTI数据集。LIO-SAM本身是个非常优秀的开源项目,融合了激光雷达和IMU数据,能构建出精度不错的点云地图和轨迹。但当你兴冲冲地把KITTI的.bin文件丢给它时,大概率会碰一鼻子灰。原因很简单,LIO-SAM默认的配置和数据接口是为特定传感器(如Velodyne HDL-32E)和ROS消息格式量身定制的,而KITTI数据集虽然也是激光雷达数据,但其数据格式、坐标系定义、甚至时间戳的提供方式都存在差异。这个“为适配kitti数据集修改的lio-sam.zip”项目,正是为了解决这些“水土不服”的问题而生。它本质上是一个针对LIO-SAM源码的补丁包,通过修改数据加载、坐标转换、参数配置等核心环节,让LIO-SAM能够顺畅地“消化”KITTI数据,输出可用于评估的轨迹和地图。对于想用KITTI这个标杆数据集来验证、测试或学习LIO-SAM算法的人来说,这个修改版是一个能节省大量前期适配时间的实用工具。
2. 核心修改内容与原理拆解
2.1 数据接口的重构:从ROS话题到KITTI .bin文件
LIO-SAM原版设计运行在ROS(Robot Operating System)环境下,其激光雷达数据的输入依赖于ROS的标准消息类型sensor_msgs/PointCloud2。节点启动后,它会订阅一个指定的ROS话题(如/points_raw)来实时接收点云。然而,KITTI数据集提供的是离线的一序列.bin文件,每个文件包含一帧激光雷达扫描的原始数据(通常是Velodyne 64线雷达的浮点格式)。这是第一个根本性矛盾。
修改的核心之一,就是创建一个新的数据读取模块,替代ROS的话题订阅。这个模块需要实现:
- 按顺序读取.bin文件:遍历指定文件夹下的所有.bin文件,并按照文件名顺序(或根据时间戳文件)进行加载。
- 二进制数据解析:KITTI的.bin文件中,每个点通常由4个
float32数值构成,分别表示点的三维坐标 (x, y, z) 和反射强度 (intensity)。解析器需要正确地将这些二进制数据解码成内存中的点云数据结构。 - 封装成LIO-SAM可用的格式:将解析出的点数据,填充到LIO-SAM内部定义的
pcl::PointCloudXYZI(PCL点云库格式)对象中。这一步是关键,它桥接了原始数据和算法内部处理逻辑。
注意:这里不能简单地将点云发布为ROS话题再让原版LIO-SAM订阅,因为那样会引入不必要的ROS通信开销和复杂度。更直接高效的方式是修改LIO-SAM的入口代码,让它的主循环直接从我们新写的解析器里获取点云对象。
2.2 坐标系与变换的校准
坐标系不一致是导致算法失效的另一个常见坑点。LIO-SAM内部有复杂的坐标系树,包括激光雷达坐标系 (lidar_link)、IMU坐标系 (imu_link)、世界坐标系 (map或odom)等。它依赖精确的外参(Extrinsic)来描述这些坐标系之间的变换关系,特别是激光雷达到IMU的变换T_lidar_to_imu。
KITTI数据集也提供了标定文件,但其坐标系定义和LIO-SAM的默认假设可能不同。例如:
- 轴向定义:KITTI中,相机坐标系通常是x向右,y向下,z向前。而激光雷达坐标系可能是x向前,y向左,z向上。不同的雷达驱动或ROS定义也可能有差异。
- 外参格式:KITTI的标定文件提供的是相机到激光雷达的变换矩阵,我们需要从中提取或推导出激光雷达到IMU的变换。但KITTI的原始数据中,IMU(实际上来自GPS/IMU单元)和激光雷达是刚性连接的,其变换矩阵通常是固定的,但需要根据传感器安装位置确定。
修改版必须仔细核对并修正以下参数:
T_lidar_to_imu:在LIO-SAM的配置YAML文件(如params.yaml)中,需要填入从KITTI标定文件计算或推导出的正确变换矩阵。如果这个参数错了,激光雷达特征点和IMU预积分信息将在不同的空间基准下,导致状态估计完全发散。- 点云去畸变参数:KITTI数据是否已经做了运动畸变校正?通常原始.bin数据是未校正的。LIO-SAM有自己的运动畸变校正模块,但需要知道雷达的扫描模式(如旋转速度、扫描方向)。修改版可能需要调整相关代码或参数,以匹配KITTI雷达(Velodyne HDL-64E)的实际扫描特性。
2.3 时间戳同步策略的调整
时间是多传感器融合的命脉。原版LIO-SAM严重依赖ROS的ros::Time来为每一帧点云和IMU数据打上时间戳,并以此进行精确的时间同步。
KITTI数据集提供了两个相关文件:
timestamps.txt:记录了每个激光雷达帧的采集时间(UTC时间)。oxts文件夹下的数据:包含了GPS/IMU的位姿、速度、角速度等信息,每个IMU数据包也有对应的时间戳。
修改版需要实现一套新的时间管理系统:
- 时间基准统一:将KITTI文本文件中的UTC时间字符串,转换为一个从数据集开始时刻计算的、单调递增的
double类型秒数(或纳秒数),作为内部时间基准。 - 点云时间戳:为每一帧读取的点云赋予对应的时间戳。
- IMU数据插值与同步:KITTI的IMU数据频率(通常10Hz)远低于激光雷达(10Hz)。LIO-SAM的IMU预积分需要高频数据。修改版需要编写一个IMU数据读取器,读取
oxts数据,并根据其时间戳,在点云帧间进行插值,生成高频的虚拟IMU测量值,或者直接适配KITTI的低频IMU输入(这可能需要调整LIO-SAM的IMU处理逻辑,对性能有影响)。 - 时间戳传递:确保在LIO-SAM内部的因子图优化等环节,所有数据都能使用这套统一的时间基准。
2.4 配置参数的重调优
即使数据灌进去了,坐标系也对齐了,时间也同步了,直接用原版参数跑KITTI数据效果也可能不理想。因为传感器特性变了。
- 激光雷达参数:KITTI用的Velodyne HDL-64E与LIO-SAM默认适配的雷达(如HDL-32E)在线数、水平分辨率、垂直视场角、测距范围等方面都不同。需要调整
params.yaml中的相关参数,例如:N_SCAN: 激光雷达的线数,HDL-64E应设为64。Horizon_SCAN: 每圈扫描的点数,这取决于雷达的水平角分辨率。lidarMinRange&lidarMaxRange: 有效测距范围,需要根据KITTI数据实际情况设置,过滤掉过近和过远的噪声点。
- 特征提取参数:曲率阈值、平面点判断条件等,可能需要针对KITTI城市道路环境进行微调,以稳定地提取出地面、建筑立面等特征。
- 运动参数:KITTI数据集来自汽车平台,其运动模型(主要是平面运动,加减速模式)与无人机或机器人不同。可能需要调整IMU噪声参数、运动预测的参数,使状态估计更符合车辆运动学。
3. 适配修改的实操步骤详解
3.1 环境准备与源码获取
假设你已经在Ubuntu系统上配置好了ROS(推荐Melodic或Noetic)和必要的依赖(如PCL, Eigen, gtsam等)。接下来:
- 获取原始LIO-SAM:从GitHub克隆LIO-SAM的官方仓库到你的ROS工作空间的
src目录下,并编译通过。这是基础,确保原版能正常编译。cd ~/catkin_ws/src git clone https://github.com/TixiaoShan/LIO-SAM.git cd .. catkin_make -DCMAKE_BUILD_TYPE=Release - 获取适配修改包:找到“为适配kitti数据集修改的lio-sam.zip”这个资源包。解压后,你会看到它通常包含以下几类文件:
- 修改过的核心源文件(如
imageProjection.cpp,mapOptmization.cpp等)。 - 新增的文件(如
kitti_loader.cpp/hpp,专门用于读取.bin文件)。 - 针对KITTI的配置文件示例(如
params_kitti.yaml)。 - 可能还有修改过的CMakeLists.txt或launch文件。
- 修改过的核心源文件(如
- 应用修改:这是最关键且最容易出错的一步。不要直接覆盖!建议的做法是:
- 仔细阅读修改包中的
README.md或说明文档(如果有的话)。 - 使用
diff工具或Git的patch功能,将修改包中的变更应用到你的原始LIO-SAM代码上。例如,如果修改包提供了补丁文件(.patch),你可以使用:cd ~/catkin_ws/src/LIO-SAM git apply /path/to/your/kitti_adaptation.patch - 如果没有补丁文件,你需要手动对比修改版和原版文件的差异,将必要的代码段合并到你的源码中。重点关注数据读取、时间戳处理、坐标系变换相关的函数。
- 仔细阅读修改包中的
3.2 数据准备与路径配置
- 下载KITTI Odometry数据集:从KITTI官网下载你需要的数据序列(例如序列00-10)。解压后,目录结构应类似:
kitti_dataset/sequences/00/ ├── velodyne/ # 存放 .bin 点云文件 ├── calib.txt # 标定文件 └── times.txt # 时间戳文件 - 修改配置文件:使用修改包提供的
params_kitti.yaml作为模板,创建你自己的配置文件。需要修改的核心路径参数包括:
如何从# 示例参数 pointCloudTopic: "/kitti/velodyne_points" # 可能已被内部读取器替代,但话题名仍需定义 sequence_path: "/home/user/dataset/kitti/sequences/00" # KITTI序列的绝对路径 # 外参参数 (需要根据calib.txt计算) extrinsicTrans: [x, y, z] # 雷达到IMU的平移 extrinsicRot: [ [r11, r12, r13], [r21, r22, r23], [r31, r32, r33] ] # 雷达到IMU的旋转矩阵 extrinsicRPY: [roll, pitch, yaw] # 或以欧拉角形式表示 # 雷达参数 N_SCAN: 64 Horizon_SCAN: 1800 # 以HDL-64E为例,需核实 lidarMinRange: 2.0 # 过滤车体自身点云 lidarMaxRange: 100.0calib.txt计算外参:calib.txt中的Tr是3x4矩阵,表示从相机0坐标系到激光雷达坐标系的变换(P_velo_to_cam0)。而LIO-SAM需要的是激光雷达到IMU的变换。通常可以假设IMU坐标系与相机坐标系近似对齐(或有一个固定的小偏移),因此T_lidar_to_imu ≈ inv(Tr)。你需要仔细查阅KITTI的传感器安装文档来确定精确关系。
3.3 编译与运行测试
- 编译工程:应用所有修改并配置好YAML文件后,回到工作空间根目录重新编译。
确保编译过程没有报错。如果有错误,通常是代码合并冲突或依赖缺失,需要根据错误信息逐一排查。cd ~/catkin_ws catkin_make -DCMAKE_BUILD_TYPE=Release - 启动LIO-SAM节点:使用修改后的launch文件启动。这个launch文件应该已经配置为加载你修改过的
params_kitti.yaml,并且可能禁用了原始的ROS话题订阅器,启用了内置的KITTI数据读取器。roslaunch lio_sam run.launch - 观察运行状态:打开RViz,添加
/lio_sam/mapping/odometry(轨迹)和/lio_sam/mapping/cloud_registered(当前帧点云)等话题进行可视化。你应该能看到点云被一帧帧地处理,并逐渐生成轨迹。 - 保存结果:LIO-SAM通常会在程序结束时,在
~/catkin_ws/src/LIO-SAM/results目录下保存估计的轨迹文件(如pose.txt或tum格式.txt)。你可以用这个文件与KITTI提供的真值轨迹进行对比,评估精度。
3.4 结果评估与轨迹对比
使用像evo这样的工具可以方便地进行轨迹评估。
- 格式转换:将LIO-SAM输出的轨迹和KITTI的真值轨迹(通常在
poses文件夹下,为.txt文件,每行是一个3x4的位姿矩阵)转换为evo支持的格式,如TUM格式。 - 运行评估:
通过APE和RPE指标,以及绘制的轨迹对比图,可以定量和定性地分析修改后的LIO-SAM在KITTI数据集上的性能。# 计算绝对位姿误差 (APE) evo_ape kitti ground_truth.txt lio_sam_estimate.txt -r trans_part --plot --plot_mode xyz # 计算相对位姿误差 (RPE) evo_rpe kitti ground_truth.txt lio_sam_estimate.txt -r trans_part --delta 100 --plot
4. 常见问题与深度排查指南
4.1 编译错误:头文件缺失或函数未定义
- 问题现象:
catkin_make时出现fatal error: xxx.h: No such file or directory或undefined reference to xxx。 - 排查思路:
- 检查代码合并:这是最常见的原因。手动合并代码时,可能漏掉了新增的头文件引用或函数实现。回顾你修改的文件,确保所有从修改包中引入的新类(如
KITTILoader)的头文件(.hpp)都已正确放置,并且在CMakeLists.txt中添加了相应的编译依赖。 - 检查依赖:修改可能引入了对额外库的依赖(如某个特定的时间处理库)。检查修改包中的CMakeLists.txt,看是否有新增的
find_package或target_link_libraries语句,并将其同步到你的CMakeLists.txt中。 - 清理重编:尝试彻底清理编译缓存后重试。
cd ~/catkin_ws rm -rf build devel catkin_make clean catkin_make -DCMAKE_BUILD_TYPE=Release
- 检查代码合并:这是最常见的原因。手动合并代码时,可能漏掉了新增的头文件引用或函数实现。回顾你修改的文件,确保所有从修改包中引入的新类(如
4.2 运行时崩溃或点云无输出
- 问题现象:程序启动后立即崩溃,或在RViz中看不到任何点云和轨迹。
- 排查思路:
- 数据路径:首先确认
params_kitti.yaml中的sequence_path配置是否正确,且该路径下确实存在velodyne文件夹和.bin文件。路径错误会导致数据读取器立即失败。 - 控制台输出:仔细查看
roslaunch启动后的终端输出。通常数据读取模块会在开始时打印读取到的文件数量。如果没有相关输出或报错“cannot open file”,就是路径问题。 - 坐标系检查:如果程序能运行但点云看起来是乱码(比如所有点堆积在原点附近),极有可能是坐标系变换
extrinsicRot和extrinsicTrans设置错误。一个快速的验证方法是:注释掉运动畸变校正和优化部分,只显示原始点云经过初始外参变换后的结果。如果点云形状正确但位置方向不对,就是外参问题。 - 时间戳处理:检查时间戳解析逻辑。如果时间戳全部为0或出现巨大跳变,会导致IMU预积分异常,进而可能引起系统崩溃。在数据读取代码中打印几帧的时间戳,确保其是合理递增的。
- 数据路径:首先确认
4.3 轨迹严重漂移或发散
- 问题现象:开始时轨迹还正常,运行一段时间后轨迹开始乱飞,或者直接发散成一条直线飞向无穷远。
- 排查思路:
- 外参精度:这是导致漂移的首要嫌疑。激光雷达和IMU之间的变换哪怕只有几度的误差,在积分后也会被放大。务必反复核对从KITTI标定文件到
T_lidar_to_imu的计算过程。可以尝试将外参的旋转部分设为单位矩阵,平移设为0,先验证在无外参情况下系统能否“僵住”(不更新),如果能,说明问题很可能在外参。 - IMU数据与同步:检查IMU数据的读取和插值是否正确。如果IMU数据(特别是角速度)存在系统性偏差或噪声过大,预积分会产生巨大误差。可以尝试将配置文件中的
imuTopic设置为一个空话题,并设置useImu为false,仅用激光雷达里程计部分运行。如果漂移消失,问题就出在IMU相关环节。 - 参数调优:
- 特征提取参数:在KITTI城市场景中,地面点很多。适当调整
edgeThreshold和surfThreshold,确保能稳定提取到足够的角点和平面点。可以通过RViz实时显示提取的特征点,观察其是否稳定。 - IMU噪声参数:
gyrCov(陀螺仪噪声)和accCov(加速度计噪声)需要根据KITTI车辆IMU的实际性能调整。过小的噪声值会让优化器过于信任IMU,可能放大误差;过大的噪声值则会削弱IMU的作用。通常需要根据轨迹结果进行反复试验。 - 回环检测参数:KITTI序列有回环。确保回环检测功能开启,并调整
loopClosureFrequency和surroundingKeyframeSize等参数,使其能在适当的时候检测并修正回环。
- 特征提取参数:在KITTI城市场景中,地面点很多。适当调整
- 外参精度:这是导致漂移的首要嫌疑。激光雷达和IMU之间的变换哪怕只有几度的误差,在积分后也会被放大。务必反复核对从KITTI标定文件到
4.4 性能低下或处理速度慢
- 问题现象:数据处理的频率远低于激光雷达帧率(10Hz),导致卡顿。
- 排查思路:
- 资源监控:使用
htop或top命令查看CPU和内存占用。LIO-SAM本身计算量较大。 - 降采样设置:检查
params_kitti.yaml中的filter参数。对于64线雷达,原始一帧点云约有10万+个点。务必开启降采样,例如设置filter_size_surf(平面特征降采样栅格)和filter_size_map(地图降采样栅格)为0.2-0.4米,可以大幅减少计算量。 - 地图管理:
surroundingKeyframeSearchRadius和surroundingKeyframeSearchNum控制着局部地图的大小。在KITTI这种长走廊环境中,过大的搜索半径会导致构建的地图点云过多,拖慢匹配速度。可以适当调小。 - 调试输出:关闭所有不必要的调试信息输出。在ROS中,可以通过
rosconsole设置或编译Release版来减少日志开销。
- 资源监控:使用
5. 进阶技巧与扩展思考
5.1 融合GPS先验信息(可选)
KITTI的oxts数据中包含了高精度的GPS位置信息。虽然LIO-SAM本身是紧耦合的激光-IMU里程计,但在长时间、大范围场景下,加入GPS作为绝对位置约束可以有效地抑制累积误差。修改版可以进一步扩展,在因子图中加入GPS因子。这需要:
- 解析
oxts数据中的经纬高,并转换为UTM坐标或局部笛卡尔坐标。 - 在
mapOptmization.cpp中,当接收到有效的GPS数据时,构造一个gtsam::PriorFactor<gtsam::Pose3>因子,添加到因子图中。GPS因子的噪声协方差需要根据GPS的精度(如单点定位还是RTK)合理设置。
5.2 适配KITTI 3D检测数据集
“kitti 3d 专用迷你数据集”通常指用于目标检测的裁剪后的小数据集。如果你想用LIO-SAM处理这类数据,需要注意:
- 数据范围:检测数据集可能只包含感兴趣区域(如车辆周围)的点云,而不是完整的360度扫描。这可能会破坏LIO-SAM基于全周扫描的特征提取和回环检测逻辑。
- 坐标系:确保数据集的坐标系与Odometry数据集一致。
- 实用性:用SLAM算法处理这类裁剪数据意义有限,因为建图和定位需要环境上下文。更常见的做法是用完整的Odometry序列运行LIO-SAM生成地图和位姿,然后将位姿用于检测数据的标注或分析。
5.3 向其他数据集迁移的思路
成功适配KITTI后,这套修改思路可以复用到其他数据集,如nuScenes。核心工作流是一致的:
- 数据读取器:根据新数据集的格式(可能是
.pcd,.ply或自定义二进制),编写新的数据加载模块。 - 标定文件解析:解析新数据集的传感器标定文件,计算出正确的
T_lidar_to_imu。 - 时间戳同步:建立统一的时间系统,处理多传感器数据的时间对齐。
- 参数重调优:根据新雷达的线数、频率、视场角等调整参数。 “kitti 转 nuscenes”这个热词也反映了社区对跨数据集工具的需求。你可以将适配KITTI的代码模块化,使其更容易配置和切换到其他数据集。
5.4 对LIO-SAM算法本身的理解加深
通过这次适配,你会被迫深入阅读LIO-SAM的代码,理解其每一个模块:
- 点云预处理和特征提取:如何从原始点云中提取角点和平面点?
- IMU预积分:如何利用IMU数据在两帧激光之间进行运动预测?
- 因子图优化:激光匹配因子、IMU预积分因子、回环因子是如何构建和优化的?
- 地图管理:如何维护和更新全局地图、局部地图、关键帧?
这个过程远比单纯跑通一个demo有价值。当你遇到问题并逐一解决时,你对激光惯性里程计系统的理解会达到一个新的层次。例如,你会明白为什么外参不准会导致发散,为什么时间同步如此关键,以及各个噪声参数如何影响最终的轨迹精度。
本文还有配套的精品资源,点击获取