• FAST-LIO(二):程序运行&代码注释



    前言

    论文题目:FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter,FAST-LIO:一种基于紧耦合IKF算法的快速的,鲁棒性的激光雷达惯性里程计。这里主要记录自己阅读代码的笔记。


    数据准备

    相应的数据文件,我放在了百度网盘上,把数据下载下来,放在相应的目录下就可以。
    数据百度网盘链接
    提取码:ob9k

    上面链接给出的数据中,livox avia激光雷达IMU频率为:200Hz,激光雷达的频率为10Hz,也就是一帧数据的时间。

    程序运行

    代码的下载,以及相应依赖库的安装参考:
    安装参考
    程序运行命令:

    roslaunch fast_lio mapping_avia.launch

    roslaunch fast_lio mapping_velodyne.launch

    cd /home/nvidia/ws_fast_lio/src/FAST_LIO/data/

    rosbag play YOUR_DOWNLOADED.bag

    运行livox avia其中一条数据,效果如下:
    在这里插入图片描述
    在这里插入图片描述

    代码注释

    1.laserMapping.cpp

    // This is an advanced implementation of the algorithm described in the
    // following paper:
    //   J. Zhang and S. Singh. LOAM: Lidar Odometry and Mapping in Real-time.
    //     Robotics: Science and Systems Conference (RSS). Berkeley, CA, July 2014.
    
    // Modifier: Livox               dev@livoxtech.com
    
    // Copyright 2013, Ji Zhang, Carnegie Mellon University
    // Further contributions copyright (c) 2016, Southwest Research Institute
    // All rights reserved.
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions are met:
    //
    // 1. Redistributions of source code must retain the above copyright notice,
    //    this list of conditions and the following disclaimer.
    // 2. Redistributions in binary form must reproduce the above copyright notice,
    //    this list of conditions and the following disclaimer in the documentation
    //    and/or other materials provided with the distribution.
    // 3. Neither the name of the copyright holder nor the names of its
    //    contributors may be used to endorse or promote products derived from this
    //    software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    // POSSIBILITY OF SUCH DAMAGE.
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "IMU_Processing.hpp"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "preprocess.h"
    #include 
    
    #define INIT_TIME           (0.1)
    #define LASER_POINT_COV     (0.001)
    #define MAXN                (720000)
    #define PUBFRAME_PERIOD     (20)
    
    // time_sync_en:IMU和雷达不是同一个时间系统时使用
    
    /*** Time Log Variables ***/
    double kdtree_incremental_time = 0.0, kdtree_search_time = 0.0, kdtree_delete_time = 0.0;
    double T1[MAXN], s_plot[MAXN], s_plot2[MAXN], s_plot3[MAXN], s_plot4[MAXN], s_plot5[MAXN], s_plot6[MAXN], s_plot7[MAXN], s_plot8[MAXN], s_plot9[MAXN], s_plot10[MAXN], s_plot11[MAXN];
    double match_time = 0, solve_time = 0, solve_const_H_time = 0;
    int    kdtree_size_st = 0, kdtree_size_end = 0;
    int add_point_size = 0; // ikdtree 新增数目
    int kdtree_delete_counter = 0;
    bool   runtime_pos_log = false, pcd_save_en = false, time_sync_en = false;
    bool extrinsic_est_en = true; // 外参估计开关
    bool path_en = true;
    /**************************/
    
    float res_last[100000] = {0.0};
    float DET_RANGE = 300.0f;
    const float MOV_THRESHOLD = 1.5f;
    
    mutex mtx_buffer;
    condition_variable sig_buffer;
    
    string root_dir = ROOT_DIR;
    string map_file_path, lid_topic, imu_topic;
    
    double res_mean_last = 0.05; // 观测模型中的平均残差
    double total_residual = 0.0; // 观测模型中的残差和
    double last_timestamp_lidar = 0;  // 最新的雷达接收回调时间戳
    double last_timestamp_imu = -1.0; // 最新的imu接收回调时间戳
    double gyr_cov = 0.1, acc_cov = 0.1, b_gyr_cov = 0.0001, b_acc_cov = 0.0001;
    double filter_size_corner_min = 0, filter_size_surf_min = 0, filter_size_map_min = 0, fov_deg = 0;
    double cube_len = 0, HALF_FOV_COS = 0, FOV_DEG = 0, total_distance = 0, lidar_end_time = 0;
    double first_lidar_time = 0.0; // 一帧雷达数据的开始时间戳
    int    effct_feat_num = 0, time_log_counter = 0, scan_count = 0, publish_count = 0;
    int    iterCount = 0, feats_down_size = 0, NUM_MAX_ITERATIONS = 0, laserCloudValidNum = 0, pcd_save_interval = -1, pcd_index = 0;
    bool   point_selected_surf[100000] = {0}; // 有效的特征点
    bool   lidar_pushed = true; // 
    bool flg_first_scan = true; // 第一帧
    bool flg_exit = false, flg_EKF_inited;
    bool   scan_pub_en = false, dense_pub_en = false, scan_body_pub_en = false;
    
    vector<vector<int>>  pointSearchInd_surf; 
    vector<BoxPointType> cub_needrm;
    vector<PointVector>  Nearest_Points; // ??
    vector<double>       extrinT(3, 0.0);
    vector<double>       extrinR(9, 0.0);
    deque<double>                     time_buffer; // 激光雷达数据
    deque<PointCloudXYZI::Ptr>        lidar_buffer; // 雷达数据队列 
    deque<sensor_msgs::Imu::ConstPtr> imu_buffer;   // IMU数据队列(指针形式)
    
    // PointCloudXYZI:点云坐标 + 信号强度形式
    // Ptr:指针形式
    PointCloudXYZI::Ptr featsFromMap(new PointCloudXYZI());
    PointCloudXYZI::Ptr feats_undistort(new PointCloudXYZI());
    PointCloudXYZI::Ptr feats_down_body(new PointCloudXYZI()); // 雷达坐标系
    PointCloudXYZI::Ptr feats_down_world(new PointCloudXYZI());// 世界坐标系
    PointCloudXYZI::Ptr normvec(new PointCloudXYZI(100000, 1));
    PointCloudXYZI::Ptr laserCloudOri(new PointCloudXYZI(100000, 1)); // 雷达滤波后原始数据
    PointCloudXYZI::Ptr corr_normvect(new PointCloudXYZI(100000, 1)); // 存放法向量
    PointCloudXYZI::Ptr _featsArray;
    
    // VoxelGrid:使用体素化网格的方法实现下采样,并保持点云的形状特征
    pcl::VoxelGrid<PointType> downSizeFilterSurf;
    pcl::VoxelGrid<PointType> downSizeFilterMap;
    
    KD_TREE<PointType> ikdtree;
    
    V3F XAxisPoint_body(LIDAR_SP_LEN, 0.0, 0.0);
    V3F XAxisPoint_world(LIDAR_SP_LEN, 0.0, 0.0);
    V3D euler_cur;
    V3D position_last(Zero3d);
    V3D Lidar_T_wrt_IMU(Zero3d); // 雷达和IMU之间的杆臂
    M3D Lidar_R_wrt_IMU(Eye3d);  // 雷达和IMU之间的安装角(转换矩阵形式)
    
    /*** EKF inputs and output ***/
    MeasureGroup Measures; // 激光雷达,IMU数据
    // state_ikfom:22维
    // 系统噪声的维数:12
    // input_ikfom:6维
    esekfom::esekf<state_ikfom, 12, input_ikfom> kf;
    state_ikfom state_point; // 状态向量(反馈之后)
    vect3 pos_lid; // 雷达位置(导航系)
    
    nav_msgs::Path path;
    nav_msgs::Odometry odomAftMapped; // 里程计消息
    geometry_msgs::Quaternion geoQuat;
    geometry_msgs::PoseStamped msg_body_pose;
    
    shared_ptr<Preprocess> p_pre(new Preprocess());
    shared_ptr<ImuProcess> p_imu(new ImuProcess()); // 类指针
    
    void SigHandle(int sig)
    {
        flg_exit = true;
        ROS_WARN("catch sig %d", sig);
        sig_buffer.notify_all();
    }
    
    inline void dump_lio_state_to_log(FILE *fp)  
    {
        V3D rot_ang(Log(state_point.rot.toRotationMatrix()));
        fprintf(fp, "%lf ", Measures.lidar_beg_time - first_lidar_time);
        fprintf(fp, "%lf %lf %lf ", rot_ang(0), rot_ang(1), rot_ang(2));                   // Angle
        fprintf(fp, "%lf %lf %lf ", state_point.pos(0), state_point.pos(1), state_point.pos(2)); // Pos  
        fprintf(fp, "%lf %lf %lf ", 0.0, 0.0, 0.0);                                        // omega  
        fprintf(fp, "%lf %lf %lf ", state_point.vel(0), state_point.vel(1), state_point.vel(2)); // Vel  
        fprintf(fp, "%lf %lf %lf ", 0.0, 0.0, 0.0);                                        // Acc  
        fprintf(fp, "%lf %lf %lf ", state_point.bg(0), state_point.bg(1), state_point.bg(2));    // Bias_g  
        fprintf(fp, "%lf %lf %lf ", state_point.ba(0), state_point.ba(1), state_point.ba(2));    // Bias_a  
        fprintf(fp, "%lf %lf %lf ", state_point.grav[0], state_point.grav[1], state_point.grav[2]); // Bias_a  
        fprintf(fp, "\r\n");  
        fflush(fp);
    }
    
    // 函数功能:激光雷达坐标点转到世界坐标系
    void pointBodyToWorld_ikfom(PointType const * const pi, PointType * const po, state_ikfom &s)
    {
        V3D p_body(pi->x, pi->y, pi->z);
        V3D p_global(s.rot * (s.offset_R_L_I*p_body + s.offset_T_L_I) + s.pos);
    
        po->x = p_global(0);
        po->y = p_global(1);
        po->z = p_global(2);
        po->intensity = pi->intensity;
    }
    
    // 函数功能:激光雷达坐标点转到世界坐标系
    void pointBodyToWorld(PointType const * const pi, PointType * const po)
    {
        V3D p_body(pi->x, pi->y, pi->z);
        V3D p_global(state_point.rot * (state_point.offset_R_L_I*p_body + state_point.offset_T_L_I) + state_point.pos);
    
        po->x = p_global(0);
        po->y = p_global(1);
        po->z = p_global(2);
        po->intensity = pi->intensity; // 信号强度
    }
    
    // pi:激光雷达坐标系
    // 函数功能:激光雷达坐标点转到世界坐标系
    // state_point.offset_R_L_I*p_body + state_point.offset_T_L_I:转到IMU坐标系
    // state_point.rot:IMU坐标系到世界坐标系
    template<typename T>
    void pointBodyToWorld(const Matrix<T, 3, 1> &pi, Matrix<T, 3, 1> &po)
    {
        V3D p_body(pi[0], pi[1], pi[2]);
        V3D p_global(state_point.rot * (state_point.offset_R_L_I*p_body + state_point.offset_T_L_I) + state_point.pos);
    
        po[0] = p_global(0);
        po[1] = p_global(1);
        po[2] = p_global(2);
    }
    
    // 函数功能:激光雷达坐标点转到世界坐标系
    void RGBpointBodyToWorld(PointType const * const pi, PointType * const po)
    {
        V3D p_body(pi->x, pi->y, pi->z);
        V3D p_global(state_point.rot * (state_point.offset_R_L_I*p_body + state_point.offset_T_L_I) + state_point.pos);
    
        po->x = p_global(0);
        po->y = p_global(1);
        po->z = p_global(2);
        po->intensity = pi->intensity;
    }
    
    // 函数功能:激光雷达坐标点转到IMU坐标系
    void RGBpointBodyLidarToIMU(PointType const * const pi, PointType * const po)
    {
        V3D p_body_lidar(pi->x, pi->y, pi->z);
        V3D p_body_imu(state_point.offset_R_L_I*p_body_lidar + state_point.offset_T_L_I);
    
        po->x = p_body_imu(0);
        po->y = p_body_imu(1);
        po->z = p_body_imu(2);
        po->intensity = pi->intensity;
    }
    
    void points_cache_collect()
    {
        PointVector points_history;
        ikdtree.acquire_removed_points(points_history);
        // for (int i = 0; i < points_history.size(); i++) _featsArray->push_back(points_history[i]);
    }
    
    BoxPointType LocalMap_Points;
    bool Localmap_Initialized = false;
    
    void lasermap_fov_segment()
    {
        cub_needrm.clear();
        kdtree_delete_counter = 0;
        kdtree_delete_time = 0.0;    
        pointBodyToWorld(XAxisPoint_body, XAxisPoint_world); // ??
        V3D pos_LiD = pos_lid;
        if (!Localmap_Initialized){
            for (int i = 0; i < 3; i++){
                // vertex:顶点
                // cube_len:200
                LocalMap_Points.vertex_min[i] = pos_LiD(i) - cube_len / 2.0;
                LocalMap_Points.vertex_max[i] = pos_LiD(i) + cube_len / 2.0;
            }
            Localmap_Initialized = true;
            return;
        }
        float dist_to_map_edge[3][2];
        bool need_move = false;
        for (int i = 0; i < 3; i++){
            dist_to_map_edge[i][0] = fabs(pos_LiD(i) - LocalMap_Points.vertex_min[i]);
            dist_to_map_edge[i][1] = fabs(pos_LiD(i) - LocalMap_Points.vertex_max[i]);
            if (dist_to_map_edge[i][0] <= MOV_THRESHOLD * DET_RANGE || dist_to_map_edge[i][1] <= MOV_THRESHOLD * DET_RANGE) need_move = true;
        }
        if (!need_move) return;
        BoxPointType New_LocalMap_Points, tmp_boxpoints;
        New_LocalMap_Points = LocalMap_Points;
        float mov_dist = max((cube_len - 2.0 * MOV_THRESHOLD * DET_RANGE) * 0.5 * 0.9, double(DET_RANGE * (MOV_THRESHOLD -1)));
        for (int i = 0; i < 3; i++){
            tmp_boxpoints = LocalMap_Points;
            if (dist_to_map_edge[i][0] <= MOV_THRESHOLD * DET_RANGE){
                New_LocalMap_Points.vertex_max[i] -= mov_dist;
                New_LocalMap_Points.vertex_min[i] -= mov_dist;
                tmp_boxpoints.vertex_min[i] = LocalMap_Points.vertex_max[i] - mov_dist;
                cub_needrm.push_back(tmp_boxpoints);
            } else if (dist_to_map_edge[i][1] <= MOV_THRESHOLD * DET_RANGE){
                New_LocalMap_Points.vertex_max[i] += mov_dist;
                New_LocalMap_Points.vertex_min[i] += mov_dist;
                tmp_boxpoints.vertex_max[i] = LocalMap_Points.vertex_min[i] + mov_dist;
                cub_needrm.push_back(tmp_boxpoints);
            }
        }
        LocalMap_Points = New_LocalMap_Points;
    
        points_cache_collect();
        double delete_begin = omp_get_wtime();
        if(cub_needrm.size() > 0) kdtree_delete_counter = ikdtree.Delete_Point_Boxes(cub_needrm);
        kdtree_delete_time = omp_get_wtime() - delete_begin;
    }
    
    // 标准雷达回调函数
    void standard_pcl_cbk(const sensor_msgs::PointCloud2::ConstPtr &msg) 
    {
        mtx_buffer.lock();
        scan_count ++;
        double preprocess_start_time = omp_get_wtime();
        if (msg->header.stamp.toSec() < last_timestamp_lidar)
        {
            ROS_ERROR("lidar loop back, clear buffer");
            lidar_buffer.clear();
        }
    
        PointCloudXYZI::Ptr  ptr(new PointCloudXYZI());
        p_pre->process(msg, ptr);
        lidar_buffer.push_back(ptr);
        time_buffer.push_back(msg->header.stamp.toSec());
        last_timestamp_lidar = msg->header.stamp.toSec();
        s_plot11[scan_count] = omp_get_wtime() - preprocess_start_time;
        mtx_buffer.unlock();
        sig_buffer.notify_all();
    }
    
    // 雷达和IMU之间的时间差(不是同一个时间系统)
    double timediff_lidar_wrt_imu = 0.0;
    bool   timediff_set_flg = false; // 是否已经计算了时间差
    
    // livox激光雷达回调函数
    void livox_pcl_cbk(const livox_ros_driver::CustomMsg::ConstPtr &msg) 
    {
        mtx_buffer.lock();
        // omp_get_wtime:获得绝对时间
        double preprocess_start_time = omp_get_wtime();
        scan_count ++;
        if (msg->header.stamp.toSec() < last_timestamp_lidar)
        {
            ROS_ERROR("lidar loop back, clear buffer");
            lidar_buffer.clear();
        }
        last_timestamp_lidar = msg->header.stamp.toSec();
        
        // 不是同一个时间系统
        if (!time_sync_en && abs(last_timestamp_imu - last_timestamp_lidar) > 10.0 && !imu_buffer.empty() && !lidar_buffer.empty() )
        {
            printf("IMU and LiDAR not Synced, IMU time: %lf, lidar header time: %lf \n",last_timestamp_imu, last_timestamp_lidar);
        }
        // 如果是同一个时间系统,正常情况下不会相差大于1s(不是同一个时间系统)
        if (time_sync_en && !timediff_set_flg && abs(last_timestamp_lidar - last_timestamp_imu) > 1 && !imu_buffer.empty())
        {
            timediff_set_flg = true;
            timediff_lidar_wrt_imu = last_timestamp_lidar + 0.1 - last_timestamp_imu; // 0.1??
            printf("Self sync IMU and LiDAR, time diff is %.10lf \n", timediff_lidar_wrt_imu);
        }
    
        PointCloudXYZI::Ptr  ptr(new PointCloudXYZI());
        p_pre->process(msg, ptr); // 数据格式转换
        lidar_buffer.push_back(ptr);
        time_buffer.push_back(last_timestamp_lidar);
        
        s_plot11[scan_count] = omp_get_wtime() - preprocess_start_time;
        mtx_buffer.unlock();
        sig_buffer.notify_all();
    }
    
    // 接收IMU数据回调函数
    // ConstPtr:智能指针
    void imu_cbk(const sensor_msgs::Imu::ConstPtr &msg_in) 
    {
        publish_count ++;
        // cout<<"IMU got at: "<header.stamp.toSec()<
        sensor_msgs::Imu::Ptr msg(new sensor_msgs::Imu(*msg_in));
    
        // 不是同一个时间系统,需要转换到同一个时间系统
        if (abs(timediff_lidar_wrt_imu) > 0.1 && time_sync_en)
        {
            // 重新计算时间
            msg->header.stamp = \
            ros::Time().fromSec(timediff_lidar_wrt_imu + msg_in->header.stamp.toSec());
        }
    
        double timestamp = msg->header.stamp.toSec();
    
        mtx_buffer.lock(); // 上锁
    
        if (timestamp < last_timestamp_imu)
        {
            ROS_WARN("imu loop back, clear buffer");
            imu_buffer.clear();
        }
    
        last_timestamp_imu = timestamp;
    
        imu_buffer.push_back(msg);
        mtx_buffer.unlock(); // 解锁
        sig_buffer.notify_all(); // ??
    }
    
    double lidar_mean_scantime = 0.0; // 雷达扫描一帧平均时间
    int    scan_num = 0; // 激光雷达帧数
    
    // 取一帧激光雷达数据,以及对应时间区间的IMU数据
    // 输入数据:lidar_buffer,imu_buffer
    // 输出数据:MeasureGroup
    // 备注:必须同时有IMU数据,以及雷达数据
    bool sync_packages(MeasureGroup &meas)
    {
        if (lidar_buffer.empty() || imu_buffer.empty()) {
            return false;
        }
    
        /*** push a lidar scan ***/
        // 计算lidar_end_time
        if(!lidar_pushed)
        {
            meas.lidar = lidar_buffer.front();
            meas.lidar_beg_time = time_buffer.front();
            if (meas.lidar->points.size() <= 1) // time too little
            {
                lidar_end_time = meas.lidar_beg_time + lidar_mean_scantime;
                ROS_WARN("Too few input point cloud!\n");
            }
            // curvature:曲率?时间单位
            // 一帧所用的时间
            else if (meas.lidar->points.back().curvature / double(1000) < 0.5 * lidar_mean_scantime)
            {
                lidar_end_time = meas.lidar_beg_time + lidar_mean_scantime;
            }
            else
            {
                scan_num ++;
                lidar_end_time = meas.lidar_beg_time + meas.lidar->points.back().curvature / double(1000);
                // 迭代方式计算平均时间
                lidar_mean_scantime += (meas.lidar->points.back().curvature / double(1000) - lidar_mean_scantime) / scan_num;
            }
    
            meas.lidar_end_time = lidar_end_time;
    
            lidar_pushed = true;
        }
        // last_timestamp_imu:最新IMU时间戳
        // 必须有IMU数据
        if (last_timestamp_imu < lidar_end_time)
        {
            return false;
        }
    
        /*** push imu data, and pop from imu buffer ***/
        // 在激光雷达一帧时间区间中取IMU数据
        // 同时有IMU数据和雷达数据
        double imu_time = imu_buffer.front()->header.stamp.toSec();
        meas.imu.clear();
        while ((!imu_buffer.empty()) && (imu_time < lidar_end_time))
        {
            imu_time = imu_buffer.front()->header.stamp.toSec();
            if(imu_time > lidar_end_time) break;
            meas.imu.push_back(imu_buffer.front());
            imu_buffer.pop_front();
        }
    
        lidar_buffer.pop_front();
        time_buffer.pop_front();
        lidar_pushed = false;
        return true;
    }
    
    int process_increments = 0;
    
    // 更新地图
    void map_incremental()
    {
        PointVector PointToAdd;// 需要在地图中新增的雷达点
        PointVector PointNoNeedDownsample; // 不需要在地图中新增的雷达点
        PointToAdd.reserve(feats_down_size);
        PointNoNeedDownsample.reserve(feats_down_size);
        for (int i = 0; i < feats_down_size; i++)
        {
            /* transform to world frame */
            // 转到导航坐标系
            pointBodyToWorld(&(feats_down_body->points[i]), &(feats_down_world->points[i]));
            /* decide if need add to map */
            // Nearest_Points??
            if (!Nearest_Points[i].empty() && flg_EKF_inited)
            {
                const PointVector &points_near = Nearest_Points[i];
                bool need_add = true;
                BoxPointType Box_of_Point;
                PointType downsample_result, mid_point; 
                // 体素滤波器长度:filter_size_map_min
                mid_point.x = floor(feats_down_world->points[i].x/filter_size_map_min)*filter_size_map_min + 0.5 * filter_size_map_min;
                mid_point.y = floor(feats_down_world->points[i].y/filter_size_map_min)*filter_size_map_min + 0.5 * filter_size_map_min;
                mid_point.z = floor(feats_down_world->points[i].z/filter_size_map_min)*filter_size_map_min + 0.5 * filter_size_map_min;
                // 二范数:dist
                float dist  = calc_dist(feats_down_world->points[i],mid_point);
                if (fabs(points_near[0].x - mid_point.x) > 0.5 * filter_size_map_min && fabs(points_near[0].y - mid_point.y) > 0.5 * filter_size_map_min && fabs(points_near[0].z - mid_point.z) > 0.5 * filter_size_map_min){
                    PointNoNeedDownsample.push_back(feats_down_world->points[i]);
                    continue;
                }
                for (int readd_i = 0; readd_i < NUM_MATCH_POINTS; readd_i ++)
                {
                    // NUM_MATCH_POINTS:5
                    if (points_near.size() < NUM_MATCH_POINTS) break;
                    if (calc_dist(points_near[readd_i], mid_point) < dist)
                    {
                        need_add = false;
                        break;
                    }
                }
                if (need_add) PointToAdd.push_back(feats_down_world->points[i]);
            }
            else // 初始点
            {
                PointToAdd.push_back(feats_down_world->points[i]);
            }
        }
    
        double st_time = omp_get_wtime();
        add_point_size = ikdtree.Add_Points(PointToAdd, true);
        ikdtree.Add_Points(PointNoNeedDownsample, false); 
        add_point_size = PointToAdd.size() + PointNoNeedDownsample.size();
        kdtree_incremental_time = omp_get_wtime() - st_time;
    }
    
    PointCloudXYZI::Ptr pcl_wait_pub(new PointCloudXYZI(500000, 1));
    PointCloudXYZI::Ptr pcl_wait_save(new PointCloudXYZI());
    void publish_frame_world(const ros::Publisher & pubLaserCloudFull)
    {
        if(scan_pub_en)
        {
            PointCloudXYZI::Ptr laserCloudFullRes(dense_pub_en ? feats_undistort : feats_down_body);
            int size = laserCloudFullRes->points.size();
            PointCloudXYZI::Ptr laserCloudWorld( \
                            new PointCloudXYZI(size, 1));
    
            for (int i = 0; i < size; i++)
            {
                RGBpointBodyToWorld(&laserCloudFullRes->points[i], \
                                    &laserCloudWorld->points[i]);
            }
    
            sensor_msgs::PointCloud2 laserCloudmsg;
            pcl::toROSMsg(*laserCloudWorld, laserCloudmsg);
            laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
            laserCloudmsg.header.frame_id = "camera_init";
            pubLaserCloudFull.publish(laserCloudmsg);
            publish_count -= PUBFRAME_PERIOD;
        }
    
        /**************** save map ****************/
        /* 1. make sure you have enough memories
        /* 2. noted that pcd save will influence the real-time performences **/
        if (pcd_save_en)
        {
            int size = feats_undistort->points.size();
            PointCloudXYZI::Ptr laserCloudWorld( \
                            new PointCloudXYZI(size, 1));
    
            for (int i = 0; i < size; i++)
            {
                RGBpointBodyToWorld(&feats_undistort->points[i], \
                                    &laserCloudWorld->points[i]);
            }
            *pcl_wait_save += *laserCloudWorld;
    
            static int scan_wait_num = 0;
            scan_wait_num ++;
            if (pcl_wait_save->size() > 0 && pcd_save_interval > 0  && scan_wait_num >= pcd_save_interval)
            {
                pcd_index ++;
                string all_points_dir(string(string(ROOT_DIR) + "PCD/scans_") + to_string(pcd_index) + string(".pcd"));
                pcl::PCDWriter pcd_writer;
                cout << "current scan saved to /PCD/" << all_points_dir << endl;
                pcd_writer.writeBinary(all_points_dir, *pcl_wait_save);
                pcl_wait_save->clear();
                scan_wait_num = 0;
            }
        }
    }
    
    void publish_frame_body(const ros::Publisher & pubLaserCloudFull_body)
    {
        int size = feats_undistort->points.size();
        PointCloudXYZI::Ptr laserCloudIMUBody(new PointCloudXYZI(size, 1));
    
        for (int i = 0; i < size; i++)
        {
            RGBpointBodyLidarToIMU(&feats_undistort->points[i], \
                                &laserCloudIMUBody->points[i]);
        }
    
        sensor_msgs::PointCloud2 laserCloudmsg;
        pcl::toROSMsg(*laserCloudIMUBody, laserCloudmsg);
        laserCloudmsg.header.stamp = ros::Time().fromSec(lidar_end_time);
        laserCloudmsg.header.frame_id = "body";
        pubLaserCloudFull_body.publish(laserCloudmsg);
        publish_count -= PUBFRAME_PERIOD;
    }
    
    void publish_effect_world(const ros::Publisher & pubLaserCloudEffect)
    {
        PointCloudXYZI::Ptr laserCloudWorld( \
                        new PointCloudXYZI(effct_feat_num, 1));
        for (int i = 0; i < effct_feat_num; i++)
        {
            RGBpointBodyToWorld(&laserCloudOri->points[i], \
                                &laserCloudWorld->points[i]);
        }
        sensor_msgs::PointCloud2 laserCloudFullRes3;
        pcl::toROSMsg(*laserCloudWorld, laserCloudFullRes3);
        laserCloudFullRes3.header.stamp = ros::Time().fromSec(lidar_end_time);
        laserCloudFullRes3.header.frame_id = "camera_init";
        pubLaserCloudEffect.publish(laserCloudFullRes3);
    }
    
    void publish_map(const ros::Publisher & pubLaserCloudMap)
    {
        sensor_msgs::PointCloud2 laserCloudMap;
        pcl::toROSMsg(*featsFromMap, laserCloudMap);
        laserCloudMap.header.stamp = ros::Time().fromSec(lidar_end_time);
        laserCloudMap.header.frame_id = "camera_init";
        pubLaserCloudMap.publish(laserCloudMap);
    }
    
    template<typename T>
    void set_posestamp(T & out)
    {
        out.pose.position.x = state_point.pos(0);
        out.pose.position.y = state_point.pos(1);
        out.pose.position.z = state_point.pos(2);
        out.pose.orientation.x = geoQuat.x;
        out.pose.orientation.y = geoQuat.y;
        out.pose.orientation.z = geoQuat.z;
        out.pose.orientation.w = geoQuat.w;
        
    }
    
    // 涉及坐标转换?
    void publish_odometry(const ros::Publisher & pubOdomAftMapped)
    {
        odomAftMapped.header.frame_id = "camera_init";
        odomAftMapped.child_frame_id = "body";
        odomAftMapped.header.stamp = ros::Time().fromSec(lidar_end_time);// ros::Time().fromSec(lidar_end_time);
        set_posestamp(odomAftMapped.pose); // 设置位置,欧拉角
        pubOdomAftMapped.publish(odomAftMapped);
        auto P = kf.get_P(); // 协方差
        for (int i = 0; i < 6; i ++)
        {
            // 0,3
            // 1,4
            // 2,5
            // 3,0
            // 4,1
            // 5,2
            // 0-2:位置
            // 3-5:欧拉角
            int k = i < 3 ? i + 3 : i - 3;
            odomAftMapped.pose.covariance[i*6 + 0] = P(k, 3);
            odomAftMapped.pose.covariance[i*6 + 1] = P(k, 4);
            odomAftMapped.pose.covariance[i*6 + 2] = P(k, 5);
            odomAftMapped.pose.covariance[i*6 + 3] = P(k, 0);
            odomAftMapped.pose.covariance[i*6 + 4] = P(k, 1);
            odomAftMapped.pose.covariance[i*6 + 5] = P(k, 2);
        }
    
        static tf::TransformBroadcaster br;
        tf::Transform                   transform;
        tf::Quaternion                  q;
        transform.setOrigin(tf::Vector3(odomAftMapped.pose.pose.position.x, \
                                        odomAftMapped.pose.pose.position.y, \
                                        odomAftMapped.pose.pose.position.z));
        q.setW(odomAftMapped.pose.pose.orientation.w);
        q.setX(odomAftMapped.pose.pose.orientation.x);
        q.setY(odomAftMapped.pose.pose.orientation.y);
        q.setZ(odomAftMapped.pose.pose.orientation.z);
    
        transform.setRotation( q );
        br.sendTransform( tf::StampedTransform( transform, odomAftMapped.header.stamp, "camera_init", "body" ) );
    }
    
    void publish_path(const ros::Publisher pubPath)
    {
        set_posestamp(msg_body_pose);
        msg_body_pose.header.stamp = ros::Time().fromSec(lidar_end_time);
        msg_body_pose.header.frame_id = "camera_init";
    
        /*** if path is too large, the rvis will crash ***/
        static int jjj = 0;
        jjj++;
        if (jjj % 10 == 0) 
        {
            path.poses.push_back(msg_body_pose);
            pubPath.publish(path);
        }
    }
    
    // 观测模型
    void h_share_model(state_ikfom &s, esekfom::dyn_share_datastruct<double> &ekfom_data)
    {
        double match_start = omp_get_wtime();
        laserCloudOri->clear(); 
        corr_normvect->clear(); 
        total_residual = 0.0; // 残差和
    
        // 最邻近面搜索,以及残差计算
        /** closest surface search and residual computation **/
        #ifdef MP_EN
            omp_set_num_threads(MP_PROC_NUM);
            #pragma omp parallel for
        #endif
        // feats_down_size??
        //遍历所有的特征点
        for (int i = 0; i < feats_down_size; i++)
        {
            // feats_down_body:网格滤波器之后的激光点
            PointType &point_body  = feats_down_body->points[i]; 
            // feats_down_world:世界坐标系下的激光点
            PointType &point_world = feats_down_world->points[i]; 
    
            /* transform to world frame */
            V3D p_body(point_body.x, point_body.y, point_body.z);
            // 激光雷达坐标系->IMU坐标系->世界坐标系
            V3D p_global(s.rot * (s.offset_R_L_I*p_body + s.offset_T_L_I) + s.pos);
            point_world.x = p_global(0);
            point_world.y = p_global(1);
            point_world.z = p_global(2);
            point_world.intensity = point_body.intensity; // 信号强度
            // NUM_MATCH_POINTS:5
            vector<float> pointSearchSqDis(NUM_MATCH_POINTS);
            auto &points_near = Nearest_Points[i];
    
            if (ekfom_data.converge)
            {
                /** Find the closest surfaces in the map **/
                // 在地图中找到与之最邻近的平面
                ikdtree.Nearest_Search(point_world, NUM_MATCH_POINTS, points_near, pointSearchSqDis);
                //判断是否是有效匹配点,与loam系列类似,要求特征点最近邻的地图点数量大于阈值A,距离小于阈值B
                point_selected_surf[i] = points_near.size() < NUM_MATCH_POINTS ? false : pointSearchSqDis[NUM_MATCH_POINTS - 1] > 5 ? false : true;
            }
    
            if (!point_selected_surf[i]) continue;
    
            VF(4) pabcd; //法向量
            // 参考:https://blog.csdn.net/u011483307/article/details/51034169
            point_selected_surf[i] = false;
            if (esti_plane(pabcd, points_near, 0.1f))//计算平面法向量
            {
                float pd2 = pabcd(0) * point_world.x + pabcd(1) * point_world.y + pabcd(2) * point_world.z + pabcd(3);//残差(点到平面距离)
                // 发射距离越长,测量误差越大,归一化,消除雷达点发射距离的影响
                float s = 1 - 0.9 * fabs(pd2) / sqrt(p_body.norm()); 
    
                if (s > 0.9)
                {
                    point_selected_surf[i] = true;
                    normvec->points[i].x = pabcd(0);  //法向量
                    normvec->points[i].y = pabcd(1);
                    normvec->points[i].z = pabcd(2);
                    normvec->points[i].intensity = pd2; //残差存到intensity里
                    res_last[i] = abs(pd2);
                }
            }
        }
        
        effct_feat_num = 0;
    
        for (int i = 0; i < feats_down_size; i++) 
        {
            if (point_selected_surf[i])//只保留有效的特征点
            {
                laserCloudOri->points[effct_feat_num] = feats_down_body->points[i];
                corr_normvect->points[effct_feat_num] = normvec->points[i];
                total_residual += res_last[i];
                effct_feat_num ++;
            }
        }
    
        if (effct_feat_num < 1)
        {
            ekfom_data.valid = false;
            ROS_WARN("No Effective Points! \n");
            return;
        }
    
        res_mean_last = total_residual / effct_feat_num;
        match_time  += omp_get_wtime() - match_start;
        double solve_start_  = omp_get_wtime();
        
        /*** Computation of Measuremnt Jacobian matrix H and measurents vector ***/
        // 计算雅可比矩阵,以及观测向量
        //h_x是观测h相对于状态x的jacobian,见fatliov1的论文公式(14)
        //h_x 为观测相对于(姿态、位置、imu和雷达间的变换)
        //的雅克比,尺寸为 特征点数x12
        ekfom_data.h_x = MatrixXd::Zero(effct_feat_num, 12); //23
        ekfom_data.h.resize(effct_feat_num);
    
        for (int i = 0; i < effct_feat_num; i++)
        {
            const PointType &laser_p  = laserCloudOri->points[i];
            V3D point_this_be(laser_p.x, laser_p.y, laser_p.z);
            M3D point_be_crossmat;
            point_be_crossmat << SKEW_SYM_MATRX(point_this_be);
            // 激光雷达坐标系->IMU坐标系
            V3D point_this = s.offset_R_L_I * point_this_be + s.offset_T_L_I;
            M3D point_crossmat;
            point_crossmat<<SKEW_SYM_MATRX(point_this);
    
            /*** get the normal vector of closest surface/corner ***/
            const PointType &norm_p = corr_normvect->points[i]; // 法向量
            V3D norm_vec(norm_p.x, norm_p.y, norm_p.z);
    
            /*** calculate the Measuremnt Jacobian matrix H ***/
            // conjugate:共轭,相当于矩阵求逆
            // 
            V3D C(s.rot.conjugate() *norm_vec);  // 转到IMU坐标系
            V3D A(point_crossmat * C);
    
            if (extrinsic_est_en)
            {
                // 先转到雷达坐标系
                // 如何推导???
                V3D B(point_be_crossmat * s.offset_R_L_I.conjugate() * C); //s.rot.conjugate()*norm_vec);
                ekfom_data.h_x.block<1, 12>(i,0) << norm_p.x, norm_p.y, norm_p.z, VEC_FROM_ARRAY(A), VEC_FROM_ARRAY(B), VEC_FROM_ARRAY(C);
            }
            else
            {
                ekfom_data.h_x.block<1, 12>(i,0) << norm_p.x, norm_p.y, norm_p.z, VEC_FROM_ARRAY(A), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
            }
    
            /*** Measuremnt: distance to the closest surface/corner ***/
            // 观测量:误差形式
            ekfom_data.h(i) = -norm_p.intensity;
        }
        solve_time += omp_get_wtime() - solve_start_;
    }
    
    int main(int argc, char** argv)
    {
        ros::init(argc, argv, "laserMapping");
        ros::NodeHandle nh;
    
        nh.param<bool>("publish/path_en",path_en, true); // ??
        nh.param<bool>("publish/scan_publish_en",scan_pub_en, true);
        nh.param<bool>("publish/dense_publish_en",dense_pub_en, true);// 高密度点云
        nh.param<bool>("publish/scan_bodyframe_pub_en",scan_body_pub_en, true);
        nh.param<int>("max_iteration",NUM_MAX_ITERATIONS,4); // IEKF最大迭代次数?
        nh.param<string>("map_file_path",map_file_path,"");
        nh.param<string>("common/lid_topic",lid_topic,"/livox/lidar");
        nh.param<string>("common/imu_topic", imu_topic,"/livox/imu");
        nh.param<bool>("common/time_sync_en", time_sync_en, false);
        nh.param<double>("filter_size_corner",filter_size_corner_min,0.5);
        nh.param<double>("filter_size_surf",filter_size_surf_min,0.5);
        nh.param<double>("filter_size_map",filter_size_map_min,0.5); // ??
        nh.param<double>("cube_side_length",cube_len,200); // 
        nh.param<float>("mapping/det_range",DET_RANGE,300.f);
        nh.param<double>("mapping/fov_degree",fov_deg,180);
        nh.param<double>("mapping/gyr_cov",gyr_cov,0.1);
        nh.param<double>("mapping/acc_cov",acc_cov,0.1);
        nh.param<double>("mapping/b_gyr_cov",b_gyr_cov,0.0001);
        nh.param<double>("mapping/b_acc_cov",b_acc_cov,0.0001);
        nh.param<double>("preprocess/blind", p_pre->blind, 0.01);
        nh.param<int>("preprocess/lidar_type", p_pre->lidar_type, AVIA); // 激光雷达类型
        nh.param<int>("preprocess/scan_line", p_pre->N_SCANS, 16); // 激光雷达线束数
        nh.param<int>("preprocess/timestamp_unit", p_pre->time_unit, US);
        nh.param<int>("preprocess/scan_rate", p_pre->SCAN_RATE, 10); // 激光雷达扫描频率?
        nh.param<int>("point_filter_num", p_pre->point_filter_num, 2);
        nh.param<bool>("feature_extract_enable", p_pre->feature_enabled, false); // 是否提取特征
        nh.param<bool>("runtime_pos_log_enable", runtime_pos_log, 0);
        nh.param<bool>("mapping/extrinsic_est_en", extrinsic_est_en, true); // 打开外参估计
        nh.param<bool>("pcd_save/pcd_save_en", pcd_save_en, false);
        nh.param<int>("pcd_save/interval", pcd_save_interval, -1);
        nh.param<vector<double>>("mapping/extrinsic_T", extrinT, vector<double>()); // IMU和激光雷达之间的杆臂
        nh.param<vector<double>>("mapping/extrinsic_R", extrinR, vector<double>()); // IMU和激光雷达之间的安装角()
        cout<<"p_pre->lidar_type "<<p_pre->lidar_type<<endl;
        
        path.header.stamp    = ros::Time::now();
        path.header.frame_id ="camera_init";
    
        /*** variables definition ***/
        int effect_feat_num = 0, frame_num = 0;
        double deltaT, deltaR, aver_time_consu = 0, aver_time_icp = 0, aver_time_match = 0, aver_time_incre = 0, aver_time_solve = 0, aver_time_const_H_time = 0;
        bool flg_EKF_converged, EKF_stop_flg = 0;
        
        FOV_DEG = (fov_deg + 10.0) > 179.9 ? 179.9 : (fov_deg + 10.0); // ??
        HALF_FOV_COS = cos((FOV_DEG) * 0.5 * PI_M / 180.0);
    
        _featsArray.reset(new PointCloudXYZI());
    
        memset(point_selected_surf, true, sizeof(point_selected_surf));
        memset(res_last, -1000.0f, sizeof(res_last));
        // setLeafSize:设置体素的长,宽,高
        // 这里默认是0.5米
        downSizeFilterSurf.setLeafSize(filter_size_surf_min, filter_size_surf_min, filter_size_surf_min);
        downSizeFilterMap.setLeafSize(filter_size_map_min, filter_size_map_min, filter_size_map_min);
        memset(point_selected_surf, true, sizeof(point_selected_surf));
        memset(res_last, -1000.0f, sizeof(res_last));
    
        //设置参数
        Lidar_T_wrt_IMU<<VEC_FROM_ARRAY(extrinT);
        Lidar_R_wrt_IMU<<MAT_FROM_ARRAY(extrinR);
        p_imu->set_extrinsic(Lidar_T_wrt_IMU, Lidar_R_wrt_IMU); // 外参(安装角,杆臂)
        p_imu->set_gyr_cov(V3D(gyr_cov, gyr_cov, gyr_cov));
        p_imu->set_acc_cov(V3D(acc_cov, acc_cov, acc_cov));
        p_imu->set_gyr_bias_cov(V3D(b_gyr_cov, b_gyr_cov, b_gyr_cov));
        p_imu->set_acc_bias_cov(V3D(b_acc_cov, b_acc_cov, b_acc_cov));
    
        double epsi[23] = {0.001};
        // fill:用相同的值做初始化
        fill(epsi, epsi+23, 0.001);
        // NUM_MAX_ITERATIONS = 4
        // 
        kf.init_dyn_share(get_f, df_dx, df_dw, h_share_model, NUM_MAX_ITERATIONS, epsi);
    
        /*** debug record ***/
        FILE *fp;
        string pos_log_dir = root_dir + "/Log/pos_log.txt";
        fp = fopen(pos_log_dir.c_str(),"w");
    
        ofstream fout_pre, fout_out, fout_dbg;
        fout_pre.open(DEBUG_FILE_DIR("mat_pre.txt"),ios::out);
        fout_out.open(DEBUG_FILE_DIR("mat_out.txt"),ios::out);
        fout_dbg.open(DEBUG_FILE_DIR("dbg.txt"),ios::out);
        if (fout_pre && fout_out)
            cout << "~~~~"<<ROOT_DIR<<" file opened" << endl;
        else
            cout << "~~~~"<<ROOT_DIR<<" doesn't exist" << endl;
    
        /*** ROS subscribe initialization ***/
        // 订阅话题
        // 话题名:lid_topic
        // 队列大小:200000
        // 回调函数:livox_pcl_cbk
        // 通过回调函数接收激光雷达数据,IMU数据
        ros::Subscriber sub_pcl = p_pre->lidar_type == AVIA ? \
            nh.subscribe(lid_topic, 200000, livox_pcl_cbk) : \
            nh.subscribe(lid_topic, 200000, standard_pcl_cbk);
        ros::Subscriber sub_imu = nh.subscribe(imu_topic, 200000, imu_cbk);
        // 发布消息类型:sensor_msgs::PointCloud2
        // 消息名:/cloud_registered
        // 消息队列大小:100000
        ros::Publisher pubLaserCloudFull = nh.advertise<sensor_msgs::PointCloud2>
                ("/cloud_registered", 100000);
        ros::Publisher pubLaserCloudFull_body = nh.advertise<sensor_msgs::PointCloud2>
                ("/cloud_registered_body", 100000);
        ros::Publisher pubLaserCloudEffect = nh.advertise<sensor_msgs::PointCloud2>
                ("/cloud_effected", 100000);
        ros::Publisher pubLaserCloudMap = nh.advertise<sensor_msgs::PointCloud2>
                ("/Laser_map", 100000);
        ros::Publisher pubOdomAftMapped = nh.advertise<nav_msgs::Odometry> 
                ("/Odometry", 100000);
        ros::Publisher pubPath          = nh.advertise<nav_msgs::Path> 
                ("/path", 100000);
    //------------------------------------------------------------------------------------------------------
        // 信号捕获函数
        signal(SIGINT, SigHandle);
        // 设置循环频率:5000HZ
        ros::Rate rate(5000);
        bool status = ros::ok();
        while (status)
        {
            if (flg_exit) break;
            // 可以根据自己的需求设置接收频率,更加主动灵活
            ros::spinOnce();
            // sync_packages: 取一帧激光雷达数据,以及对应时间区间的IMU数据
            if(sync_packages(Measures)) 
            {
                // 第一帧雷达数据
                if (flg_first_scan)
                {
                    first_lidar_time = Measures.lidar_beg_time;
                    p_imu->first_lidar_time = first_lidar_time;
                    flg_first_scan = false;
                    continue;
                }
    
                double t0,t1,t2,t3,t4,t5,match_start, solve_start, svd_time;
    
                match_time = 0;
                kdtree_search_time = 0.0;
                solve_time = 0;
                solve_const_H_time = 0;
                svd_time   = 0;
                t0 = omp_get_wtime();
                // feats_undistort:运动畸变去除之后的点云数据
                // 对IMU数据进行预处理,其中包含了点云畸变处理 前向传播 反向传播
                p_imu->Process(Measures, kf, feats_undistort);
                state_point = kf.get_x();
                // state_point.pos:IMU位置
                // pos_lid:雷达位置
                pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I; // 导航系
    
                if (feats_undistort->empty() || (feats_undistort == NULL))
                {
                    ROS_WARN("No point, skip this scan!\n");
                    continue;
                }
    
                flg_EKF_inited = (Measures.lidar_beg_time - first_lidar_time) < INIT_TIME ? \
                                false : true;
                /*** Segment the map in lidar FOV ***/
                lasermap_fov_segment();
    
                /*** downsample the feature points in a scan ***/
                downSizeFilterSurf.setInputCloud(feats_undistort);
                downSizeFilterSurf.filter(*feats_down_body);
                t1 = omp_get_wtime();
                feats_down_size = feats_down_body->points.size();
                /*** initialize the map kdtree ***/
                if(ikdtree.Root_Node == nullptr)
                {
                    if(feats_down_size > 5)
                    {
                        ikdtree.set_downsample_param(filter_size_map_min);
                        feats_down_world->resize(feats_down_size);
                        for(int i = 0; i < feats_down_size; i++)
                        {
                            // 转到导航系
                            pointBodyToWorld(&(feats_down_body->points[i]), &(feats_down_world->points[i]));
                        }
                        ikdtree.Build(feats_down_world->points);
                    }
                    continue;
                }
                int featsFromMapNum = ikdtree.validnum();
                kdtree_size_st = ikdtree.size();
                
                // cout<<"[ mapping ]: In num: "<points.size()<<" downsamp "<
    
                /*** ICP and iterated Kalman filter update ***/
                if (feats_down_size < 5)
                {
                    ROS_WARN("No point, skip this scan!\n");
                    continue;
                }
                
                normvec->resize(feats_down_size);
                feats_down_world->resize(feats_down_size);
    
                V3D ext_euler = SO3ToEuler(state_point.offset_R_L_I);
                fout_pre<<setw(20)<<Measures.lidar_beg_time - first_lidar_time<<" "<<euler_cur.transpose()<<" "<< state_point.pos.transpose()<<" "<<ext_euler.transpose() << " "<<state_point.offset_T_L_I.transpose()<< " " << state_point.vel.transpose() \
                <<" "<<state_point.bg.transpose()<<" "<<state_point.ba.transpose()<<" "<<state_point.grav<< endl;
    
                if(0) // If you need to see map point, change to "if(1)"
                {
                    PointVector ().swap(ikdtree.PCL_Storage);
                    ikdtree.flatten(ikdtree.Root_Node, ikdtree.PCL_Storage, NOT_RECORD);
                    featsFromMap->clear();
                    featsFromMap->points = ikdtree.PCL_Storage;
                }
    
                pointSearchInd_surf.resize(feats_down_size);
                Nearest_Points.resize(feats_down_size);
                int  rematch_num = 0;
                bool nearest_search_en = true; //
    
                t2 = omp_get_wtime();
                
                /*** iterated state estimation ***/
                double t_update_start = omp_get_wtime();
                double solve_H_time = 0;
                // 核心函数
                // 观测方程
                kf.update_iterated_dyn_share_modified(LASER_POINT_COV, solve_H_time);
                state_point = kf.get_x();
                euler_cur = SO3ToEuler(state_point.rot);
                // pos_lid:雷达后验位置
                // 补偿IMU和雷达之间杆臂,得到雷达的导航系坐标
                pos_lid = state_point.pos + state_point.rot * state_point.offset_T_L_I;
                // 转到四元数
                geoQuat.x = state_point.rot.coeffs()[0];
                geoQuat.y = state_point.rot.coeffs()[1];
                geoQuat.z = state_point.rot.coeffs()[2];
                geoQuat.w = state_point.rot.coeffs()[3];
    
                double t_update_end = omp_get_wtime();
    
                /******* Publish odometry *******/
                publish_odometry(pubOdomAftMapped);
    
                /*** add the feature points to map kdtree ***/
                t3 = omp_get_wtime();
                map_incremental();
                t5 = omp_get_wtime();
                
                /******* Publish points *******/
                if (path_en)                         publish_path(pubPath);
                if (scan_pub_en || pcd_save_en)      publish_frame_world(pubLaserCloudFull);
                if (scan_pub_en && scan_body_pub_en) publish_frame_body(pubLaserCloudFull_body);
                // publish_effect_world(pubLaserCloudEffect);
                // publish_map(pubLaserCloudMap);
    
                /*** Debug variables ***/
                if (runtime_pos_log)
                {
                    frame_num ++;
                    kdtree_size_end = ikdtree.size();
                    aver_time_consu = aver_time_consu * (frame_num - 1) / frame_num + (t5 - t0) / frame_num;
                    aver_time_icp = aver_time_icp * (frame_num - 1)/frame_num + (t_update_end - t_update_start) / frame_num;
                    aver_time_match = aver_time_match * (frame_num - 1)/frame_num + (match_time)/frame_num;
                    aver_time_incre = aver_time_incre * (frame_num - 1)/frame_num + (kdtree_incremental_time)/frame_num;
                    aver_time_solve = aver_time_solve * (frame_num - 1)/frame_num + (solve_time + solve_H_time)/frame_num;
                    aver_time_const_H_time = aver_time_const_H_time * (frame_num - 1)/frame_num + solve_time / frame_num;
                    T1[time_log_counter] = Measures.lidar_beg_time;
                    s_plot[time_log_counter] = t5 - t0;
                    s_plot2[time_log_counter] = feats_undistort->points.size();
                    s_plot3[time_log_counter] = kdtree_incremental_time;
                    s_plot4[time_log_counter] = kdtree_search_time;
                    s_plot5[time_log_counter] = kdtree_delete_counter;
                    s_plot6[time_log_counter] = kdtree_delete_time;
                    s_plot7[time_log_counter] = kdtree_size_st;
                    s_plot8[time_log_counter] = kdtree_size_end;
                    s_plot9[time_log_counter] = aver_time_consu;
                    s_plot10[time_log_counter] = add_point_size;
                    time_log_counter ++;
                    printf("[ mapping ]: time: IMU + Map + Input Downsample: %0.6f ave match: %0.6f ave solve: %0.6f  ave ICP: %0.6f  map incre: %0.6f ave total: %0.6f icp: %0.6f construct H: %0.6f \n",t1-t0,aver_time_match,aver_time_solve,t3-t1,t5-t3,aver_time_consu,aver_time_icp, aver_time_const_H_time);
                    ext_euler = SO3ToEuler(state_point.offset_R_L_I);
                    fout_out << setw(20) << Measures.lidar_beg_time - first_lidar_time << " " << euler_cur.transpose() << " " << state_point.pos.transpose()<< " " << ext_euler.transpose() << " "<<state_point.offset_T_L_I.transpose()<<" "<< state_point.vel.transpose() \
                    <<" "<<state_point.bg.transpose()<<" "<<state_point.ba.transpose()<<" "<<state_point.grav<<" "<<feats_undistort->points.size()<<endl;
                    dump_lio_state_to_log(fp);
                }
            }
    
            status = ros::ok();
            rate.sleep(); // 通过睡眠度过循环中剩余的时间
        }
    
        /**************** save map ****************/
        /* 1. make sure you have enough memories
        /* 2. pcd save will largely influence the real-time performences **/
        if (pcl_wait_save->size() > 0 && pcd_save_en)
        {
            string file_name = string("scans.pcd");
            string all_points_dir(string(string(ROOT_DIR) + "PCD/") + file_name);
            pcl::PCDWriter pcd_writer;
            cout << "current scan saved to /PCD/" << file_name<<endl;
            pcd_writer.writeBinary(all_points_dir, *pcl_wait_save);
        }
    
        fout_out.close();
        fout_pre.close();
    
        if (runtime_pos_log)
        {
            vector<double> t, s_vec, s_vec2, s_vec3, s_vec4, s_vec5, s_vec6, s_vec7;    
            FILE *fp2;
            string log_dir = root_dir + "/Log/fast_lio_time_log.csv";
            fp2 = fopen(log_dir.c_str(),"w");
            fprintf(fp2,"time_stamp, total time, scan point size, incremental time, search time, delete size, delete time, tree size st, tree size end, add point size, preprocess time\n");
            for (int i = 0;i<time_log_counter; i++){
                fprintf(fp2,"%0.8f,%0.8f,%d,%0.8f,%0.8f,%d,%0.8f,%d,%d,%d,%0.8f\n",T1[i],s_plot[i],int(s_plot2[i]),s_plot3[i],s_plot4[i],int(s_plot5[i]),s_plot6[i],int(s_plot7[i]),int(s_plot8[i]), int(s_plot10[i]), s_plot11[i]);
                t.push_back(T1[i]);
                s_vec.push_back(s_plot9[i]);
                s_vec2.push_back(s_plot3[i] + s_plot6[i]);
                s_vec3.push_back(s_plot4[i]);
                s_vec5.push_back(s_plot[i]);
            }
            fclose(fp2);
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849
    • 850
    • 851
    • 852
    • 853
    • 854
    • 855
    • 856
    • 857
    • 858
    • 859
    • 860
    • 861
    • 862
    • 863
    • 864
    • 865
    • 866
    • 867
    • 868
    • 869
    • 870
    • 871
    • 872
    • 873
    • 874
    • 875
    • 876
    • 877
    • 878
    • 879
    • 880
    • 881
    • 882
    • 883
    • 884
    • 885
    • 886
    • 887
    • 888
    • 889
    • 890
    • 891
    • 892
    • 893
    • 894
    • 895
    • 896
    • 897
    • 898
    • 899
    • 900
    • 901
    • 902
    • 903
    • 904
    • 905
    • 906
    • 907
    • 908
    • 909
    • 910
    • 911
    • 912
    • 913
    • 914
    • 915
    • 916
    • 917
    • 918
    • 919
    • 920
    • 921
    • 922
    • 923
    • 924
    • 925
    • 926
    • 927
    • 928
    • 929
    • 930
    • 931
    • 932
    • 933
    • 934
    • 935
    • 936
    • 937
    • 938
    • 939
    • 940
    • 941
    • 942
    • 943
    • 944
    • 945
    • 946
    • 947
    • 948
    • 949
    • 950
    • 951
    • 952
    • 953
    • 954
    • 955
    • 956
    • 957
    • 958
    • 959
    • 960
    • 961
    • 962
    • 963
    • 964
    • 965
    • 966
    • 967
    • 968
    • 969
    • 970
    • 971
    • 972
    • 973
    • 974
    • 975
    • 976
    • 977
    • 978
    • 979
    • 980
    • 981
    • 982
    • 983
    • 984
    • 985
    • 986
    • 987
    • 988
    • 989
    • 990
    • 991
    • 992
    • 993
    • 994
    • 995
    • 996
    • 997
    • 998
    • 999
    • 1000
    • 1001
    • 1002
    • 1003
    • 1004
    • 1005
    • 1006
    • 1007
    • 1008
    • 1009
    • 1010
    • 1011
    • 1012
    • 1013
    • 1014
    • 1015
    • 1016
    • 1017
    • 1018
    • 1019
    • 1020
    • 1021
    • 1022
    • 1023
    • 1024
    • 1025
    • 1026
    • 1027
    • 1028
    • 1029
    • 1030
    • 1031
    • 1032
    • 1033
    • 1034
    • 1035
    • 1036
    • 1037
    • 1038
    • 1039
    • 1040
    • 1041
    • 1042
    • 1043
    • 1044
    • 1045
    • 1046
    • 1047
    • 1048
    • 1049
    • 1050
    • 1051
    • 1052
    • 1053
    • 1054
    • 1055
    • 1056
    • 1057
    • 1058
    • 1059
    • 1060
    • 1061
    • 1062
    • 1063
    • 1064
    • 1065
    • 1066
    • 1067
    • 1068
    • 1069
    • 1070
    • 1071
    • 1072
    • 1073
    • 1074
    • 1075
    • 1076
    • 1077
    • 1078
    • 1079
    • 1080
    • 1081
    • 1082
    • 1083
    • 1084
    • 1085
    • 1086
    • 1087
    • 1088
    • 1089
    • 1090
    • 1091
    • 1092
    • 1093
    • 1094
    • 1095
    • 1096
    • 1097
    • 1098
    • 1099
    • 1100
    • 1101
    • 1102
    • 1103
    • 1104
    • 1105
    • 1106
    • 1107
    • 1108
    • 1109
    • 1110
    • 1111
    • 1112
    • 1113
    • 1114
    • 1115
    • 1116
    • 1117
    • 1118
    • 1119
    • 1120
    • 1121
    • 1122
    • 1123
    • 1124
    • 1125
    • 1126
    • 1127
    • 1128
    • 1129
    • 1130
    • 1131
    • 1132
    • 1133
    • 1134
    • 1135
    • 1136
    • 1137
    • 1138
    • 1139
    • 1140
    • 1141
    • 1142
    • 1143
    • 1144
    • 1145
    • 1146
    • 1147
    • 1148
    • 1149
    • 1150
    • 1151
    • 1152
    • 1153
    • 1154
    • 1155
    • 1156
    • 1157
    • 1158
    • 1159
    • 1160
    • 1161

    2.IMU_Processing.hpp

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "use-ikfom.hpp"
    
    /// *************Preconfiguration
    
    #define MAX_INI_COUNT (10)
    
    const bool time_list(PointType &x, PointType &y) {return (x.curvature < y.curvature);};
    
    /// *************IMU Process and undistortion
    class ImuProcess
    {
     public:
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    
      ImuProcess();
      ~ImuProcess();
      
      void Reset();
      void Reset(double start_timestamp, const sensor_msgs::ImuConstPtr &lastimu);
      void set_extrinsic(const V3D &transl, const M3D &rot);
      void set_extrinsic(const V3D &transl);
      void set_extrinsic(const MD(4,4) &T);
      void set_gyr_cov(const V3D &scaler);
      void set_acc_cov(const V3D &scaler);
      void set_gyr_bias_cov(const V3D &b_g);
      void set_acc_bias_cov(const V3D &b_a);
      Eigen::Matrix<double, 12, 12> Q;
      void Process(const MeasureGroup &meas,  esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, PointCloudXYZI::Ptr pcl_un_);
    
      ofstream fout_imu;
      V3D cov_acc; // 加速度方差 
      V3D cov_gyr; // 陀螺仪方差
      V3D cov_acc_scale;
      V3D cov_gyr_scale;
      V3D cov_bias_gyr;
      V3D cov_bias_acc;
      double first_lidar_time; //一帧雷达数据的开始时间戳 
    
     private:
      void IMU_init(const MeasureGroup &meas, esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, int &N);
      void UndistortPcl(const MeasureGroup &meas, esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, PointCloudXYZI &pcl_in_out);
    
      PointCloudXYZI::Ptr cur_pcl_un_; // 没有去除畸变之前的雷达数据
      sensor_msgs::ImuConstPtr last_imu_; // 一帧雷达数据对应的最后一个imu数据
      deque<sensor_msgs::ImuConstPtr> v_imu_; //IMU数据队列
      vector<Pose6D> IMUpose; // 一帧激光雷达时间区间内的imu位姿(前向预测过程)
      vector<M3D>    v_rot_pcl_;
      M3D Lidar_R_wrt_IMU; //雷达和IMU之间的安装角
      V3D Lidar_T_wrt_IMU; //雷达和IMU之间的旋转矩阵
      V3D mean_acc; // 求平均,加速度零偏
      V3D mean_gyr; // 求平均,陀螺仪零偏
      V3D angvel_last; // 去除零偏之后的角速度
      V3D acc_s_last; // 导航系坐标系的加速度
      double start_timestamp_;
      double last_lidar_end_time_; // 一帧雷达点的最后时间戳
      int    init_iter_num = 1; // 计算陀螺仪零偏需要的IMU个数
      bool   b_first_frame_ = true; // 第一帧IMU数据
      bool   imu_need_init_ = true; // imu没有完成初始化
    };
    
    ImuProcess::ImuProcess()
        : b_first_frame_(true), imu_need_init_(true), start_timestamp_(-1)
    {
      init_iter_num = 1;
      Q = process_noise_cov();
      cov_acc       = V3D(0.1, 0.1, 0.1);
      cov_gyr       = V3D(0.1, 0.1, 0.1);
      cov_bias_gyr  = V3D(0.0001, 0.0001, 0.0001);
      cov_bias_acc  = V3D(0.0001, 0.0001, 0.0001);
      mean_acc      = V3D(0, 0, -1.0);
      mean_gyr      = V3D(0, 0, 0);
      angvel_last     = Zero3d;
      Lidar_T_wrt_IMU = Zero3d;
      Lidar_R_wrt_IMU = Eye3d;
      last_imu_.reset(new sensor_msgs::Imu());
    }
    
    ImuProcess::~ImuProcess() {}
    
    void ImuProcess::Reset() 
    {
      // ROS_WARN("Reset ImuProcess");
      mean_acc      = V3D(0, 0, -1.0); // 平均比力
      mean_gyr      = V3D(0, 0, 0);
      angvel_last       = Zero3d;
      imu_need_init_    = true; // 还没有初始化,需要初始化
      start_timestamp_  = -1;
      init_iter_num     = 1;
      v_imu_.clear();
      IMUpose.clear();
      last_imu_.reset(new sensor_msgs::Imu());
      cur_pcl_un_.reset(new PointCloudXYZI());
    }
    
    void ImuProcess::set_extrinsic(const MD(4,4) &T)
    {
      Lidar_T_wrt_IMU = T.block<3,1>(0,3);
      Lidar_R_wrt_IMU = T.block<3,3>(0,0);
    }
    
    void ImuProcess::set_extrinsic(const V3D &transl)
    {
      Lidar_T_wrt_IMU = transl;
      Lidar_R_wrt_IMU.setIdentity();
    }
    
    // 设置外参
    void ImuProcess::set_extrinsic(const V3D &transl, const M3D &rot)
    {
      Lidar_T_wrt_IMU = transl;
      Lidar_R_wrt_IMU = rot;
    }
    
    // 设置陀螺仪噪声
    void ImuProcess::set_gyr_cov(const V3D &scaler)
    {
      cov_gyr_scale = scaler;
    }
    
    // 设置加表噪声
    void ImuProcess::set_acc_cov(const V3D &scaler)
    {
      cov_acc_scale = scaler;
    }
    
    // 设置陀螺仪零偏
    void ImuProcess::set_gyr_bias_cov(const V3D &b_g)
    {
      cov_bias_gyr = b_g;
    }
    
    // 设置加表零偏
    void ImuProcess::set_acc_bias_cov(const V3D &b_a)
    {
      cov_bias_acc = b_a;
    }
    
    // 初始化滤波器状态变量,以及初始协方差矩阵
    // IMU初始化,需要静止
    // meas:激光雷达,IMU数据集合
    // 计算陀螺仪零偏
    void ImuProcess::IMU_init(const MeasureGroup &meas, esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, int &N)
    {
      /** 1. initializing the gravity, gyro bias, acc and gyro covariance
       ** 2. normalize the acceleration measurenments to unit gravity **/
      
      V3D cur_acc, cur_gyr;
      
      if (b_first_frame_)
      {
        Reset();
        N = 1;
        b_first_frame_ = false;
        const auto &imu_acc = meas.imu.front()->linear_acceleration; // 线加速度
        const auto &gyr_acc = meas.imu.front()->angular_velocity;    // 角速度
        mean_acc << imu_acc.x, imu_acc.y, imu_acc.z;
        mean_gyr << gyr_acc.x, gyr_acc.y, gyr_acc.z;
        first_lidar_time = meas.lidar_beg_time; // 雷达开始时间
      }
    
      for (const auto &imu : meas.imu)
      {
        const auto &imu_acc = imu->linear_acceleration;
        const auto &gyr_acc = imu->angular_velocity;
        cur_acc << imu_acc.x, imu_acc.y, imu_acc.z;
        cur_gyr << gyr_acc.x, gyr_acc.y, gyr_acc.z;
    
        // 迭代方式求平均 
        mean_acc += (cur_acc - mean_acc) / N;
        mean_gyr += (cur_gyr - mean_gyr) / N;
        // cwiseProduct??
        // 方差
        cov_acc = cov_acc * (N - 1.0) / N + (cur_acc - mean_acc).cwiseProduct(cur_acc - mean_acc) * (N - 1.0) / (N * N);
        cov_gyr = cov_gyr * (N - 1.0) / N + (cur_gyr - mean_gyr).cwiseProduct(cur_gyr - mean_gyr) * (N - 1.0) / (N * N);
    
        // cout<<"acc norm: "<
    
        N ++;
      }
      state_ikfom init_state = kf_state.get_x();
      // 归一化重力向量: - mean_acc / mean_acc.norm()
      // 防止加速度数据标度因子的影响:G_m_s2:9.81
      // S2?
      init_state.grav = S2(- mean_acc / mean_acc.norm() * G_m_s2); // 重力向量
      
      //state_inout.rot = Eye3d; // Exp(mean_acc.cross(V3D(0, 0, -1 / scale_gravity)));
      init_state.bg  = mean_gyr; // 陀螺零偏
      init_state.offset_T_L_I = Lidar_T_wrt_IMU;
      init_state.offset_R_L_I = Lidar_R_wrt_IMU;
      kf_state.change_x(init_state);
    
      // 协方差注意单位
      esekfom::esekf<state_ikfom, 12, input_ikfom>::cov init_P = kf_state.get_P();
      init_P.setIdentity();
      init_P(6,6) = init_P(7,7) = init_P(8,8) = 0.00001;     // IMU和雷达安装角
      init_P(9,9) = init_P(10,10) = init_P(11,11) = 0.00001; // IMU和雷达杆臂
      init_P(15,15) = init_P(16,16) = init_P(17,17) = 0.0001; // 陀螺仪零偏
      init_P(18,18) = init_P(19,19) = init_P(20,20) = 0.001;  // 加表零偏
      init_P(21,21) = init_P(22,22) = 0.00001;  // 重力向量
      kf_state.change_P(init_P);
      last_imu_ = meas.imu.back();
    
    }
    
    // 激光雷达去畸变
    // 设置系统噪声
    // 滤波预测过程
    void ImuProcess::UndistortPcl(const MeasureGroup &meas, esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, PointCloudXYZI &pcl_out)
    {
      /*** add the imu of the last frame-tail to the of current frame-head ***/
      auto v_imu = meas.imu;
      // push_front:从队列最前面插入
      v_imu.push_front(last_imu_); 
      const double &imu_beg_time = v_imu.front()->header.stamp.toSec();
      const double &imu_end_time = v_imu.back()->header.stamp.toSec();
      const double &pcl_beg_time = meas.lidar_beg_time;
      const double &pcl_end_time = meas.lidar_end_time;
      
      /*** sort point clouds by offset time ***/
      pcl_out = *(meas.lidar);
      // 按照排序?
      sort(pcl_out.points.begin(), pcl_out.points.end(), time_list);
      // cout<<"[ IMU Process ]: Process lidar from "<
    
      /*** Initialize IMU pose ***/
      state_ikfom imu_state = kf_state.get_x();
      IMUpose.clear();
      IMUpose.push_back(set_pose6d(0.0, acc_s_last, angvel_last, imu_state.vel, imu_state.pos, imu_state.rot.toRotationMatrix()));
    
        //前向过程 
      /*** forward propagation at each imu point ***/
      V3D angvel_avr, acc_avr, acc_imu, vel_imu, pos_imu;
      M3D R_imu;
    
      double dt = 0;
    
      input_ikfom in;
      for (auto it_imu = v_imu.begin(); it_imu < (v_imu.end() - 1); it_imu++)
      {
        auto &&head = *(it_imu); // &&?
        auto &&tail = *(it_imu + 1);
        
        if (tail->header.stamp.toSec() < last_lidar_end_time_)    continue;
    
        // 取平均值
        // 角速度平均值
        angvel_avr<<0.5 * (head->angular_velocity.x + tail->angular_velocity.x),
                    0.5 * (head->angular_velocity.y + tail->angular_velocity.y),
                    0.5 * (head->angular_velocity.z + tail->angular_velocity.z);
        // 加速度平均值
        acc_avr   <<0.5 * (head->linear_acceleration.x + tail->linear_acceleration.x),
                    0.5 * (head->linear_acceleration.y + tail->linear_acceleration.y),
                    0.5 * (head->linear_acceleration.z + tail->linear_acceleration.z);
    
        // fout_imu << setw(10) << head->header.stamp.toSec() - first_lidar_time << " " << angvel_avr.transpose() << " " << acc_avr.transpose() << endl;
        // 防止加速度数据标度因子的影响
        acc_avr     = acc_avr * G_m_s2 / mean_acc.norm(); // - state_inout.ba;
    
        if(head->header.stamp.toSec() < last_lidar_end_time_)
        {
          dt = tail->header.stamp.toSec() - last_lidar_end_time_;
          // dt = tail->header.stamp.toSec() - pcl_beg_time;
        }
        else
        {
          dt = tail->header.stamp.toSec() - head->header.stamp.toSec();
        }
        
        in.acc = acc_avr; // 加速度计平均值
        in.gyro = angvel_avr; // 陀螺仪平均值
        // 设置系统噪声
        // Q:12 * 12
        Q.block<3, 3>(0, 0).diagonal() = cov_gyr;
        Q.block<3, 3>(3, 3).diagonal() = cov_acc;
        Q.block<3, 3>(6, 6).diagonal() = cov_bias_gyr;
        Q.block<3, 3>(9, 9).diagonal() = cov_bias_acc;
        kf_state.predict(dt, Q, in); // 滤波预测过程
    
        /* save the poses at each IMU measurements */
        imu_state = kf_state.get_x();
        angvel_last = angvel_avr - imu_state.bg;
        acc_s_last  = imu_state.rot * (acc_avr - imu_state.ba);// 加速度转到导航系
        for(int i=0; i<3; i++)
        {
          acc_s_last[i] += imu_state.grav[i]; // 计算导航系比力
        }
        // offs_t:畸变时间
        double &&offs_t = tail->header.stamp.toSec() - pcl_beg_time;
        IMUpose.push_back(set_pose6d(offs_t, acc_s_last, angvel_last, imu_state.vel, imu_state.pos, imu_state.rot.toRotationMatrix()));
      }
    
      /*** calculated the pos and attitude prediction at the frame-end ***/
      double note = pcl_end_time > imu_end_time ? 1.0 : -1.0;
      dt = note * (pcl_end_time - imu_end_time); // dt > 0
      kf_state.predict(dt, Q, in);// 滤波预测过程
      
      imu_state = kf_state.get_x();
      last_imu_ = meas.imu.back();
      last_lidar_end_time_ = pcl_end_time;
    
      // 反向过程
      /*** undistort each lidar point (backward propagation) ***/
      if (pcl_out.points.begin() == pcl_out.points.end()) return;
      auto it_pcl = pcl_out.points.end() - 1;
      // 对于每一个imu位姿,找到一个对应的雷达位姿,该雷达时间戳比imu时间点大,并且满足最邻近,
      // 去求该雷达点时间戳所对应的位姿
      for (auto it_kp = IMUpose.end() - 1; it_kp != IMUpose.begin(); it_kp--)
      {
        auto head = it_kp - 1;
        auto tail = it_kp;
        R_imu<<MAT_FROM_ARRAY(head->rot);
        // cout<<"head imu acc: "<
        vel_imu<<VEC_FROM_ARRAY(head->vel);
        pos_imu<<VEC_FROM_ARRAY(head->pos);
        acc_imu<<VEC_FROM_ARRAY(tail->acc);
        angvel_avr<<VEC_FROM_ARRAY(tail->gyr);
        // 遍历一帧中的每一个雷达点
        // curvature:相对于一帧中第一个雷达点的时间
        // double &&offs_t = tail->header.stamp.toSec() - pcl_beg_time!!!
        // curvature = 
        // 由imu时间戳位置计算雷达时间戳位姿
        for(; it_pcl->curvature / double(1000) > head->offset_time; it_pcl --)
        {
          dt = it_pcl->curvature / double(1000) - head->offset_time; // dt > 0
    
          /* Transform to the 'end' frame, using only the rotation
           * Note: Compensation direction is INVERSE of Frame's moving direction
           * So if we want to compensate a point at timestamp-i to the frame-e
           * P_compensate = R_imu_e ^ T * (R_i * P_i + T_ei) where T_ei is represented in global frame */
          M3D R_i(R_imu * Exp(angvel_avr, dt)); // 最新的转换矩阵(IMU到导航坐标系)
          
          V3D P_i(it_pcl->x, it_pcl->y, it_pcl->z); // 没有去除畸变的激光雷达坐标(雷达坐标系)
          V3D T_ei(pos_imu + vel_imu * dt + 0.5 * acc_imu * dt * dt - imu_state.pos);
          // offset_T_L_I:IMU和雷达之间的杆臂
          // offset_R_L_I:IMU和雷达之间的安装角
          // imu_state.offset_R_L_I * P_i + imu_state.offset_T_L_I:转到IMU坐标系
          // (R_i * (imu_state.offset_R_L_I * P_i + imu_state.offset_T_L_I) + T_ei):
          // 
          V3D P_compensate = imu_state.offset_R_L_I.conjugate() * (imu_state.rot.conjugate() * (R_i * (imu_state.offset_R_L_I * P_i + imu_state.offset_T_L_I) + T_ei) - imu_state.offset_T_L_I);// not accurate!
          
          // save Undistorted points and their rotation
          // 去除畸变之后的激光雷达点云
          it_pcl->x = P_compensate(0);
          it_pcl->y = P_compensate(1);
          it_pcl->z = P_compensate(2);
    
          if (it_pcl == pcl_out.points.begin()) break;
        }
      }
    }
    
    // feats_undistort:运动畸变去除之后的点云数据
    // 对IMU数据进行预处理,其中包含了点云畸变处理 前向传播 反向传播
    void ImuProcess::Process(const MeasureGroup &meas,  esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, PointCloudXYZI::Ptr cur_pcl_un_)
    {
      double t1,t2,t3;
      t1 = omp_get_wtime();
    
      if(meas.imu.empty()) {return;};
      ROS_ASSERT(meas.lidar != nullptr);
    
      // 初始化,执行一次
      if (imu_need_init_)
      {
        /// The very first lidar frame
        // init_iter_num:计算陀螺仪零偏需要的IMU个数
        IMU_init(meas, kf_state, init_iter_num);
         
        imu_need_init_ = true;
        
        last_imu_   = meas.imu.back();
    
        state_ikfom imu_state = kf_state.get_x();
        // MAX_INI_COUNT:10
        if (init_iter_num > MAX_INI_COUNT)
        {
          // G_m_s2:广东重力加速度
          // norm:范数
          cov_acc *= pow(G_m_s2 / mean_acc.norm(), 2); // ?
          imu_need_init_ = false;
          // cov_acc覆盖??
          cov_acc = cov_acc_scale; // 设置加表噪声
          cov_gyr = cov_gyr_scale; // 设置陀螺仪噪声
          ROS_INFO("IMU Initial Done");
          // ROS_INFO("IMU Initial Done: Gravity: %.4f %.4f %.4f %.4f; state.bias_g: %.4f %.4f %.4f; acc covarience: %.8f %.8f %.8f; gry covarience: %.8f %.8f %.8f",\
          //          imu_state.grav[0], imu_state.grav[1], imu_state.grav[2], mean_acc.norm(), cov_bias_gyr[0], cov_bias_gyr[1], cov_bias_gyr[2], cov_acc[0], cov_acc[1], cov_acc[2], cov_gyr[0], cov_gyr[1], cov_gyr[2]);
          fout_imu.open(DEBUG_FILE_DIR("imu.txt"),ios::out);
        }
    
        return;
      }
    
      UndistortPcl(meas, kf_state, *cur_pcl_un_);
    
      t2 = omp_get_wtime();
      t3 = omp_get_wtime();
      
      // cout<<"[ IMU Process ]: Time: "<
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425

    3.use-ikfom.hpp

    #ifndef USE_IKFOM_H
    #define USE_IKFOM_H
    
    #include 
    
    typedef MTK::vect<3, double> vect3;
    typedef MTK::SO3<double> SO3;
    typedef MTK::S2<double, 98090, 10000, 1> S2; 
    typedef MTK::vect<1, double> vect1;
    typedef MTK::vect<2, double> vect2;
    
    // 状态向量(22维)
    // pos:位置
    // rot:欧拉角
    // offset_R_L_I:IMU和激光雷达之间的安装角(旋转矩阵)
    // offset_T_L_I:IMU和激光雷达之间的杆臂
    // vel:速度
    // bg:陀螺仪零偏
    // ba:加速度计零偏
    // grav:重力向量
    MTK_BUILD_MANIFOLD(state_ikfom,
    ((vect3, pos))
    ((SO3, rot))
    ((SO3, offset_R_L_I))
    ((vect3, offset_T_L_I))
    ((vect3, vel))
    ((vect3, bg))
    ((vect3, ba))
    ((S2, grav))
    );
    
    // 输入数据:加速度,陀螺仪
    // 增量形式?
    MTK_BUILD_MANIFOLD(input_ikfom,
    ((vect3, acc))
    ((vect3, gyro))
    );
    
    // IMU噪声
    MTK_BUILD_MANIFOLD(process_noise_ikfom,
    ((vect3, ng))
    ((vect3, na))
    ((vect3, nbg))
    ((vect3, nba))
    );
    
    // 设置系统噪声
    MTK::get_cov<process_noise_ikfom>::type process_noise_cov()
    {
    	MTK::get_cov<process_noise_ikfom>::type cov = MTK::get_cov<process_noise_ikfom>::type::Zero();
    	MTK::setDiagonal<process_noise_ikfom, vect3, 0>(cov, &process_noise_ikfom::ng, 0.0001);// 0.03
    	MTK::setDiagonal<process_noise_ikfom, vect3, 3>(cov, &process_noise_ikfom::na, 0.0001); // *dt 0.01 0.01 * dt * dt 0.05
    	MTK::setDiagonal<process_noise_ikfom, vect3, 6>(cov, &process_noise_ikfom::nbg, 0.00001); // *dt 0.00001 0.00001 * dt *dt 0.3 //0.001 0.0001 0.01
    	MTK::setDiagonal<process_noise_ikfom, vect3, 9>(cov, &process_noise_ikfom::nba, 0.00001);   //0.001 0.05 0.0001/out 0.01
    	return cov;
    }
    
    //double L_offset_to_I[3] = {0.04165, 0.02326, -0.0284}; // Avia 
    //vect3 Lidar_offset_to_IMU(L_offset_to_I, 3);
    // 函数功能:求系统微分方程(系统转换矩阵)
    // 备注:没有陀螺仪随机游走,以及加速度随机游走
    Eigen::Matrix<double, 24, 1> get_f(state_ikfom &s, const input_ikfom &in)
    {
    	Eigen::Matrix<double, 24, 1> res = Eigen::Matrix<double, 24, 1>::Zero();
    	vect3 omega;
    	// in.gyro:输入的陀螺仪数据
    	in.gyro.boxminus(omega, s.bg); // 陀螺仪数据减去零偏
    	// in.acc:输入的加速度数据
    	// 加速度数据转到导航坐标系
    	vect3 a_inertial = s.rot * (in.acc-s.ba); // 加速度数据减去零偏
    	for(int i = 0; i < 3; i++ ){
    		res(i) = s.vel[i]; // 位置微分方程(00-02:位置)
    		res(i + 3) =  omega[i]; // 欧拉角微分方程(03-05:欧拉角)
    		// 消除重力加速度
    		res(i + 12) = a_inertial[i] + s.grav[i]; // 速度微分方程(12-15:速度)
    	}
    	return res;
    }
    
    // 求雅可比矩阵:系统转换矩阵的雅可比矩阵
    // 参考论文《FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter》,公式(7)
    // 状态变量:
    // 00-02:位置
    // 03-05:欧拉角
    // 06-08:IMU和激光雷达之间的安装角(旋转矩阵)
    // 09-11:IMU和激光雷达之间的杆臂
    // 12-15:速度
    // 15-17:陀螺仪零偏
    // 18-20:加速度零偏
    // 21-23:重力向量
    // 备注:求偏导(分子->行号,分母->列号)
    Eigen::Matrix<double, 24, 23> df_dx(state_ikfom &s, const input_ikfom &in)
    {
    	Eigen::Matrix<double, 24, 23> cov = Eigen::Matrix<double, 24, 23>::Zero();
    	cov.template block<3, 3>(0, 12) = Eigen::Matrix3d::Identity(); // 位置对速度
    	vect3 acc_;
    	in.acc.boxminus(acc_, s.ba); // 加速度计数据减去零偏
    	vect3 omega;
    	in.gyro.boxminus(omega, s.bg); // 陀螺仪数据减去零偏
    	// 
    	cov.template block<3, 3>(12, 3) = -s.rot.toRotationMatrix()*MTK::hat(acc_); //速度对欧拉角
    	cov.template block<3, 3>(12, 18) = -s.rot.toRotationMatrix(); // 速度对加速度零偏
    	Eigen::Matrix<state_ikfom::scalar, 2, 1> vec = Eigen::Matrix<state_ikfom::scalar, 2, 1>::Zero();
    	Eigen::Matrix<state_ikfom::scalar, 3, 2> grav_matrix;
    	// grav_matrix:0
    	s.S2_Mx(grav_matrix, vec, 21);
    	cov.template block<3, 2>(12, 21) =  grav_matrix; // 速度对
    	// 以下公式和论文不一致 
    	cov.template block<3, 3>(3, 15) = -Eigen::Matrix3d::Identity(); // 欧拉角对陀螺仪零偏??
    	return cov;
    }
    
    // 求雅可比矩阵:噪声转换矩阵的雅可比矩阵
    // 参考论文《FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter》,公式(7)
    // 设定固定不变的值
    // 状态变量:
    // 00-02:位置
    // 03-05:欧拉角
    // 06-08:IMU和激光雷达之间的安装角(旋转矩阵)
    // 09-11:IMU和激光雷达之间的杆臂
    // 12-15:速度
    // 15-17:陀螺仪零偏
    // 18-20:加速度零偏
    // 21-23:重力向量
    Eigen::Matrix<double, 24, 12> df_dw(state_ikfom &s, const input_ikfom &in)
    {
    	Eigen::Matrix<double, 24, 12> cov = Eigen::Matrix<double, 24, 12>::Zero();
    	cov.template block<3, 3>(12, 3) = -s.rot.toRotationMatrix();  // 速度对加速度零偏的偏导
    	cov.template block<3, 3>(3, 0) = -Eigen::Matrix3d::Identity(); // 欧拉角对陀螺仪零偏的偏导
    	cov.template block<3, 3>(15, 6) = Eigen::Matrix3d::Identity(); // 陀螺零偏对陀螺仪随机游走噪声
    	cov.template block<3, 3>(18, 9) = Eigen::Matrix3d::Identity(); // 加速度零偏对加速度计随机游走噪声
    	return cov;
    }
    
    // 旋转矩阵转欧拉角:噪声转换矩阵的雅可比矩阵
    vect3 SO3ToEuler(const SO3 &orient) 
    {
    	Eigen::Matrix<double, 3, 1> _ang;
    	Eigen::Vector4d q_data = orient.coeffs().transpose();
    	//scalar w=orient.coeffs[3], x=orient.coeffs[0], y=orient.coeffs[1], z=orient.coeffs[2];
    	double sqw = q_data[3]*q_data[3];
    	double sqx = q_data[0]*q_data[0];
    	double sqy = q_data[1]*q_data[1];
    	double sqz = q_data[2]*q_data[2];
    	double unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise is correction factor
    	double test = q_data[3]*q_data[1] - q_data[2]*q_data[0];
    
    	if (test > 0.49999*unit) { // singularity at north pole
    	
    		_ang << 2 * std::atan2(q_data[0], q_data[3]), M_PI/2, 0;
    		double temp[3] = {_ang[0] * 57.3, _ang[1] * 57.3, _ang[2] * 57.3};
    		vect3 euler_ang(temp, 3);
    		return euler_ang;
    	}
    	if (test < -0.49999*unit) { // singularity at south pole
    		_ang << -2 * std::atan2(q_data[0], q_data[3]), -M_PI/2, 0;
    		double temp[3] = {_ang[0] * 57.3, _ang[1] * 57.3, _ang[2] * 57.3};
    		vect3 euler_ang(temp, 3);
    		return euler_ang;
    	}
    		
    	_ang <<
    			std::atan2(2*q_data[0]*q_data[3]+2*q_data[1]*q_data[2] , -sqx - sqy + sqz + sqw),
    			std::asin (2*test/unit),
    			std::atan2(2*q_data[2]*q_data[3]+2*q_data[1]*q_data[0] , sqx - sqy - sqz + sqw);
    	double temp[3] = {_ang[0] * 57.3, _ang[1] * 57.3, _ang[2] * 57.3};
    	vect3 euler_ang(temp, 3);
    		// euler_ang[0] = roll, euler_ang[1] = pitch, euler_ang[2] = yaw
    	return euler_ang;
    }
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172

  • 相关阅读:
    跨域解决方案
    消息队列(MQ)的简单介绍
    第一批吃螃蟹的人:浙大全日制英文MBA复试经验分享
    android崩溃系列-崩溃原理分析
    从原理和源码理解Vue3的响应式机制
    JAVA面试题----------抽象类和接口的区别
    前端三件套 HTML+CSS+JS基础知识内容笔记
    SpringMVC入门
    学习open62541 --- [66] UA_String的生成方法
    【随想录】-【8 回溯算法】【组合问题】40 组合总和Ⅱ
  • 原文地址:https://blog.csdn.net/waihekor/article/details/127780369