SLAM算法与工程实践——SLAM基本库的安装与使用(6):g2o优化库(2)g2o编程框架

SLAM算法与工程实践系列文章

下面是SLAM算法与工程实践系列文章的总链接,本人发表这个系列的文章链接均收录于此

SLAM算法与工程实践系列文章链接


下面是专栏地址:

SLAM算法与工程实践系列专栏


文章目录

  • SLAM算法与工程实践系列文章
    • SLAM算法与工程实践系列文章链接
    • SLAM算法与工程实践系列专栏
  • 前言
  • SLAM算法与工程实践——SLAM基本库的安装与使用(6):g2o优化库(2)
    • g2o求解步骤
      • 第 1 步:创建一个线性求解器 ( LinearSolver )
      • 第2步:创建块求解器(BlockSolver),并用上面定义的线性求解器初始化。
      • 第3步:创建总求解器(Solver),并从GN、LM、DogLeg中选择一个,再用上述块求解器初始化。
      • 第4步,创建稀疏优化器(SparseOptimizer),并用已定义求解器作为求解方法。
      • 第5~6步,定义图的顶点和边,并添加到优化器中。
      • 第7步,设置优化参数,开始执行优化


前言

这个系列的文章是分享SLAM相关技术算法的学习和工程实践


SLAM算法与工程实践——SLAM基本库的安装与使用(6):g2o优化库(2)

图结构:

  • 顶点:待优化的变量。比如机器人位姿、空间中地图点(路标点)
  • 边:顶点之间的约束产生的误差,比如重投影误差

图优化的目的是通过调整顶点来使得边的整体误差最小,此时的顶点认为是最准确的

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

g2o 求解曲线参数的例子

// 每个误差项优化变量维度为3,误差值维度为1
typedef g2o::BlockSolver<g2o::BlockSolverTraits<3,1>>  Block;// 第1步:创建一个线性求解器(LinearSolver)
Block::LinearSolverType* linearSolver = new g2o::LinearSolverDense<Block::PoseMatrixType>();// 第2步:创建块求解器(BlockSolver),并用上面定义的线性求解器初始化
Block* solver_ptr = new Block( linearSolver );// 第3步:创建总求解器(Solver),并从GN、LM、DogLeg中选择一个,再用上述块求解器初始化
g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );// 第4步:创建稀疏优化器(SparseOptimizer)
g2o::SparseOptimizer optimizer;      // 创建优化器
optimizer.setAlgorithm( solver );     // 用前面定义好的求解器作为求解方法
optimizer.setverbose( true );       // 在优化过程中输出调试信息// 第5步:定义图的顶点,并添加到优化器中
CurveFittingVertex* v = new CurveFittingVertex();   //向图中增加顶点v->setEstimate( Eigen::Vector3d(0,0,0) );
v->setId(0);
optimizer.addvertex( v );// 第6步:定义图的边,并添加到优化器中
for (int i=0; i<N ; i++)    // 向图中增加边
{CurveFittingEdge* edge = new CurveFittingEdge(x_data[i]);edge->setId(i);edge->setvertex( 0 , v );   // 设置连接的顶点edge->setMeasurement(y_data[i]);     // 观测数值// 信息矩阵:协方差矩阵之逆edge->setInformation(Eigen::Matrix<double,1,1>::Identity() * 1 /(w_sigma * w_sigma));optimizer.addEdge( edge );
}// 第7步:设置优化参数,开始执行优化
optimizer.initializeOptimization();
optimizer.optimize(100);    // 设置迭代次数

当然,在定义求解器变量时,可以直接一步到位,例如

// 梯度下降方法,可以从GN, LM, DogLeg 中选
auto solver = new g2o::OptimizationAlgorithmGaussNewton(g2o::make_unique<BlockSolverType>(g2o::make_unique<LinearSolverType>()));

g2o求解步骤

第 1 步:创建一个线性求解器 ( LinearSolver )

我们要求的增量方程的形式是 H Δ x = − b H\Delta x=-b HΔx=b, 在通常情况下想到的方法就是直接求逆,也就是 Δ x = − H − 1 b \Delta x=-\boldsymbol{H}^{-1}\boldsymbol{b} Δx=H1b。看起来好像很简单,但有一个前提,就是 H H H 的维度较小,此时只需要对矩阵求逆就能解决问题。

H H H 的维度较大时,矩阵求逆变得很困难,求解问题也会变得很复杂。

需要使用一些特殊的方法对矩阵进行求逆,在 g2o 中主要有以下几种线性求解方法。

LinearSolverCholmod:使用 sparse cholesky 分解法。继承自 LinearSolverCCS
LinearSolvercSparse:使用 CSparse 法。继承自 LinearSolverCCS
LinearSolverPCG:使用 preconditioned conjugate gradient 法。继承自 LinearSolver
LinearSolverDense:使用 dense cholesky 分解法。继承自 LinearSolver
LinearSolverEigen:依赖项只有 eigen,使用 eigen 中 sparse Cholesky 求解,编译好后可以在其他地方使用。继承自 LinearSolver

第2步:创建块求解器(BlockSolver),并用上面定义的线性求解器初始化。

块求解器的内部包含线性求解器,用上面定义的线性求解器来初始化。

块求解器有两种定义方式,一种是固定变量的求解器,定义如下。

using BlockSolverPL =  BlockSolver<BlockSolverTraits<p,l>>

其中,p 表示位姿的维度,l 表示路标点的维度。另一种是可变尺寸的求解器,定义如下。

using BlockSolverX = BlockSolverPL<Eigen::Dynamic,Eigen::Dynamic>;

为何会有可变尺寸的求解器呢?

因为在某些应用场景中,位姿和路标点在程序开始时并不能被确定,此时块求解器就没办法固定变量,应该使用可变尺寸的求解器,以便让所有的参数都在中间过程中被确定。

在块求解器头文件 block_solver.h 的最后,预定义了比较常用的几种类型,这个也不用记,以后遇到了知道这些数字代表什么意思就行了

BlockSolver_6_3:表示 pose 为 6 维,观测点为 3 维。用于 3D SLAM 中的 BA
BlockSolver_7_3:在 BlockSolver_6_3 的基础上多了一个 scale
BlockSolver_3_2:表示 pose 为 3 维,观测点为 2 维

第3步:创建总求解器(Solver),并从GN、LM、DogLeg中选择一个,再用上述块求解器初始化。

下面来看 g2o/g2o/core/ 目录,可以发现 Solver 的优化方法有3种,分别是Gauss Newton法、Levenberg-Marquardt法和Dogleg法。

如果进入这几个算法内部,就会发现它们都继承自同一个类——OptimizationWithHessian,而 OptimizationWithHessian 又继承自OptimizationAlgorithm,和图6-2正好对应。

// optimization_algorithm gauss_newton.h
// Gauss Newton 算法
class G2O_CORE_API OptimizationAlgorithmGaussNewton : public OptimizationAlgorithmwithHessian
{// ......
};// optimization_algorithm levenberg.h
// Levenberg 算法
class G2O_CORE_API OptimizationAlgorithmLevenberg : public OptimizationAlgorithmwithHessian
{// ......
};// optimization algorithm dogleg.h
// Powell's Dogleg 算法
class G2O_CORE_API OptimizationAlgorithmDogleg : public OptimizationAlgorithmWithHessian
{// ......
};// optimization algorithm_with_hessian.h
// brief Base for solvers operating on the approximated Hessian,e.g.,Gauss-Newton,Levenberg
class G2O_CORE_API OptimizationAlgorithmWithHessian : public OptimizationAlgorithm
{// ......
};

总之,在该阶段,可以选择以下3种方法,其中用得比较多的是OptimizationAlgorithmLevenberg。

g2o::OptimizationAlgorithmGaussNewton
// Gauss Newton 法
g2o::OptimizationAlgorithmLevenberg
// Levenberg-Marquardt 法
g2o::OptimizationAlgorithmDogleg
// Dogleg 法

其中用得比较多的 OptimizationAlgorithmLevenberg。

第4步,创建稀疏优化器(SparseOptimizer),并用已定义求解器作为求解方法。

第5~6步,定义图的顶点和边,并添加到优化器中。

这部分比较复杂,我们在后面单独介绍。

第7步,设置优化参数,开始执行优化

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

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

相关文章

嵌入式 开发——DMA内存到外设

学习目标 加强理解DMA数据传输过程加强掌握DMA的初始化流程掌握DMA数据表查询理解源和目标的配置理解数据传输特点能够动态配置源数据学习内容 需求 串口发送数据 uint8_t data = 0x01; 串口发送(data); 实现串口的发送数据, 要求采用dma的方式 数据交互流程 CPU配置好DM…

10.2多点触摸屏驱动

多点电容触摸&#xff08;MT&#xff09;协议 多点电容触摸&#xff08;MT&#xff09;协议是 input 子系统的一部分&#xff0c; MT 协议被分为两种类型&#xff0c;分别是 Type A 和 Type B &#xff1a; Type A &#xff1a;适用于触摸点不能被区分或者追踪的设备&#xf…

【Java】springboot

文章目录 Spingboot1、起步依赖2、构建springboot工程jar包3、springboot配置文件4、多环境配置5、maven和boot多环境兼容问题6、配置文件分类7、springboot整合mybatis Spingboot springboot用来简化spring的初始搭建以及开发过程。 比方说&#xff0c;创建一个springmvc程序…

Ps2022版DR5插件扩展窗口不展示及未正确签署等问题修复

前言 最近在安装DR5的时候遇到了一些报错问题&#xff0c;翻看了几篇文章找了一些实质性的方案&#xff0c;亲测有效&#xff0c;有同样问题的小伙伴自己对号入座哈。 窗口扩展不显示问题 问题 很多人第一次安装DR5时会发现这个【窗口-扩展】是灰色的&#xff0c;且没有DR5…

class087 动态规划中根据数据量猜解法的技巧【算法】

class087 动态规划中根据数据量猜解法的技巧【算法】 2023-12-24 14:36:06 算法讲解087【必备】动态规划中根据数据量猜解法的技巧 code1 打 怪 兽 // 贿赂怪兽 // 开始时你的能力是0&#xff0c;你的目标是从0号怪兽开始&#xff0c;通过所有的n只怪兽 // 如果你当前的能力…

35c3 krautflare

参考这篇文章可以彻底了解本题的漏洞所在 https://xz.aliyun.com/t/6527 由于Math.expm1经过patch以后的返回值不可能是-0&#xff0c;但是patch的地方是在typer优化中&#xff0c;所以实际上如果没有优化的话是可以返回-0的&#xff0c;这就意味着如果我们先不停地Math.expm1…

【C++】unordered_set/unordered_multiset/unordered_map/unordered_multimap

我们下面来学习C的另外两个容器&#xff1a;unordered_set和unordered_map 目录 一、unordered系列关联式容器 二、unordered_map 2.1 unordered_map的介绍 2.2 unordered_map的接口说明 2.2.1 unordered_map的构造 2.2.2 unordered_map的容量 2.2.3 unordered_map的迭…

java的XWPFDocument3.17版本学习

maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version> </dependency> 测试类&#xff1a; import org.apache.poi.openxml4j.exceptions.InvalidFormatExcep…

探索应用程序的指路明灯:Route 和 Router 入门指南(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

一站式指南:第 377 场力扣周赛的终极题解

比赛详情 比赛地址 题目一很简单题目二主要是题目长了点&#xff0c;其实解法很常规(比赛后才意识到)题目三套用Dijkstra算法题目四没时间解答水平还有待提升(其实就是需要灵活组合运用已知的算法&#xff0c;有点类似大模型的Agent) 题解和思路 第一题&#xff1a;最小数字…

信号与线性系统翻转课堂笔记10——傅里叶变换的性质

信号与线性系统翻转课堂笔记10——傅里叶变换的性质 The Flipped Classroom10 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#xff0c;重点&…

Echarts社区推荐

Apache Echarts官方示例中&#xff0c;有的demo并不能完全符合我们的需求&#xff0c;下面推荐几个Echarts社区&#xff0c;以便快速搭建项目。 1. isqqw 官方地址 &#xff1a;https://www.isqqw.com/ 2. makepie 官方地址 &#xff1a;https://www.makeapie.cn/echarts 3. P…