从零开始搭二维激光SLAM --- 基于gtsam的后端优化的代码实现

2023-05-16

上一篇文章我们分析了如何使用ceres进行位姿图的优化.

这篇文章来讲一下如何使用gtsam进行位姿图的优化.

1 gtsam简介

gtsam是最近几年火起来的一个优化库.

GTSAM(Georgia Tech Smoothing and Mapping)是基于因子图的C++库,它由佐治亚理工学院的教授和学生们创造。它可以解决slam和sfm的问题,当然它也可以解决简单或者更加复杂的估计问题。

1.1 怎么学gtsam

由于其使用了概率图中的因子图这种理论, 以及官方文档的不足, 导致很多人学这个库不知道从哪里入手.

在这里简要说一下gtsam怎么学.

如果是刚接触gtsam的同学, 可以看一下董靖之前的直播, 能够对gtsam先产生个比较直观的印象.

【泡泡机器人公开课】第五十六课:gtsam_tutorial-董靖
https://www.bilibili.com/video/BV1C4411772G/?spm_id_from=333.788.recommend_more_video.1

之后要弄清楚一件事情, 就是学gtsam库和学概率图与因子图是2个事情.

学gtsam库, 就是学习如何使用gtsam库 编写代码进行优化, 只需要学习gtsam的接口, 学习怎么使用gtsam的函数就够了.

就像你学ceres库, 只是学了怎么使用ceres, ceres的接口是什么, 没必要去学ceres是怎么进行自动微分的. 学gtsam库也是一样, 人家就是为了不让每个人都去重复的学这一块的理论, 重复写代码, 所以弄成库放了出来, 直接用就可以了.

而如果你想要学gtsam背后的理论, 概率图和因子图等等 , 才需要去弄清楚什么是概率图, 什么是因子图, 怎么根据因子图做推断等等.

1.2 如何学gtsam库的使用

首先推荐一篇文章, 是这人学gtsam的建议.

GTSAM 库的学习建议
https://zhuanlan.zhihu.com/p/356968742

gtsam.pdf

网上的诸多文章, 大都是翻译的官方教程, 所以这里推荐大家直接去看官方的教程
https://gtsam.org/tutorials/intro.html

这个网址如果打不开, 可以去看 gtsam源码doc文件夹中的 gtsam.pdf, 他们的内容是一样的.

这个文章是翻译的, 但是翻译的不全
gtsam:从入门到使用
https://blog.csdn.net/QLeelq/article/details/111368277#t24

gtsam/examples

然后推荐去看gtsam源码中examples文件夹中的各种代码的举例, 再去结合网上的文章, 学习gtsam的接口应该是很快的.

OdometryExample.cpp 和 Pose2SLAMExample.cpp 两个文件展示了如何使用gtsam进行二维位姿的优化, 后一个文件也是 董靖 在直播中讲的例子. 如果你只是做2维位姿的优化, 那么看懂这2个文件就应该够用了.

如果你想对gtsam有更多的了解, 可以将example中的例子全部看完.

gtsam/examples/README.md 对所有的例子进行了简单的分类, 但是有点和文件对不上. 在这里我对 4.0.2版本的gtsam 的examples中的所有文件进行了简单的分类, 如下所示

  • basic
    - SimpleRotation.cpp : 只有一个先验旋转的姿态优化

  • 2D pose
    - OdometryExample.cpp : 使用里程计进行位姿估计
    - Pose2SLAMExample.cpp : 使用里程计进行位姿估计
    - PlanarSLAMExample.cpp : 带二维激光观测的二维SLAM位姿估计
    - LocalizationExample.cpp : 自定义GPS观测的GPS与里程计的位姿估计
    - Pose2SLAMExampleExpressions.cpp : 使用自动微分的位姿估计
    - Pose2SLAMExample_g2o.cpp
    - Pose2SLAMExample_graph.cpp
    - Pose2SLAMExample_graphviz.cpp
    - Pose2SLAMExample_lago.cpp
    - Pose2SLAMStressTest.cpp
    - Pose2SLAMwSPCG.cpp
    - RangeISAMExample_plaza2.cpp
    - METISOrderingExample.cpp

  • 3D pose
    - Pose3SLAMExample_g2o.cpp : 几乎与二维的是相同的代码
    - Pose3SLAMExample_changeKeys.cpp
    - Pose3SLAMExample_initializePose3Chordal.cpp
    - Pose3SLAMExample_initializePose3Gradient.cpp
    - Pose3SLAMExampleExpressions_BearingRangeWithTransform.cpp

  • 视觉
    - CameraResectioning.cpp
    - StereoVOExample.cpp : 双目视觉里程计的例子
    - StereoVOExample_large.cpp
    - SelfCalibrationExample.cpp

  • imu预积分
    - ImuFactorsExample.cpp : imu预积分与GPS观测的位姿优化
    - ImuFactorExample2.cpp : 使用isam2进行imu的位姿优化

  • isam算法
    - VisualISAMExample.cpp
    - VisualISAM2Example.cpp
    - ISAM2_SmartFactorStereo_IMU.cpp
    - ISAM2Example_SmartFactor.cpp

  • kalman filter
    - easyPoint2KalmanFilter.cpp
    - elaboratePoint2KalmanFilter.cpp

  • SFM
    - SFMExample.cpp
    - SFMExample_bal.cpp
    - SFMExample_bal_COLAMD_METIS.cpp
    - SFMExampleExpressions.cpp
    - SFMExampleExpressions_bal.cpp
    - SFMExample_SmartFactor.cpp
    - SFMExample_SmartFactorPCG.cpp

  • 概率图相关
    - DiscreteBayesNet_FG.cpp
    - UGM_chain.cpp
    - UGM_small.cpp

  • 其他
    - InverseKinematicsExampleExpressions.cpp
    - SolverComparer.cpp
    - TimeTBB.cpp

从分类中可以发现gtsam和isam的关系. gtsam是一个基于因子图的库, isam2是可以更快进行矩阵计算和更新的算法. gtsam库包含了isam2算法.

如果想要看更多使用gtsam进行编程的例子, 可以看看董靖自己写的demo.
https://hub.fastgit.org/dongjing3309/gtsam-examples

1.3 如何学因子图

关于 概率图, 因子图, 隐式马尔科夫 等等的学习, 我推荐一个b站上的讲机器学习的视频

【机器学习】【白板推导系列】【合集 1~23】
https://www.bilibili.com/video/BV1aE411o7qd?p=46

之后也有几个文章推荐

干货:因子图优化的资源合集 里边放了学习gtsam理论的视频和论文.
https://zhuanlan.zhihu.com/p/128720019
一文搞懂HMM(隐马尔可夫模型)
https://www.cnblogs.com/skyme/p/4651331.html
从贝叶斯方法谈到贝叶斯网络
https://blog.csdn.net/v_july_v/article/details/40984699

2 基于gtsam的后端优化的代码讲解

头文件也是继承karto::ScanSolver即可

2.1 向因子图中添加变量节点

首先, 看一下构造函数

GTSAMSolver::GTSAMSolver()
{
  // add the prior on the first node which is known
  noiseModel::Diagonal::shared_ptr priorNoise = noiseModel::Diagonal::Sigmas(Vector3(1e-6, 1e-6, 1e-8));
  graph_.emplace_shared<PriorFactor<Pose2>>(0, Pose2(0, 0, 0), priorNoise);
}

向因子图中添加了初始节点以及其协方差矩阵.

之后, 看一下添加节点这个函数.

void GTSAMSolver::AddNode(karto::Vertex<karto::LocalizedRangeScan> *pVertex)
{
  karto::Pose2 odom = pVertex->GetObject()->GetCorrectedPose();
  initialGuess_.insert(pVertex->GetObject()->GetUniqueId(),
                       Pose2(odom.GetX(), odom.GetY(), odom.GetHeading()));
  graphNodes_.push_back(Eigen::Vector2d(odom.GetX(), odom.GetY()));
}

可以看到, 这里将节点的位姿通过 initialGuess_.insert() 添加到因子图中, 作为节点的初值.

并且将这个节点的 xy 坐标保存在 graphNodes_ 这个vector中.

2.2 向因子图中添加因子节点

向因子图中添加因子节点, 对应着向位姿图中添加约束.

如果看完了example中的例子就会发现, 这段代码和例子中的代码几乎一样.

只不过这里先将约束的协方差矩阵转成gtsam格式的协方差矩阵, 然后向因子图中添加 BetweenFactor 格式的因子.

void GTSAMSolver::AddConstraint(karto::Edge<karto::LocalizedRangeScan> *pEdge)
{
  // Set source and target
  int sourceID = pEdge->GetSource()->GetObject()->GetUniqueId();
  int targetID = pEdge->GetTarget()->GetObject()->GetUniqueId();

  // Set the measurement (poseGraphEdge distance between vertices)
  karto::LinkInfo *pLinkInfo = (karto::LinkInfo *)(pEdge->GetLabel());
  karto::Pose2 diff = pLinkInfo->GetPoseDifference();

  // Set the covariance of the measurement
  karto::Matrix3 precisionMatrix = pLinkInfo->GetCovariance();

  Eigen::Matrix<double, 3, 3> cov;
  cov(0, 0) = precisionMatrix(0, 0);
  cov(0, 1) = cov(1, 0) = precisionMatrix(0, 1);
  cov(0, 2) = cov(2, 0) = precisionMatrix(0, 2);
  cov(1, 1) = precisionMatrix(1, 1);
  cov(1, 2) = cov(2, 1) = precisionMatrix(1, 2);
  cov(2, 2) = precisionMatrix(2, 2);
  noiseModel::Gaussian::shared_ptr model = noiseModel::Diagonal::Covariance(cov);
  graph_.emplace_shared<BetweenFactor<Pose2>>(sourceID, targetID, Pose2(diff.GetX(), diff.GetY(), diff.GetHeading()), model);
}

2.3 优化求解

这段代码说明了如何使用gtsam进行优化的求解.

上边的2个函数将因子图已经构建好了, 这里就可以直接求解了.

首先, 设置 LM算法的各种参数.

然后生成一个 LevenbergMarquardtOptimizer 格式的LM优化器, 通过调用优化器的 optimize() 函数进行优化.

最后, 将优化完的节点进行保存.

void GTSAMSolver::Compute()
{
  corrections_.clear();
  graphNodes_.clear();

  LevenbergMarquardtParams parameters;
  parameters.relativeErrorTol = 1e-5;
  parameters.maxIterations = 500;
  LevenbergMarquardtOptimizer optimizer(graph_, initialGuess_, parameters);
  
  // optimize
  Values result = optimizer.optimize();
  Values::ConstFiltered<Pose2> viewPose2 = result.filter<Pose2>();

  // put values into corrections container
  for (const Values::ConstFiltered<Pose2>::KeyValuePair &key_value : viewPose2)
  {
    karto::Pose2 pose(key_value.value.x(), key_value.value.y(), key_value.value.theta());
    corrections_.push_back(std::make_pair(key_value.key, pose));
    graphNodes_.push_back(Eigen::Vector2d(key_value.value.x(), key_value.value.y()));
  }
}

3 运行

3.1 依赖

这篇文章的代码是需要依赖 4.0.2 版本的gtsam库, 如果没装gtsam的需要先安装一下.
我将gtsam库的安装包放在了 工程Creating-2D-laser-slam-from-scratch/TrirdParty文件加内, 可以直接解压安装.

安装的方法可以看一下 install_dependence.sh 脚本中的安装指令, 也可以直接执行这个脚本进行所有依赖项的安装.

安装完了gtsam之后, 编译代码, 如果一切顺利的话是可以编译通过的.

这里要说一下, 我一直用的是 1604版本的ubuntu, 没试过其他版本的ubuntu能不能编译通过. 如果实在编译不过就看看文章或者看看源码吧.

3.2 运行

本篇文章对应的数据包, 请在我的公众号中回复 lesson6 获得,并将launch中的bag_filename更改成您实际的目录名。

我将之前使用过的数据包的链接都放在腾讯文档里了, 腾讯文档的地址如下:
https://docs.qq.com/sheet/DVElRQVNlY0tHU01I?tab=BB08J2

通过如下命令运行本篇文章对应的程序
roslaunch lesson6 karto_slam_outdoor.launch solver_type:=gtsam_solver

3.3 结果分析

启动之后, 会显示出使用的优化器的具体类型.

[ INFO] [1637561045.388129070]: ----> Karto SLAM started.
[ INFO] [1637561045.420115628]: Use back end.
[ INFO] [1637561045.420160652]: solver type is GtsamSolver.

在运行前期, 由于没有找到回环, 所以一直没有进行优化. 在最后阶段产生回环时, 会调用基于ceres的优化, 并打印处如下的log.

[ INFO] [1637563465.472380312, 1606808846.502199766]: [gtsam] Calling gtsam for Optimization
[ INFO] [1637563465.841370726, 1606808846.864457794]: [gtsam] Calling gtsam for Optimization

优化前

请添加图片描述

优化后

前几次优化之后, 可以看到, 地图的方向发生了变化. 但是误差依然存在
请添加图片描述在最后一次的优化完成之后, 地图和雷达数据才完全匹配上.

可以感受到, gtsam的优化在效果上没有g2o与ceres的优化的效果好. 而且地图的方向还会发生变化.
请添加图片描述

最终的地图

请添加图片描述

4 总结

通过这篇文章, 我们知道了如何使用gtsam进行后端优化, 体验了gtsam进行优化的效果.

下篇文章将进行从零开始搭二维激光SLAM系列的总结, 与下个系列的期望.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零开始搭二维激光SLAM --- 基于gtsam的后端优化的代码实现 的相关文章

  • 进程内存使用

    查看进程内存使用 28028 是进程的pid top p 28028 还可以查看进程的status文件 xff1a cat proc 28028 status VmRSS对应的值就是物理内存占用 内存占用比较多的程序 ps aux sort
  • perf使用

    perf可记录高达700多种events事件 sudo perf list 可以查看可以perf的事件 sudo perf record F 999 e cpu clock faults a g p 28544 sleep 60 制定进程7
  • gperftools

    gperftools 实现了更高性能的多线程的malloc 实现 增加了极好的性能分析工具 gperftools 的前身是 pprof https github com google pprof sudo apt get install a
  • RDMA 设备查看

    1硬件检测 1 1检查硬件是否安装 确认硬件已安装 lspci tvm grep Mellanox 查看OFED驱动版本命令 如果没有驱动可以参考 https km sankuai com page 335338645 安装 rpm qa
  • spark 转换tfrecord 成parquet格式

    读取tfrecord 成parquet文件格式 read tfrecord py coding utf 8 34 34 34 读取tfrecord生成parquet文件格式 34 34 34 import os import time im
  • ffmpeg压缩视频

    安装ffmpeg conda install c conda forge x264 61 61 39 1 161 3030 39 ffmpeg 61 4 3 2 压缩mov视频 ffmpeg i movie mov c v libx264
  • AI行动,解放做表打工人

    1 atomecho 插件介绍 如果你是个 需要做财报 数据新闻的冤种 xff1b 或者是 网上有的我都想要 的囤积狂魔 xff1b 或是沉迷 Ctrl 43 C Ctrl 43 V 的做表工具人 那你一定不陌生 对不上的格式 找不到的数据
  • golang高性能rocksdb参数配置

    golang高性能rocksdb参数配置 import 34 errors 34 34 log 34 34 monorepo service autotable comm grocksdb 34 34 strings 34 34 githu
  • Linux doc和docx转换pdf

    准备工作 服务器安装libreoffice apt get install libreoffice 安装完成libreoffice后 xff0c 测试是否安装成功 soffice h 例子 把 tmp test docx 转换成 tmp t
  • 多个硬盘挂载到同一个目录

    同一目录无法重复挂载 xff0c 后挂载的会覆盖之前挂载的磁盘 但是现在需要将4块磁盘并行挂载 xff0c 该如何操作呢 xff1f 将2块磁盘合并到一个逻辑卷 进行挂载 基本知识 基本概念PV Physical Volume 物理卷物理卷
  • LeetCode 跳跃游戏 题解

    题述 xff1a 给定一个非负整数数组 nums xff0c 你最初位于数组的 第一个下标 数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标 思路 xff1a 阅读题目我们可以发现只要数组里面没有0 我们就一
  • #error This file was generated by a newer version of protoc which is 【protoc版本问题】

    在github上下载自己适合的protoc版 xff08 我的环境是ubuntu18 04 ros melodic版本 xff09 gazebo9对应的最低版本protoc为3 0 0 我之前版本为3 14 0会提示目前文件由旧版本生成 x
  • Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

    前段时间 xff0c 公司同事开发了一个小工具 xff0c 在工具执行过程中 xff0c UI 界面一直处于卡死状态 通过阅读代码发现 xff0c 主要是由于 Dispatcher BeginInvoke 方法使用不当导致的 本文将通过一个
  • List的Clear方法与RemoveAll方法用法小结

    示例代码 using System using System Collections Generic namespace ListClearExp class Program static void Main string args Lis
  • 利用C#访问注册表获取软件的安装路径

    绝大多数软件 xff0c 基本上都会在注册表中记录自己的名字和安装路径信息 在注册表中记录这些信息的位置是 xff1a HKEY LOCAL MACHINE SOFTWARE Microsoft Windows CurrentVersion
  • 使用ValidationRule类来检查用户输入的有效性

    1 新建WPF应用程序ValidationRuleExp 整个程序的结构如下图所示 程序运行起来后的效果如下图所示 用户操作程序时 xff0c 先输入固话 手机 Email 个人网站等信息 xff0c 再点击右侧的 点我记住你 按钮 xff
  • 关闭窗体后,进程仍然在运行的问题重现与解决

    1 问题陈述 在开发中 xff0c 遇到这样一个问题 xff1a 点击程序主窗体右上角的叉号关闭应用程序后 xff0c 程序的进程却没有关闭 通过查阅资料 xff0c 了解到 xff0c 产生此类问题的原因主要有以下两点 xff1a 1 x
  • Python判断一个字符串是否包含子串的几种方法

    1 使用成员操作符 in span class hljs prompt gt gt gt span s 61 span class hljs string 39 nihao shijie 39 span span class hljs pr
  • easyui-datagrid获取行和列数据

    1 获取当前行 span class hljs keyword var span row 61 span class hljs string 39 dg 39 span datagrid span class hljs string 39
  • No plugin found for prefix ‘tomcat7’ in the current project and in the plugin groups

    idea中开发javaweb应用 xff0c 使用mvn tomcat7 run命令运行应用时 xff0c 需要配置tomcat的maven插件 在没有配置的情况下会出现下面的错误提示 ERROR No plugin found for p

随机推荐

  • C#中的IComparable和IComparer接口

    C 中 xff0c 自定义类型 xff0c 支持比较和排序 xff0c 需要实现IComparable接口 IComparable接口存在一个名为CompareTo 的方法 xff0c 接收类型为object的参数表示被比较对象 xff0c
  • LeetCode Nim游戏 题解

    题述 xff1a 你和你的朋友 xff0c 两个人一起玩 Nim 游戏 xff1a 桌子上有一堆石头 你们轮流进行自己的回合 xff0c 你作为先手 每一回合 xff0c 轮到的人拿掉 1 3 块石头 拿掉最后一块石头的人就是获胜者 假设你
  • C#接口汇总

    1 IComparable和IComparer接口 用于比较和排序 IComparable 可比较的 xff0c 实现该接口的类 xff0c 便具有 可比较的 特性 IComparer 比较器 xff0c 实现该接口的类 xff0c 是一个
  • Python操作环境变量

    1 使用os读取环境变量 import os os getenv 39 path 39 os environ get 39 path 39 os environ 39 path 39 2 遍历打印所有环境变量 通过访问os environ可
  • 教程 | 阿克曼结构移动机器人的gazebo仿真(一)

    第一章 从SOLIDWORKS中导出URDF 二轮差速小车已经完结 接下去要进入阿克曼结构移动机器人的仿真 阿克曼小车的结构也就是我们看到最多的应用最广的车型 xff0c 也称为car like robot 在这里先挖下一个大坑 xff0c
  • TIANBOT MINI机器人使用blender进行贴图并导出详细教程

    很多小伙伴在看一些仿真视频中会看到 xff0c 仿真模型栩栩如生 xff0c 但是我们自己导出的模型总是不堪入目 xff0c 哪是因为你还没学会贴图 xff0c 下面我来教大家一步一步怎么学会贴图 首先我们打开blender并设置好简体中文
  • 什么是ROS2GO随身系统?

    随着ROS xff08 Robot Operating System xff09 机器人操作系统的越来越热 xff0c 大家都跃跃欲试 想一睹ROS的风采 xff0c 感受ROS的魅力 但是挡在初学者面前的第一个难题就是如何在Ubuntu系
  • 教程 | 阿克曼结构移动机器人的gazebo仿真(二)

    第二章 配置xacro文件 0 前言 上一节已经将urdf导出来了 xff0c 这一节需要配置一下xacro文件 先看一下导出的功能包在gazebo以及rviz中显示的效果 将功能包放进工作空间进行编译 xff0c source一下环境 x
  • 教程 | 阿克曼结构移动机器人的gazebo仿真(三)

    第三章 让小车动起来 1 配置controller 在tianracer description功能包新建config文件夹时 xff0c 我们可以通过一个yaml文件smart control config yaml来声明我们所需要的co
  • 教程 | 阿克曼结构移动机器人的gazebo仿真(五)

    第四章 用xacro优化URDF并配置gazebo仿真插件 1 前言 上节用简易模型写了一个小车的URDF代码 xff0c 这一节将用xacro对其进行优化 xff0c 这里我并不打算用宏对参数进行封装 xff0c 因为我个人觉得这样看起来
  • 教程 | Jetson Xavier NX 开发板强化学习环境配置流程

    一 基本介绍 NX开发板 全名Jetson Xavier NX xff08 后简称为NX xff09 xff0c 是NVIDIA英伟达提供的模组和开发者套件 xff0c 保持Jetson Nano小巧尺寸的同时拥有相当于Jetson TX2
  • 免费教程·开源 | 从零开始制作ROS无人竞速车RACECAR教程

    一 课程前提 自动驾驶汽车即将成为交通出行的主流工具之一 xff0c 它以计算机 现代汽车产业技术为基础 xff0c 以数字化 智能化为依托实现自动化驾驶 xff0c 学习自动驾驶需要了解架构 环境感知 行为决策 规划路径 xff0c 多传
  • c++ 继承 学习总结3 继承中父类和子类同名非静态成员或者同名静态成员的处理方式

    1 继承中父类和子类有同名非静态成员的处理方式 eg include lt iostream gt using namespace std class Base public Base m A 61 100 void func cout l
  • 2022ROS暑期学校暨人工智能与机器人论坛报名及日程安排

    机器人操作系统 ROS 暑期学校自2015年举办以来 xff0c 被中国机器人业界和学界 xff0c 以及ROS开源基金会誉为除了ROSCon之外规模最大 参与人数最多 最成功的ROS线下活动 过去八年 xff0c 共吸引了全国300多所高
  • MATLAB Simulink开发ROS无人车与机器人应用 详细教程

    引言 xff1a MATLAB在机器人中的应用 现在大多数机器人开发者都会选择ROS xff0c 在ROS整个框架下 调包 极其容易 很多ROS开发者热衷于 调包 来实现功能 xff0c 却难以在机器人学的理论知识上有所突破 MATLAB的
  • DE1-SOC入门之Linux开发环境搭建

    入手DE1 SOC这块FPGA也有两三个月了 xff0c 将友晶提供的入门学习例程 代码等摸索了一下 xff0c 感觉正常的fpga和arm之间的通信 控制已经没多大问题了 可是很多时候 xff0c 事情没有自己想的那么简单 现在接手的项目
  • sensor_msgs/NavSatFix Message

    1 sensor msgs NavSatStatus Message http docs ros org en api sensor msgs html msg NavSatStatus html Navigation Satellite
  • 零基础如何入门激光SLAM

    零基础如何入门激光SLAM 最近有几个人加我 xff0c 都说是刚开始学激光slam xff0c 基本都是研一 xff0c 也有一些大四的 xff08 大四的都开始学SLAM了 xff01 xff09 情况也都差不多 xff0c 有的是课题
  • 从零开始搭二维激光SLAM --- 栅格地图的构建

    上周搬家 导致这篇文章更新的慢了点 之前的文章我们都是通过scan to scan的方式进行位姿变换的计算 接下来的文章将带领大家体验scan to map的计算位姿变换的方式 首先 来简要介绍一下什么是map 1 地图与占用栅格地图 1
  • 从零开始搭二维激光SLAM --- 基于gtsam的后端优化的代码实现

    上一篇文章我们分析了如何使用ceres进行位姿图的优化 这篇文章来讲一下如何使用gtsam进行位姿图的优化 1 gtsam简介 gtsam是最近几年火起来的一个优化库 GTSAM xff08 Georgia Tech Smoothing a