当前位置:网站首页>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中,详细的公式我们后面再来讲。
…详情请参照古月居
边栏推荐
- Background project Express-Mysql-Vue3-TS-Pinia page layout-sidebar menu
- Create virtual environments with virtualenv and Virtualenvwrapper virtual environment management tools
- 用virtualenv和Virtualenvwrapper虚拟环境管理工具创建虚拟环境
- perspectiveTransform warpPerspective getPerspectiveTransform findHomography
- 在CDH的hue上的oozie出现,提交 Coordinator My Schedule 时出错
- SQL Server (design database--stored procedure--trigger)
- How do programmers solve online problems gracefully?
- 加载字体时避免隐藏文本
- 6132. All the elements in the array is equal to zero - quick sort method
- excel edit a cell without double clicking
猜你喜欢
[Camp Experience Post] 2022 Cybersecurity Summer Camp
C语言——分支语句和循环语句
The third chapter of the imitation cattle network project: develop the core functions of the community (detailed steps and ideas)
企业防护墙管理,有什么防火墙管理工具?
Codeforces CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-D Solution
请问什么是 CICD
chrome复制一张图片的base64数据
分享10套开源免费的高品质源码,免费源码下载平台
E - Integer Sequence Fair
从0到1:图文投票小程序设计与研发笔记
随机推荐
Deep Learning Fundamentals - Numpy-based Recurrent Neural Network (RNN) implementation and backpropagation training
计算两点之间的中点
What is CICD excuse me
How to use pywinauto and pyautogui to link the anime lady and sister please go home
6134. Find the closest node to the given two nodes - force double hundred code
CF1703G Good Key, Bad Key
qt-faststart installation and use
[LeetCode304 Weekly Competition] Two questions about the base ring tree 6134. Find the closest node to the given two nodes, 6135. The longest cycle in the graph
还在纠结报表工具的选型么?来看看这个
简单3D渲染器的制作
Making a Simple 3D Renderer
Access the selected node in the console
添加大量元素时使用 DocumentFragments
Chapter 12 End-User Task As Shell Scripts
C语言——分支语句和循环语句
分享10套开源免费的高品质源码,免费源码下载平台
Leetcode 129求根节点到叶节点数字之和、104二叉树的最大深度、8字符串转换整数(atoi)、82删除排序链表中的重复元素II、204二分查找、94二叉树的中序遍历、144二叉树的前序遍历
Flink学习第四天——完成第一个Flink 流批一体案例
ICLR 2022最佳论文:基于对比消歧的偏标签学习
The third chapter of the imitation cattle network project: develop the core functions of the community (detailed steps and ideas)