FAST-LIO2代码解析(六)

article/2025/10/7 8:04:18

0. 简介

上一节我们将while内部的IKD-Tree部分全部讲完,下面将是最后一部分,关于后端优化更新的部分。

1. 迭代更新

最后一块主要做的就是,拿当前帧与IKD-Tree建立的地图算出的残差,然后去计算更新自己的位置,并将更新后的结果通过map_incremental函数插入到由ikd-Tree表示的映射中。

// 外参,旋转矩阵转欧拉角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)"{// 释放PCL_Storage的内存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();/*** 迭代状态估计 ***/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(pubOdomAftMapped);/*** 向映射kdtree添加特性点 ***/t3 = omp_get_wtime();map_incremental();t5 = omp_get_wtime();/******* 发布轨迹和点 *******/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_frame_lidar(pubLaserCloudFull_lidar);}// publish_effect_world(pubLaserCloudEffect);// publish_map(pubLaserCloudMap);/*** Debug 参数 ***/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;        // kdtree增量时间s_plot4[time_log_counter] = kdtree_search_time;             // kdtree搜索耗时s_plot5[time_log_counter] = kdtree_delete_counter;          // kdtree删除点数量s_plot6[time_log_counter] = kdtree_delete_time;             // kdtree删除耗时s_plot7[time_log_counter] = kdtree_size_st;                 // kdtree初始大小s_plot8[time_log_counter] = kdtree_size_end;                // kdtree结束大小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;
}

前面获取的传播状态 x k ^ \hat{x_k} xk^和协方差 P k ^ \hat{P_k} Pk^对未知状态 x k x_k xk施加了一个先验高斯分布。具体来说, P k ^ \hat{P_k} Pk^表示以下误差状态的协方差:
在这里插入图片描述
式中,Jκ为 ( x ^ k π 田 x ^ k κ ) 日 x ^ k ( \widehat {x}_ {k}^ {\pi } 田 \widehat {x}_ {k}^ {\kappa } )日 \widehat {x} k (x kπx kκ)x k x ^ k k \hat{x}^k_k x^kk=0处的偏微分。
在这里插入图片描述
式中, A ( . ) − 1 A(.)^{-1} A(.)1 定义于公式(6),如下。
在这里插入图片描述
如下的 δ G θ I k δ^Gθ_{I_k} δGθIk δ I θ L k δ^Iθ{L_k} δIθLk分别为IMU的姿态和转动的误差状态。

在这里插入图片描述
对于第一次迭代(以拓展的卡尔曼滤波器为例),有 x k κ ^ = x k \hat{x^κ_k} =x_k xkκ^=xk, J κ = I J_κ =I Jκ=I

除了先验分布外,我们也有一个源于测量(8)的状态分布:
在这里插入图片描述
结合(10)的先验分布和(12)的测量模型,可得到状态 x k x_k xk的后验分布,其等价表示为 x k k x^k_k xkk及其最大后验估计:
在这里插入图片描述
式中,有 ∣ ∣ x ∣ ∣ M 2 = x T M − 1 x ||x||^2_M = x^TM^{−1} x ∣∣xM2=xTM1x。该最大后验估计问题可由下面的迭代卡尔曼滤波器解决:
在这里插入图片描述
需注意,卡尔曼增益K计算需要对状态维数矩阵求逆,而不是在之前的工作中使用的测量维数矩阵。上述过程将重复进行,直到收敛(即 ∣ ∣ x κ ( k + 1 ) 日 x k κ ∣ ∣ < ||x_κ^{(k+1)} 日 x^κ_k||< ∣∣xκ(k+1)xkκ∣∣<无穷小)。收敛后的最优状态和协方差估计为:
在这里插入图片描述
通过状态更新 x k x_k xk,第k次扫描中的每个LiDAR点(Lpj)将通过(16)被转换到全局框架:
在这里插入图片描述
转换后的LiDAR点{Gp¯j}将被插入到由ikd-Tree表示的映射中。我们的状态估计在算法1中进行了总结。

在这里插入图片描述

…详情请参照古月居


http://chatgpt.dhexx.cn/article/MKVyu3Ln.shtml

相关文章

DeblurGAN-V2源代码解析

DeblurGAN-V2源代码解析&#xff08;pytorch&#xff09; DeblurGAN-V2是DeblurGAN的改进版&#xff0c;主要解决的是去图像运动模糊的问题&#xff0c;相比于DeblurGAN而言有速度更快&#xff0c;效果更好的优点。 论文&#xff1a;https://arxiv.org/pdf/1908.03826.pdf 代码…

mmsegmentation模型生成代码解析

前言 疫情在家办公&#xff0c;新Team这边习惯用MMLab开发网络&#xff0c;正好趁这段时间理解一下商汤大佬们的框架。我之前其实网络开发的比较少&#xff0c;主要是学习用的&#xff0c;而且开发网络基本是靠手写或者copy&#xff0c;用这种架构开发我是十分赞成的&#xff…

PX4代码解析(1)

前言 做pixhawk飞控有一段时间了&#xff0c;但在学习过程中遇到许多困难&#xff0c;目前网上找不到比较完整的PX4学习笔记&#xff0c;我打算结合自己理解&#xff0c;写写自己对PX4源码的理解&#xff0c;不一定对&#xff0c;只是希望与各位大佬交流交流&#xff0c;同时梳…

PX4代码解析(2)

前言 在大致了解PX4代码架构后&#xff0c;我们需要了解PX4的通信机制。在PX4代码架构中&#xff0c;每通信总线主要分为两个部分&#xff0c;一是内部通信总线uORB,即PX4内部进程通信采用的协议&#xff0c;例如PX4内部姿态控制需要获取飞行器姿态&#xff0c;而飞行器姿态是…

Teams Bot App 代码解析

上一篇文章我们讲了如何使用 teams toolkit 来快速弄一个 teams bot&#xff0c;可以看到 toolkit 给我们提供了极大的方便性&#xff0c;让开发人员可以更好的把重心放在 coding 上&#xff0c;而不是各种配置上。 那我们这篇文章主要接着上篇&#xff0c;来解析一下 teams b…

代码分析(一)

2021SCSDUSC 分析前言 对于APIJSON的代码分析首先就是&#xff0c;看一下该项目的作用以及如何进行&#xff0c;看一下原来不部署这个项目的正常流程&#xff1a; 再来看一下部署上APIJSON后项目的流程走向&#xff1a; 接下来开始按照这个流程对相应的代码进行分析。 Abst…

Linux命令之lsusb

一、lsusb命令用于显示本机的USB设备列表&#xff0c;以及USB设备的详细信息。 二、lsusb命令显示的USB设备信息来自“/proc/bus/usb”目录下的对应文件。 三、Linux从/var/lib/usbutils/usb.ids识别USB设备的详细信息。 语法格式 lsusb [参数] 常用参数&#xff1a; -v显…

Linux命令-磁盘管理-lsusb

1 需求 2 语法 C:\>adb shell lsusb --help Toybox 0.8.4-android multicall binary: https://landley.net/toybox (see toybox --help)usage: lsusbList USB hosts/devices. 3 示例 adb shell lsusb 4 参考资料

嵌入式debian没有lsusb命令解决

问题 -bash: lsusb: command not found 解决

linux之lsusb命令和cd -命令使用总结

1、lsusb命令介绍 使用 lsusb 来列出 USB 设备和它的属性,lsusb 会显示驱动和内部连接到你系统的设备。直接在控制台输入 lsusb 即可 2、lsusb简单使用 在控制台输入 lsusb 效果如下 系统中同时使用了 USB 2.0 root hub 驱动和 USB 3.0 root hub 驱动。 bus 002 指明设备…

LSB

知识点 LSB即为最低有效位&#xff08;Least Significant Bit&#xff0c;lsb&#xff09;&#xff0c;这里百度了一下&#xff1a;图片中的图像像素一般是由RGB三原色&#xff08;红绿蓝&#xff09;组成&#xff0c;每一种颜色占用8位&#xff0c;取值范围为0x00~0xFF&#…

lsusb命令-在系统中显示有关USB设备信息

在 中我们使用lsusb 列出USB设备及其属性&#xff0c;lsusb用于显示系统中的USB总线及其连接的设备信息。下面介绍如何安装并使用。 系统环境 7 安装usbutils 默认Centos7系统中没有lsusb &#xff0c;我们需要安装usbutils安装包&#xff0c;才能使用lsusb&#xff1a; […

LSF-bsub命令

文章目录 一、LSF(load sharing facility)二、bsub命令三、 常用命令3.1 bhosts3.2 bqueues3.3 bjobs3.4 bkill3.5 bhist3.6 busers 一、LSF(load sharing facility) 分布资源管理的工具&#xff0c;用来调度、监视、分析联网计算机的负载。 目的&#xff1a;通过集中监控和调…

Linux下的lsusb命令详解

lsusb命令详解 参考&#xff1a; 1、https://zhuanlan.zhihu.com/p/142403866 2、https://blog.csdn.net/phmatthaus/article/details/124198879 简介 ​USB&#xff0c;是英文Universal Serial Bus&#xff08;通用串行总线&#xff09;的缩写&#xff0c;是一个外部总线标…

详解 lsusb命令

USB设备检测的一般过程 USB设备检测也是通过/proc目录下的USB文件系统进行的。为了使一个USB设备能够正常工作&#xff0c;必须要现在系统中插入USB桥接器模块。在检测开始时&#xff0c;一般要先检测是否存在/proc/bus/usb目录&#xff0c;若不存在则尝试插入USB桥接模块。 现…

lsusb

1.lsusb查看系统的USB设备 $ lsusb Bus 001 Device 006: ID 0951:1666 Kingston Technology Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 004: ID 0e0f:0008 VMware, Inc. Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB H…

Linux常用命令——lsusb命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) lsusb 显示本机的USB设备列表信息 补充说明 lsusb命令用于显示本机的USB设备列表&#xff0c;以及USB设备的详细信息。 lsusb命令是一个学习USB驱动开发&#xff0c;认识USB设备的助手&#xff0c;推荐大家使用…

Linux下lsusb命令详解

Linux下lsusb命令详解 参考链接&#xff1a;https://zhuanlan.zhihu.com/p/142403866 ​ USB&#xff0c;是英文Universal Serial Bus&#xff08;通用串行总线&#xff09;的缩写&#xff0c;是一个外部总线标准&#xff0c;早期用于规范电脑与外部设备的连接和通讯。 ​ U…

[Kong 与 Konga 与 Postgres数据库] 之 Kuberneres 部署

1、Kong的概述 Kong是一个clould-native、快速的、可扩展的、分布式的微服务抽象层&#xff08;也称为API网关、API中间件或在某些情况下称为服务网格&#xff09;框架。Kong作为开源项目在2015年推出&#xff0c;它的核心价值是高性能和可扩展性。Kong被广泛用于从初创企业到全…

Konga arm64 安装

arm64 平台&#xff1a; 一、源码安装 konga 前提&#xff1a;安装nodejswget https://nodejs.org/dist/v12.16.1/node-v12.16.1-linux-arm64.tar.xztar -xf node-v12.16.1-linux-arm64.tar.xz 配置node环境变量&#xff1a;vi /etc/profileexport NODE_HOME/home/node-v12.16…