张鹏辉

个人站

欢迎来到我的个人站,本人小白,希望大家指导。


minisam(二)例程 A 2D pose-graph example

说明:本系列博客用来记录本人在学习minisam过程中的理解,方便同大家一起谈论。

一、简单的二维位姿案例

在这里我们使用因子图来解决二维位姿例程。如图所示,

我们要估计小车在时的位姿,定义系统的状态变量:

其中,.

使用因子图将该问题建模为:

二、c++程序分析

查看所有源程序(含有自己写的中文注释),点击这里源代码链接

1.第一步,创建因子图框架,加入一个先验因子(prior factor),中间因子(between factor),各损失函数,闭环约束等。


  FactorGraph graph;

  // 在第一位置上加入一个先验,并将其设置为原点
  // 先验需要在世界坐标系下去修改/校正运行轨迹
  // 先验因子包括一个均值和损失函数(协方差矩阵)

  const std::shared_ptr<LossFunction> priorLoss =
      DiagonalLoss::Sigmas(Eigen::Vector3d(1.0, 1.0, 0.1));   //先验因子的损失函数
  graph.add(PriorFactor<Sophus::SE2d>(
      key('x', 1), Sophus::SE2d(0, Eigen::Vector2d(0, 0)), priorLoss));   //添加先验因子

  // 里程计测量的误差函数
  const std::shared_ptr<LossFunction> odomLoss =
      DiagonalLoss::Sigmas(Eigen::Vector3d(0.5, 0.5, 0.1));

  // 在连续位姿之间添加Between Factor
  // 每次前进5个单位,运动到x3-x5时会有向右90°的转动
  graph.add(BetweenFactor<Sophus::SE2d>(
      key('x', 1), key('x', 2), Sophus::SE2d(0.0, Eigen::Vector2d(5, 0)),
      odomLoss));
  graph.add(BetweenFactor<Sophus::SE2d>(
      key('x', 2), key('x', 3), Sophus::SE2d(-1.57, Eigen::Vector2d(5, 0)),
      odomLoss));
  graph.add(BetweenFactor<Sophus::SE2d>(
      key('x', 3), key('x', 4), Sophus::SE2d(-1.57, Eigen::Vector2d(5, 0)),
      odomLoss));
  graph.add(BetweenFactor<Sophus::SE2d>(
      key('x', 4), key('x', 5), Sophus::SE2d(-1.57, Eigen::Vector2d(5, 0)),
      odomLoss));

  // 闭环检测的误差函数
  const std::shared_ptr<LossFunction> loopLoss =
      DiagonalLoss::Sigmas(Eigen::Vector3d(0.5, 0.5, 0.1));

  // 加入闭环约束
  graph.add(BetweenFactor<Sophus::SE2d>(
      key('x', 5), key('x', 2), Sophus::SE2d(-1.57, Eigen::Vector2d(5, 0)),
      loopLoss));

  graph.print();
  cout << endl;


2.第二步,加入变量初始值和随机噪声。


  // 加入变量初始值
  // 加入随机噪声(自定义?) 
  Variables initials;

  initials.add(key('x', 1), Sophus::SE2d(0.2, Eigen::Vector2d(0.2, -0.3)));
  initials.add(key('x', 2), Sophus::SE2d(-0.1, Eigen::Vector2d(5.1, 0.3)));
  initials.add(key('x', 3),
               Sophus::SE2d(-1.57 - 0.2, Eigen::Vector2d(9.9, -0.1)));
  initials.add(key('x', 4),
               Sophus::SE2d(-3.14 + 0.1, Eigen::Vector2d(10.2, -5.0)));
  initials.add(key('x', 5),
               Sophus::SE2d(1.57 - 0.1, Eigen::Vector2d(5.1, -5.1)));

  initials.print();
  cout << endl;


  1. 使用Levenberg-Marquard优化方法进行优化,并输出优化结果。

  // 调用 LM 方法对初值进行优化
  LevenbergMarquardtOptimizerParams opt_param;
  opt_param.verbosity_level = NonlinearOptimizerVerbosityLevel::ITERATION;
  LevenbergMarquardtOptimizer opt(opt_param);

  Variables results;

  auto status = opt.optimize(graph, initials, results);
  if (status != NonlinearOptimizationStatus::SUCCESS) {
    cout << "optimization error" << endl;
  }

  results.print();
  cout << endl;


  1. 计算边际协方差(误差)

MarginalCovarianceSolver mcov_solver;

  auto cstatus = mcov_solver.initialize(graph, results);
  if (cstatus != MarginalCovarianceSolverStatus::SUCCESS) {
    cout << "maginal covariance error" << endl;
  }

  Eigen::Matrix3d cov1 = mcov_solver.marginalCovariance(key('x', 1));
  Eigen::Matrix3d cov2 = mcov_solver.marginalCovariance(key('x', 2));
  Eigen::Matrix3d cov3 = mcov_solver.marginalCovariance(key('x', 3));
  Eigen::Matrix3d cov4 = mcov_solver.marginalCovariance(key('x', 4));
  Eigen::Matrix3d cov5 = mcov_solver.marginalCovariance(key('x', 5));

  cout << "cov pose 1:" << cov1 << endl;
  cout << "cov pose 2:" << cov2 << endl;
  cout << "cov pose 3:" << cov3 << endl;
  cout << "cov pose 4:" << cov4 << endl;
  cout << "cov pose 5:" << cov5 << endl;


三、代码运行结果分析

显示初始值。

优化结果。如图,起初误差为18.6051,经过三次迭代之后,误差为0.00012…,收敛,优化停止,输出优化后的位姿。

计算的边际协方差结果如图显示,但并不直观,可用matlab工具画图,这里就不予展示了。


转载请注明:张鹏辉的博客 » minisam2

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦