从零入门激光SLAM(二十二)——Fast-lio2代码详解(三) 迭代误差更新

Fast-lio2原理解析见链接
从零入门激光SLAM(二十一)——看不懂FAST-LIO?进来_fastlio 雷达 更改频率-CSDN博客
注释版代码完整版见
GitHub - huashu996/Fast-lio2-Supernote: Fast-lio2 code with note
本代码解析以算法流程的逻辑解析代码,一些简单的函数忽略讲解。

一、误差迭代更新

1.1 整体框架

迭代更新流程:输出修正结果、更新状态、发布里程计信息以及将特征点添加到地图

   /*** iterated state estimation ***///计算欧拉角并输出预测结果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; //输出预测的结果//记录更新开始时间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 = 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将特征点添加到地图 KD 树 ***/t3 = omp_get_wtime();map_incremental();t5 = omp_get_wtime();/******* Publish points发布点云数据 *******/if (1)                         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);

1.2 迭代更新

初始化动态共享数据结构,用于在迭代过程中共享数据和控制迭代过程。 初始化传播后的状态和协方差,以准备在后续的滤波步骤中使用。
定义并初始化卡尔曼增益矩阵,以用于后续的卡尔曼滤波计算。
初始化状态增量向量,用于存储新的状态增量。

  void update_iterated_dyn_share_modified(double R, double &solve_time) {1.初始化//动态共享数据结构的初始化:dyn_share_datastruct<scalar_type> dyn_share; // 定义一个名为 dyn_share 的动态共享数据结构 dyn_share.valid = true; //表示数据有效dyn_share.converge = true; //表示迭代过程已经收敛//变量初始化int t = 0; //用于记录迭代次数state x_propagated = x_; //初始化当前状态 x_,表示传播后的状态cov P_propagated = P_; //初始化当前的协方差 P_,表示传播后的协方差int dof_Measurement; //用于表示测量的自由度//卡尔曼增益矩阵的初始化Matrix<scalar_type, n, 1> K_h;Matrix<scalar_type, n, n> K_x; //定义 dx_new 并初始化为零向量,用于存储新的状态增量vectorized_state dx_new = vectorized_state::Zero();//2.迭代循环for(int i=-1; i<maximum_iter; i++){//共享数据结构的初始化和检查dyn_share.valid = true;    //观测模型h_dyn_share(x_, dyn_share);if(! dyn_share.valid){continue; }//获取观测矩阵 h_x_ 矩阵用于存储观测模型的雅可比矩阵//Matrix<scalar_type, Eigen::Dynamic, 1> h = h_dyn_share(x_, dyn_share);#ifdef USE_sparsespMt h_x_ = dyn_share.h_x.sparseView();#elseEigen::Matrix<scalar_type, Eigen::Dynamic, 12> h_x_ = dyn_share.h_x;#endif//记录时间起始点和测量自由度double solve_start = omp_get_wtime();dof_Measurement = h_x_.rows();//状态增量计算vectorized_state dx;//前状态 x_ 与传播状态 x_propagated 之间的增量 dxx_.boxminus(dx, x_propagated);dx_new = dx;//初始化协方差矩阵 P_ 为传播后的协方差 P_propagatedP_ = P_propagated;//SO3状态更新Matrix<scalar_type, 3, 3> res_temp_SO3;MTK::vect<3, scalar_type> seg_SO3;for (std::vector<std::pair<int, int> >::iterator it = x_.SO3_state.begin(); it != x_.SO3_state.end(); it++) {int idx = (*it).first;int dim = (*it).second;for(int i = 0; i < 3; i++){seg_SO3(i) = dx(idx+i);}res_temp_SO3 = MTK::A_matrix(seg_SO3).transpose();dx_new.template block<3, 1>(idx, 0) = res_temp_SO3 * dx_new.template block<3, 1>(idx, 0);for(int i = 0; i < n; i++){P_. template block<3, 1>(idx, i) = res_temp_SO3 * (P_. template block<3, 1>(idx, i));    }for(int i = 0; i < n; i++){P_. template block<1, 3>(i, idx) =(P_. template block<1, 3>(i, idx)) *  res_temp_SO3.transpose();    }}//S2状态更新Matrix<scalar_type, 2, 2> res_temp_S2;MTK::vect<2, scalar_type> seg_S2;for (std::vector<std::pair<int, int> >::iterator it = x_.S2_state.begin(); it != x_.S2_state.end(); it++) {int idx = (*it).first;int dim = (*it).second;for(int i = 0; i < 2; i++){seg_S2(i) = dx(idx + i);}Eigen::Matrix<scalar_type, 2, 3> Nx;Eigen::Matrix<scalar_type, 3, 2> Mx;x_.S2_Nx_yy(Nx, idx);x_propagated.S2_Mx(Mx, seg_S2, idx);res_temp_S2 = Nx * Mx; dx_new.template block<2, 1>(idx, 0) = res_temp_S2 * dx_new.template block<2, 1>(idx, 0);for(int i = 0; i < n; i++){P_. template block<2, 1>(idx, i) = res_temp_S2 * (P_. template block<2, 1>(idx, i));    }for(int i = 0; i < n; i++){P_. template block<1, 2>(i, idx) = (P_. template block<1, 2>(i, idx)) * res_temp_S2.transpose();}}//状态维数大于测量自由度时的计算卡尔曼增益if(n > dof_Measurement){//创建一个大小为dof_Measurement×n 的零矩阵h_x_curEigen::Matrix<scalar_type, Eigen::Dynamic, Eigen::Dynamic> h_x_cur = Eigen::Matrix<scalar_type, Eigen::Dynamic, Eigen::Dynamic>::Zero(dof_Measurement, n);//将 h_x_ 矩阵的前 12 列复制到 h_x_cur 中的左上角h_x_cur.topLeftCorner(dof_Measurement, 12) = h_x_;//计算卡尔曼增益矩阵KMatrix<scalar_type, Eigen::Dynamic, Eigen::Dynamic> K_ = P_ * h_x_cur.transpose() * (h_x_cur * P_ * h_x_cur.transpose()/R + Eigen::Matrix<double, Dynamic, Dynamic>::Identity(dof_Measurement, dof_Measurement)).inverse()/R;//计算增益矩阵 K_h 和 K_x//dyn_share.h 表示测量残差K_h = K_ * dyn_share.h;K_x = K_ * h_x_cur;}//状态维数小于测量自由度时的计算卡尔曼增益

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#面:如果不用VisualStudio,用哪个命令行编译C#程序

可以使用命令提示符或者终端来执行编译命令 csc.exe 。 步骤&#xff1a; 打开命令提示符或终端。使用 cd 切换到 C# 程序所在的目录。使用以下命令来编译C#程序&#xff1a; 其中&#xff0c;是你的C#源代码文件的名称&#xff08;包括扩展名.cs&#xff09;。如果编译成功&…

ONLYOFFICE 协作空间与 WordPress 如何集成

转载自作者&#xff1a;VincentYoung&#xff0c;略有改动 阅读本文&#xff0c;了解如何将 ONLYOFFICE 协作空间与 WordPress 进行集成。 ONLYOFFICE 协作空间是其去年新推出的产品&#xff0c;用创建虚拟办公室房间的方式&#xff0c;来组织公司内部团队成员的在线协作办公&…

C++中的双指针和三指针

目录 摘要 双指针&#xff08;Double Pointers&#xff09; 含义 使用场景 三指针&#xff08;Triple Pointers&#xff09; 含义 使用场景 总结 双指针的详细说明 三指针的详细说明 摘要 在C中&#xff0c;双指针和三指针分别是指向指针的指针和指向指向指针的指针…

C. Swap Adjacent Elements 题解

C. Swap Adjacent Elements 题解 S A E 题目大意思路代码题目大意 输入格式: 第一行一个整数 n n n ( 2 ≤ (2≤ (2≤ n n n ≤ 200000 ) ≤200000) ≤200000) 第二行 n个整数 a 1 a_1 a1​, a 2 a_2 a2​

redis 允许外网访问

要使Redis服务器允许外网访问&#xff0c;可以遵循以下步骤进行配置&#xff1a; 编辑Redis配置文件&#xff1a; 找到Redis的配置文件&#xff0c;通常位于/etc/redis/redis.conf&#xff0c;但位置可能因安装方式和操作系统而异。取消绑定本地地址&#xff1a;在配置文件中&a…

Charles-ios无法抓包原因之一证书

VPN证书安装完成后依然无法抓包存在无网络问题 VPN安装证书后直接抓包这时候抓包接口返回无网络&#xff0c;原因是IOS通用-关于本机-证书信任设计未开启信任

webpack5零基础入门-19HMR的应用

1.定义 HMR即HotModuleReplacement 开发时&#xff0c;当我们修改了其中一个模块的代码webpack默认会将所有模块重新打包编译&#xff0c;速度很慢所以我们需要做到修改摸个模块代码&#xff0c;只对这个模块的代码重新打包编译&#xff0c;其他模块不变&#xff0c;这样打包…

elementUI dialog 组件二次封装 before-close 回调函数作用

before-close 弹框关闭前的回调函数&#xff0c;父组件可以向子组件传递一个函数&#xff0c;用于修改子组件内的变量变量。应用场景如下&#xff1a; 1、封装 dialog 组件为 baseDialog&#xff0c;页面中使用 baseDialog 组件。 2、封装 dialog 组件为 baseDialog&#xff…

OpenAI和Anthropic在人工智能领域各自进行着不同的工作,以下是对它们工作内容的清晰归纳

OpenAI和Anthropic在人工智能领域各自进行着不同的工作&#xff0c;以下是对它们工作内容的清晰归纳&#xff1a; OpenAI&#xff1a; 公司背景与使命&#xff1a; 成立于2015年12月11日&#xff0c;总部位于美国旧金山。是一家由营利性公司OpenAI LP及非营利性母公司OpenAI …

ubuntu20.04部署gitlab流程

参考&#xff1a; https://blog.csdn.net/weixin_57025326/article/details/136048507 362 wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/ubuntu/focal/gitlab-ce_16.2.1-ce.0_amd64.deb/download.deb367 sudo apt install gitlab-ce…

初识Spring Boot:构建项目结构与组件解析

目录 前言 第一点&#xff1a;项目的结构 第二点&#xff1a;controller类的创建与使用&#xff08;构造器&#xff09; 第二点&#xff1a;service类的创建与使用&#xff08;逻辑层&#xff09; 第三点&#xff1a;Mapper类的创建与使用(数据操作) 总结 前言 在进行Sp…

【稳定检索】2024年心理学与现代化教育、媒体国际会议(PMEM 2024)

2024年心理学与现代化教育、媒体国际会议 2024 International Conference on Psychology and Modern Education and Media 【1】会议简介 2024年心理学与现代化教育、媒体国际会议即将召开&#xff0c;这是一场汇聚全球心理学、教育及媒体领域精英的学术盛宴。 本次会议将深入探…

目前最强的AI绘画工具 DALL-E、Stable Diffusion 和 Midjourney工具对比

大家好&#xff0c;我是AIGC的实践者SKY&#xff0c;今天和大家来聊聊DALL-E、Stable Diffusion和Midjourney。 随着人工智能技术的飞速发展&#xff0c;艺术生成工具如DALL-E、Stable Diffusion和Midjourney等&#xff0c;已经成为创意产业的新宠。这些工具利用深度学习算法&…

618适合入手哪些数码好物?实用数码好物清单分享,错过拍烂大腿!

在一年一度的618购物狂欢节里&#xff0c;许多数码爱好者们都在这次盛大的购物盛宴中觅得心仪的数码好物&#xff0c;数码产品不仅改变了我们的生活方式&#xff0c;更让我们享受到了前所未有的便捷和乐趣&#xff0c;那么在这个618&#xff0c;哪些数码好物值得我们入手呢&…

ER图介绍

在数据库设计和建模中&#xff0c;实体-关系图&#xff08;Entity-Relationship Diagram&#xff0c;简称ER图&#xff09;是一个至关重要的工具。ER图通过图形化的方式描述了现实世界中的实体&#xff08;Entity&#xff09;及其之间的关系&#xff08;Relationship&#xff0…

Java实战入门:深入解析Java中的`String.split`方法

文章目录 一、方法定义参数说明返回值 二、使用场景三、实现原理无限制分割限制分割 四、示例代码示例一&#xff1a;基本分割示例二&#xff1a;使用正则表达式分割示例三&#xff1a;限制分割次数示例四&#xff1a;保留空字符串 五、注意事项六、总结 在Java编程中&#xff…

oracle中的INTERVAL函数学习总结

Oracle 从9i数据库开始引入了一种新特性&#xff0c;可以用来存储时间间隔&#xff0c;出现了INTERVAL 函数。这个函数的表达式比较多&#xff0c;初学比较费劲不好掌握&#xff0c;经过以几个小时的查阅资料和实验&#xff0c;总结如下&#xff1a; interval year t…

python绘制北京汽车流量热力图:从原理到实践

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、热力图绘制原理 三、热力图绘制实践 1. 数据准备 2. 地图组件选择 3. 数据…

建WordPress主题官网模板

蓝色的中文WordPress企业模板 https://www.zhanyes.com/qiye/6305.html 暗红色WordPress律师事务所网站模板 https://www.zhanyes.com/qiye/23.html 红色大banner图WordPress外贸网站模板 https://www.zhanyes.com/waimao/27.html

显示器控制变频器编程软件:深入探索与实用指南

显示器控制变频器编程软件&#xff1a;深入探索与实用指南 在工业自动化日益发展的今天&#xff0c;显示器控制变频器编程软件以其高效、直观的特点&#xff0c;成为控制电机转速和工作模式的关键工具。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;对这一技术…