转载@梦凝小筑

本人的研究方向为激光SLAM,因此对于Google Cartographer 的经典算法十分感兴趣,但是苦于该算法的论文是英文写作,且该论文有着公式多,解释少的特点。因此在看了原论文和网上的各种论文解读,都没有能够完全把这块硬骨头吃下去。

机缘巧合,本人研究生课程高等运筹学大作业需要运用和Google Cartographer 中的闭环检测 相同的方法,结合Cartographer的源代码,才彻底将Cartographer论文搞懂。因此在这里写一篇比较完整的总结,方便大家相互学习讨论!

贴出本人参考的一些链接

官方资料1:https://google-cartographer-ros.readthedocs.io/en/latest/going_further.html

官方资料2:https://google-cartographer.readthedocs.io/en/latest/

论文链接1:https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/45466.pdf

论文链接2:https://april.eecs.umich.edu/pdfs/olson2009icra.pdf

参考链接:https://zhehangt.github.io/2017/05/01/SLAM/Cartographer/CartographerPaper/

Cartographer 论文解读
一、Introduction
    在建图上应用SLAM并不是一个新的概念,这里不再作为本文的重点。

本文的贡献在于:提出了一种新的基于激光数据的回环检测方法,这种方法可以减少计算量,可以满足大空间的建图需要,并且对大规模数据进行实时优化。

hector并没有应用到回环检测,而google在此基础上进行改进,并应用上了回环检测,,还是值得学习和借鉴的。

二、Related Work
    相关工作不再赘述,直接搬用索哥的总结

相关工作中首先介绍了scan matching的几种方法:

1.scan-to-scan matching是基于激光SLAM中最常用来估计相关位姿的。但是非常容易造成累积误差。

2.scan-to-map matching 可以减少累积误差,因为scan-to-map每次都通过高斯-牛顿法获得局部最优的位姿,前提是要有一个比较好的初始化位姿估计

3.pixel-accurate scan matching 可以进一步减小局部误差,但是计算量比较大。这个方法同样可以用来检测回环。

4.从laser scan 中提取特征,从而减少计算量。histogram-based matching用于回环检测。用机器学习做laser scan的特征检测。

之后介绍了处理累积误差的两种方式

1.基于粒子滤波的优化。粒子滤波在处理大场景地图时,由于粒子数的极具增长造成资源密集。

2.基于位姿图的优化。与视觉SLAM的位姿图优化大同小异,主要是在观测方程上的区别。

三、System Overview
    Cartographer 能产生一个精度为5cm的2D栅格地图。

Cartographer在前端匹配环节区别与其它建图算法的主要是使用了Submap这一概念,每当或得一次laser scan的数据后,便与当前最近建立的Submap去进行匹配,使这一帧的laser scan数据插入到Submap上最优的位置。(这里用的是高斯牛顿解最小二乘问题)在不断插入新数据帧的同时该Submap也得到了更新。一定量的数据组合成为一个Submap,当不再有新的scan插入到Submap时,就认为这个submap已经创建完成,接着会去创建下一个submap,具体过程如下图。(这里没有理解什么情况下新的scan不会再匹配到该Submap上)

因此这里scan matching的本质是当前laser scan与多个邻近的laser scan之间进行的。

通过scan matching得到的位姿估计在短时间内是可靠的,但是长时间会有累积误差。因此Cartographer应用了回环检测对累积误差进行优化。所有创建完成的submap以及当前的laser scan都会用作回环检测的scan matching。如果当前的scan和所有已创建完成的submap在距离上足够近,则进行回环检测。这里为了减少计算量,提高实时回环检测的效率,Cartographer应用了branch and bound(分支定界)优化方法进行优化搜索。如果得到一个足够好的匹配,则会将该匹配的闭环约束加入到所有Submap的姿态优化上。

四、LOCAL 2D SLAM
    Cartographer结合了local 和 global 两种方式进行2d SLAM。

local方式就是前端匹配中通过submap进行scan matching。

global方式就是回环检测,因为是对全局的submap进行匹配

scans中的每个点束的姿态被表示为

A、Scans
    一个scans即激光点云图,包含一个起点和许多的终点。起点称为origin,终点称为scan points,用 H 表示点云集,其表达形式如下。

当获得一个新的scans,并且要插入到submap中时,scans中点集在submap中的位置被表示成 ,其转换公式如下:

B、Submaps
    一个submap是通过几个连续的scans创建而成的,由5cm*5cm大小的概率栅格 构造而成,submap在创建完成时,栅格概率小于表示该点无障碍,在与之间表示未知,大于表示该点有障碍。每一帧的scans都会生成一组称为hits的栅格点和一组称为misses的栅格点 ,如图所示。

其中阴影带叉的表示hits,阴影不带叉的表示misses,每个hits中的栅格点被赋予初值,每个misses中的栅格点被称为,如果该栅格点在先前已经有值,则用下述对该栅格点的值进行更新(此处为,类似)。

其中clamp是区间限定函数。

C、Ceres scan matching
    每次获得的最新的scan需要插入到submap中最优的位置,使我们scan中的点束的位姿经过转换后落到submap中时,每个点的信度和最高。通过scan matching对进行优化,这里的优化问题为解最小二乘问题,其问题描述可表示为:

其中 是线性评价函数,方法为双三次插值法,该函数的输出结果为(0,1)以内的数,在这之外的数可以生成,但不被考虑进去,通过这种平滑函数的优化,能够提供比栅格分辨率更好的精度。该最小二乘问题在cartogrper中通过google自家的Ceres库进行求解。

五、Closing Loops
    Cartographer通过创建大量的submap来实现大场景建图,submap在短时间内的准确度是可靠的,但长时间会存在累积误差,为了消除累积误差,需要通过回环检测来优化所有submap的位姿。

A、Optimization problem
    回环的优化问题同样为非线性最小二乘问题,其问题描述可表示为:

其中

Ξm  是submap的位姿

Ξs 是scan的位姿

这些位姿是在世界坐标系下的。submap位姿和scan位姿之间存在约束条件

表示scan在submap坐标系下的位姿,描述scan在哪一个submap坐标匹配,是相应的协方差矩阵

残差E的计算公式如下:

个人理解:

首先回环优化,我们需要检测到回环,再进行优化。如何检测回环呢,前文也提到过,如果当前的scan和所有已创建完成的submap中的某个laser scan的位姿在距离上足够近,那么通过某种 scan match策略就会找到该闭环。这里为了减少计算量,提高实时回环检测的效率,Cartographer应用了branch and bound(分支定界)优化方法进行优化搜索,如果得到一个足够好的匹配,到此处,回环检测部分已经结束了,已经检测到了回环得存在。接下来要根据当前scan的位姿和匹配到得最接近的submap中的某一个位姿来对所有的submap中的位姿进行优化,即使残差E最小。回环检测与回环优化过程中scan和submap的关系如图所示:

即优化local中的submap与gloab中的submap之间的位姿的误差,又因为所有的submap位姿存在着约束,因此,即是对所有submap的位姿进行优化,使error最小。

B、Branch-and-bound scan matching
    回环检测即是一种匹配过程,即当获得新的scan时,在其附近一定范围搜索最优匹配帧,若该最优匹配帧符合要求,则认为是一个回环。首先,该匹配问题可以描述为如下式子:

其中W是搜索空间,是该点对应的栅格点的M值,该式子可理解为对于scan中的每一个点束插在该submap上时的信度和,信度越高则认为越相似,我们需要在W空间中寻找出该信度和最大的匹配帧。

因此需要在W空间中寻找出pixel-accurate match的最优解。

显然有一种方法是暴力匹配法,即在搜索空间范围内中的每一帧与当前帧进行计算BBS式子的数值,求出最大值。

对于暴力匹配法来说,该方法的搜索步长为1。我们假定搜索空间W

步长r =1  ,因此

                           

其中 ,搜索空间是7m*7m

暴力匹配的 algorithm 如下 ,这样逐个遍历的方法显然是缓慢的

*branch and bound
    为了提高搜索效率,Cartogrpher采用了branch and bound(分支定界) 的方法,本人研一课程高等运筹学也运用了该方法求解整数规划问题,在大作业中,我也运用该方法求解了JSP问题,主要思路来源也是参考Cartogrpher这部分算法的源代码。首先我简单讲解下 branch and bound 对该方法比较熟悉的读者可跳过。

分枝界限法是由三栖学者查理德·卡普(Richard M.Karp)在20世纪60年代发明,成功求解含有65个城市的旅行商问题,创当时的记录。“分枝界限法”把问题的可行解展开如树的分枝,再经由各个分枝中寻找最佳解。

其主要思想:把全部可行的解空间不断分割为越来越小的子集(称为分支),并为每个子集内的解的值计算一个下界或上界(称为定界)。在每次分支后,对凡是界限超出已知可行解值那些子集不再做进一步分支。这样,解的许多子集(即搜索树上的许多结点)就可以不予考虑了,从而缩小了搜索范围。

或许有些读者还是不太理解,下面贴一张图进行讲解。

这张图就已经比较好的描述了分支定界的思想,还有它为什么能够缩小搜索范围的情况下依然能求到最优解。若先前提到的暴力匹配是枚举法,则分支定界是一种隐式枚举法,。

分支定界进行分支的过程,是不断提高搜索精度的过程,或者可以说增加约束的过程,整个分支树的最底层的所有枚举情况,便是最高搜索精度的枚举集合,便是暴力匹配搜索范围的全部整搜索空间。但是分支定界并没有真正的去求解所有枚举情况的目标函数(BBS)值。

再来看这张图假设我们需要去计算检测匹配的点为如图所示16个

则我们第一层搜索精度最低,只列举其中两个,并优先考虑靠左(优先考虑可能性最高的)。
对其继续分层,将其精度提高一倍,又可以列举出两个,并优先考虑靠左。
这样直至最底层,计算出该情况下的目标函数BBS(值),最左的底层有两个值A和B,我们求出最大值,并将其视为best_score
然后我们返回上一层还未来得及展开的C,计算C的目标函数BBS(值)并让它与best_score比较,若best_score依旧最大,则不再考虑C,即不对其进行分层讨论。
 若C的目标函数BBS(值)更大,则对其进行分层,计算D和E的值,我们假设D值大于E,则将D与best_score对比
 若D最大,则将D视为best_score,否则继续返回搜索。
    将此算法应用在我们的回环检测中,现已知我们的搜索范围(搜索最高精度,最底层),设置步长来对该问题进行优化搜索。

a, 首先计算顶层线性搜索空间:

假设  = 1000 则  

其中depth是自己定义的,如果是8, 顶层步长 

那么顶层的线性搜索空间大小就是1000/256,大约为4

角度搜索步长由cell大小(1 pixel),和scan的最大扫描距离决定,大约为300

所以顶层candidate数量是:4×4×300

论文中用下面两个公式规定了步长的范围

b,计算其余层结构

一个candidate可构建四个子Candidate。

角度参数不变

对x_index_offset,y_index_offset加入新的偏移量

C层搜索空间:

c,搜索算法

1,构建顶层C0,计算所有C0 的target 得分,从大到小排序

2,C0  C1 ,计算这四新的C1的target 得分,从大到小排序

3,重复步骤 2 ,直到 depth = Max , 得到最底层的四个Cdepth 并计算target得分,得分最高的作为 best_score

4,返回倒数第二层,将best_score与剩下三个Cdepth-1 比较,若best_score大于任何一个得分,则无须进入其它分支,继续返回best_score

5,重复 4 直到遍历整个分支树 返回的结果为最优结果

论文中的伪代码如下:

下面贴出Cartogrpher branch and bound 的核心源代码和部分注释

Candidate2D FastCorrelativeScanMatcher2D::BranchAndBound(const std::vector<DiscreteScan2D>& discrete_scans,const SearchParameters& search_parameters,const std::vector<Candidate2D>& candidates, const int candidate_depth,float min_score) const {if (candidate_depth == 0) {// Return the best candidate.return *candidates.begin();}Candidate2D best_high_resolution_candidate(0, 0, 0, search_parameters);//讨论分层并计算目标函数值best_high_resolution_candidate.score = min_score;//更新下best scorefor (const Candidate2D& candidate : candidates) { //在分支定界中for循环用来分层if (candidate.score <= min_score) { //若该值不优,则减枝break;}std::vector<Candidate2D> higher_resolution_candidates;const int half_width = 1 << (candidate_depth - 1);for (int x_offset : {0, half_width}) {if (candidate.x_index_offset + x_offset >search_parameters.linear_bounds[candidate.scan_index].max_x) {break;}for (int y_offset : {0, half_width}) {if (candidate.y_index_offset + y_offset >search_parameters.linear_bounds[candidate.scan_index].max_y) {break;}higher_resolution_candidates.emplace_back(candidate.scan_index, candidate.x_index_offset + x_offset,candidate.y_index_offset + y_offset, search_parameters);}}ScoreCandidates(precomputation_grid_stack_->Get(candidate_depth - 1),discrete_scans, search_parameters,&higher_resolution_candidates);best_high_resolution_candidate = std::max(best_high_resolution_candidate,//下面利用递归,继续搜索BranchAndBound(discrete_scans, search_parameters,higher_resolution_candidates, candidate_depth - 1,best_high_resolution_candidate.score));}return best_high_resolution_candidate;
}

后面是一些结果对比,大家自行看论文。
前面写的部分不错,需要补存几点:

1 Cartography怎样去除畸的

2 IMU在前后端是怎样使用

3如果ceres scan time匹配碰见对称环境是怎样解决的

4fast real time scan match 求解约束中线程池怎样做的, 在SPA的时候为了保证实时性每帧雷达数据需要dection loop constraint

5 室外环境的大场景没有办法正常闭环是怎样解决的呢

Cartographe纯雷达计算位姿的前后端总结相关推荐

  1. 【VUE】vue实现登录滑动拼图验证的两种方法,纯前端组件验证以及前后端同时验证

    vue实现登录滑动拼图验证的两种方法: 第一种是纯前端组件验证,只能区分是人为操作还是机器操作. 第二种是前后端同时验证,这种方法加上后端校验相对会更安全一些.(注:在最底部加上了同时兼容移动端的方法 ...

  2. uniapp开发即时通讯聊天app,纯nvue仿微信,前后端开源

    github地址:GitHub - guipie/GpChat: uniapp开发的纯nvue的即时聊天通讯App. gitee:https://gitee.com/chenwei_zq/GpChat ...

  3. html 和jsp 引入jquery_不用jsp怎么实现前后端交互?给萌新后端的ajax教程(1)

    众所周知jsp是已经入土的技术,虽然仍有不少老项目在用,但已经不值得花时间学习了,当然了解一下也是可以的.如果你是一位萌新后端,不想了解jsp,或者想做一个前后端分离的项目,想在纯html网页上实现前 ...

  4. 微信小程序前后端交互案例

    微信小程序前后端交互案例 首先声明一下,本人也是一个初学者(下面的案例可能会有很多不完整或说的不正确的,所以只能起到参考作用,千万不要拿我的话当标准). 我是纯自学,之前在前后端交互方面一直搞不懂,所 ...

  5. Springboot+爬虫+推荐算法+前后端分离实现小说推荐系统

    如何针对互联网各大小说阅读网站的小说数据进行实时采集更新,建立自己的小说资源库,针对海量的小说数据开展标签处理特征分析,利用推荐算法完成针对用户的个性化阅读推荐? 基于以上问题,本次小说推荐系统,建设 ...

  6. 前后端分离的在线考试系统

    分享好玩的项目,挖掘开源的价值 大家好,我是开源君,今天给大家推荐的是**[学之思在线考试系统]** 项目介绍 学之思开源考试系统 - postgresql版,支持多种题型:选择题.多选题.判断题.填 ...

  7. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  8. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性+watch...

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  9. 移动端开发者眼中的前端开发流程变迁与前后端分离

    写在最开始 这是一篇面向移动端开发者的科普性文章,从前端开发的最初流程开始,结合示范代码,讨论开发流程的演变过程,希望能覆盖一部分前端开发技术栈,从而对前端开发的相关概念形成初步的认识. 本文会提供一 ...

最新文章

  1. 干货丨 从遗传算法到强化学习,一文介绍五大生物启发式学习算法
  2. 树莓派3b python3.6.1 SSL模块调用不起来的坑
  3. IOS7新增120*120Icon图标
  4. GDB调试——常用命令
  5. mysql integrityerror_mysql插入数据报错IntegrityError: (1062, Duplicate entry 'xx' for key 'xxxxx')...
  6. linux磁盘管理的命令行,Linux磁盘管理命令介绍
  7. 听听一个院士的故事,你也能找到自己的路。
  8. Struts2增删改查 myeclipse开发文档加项目源码及eclipse开发项目源码
  9. View绘制详解(三),扒一扒View的测量过程
  10. Cinchoo ETL-对大型CSV文件进行排序
  11. 变量的引用类型和非引用类型的区别
  12. 老杨推荐|初级到高级网工学习渠道最全汇总(建议收藏)
  13. 惠普计算机工作站,HP 笔记本计算机和移动工作站电池安全召回和更换计划
  14. excel手机版_这些Excel恢复神器,据说个个都很强,你用过吗?网友:很实用
  15. 面对这样的网络状况我真的醉了
  16. 前端代码规范,vue 代码规范
  17. javaSE试题(一)
  18. php安全新闻早八点-Microdoor-第一季
  19. 在家做科研是一种什么样的体验?
  20. 实验吧-杂项-MD5之守株待兔(时间戳python时间戳函数time.time())

热门文章

  1. requests模块用法举例
  2. Jmeter(三) - 从入门到上天 - 常用原件 (详解教程)
  3. ctfshow命令执行(持续更新,已更至web39)
  4. 树莓派:10行代码体验红外检测
  5. 家庭财务管理系统(C++面向对象课程设计附课设报告)
  6. 红队 入门_我穿越网络安全红队的硕士证书的旅程
  7. arcmin 弧分的转换
  8. 收支系统(超超超简版)1.0
  9. tomcat定时自动重启设置方法
  10. 我的爸爸,在滴滴做自动驾驶