当前位置:网站首页>FAST-LIO2代码解析(二)
FAST-LIO2代码解析(二)
2022-08-01 23:34:00 【Hermit_Rabbit】
0. 简介
在上文中讲述了激光雷达的数据获取以及特征点提取的操作,这一节我们将围绕着IMU_Processing这一节来进行介绍。
1. ImuProcess类定义
在ImuProcess.hpp中,一开始就是完成了对ImuProcess类的申明,里面我们可以看到在imu中最主要的还是角速度和加速度这两项特征,这与视觉SLAM的imu融合非常相似。
//判断点的时间是否先后颠倒
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; // 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; // lidar到IMU的旋转外参
V3D Lidar_T_wrt_IMU; // lidar到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; //初始化迭代次数
bool b_first_frame_ = true; //是否是第一帧
bool imu_need_init_ = true; //是否需要初始化imu
};
2. 构造函数与传入函数
首先就是调用初始化的构造函数和重置函数。
ImuProcess::ImuProcess()
: b_first_frame_(true), imu_need_init_(true), start_timestamp_(-1)
{
init_iter_num = 1; //初始化迭代次数
Q = process_noise_cov(); //调用use-ikfom.hpp里面的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到IMU的位置外参初始化
Lidar_R_wrt_IMU = Eye3d; // lidar到IMU的旋转外参初始化
last_imu_.reset(new sensor_msgs::Imu()); //上一帧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; //是否需要初始化imu
start_timestamp_ = -1; //开始时间戳
init_iter_num = 1; //初始化迭代次数
v_imu_.clear(); // imu队列清空
IMUpose.clear(); // imu位姿清空
last_imu_.reset(new sensor_msgs::Imu()); //上一帧imu初始化
cur_pcl_un_.reset(new PointCloudXYZI()); //当前帧点云未去畸变初始化
}
然后就是外参和偏置协方差的传入
//传入外参,包含R,T
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);
}
//传入外参,包含T
void ImuProcess::set_extrinsic(const V3D &transl)
{
Lidar_T_wrt_IMU = transl;
Lidar_R_wrt_IMU.setIdentity();
}
// 传入外参,包含R,T
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;
}
3. IMU初始化
这一部分主要是IMU的初始化,内部主要是对x_和P_完成了初始化,这里涉及到esikfom文件内部的知识,这里暂且先不讲
void ImuProcess::IMU_init(const MeasureGroup &meas, esekfom::esekf<state_ikfom, 12, input_ikfom> &kf_state, int &N)
{
/** 1. 初始化重力、陀螺偏差、acc和陀螺仪协方差 /** 2. 将加速度测量值标准化为单位重力**/
//这里应该是静止初始化
V3D cur_acc, cur_gyr;
if (b_first_frame_) //判断是否为第一帧
{
Reset(); //重置参数
N = 1; //将迭代次数置1
b_first_frame_ = false;
const auto &imu_acc = meas.imu.front()->linear_acceleration; //从common_lib.h中拿到imu初始时刻的加速度
const auto &gyr_acc = meas.imu.front()->angular_velocity; //从common_lib.h中拿到imu初始时刻的角速度
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; //将当期imu帧对应的lidar时间作为初始时间
}
//计算方差
for (const auto &imu : meas.imu) //拿到所有的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()对应系数相乘
//每次迭代之后均值都会发生变化,最后的方差公式中减的应该是最后的均值
// https://blog.csdn.net/weixin_44479136/article/details/90510374 方差迭代计算公式
//按照博客推导出来的下面方差递推公式有两种
//第一种是
cov_acc = cov_acc * (N - 1.0) / N + (cur_acc - mean_acc).cwiseProduct(cur_acc - mean_acc) / (N - 1.0);
cov_gyr = cov_gyr * (N - 1.0) / N + (cur_gyr - mean_gyr).cwiseProduct(cur_gyr - mean_gyr) / (N - 1.0);
//第二种是
// cov_acc = cov_acc * (N - 1.0) / N + (cur_acc - mean_acc).cwiseProduct(cur_acc - 上一次的mean_acc) / N;
// cov_gyr = cov_gyr * (N - 1.0) / N + (cur_gyr - mean_gyr).cwiseProduct(cur_gyr - 上一次的mean_gyr) / N;
// cout<<"acc norm: "<<cur_acc.norm()<<" "<<mean_acc.norm()<<endl;
N++;
}
state_ikfom init_state = kf_state.get_x(); //在esekfom.hpp获得x_的状态
init_state.grav = S2(-mean_acc / mean_acc.norm() * G_m_s2); //从common_lib.h中拿到重力,并与加速度测量均值的单位重力求出SO2的旋转矩阵类型的重力加速度
// 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; //将lidar和imu外参位移量传入
init_state.offset_R_L_I = Lidar_R_wrt_IMU; //将lidar和imu外参旋转量传入
kf_state.change_x(init_state); //将初始化状态传入esekfom.hpp中的x_
esekfom::esekf<state_ikfom, 12, input_ikfom>::cov init_P = kf_state.get_P(); //在esekfom.hpp获得P_的协方差矩阵
init_P.setIdentity(); //将协方差矩阵置为单位阵
init_P(6, 6) = init_P(7, 7) = init_P(8, 8) = 0.00001; //将协方差矩阵的位置和旋转的协方差置为0.00001
init_P(9, 9) = init_P(10, 10) = init_P(11, 11) = 0.00001; //将协方差矩阵的速度和位姿的协方差置为0.00001
init_P(15, 15) = init_P(16, 16) = init_P(17, 17) = 0.0001; //将协方差矩阵的重力和姿态的协方差置为0.0001
init_P(18, 18) = init_P(19, 19) = init_P(20, 20) = 0.001; //将协方差矩阵的陀螺仪偏差和姿态的协方差置为0.001
init_P(21, 21) = init_P(22, 22) = 0.00001; //将协方差矩阵的lidar和imu外参位移量的协方差置为0.00001
kf_state.change_P(init_P); //将初始化协方差矩阵传入esekfom.hpp中的P_
last_imu_ = meas.imu.back(); //将最后一帧的imu数据传入last_imu_中,暂时没用到
}
4. IMU更新
在UndistortPcl函数中不但有IMU的前向信息,还有激光雷达去畸变的问题,这一节我们围绕着IMU的正向传播展开,代码中通过迭代的形式完成了IMU数据的更新,并将acc和gyro的数据传入到ESKF中,详细的公式我们后面再来讲。
…详情请参照古月居
边栏推荐
- problem solved
- The third chapter of the imitation cattle network project: develop the core functions of the community (detailed steps and ideas)
- numpy.hstack
- DRF generating serialization class code
- 6134. Find the closest node to the given two nodes - force double hundred code
- Is TCP reliable?Why?
- Solve the port to take up
- 辛普森悖论
- 程序员如何优雅地解决线上问题?
- Flink学习第三天——一文带你了解什么是Flink流?
猜你喜欢

C语言——分支语句和循环语句

y84. Chapter 4 Prometheus Factory Monitoring System and Actual Combat -- Advanced Prometheus Alarm Mechanism (15)

Making a Simple 3D Renderer

请问什么是 CICD

Deep Learning Fundamentals - Numpy-based Recurrent Neural Network (RNN) implementation and backpropagation training

E - Integer Sequence Fair

Codeforces CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-D Solution
![Thesis understanding [RL - Exp Replay] - Experience Replay with Likelihood-free Importance Weights](/img/f1/9824f32dd4fe4b3e94af3f945b1801.png)
Thesis understanding [RL - Exp Replay] - Experience Replay with Likelihood-free Importance Weights
![[C language advanced] file operation (2)](/img/4d/49d9603aeed16f1600d69179477eb3.png)
[C language advanced] file operation (2)

Is TCP reliable?Why?
随机推荐
CDH6的Hue打开出现‘ascii‘ codec can‘t encode characters
如何使用pywinauto和pyautogui将动漫小姐姐链接请回家
计算由两点定义的线的角度
用virtualenv和Virtualenvwrapper虚拟环境管理工具创建虚拟环境
numpy.around
解决端口占用
IDEA common plugins
最短路模板
程序员还差对象?new一个就行了
excel change cell size
The third chapter of the imitation cattle network project: develop the core functions of the community (detailed steps and ideas)
qt-faststart installation and use
Thesis understanding [RL - Exp Replay] - Experience Replay with Likelihood-free Importance Weights
【C语言进阶】文件操作(二)
System availability: 3 9s, 4 9s in SRE's mouth... What is it?
计算两点之间的距离
DRF generating serialization class code
论文理解【RL - Exp Replay】—— Experience Replay with Likelihood-free Importance Weights
Calculate the angle of a line defined by two points
斜堆、、、