《概率机器人》里程计运动模型gmapping中代码解析

2024-08-25 06:32

本文主要是介绍《概率机器人》里程计运动模型gmapping中代码解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

里程计运动模型(odometery motion model)用距离测量代替控制。实际经验表明虽然里程计虽然仍存在误差,但通常比速度运动模型更加的精确。相比于速度运动模型运动信息 ut

(x¯t1x¯t)

为了提取相对的距离, ut 被转变为三个步骤的序列:旋转,平移,另一个旋转,
测距模型
上图就是里程计的测距模型,同样这些旋转和平移都是有噪声的。
首先由里程计算 p(xt|ut,xt1) 的算法,算法的输入是机器人的初始位姿 xt1 ,从机器人里程计获得的一对位姿 ut=(x¯t1,x¯t) ,以及一个假定的最终姿态 xt ,输出的数值概率是 p(xt|ut,xt1)

这里写图片描述

算法的2-4行是从里程计的读数获取相对运动参数 (δrot1 δtrans δrot2)T
第5-7行是相同的,就是计算位姿为 xt1 xt 的相对运动参数,
第8-10行是计算误差概率,
第11行返回各自的误差概率P1 ,P2 ,P3相乘得到的组合误差概率,假定不同误差源之间是相互独立的,变量 α1 α4 是指定机器人运动噪声的机器人的特定参数。
基于里程计运动模型的采样算法

这里写图片描述

数学推导:根据上上面的图应该不难推导出算法中的 (δrot1 δtrans δrot2)T ,为了建立运动误差模型,假设旋转和平移的“真”值是测量值减去均值为0 方差为 b2 的独立噪声 ϵb2 得到也就是上述算法中的5-7行,为了计算旋转和平移的真值引入了误差参数 α1 α4 ,所以实际位置 xt ,从 xt1 经过初始旋转 δ^rot1 跟随平移距离 δ^trans 和另一个旋转 δ^rot2 得到

这里写图片描述
这里的时刻t的位姿用 xt1=(x y θ)T
那么根据给定的运动模型采样算法,,对于不同的误差参数也会有不同的概率分布:
这里写图片描述
第一个模型的采样参数是中等的,可以说是正常的,第二个和第三个扥别是比较大的平移和旋转的误差所造成的。

Gmapping中实现里程计运动模型的采样程序如下:

这个函数的输入是机器人的当前位姿pnew和上一时刻的机器人的位姿pold,

OrientedPoint 
MotionModel::drawFromMotion(const OrientedPoint& p, const OrientedPoint& pnew, const OrientedPoint& pold) const{double sxy=0.3*srr;  //srr我理解为两轮子里程计的方差OrientedPoint delta=absoluteDifference(pnew, pold); //具体如下面的介绍OrientedPoint noisypoint(delta);//存储噪声估计noisypoint.x+=sampleGaussian(srr*fabs(delta.x)+str*fabs(delta.theta)+sxy*fabs(delta.y));noisypoint.y+=sampleGaussian(srr*fabs(delta.y)+str*fabs(delta.theta)+sxy*fabs(delta.x));noisypoint.theta+=sampleGaussian(stt*fabs(delta.theta)+srt*sqrt(delta.x*delta.x+delta.y*delta.y));noisypoint.theta=fmod(noisypoint.theta, 2*M_PI);if (noisypoint.theta>M_PI)noisypoint.theta-=2*M_PI;return absoluteSum(p,noisypoint);
}

首先解释一下函数:

OrientedPoint delta=absoluteDifference(pnew,pold);double 

具体的 内容如下

orientedpoint<T,A> absoluteDifference(const orientedpoint<T,A>& p1,const orientedpoint<T,A>& p2){orientedpoint<T,A> delta=p1-p2;delta.theta=atan2(sin(delta.theta), cos(delta.theta));double s=sin(p2.theta), c=cos(p2.theta);return orientedpoint<T,A>(c*delta.x+s*delta.y, -s*delta.x+c*delta.y, delta.theta);
}

就是计算位姿的变化量,这个OrientedPoint delta的计算 结果对应的理论公式的结果就是

(xx)cosθ+(yy)sinθ(xx)sinθ+(yy)cosθΔθ

计算新旧帧的绝对误差.具体就不再深入。
那么对于其中的三行代码是分别给位姿的三个两添加噪声进去,为什么要这样写呢?

noisypoint.x+=sampleGaussian(srr*fabs(delta.x)+str*fabs(delta.theta)+sxy*fabs(delta.y));noisypoint.y+=sampleGaussian(srr*fabs(delta.y)+str*fabs(delta.theta)+sxy*fabs(delta.x));noisypoint.theta+=sampleGaussian(stt*fabs(delta.theta)+srt*sqrt(delta.x*delta.x+delta.y*delta.y));

首先我们对sampleGaussian( b2 )函数已经是有了解了,这个意思就是以均值为0 方差为 b2 的近似的正态分布的采样算法。所以这些括号里的都是计算方差的,为什么参数不同呢?仔细看看就能找到规律了,但是明白之前的一篇博客里是有对srr srt str stt这些高斯模型参数的设置的,分别代表delta的三个变量之间的方差而已。
接下来的程序

noisypoint.theta=fmod(noisypoint.theta, 2*M_PI);if (noisypoint.theta>M_PI)noisypoint.theta-=2*M_PI;

百度一下fmod()函数是对浮点型数据进行取模运算,就是计算
noisypoint.theta/2*M_PI的余数。 因为要把角度差限定在 [π π] 之间。
最后是返回累计的噪声:
absoluteSum(p,noisypoint);
这个函数的实现代码是

template <class T, class A>
orientedpoint<T,A> absoluteSum(const orientedpoint<T,A>& p1,const orientedpoint<T,A>& p2){double s=sin(p1.theta), c=cos(p1.theta);return orientedpoint<T,A>(c*p2.x-s*p2.y,s*p2.x+c*p2.y, p2.theta) + p1;

P1是当前机器人的位姿,前面的c*p2.x-s*p2.y, s*p2.x+c*p2.y, p2.theta是分别在P1的位姿上加上各自的噪声分量。

*这是我个人的理解,可能有一些偏差,或者错误,有错误还请指正,当然不喜勿喷

这篇关于《概率机器人》里程计运动模型gmapping中代码解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104806

相关文章

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析