SLAM——之GTSAM函数库

本文介绍了GTSAM库中如何利用因子图表示隐马尔可夫模型,并详细展示了使用BetweenFactor和PriorFactor构建高斯因子图的过程。重点讲解了信赖区域法(列文伯格方法)在优化估计中的应用,通过实际代码演示了如何使用LevenbergMarquardtOptimizer进行最小二乘求解。最后,展示了如何计算变量的边缘概率和信息量。

Factor Graphs and GTSAM

1. 因子图表达

在这里插入图片描述

  1. 上图为一个HMM(隐马尔可夫链)模型
    在这里插入图片描述
  2. 其因子图为(用来极大化最大后验误差):

在这里插入图片描述
以一个马尔可夫链为例
在这里插入图片描述
在这里插入图片描述
代码:

//BetweenFactor 包含描述两个因子之间相关操作类
//              和初始状态概率矩阵
#include <gtsam/slam/BetweenFactor.h>
//误差
#include <gtsam/slam/PriorFactor.h> 
//非线性
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
//列文伯格求解方程组
#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
//Pose2 类库 把3d点用作(x,y,theta)表示
#include <gtsam/geometry/Pose2.h>
#include <iostream>
//计算边缘分布
#include <gtsam/nonlinear/Marginals.h>

//指定列文伯格迭代的初始值
#include <gtsam/nonlinear/Values.h>
#include <gtsam/base/Vector.h>
#include <CppUnitLite/TestHarness.h>// 单元测试库
#include <boost/shared_ptr.hpp>
#include <boost/assign/std/list.hpp>
using namespace std;
using namespace gtsam;
int main(int argc, const char** argv) {
    NonlinearFactorGraph graph;//高斯因子图

    //3d点
    Pose2 priorMean(0,0,0);//先验值 x,y,theta
    //Pose2(Point2,Rot2):位置姿态
    //Rot2(cos(theta),sin(theta)):夹角的余弦值和正弦值
    
    //添加噪声,替他还有gussian,Robust、Unit 噪声
    noiseModel::Diagonal::shared_ptr priorNoise=noiseModel::Diagonal::Sigmas(Vector3(0.3,0.3,0.1));
    //Eigen::Vector3
    //sigma函数:1/(1+e^(-z))
    noiseModel::Diagonal::shared_ptr odometryNoise = noiseModel::Diagonal::Sigmas(Vector3(0.2, 0.2, 0.1));
    //在因子图中添加因子(//初始化)
    //graph.add(PriorFactor<Pose2>(1,priorMean,odometryNoise));//添加单个
    graph.emplace_shared<PriorFactor<Pose2> >(1,priorMean,priorNoise);//可以添加多个
    //1 因子图顺序 priorMean 数据 odometryNoise 噪声
    Pose2 odometry(2.0,0,0);
    graph.emplace_shared<BetweenFactor<Pose2> >(1,2,odometry,odometryNoise);
    //t-1:1,t:2 odometry数据,odometryNoise噪声
    
    graph.emplace_shared<BetweenFactor<Pose2> >(2,3,odometry,odometryNoise);

    graph.print("\nFactor Graph:\n");//等价与print

    Values initial;
    //初始化观测矩阵
    initial.insert(1, Pose2(0.5, 0.0, 0.2));//插入观测数据
    initial.insert(2, Pose2(2.3, 0.1, -0.2));
    initial.insert(3, Pose2(4.1, 0.1, 0.1));
    initial.print("\nInitial Estimate:\n"); // print

    //使用列文伯格迭代求解最小二乘:min(z-gussan(x+w)-gussan(y+v)+gussan(z+e))
    Values result=LevenbergMarquardtOptimizer(graph,initial).optimize();//经过三次迭代后的预测值
    result.print("Final Result:\n");

    
    //cout<<"date"<<result.find(1)<<endl;
    //cout<<<"result:"<<<<endl;
    cout.precision(2);//精度 streamsize设为2,小数点后两为
    

    
    //计算非线性因子图中变量的高斯边缘概率
    Marginals marginals(graph, result);
    
    cout << "x1 covariance:\n" << marginals.marginalCovariance(1) << endl;   
    cout << "x2 covariance:\n" << marginals.marginalCovariance(2) << endl;
    cout << "x3 covariance:\n" << marginals.marginalCovariance(3) << endl;
    cout << "x1 marginalInformation:\n" << marginals.marginalInformation(1) << endl;
    cout << "x2 marginalInformation:\n" << marginals.marginalInformation(2) << endl;
    cout << "x3 marginalInformation:\n" << marginals.marginalInformation(3) << endl;
    
    //查询优化结果
    for (const gtsam::Values::ConstKeyValuePair& key_value: result )
    {   
        cout<<"key "<<key_value.key<<endl;
        Pose2 pose = key_value.value.cast<gtsam::Pose2>();//类型转换
        cout<<"data:"<<pose.matrix()<<endl;
    }
    //遍历
    for ( gtsam::NonlinearFactor::shared_ptr factor: graph )//遍历因子图节点
    {
         gtsam::BetweenFactor<gtsam::Pose2>::shared_ptr f = dynamic_pointer_cast<gtsam::BetweenFactor<gtsam::Pose2>>( factor );//提取边
         if (f){
                 gtsam::SharedNoiseModel model = f->noiseModel();//提取噪声模型
                 gtsam::noiseModel::Diagonal::shared_ptr DiagModel = dynamic_pointer_cast<gtsam::noiseModel::Diagonal>( model );//从噪声模型提取高斯模型
                 if ( DiagModel )
                {       
                    gtsam::Matrix info;   
                    gtsam::Vector DiagModel_sigma=DiagModel->sigmas();
                    cout<<"DiagModel_sigma:"<<DiagModel_sigma<<endl;//输出误差
                    Pose2 pose=f->measured();
                    cout<<"data:"<<pose.matrix()<<endl;//显示测量
                }
         }
    }
    return 0;
}

2. gstam 中的信赖区域法(或列文伯格方法)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 官网Factor Graphs and GTSAM

### SLAM14讲第11章内容总结 SLAM14讲的第11章主要围绕 **基于图优化的SLAM技术** 展开讨论,重点在于如何通过构建全局一致性地图来解决累积误差问题。这一章节从理论基础到实际应用进行了全面阐述。 #### 图优化的核心概念 图优化是一种将SLAM问题建模为最优化问题的方法。具体来说,它将机器人轨迹和环境特征的关系抽象成一个带权重的无向图结构[^1]。其中: - 节点代表机器人的位姿或路标位置; - 边则表示节点之间的约束关系(例如由传感器测量得到的信息)。 目标是最小化所有边上的残差函数,从而获得最优的状态估计。常见的能量函数形式如下: ```math E(X) = \sum_{i,j} e_{ij}(X)^T \Omega_{ij} e_{ij}(X) ``` 此处 \(e_{ij}\) 表示观测残差,\(\Omega_{ij}\) 是对应的协方差矩阵逆。 #### 帧间配准与闭环检测 为了减少漂移并提高定位精度,本章还深入探讨了两种关键技术——帧间配准和闭环检测。 - **帧间配准** 主要用于连续帧之间的小范围运动估计,通常依赖于ICP算法或其他相似度量方法。 - **闭环检测** 则负责识别先前访问过的区域,消除长时间运行过程中积累的位置偏差[^3]。 #### 实现细节与工具支持 针对实际开发需求,作者推荐了一些常用的开源框架和技术手段辅助完成上述任务。比如GTSAM库提供了强大的非线性最小二乘求解器功能;而ROS环境下也有专门插件可以方便集成这些高级特性[^4]。 以下是部分伪代码展示如何初始化一个简单的图优化流程: ```python import gtsam def initialize_graph(): graph = gtsam.NonlinearFactorGraph() # Add prior on the first pose initial_estimate = gtsam.Values() priorMean = gtsam.Pose2(0.0, 0.0, 0.0) priorNoise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1])) graph.add(gtsam.PriorFactorPose2(1, priorMean, priorNoise)) return graph,initial_estimate ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大江东去浪淘尽千古风流人物

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值