概述
阅读AMCL源码,首先撇开算法具体细节以及技术细节,对ACML核心程序流程进行整理,看懂AMCL由外部数据触发到完成定位的整个过程。这里读的是navigation仓库melodic-devel分支,提交id为b52e0ea9362131dc81326da471792ab8698c9564的源码。
程序入口
先找到程序入口,也就是main函数,可以直接搜索main就可以很快定位到该函数了,主函数很短,如下
1 | int |
可以看到,主函数中简单的初始化一下节点,初始化AmclNode类,然后根据命令参数的个数argc分别有两种执行方式,一种是直接接受传感器数据运行,一种是利用bag文件回放数据运行。我们跳到runFromBag函数中,可以看到利用bag文件数据文件运行的方式大概就是回放bag文件中的话题数据,不断读取并发布。所以,核心的流程还是一致的。
初始化
在主函数中可以看到,那里直接实例化AmclNode类后就进入ros::spin();。因此,从AmclNode构造函数开始看,可以看到,在构造函数中,AmclNode对很对成员变量进行初始化以及从参数服务器读取各个配置参数,然后注册几个话题的发布和订阅以及一些服务,大致就完成了。所以初始化完成之后,主要入口就是几个话题和服务了。
这里为了把握住主线,我们还是得找出核心的东西来,首先服务和发布的话题先不管,因为服务相对还是比较“被动”地调用,而发布的话题,则是对外的,也先不管。因此,就主要关注一下订阅的几个话题了,包括scan,initialpose和map。其实还有tf,不过tf主要就是读一下一些变化或者发布一下,主要在代码执行过程中需要的时候查询一下获取信息就完事了。
回调函数
经过上面的整理,我们的重点就落在了几个订阅话题的回调函数中了,也不多,也就仨。一看就可以看出来哪个是重头戏了,initialpose和map话题回调函数中其实还是设置算法参数,分别设置初始化姿态和栅格地图。到这里,核心的部分也就出来了,就是订阅雷达话题scan的回调函数laserReceived,这里将这段代码贴出来,在注释中说明到底干了啥!
1 | void |
上面就是Amcl执行的核心流程,可以说思路是很明确的,在各种情况判断后,依次进行odom_->UpdateAction(pf_, (AMCLSensorData*)&odata);,lasers_[laser_index]->UpdateSensor(pf_, (AMCLSensorData*)&ldata);和pf_update_resample(pf_);,这三步就是粒子滤波三个核心步骤的接口,分别实现预测、更新和重要性采样算法。