深入LIO-SAM因子图:拆解GTSAM后端优化与多传感器融合机理
1. 从LOAM到LIO-SAM的算法演进
在SLAM技术发展历程中,LOAM(Lidar Odometry and Mapping)系列算法因其卓越的激光里程计性能而广受关注。然而传统LOAM存在两个显著痛点:一是依赖高精度激光雷达,二是缺乏多传感器深度融合能力。LIO-SAM通过引入因子图框架和IMU预积分技术,实现了三大突破:
- 多源传感器紧耦合:IMU、激光雷达、GPS(可选)数据通过因子图统一优化
- 增量式优化架构:采用iSAM2实现高效增量求解,避免全局优化的计算瓶颈
- 运动畸变补偿:利用IMU高频数据实现激光点云去畸变
关键性能对比:
| 特性 | LOAM | LIO-SAM |
|---|---|---|
| 传感器融合 | 无 | IMU+LiDAR |
| 优化方式 | 帧到帧匹配 | 因子图优化 |
| 计算效率 | O(n²) | O(n) |
| 回环检测 | 无 | 支持 |
| 退化场景鲁棒性 | 较弱 | 较强 |
2. 因子图构建的核心要素
2.1 IMU预积分因子
在imuPreintegration.cpp中,IMU数据通过预积分技术转化为帧间约束因子。核心数学表达:
ΔR_{ij} = ∏_{k=i}^{j-1} Exp((ω_k - b^g_k)Δt) Δv_{ij} = ∑_{k=i}^{j-1} ΔR_{ik}(a_k - b^a_k)Δt Δp_{ij} = ∑_{k=i}^{j-1} [Δv_{ik}Δt + 0.5ΔR_{ik}(a_k - b^a_k)Δt²]关键实现细节:
- 使用
imuIntegratorOpt_处理两帧激光间的IMU数据 - 采用中值积分降低离散化误差
- 偏差(bias)作为状态变量参与优化
2.2 激光里程计因子
mapOptimization.cpp中实现的激光匹配因子包含两类几何约束:
边缘点约束:
// 点到线距离计算 float a012 = sqrt(...); // 叉积模长 float l12 = sqrt(...); // 基线长度 float ld2 = a012 / l12; // 垂直距离平面点约束:
// 平面方程求解 Eigen::Matrix<float,5,3> matA0; Eigen::Matrix<float,5,1> matB0 = -1*Eigen::Matrix<float,5,1>::Ones(); Eigen::Vector3f matX0 = matA0.colPivHouseholderQr().solve(matB0);2.3 因子图结构示例
典型因子图包含以下节点和因子:
graph TD X0 -->|Prior| X0 X0 -->|IMU| X1 X1 -->|Lidar Odom| X2 X2 -->|GPS| X2 X2 -->|Loop Closure| X03. iSAM2增量优化机制
3.1 贝叶树数据结构
iSAM2通过贝叶树(Bayes Tree)实现增量更新:
- 矩阵分解:将Hessian矩阵分解为贝叶树节点
- 部分重线性化:仅更新受影响的变量簇
- 增量QR分解:避免每次迭代的完全分解
关键参数配置:
ISAM2Params parameters; parameters.relinearizeThreshold = 0.1; parameters.relinearizeSkip = 1; isam = new ISAM2(parameters);3.2 协方差估计
通过边际协方差获取位姿不确定性:
poseCovariance = isam->marginalCovariance( isamCurrentEstimate.size()-1);该协方差用于:
- GPS因子权重分配
- 退化场景检测
- 关键帧筛选
4. 多传感器时间对齐策略
4.1 激光-IMU同步
在imageProjection.cpp中实现精确时间对齐:
- IMU数据缓存队列(
imuQueue) - 双指针查找激光扫描起止时刻对应的IMU数据
- 运动补偿公式:
T_{k,i} = T_{k,start}^{-1} * T_{i}^{W} * T_{start}^{W}^{-1} * T_{k}^{W}4.2 关键实现技巧
- IMU坐标系转换:通过
imuConverter统一到激光坐标系 - 双缓存机制:
imuQueOpt用于优化,imuQueImu用于预测 - 零空间处理:当Hessian矩阵出现小特征值时,约束对应方向的更新量
5. 工程实践关键点
5.1 退化场景处理
在LMOptimization函数中实现退化检测:
if (matE.at<float>(0,i) < eignThre[i]) { for (int j=0; j<6; j++) matV2.at<float>(i,j) = 0; isDegenerate = true; }应对策略:
- 冻结退化方向的状态更新
- 增强IMU约束权重
- 触发GPS因子激活
5.2 内存优化技巧
- 滑动窗口管理:保留最近100个关键帧的因子
- 点云降采样:采用体素滤波控制数据量
downSizeFilterCorner.setLeafSize(0.2,0.2,0.2);- 地图缓存:
laserCloudMapContainer自动清理旧数据
6. 性能调优建议
根据实际部署经验,推荐参数调整方向:
实时性优化:
- 降低
surroundingKeyframeSearchRadius减少局部地图规模 - 增大
mappingSurfLeafSize减少平面点数量
- 降低
精度提升:
- 减小
historyKeyframeSearchRadius提高回环检测精度 - 调整
imuAccNoise和imuGyrNoise匹配实际IMU性能
- 减小
鲁棒性增强:
- 适当提高
edgeThreshold和surfThreshold - 启用
z_tollerance约束高度漂移
- 适当提高
实际测试表明,在UrbanNav数据集上,优化后的LIO-SAM可实现:
- 定位误差:<0.3% 轨迹长度
- 内存占用:<1.5GB (1km轨迹)
- 单帧处理时间:<50ms (i7-11800H)