ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LIO-SAM适配KITTI数据集:从原理到实践的完整指南

2026/9/4 4:06:29 拓冰建站 浏览量
LIO-SAM适配KITTI数据集:从原理到实践的完整指南 简介本资源是面向SLAM算法研究者与自动驾驶方向开发者的Kitti数据集专用LIO-SAM改进版本解决原始LIO-SAM在Kitti真实城市场景中因传感器标定差异、点云密度变化及IMU同步偏差导致的建图漂移与定位不稳定问题。压缩包共44个文件含5个launch启动脚本适配Kitti序列加载、4个核心cpp源码含LiDAR-IMU时间对齐与特征提取优化模块、3个conf/yaml配置文件预设Kitti雷达型号与运动先验参数、8个png/gif可视化结果图含轨迹对比与地图重建效果以及Dockerfile、rviz配置与完整README说明文档整体76.06MB。已有1059人学习下载提供可直接编译运行的完整工程结构MY-LIO-SAM-main为主目录涵盖数据预处理接口、城市道路特征匹配策略改进、EKF滤波器参数调优方案及标准Kitti序列如00/05/10的评估结果对比助读者快速复现、调试并深入理解多传感器融合SLAM在真实数据上的适配逻辑。1. 项目概述当LIO-SAM遇上KITTI如果你正在做自动驾驶或者机器人定位与建图SLAM的研究那么“LIO-SAM”和“KITTI”这两个词对你来说一定不陌生。LIO-SAM是一个基于因子图优化的紧耦合激光惯性里程计框架以其在复杂场景下的高精度和鲁棒性而闻名。而KITTI数据集则是这个领域里最经典、最权威的公开基准测试集之一无数算法都在它的排行榜上证明过自己。但当你兴冲冲地下载了LIO-SAM的代码准备用KITTI数据来跑一跑验证一下效果时很可能会发现程序直接报错或者跑出来的轨迹和真值对不上。这就像你拿到了一把精密的瑞士军刀LIO-SAM却发现它没法直接开你手边这个特定牌子的罐头KITTI数据集。这个名为“为适配kitti数据集修改的lio-sam.zip”的项目就是为了解决这个“刀”与“罐头”不匹配的问题。它不是一个全新的轮子而是对原始LIO-SAM仓库进行了一系列针对性的“外科手术式”修改使其能够无缝读取、解析并处理KITTI数据集提供的传感器数据格式最终输出可与KITTI官方真值进行对比的轨迹结果。对于研究者而言这意味着你可以快速在公认的基准上评估LIO-SAM的性能对于学习者来说这提供了一个绝佳的、可运行的实例让你能深入理解激光-惯性里程计如何处理真实世界中的标准化数据。接下来我将详细拆解这个适配工作的核心思路、具体修改点、实操步骤以及我踩过的那些坑。2. 核心需求与适配思路拆解2.1 原始LIO-SAM与KITTI的“代沟”要理解为什么需要修改首先得看清两者之间的不匹配点。原始的LIO-SAM代码仓库预设了特定的数据输入接口主要体现在以下几个方面传感器话题与消息类型LIO-SAM默认订阅ROSRobot Operating System中的特定话题例如/velodyne_points激光雷达点云和/imu/dataIMU数据。它期望接收的是ROS标准消息类型sensor_msgs/PointCloud2和sensor_msgs/Imu。而KITTI数据集提供的是.bin格式的激光雷达文件和.txt格式的IMU/Odometry数据并非ROS消息。坐标系与时间戳LIO-SAM内部有复杂的坐标系变换树TF tree包括map,odom,base_link,velodyne,imu_link等。它假设传感器之间的外参Extrinsics是已知并通过参数文件配置的。KITTI数据集虽然提供了标定文件但其坐标系定义例如相机坐标系cam0和LIO-SAM的预设可能不同。此外KITTI数据的时间戳是独立的文件需要被正确解析并赋予到每条数据上以维持时间同步这是多传感器融合的命脉。数据播放与同步LIO-SAM是一个在线系统设计为实时处理ROS话题流。我们需要一个“播放器”来将KITTI的离线数据按照正确的时间顺序以ROS话题的形式“模拟实时”地发布出来。这个播放器还需要处理不同传感器数据流之间的时间同步问题。真值格式与评估KITTI提供poses.txt作为真值轨迹以第一个相机坐标系为参考。我们需要将LIO-SAM输出的轨迹通常是odom坐标系下的位姿转换到与真值相同的坐标系下才能进行ATE绝对轨迹误差等定量评估。原始LIO-SAM不包含这个评估流程。2.2 适配工作的整体架构基于以上分析适配工作的核心思路可以概括为“搭建一座桥”这座桥由几个关键组件构成KITTI数据转ROS包工具我们需要一个工具将原始的KITTI数据集data_odometry_velodyne和data_odometry_calib转换为ROS支持的.bag文件。这样我们就可以使用rosbag play命令来“回放”数据模拟在线传感器输入。常用的工具是kitti2bag。修改LIO-SAM的启动与参数配置话题重映射修改LIO-SAM的启动文件.launch使其订阅的话题名称与kitti2bag生成的话题名称一致。例如KITTI的激光雷达数据可能发布在/kitti/velo/pointcloud。参数调整根据KITTI传感器Velodyne HDL-64E激光雷达和OXTS IMU/GPS的实际参数调整LIO-SAM配置文件中的关键参数。这包括pointCloudTopic: 激光雷达点云话题名。imuTopic: IMU话题名。extrinsicTrans,extrinsicRot: 激光雷达到IMU的外参矩阵需要从KITTI标定文件计算得出。imuAccNoise,imuGyrNoise,imuAccBiasN,imuGyrBiasN: IMU噪声参数这些参数对滤波和优化效果影响巨大通常需要根据传感器手册或经验调整。timeOffset: 如果发现激光雷达和IMU时间戳存在固定偏移需要在此处补偿。坐标系对齐与轨迹输出修改LIO-SAM的代码使其在保存轨迹时能够输出与KITTI真值坐标系对齐的位姿。这通常涉及在因子图优化后将位姿从odom或map坐标系转换到第一个激光雷达帧或第一个相机帧坐标系。同时需要将位姿保存为KITTIposes.txt格式每行12个数字代表3x4的变换矩阵的前三行。可选轨迹评估脚本编写或集成一个Python脚本用于读取LIO-SAM输出的轨迹文件和KITTI的真值文件计算ATE、RPE等指标并绘制轨迹对比图。这个“为适配kitti数据集修改的lio-sam.zip”项目本质上就是完成了上述第2步和第3步的核心修改并可能提供了第4步的脚本打包成了一个开箱即用的版本。3. 关键修改点与代码解析拿到一个适配好的lio-sam.zip我们不应该只满足于能跑起来更要理解作者改了哪里为什么这么改。这里我结合自己的经验剖析几个最关键的修改部位。3.1 启动文件与参数配置的调整通常修改会从config/params.yaml和launch/module.launch开始。params.yaml关键参数修改示例# 原始LIO-SAM可能为 pointCloudTopic: “/velodyne_points” imuTopic: “/imu/data” # 适配KITTI后需改为具体话题名取决于kitti2bag的版本和设置 pointCloudTopic: “/kitti/velo/pointcloud” imuTopic: “/kitti/oxts/imu” # 外参参数 - 这是重中之重 # KITTI的标定文件提供了相机0到相机N以及相机0到Velodyne的变换矩阵。 # LIO-SAM需要的是Velodyne到IMU的变换。但KITTI的IMU/GPS数据是OXTS单元其坐标系与相机0有固定的变换关系通常记录在calib.txt中。 # 假设我们从标定文件中得到了从Velodyne到相机0的变换矩阵 T_v2c0以及从相机0到IMUOXTS的变换矩阵 T_c02i。 # 那么 Velodyne 到 IMU 的变换为T_v2i T_c02i * T_v2c0 # 需要将这个矩阵的平移和旋转部分分解填入以下参数 extrinsicTrans: [x, y, z] # T_v2i 的平移部分 extrinsicRot: [r11, r12, r13, r21, r22, r23, r31, r32, r33] # T_v2i 的旋转矩阵行优先展开注意外参的计算很容易出错。务必仔细阅读KITTI的readme.txt理解每个标定矩阵的含义是从目标坐标系到源坐标系还是反过来。一个常见的错误是矩阵乘法顺序或求逆搞反这会导致建图完全错乱。我个人的习惯是先用一个小脚本用标定数据验证一下变换链是否正确比如将一个在激光雷达坐标系下的点通过变换链转换到IMU坐标系看看是否合理。module.launch修改这里主要是确保所有节点订阅的话题与params.yaml中的设置以及实际rosbag发布的话题一致。有时kitti2bag生成的话题带有命名空间比如/kitti/velo/pointcloud那么launch文件中对应的remap标签就需要做相应调整。3.2 核心代码修改轨迹输出与坐标系对齐这是适配工作的核心技术部分通常需要修改src/mapOptmization.cpp或相关的保存轨迹的代码段。原始LIO-SAM的输出可能是在map或odom坐标系下的位姿保存格式可能是TUM时间戳 位置 四元数或自定义格式。目标输出在KITTI第一个相机或第一个激光雷达帧坐标系下的位姿格式为poses.txt每行12个值代表3x4变换矩阵的前三行即R|t。修改逻辑获取初始变换在程序开始时例如第一帧激光雷达数据到来时记录下此时odom或map坐标系到base_link或velodyne坐标系的变换T_odom2velo_init。这个变换可以通过查询TF树获得。定义目标坐标系我们的目标是将所有位姿表示在第一个激光雷达帧坐标系下。设第一个激光雷达帧为velo_init。在线计算与保存对于后续优化得到的每一个关键帧位姿T_odom2velo_current我们计算它相对于初始帧的变换T_velo_init2velo_current T_odom2velo_current * inverse(T_odom2velo_init)这个T_velo_init2velo_current就是当前帧在初始激光雷达坐标系下的位姿。格式转换与输出将T_velo_init2velo_current这个4x4齐次变换矩阵的前三行3x4即旋转矩阵R和平移向量t按行优先顺序写入文件。同时KITTI的poses.txt通常不需要时间戳但我们可以选择同时保存时间戳以备其他用途。代码片段示意关键思想// 假设在某个回调函数或保存函数中 // 获取当前关键帧在odom下的位姿 (来自因子图优化结果) Eigen::Isometry3d pose_odom2velo_current ...; // 计算相对于初始帧的位姿 Eigen::Isometry3d pose_velo_init2velo_current pose_odom2velo_current * pose_odom2velo_init.inverse(); // 提取旋转矩阵和平移向量 Eigen::Matrix3d R pose_velo_init2velo_current.rotation(); Eigen::Vector3d t pose_velo_init2velo_current.translation(); // 按KITTI格式写入文件 (行优先3x4矩阵) std::ofstream out_file(“trajectory_kitti.txt”, std::ios::app); out_file R(0,0) “ “ R(0,1) “ “ R(0,2) “ “ t(0) “ “ R(1,0) “ “ R(1,1) “ “ R(1,2) “ “ t(1) “ “ R(2,0) “ “ R(2,1) “ “ R(2,2) “ “ t(2) std::endl;实操心得这里有一个细节需要注意就是T_odom2velo_init的获取时机。必须在LIO-SAM完成初始化例如IMU预积分稳定、收到第一帧有效的激光雷达数据并完成初始化位姿估计之后获取否则初始位姿不准会导致整个轨迹发生旋转或平移。我通常会在收到第一个“关键帧”并成功插入到因子图之后才记录这个初始变换。3.3 时间同步与传感器频率处理KITTI数据集中激光雷达频率是10Hz而OXTS IMU/GPS数据频率是100Hz。在rosbag play时如果播放速度过快可能会导致LIO-SAM的缓存队列溢出或处理不及时。如果播放速度设为真实时间那么处理速度会很慢。常见处理方式使用--clock和-r参数rosbag play --clock -r 2 kitti.bag。--clock发布模拟时间-r 2表示以2倍速播放。这可以加快处理速度同时保持传感器数据间的时间关系。调整LIO-SAM队列大小如果出现数据丢失警告可以适当增大params.yaml中的imuQueueSize和pointCloudQueueSize。检查时间戳确保kitti2bag正确地将KITTI的时间戳通常是微秒或纳秒转换成了ROS时间戳。有时时间戳错误会导致TF查找失败。可以在rviz中查看/tf和/tf_static来诊断。4. 完整实操流程从数据准备到轨迹评估假设你已经有一个修改好的lio-sam-kitti.zip以下是详细的复现步骤。4.1 环境准备与依赖安装系统与ROS推荐Ubuntu 18.04 ROS Melodic或Ubuntu 20.04 ROS Noetic。确保ROS基础环境安装完整。安装LIO-SAM依赖sudo apt-get install -y ros-$ROS_DISTRO-navigation ros-$ROS_DISTRO-robot-localization ros-$ROS_DISTRO-robot-state-publisher sudo apt-get install -y libsuitesparse-dev libpcl-dev libeigen3-dev安装kitti2bagpip install kitti2bag # 如果pip安装失败可以尝试从源码安装 # git clone https://github.com/tomas789/kitti2bag.git # cd kitti2bag pip install -e .编译修改后的LIO-SAMunzip lio-sam-kitti.zip cd lio-sam-kitti mkdir build cd build cmake .. make -j4 # 根据你的CPU核心数调整4.2 KITTI数据下载与转换下载KITTI Odometry数据集从KITTI官网下载data_odometry_velodyne.zip激光雷达数据和data_odometry_calib.zip标定文件。选择你想要的序列比如序列00。解压并组织数据解压后目录结构应类似kitti_data/ ├── dataset/ │ └── sequences/ │ └── 00/ │ ├── velodyne/ # .bin文件 │ ├── calib.txt │ └── times.txt转换为ROS Bagcd path/to/kitti_data kitti2bag -t 2011_10_03 -r 00 raw_synced .这个命令会生成一个名为kitti_2011_10_03_drive_00xx_synced.bag的文件。-t指定日期-r指定行程号raw_synced是数据类型.表示在当前目录查找数据集。注意kitti2bag对目录结构有严格要求务必确保calib.txt和times.txt在序列文件夹内。4.3 运行LIO-SAM处理Bag文件启动ROS核心roscore在新的终端中启动LIO-SAMcd lio-sam-kitti source devel/setup.bash roslaunch lio_sam run.launch确保launch文件中的参数路径正确特别是params.yaml。播放KITTI Bag文件cd path/to/your/bag rosbag play --clock -r 2 kitti_2011_10_03_drive_00xx_synced.bag使用--clock发布模拟时间至关重要这样LIO-SAM才能使用bag文件中的时间戳。-r 2是2倍速可以根据你的电脑性能调整。观察与记录打开rviz添加PointCloud2显示话题选择/lio_sam/feature/cloud_full或/lio_sam/mapping/odometry可以看到实时建图效果。LIO-SAM会在指定目录通常在~/catkin_ws/src/LIO-SAM/下输出轨迹文件如trajectory_kitti.txt。4.4 轨迹评估与可视化安装评估工具推荐使用evo一个强大的轨迹评估工具。pip install evo --upgrade --no-binary evo准备真值文件KITTI Odometry数据集的poses文件夹下提供了00.txt等真值文件。每行已经是3x4的变换矩阵。使用evo进行评估格式转换如果LIO-SAM输出的格式不是标准的tum或kitti可能需要写个小脚本转换一下。假设输出已经是KITTI格式。计算绝对轨迹误差ATEevo_ape kitti ground_truth_00.txt lio_sam_trajectory.txt -va --plot --plot_mode xz这个命令会计算ATE并给出最大、最小、均方根误差等统计量同时生成轨迹对比图和误差图。计算相对位姿误差RPEevo_rpe kitti ground_truth_00.txt lio_sam_trajectory.txt -va --plot --plot_mode xzRPE反映了局部精度对于里程计来说也很重要。结果分析观察生成的图表。理想情况下两条轨迹应该基本重合。如果出现明显的漂移、旋转或尺度错误就需要回头检查外参、时间同步或IMU参数。5. 常见问题排查与调优心得在实际操作中你几乎一定会遇到各种问题。下面是我总结的一些典型问题及其解决方法。5.1 问题排查速查表问题现象可能原因排查步骤与解决方法启动LIO-SAM后无点云显示1. 话题不匹配。2. Bag文件未播放或播放错误。3. TF树断裂。1. 使用rostopic list确认Bag发布的话题名与params.yaml中的pointCloudTopic对比。2. 使用rostopic echo /kitti/velo/pointcloud轨迹严重漂移或旋转1. 激光雷达-IMU外参错误。2. IMU噪声参数设置不当。3. 时间戳不同步。1.重点检查重新计算extrinsicTrans和extrinsicRot用可视化工具验证如将点云用外参变换后叠加。2. 调整imuAccNoise,imuGyrNoise等参数尝试将噪声值适当调大更保守的滤波。3. 检查times.txt和IMU数据时间戳确保rosbag play使用了--clock。程序运行缓慢或卡顿1. 点云过于稠密。2. 回环检测计算量大。3. 系统资源不足。1. 在params.yaml中启用downsampleRate对输入点云进行降采样。2. 增大keyframeResolution关键帧距离阈值减少关键帧数量。3. 关闭rviz或降低其刷新率。考虑使用-r参数降低bag播放速度。保存的轨迹文件为空1. 轨迹保存路径错误或不可写。2. 保存轨迹的代码逻辑未触发。1. 检查代码中指定的保存路径确保有写入权限。2. 在保存轨迹的代码处添加打印信息确认程序执行到了那里。检查是否有关键帧成功生成的标志。evo评估时报格式错误1. 轨迹文件格式与evo命令指定的格式不匹配。2. 文件中有空行或格式错误。1. 确认evo_ape kitti ...中的kitti格式是否正确。用evo_traj先查看轨迹evo_traj kitti your_file.txt --plot。2. 检查轨迹文件确保每行都有正确数量的数值且为纯数字。5.2 参数调优经验分享LIO-SAM的性能很大程度上依赖于参数配置。对于KITTI数据集以下参数需要特别关注imuAccNoise和imuGyrNoise这是IMU的随机游走噪声。KITTI使用的OXTS IMU精度相对较高。如果轨迹出现“抖动”或高频噪声可以尝试稍微增大这些值例如从0.01调到0.02让滤波器更信任激光雷达。如果轨迹过于平滑但延迟大可以尝试调小。imuAccBiasN和imuGyrBiasN这是IMU偏置的随机游走噪声。通常保持默认值即可除非你观察到明显的偏置不稳定。edgeFeatureMinValidNum和surfFeatureMinValidNum提取特征点的最小数量。对于Velodyne 64线雷达点云很稠密可以适当提高这些值如从10调到30以提取更稳定、更少的特征提高计算速度和鲁棒性。loopClosureFrequency回环检测频率。KITTI序列较长开启回环对消除累积漂移至关重要。但回环检测很耗时。可以设置为1.01Hz或更低在精度和速度间取得平衡。keyframeResolution关键帧距离阈值。设置为1.0或2.0米对于KITTI的城市场景通常比较合适。太小会导致关键帧过多计算量剧增太大会导致匹配约束不足精度下降。一个实用的调优流程先用序列00城市场景有回环进行调试。首先保证外参绝对正确这是基础。然后关闭回环只调里程计部分的参数IMU噪声、特征提取使开环轨迹的形状基本正确。最后打开回环调整回环相关参数观察轨迹末端是否能正确闭合。5.3 关于“KITTI 3D专用迷你数据集”和“KITTI转nuScenes”KITTI 3D专用迷你数据集这通常指的是从完整的KITTI 3D Object Detection或Tracking数据集中提取的小规模子集用于快速算法验证。在LIO-SAM的适配中我们主要使用Odometry数据集。但如果你手头只有这种迷你检测数据集需要注意它可能不包含连续的全序列点云和IMU数据可能无法直接用于里程计任务。KITTI转nuScenesnuScenes是另一个大型自动驾驶数据集其数据格式特别是标注和传感器布局与KITTI不同。存在一些工具可以将KITTI格式的数据主要是检测框转换到nuScenes格式以便在nuScenes的评估框架下测试。但这与LIO-SAM的适配是两回事。LIO-SAM适配关注的是原始传感器数据点云、IMU的读取和预处理而不是高层级的标注信息。所以“KITTI转nuScenes”这个热词对于本项目而言更可能是一个平行的数据格式转换工具领域除非你需要在一个统一的nuScenes格式管道中处理KITTI的传感器数据流那将涉及更底层的数据驱动层改写。最后我想说的是成功适配并跑通LIO-SAM on KITTI只是一个开始。通过这个过程你不仅得到了一个可用的工具更重要的是深入理解了激光-惯性里程计系统如何与具体的数据格式、坐标系、时间戳打交道。这些经验对于你将来处理其他传感器、其他数据集甚至调试自己SLAM系统中的类似问题都是极其宝贵的。当你看到evo输出的ATE曲线完美贴合两条轨迹几乎重叠时那种成就感就是对所有调试工作最好的回报。如果在操作中遇到任何问题不妨多看看终端输出的INFO和WARN信息那往往是解决问题的第一线索。本文还有配套的精品资源点击获取