????????LIO-SAM是一个多传感器融合的紧耦合SLAM框架,融合的传感器类型有雷达、IMU和GPS,其中雷达和IMU在LIO-SAM框架中必须使用的。LIO-SAM的优化策略采用了GTSAM库,GTSAM库采用了因子图的优化方法,其提供了一些列C++的外部接口,以便用户方便传入参数等进行优化。特别的是GTSAM库专门单独设计关于IMU计算与优化的接口。
????????IMU预积分模块在LIO-SAM源码中写在了imuPreintegration.cpp文件中,其中预积分模块的功能使用class IMUPreintegration来实现,IMUPreintegration类中构造函数中最主要的两个部分分别是imu的回调函数imuHandler和odom的回调函数odometryHandler。
在odometryHandler回调函数中主要进行了imu数据和lidar的里程计数据联合进行因子图优化的操作。
// 上面imu预积分的结果
const gtsam::PreintegratedImuMeasurements &preint_imu = dynamic_cast<const gtsam::PreintegratedImuMeasurements &>(*imuIntegratorOpt_);
// 参数:前一帧位姿,前一帧速度,当前帧位姿,当前帧速度,前一帧偏置,预计分量 //?:此处的当前帧位姿和当前帧速度是哪里得到的?此处是否是待求量?
gtsam::ImuFactor imu_factor(X(key - 1), V(key - 1), X(key), V(key), B(key - 1), preint_imu);
graphFactors.add(imu_factor);
graphFactors.add(gtsam::BetweenFactor<gtsam::imuBias::ConstantBias>(B(key - 1), B(key), gtsam::imuBias::ConstantBias(),
gtsam::noiseModel::Diagonal::Sigmas(sqrt(imuIntegratorOpt_->deltaTij()) * noiseModelBetweenBias)));
gtsam::Pose3 curPose = lidarPose.compose(lidar2Imu);
gtsam::PriorFactor<gtsam::Pose3> pose_factor(X(key), curPose, degenerate ? correctionNoise2 : correctionNoise);
graphFactors.add(pose_factor);
// 用前一帧的状态、偏置,施加imu预计分量,得到当前帧的状态 // note: 前一帧的状态是经过上一次优化后的结果
gtsam::NavState propState_ = imuIntegratorOpt_->predict(prevState_, prevBias_);
graphValues.insert(X(key), propState_.pose());
graphValues.insert(V(key), propState_.v());
graphValues.insert(B(key), prevBias_);
optimizer.update(graphFactors, graphValues);
optimizer.update();
graphFactors.resize(0);
graphValues.clear();
// 优化结果
gtsam::Values result = optimizer.calculateEstimate();
注意:?每优化完成一次后,就会清空因子图和变量,优化器是每100帧重置一次。因此每次向优化器内添加的因子图和变量是一一对应的。
// 更新当前帧位姿、速度
prevPose_ = result.at<gtsam::Pose3>(X(key));
prevVel_ = result.at<gtsam::Vector3>(V(key));
// 更新当前帧状态
prevState_ = gtsam::NavState(prevPose_, prevVel_);
// 更新当前帧imu偏置
prevBias_ = result.at<gtsam::imuBias::ConstantBias>(B(key));
imuIntegratorOpt_->resetIntegrationAndSetBias(prevBias_);
????????这里用一张示意图来表达,这一部操作最主要的原因是:imu接受数据的频率大于odom里程计的数据,因此每来一个odom数据,队列中已经有多个imu数据,而因子图优化的频率是按照odom里程计的频率来进行的,因此如果想要得到每一个imu数据时刻的位姿估计就要以最近的odom时刻的位姿为初始值,通过每个imu数据时刻的预积分进行位姿的传播。
效果展示:此处一小段粉红色的轨迹就是通过经过因子图优化后的重传播(IMU预积分)预测出的轨迹,前面蓝色的轨迹是因子图优化得到的轨迹。