1. KITTI数据集准备与格式转换
第一次接触KITTI数据集时,我被它庞大的数据量和复杂的目录结构搞得晕头转向。经过多次实践,我总结出一套最高效的数据处理方法。KITTI数据集分为raw data和odometry两个主要部分,对于LIO-SAM这类激光惯性里程计算法,我们需要特别注意数据的选择和处理方式。
1.1 数据集下载与选择
KITTI官网需要注册才能下载数据,这个过程确实有点麻烦。我推荐使用百度云盘的镜像资源,搜索"KITTI data_odometry_velodyne"就能找到现成的打包文件。下载时要注意,LIO-SAM需要同时获取两种数据:
- *_sync.zip:包含10Hz的IMU数据和去畸变的视觉数据,激光数据以bin格式存储
- *_extract.zip:包含100Hz的IMU原始数据,但视觉数据未去畸变
为什么需要两者?因为LIO-SAM对IMU数据频率要求较高,而_sync.zip中的激光数据格式更友好。我实测发现,只使用_extract.zip转换时会遇到两个问题:一是转换耗时极长(txt格式的激光数据解析慢),二是需要额外处理时间同步。
1.2 数据转换实战
转换工具我推荐两个方案:官方kitti2bag和LIO-SAM作者修改版。先说说基础环境准备:
# 必须升级numpy sudo pip install -U numpy # 安装基础工具 sudo pip install kitti2bag pykitti tqdm对于只有_sync.zip的情况,转换命令很简单:
kitti2bag -t 2011_09_30 -r 0016 raw_synced但结合_extract.zip时就需要特殊处理了。这里有个坑我踩过——时间戳对齐问题。LIO-SAM作者提供的脚本会自动处理这个问题,关键代码如下:
# 时间戳线性拟合校正 imu_index = np.asarray(range(len(imu_datetimes)), dtype=np.float64) z = np.polyfit(imu_index, imu_datetimes, 1) imu_datetimes_new = z[0] * imu_index + z[1]转换完成后,建议用rosbag info检查数据完整性。我遇到过bag文件中缺少IMU数据的情况,这时候需要检查_extract.zip是否下载完整。转换后的bag文件通常很大(序列00大约15GB),记得预留足够磁盘空间。
2. LIO-SAM源码适配KITTI
直接跑原始LIO-SAM在KITTI上会报错,主要因为两个关键差异:点云ring信息和时间戳处理。经过多次调试,我总结出最稳定的修改方案。
2.1 点云ring信息计算
KITTI的Velodyne HDL-64E激光雷达数据不包含ring字段,而LIO-SAM依赖这个信息进行特征提取。我们需要根据垂直角度动态计算:
float verticalAngle = atan2(thisPoint.z, sqrt(thisPoint.x*thisPoint.x + thisPoint.y*thisPoint.y)) * 180 / M_PI; rowIdn = (verticalAngle + ang_bottom) / ang_res_y;这里ang_bottom和ang_res_y需要根据HDL-64E的参数设置:
- ang_bottom = 24.8°(下方视角)
- ang_res_y = 0.4°(垂直角分辨率)
实测中发现,直接这样计算有时会导致rowIdn越界,我增加了边界检查:
if (rowIdn < 0 || rowIdn >= N_SCAN) continue;2.2 时间戳处理优化
KITTI原始数据中没有每个点的时间戳,需要根据扫描周期模拟:
float relTime = (ori - cloudInfo.startOrientation) / cloudInfo.orientationDiff; laserCloudIn->points[i].time = 0.1 * relTime; // 10Hz扫描周期这里有个细节需要注意:当扫描跨过π角度时要做特殊处理,否则会导致时间戳跳变。我的解决方案是:
if (!halfPassed) { if (ori < cloudInfo.startOrientation - M_PI/2) { ori += 2*M_PI; } else if (ori > cloudInfo.startOrientation + M_PI*3/2) { ori -= 2*M_PI; } }2.3 轨迹输出格式转换
为了用EVO评估,需要将位姿输出为TUM格式。这里涉及坐标系转换:
Eigen::Matrix<double, 4, 4> cali_paremeter; cali_paremeter << 2.347736981471e-04, -9.999441545438e-01, -1.056347781105e-02, -2.796816941295e-03, 1.044940741659e-02, 1.056535364138e-02, -9.998895741176e-01, -7.510879138296e-02, 9.999453885620e-01, 1.243653783865e-04, 1.045130299567e-02, -2.721327964059e-01, 0, 0, 0, 1; Eigen::Matrix<double, 4, 4> myloam_pose_f = cali_paremeter * mylio_pose * cali_paremeter.inverse();这个变换矩阵是将结果转换到左相机坐标系,与KITTI真值保持一致。输出时建议使用科学计数法保证精度:
pose2.setf(std::ios::scientific, std::ios::floatfield);3. EVO精度评估实战
EVO是SLAM评估的神器,但要用好它需要掌握一些技巧。我整理了最常用的四种评估模式及其解读方法。
3.1 APE绝对轨迹误差分析
APE反映整体轨迹精度,我的常用命令:
evo_ape tum kitti_00_gt.txt lio_sam_00.txt -r trans_part --align \ --plot --plot_mode xz --save_results results/ape.zip关键参数说明:
-r trans_part:只评估平移部分(旋转误差单独评估)--align:先进行Umeyama对齐--plot_mode xz:选择最能反映SLAM性能的xz平面
输出结果中要重点关注:
max: 3.214192 mean: 1.082736 median: 0.945201 min: 0.012345 rmse: 1.214587我习惯用rmse作为主要指标,当max值异常大时,可能是某些帧出现了严重漂移。
3.2 RPE相对位姿误差
RPE反映局部一致性,对激光SLAM更重要:
evo_rpe tum kitti_00_gt.txt lio_sam_00.txt -r trans_part -d 10 -u m \ --plot --save_results results/rpe.zip这里-d 10表示以10米为间隔计算相对位姿变化,-u m指定单位为米。好的激光SLAM在10米间隔下的RPE通常应该小于1%。
3.3 多算法对比技巧
用evo_res可以方便地比较多个结果:
evo_res results/*.zip -p --save_table results/compare.csv表格输出包含所有关键指标,我经常用这个功能比较不同参数配置的效果。加--save_table可以导出为CSV,方便做进一步分析。
3.4 轨迹可视化要点
轨迹可视化时容易犯的错误是坐标系不统一:
evo_traj tum lio_sam_00.txt -r kitti_00_gt.txt -a -p \ --plot_mode xz --correct_scale--correct_scale确保三个轴比例一致,避免图形变形。当轨迹很大时(如KITTI 00序列),建议用--n_to_align 100只对齐前100帧,加快处理速度。
4. 实战经验与调优建议
经过多次实验,我总结出几个提升LIO-SAM在KITTI上表现的技巧。
4.1 参数调优关键点
修改params.yaml中这几个参数效果最明显:
pointCloudMinRange: 5.0 # KITTI场景较大,适当提高 pointCloudMaxRange: 100.0 mapResolution: 0.4 # 平衡精度和计算量IMU参数需要特别注意:
imuAccNoise: 1e-2 imuGyrNoise: 1e-3 imuAccBiasN: 1e-4 imuGyrBiasN: 1e-5KITTI的IMU噪声较大,适当调高噪声参数反而能提升效果。
4.2 常见问题解决
遇到过最棘手的问题是点云抖动,解决方案是:
- 检查ring计算是否正确
- 调整scanRegistration中的featureExtraction参数
- 增加imuHistorySize到1000
另一个典型问题是轨迹漂移,我通常从三个方面排查:
- IMU-Camera外参是否准确
- 点云去畸变是否充分
- 回环检测是否生效
4.3 性能优化技巧
在低配设备上运行可以:
- 降低laserCloudStackNum到2
- 关闭visualizeCloud
- 使用ROS的compressed传输
对于长时间序列(如KITTI 00),建议修改:
// 增加关键帧选择间隔 keyframeMeterGap = 10.0; keyframeDegGap = 30.0;记得在评估时要把这些调整考虑进去,不同的参数设置会导致EVO结果有显著差异。我通常会在README中记录每次实验的具体参数,方便结果复现和对比。