AMCL代码详解(六)amcl中的重采样

news/2024/4/29 16:42:48/文章来源:https://blog.csdn.net/YiYeZhiNian/article/details/127398780

1.重采样判断

上一章讲述了amcl中如何根据激光观测更新粒子权重,当粒子更新完后amcl会需要根据程序判断是否需要进行重采样。这个判断在粒子观测更新权重后进行判断,代码在amcl_node.cpp中:

    if(!(++resample_count_ % resample_interval_)){ pf_update_resample(pf_);resampled = true;}

这里通过两个参数判断是否进行重采样操作,resample_count_是个计数值,每次自加1,resample_interval_是一个常系数参数,可以在.launch文件中设置。这个值默认为1,所以如果不修改的话算法每一次运算都会进行重采样操作。

2.重采样原理

关于amcl中的重采样原理,这里一篇文章讲述的比较通俗易懂:《粒子滤波重采样的理解及MATLAB实现》。粒子滤波中重采样的过程其实就是相当于一个转转盘的过程,如下图所示:
在这里插入图片描述
这个转盘被分成了N分,即从w1到wn,和为1。每个区间就是一个粒子的权值,权值越大,区间的弧度就越大。每次都从w1左边的竖线开始转,显而易见,转到w1的概率为0-w1之间的随机数,转到w2的概率为w1到w1+w2之间的随机数,转到w3的概率为w1+w2到w1+w2+w3之间的随机数,后面的依次类推。当某个粒子的权值较大的时候,产生的随机数落在相应区间的概率就会增大,从而实现了对权值大粒子的多次复制,权值小的粒子的剔除。这样重采样的过程中不是全部复制大权值粒子,也有可能对小权值粒子进行了复制,因为区间虽小,但也有可能转到这个区间。不过这样在一定程度上也保证了粒子的多样性。

3.重采样代码实现

amcl中重采样的代码实际是在pf.c中:

void pf_update_resample(pf_t *pf)
{int i;double total;pf_sample_set_t *set_a, *set_b;pf_sample_t *sample_a, *sample_b;//double r,c,U;//int m;//double count_inv;double* c;double w_diff;set_a = pf->sets + pf->current_set;//current,只有0和1,a和b交替指向sets的第一个和第二个位置,//每个周期由a生成b,但是a所指向的sets的位置不一样,a在本个周期指向的是上个周期中b的位置set_b = pf->sets + (pf->current_set + 1) % 2;//这里是粒子集指针的切换//set_a为上周期采样的粒子,set_b为本周期将要采样的粒子if (pf->selective_resampling != 0){if (set_a->n_effective > 0.5*(set_a->sample_count)){// copy set a to bcopy_set(set_a,set_b);// Re-compute cluster statisticspf_cluster_stats(pf, set_b);// Use the newly created sample setpf->current_set = (pf->current_set + 1) % 2;return;}}// Build up cumulative probability table for resampling.累积概率以进行重采样// TODO: Replace this with a more efficient procedure   这里应该有更高效的方法// (e.g., http://www.network-theory.co.uk/docs/gslref/GeneralDiscreteDistributions.html)// 然后对粒子的权重进行积分,获得分布函数,后面用于生成样本。c = (double*)malloc(sizeof(double)*(set_a->sample_count+1));//malloc函数用于分配内存c[0] = 0.0;for(i=0;i<set_a->sample_count;i++)//权重累积c[i+1] = c[i]+set_a->samples[i].weight;// Create the kd tree for adaptive samplingpf_kdtree_clear(set_b->kdtree);//为自适应采样创建kd树// Draw samples from set a to create set b.total = 0;set_b->sample_count = 0;w_diff = 1.0 - pf->w_fast / pf->w_slow;// 此时和初始的分布差异较大,即w_idff变大,需要重采样;如果是大部分粒子有较大的权重,差异不大,不进行重采样if(w_diff < 0.0)w_diff = 0.0;//printf("w_diff: %9.6f\n", w_diff);// Can't (easily) combine low-variance sampler with KLD adaptive// sampling, so we'll take the more traditional route./*//不能容易地将低方差采样器与KLD自适应组合采样,所以我们采取更传统的路线。// Low-variance resampler, taken from Probabilistic Robotics, p110count_inv = 1.0/set_a->sample_count;r = drand48() * count_inv;c = set_a->samples[0].weight;i = 0;m = 0;*/while(set_b->sample_count < pf->max_samples){//set_b的粒子指针指向set_b的采样数之后的位置,用于添加重采样的粒子sample_b = set_b->samples + set_b->sample_count++;//0-1之间均匀分布的随机数,按照概率增加,w_diff越大,增加粒子的可能性也越大if(drand48() < w_diff)sample_b->pose = (pf->random_pose_fn)(pf->random_pose_data);//增加随机分布粒子,重采样else{// Can't (easily) combine low-variance sampler with KLD adaptive// sampling, so we'll take the more traditional route./*// Low-variance resampler, taken from Probabilistic Robotics, p110U = r + m * count_inv;while(U>c){i++;// Handle wrap-around by resetting counters and picking a new random// numberif(i >= set_a->sample_count){r = drand48() * count_inv;c = set_a->samples[0].weight;i = 0;m = 0;U = r + m * count_inv;continue;}c += set_a->samples[i].weight;}m++;*/// Naive discrete event sampler  离散采样器double r; //生成一个随机数r = drand48();//判断这个随机数处于哪个粒子周围,这里生成出一个随机数,当一个粒子权重越大,则其在0-1之间占用的比例越大,随机数取到这个粒子占用部分的概率越大for(i=0;i<set_a->sample_count;i++){if((c[i] <= r) && (r < c[i+1]))//将随机数以权重为概率分配到某处break;}//assert其作用是如果它的条件返回错误,则终止程序执行assert(i<set_a->sample_count);sample_a = set_a->samples + i;assert(sample_a->weight > 0);// Add sample to listsample_b->pose = sample_a->pose;//在一个即生成随机数位置增加一个粒子,某个位置附近粒子数越多或者权重越大,这个位置生成重采样的粒子概率越大}sample_b->weight = 1.0;//每个粒子都是1,之后标准化total += sample_b->weight;// Add sample to histogrampf_kdtree_insert(set_b->kdtree, sample_b->pose, sample_b->weight);//将样本添加到直方图,关于位姿的二叉树// See if we have enough samples yetif (set_b->sample_count > pf_resample_limit(pf, set_b->kdtree->leaf_count))break;}// Reset averages, to avoid spiraling off into complete randomness.if(w_diff > 0.0)//增加粒子集后重置似然pf->w_slow = pf->w_fast = 0.0;//fprintf(stderr, "\n\n");// Normalize weightsfor (i = 0; i < set_b->sample_count; i++){sample_b = set_b->samples + i;sample_b->weight /= total;//重采样以后每个粒子权重=1 / M}// Re-compute cluster statistics// 聚类,得到均值和方差等信息,将相近的一堆粒子融合成一个粒子pf_cluster_stats(pf, set_b);// Use the newly created sample set// 新粒子集pf->current_set = (pf->current_set + 1) % 2; //计算滤波器是否收敛pf_update_converged(pf);free(c);return;
}

代码中的:

  c = (double*)malloc(sizeof(double)*(set_a->sample_count+1));//malloc函数用于分配内存c[0] = 0.0;for(i=0;i<set_a->sample_count;i++)//权重累积c[i+1] = c[i]+set_a->samples[i].weight;

代表的就是标题2中的圆盘的产生过程,将每一个点的权重值放到一个对应的数组内,根据数组的值就可以知道当前处于哪个粒子。

然后下面的while循环实际上实现了粒子的重采样过程:

while(set_b->sample_count < pf->max_samples){//set_b的粒子指针指向set_b的采样数之后的位置,用于添加重采样的粒子sample_b = set_b->samples + set_b->sample_count++;//0-1之间均匀分布的随机数,按照概率增加,w_diff越大,增加粒子的可能性也越大if(drand48() < w_diff)sample_b->pose = (pf->random_pose_fn)(pf->random_pose_data);//增加随机分布粒子,重采样else{// Naive discrete event sampler  离散采样器double r; //生成一个随机数r = drand48();//判断这个随机数处于哪个粒子周围,这里生成出一个随机数,当一个粒子权重越大,则其在0-1之间占用的比例越大,随机数取到这个粒子占用部分的概率越大for(i=0;i<set_a->sample_count;i++){if((c[i] <= r) && (r < c[i+1]))//将随机数以权重为概率分配到某处break;}//assert其作用是如果它的条件返回错误,则终止程序执行assert(i<set_a->sample_count);sample_a = set_a->samples + i;assert(sample_a->weight > 0);// Add sample to listsample_b->pose = sample_a->pose;//在一个即生成随机数位置增加一个粒子,某个位置附近粒子数越多或者权重越大,这个位置生成重采样的粒子概率越大}sample_b->weight = 1.0;//每个粒子都是1,之后标准化total += sample_b->weight;// Add sample to histogrampf_kdtree_insert(set_b->kdtree, sample_b->pose, sample_b->weight);//将样本添加到直方图,关于位姿的二叉树// See if we have enough samples yetif (set_b->sample_count > pf_resample_limit(pf, set_b->kdtree->leaf_count))break;}

首先while循环中的第一个drand48()用于判断是否重采样粒子,这里用到了两个参数:pf->w_fast 与pf->w_slow。这两个参数代表了粒子的衰减率,当:

w_diff = 1.0 - pf->w_fast / pf->w_slow;

得到的值越大,说明粒子的权重越小,当前粒子的可信度比较小,需要重采样粒子。而w_diff的值越小,说明大部分粒子有较大的权重,差异不大,不进行重采样。

首先算法随机生成一个随机数,然后根据该随机数判断是否进行随机粒子生成。对于需要重新生成粒子的情况:

if(drand48() < w_diff)sample_b->pose = (pf->random_pose_fn)(pf->random_pose_data);//增加随机分布粒子,重采样

这里的位姿生成使用的是随机位姿生成的方式得到一个之前不存在的位姿,通过这种方式提高粒子的多样性。同时我们也可以看到,w_diff越小,重新生成随机粒子的概率也越小。

而对于不重新生成粒子的情况,这里用到了第二个drand48(),这个drand48()的作用就是前面提到的轮盘,它随机转到某一个权重范围下,然后根据这个权重范围获取对应的位姿。这样子权重大的粒子被复制的概率会高于权重低的粒子。当然这里虽然复制的位姿可能会是一样的,但是没有关系,因为里程计更新时携带了噪声系数,所以一次更新后这些一样的位姿就产生了变化。

最后当粒子的数量满足了一定要求后,整个重采样的过程就结束了。可以看出,在整个重采样的过程中,粒子进行了两次种情况的刷新,一种是随机生成的新的粒子,一种是对原来的粒子的复制。当粒子的权重越低,生成新的粒子的可能性就越大,粒子的权重越高,被复制的可能性也就越大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_410076.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[GYCTF2020]Easyphp

尝试了一下万能密码不行&#xff0c;又到处翻了一下&#xff0c;扫目录结果又有www.zip 审计代码好久&#xff0c;序列化和sql结合的题还是第一次见&#xff0c;太菜了呀&#xff0c;花了很久时间才理解这个题 首先看到update.php&#xff0c;这个文件是最亮眼的&#xff0c;…

javascript 原生类 DOMParser 把 字符串格式的HTML文档源码 转换成 document DOM对象

文章目录IntroQADOMParser 在 console 的使用cheerio 在 node 项目中的使用Reference测试sumIntro 有一天我在写爬虫。 其实也说不上是爬虫&#xff0c;就是打开浏览器上网&#xff0c;觉得页面有些数据挺有意思&#xff0c;就打开开发者工具&#xff0c;在 Network/Console 中…

01.初识C语言1

一、前期准备 1.gitee网址&#xff08;代码托管网站&#xff09;&#xff1a;工作台 - Gitee.com Git教程 - 廖雪峰的官方网站 (liaoxuefeng.com) 用法&#xff1a; 1&#xff09;新建仓库 2&#xff09;随意勾选 3&#xff09;网络仓库构建完成 2.所学知识&#xff1a;计算…

【期末大作业】基于HTML+CSS+JavaScript网上订餐系统(23个页面)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Jetson Orin 平台单进程采集四路独立video调试记录

1. 概述 现在有4个摄像头, 如何捕获4个摄像头(/dev/video0 - video3)在一个进程像这样: 现在只能捕捉一个相机使用gst-launch如下: gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720 ! videoconvert ! video/x-raw,format=I420 ! xvimagesi…

《设计模式:可复用面向对象软件的基础》——行为模式(2)(笔记)

文章目录五、行为模式5.5 MEDIATOR(中介者)1.意图补充部分2.动机3.适用性4.结构5.参与者6.协作7.效果8.实现9.代码示例10.相关模式5.6 MEMENTO ( 备忘录)1.意图2.别名3.动机4.适用性5.结构6.参与者7.协作8.效果9.实现10.代码示例11.相关模式5.7 OBSERVER (观察者)1.意图2.别名3…

21.C++11

C11的官网&#xff1a;C11 - cppreference.com 1.C11简介 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于TC1主要是对C98标准中的漏洞进行修复&#xff0c;语言的核心部分则没有改动&am…

Java语言实现猜数字小游戏

之前笔者在学习C语言的初级阶段&#xff0c;就已经实现了用C语言简单实现猜数字小游戏&#xff0c;既然笔者最近在学习Java的初级阶段&#xff0c;那么&#xff0c;也应该写一个Java语言实现的猜数字小游戏&#xff01;&#xff01; C语言实现猜数字小游戏&#xff1a;原文链接…

浏览器播放rtsp视频流:4、jsmpeg+go实现局域网下的rtsp视频流web端播放

文章目录1.前言2.资料准备3.兼容性及适用性说明4.jsmpeg架构5.基于以上架构的go方案可行性分析6.编译和结果展示&#xff08;编译坑点&#xff09;7.最后1.前言 之前的rtsp转webrtc的方案存在如下缺陷&#xff1a;1.只支持h264&#xff1b;2.受限于webrtc的理解难度以及搭建tu…

Hproxy项目前端

hproxy项目前端使用vue-element-admin框架&#xff0c;页面为hook列表&#xff0c;和一个添加hook页面。 添加路由 编辑src/router/index.js文件&#xff0c;在constantRoutes列表追加如下路由内容 {path: /hproxy,component: Layout,redirect: /hproxy/index,hidden: false,c…

各省市软考准考证打印时间,一起来看!

距离软考还有一周&#xff0c;各个省市的准考证也开始打印了&#xff01; 各地防疫政策一定要遵守&#xff0c;不然错过&#xff0c;又等一年&#xff01; 周末也有一些省市因疫情推迟、取消考试的。 一起来看&#xff01; 考完之后&#xff0c;会在这里讨论一些答案&#x…

UWB室内定位系统铸造智能化企业安全管理系统

进入工业4.0时代以来&#xff0c;数字技术不断成熟、扩散和融合&#xff0c;加速推动工业企业数字化、智能化转型。企业推进数字化转型要整体规划、分布实施&#xff0c;需要考虑企业经营管理活动的全过程、全范围、全层级。各大行业已经开始配备UWB人员定位系统&#xff0c;提…

电脑C盘怎么清理到最干净

如果你的电脑C盘运行内存已经快满了&#xff0c;这个时候你怎么处理&#xff1f;让我们来看看如何清理C盘。 c如何清理盘&#xff1a; 方法一&#xff1a;存储状态 点击电脑win键&#xff0c;在设备左侧弹出提示框&#xff0c;进入系统配置&#xff0c;然后点击系统软件选项…

MyBatis Plus实现动态字段排序

利用周末时间&#xff0c;对已有的项目进行了升级&#xff0c;原来使用的是tkmybatis&#xff0c;改为mybatis plus。但是由于修改了返回数据的格式&#xff0c;前端页面字段排序失效了&#xff0c;需要刷新表格才会排序。页面效果如下 easyui的数据表格datagrid支持多字段排序…

商用车进入回暖周期,哪些供应商在领跑「主动安全」前装赛道

由于受到经济周期性影响&#xff0c;去年开始商用车市场出现一波下行行情。 中国汽车工业协会发布数据显示&#xff0c;2022年1-9月&#xff0c;商用车产销分别完成242.6万辆和248.4万辆&#xff0c;同比下降32.6%和34.2%&#xff0c;降幅较1-8月收窄1.5个百分点和2个百分点&a…

ZAB协议

1、定义 ZAB 协议全称&#xff1a;Zookeeper Atomic Broadcast&#xff08;Zookeeper 原子广播协议&#xff09;。 ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议&#xff0c;基于该协议&#xff0c;Zookeeper 实现了一种 主备模式 的…

什么是行内元素的盒模型

目录 行内元素的盒模型 display 可选值&#xff1a; visibility 可选值&#xff1a; 行内元素的盒模型 行内元素不支持设置宽度和高度 但是这并不是说明行内元素没有内容区 而是通过width和height不能改变内容区的大小 行内元素的内容区是由他里面的内容决定的&#xff0…

【视觉基础篇】14 # 如何使用片元着色器进行几何造型?

说明 【跟月影学可视化】学习笔记。 如何用片元着色器控制局部颜色&#xff1f; 把图片绘制为纯黑色&#xff1a; const fragment #ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {gl_FragColor vec4(0, 0, 0, 1);} ;根据纹理坐标值来绘制&#…

工地ai智能视频监控系统

工地ai智能视频监控系统在监控摄像头监控的画面范围之内&#xff0c;对人的不安全行为&#xff08;违规行为&#xff09;或者物的不安全状态进行实时分析识别&#xff0c;当工地ai智能视频监控系统发现现场违规行为时&#xff0c;可根据需要设置各种警戒要求&#xff0c;工地ai…

【计算机网络--物理层】编码和调制与数据交换方式

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录基带信号与宽带信号基带信号宽带信号小结编码与调制编码调制的方法数字数据编码为数字信号数字数字调制为模拟信号模拟数据编码为数字信号模拟信号调制为模拟信号数据交换电路交换报文交换分组交换数据报方式…