cartographer 代码思想解读(1)- 相关匹配

cartographer 代码思想解读(1)- 相关匹配


cartographer在2016年开源后一直在使用,但是一直未仔细阅读并分析其核心代码结构。目前网上可以找到许多博主对其分析和理解。其cartographer的基本思想可参考他人的 博主博客。本博客主要目的根据其框架思想,将其核心算法进行提取,方便后续学习和移植。其google开源的代码量太大,层次太多,大量虚函数,继承关系,功能齐全,并且采用大量的C++11.0新特性等许多原因,导致阅读代码难度加大。因此此次阅读仅对slam核心算法及其思想进行总结。

前端

基本上所有了解slam的人都知道SLAM可分为前端和后端处理,其中前端处理是slam的前提,通常称为帧间匹配,即将新的一帧激光点云和上帧或多帧进行匹配,获取新时刻位置的过程,cartographer也不例外。仔细阅读源码发现,cartographer并非仅一种前端匹配算法,本节仅分析其中一种:采用相关匹配的方法。(注:实际采用的是优化的方法)
帧间匹配主要包括:scan-to-scan、scan-to-map 和优化的方法。
其中cartographer源码中存在一种scan-to-map的相关匹配的算法,其代码目录:cartographer/mapping/internal/2d/scanmathing

栅格地图

Cartographer采用的是当前新的scan激光帧,是否匹配submap并加入。其submap为栅格地图,可以认为submap为一个2维数组,其每个索引下的value值表示概率。为提高运算性能和速度,cartographer将概率表示进行优化,包括概率整数化和对数化。其栅格地图代码目录:cartographer/mapping/2d/grid.h。后续将加入专门代码详解和cartographer的优化。

相关匹配

顶层方法文件目录:cartographer/mapping/internal/2d/scanmathing/real_time_correlative_scan_matcher_2d.cc
调用入口方法为double RealTimeCorrelativeScanMatcher2D::Match

double RealTimeCorrelativeScanMatcher2D::Match(
    const transform::Rigid2d& initial_pose_estimate,
    const sensor::PointCloud& point_cloud, const Grid2D& grid,
    transform::Rigid2d* pose_estimate) const {
  CHECK(pose_estimate != nullptr);
  //获取初始位置的角度
  const Eigen::Rotation2Dd initial_rotation = initial_pose_estimate.rotation();
  //将当前点云转换为初始角度坐标系下点云
  const sensor::PointCloud rotated_point_cloud = sensor::TransformPointCloud(
      point_cloud,
      transform::Rigid3f::Rotation(Eigen::AngleAxisf(
          initial_rotation.cast<float>().angle(), Eigen::Vector3f::UnitZ())));
  // 定义搜索的空间,包括平移的窗口和角度窗口
  // options_ 为配置参数,由上层调用传入
  const SearchParameters search_parameters(
      options_.linear_search_window(), options_.angular_search_window(),
      rotated_point_cloud, grid.limits().resolution());
  // 在一定角度搜索空间中(一定窗口内,一定分辨率,如1度分辨率, 搜索范围100度,共100个角度空间),
  // 对当前点云进行旋转变换,放入vector中
  const std::vector<sensor::PointCloud> rotated_scans =
      GenerateRotatedScans(rotated_point_cloud, search_parameters);
  // 将点云进行坐标转换到世界坐标系坐标,即根据当前估计位置(可以为里程计的位置)进行转换
  const std::vector<DiscreteScan2D> discrete_scans = DiscretizeScans(
      grid.limits(), rotated_scans,
      Eigen::Translation2f(initial_pose_estimate.translation().x(),
                           initial_pose_estimate.translation().y()));

  // 初始化在xy平移空间内偏移量,即窗口大小和偏移量
  std::vector<Candidate2D> candidates =
      GenerateExhaustiveSearchCandidates(search_parameters);

  // 计算当前帧在角度、x、y三层窗口中每个状态在grid地图中的匹配的评分
  ScoreCandidates(grid, discrete_scans, search_parameters, &candidates);

  //采用标准库,迭代获取最大置信度元素
  const Candidate2D& best_candidate =
      *std::max_element(candidates.begin(), candidates.end());
  // 坐标转换为全局坐标
  *pose_estimate = transform::Rigid2d(
      {initial_pose_estimate.translation().x() + best_candidate.x,
       initial_pose_estimate.translation().y() + best_candidate.y},
      initial_rotation * Eigen::Rotation2Dd(best_candidate.orientation));
  return best_candidate.score;
}

以上为接口代码简单注释。cartographer采用的相关匹配算法基本上可以认为是一种暴力搜索匹配算法,即采用当前的激光帧在已知的栅格地图上进行遍历匹配,获取相关性最高的位置,即置信度最高的位置。其思想几乎与KartoSLAM中的帧间匹配方法一致,但对其进行了一定优化。
3重循环暴力匹配伪代码如下:

for(x)
	for(y)
		for(theta)
			point_new= point_old
			bel = sum(point_new)/sum_num

其思想采用了3重循环,在submap中的一定范围内,进行暴力匹配。其步骤如下:

  1. 将激光点云先转换至估计坐标的世界坐标系下;
  2. 采用了预先定义x、y、yaw三个窗口大小;
  3. 将角度进行序列化生成序列,并将点云按照序列后的角度值进行旋转,即可生成N个点云序列。
  4. 将x,y按照窗口,分辨率进行序列化,即求出应当遍历的所有索引(因为x,y窗口仅需要加减平移)。
  5. 对以上所有点云在栅格地图中获取最大置信度,仅需查表读取概率值和并归一化;

其相对于KartoSLAM优化点,包括两点:
1.采用空间换取了运算性能,将其遍历的x、y层循环不做实际处理,仅保存其索引队列。同时将角度循环提前遍历并保存所有序列。后续可采用vector迭代和库进行批量处理。
2.减少乘除与sin,cos运算。三层循环最先进行角度旋转,因此sin和cos的运算的次数仅为执行角度量化个数。而后点云转换均为加减运算。

疑问点

1.此相关算法在代码实现上没有看出特别出众之处,可能理解不深。
2.由暴力匹配后得到的置信度,即point在栅格图的概率和并归一化后的结果。而cartographer提供的相关算法,在获取的置信度进行了一次基于与初始位置高斯权重处理作为最终的置信度。

    // 此处没看明白????,为什么归一化后的匹配置信度需要加权重,和初始位置距离的高斯分布的概率权重
    candidate.score *=
        std::exp(-common::Pow2(std::hypot(candidate.x, candidate.y) *
                                   options_.translation_delta_cost_weight() +
                               std::abs(candidate.orientation) *
                                   options_.rotation_delta_cost_weight()));
  • 10
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在cartographer中,使用2D点云进行扫描匹配时,可以使用ceresscanmatch功能。这个功能是基于Ceres Solver库实现的。Ceres Solver是一个非线性优化库,用于解决各种最小化问题。在cartographer中,ceresscanmatch被用于解决2D点云匹配的问题。 具体来说,ceresscanmatch用于匹配两个相邻帧的2D点云。在进行扫描匹配时,需要先对数据进行滤波处理,然后使用ceres进行优化,找到两个点云之间的最佳匹配。在这个过程中,需要使用一种优化算法来最小化匹配误差,这个误差是通过计算点云之间的距离来得到的。 相比于其他扫描匹配方法,ceresscanmatch的优势在于它能够进行非常精准的匹配。这是因为它使用了一个非线性优化算法,能够处理复杂的误差函数和约束条件。此外,ceresscanmatch还支持使用多种不同的误差函数,以适应不同的应用场景。 总之,ceresscanmatch是cartographer中用于2D点云扫描匹配的一个非常重要的功能,它能够让我们更加准确、稳定地进行扫描匹配,并且支持广泛的应用场景。 ### 回答2: 本文将继续介绍cartographer中的ceres扫描匹配部分,ceres扫描匹配是利用Ceres Solver进行的位姿优化,可以准确估计机器人运动的姿态。 ceres扫描匹配部分主要包括ceres_scan_matcher.cc和ceres_scan_matcher.h两个文件。其中ceres_scan_matcher.cc包含了ceres扫描匹配算法的具体实现,而ceres_scan_matcher.h则是相关的头文件。 ceres_scan_matcher.cc中的函数主要有两个,分别是CeresScanMatcher::Match()和CeresScanMatcher::MatchFullSubmap()。其中,CeresScanMatcher::Match()函数用于实现一次扫描匹配,输入参数为当前激光数据和候选的位姿,输出参数为匹配的位姿和评估值。 在CeresScanMatcher::Match()函数中,先通过叶芽上下文来获取轨迹和submap,然后将当前激光数据转换为点云,并对点云进行滤波和预处理,接着定义优化问题和相关的参数,其中优化问题使用ceres::Problem类来定义,相关参数则定义在CeresScanMatcherOptions结构体中,最后通过ceres::Solve()函数进行位姿优化。 CeresScanMatcher::MatchFullSubmap()函数则用于在整个submap上进行匹配,并返回匹配的位姿和评估值。它的实现与CeresScanMatcher::Match()函数类似,只是输入参数为整个submap的信息。 综上所述,ceres扫描匹配部分利用Ceres Solver进行位姿优化,可以准确估计机器人运动的姿态,是cartographer中重要的功能之一。 ### 回答3: cartographer是一款开源的SLAM系统,其源代码完整透明,方便研究和理解。其中,2D点云扫描匹配cartographer中的一个重要功能,而这一功能又是由ceres扫描匹配实现的。 ceresscanmatch是cartographer中的一个重要模块,用于实现2D点云的扫描匹配。在这个模块中,ceres solver被用来进行优化过程。具体来说,ceresscanmatch会将已知位姿下的实测点云与预测的点云进行匹配,得到匹配误差。随后,ceres solver会对这些匹配误差进行非线性优化,最终得到最优位姿。这样,就能够实现快速准确的2D点云扫描匹配,从而提高了SLAM系统的性能和精度。 在详细研究ceresscanmatch之前,首先需要了解一下ceres solver。ceres solver是一个基于C++的非线性优化库,用于解决复杂的数值优化问题。在cartographer中,ceres solver被用来进行扫描匹配的优化过程,应用目标函数和求解器来寻求最优解。其中,目标函数是由误差项和状态变量构成的,求解器则用来解决这个目标函数并确定状态变量的最优化值。 具体而言,在cartographer中,扫描匹配的目标函数是根据传感器数据得出的,其包括一系列误差项和参考帧的相对位姿。在每个迭代步骤中,ceres solver会计算目标函数的梯度和海森矩阵,并利用这些值来更新参考帧的位姿。当误差项最小化时,相对位姿就能够得到最优解。 总之,ceresscanmatch是cartographer中的一个重要模块,用于实现2D点云的扫描匹配。借助ceres solver进行优化,可以实现高效准确的扫描匹配,为SLAM系统的实现提供了重要的基础。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值