#pragma once #include #include #include namespace basalt { template class ImuBlock { public: using Scalar = Scalar_; using Vec3 = Eigen::Matrix; using VecX = Eigen::Matrix; using MatX = Eigen::Matrix; ImuBlock(const IntegratedImuMeasurement* meas, const ImuLinData* imu_lin_data, const AbsOrderMap& aom) : imu_meas(meas), imu_lin_data(imu_lin_data), aom(aom) { Jp.resize(POSE_VEL_BIAS_SIZE, 2 * POSE_VEL_BIAS_SIZE); r.resize(POSE_VEL_BIAS_SIZE); } Scalar linearizeImu( const Eigen::aligned_map>& frame_states) { Jp.setZero(); r.setZero(); const int64_t start_t = imu_meas->get_start_t_ns(); const int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = 0; const size_t end_idx = POSE_VEL_BIAS_SIZE; PoseVelBiasStateWithLin start_state = frame_states.at(start_t); PoseVelBiasStateWithLin end_state = frame_states.at(end_t); typename IntegratedImuMeasurement::MatNN d_res_d_start, d_res_d_end; typename IntegratedImuMeasurement::MatN3 d_res_d_bg, d_res_d_ba; typename PoseVelState::VecN res = imu_meas->residual( start_state.getStateLin(), imu_lin_data->g, end_state.getStateLin(), start_state.getStateLin().bias_gyro, start_state.getStateLin().bias_accel, &d_res_d_start, &d_res_d_end, &d_res_d_bg, &d_res_d_ba); if (start_state.isLinearized() || end_state.isLinearized()) { res = imu_meas->residual( start_state.getState(), imu_lin_data->g, end_state.getState(), start_state.getState().bias_gyro, start_state.getState().bias_accel); } // error Scalar imu_error = Scalar(0.5) * (imu_meas->get_sqrt_cov_inv() * res).squaredNorm(); // imu residual linearization Jp.template block<9, 9>(0, start_idx) = imu_meas->get_sqrt_cov_inv() * d_res_d_start; Jp.template block<9, 9>(0, end_idx) = imu_meas->get_sqrt_cov_inv() * d_res_d_end; Jp.template block<9, 3>(0, start_idx + 9) = imu_meas->get_sqrt_cov_inv() * d_res_d_bg; Jp.template block<9, 3>(0, start_idx + 12) = imu_meas->get_sqrt_cov_inv() * d_res_d_ba; r.template segment<9>(0) = imu_meas->get_sqrt_cov_inv() * res; // difference between biases Scalar dt = imu_meas->get_dt_ns() * Scalar(1e-9); Vec3 gyro_bias_weight_dt = imu_lin_data->gyro_bias_weight_sqrt / std::sqrt(dt); Vec3 res_bg = start_state.getState().bias_gyro - end_state.getState().bias_gyro; Jp.template block<3, 3>(9, start_idx + 9) = gyro_bias_weight_dt.asDiagonal(); Jp.template block<3, 3>(9, end_idx + 9) = (-gyro_bias_weight_dt).asDiagonal(); r.template segment<3>(9) += gyro_bias_weight_dt.asDiagonal() * res_bg; Scalar bg_error = Scalar(0.5) * (gyro_bias_weight_dt.asDiagonal() * res_bg).squaredNorm(); Vec3 accel_bias_weight_dt = imu_lin_data->accel_bias_weight_sqrt / std::sqrt(dt); Vec3 res_ba = start_state.getState().bias_accel - end_state.getState().bias_accel; Jp.template block<3, 3>(12, start_idx + 12) = accel_bias_weight_dt.asDiagonal(); Jp.template block<3, 3>(12, end_idx + 12) = (-accel_bias_weight_dt).asDiagonal(); r.template segment<3>(12) += accel_bias_weight_dt.asDiagonal() * res_ba; Scalar ba_error = Scalar(0.5) * (accel_bias_weight_dt.asDiagonal() * res_ba).squaredNorm(); return imu_error + bg_error + ba_error; } void add_dense_Q2Jp_Q2r(MatX& Q2Jp, VecX& Q2r, size_t row_start_idx) const { int64_t start_t = imu_meas->get_start_t_ns(); int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = aom.abs_order_map.at(start_t).first; const size_t end_idx = aom.abs_order_map.at(end_t).first; Q2Jp.template block(row_start_idx, start_idx) += Jp.template topLeftCorner(); Q2Jp.template block(row_start_idx, end_idx) += Jp.template topRightCorner(); Q2r.template segment(row_start_idx) += r; } void add_dense_H_b(DenseAccumulator& accum) const { int64_t start_t = imu_meas->get_start_t_ns(); int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = aom.abs_order_map.at(start_t).first; const size_t end_idx = aom.abs_order_map.at(end_t).first; const MatX H = Jp.transpose() * Jp; const VecX b = Jp.transpose() * r; accum.template addH( start_idx, start_idx, H.template block(0, 0)); accum.template addH( end_idx, start_idx, H.template block( POSE_VEL_BIAS_SIZE, 0)); accum.template addH( start_idx, end_idx, H.template block( 0, POSE_VEL_BIAS_SIZE)); accum.template addH( end_idx, end_idx, H.template block( POSE_VEL_BIAS_SIZE, POSE_VEL_BIAS_SIZE)); accum.template addB( start_idx, b.template segment(0)); accum.template addB( end_idx, b.template segment(POSE_VEL_BIAS_SIZE)); } void scaleJp_cols(const VecX& jacobian_scaling) { int64_t start_t = imu_meas->get_start_t_ns(); int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = aom.abs_order_map.at(start_t).first; const size_t end_idx = aom.abs_order_map.at(end_t).first; Jp.template topLeftCorner() *= jacobian_scaling.template segment(start_idx) .asDiagonal(); Jp.template topRightCorner() *= jacobian_scaling.template segment(end_idx) .asDiagonal(); } void addJp_diag2(VecX& res) const { int64_t start_t = imu_meas->get_start_t_ns(); int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = aom.abs_order_map.at(start_t).first; const size_t end_idx = aom.abs_order_map.at(end_t).first; res.template segment(start_idx) += Jp.template topLeftCorner() .colwise() .squaredNorm(); res.template segment(end_idx) += Jp.template topRightCorner() .colwise() .squaredNorm(); } void backSubstitute(const VecX& pose_inc, Scalar& l_diff) { int64_t start_t = imu_meas->get_start_t_ns(); int64_t end_t = imu_meas->get_start_t_ns() + imu_meas->get_dt_ns(); const size_t start_idx = aom.abs_order_map.at(start_t).first; const size_t end_idx = aom.abs_order_map.at(end_t).first; VecX pose_inc_reduced(2 * POSE_VEL_BIAS_SIZE); pose_inc_reduced.template head() = pose_inc.template segment(start_idx); pose_inc_reduced.template tail() = pose_inc.template segment(end_idx); // We want to compute the model cost change. The model function is // // L(inc) = F(x) + incT JT r + 0.5 incT JT J inc // // and thus the expect decrease in cost for the computed increment is // // l_diff = L(0) - L(inc) // = - incT JT r - 0.5 incT JT J inc. // = - incT JT (r + 0.5 J inc) // = - (J inc)T (r + 0.5 (J inc)) VecX Jinc = Jp * pose_inc_reduced; l_diff -= Jinc.transpose() * (Scalar(0.5) * Jinc + r); } protected: std::array frame_ids; MatX Jp; VecX r; const IntegratedImuMeasurement* imu_meas; const ImuLinData* imu_lin_data; const AbsOrderMap& aom; }; // namespace basalt } // namespace basalt