LI-Init源码学习笔记

在这里插入图片描述

LI-Init学习笔记

一、LiDAR里程计

1、匀速运动模型

TODO

2、LiDAR运动补偿

TODO

二、初始化计算

1、数据激活程度评估

bool LI_Init::data_sufficiency_assess(MatrixXd &Jacobian_rot, int &frame_num, V3D &lidar_omg, int &orig_odom_freq,
                                      int &cut_frame_num) {
    //Calculation of Rotation Jacobian
    // 计算旋转雅可比矩阵
    M3D lidar_omg_skew;
    lidar_omg_skew << SKEW_SYM_MATRX(lidar_omg);
    Jacobian_rot.block<3, 3>(3 * frame_num, 0) = lidar_omg_skew;
    bool data_sufficient = false;

    //Give a Data Appraisal every second
    // 每秒进行一次数据评估
    if (frame_num % (orig_odom_freq * cut_frame_num) == 0) {
        /// 计算信息矩阵(协方差矩阵)
        M3D Hessian_rot = Jacobian_rot.transpose() * Jacobian_rot;
        /// 求解信息矩阵的特征值和特征向量
        EigenSolver<M3D> es(Hessian_rot);
        V3D EigenValue = es.eigenvalues().real();
        M3D EigenVec_mat = es.eigenvectors().real();

        M3D EigenMatCwise = EigenVec_mat.cwiseProduct(EigenVec_mat);/// 逐元素求平方
        /// 提取三个特征向量的平方
        std::vector<double> EigenMat_1_col{EigenMatCwise(0, 0), EigenMatCwise(1, 0), EigenMatCwise(2, 0)};
        std::vector<double> EigenMat_2_col{EigenMatCwise(0, 1), EigenMatCwise(1, 1), EigenMatCwise(2, 1)};
        std::vector<double> EigenMat_3_col{EigenMatCwise(0, 2), EigenMatCwise(1, 2), EigenMatCwise(2, 2)};

        /// 找到最大值所在位置
        int maxPos[3] = {0};
        maxPos[0] = max_element(EigenMat_1_col.begin(), EigenMat_1_col.end()) - EigenMat_1_col.begin();
        maxPos[1] = max_element(EigenMat_2_col.begin(), EigenMat_2_col.end()) - EigenMat_2_col.begin();
        maxPos[2] = max_element(EigenMat_3_col.begin(), EigenMat_3_col.end()) - EigenMat_3_col.begin();

        /// 根据累积长度对特征值进行缩放,判断数据是否足够
        V3D Scaled_Eigen = EigenValue / data_accum_length;   //the larger data_accum_length is, the more data is needed

        V3D Rot_percent(Scaled_Eigen[1] * Scaled_Eigen[2], /// 第二轴和第三轴叉乘得到第一轴的激活程度
                        Scaled_Eigen[0] * Scaled_Eigen[2], /// 第一轴和第三轴叉乘得到第二轴的激活程度
                        Scaled_Eigen[0] * Scaled_Eigen[1]);/// 第一轴和第二轴叉乘得到第三轴的激活程度

        V3D Rot_percent_scaled(Rot_percent[0] < 0.99 ? Rot_percent[0] : 1,
                               Rot_percent[1] < 0.99 ? Rot_percent[1] : 1,
                               Rot_percent[2] < 0.99 ? Rot_percent[2] : 1);

        int axis[3];
        axis[2] = max_element(maxPos, maxPos + 3) - maxPos;
        axis[0] = min_element(maxPos, maxPos + 3) - maxPos;
        axis[1] = 3 - (axis[0] + axis[2]);

        /// 打印各方向数据激活进度
        clear(); //clear the screen
        printf("\033[3A\r");
        printProgress(Rot_percent_scaled[axis[0]], 88);
        printProgress(Rot_percent_scaled[axis[1]], 89);
        printProgress(Rot_percent_scaled[axis[2]], 90);
        fflush(stdout);

        /// 判断数据是否足够
        if (Rot_percent[0] > 0.99 && Rot_percent[1] > 0.99 && Rot_percent[2] > 0.99) {
            printf(BOLDCYAN "[Initialization] Data accumulation finished, Lidar IMU initialization begins.\n\n" RESET);
            printf(BOLDBLUE"============================================================ \n\n" RESET);
            data_sufficient = true;
        }
    }
    if (data_sufficient)
        return true;
    else
        return false;
}

2、数据预处理

(1)imu数据下采样并插值对齐Lidar状态数据
/**
 * @brief 对IMU状态数据进行下采样及插值。
 * @param param1 当前帧lidar结束时间。
 * @return 返回值的描述。
 * @function 1 剔除当前帧三秒前的数据;2 对加速度进行均值滤波; 3 反距离权重插值。
 */
void LI_Init::downsample_interpolate_IMU(const double &move_start_time) {

    /// 剔除当前帧三秒前的数据
    while (IMU_state_group_ALL.front().timeStamp < move_start_time - 3.0)
        IMU_state_group_ALL.pop_front();
    while (Lidar_state_group.front().timeStamp < move_start_time - 3.0)
        Lidar_state_group.pop_front();

    /// Original IMU measurements
    /// 将IMU_state_group_ALL容器中除最后一个元素外的所有元素,赋值给IMU_states_all_origin容器
    deque<CalibState> IMU_states_all_origin;
    IMU_states_all_origin.assign(IMU_state_group_ALL.begin(), IMU_state_group_ALL.end() - 1);

    /// Mean filter to attenuate noise
    /// 对加速度进行滑动窗口均值滤波,窗口尺寸为mean_filt_size=2
    int mean_filt_size = 2;
    for (int i = mean_filt_size; i < IMU_state_group_ALL.size() - mean_filt_size; i++) {
        V3D acc_real = Zero3d;
        for (int k = -mean_filt_size; k < mean_filt_size + 1; k++)
            acc_real += (IMU_states_all_origin[i + k].linear_acc - acc_real) / (k + mean_filt_size + 1);
        IMU_state_group_ALL[i].linear_acc = acc_real;
    }

    /// Down-sample and interpolation,Fig.4 in the paper
    /// 下采样及插值,反距离权重插值
    for (int i = 0; i < Lidar_state_group.size(); i++) {
        for (int j = 1; j < IMU_state_group_ALL.size(); j++) {
            if (IMU_state_group_ALL[j - 1].timeStamp <= Lidar_state_group[i].timeStamp
                && IMU_state_group_ALL[j].timeStamp > Lidar_state_group[i].timeStamp) {
                CalibState IMU_state_interpolation;
                double delta_t = IMU_state_group_ALL[j].timeStamp - IMU_state_group_ALL[j - 1].timeStamp;
                double delta_t_right = IMU_state_group_ALL[j].timeStamp - Lidar_state_group[i].timeStamp;
                double s = delta_t_right / delta_t;/// 反距离权重
                /// 权重插值
                IMU_state_interpolation.ang_vel = s * IMU_state_group_ALL[j - 1].ang_vel +
                                                  (1 - s) * IMU_state_group_ALL[j].ang_vel;
                IMU_state_interpolation.linear_acc = s * IMU_state_group_ALL[j - 1].linear_acc +
                                                     (1 - s) * IMU_state_group_ALL[j].linear_acc;
                /// 将插值后的数据压入容器中
                push_IMU_CalibState(IMU_state_interpolation.ang_vel, IMU_state_interpolation.linear_acc,
                                    Lidar_state_group[i].timeStamp);
                break;
            }
        }
    }
}
(2)IMU时间戳补偿
void LI_Init::IMU_time_compensate(const double &lag_time, const bool &is_discard) {
    /// 如果is_discard为true,则丢弃前10个Lidar估计值和对应的IMU测量值,以处理长时间间隔带来的误差。
    if (is_discard) {
        //Discard first 10 Lidar estimations and corresponding IMU measurements due to long time interval
        int i = 0;
        while (i < 10) {
            Lidar_state_group.pop_front();
            IMU_state_group.pop_front();
            i++;
        }
    }
    /// 遍历IMU状态组,将除最后一个元素外的每个元素的时间戳减去lag_time,完成粗标定后是lag_time_1
    auto it_IMU_state = IMU_state_group.begin();
    for (; it_IMU_state != IMU_state_group.end() - 1; it_IMU_state++) {
        it_IMU_state->timeStamp = it_IMU_state->timeStamp - lag_time;
    }
    /// 移除Lidar状态组和IMU状态组中时间戳不匹配的元素,
    /// 确保Lidar状态组的第一个元素时间戳小于或等于IMU状态组的第一个元素时间戳,
    /// 且Lidar状态组的第一个元素时间戳大于或等于IMU状态组的第二个元素时间戳。
    while (Lidar_state_group.front().timeStamp < IMU_state_group.front().timeStamp)
        Lidar_state_group.pop_front();
    while (Lidar_state_group.front().timeStamp > IMU_state_group[1].timeStamp)
        IMU_state_group.pop_front();

    //Align the size of two sequences
    /// 对Lidar状态组和IMU状态组进行大小对齐,
    /// 若IMU状态组大小大于Lidar状态组大小,则移除IMU状态组的尾部元素;
    /// 若IMU状态组大小小于Lidar状态组大小,则移除Lidar状态组的尾部元素。
    /// 这样保证两个状态组的大小相等,方便后续处理。
    while (IMU_state_group.size() > Lidar_state_group.size())
        IMU_state_group.pop_back();
    while (IMU_state_group.size() < Lidar_state_group.size())
        Lidar_state_group.pop_back();
}
(3)数据滤波(零相位低通滤波)
/**
 * @brief 对数据进行零相位滤波处理。
 * @param param1 滤波前数据。
 * @param param2 滤波后数据。
 * @return 返回值的描述。
 * @function 功能。
 */
void LI_Init::zero_phase_filt(const deque<CalibState> &signal_in, deque<CalibState> &signal_out) {
    deque<CalibState> sig_out1;
    Butter_filt(signal_in, sig_out1);

    deque<CalibState> sig_rev(sig_out1);
    /// 反转元素
    reverse(sig_rev.begin(), sig_rev.end()); //Reverse the elements

    Butter_filt(sig_rev, signal_out);
    reverse(signal_out.begin(), signal_out.end()); //Reverse the elements
}


/// 该函数是一个用于实现双向Butterworth滤波器的函数。它通过输入一个信号(deque<CalibState>类型),输出一个经过滤波处理的信号(也是deque<CalibState>类型)。
/// 首先,函数创建了一个Butterworth滤波器对象(butter)。
/// 接下来,函数计算了需要向前和向后扩展原始信号的样本数(extend_num),以便进行滤波处理。
/// 然后,函数使用这些样本数来从原始信号中提取前缀和后缀,并将它们存储在extend_front和extend_back两个deque中。
/// 接着,函数将原始信号与前后扩展的信号合并为一个新信号(sig_extended)。
/// 在完成信号扩展后,函数使用Butterworth滤波器的系数对新信号进行滤波处理,将结果存储在sig_out中。
/// 最后,函数将滤波后的信号(不包括前后扩展的部分)复制到输出信号(signal_out)中,并返回。
/// 该函数的主要作用是使用Butterworth滤波器对信号进行滤波处理,滤波器的类型和参数由Butterworth对象决定。
void LI_Init::Butter_filt(const deque<CalibState> &signal_in, deque<CalibState> &signal_out) {
    LI_Init::Butterworth butter;
    butter.extend_num = 10 * (butter.Coeff_size - 1);
    auto it_front = signal_in.begin() + butter.extend_num;
    auto it_back = signal_in.end() - 1 - butter.extend_num;

    deque<CalibState> extend_front;
    deque<CalibState> extend_back;

    for (int idx = 0; idx < butter.extend_num; idx++) {
        extend_front.push_back(*it_front);
        extend_back.push_front(*it_back);
        it_front--;
        it_back++;
    }

    deque<CalibState> sig_extended(signal_in);
    while (!extend_front.empty()) {
        sig_extended.push_front(extend_front.back());
        extend_front.pop_back();
    }
    while (!extend_back.empty()) {
        sig_extended.push_back(extend_back.front());
        extend_back.pop_front();
    }

    deque<CalibState> sig_out(sig_extended);
    //One-direction Butterworth filter Starts (all states)
    for (int i = butter.Coeff_size; i < sig_extended.size() - butter.extend_num; i++) {
        CalibState temp_state;
        for (int j = 0; j < butter.Coeff_size; j++) {
            auto it_sig_ext = *(sig_extended.begin() + i - j);
            temp_state += it_sig_ext * butter.Coeff_b[j];
        }
        for (int jj = 1; jj < butter.Coeff_size; jj++) {
            auto it_sig_out = *(sig_out.begin() + i - jj);
            temp_state -= it_sig_out * butter.Coeff_a[jj];
        }
        sig_out[i] = temp_state;
    }

    for (auto it = sig_out.begin() + butter.extend_num; it != sig_out.end() - butter.extend_num; it++) {
        signal_out.push_back(*it);
    }
}

/**
 * @brief 切割序列尾部
 *
 * 此函数用于调整和对齐Lidar状态和IMU状态两个序列的尾部,确保它们在时间上匹配并保持相对同步。
 * 该函数首先移除最近的20个Lidar和IMU状态,然后根据时间戳调整两个序列的长度,使其相等。
 */

void LI_Init::cut_sequence_tail() {
    // 移除最近的20个Lidar和IMU状态项
    for (int i = 0; i < 20; ++i) {
        Lidar_state_group.pop_back();
        IMU_state_group.pop_back();
    }

    // 移除Lidar序列中时间戳早于IMU序列最早时间戳的项
    while (Lidar_state_group.front().timeStamp < IMU_state_group.front().timeStamp)
        Lidar_state_group.pop_front();

    // 移除IMU序列中时间戳早于Lidar序列第二个时间戳的项
    while (Lidar_state_group.front().timeStamp > IMU_state_group[1].timeStamp)
        IMU_state_group.pop_front();

    // 对齐两个序列的长度,确保它们在数量上相等
    while (IMU_state_group.size() > Lidar_state_group.size())
        IMU_state_group.pop_back();
    while (IMU_state_group.size() < Lidar_state_group.size())
        Lidar_state_group.pop_back();
}

3、最大互相关法时差粗标定

/**
 * @brief 最大互相关法时差粗标定。
 * @param param1 lidar里程计频率。
 * @return 返回值的描述。
 * @function 通过计算每一个步长的互相关值,选取最大的作为时差。
 */
void LI_Init::xcorr_temporal_init(const double &odom_freq) {
    int N = IMU_state_group.size();
    //Calculate mean value of IMU and LiDAR angular velocity
    /// 计算平均角速度
    double mean_IMU_ang_vel = 0, mean_LiDAR_ang_vel = 0;
    for (int i = 0; i < N; i++) {
        mean_IMU_ang_vel += (IMU_state_group[i].ang_vel.norm() - mean_IMU_ang_vel) / (i + 1);
        mean_LiDAR_ang_vel += (Lidar_state_group[i].ang_vel.norm() - mean_LiDAR_ang_vel) / (i + 1);
    }

    //Calculate zero-centered cross correlation
    double max_corr = -DBL_MAX;
    for (int lag = -N + 1; lag < N; lag++) {
        double corr = 0;
        int cnt = 0;
        /// 计算在偏移步长为lag时的互相关值
        for (int i = 0; i < N; i++) {
            int j = i + lag;
            if (j < 0 || j > N - 1)
                continue;
            else {
                cnt++;
                /// 零中心互相关量
                corr += (IMU_state_group[i].ang_vel.norm() - mean_IMU_ang_vel) *
                        (Lidar_state_group[j].ang_vel.norm() - mean_LiDAR_ang_vel);  // Zero-centered cross correlation
            }
        }

        /// 获取最大互相关值
        if (corr > max_corr) {
            max_corr = corr;
            lag_IMU_wtr_Lidar = -lag;
        }
    }

    time_lag_1 = lag_IMU_wtr_Lidar / odom_freq;
    cout << "Max Cross-correlation: IMU lag wtr Lidar : " << -lag_IMU_wtr_Lidar << endl;
}

粗标定时差后利用该时差补偿IMU数据

4、差分计算

中心差分计算LiDAR的角加速度与线加速度,IMU的角加速度

/**
 * @brief 计算IMU状态组中每个元素的角加速度,lidar状态组中每个元素的角加速度和线加速度。
 * @param param1 参数1的描述。
 * @param param2 参数2的描述。
 * @return 返回值的描述。
 * @function 功能。
 */
void LI_Init::central_diff() {
    /// 通过中心差分法计算imu的角加速度,前后两个元素的角速度差除以时间差
    auto it_IMU_state = IMU_state_group.begin() + 1;
    for (; it_IMU_state != IMU_state_group.end() - 2; it_IMU_state++) {
        auto last_imu = it_IMU_state - 1;
        auto next_imu = it_IMU_state + 1;
        double dt_imu = next_imu->timeStamp - last_imu->timeStamp;
        it_IMU_state->ang_acc =
                (next_imu->ang_vel - last_imu->ang_vel) / dt_imu;
        fout_IMU_meas << setprecision(12)
                      << it_IMU_state->ang_vel.transpose() << " "
                      << it_IMU_state->ang_vel.norm() << " "
                      << it_IMU_state->linear_acc.transpose() << " "
                      << it_IMU_state->ang_acc.transpose() << " "
                      << it_IMU_state->timeStamp << endl;
    }

    /// 利用中心差分法计算lidar状态组的角加速度和线加速度
    auto it_Lidar_state = Lidar_state_group.begin() + 1;
    for (; it_Lidar_state != Lidar_state_group.end() - 2; it_Lidar_state++) {
        auto last_lidar = it_Lidar_state - 1;
        auto next_lidar = it_Lidar_state + 1;
        double dt_lidar = next_lidar->timeStamp - last_lidar->timeStamp;
        it_Lidar_state->ang_acc =
                (next_lidar->ang_vel - last_lidar->ang_vel) / dt_lidar;
        it_Lidar_state->linear_acc =
                (next_lidar->linear_vel - last_lidar->linear_vel) / dt_lidar;
        fout_LiDAR_meas << setprecision(12)
                        << it_Lidar_state->ang_vel.transpose() << " "
                        << it_Lidar_state->ang_vel.norm()<< " "
                        <<(it_Lidar_state->linear_acc - STD_GRAV).transpose() << " "
                        << it_Lidar_state->ang_acc.transpose()
                        << " " << it_Lidar_state->timeStamp << endl;
    }
}

5、对角加速度和线加速度滤波

/*** 第二次数据滤波,对角加速度和线加速度进行滤波 ***/
    deque<CalibState> IMU_after_2nd_zero_phase;
    deque<CalibState> Lidar_after_2nd_zero_phase;
    zero_phase_filt(get_IMU_state(), IMU_after_2nd_zero_phase);
    zero_phase_filt(get_Lidar_state(), Lidar_after_2nd_zero_phase);
    set_states_2nd_filter(IMU_after_2nd_zero_phase, Lidar_after_2nd_zero_phase);

6、参数解算

/// 求解旋转外参
    /// 只求解旋转外参,只考虑最小化v=R*omga_lidar-omga_imu
    solve_Rotation_only();
    /// 求解旋转外参、陀螺仪偏置
    /// 将上一步中计算的旋转外参作为初始值,求解旋转外参、陀螺仪偏置、时间差
    solve_Rot_bias_gyro(timediff_imu_wrt_lidar);

    /// 对IMU线加速度进行插值和lidar数据对齐
    acc_interpolate();

    /// 求解平移外参、加速度偏置、重力方向
    solve_trans_biasacc_grav();
(1)初始旋转外参求解
/// 求解旋转外参
void LI_Init::solve_Rotation_only() {
    double R_LI_quat[4];
    R_LI_quat[0] = 1;
    R_LI_quat[1] = 0;
    R_LI_quat[2] = 0;
    R_LI_quat[3] = 0;

    ceres::Manifold *quatParam = new ceres::EigenQuaternionManifold();
    ceres::Problem problem_rot;
    problem_rot.AddParameterBlock(R_LI_quat, 4, quatParam);

    for (int i = 0; i < IMU_state_group.size(); i++) {
        M3D Lidar_angvel_skew;
        Lidar_angvel_skew << SKEW_SYM_MATRX(Lidar_state_group[i].ang_vel);
        problem_rot.AddResidualBlock(Angular_Vel_Cost_only_Rot::Create(IMU_state_group[i].ang_vel, Lidar_state_group[i].ang_vel),
                                     nullptr,
                                     R_LI_quat);
    }
    ceres::Solver::Options options_quat;
    ceres::Solver::Summary summary_quat;
    ceres::Solve(options_quat, &problem_rot, &summary_quat);
    Eigen::Quaterniond q_LI(R_LI_quat[0], R_LI_quat[1], R_LI_quat[2], R_LI_quat[3]);
    Rot_Lidar_wrt_IMU = q_LI.matrix();
}
///
struct Angular_Vel_Cost_only_Rot {
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    Angular_Vel_Cost_only_Rot(V3D IMU_ang_vel_, V3D Lidar_ang_vel_) :
            IMU_ang_vel(IMU_ang_vel_), Lidar_ang_vel(Lidar_ang_vel_) {}

    template<typename T>
    bool operator()(const T *q, T *residual) const {
        Eigen::Matrix<T, 3, 1> IMU_ang_vel_T = IMU_ang_vel.cast<T>();
        Eigen::Matrix<T, 3, 1> Lidar_ang_vel_T = Lidar_ang_vel.cast<T>();
        Eigen::Quaternion<T> q_LI{q[0], q[1], q[2], q[3]};
        Eigen::Matrix<T, 3, 3> R_LI = q_LI.toRotationMatrix();  //Rotation
        Eigen::Matrix<T, 3, 1> resi = R_LI * Lidar_ang_vel_T - IMU_ang_vel_T;
        residual[0] = resi[0];
        residual[1] = resi[1];
        residual[2] = resi[2];
        return true;
    }

    static ceres::CostFunction *Create(const V3D IMU_ang_vel_, const V3D Lidar_ang_vel_) {
        return (new ceres::AutoDiffCostFunction<Angular_Vel_Cost_only_Rot, 3, 4>(
                new Angular_Vel_Cost_only_Rot(IMU_ang_vel_, Lidar_ang_vel_)));
    }

    V3D IMU_ang_vel;
    V3D Lidar_ang_vel;
};
(2)进一步求解旋转外参、陀螺偏置、时间差
/// 求解旋转外参、陀螺偏置、时间差
void LI_Init::solve_Rot_bias_gyro(double &timediff_imu_wrt_lidar) {
    /// 初始旋转外参
    Eigen::Quaterniond quat(Rot_Lidar_wrt_IMU);
    double R_LI_quat[4];
    R_LI_quat[0] = quat.w();
    R_LI_quat[1] = quat.x();
    R_LI_quat[2] = quat.y();
    R_LI_quat[3] = quat.z();
    /// 初始偏置设为0
    double bias_g[3]; //Initial value of gyro bias
    bias_g[0] = 0;
    bias_g[1] = 0;
    bias_g[2] = 0;
    /// 初始时间差为0
    double time_lag2 = 0; //Second time lag (IMU wtr Lidar)

    /*** Ceres求解 ***/
//    ceres::LocalParameterization *quatParam = new ceres::QuaternionParameterization();
    ceres::Manifold *quatParam = new ceres::EigenQuaternionManifold();
    /// 创建问题实例
    ceres::Problem problem_ang_vel;
    /// 添加参数块
    problem_ang_vel.AddParameterBlock(R_LI_quat, 4, quatParam);
    problem_ang_vel.AddParameterBlock(bias_g, 3);
    /// 设置残差块,Angular_Vel_Cost::Create函数为自定义代价函数
    for (int i = 0; i < IMU_state_group.size(); i++) {
        double deltaT = Lidar_state_group[i].timeStamp - IMU_state_group[i].timeStamp;
        problem_ang_vel.AddResidualBlock(Angular_Vel_Cost::Create(IMU_state_group[i].ang_vel,
                                                                  IMU_state_group[i].ang_acc,
                                                                  Lidar_state_group[i].ang_vel,
                                                                  deltaT),
                                         nullptr,
                                         R_LI_quat,
                                         bias_g,
                                         &time_lag2);
    }
    /// 创建求解器进行求解
    ceres::Solver::Options options_quat;
    ceres::Solver::Summary summary_quat;
    ceres::Solve(options_quat, &problem_ang_vel, &summary_quat);

    /// 获取优化结果(旋转外参、陀螺零偏、时间差)
    Eigen::Quaterniond q_LI(R_LI_quat[0], R_LI_quat[1], R_LI_quat[2], R_LI_quat[3]);
    Rot_Lidar_wrt_IMU = q_LI.matrix(); /// 旋转外参
    V3D euler_angle = RotMtoEuler(q_LI.matrix());
    gyro_bias = V3D(bias_g[0], bias_g[1], bias_g[2]); /// 陀螺零偏

    time_lag_2 = time_lag2;
    time_delay_IMU_wtr_Lidar = time_lag_1 + time_lag_2; /// 时间差
    cout << "Total time delay (IMU wtr Lidar): " << time_delay_IMU_wtr_Lidar + timediff_imu_wrt_lidar << " s" << endl;
    cout << "Using LIO: SUBTRACT this value from IMU timestamp" << endl
         << "           or ADD this value to LiDAR timestamp." << endl <<endl;

    //The second temporal compensation
    /// 第二次时间补偿
    IMU_time_compensate(get_lag_time_2(), false);

    for (int i = 0; i < Lidar_state_group.size(); i++) {
        fout_after_rot << setprecision(12) << (Rot_Lidar_wrt_IMU * Lidar_state_group[i].ang_vel + gyro_bias).transpose()
                       << " " << Lidar_state_group[i].timeStamp << endl;
    }
}

///
struct Angular_Vel_Cost {
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    /**
     * Angular_Vel_Cost 构造函数。
     * @param IMU_ang_vel_ IMU测量的角速度。
     * @param IMU_ang_acc_ IMU测量的角加速度。
     * @param Lidar_ang_vel_ Lidar测量的角速度。
     * @param deltaT_LI_ IMU和Lidar时间戳之间的差值。
     */
    Angular_Vel_Cost(V3D IMU_ang_vel_, V3D IMU_ang_acc_, V3D Lidar_ang_vel_, double deltaT_LI_) :
            IMU_ang_vel(IMU_ang_vel_), IMU_ang_acc(IMU_ang_acc_), Lidar_ang_vel(Lidar_ang_vel_),
            deltaT_LI(deltaT_LI_) {}

    template<typename T>
    bool operator()(const T *q, const T *b_g, const T *t, T *residual) const {
        //Known parameters used for Residual Construction
        Eigen::Matrix<T, 3, 1> IMU_ang_vel_T = IMU_ang_vel.cast<T>();
        Eigen::Matrix<T, 3, 1> IMU_ang_acc_T = IMU_ang_acc.cast<T>();
        Eigen::Matrix<T, 3, 1> Lidar_ang_vel_T = Lidar_ang_vel.cast<T>();
        T deltaT_LI_T{deltaT_LI};

        //Unknown Parameters, needed to be estimated
        Eigen::Quaternion<T> q_LI{q[0], q[1], q[2], q[3]};
        Eigen::Matrix<T, 3, 3> R_LI = q_LI.toRotationMatrix();  //Rotation
        Eigen::Matrix<T, 3, 1> bias_g{b_g[0], b_g[1], b_g[2]};  //Bias of gyroscope
        T td{t[0]};                                             //Time lag (IMU wtr Lidar)

        //Residual
        /// paper func(18)
        Eigen::Matrix<T, 3, 1> resi =
                R_LI * Lidar_ang_vel_T - IMU_ang_vel_T - (deltaT_LI_T + td) * IMU_ang_acc_T + bias_g;
        residual[0] = resi[0];
        residual[1] = resi[1];
        residual[2] = resi[2];
        return true;
    }

    static ceres::CostFunction *
    Create(const V3D IMU_ang_vel_, const V3D IMU_ang_acc_, const V3D Lidar_ang_vel_, const double deltaT_LI_)
    {
        return (new ceres::AutoDiffCostFunction<Angular_Vel_Cost, 3, 4, 3, 1>
                (
                new Angular_Vel_Cost(IMU_ang_vel_, IMU_ang_acc_, Lidar_ang_vel_, deltaT_LI_)
                )
                );
    }

    V3D IMU_ang_vel;
    V3D IMU_ang_acc;
    V3D Lidar_ang_vel;
    double deltaT_LI;
};
(3)对IMU线加速度进行插值和LiDAR状态对齐
void LI_Init::acc_interpolate() {
    //Interpolation to get acc_I(t_L)
    for (int i = 1; i < Lidar_state_group.size() - 1; i++) {
        double deltaT = Lidar_state_group[i].timeStamp - IMU_state_group[i].timeStamp;
        if (deltaT > 0) {
            double DeltaT = IMU_state_group[i + 1].timeStamp - IMU_state_group[i].timeStamp;
            double s = deltaT / DeltaT;
            IMU_state_group[i].linear_acc = s * IMU_state_group[i + 1].linear_acc +
                                            (1 - s) * IMU_state_group[i].linear_acc;
            IMU_state_group[i].timeStamp += deltaT;
        } else {
            double DeltaT = IMU_state_group[i].timeStamp - IMU_state_group[i - 1].timeStamp;
            double s = -deltaT / DeltaT;
            IMU_state_group[i].linear_acc = s * IMU_state_group[i - 1].linear_acc +
                                            (1 - s) * IMU_state_group[i].linear_acc;
            IMU_state_group[i].timeStamp += deltaT;
        }
    }
}
(4)求解平移外参、加速度偏置、重力
/// 求解平移外参、加速度偏置、重力
void LI_Init::solve_trans_biasacc_grav() {
    M3D Rot_Init = Eye3d;
    Rot_Init.diagonal() = V3D(1, 1, 1);
    Eigen::Quaterniond quat(Rot_Init);
    double R_GL0_quat[4];
    R_GL0_quat[0] = quat.w();
    R_GL0_quat[1] = quat.x();
    R_GL0_quat[2] = quat.y();
    R_GL0_quat[3] = quat.z();

    double bias_aL[3]; //Initial value of acc bias
    bias_aL[0] = 0;
    bias_aL[1] = 0;
    bias_aL[2] = 0;

    double Trans_IL[3]; //Initial value of Translation of IL (IMU with respect to Lidar)
    Trans_IL[0] = 0.0;
    Trans_IL[1] = 0.0;
    Trans_IL[2] = 0.0;

//    ceres::LocalParameterization *quatParam = new ceres::QuaternionParameterization();
    ceres::Manifold *quatParam = new ceres::EigenQuaternionManifold();
    ceres::Problem problem_acc;

    problem_acc.AddParameterBlock(R_GL0_quat, 4, quatParam);
    problem_acc.AddParameterBlock(bias_aL, 3);
    problem_acc.AddParameterBlock(Trans_IL, 3);

    //Jacobian of acc_bias, gravity, Translation
    int Jaco_size = 3 * Lidar_state_group.size();
    MatrixXd Jacobian(Jaco_size, 9);
    Jacobian.setZero();

    //Jacobian of Translation
    MatrixXd Jaco_Trans(Jaco_size, 3);
    Jaco_Trans.setZero();

    for (int i = 0; i < IMU_state_group.size(); i++) {
        problem_acc.AddResidualBlock(Linear_acc_Cost::Create(Lidar_state_group[i],
                                                             Rot_Lidar_wrt_IMU,
                                                             IMU_state_group[i].linear_acc),
                                     nullptr,
                                     R_GL0_quat,
                                     bias_aL,
                                     Trans_IL);

        Jacobian.block<3, 3>(3 * i, 0) = -Lidar_state_group[i].rot_end;
        Jacobian.block<3, 3>(3 * i, 3) << SKEW_SYM_MATRX(STD_GRAV);
        M3D omg_skew, angacc_skew;
        omg_skew << SKEW_SYM_MATRX(Lidar_state_group[i].ang_vel);
        angacc_skew << SKEW_SYM_MATRX(Lidar_state_group[i].ang_acc);
        M3D Jaco_trans_i = omg_skew * omg_skew + angacc_skew;
        Jaco_Trans.block<3, 3>(3 * i, 0) = Jaco_trans_i;
        Jacobian.block<3, 3>(3 * i, 6) = Jaco_trans_i;
    }

    for (int index = 0; index < 3; ++index) {
        problem_acc.SetParameterUpperBound(bias_aL, index, 0.01);
        problem_acc.SetParameterLowerBound(bias_aL, index, -0.01);
    }

    ceres::Solver::Options options_acc;
    ceres::Solver::Summary summary_acc;
    ceres::Solve(options_acc, &problem_acc, &summary_acc);


    Eigen::Quaterniond q_GL0(R_GL0_quat[0], R_GL0_quat[1], R_GL0_quat[2], R_GL0_quat[3]);
    Rot_Grav_wrt_Init_Lidar = q_GL0.matrix();
    Grav_L0 = Rot_Grav_wrt_Init_Lidar * STD_GRAV;

    V3D bias_a_Lidar(bias_aL[0], bias_aL[1], bias_aL[2]);
    acc_bias = Rot_Lidar_wrt_IMU * bias_a_Lidar;

    V3D Trans_IL_vec(Trans_IL[0], Trans_IL[1], Trans_IL[2]);
    Trans_Lidar_wrt_IMU = -Rot_Lidar_wrt_IMU * Trans_IL_vec;

    for (int i = 0; i < IMU_state_group.size(); i++) {
        V3D acc_I = Lidar_state_group[i].rot_end * Rot_Lidar_wrt_IMU.transpose() * IMU_state_group[i].linear_acc -
                    Lidar_state_group[i].rot_end * bias_a_Lidar;
        V3D acc_L = Lidar_state_group[i].linear_acc +
                    Lidar_state_group[i].rot_end * Jaco_Trans.block<3, 3>(3 * i, 0) * Trans_IL_vec - Grav_L0;
        fout_acc_cost << setprecision(10) << acc_I.transpose() << " " << acc_L.transpose() << " "
                      << IMU_state_group[i].timeStamp << " " << Lidar_state_group[i].timeStamp << endl;
    }

    M3D Hessian_Trans = Jaco_Trans.transpose() * Jaco_Trans;
    EigenSolver<M3D> es_trans(Hessian_Trans);
    M3D EigenValue_mat_trans = es_trans.pseudoEigenvalueMatrix();
    M3D EigenVec_mat_trans = es_trans.pseudoEigenvectors();

}
///
struct Linear_acc_Cost {
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    Linear_acc_Cost(CalibState LidarState_, M3D R_LI_, V3D IMU_linear_acc_) :
            LidarState(LidarState_), R_LI(R_LI_), IMU_linear_acc(IMU_linear_acc_) {}

    template<typename T>
    bool operator()(const T *q, const T *b_a, const T *trans, T *residual) const {
        //Known parameters used for Residual Construction
        Eigen::Matrix<T, 3, 3> R_LL0_T = LidarState.rot_end.cast<T>();
        Eigen::Matrix<T, 3, 3> R_LI_T_transpose = R_LI.transpose().cast<T>();
        Eigen::Matrix<T, 3, 1> IMU_linear_acc_T = IMU_linear_acc.cast<T>();
        Eigen::Matrix<T, 3, 1> Lidar_linear_acc_T = LidarState.linear_acc.cast<T>();

        //Unknown Parameters, needed to be estimated
        /// 待估计参数:R_GL0、bias_aL、T_IL
        Eigen::Quaternion<T> q_GL0{q[0], q[1], q[2], q[3]};
        Eigen::Matrix<T, 3, 3> R_GL0 = q_GL0.toRotationMatrix();   //Rotation from Gravitational to First Lidar frame
        Eigen::Matrix<T, 3, 1> bias_aL{b_a[0], b_a[1], b_a[2]};    //Bias of Linear acceleration
        Eigen::Matrix<T, 3, 1> T_IL{trans[0], trans[1], trans[2]}; //Translation of I-L (IMU wtr Lidar)

        //Residual Construction
        /// 构造残差
        M3D Lidar_omg_SKEW, Lidar_angacc_SKEW;
        Lidar_omg_SKEW << SKEW_SYM_MATRX(LidarState.ang_vel);
        Lidar_angacc_SKEW << SKEW_SYM_MATRX(LidarState.ang_acc);
        M3D Jacob_trans = Lidar_omg_SKEW * Lidar_omg_SKEW + Lidar_angacc_SKEW;
        Eigen::Matrix<T, 3, 3> Jacob_trans_T = Jacob_trans.cast<T>();

        Eigen::Matrix<T, 3, 1> resi = R_LL0_T * R_LI_T_transpose * IMU_linear_acc_T - R_LL0_T * bias_aL
                                      + R_GL0 * STD_GRAV - Lidar_linear_acc_T - R_LL0_T * Jacob_trans_T * T_IL;

        residual[0] = resi[0];
        residual[1] = resi[1];
        residual[2] = resi[2];
        return true;
    }

    static ceres::CostFunction *Create(const CalibState LidarState_, const M3D R_LI_, const V3D IMU_linear_acc_) {
        return (new ceres::AutoDiffCostFunction<Linear_acc_Cost, 3, 4, 3, 3>(
                new Linear_acc_Cost(LidarState_, R_LI_, IMU_linear_acc_)));
    }

    CalibState LidarState;
    M3D R_LI;
    V3D IMU_linear_acc;
};

三、进一步优化计算

TODO

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值