06 g2o 学习

文章目录

    • 06 g2o 学习
      • 6.1 概念
      • 6.2 框架简介
      • 6.3 代码示例

06 g2o 学习

6.1 概念

g2o(General Graphic Optimization)是基于图优化的库。图优化是把优化问题表现成图的一种方式。一个图由若干个顶点(Vertex),以及连接这这些顶点的边(Edge)组成。用顶点表示优化变量,用边表示误差项。

那么在 SLAM 中,不同时刻的位姿和路标点为待优化变量即顶点,将他们之间的观测作为边。数学表述为,传感器的观测方程

z k = h ( x k ) z_{k}=h\left(x_{k}\right) zk=h(xk)

实际上二者并不会相等,而是有误差存在

e k = z k − h ( x k ) e_k=z_k-h\left(x_k\right) ek=zkh(xk)

于是,位姿 x k x_k xk 和 路标 z k z_k zk 为待优化变量(图中节点),误差 e k e_k ek 为约束(红色虚线)。

在这里插入图片描述

6.2 框架简介

在这里插入图片描述

几个需要注意的点:

(1)迭代形式为 H Δ x = b H\Delta x=b HΔx=b,也就是求出每次迭代步长 Δ x \Delta x Δx,三个算法可选:高斯牛顿、LM 和 Dog-Leg;

(2)定义顶点:顶点也就是待优化变量,它继承自基础类 BaseVertex<D, T>,其中 D 为 int 类型,表示维度,T 为数据类型。例如

g2o::BaseVertex<3, Eigen::Vector3d>  // 三维点,Eigen::Vector3d 类型g2o::BaseVertex<6, SE3Quat>  // SE3 变换矩阵,6个参数(平移+旋转)

(3)顶点更新:对于一般的函数,更新策略是 x k + 1 = x k + Δ x x_{k+1}=x_k+\Delta x xk+1=xk+Δx,也就是加上求出的 Δ x \Delta x Δx,而对于位姿 S E ( 3 ) SE(3) SE(3) 这样的数据类型类型来说,要用乘法。

// 顶点更新函数
void curveVetex::oplusImpl(const double* update)
{_estimate += Eigen::Vector3d(update);   // 加法更新
}

(4)添加顶点,有多少个顶点就添加多少个。

// 新建顶点
curveVetex* v = new curveVetex();          // 自定义顶点类型
v->setEstimate(Eigen::Vector3d(0,0,0));    // 初始化
v->setId(0);                               // 设置 Id
optimizer.addVertex(v);                    // 加入优化器中

(5)定义边:包括一元边、二元边和多元边。误差=测量值-估计值

在这里插入图片描述

以二元边为例

g2o::BaseBinaryEdge<errorDim, errorType, Vertex1Type, Vertex2Type>   // Vertex1Type 连接的顶点的类名

(6)添加边

EdgePointOnCurve* e = new EdgePointOnCurve;
e->setId(0);                               // 设置 Id
e->setInformation(Eigen::Matrix<double,1,1>::Identity());   // 信息矩阵
e->setVertex(0, v);            // 设置连接的顶点
e->setMeasurement(y_data[i]);    // 观测值
optimizer.addEdge(e); 

(7)主要步骤

  • 定义顶点和边的类型
  • 构建图(添加顶点和边)
  • 选择优化算法
  • 调用 g2o 进行优化,返回结果

通用模板

// 1. 定义顶点
class curveVetex: public g2o::BaseVertex<3,Eigen::Vector3d>
{public:EIGEN_MAKE_ALIGNED_OPERATOR_NEWvirtual void setToOriginImpl();   // 顶点初始值,置零virtual void oplusImpl(const double* update);  // 更新virtual bool read(std::istream &is);          // 读盘、存盘,留空即可virtual bool write(std::ostream &os) const;
};// 2. 添加顶点
curveVetex* v = new curveVetex();          // 自定义顶点类型
v->setEstimate(Eigen::Vector3d(0,0,0));    // 初始化
v->setId(0);                               // 设置 Id
optimizer.addVertex(v);                    // 加入优化器中// 3. 定义边
class myEdge: public g2o::BaseBinaryEdge<errorDim, errorType, Vertex1Type, Vertex2Type>
{
public:EIGEN_MAKE_ALIGNED_OPERATOR_NEWmyEdge(){}// 计算曲线模型误差=测量值-估计值void computeError();//存取bool read(std::istream& is);bool write(std::ostream& os) const;// 增量计算函数:误差对优化变量的偏导数void linearizeOplus();
}// 4. 添加边
EdgePointOnCurve* e = new EdgePointOnCurve;
e->setId(0);                               // 设置 Id
e->setInformation(Eigen::Matrix<double,1,1>::Identity());   // 信息矩阵
e->setVertex(0, v);            // 设置连接的顶点
e->setMeasurement(y_data[i]);    // 观测值
optimizer.addEdge(e); 

6.3 代码示例

拟合函数 y = exp ⁡ ( a x 2 + b x + c ) y=\exp(ax^2+bx+c) y=exp(ax2+bx+c)

显然待优化变量为 a b c abc abc,只有一个顶点;误差值=观测值(实际值)-估计值(理论值),一元边。

在这里插入图片描述

需要注意的是,这里用的三种优化算法,都是误差 e i e_i ei 对代优化变量的偏导数,而不是 F ( x ) \boldsymbol{F}(x) F(x),即

e i = y i − e x p ( a x i 2 + b i x + c ) e_i=y_i-exp(ax_i^2+b_ix+c) ei=yiexp(axi2+bix+c)
∂ e i ∂ a = − x i 2 exp ⁡ ( a x i 2 + b i x + c ) ∂ e i ∂ b = − x i exp ⁡ ( a x i 2 + b i x + c ) ∂ e i ∂ c = − exp ⁡ ( a x i 2 + b i x + c ) \frac{ \partial e_i }{ \partial a}=-x_i^2\exp(ax_i^2+b_ix+c) \\ \frac{ \partial e_i }{ \partial b}=-x_i\exp(ax_i^2+b_ix+c) \\ \frac{ \partial e_i }{ \partial c}=-\exp(ax_i^2+b_ix+c) aei=xi2exp(axi2+bix+c)bei=xiexp(axi2+bix+c)cei=exp(axi2+bix+c)

关于 g2o 使用的几个问题

(1)安装:

安装依赖项:

sudo apt-get install libqt4-dev qt4-qmake libqglviewer-dev libsuitesparse-dev libcxsparse3.1.2 libcholmod-dev

安装下列命令依次执行安装:

git clone https://github.com/RainerKuemmerle/g2o.git
cd g2o
mkdir build
cd build
cmake ..
make
sudo make install

安装完成后在目录/usr/local/includ 下能找到 g2o 目录,在 /usr/local/lib 下能找到libg2o_**.so的文件。

(2)cmakelists.txt

include_directories( ${G2O_INCLUDE_DIRS})
SET(G2O_LIBS g2o_cli g2o_ext_freeglut_minimal g2o_simulator g2o_solver_slam2d_linear g2o_types_icp g2o_types_slam2d g2o_core g2o_interface g2o_solver_csparse g2o_solver_structure_only g2o_types_sba g2o_types_slam3d g2o_csparse_extension g2o_opengl_helper g2o_solver_dense g2o_stuff g2o_types_sclam2d g2o_parser g2o_solver_pcg g2o_types_data g2o_types_sim3 cxsparse )include_directories("/usr/include/eigen3")add_executable(g2oCurveFitting ./src/g2oCurveFitting.cpp)
target_link_libraries(g2oCurveFitting ${G2O_LIBS})

(3)编译过程中遇到如下错误

error while loading shared libraries: libg2o_core.so: cannot open shared object file: No such file or directory

出现这个问题的主要原因是,新安装的 g2o 没能生效。执行

sudo ldconfig

代码

/***********************************************************                                          *
* Time: 2023/8/27
* Author: xiaocong
* Function: g2o
* 注意这里用的是 ae * xi * xi + be * xi + sin(ce)
***********************************************************/#include <iostream>
#include <g2o/core/g2o_core_api.h>
#include <g2o/core/base_vertex.h>
#include <g2o/core/base_unary_edge.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_gauss_newton.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/optimization_algorithm_dogleg.h>
#include <g2o/solvers/dense/linear_solver_dense.h>
#include <eigen3/Eigen/Core>
#include <cmath>const int N = 100;                 // 数据点个数using namespace std;// 定义顶点即待优化变量 abc
class CurveFittingVertex : public g2o::BaseVertex<3, Eigen::Vector3d>
{
public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW// 设置初始值virtual void setToOriginImpl(){_estimate << 0, 0, 0;}// 更新,直接加上 delta_xvirtual void oplusImpl(const double* update){_estimate += Eigen::Vector3d(update);}// 存盘和读盘:留空virtual bool read(istream& in) {}virtual bool write(ostream& out) const {}
};// 定义边,包括误差项及其对优化变量的偏导数
class CurveFittingEdge : public g2o::BaseUnaryEdge<1, double, CurveFittingVertex>
{
public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW;// 构造函数CurveFittingEdge(double x) : _x(x) {}// 计算曲线模型误差=测量值-估计值virtual void computeError(){// 取出 _vertices 中的第一个顶点,强制转换为 CurveFittingVertex* 类型const CurveFittingVertex* v = static_cast<const CurveFittingVertex*> (_vertices[0]);const Eigen::Vector3d abc = v->estimate();_error(0, 0) = _measurement - std::exp(abc(0, 0) * _x * _x + abc(1, 0) * _x + abc(2, 0));}// 计算误差对优化变量的雅可比矩阵virtual void linearizeOplus(){const CurveFittingVertex* v = static_cast<const CurveFittingVertex*> (_vertices[0]);const Eigen::Vector3d abc = v->estimate();double y = exp(abc[0] * _x * _x + abc[1] * _x + abc[2]);_jacobianOplusXi[0] = -_x * _x * y;_jacobianOplusXi[1] = -_x * y;_jacobianOplusXi[2] = -y;}// 存盘和读盘:留空virtual bool read(istream& in) {}virtual bool write(ostream& out) const {}public:double _x;   //x 值, y 值为 _measurement
};int main()
{double ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值// 生成数据vector<double> x_data, y_data;for (int i = 0; i < N; i++){double xi = i / 100.0;                                     // [0~1]double sigma = 0.02 * (rand() % 1000) / 1000.0 - 0.01;     // 随机噪声,[-0.01, 0.01]double yi = exp(ar * xi * xi + br * xi + cr) + sigma;x_data.push_back(xi);y_data.push_back(yi);}// 构建图优化typedef g2o::BlockSolver< g2o::BlockSolverTraits<3, 1> > Block;  // 每个误差项优化变量维度为3,误差值维度为1Block::LinearSolverType* linearSolver = new g2o::LinearSolverDense<Block::PoseMatrixType>(); // 线性方程求解器Block* solver_ptr = new Block(linearSolver);      // 矩阵块求解器// 高斯牛顿法优化   g2o::OptimizationAlgorithmGaussNewton* solver = new g2o::OptimizationAlgorithmGaussNewton(solver_ptr);g2o::SparseOptimizer optimizer;     // 图模型optimizer.setAlgorithm(solver);     // 设置求解器optimizer.setVerbose(true);         // 打开调试输出// 向图中添加顶点(只有一个顶点)CurveFittingVertex* v = new CurveFittingVertex();v->setEstimate(Eigen::Vector3d(0, 0, 0));   // 初始值v->setId(0);                                   // 顶点序号optimizer.addVertex(v);                        // 加入优化器// 向图中添加边for (int i = 0; i < N; i++){CurveFittingEdge* e = new CurveFittingEdge(x_data[i]);e->setId(i);                 // 设置 Ide->setVertex(0, v);          // 连接的顶点e->setMeasurement(y_data[i]);      // 观测值e->setInformation(Eigen::Matrix<double, 1, 1>::Identity());    // 信息矩阵optimizer.addEdge(e);       // 加入优化器}// 执行优化cout << "start optimization" << endl;optimizer.initializeOptimization();optimizer.optimize(100);               // 最大迭代次数// 输出优化值Eigen::Vector3d abc_estimate = v->estimate();cout << "result: " << abc_estimate.transpose() << endl;return 0;
}

结果

result: 0.999313  2.00098 0.999658

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

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

相关文章

【python】——函数

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

P8 删除链表指定节点

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f4…

【灵魂 |数据结构与算法】 数据结构必备经法(开山篇),一起修炼算法经法!

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

基于Springboot的秒杀系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的秒杀系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xf…

【开源】基于Vue和SpringBoot的音乐偏好度推荐系统

项目编号&#xff1a; S 012 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S012&#xff0c;文末获取源码。} 项目编号&#xff1a;S012&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1…

easyrecovery2024最新破解版激活密钥

平时很多人都会把自己工作时&#xff0c;或者生活中的数据存储在我们的电脑上&#xff0c;很多时候&#xff0c;由于我们的误操作或者是其它某些问题&#xff0c;很容易就会误删除一些文件数据了&#xff0c;尤其是一些电脑出现故障&#xff0c;总是会导致数据丢失&#xff0c;…

linux 内核regulator

问题 在sys文件系统下没有生成cpu 调频的相关节点。 日志对比 [ 3.588745] cpu cpu4: Looking up cpu-supply from device tree [ 3.588753] cpu cpu4: Failed to get reg [ 3.588791] cpu cpu4: Looking up cpu-supply from device tree [ 3.588808] Failed to i…

智能优化算法应用:基于和声算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于和声算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于和声算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.和声算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

外贸建站是WP还是CMS?海洋建站教程指南?

外贸建站选WP还是CMS系统&#xff1f;外贸企业网站建站怎么做&#xff1f; 随着全球化的不断发展&#xff0c;越来越多的企业开始拓展海外市场&#xff0c;外贸建站成为了这些企业的必备项目。然而&#xff0c;选择使用哪种建站系统却是一个让人头疼的问题。那么&#xff0c;海…

ElementUI+vue+nodejs培训学校课程预约网站的设计与开发

该系统将采用B/S结构模式&#xff0c;前端部分主要使用html、css、JavaScript等技术&#xff0c;使用Vue和ElementUI框架搭建前端页面&#xff0c;后端部分将使用Nodejs来搭建服务器&#xff0c;并使用MySQL建立后台数据系统&#xff0c;通过axios完成前后端的交互&#xff0c;…

oops-framework框架 之 界面管理(三)

引擎&#xff1a; CocosCreator 3.8.0 环境&#xff1a; Mac Gitee: oops-game-kit 注&#xff1a; 作者dgflash的oops-framework框架QQ群&#xff1a; 628575875 回顾 在上文中主要通过oops-game-kit大家了一个新的模版项目&#xff0c; 主要注意项是resources目录下的两个文…

如何在安卓Termux中使用SFTP文件传输并结合内网穿透工具实现远程传输

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…

Jmeter的安装配置,性能测试编写

1、jmeter介绍 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言&#xff0c;JMeter小巧轻便且免费&#xff0c;逐渐成为了主流的性能测试工具&#xff0c;是每个测试人员都必须要掌握的工具之一。 运行环境为Windows 10系统&#xff0c…

AI创作ChatGPT网站系统源码保姆级搭建部署教程+支持GPT-4图片对话能力

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

数据结构与算法-动态查找表

查找 &#x1f388;3动态查找表&#x1f52d;3.1二叉排序树&#x1f3c6;3.1.1二叉排序树的类定义&#x1f3c6;3.1.2二叉排序树的插入和生成&#x1f3c6;3.1.3二叉树的查找&#x1f3c6;3.1.4二叉排序树的删除 &#x1f52d;3.2平衡二叉树&#x1f3c6;3.2.1平衡二叉树的调整…

基于粒子群算法思想的电动汽车充放电策略-V2G模型-程序代码!

电动汽车充放电对电网的安全稳定带来影响&#xff0c;合理规划电动汽车充放电时间和策略是目前的研究热点。本程序仿真了汽车有序充电和无需充电两种案例&#xff0c;利用电动汽车合理消纳新能源电量&#xff0c;利用粒子群算法思想来求解模型&#xff0c;程序中案例丰富&#…

智能锁-SI522TORC522方案资料

南京中科微这款SI522目前完全PinTOPin兼容的NXP&#xff1a;RC522、CV520 复旦微&#xff1a;FM17520、FM17522/FM17550 瑞盟&#xff1a;MS520、MS522 国民技术:NZ3801、NZ3802 SI522 是应用于13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员。是NXP 公司针对&quo…

2.1 Linux C 编程

一、Hello World 1、在用户根目录下创建一个C_Program&#xff0c;并在这里面创建3.1文件夹来保存Hellow World程序&#xff1b; 2、安装最新版nvim ①sudo apt-get install ninja-build gettext cmake unzip curl ②sudo apt install lua5.1 ③git clone https://github.…

HarmonyOS 振动效果开发指导

Vibrator 开发概述 振动器模块服务最大化开放硬工最新马达器件能力&#xff0c;通过拓展原生马达服务实现振动与交互融合设计&#xff0c;打造细腻精致的一体化振动体验和差异化体验&#xff0c;提升用户交互效率和易用性、提升用户体验、增强品牌竞争力。 运作机制 Vibrato…

内衣专用洗衣机怎么样?好用又便宜的迷你洗衣机推荐

迷你洗衣机作为一种小型便捷的家用必备洗涤设备&#xff0c;一直都受到越来越多家庭的青睐。一台迷你洗衣机可以帮助我们解决很多麻烦&#xff0c;节省我们的很多时间。对于不少在外工作的人&#xff0c;往往是一个人住&#xff0c;买一台大型的洗衣机或许有点浪费资源&#xf…