精华内容
下载资源
问答
  • 在集中式滤波结构和联邦式滤波结构的基础上,设计了一种基于自适应容积卡尔曼滤波算法的多传感器系统混合式组合滤波结构,并给出了融合各传感器的局部滤波信息以得到全局滤波估计的计算方法。以对车辆的定位导航为...
  • 在集中式滤波结构和联邦式滤波结构的基础上,设计了一种基于自适应容积卡尔曼滤波算法的多传感器系统混合式组合滤波结构,并给出了融合各传感器的局部滤波信息以得到全局滤波估计的计算方法。以对车辆的定位导航为...
  • 卡尔曼滤波算法及C语言代码卡尔曼滤波简介及其算法实现代码卡尔曼滤波算法实现代码(C,C++分别实现)卡尔曼滤波器简介近来发现有些问题很多人都很感兴趣。所以在这里希望能尽自己能力跟大家讨论一些力所能及的算法...

    卡尔曼滤波算法及C语言代码

    卡尔曼滤波简介及其算法实现代码

    卡尔曼滤波算法实现代码(C,C++分别实现)

    卡尔曼滤波器简介

    近来发现有些问题很多人都很感兴趣。所以在这里希望能尽自己能力跟大家讨论一些力所能及的算法。现在先讨论一下卡尔曼滤波器,如果时间和能力允许,我还希望能够写写其他的算法,例如遗传算法,傅立叶变换,数字滤波,神经网络,图像处理等等。

    因为这里不能写复杂的数学公式,所以也只能形象的描述。希望如果哪位是这方面的专家,欢迎讨论更正。

    卡尔曼滤波器 – Kalman Filter

    1. 什么是卡尔曼滤波器 (What is the Kalman Filter?)

    在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”。跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人!

    卡尔曼全名Rudolf Emil Kalman,匈牙利数学家,1930年出生于匈牙利首都布达佩斯。1953,1954年于麻省理工学院分别获得电机工程学士及硕士学位。1957年于哥伦比亚大学获得博士学位。我们现在要学习的卡尔曼滤波器,正是源于他的博士论文和1960年发表的论文《A New Approach to Linear Filtering and Prediction Problems》(线性滤波与预测问题的新方法)。如果对这编论文有兴趣,可以到这里的地址下载:

    http://www.cs.unc.edu/~welch/media/pdf/Kalman1960.pdf。

    简单来说,卡尔曼滤波器是一个“optimal recursive data processing algorithm(最优化自回归数据处理算法)”。对于解决很大部分的问题,他是最优,效率最高甚至是最有用的。他的广泛应用已经超过30年,包括机器人导航,控制,传感器数据融合甚至在军事方面的雷达系统以及导弹追踪等等。近年来更被应用于计算机图像处理,例如头脸识别,图像分割,图像边缘检测等等。

    2.卡尔曼滤波器的介绍

    (Introduction to the Kalman Filter)

    为了可以更加容易的理解卡尔曼滤波器,这里会应用形象的描述方法来讲解,而不是像大多数参考书那样罗列一大堆的数学公式和数学符号。但是,他的5条公式是其核心内容。结合现代的计算机,其实卡尔曼的程序相当的简单,只要你理解了他的那5条公式。

    在介绍他的5条公式之前,先让我们来根据下面的例子一步一步的探索。

    假设我们要研究的对象是一个房间的温度。根据你的经验判断,这个房间的温度是恒定的,也就

    展开全文
  • 卡尔曼滤波数据融合算法

    万次阅读 多人点赞 2017-11-10 14:06:43
  • 针对移动机器人在室内环境中定位难的问题,提出了一种基于RSSI(Receive Signal Strength Indicator)的卡尔曼滤波定位算法。利用基于RSSI的定位方法估算用户的位置坐标,利用卡尔曼滤波算法对用户的估算位置坐标...
  • 基于卡尔曼滤波数据融合算法的智能钓鱼竿系统.pdf
  • 针对目前国内市场智能钓鱼竿功能不足的问题,本文通过四元数法对鱼竿姿态解算,利用基于卡尔曼滤波的数据融合算法,并以微处理器STM32为核心搭建uC/OS-II操作系统,结合多种环境传感器和串级PID控制方法,设计了一种...
  • 详解卡尔曼滤波原理

    万次阅读 多人点赞 2017-03-18 13:54:15
    详解卡尔曼滤波原理 在网上看了不少与卡尔曼滤波相关的博客、论文,要么是只谈理论、缺乏感性,或者有感性认识,缺乏理论推导。能兼顾二者的少之又少,直到我看到了国外的一篇博文,真的惊艳到我了,不得不佩服作者...

    详解卡尔曼滤波原理

      在网上看了不少与卡尔曼滤波相关的博客、论文,要么是只谈理论、缺乏感性,或者有感性认识,缺乏理论推导。能兼顾二者的少之又少,直到我看到了国外的一篇博文,真的惊艳到我了,不得不佩服作者这种细致入微的精神,翻译过来跟大家分享一下,原文链接:http://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/
      我不得不说说卡尔曼滤波,因为它能做到的事情简直让人惊叹!意外的是很少有软件工程师和科学家对对它有所了解,这让我感到沮丧,因为卡尔曼滤波是一个如此强大的工具,能够在不确定性中融合信息,与此同时,它提取精确信息的能力看起来不可思议。

    什么是卡尔曼滤波?

      你可以在任何含有不确定信息的动态系统中使用卡尔曼滤波,对系统下一步的走向做出有根据的预测,即使伴随着各种干扰,卡尔曼滤波总是能指出真实发生的情况。
      在连续变化的系统中使用卡尔曼滤波是非常理想的,它具有占用内存小的优点(除了前一个状态量外,不需要保留其它历史数据),并且速度很快,很适合应用于实时问题和嵌入式系统。
      在Google上找到的大多数关于实现卡尔曼滤波的数学公式看起来有点晦涩难懂,这个状况有点糟糕。实际上,如果以正确的方式看待它,卡尔曼滤波是非常简单和容易理解的,下面我将用漂亮的图片和色彩清晰的阐述它,你只需要懂一些基本的概率和矩阵的知识就可以了。

    我们能用卡尔曼滤波做什么?

      用玩具举例:你开发了一个可以在树林里到处跑的小机器人,这个机器人需要知道它所在的确切位置才能导航。

    这里写图片描述

      我们可以说机器人有一个状态 这里写图片描述,表示位置和速度:

    这里写图片描述

      注意这个状态只是关于这个系统基本属性的一堆数字,它可以是任何其它的东西。在这个例子中是位置和速度,它也可以是一个容器中液体的总量,汽车发动机的温度,用户手指在触摸板上的位置坐标,或者任何你需要跟踪的信号。
      这个机器人带有GPS,精度大约为10米,还算不错,但是,它需要将自己的位置精确到10米以内。树林里有很多沟壑和悬崖,如果机器人走错了一步,就有可能掉下悬崖,所以只有GPS是不够的。

    这里写图片描述

      或许我们知道一些机器人如何运动的信息:例如,机器人知道发送给电机的指令,知道自己是否在朝一个方向移动并且没有人干预,在下一个状态,机器人很可能朝着相同的方向移动。当然,机器人对自己的运动是一无所知的:它可能受到风吹的影响,轮子方向偏了一点,或者遇到不平的地面而翻倒。所以,轮子转过的长度并不能精确表示机器人实际行走的距离,预测也不是很完美。
      GPS 传感器告诉了我们一些状态信息,我们的预测告诉了我们机器人会怎样运动,但都只是间接的,并且伴随着一些不确定和不准确性。但是,如果使用所有对我们可用的信息,我们能得到一个比任何依据自身估计更好的结果吗?回答当然是YES,这就是卡尔曼滤波的用处。

    卡尔曼滤波是如何看到你的问题的

      下面我们继续以只有位置和速度这两个状态的简单例子做解释。

    这里写图片描述

      我们并不知道实际的位置和速度,它们之间有很多种可能正确的组合,但其中一些的可能性要大于其它部分:

      卡尔曼滤波假设两个变量(位置和速度,在这个例子中)都是随机的,并且服从高斯分布。每个变量都有一个均值 μ,表示随机分布的中心(最可能的状态),以及方差 这里写图片描述,表示不确定性。

      在上图中,位置和速度是不相关的,这意味着由其中一个变量的状态无法推测出另一个变量可能的值。下面的例子更有趣:位置和速度是相关的,观测特定位置的可能性取决于当前的速度:

      这种情况是有可能发生的,例如,我们基于旧的位置来估计新位置。如果速度过高,我们可能已经移动很远了。如果缓慢移动,则距离不会很远。跟踪这种关系是非常重要的,因为它带给我们更多的信息:其中一个测量值告诉了我们其它变量可能的值,这就是卡尔曼滤波的目的,尽可能地在包含不确定性的测量数据中提取更多信息!
      这种相关性用协方差矩阵来表示,简而言之,矩阵中的每个元素 这里写图片描述 表示第 i 个和第 j 个状态变量之间的相关度。(你可能已经猜到协方差矩阵是一个对称矩阵,这意味着可以任意交换 i 和 j)。协方差矩阵通常用“这里写图片描述”来表示,其中的元素则表示为“这里写图片描述 ”。

    使用矩阵来描述问题

      我们基于高斯分布来建立状态变量,所以在时刻 k 需要两个信息:最佳估计 这里写图片描述(即均值,其它地方常用 μ 表示),以及协方差矩阵 这里写图片描述

    这里写图片描述        (1)

      (当然,在这里我们只用到了位置和速度,实际上这个状态可以包含多个变量,代表任何你想表示的信息)。接下来,我们需要根据当前状态k-1 时刻)来预测下一状态k 时刻)。记住,我们并不知道对下一状态的所有预测中哪个是“真实”的,但我们的预测函数并不在乎。它对所有的可能性进行预测,并给出新的高斯分布。

      我们可以用矩阵 这里写图片描述 来表示这个预测过程:

      它将我们原始估计中的每个点都移动到了一个新的预测位置,如果原始估计是正确的话,这个新的预测位置就是系统下一步会移动到的位置。那我们又如何用矩阵来预测下一个时刻的位置和速度呢?下面用一个基本的运动学公式来表示:

    这里写图片描述

      现在,我们有了一个预测矩阵来表示下一时刻的状态,但是,我们仍然不知道怎么更新协方差矩阵。此时,我们需要引入另一个公式,如果我们将分布中的每个点都乘以矩阵 A,那么它的协方差矩阵 这里写图片描述 会怎样变化呢?很简单,下面给出公式:

    这里写图片描述

      结合方程(4)和(3)得到:

    这里写图片描述

    外部控制量

      我们并没有捕捉到一切信息,可能存在外部因素会对系统进行控制,带来一些与系统自身状态没有相关性的改变。
      以火车的运动状态模型为例,火车司机可能会操纵油门,让火车加速。相同地,在我们机器人这个例子中,导航软件可能会发出一个指令让轮子转向或者停止。如果知道这些额外的信息,我们可以用一个向量这里写图片描述来表示,将它加到我们的预测方程中做修正。
      假设由于油门的设置或控制命令,我们知道了期望的加速度a,根据基本的运动学方程可以得到:

    这里写图片描述

      以矩阵的形式表示就是:

    这里写图片描述

      这里写图片描述称为控制矩阵,这里写图片描述称为控制向量(对于没有外部控制的简单系统来说,这部分可以忽略)。让我们再思考一下,如果我们的预测并不是100%准确的,该怎么办呢?

    外部干扰

      如果这些状态量是基于系统自身的属性或者已知的外部控制作用来变化的,则不会出现什么问题。
      但是,如果存在未知的干扰呢?例如,假设我们跟踪一个四旋翼飞行器,它可能会受到风的干扰,如果我们跟踪一个轮式机器人,轮子可能会打滑,或者路面上的小坡会让它减速。这样的话我们就不能继续对这些状态进行跟踪,如果没有把这些外部干扰考虑在内,我们的预测就会出现偏差。
      在每次预测之后,我们可以添加一些新的不确定性来建立这种与“外界”(即我们没有跟踪的干扰)之间的不确定性模型:

      原始估计中的每个状态变量更新到新的状态后,仍然服从高斯分布。我们可以说这里写图片描述的每个状态变量移动到了一个新的服从高斯分布的区域,协方差为这里写图片描述。换句话说就是,我们将这些没有被跟踪的干扰当作协方差为这里写图片描述噪声来处理。

      这产生了具有不同协方差(但是具有相同的均值)的新的高斯分布。

      我们通过简单地添加这里写图片描述得到扩展的协方差,下面给出预测步骤的完整表达式:

    这里写图片描述

      由上式可知,新的最优估计是根据上一最优估计预测得到的,并加上已知外部控制量修正
      而新的不确定性上一不确定预测得到,并加上外部环境的干扰
      好了,我们对系统可能的动向有了一个模糊的估计,用这里写图片描述这里写图片描述来表示。如果再结合传感器的数据会怎样呢?

    用测量值来修正估计值

      我们可能会有多个传感器来测量系统当前的状态,哪个传感器具体测量的是哪个状态变量并不重要,也许一个是测量位置,一个是测量速度,每个传感器间接地告诉了我们一些状态信息。

      注意,传感器读取的数据的单位和尺度有可能与我们要跟踪的状态的单位和尺度不一样,我们用矩阵 这里写图片描述 来表示传感器的数据。

      我们可以计算出传感器读数的分布,用之前的表示方法如下式所示:

    这里写图片描述

      卡尔曼滤波的一大优点就是能处理传感器噪声,换句话说,我们的传感器或多或少都有点不可靠,并且原始估计中的每个状态可以和一定范围内的传感器读数对应起来。

      从测量到的传感器数据中,我们大致能猜到系统当前处于什么状态。但是由于存在不确定性,某些状态可能比我们得到的读数更接近真实状态。

      我们将这种不确定性(例如:传感器噪声)用协方差这里写图片描述表示,该分布的均值就是我们读取到的传感器数据,称之为这里写图片描述
    现在我们有了两个高斯分布,一个是在预测值附近,一个是在传感器读数附近。

      我们必须在预测值粉红色)和传感器测量值绿色)之间找到最优解。
      那么,我们最有可能的状态是什么呢?对于任何可能的读数这里写图片描述,有两种情况:(1)传感器的测量值;(2)由前一状态得到的预测值。如果我们想知道这两种情况都可能发生的概率,将这两个高斯分布相乘就可以了。

      剩下的就是重叠部分了,这个重叠部分的均值就是两个估计最可能的值,也就是给定的所有信息中的最优估计
      瞧!这个重叠的区域看起来像另一个高斯分布。

      如你所见,把两个具有不同均值和方差的高斯分布相乘,你会得到一个新的具有独立均值和方差的高斯分布!下面用公式讲解。

    融合高斯分布

      先以一维高斯分布来分析比较简单点,具有方差 这里写图片描述 和 μ 的高斯曲线可以用下式表示:

    这里写图片描述

      如果把两个服从高斯分布的函数相乘会得到什么呢?

    这里写图片描述

      将式(9)代入到式(10)中(注意重新归一化,使总概率为1)可以得到:

    这里写图片描述

      将式(11)中的两个式子相同的部分用 k 表示:

    这里写图片描述

      下面进一步将式(12)和(13)写成矩阵的形式,如果 Σ 表示高斯分布的协方差,这里写图片描述 表示每个维度的均值,则:

    这里写图片描述

      矩阵这里写图片描述称为卡尔曼增益,下面将会用到。放松!我们快要完成了!

    将所有公式整合起来

      我们有两个高斯分布,预测部分这里写图片描述,和测量部分这里写图片描述,将它们放到式(15)中算出它们之间的重叠部分:

    这里写图片描述

      由式(14)可得卡尔曼增益为:

    这里写图片描述

      将式(16)和式(17)的两边同时左乘矩阵的逆(注意这里写图片描述里面包含了 这里写图片描述 )将其约掉,再将式(16)的第二个等式两边同时右乘矩阵 这里写图片描述 的逆得到以下等式:

    这里写图片描述

      上式给出了完整的更新步骤方程。这里写图片描述就是新的最优估计,我们可以将它和这里写图片描述放到下一个预测更新方程中不断迭代。

    总结

      以上所有公式中,你只需要用到式(7)、(18)、(19)。(如果忘了的话,你可以根据式(4)和(15)重新推导一下)
      我们可以用这些公式对任何线性系统建立精确的模型,对于非线性系统来说,我们使用扩展卡尔曼滤波,区别在于EKF多了一个把预测和测量部分进行线性化的过程。

    (ps: 第一次用Markdown,添加图片和公式心累啊,什么时候能直接拖拽就好了~~)

    附Markdown使用技巧:
    1. 改变文本字体、字号与颜色。参考链接:(http://blog.csdn.net/testcs_dn/article/details/45719357/)
    2. 在线公式编辑器,编辑好了右键“复制图片地址”,当作图片来添加。
     链接:(http://private.codecogs.com/latex/eqneditor.php)
    3. 段落首行缩进,按Shift+Space将输入法切换到全角状态,然后敲空格即可,一个空格代表一个汉字的间隔。
    4. 设置图片大小及居中显示。参考链接:(http://blog.csdn.net/soindy/article/details/50427079)
    5. 不懂百度。

    展开全文
  • EKF对非线性函数的Taylor展开式进行一阶线性化截断,忽略其余高阶项,从而将非线性问题转化为线性,可以将卡尔曼线性滤波算法应用于非线性系统中多种二阶广义卡尔曼滤波方法的提出及应用进一步提高了卡尔曼滤波对非...

           卡尔曼滤波是由Swerling1958)和Kalman1960)为解决线性高斯系统的预测和滤波发明的。卡尔曼滤波要求观测是线性函数,且下一个状态是前一个状态的线性函数,这两个假设是应用Kalman滤波的基本原则。但实际上状态转移和测量很少是线性的,如本课题讨论的滑移转向机器人,当其具有恒定的线速度和角速度时,移动机器人的轨迹是个圆,无法用线性状态转移来描述。而扩展卡尔曼滤波(EKF)解决了这一问题,这里假设状态转移方程和观测方程分别由非线性函数组成。EKF利用一阶泰勒展开的方法进行线性化处理,然后通过卡尔曼滤波进行位置预测。

    卡尔曼滤波器就不断的把协方差(covariance)递归,从而估算出最优的温度值。他运行的很快,而且它只保留了上一时刻的协方差(covariance)。上面的Kg,就是卡尔曼增益(Kalman Gain)。他可以随不同的时刻而改变他自己的值。

    1)线性系统状态方程:状态空间描述(内部描述):基于系统内部结构,是对系统的一种完整的描述。

    2)状态方程:描述系统状态变量间或状态变量与系统输入变量间关系的一个一阶微分方程组(连续系统)或一阶差分方程组(离散系统),称为状态方程。

    3)观测数据:观测数据代表传感器采集的实际数据,可能存在着或多或少的误差,例如陀螺仪的积分误差等。

    4)最优估计:最优估计指的是使经过KF算法解算的数据无限接近于真实值的估计,用数学表述即为后验概率估计无限接近于真实值。 

    卡尔曼滤波算法核心思想在于预测+测量反馈,它由两部分组成,第一部分是线性系统状态预测方程,第二部分是线性系统观测方程。 

    EKF的基本思想是将非线性系统线性化,然后进行卡尔曼滤波,因此EKF是一种伪非线性的卡尔曼滤波。实际中一阶EKF应用广泛。EKF对非线性函数的Taylor展开式进行一阶线性化截断,忽略其余高阶项,从而将非线性问题转化为线性,可以将卡尔曼线性滤波算法应用于非线性系统中多种二阶广义卡尔曼滤波方法的提出及应用进一步提高了卡尔曼滤波对非线性系统的估计性能。

    图给出了机器人在一维走廊的环境内,扩展卡尔曼滤波定位算法的定位示例。为使扩展卡尔曼滤波保持置信度的单峰形状,需要两个假设前提:第一,假设每个门都有特定的标签,从而保证机器人能对每个门进行准确识别。第二,假设初始位姿相对容易知道。为满足这两个假设,设定机器人初始位置在第一个门的位置,移动机器人不确定性如图(a)所示。当机器人向右移动,它的置信度与运动模型卷积。结果产生的置信度是宽度增加的高斯分布,如图(b)。当机器人运动到第二个门时,观测概率与机器人置信度产生后验概率,如图(c)所示,相对于经过第一个门的置信度有所提高。继续向右运动,由于扩展卡尔曼滤波继续将运动不确定性合并到机器人置信度,机器人的不确定性再次增加,如图(d)所示。

                                                                 扩展卡尔曼滤波定位原理示意图[29]

    粒子滤波定位广泛应用于视觉跟踪、通信与信号处理、机器人、图像处理,以及目标定位、导航、跟踪领域。粒子滤波定位利用带权值的点集来估计随机变量的后验概率分布,运动连续重要性采样及重采样算法对粒子群进行更新,最终使粒子群的分布符合估计对象状态。图为粒子滤波定位一维走廊示例。初始时,粒子均匀的分布在走廊中,移动机器人可能在整个空间的任意位置,如图(a)所示。当机器人感知到门时,粒子滤波定位为每个粒子分配重要性系数。产生的粒子集合如(b)所示。粒子滤波定位进行重采样并综合了机器人运动后的粒子集合,建立了新的具有均匀性权重的粒子集合,但在3个可能的位置增加了粒子数,如图(c)。机器人继续前进,运动到第二个门,新的测量分配了非均的重要性权重给粒子,如图(d)。进一步运动引起重采样和产生新粒子集合,如图(e)。重复上述过程,进行移动机器人位置的估计。

     

    粒子滤波定位原理示意图[29]

    当机器人在光滑地面运动时的里程计模型误差误差大,扩展卡尔曼滤波在特征识别后与运动模型卷积,可能会很大程度,减少定位的置信度。扩展卡尔曼滤波需要对运动方程和观测方程进行线性化处理,会增加定位误差。又由于扩展卡尔曼滤波定位算法假定地图上存在一些特征,并且这些特征需唯一且可辨识,在实际应用中,有许多相似的地形,也会导致扩展卡尔曼滤波定位失败。对非线性滤波方法进行比较,人们进行了大量的仿真与实验,针对于非线性误差大的系统,应用粒子滤波算法优于其它滤波算法。

    里程计模型参数如下。

    结合上边两个公式,含有控制量的状态预测: 公式中, 为转换矩阵,误差值为

    假设激光雷达对某一特征点进行观测,假设特征点的位置为 ,机器人在k时刻的位置为 ,激光雷达发射和反射波测量目标与激光雷达之间的距离为观测量 ,则观测方程为

    式中, 是激光雷达自身的测量误差 。

    (1)初始状态:用大量粒子模拟X(t),粒子在空间内均匀分布,如下图:

     

    初始粒子分布

    (2)重要性采样:权重计算是粒子滤波算法的重要部分,意义在于,根据权重大小实现“优质”粒子的大量复制,对“劣质”粒子实现淘汰。权值计算主要过程:首先将表示目标k时刻的状态的每个粒子带入公式中,得到预测值 。 是一个集合,将每个值代入到观测方程,计算观测值的预测 。在k时刻,测量系统的观测值 ,通过观测值衡量每个粒子的权重,分布曲线如下图。粒子滤波在计算权重时,可用计算。当 取值不同时,预测值 与传感器观测值越接近,越接近峰值,其权重越大。

    (3)重采样是通过样本重新采样,大量繁殖权重高的粒子,淘汰权值低的粒子,从而抑制退化,图所示。重采样之前,粒子样本集合与权重为 ,重采样之后变为 ,图中圆表示粒子,面积表示权重。重采样之前各个粒子 对应的权重为 ,经重采样后粒子总数保持不变,权值大的粒子分成了多个粒子,权值小的被剔除,采样后权值相同,均为 。重采样主要方法有:随机重采样、多项式重采样、系统重采样、残差重采样。

     

    (4)状态估计:如下图,蓝色点为估计位置,红色点为实际位置,开始时粒子均匀分布在空间中,估计值为中心点,随着观测值的获取,粒子逐渐靠近真实值。

    1.搭建结构

    安装ubuntu 16.04 ,安装好ros系统

    mkdir ~/dashgo_ws/src

    cd ~/dashgo_ws

    mkdir

    cd ./src 

    git clone https://github.com/EAIBOT/dashgo.git
    cd ~/dashgo_ws/src/dashgo
    cd ~/dashgo_ws
    catkin_make

    装KINCET

    https://blog.csdn.net/weixin_39585934/article/details/81320461

    需要同时出现3个 Microsoft Crop 才可以,如果只出现一个,说明你的USB接口是USB2.0,这个需要USB3.0。

    https://blog.csdn.net/qq_41925420/article/details/90710084

    构建地图

    <launch>    
        <!-- start kinect2-->            
        <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch">
            <arg name="base_name"         value="kinect2"/>
            <arg name="sensor"            value=""/>
            <arg name="publish_tf"        value="true"/>
            <arg name="base_name_tf"      value="kinect2"/>
            <arg name="fps_limit"         value="-1.0"/>
            <arg name="calib_path"        value="$(find kinect2_bridge)/data/"/>
            <arg name="use_png"           value="false"/>
            <arg name="jpeg_quality"      value="90"/>
            <arg name="png_level"         value="1"/>
            <arg name="depth_method"      value="default"/>
            <arg name="depth_device"      value="-1"/>
            <arg name="reg_method"        value="default"/>
            <arg name="reg_device"        value="-1"/>
            <arg name="max_depth"         value="12.0"/>
            <arg name="min_depth"         value="0.1"/>
            <arg name="queue_size"        value="5"/>
            <arg name="bilateral_filter"  value="true"/>
            <arg name="edge_aware_filter" value="true"/>
            <arg name="worker_threads"    value="4"/>
        </include>  
    
      <!-- Run the depthimage_to_laserscan node -->
      <node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen">
        <!--输入图像-->
        <remap from="image" to="/kinect2/qhd/image_depth_rect"/>
        <!--相关图像的相机信息。通常不需要重新变形,因为camera_info将从与图像相同的命名空间订阅。-->
        <remap from="camera_info" to="/kinect2/qhd/camera_info" />
        <!--输出激光数据的话题-->
        <remap from="scan" to="/scan" /> 
    
        <!--激光扫描的帧id。对于来自具有Z向前的“光学”帧的点云,该值应该被设置为具有X向前和Z向上的相应帧。-->
        <param name="output_frame_id" value="/kinect2_depth_frame"/>
        <!--用于生成激光扫描的像素行数。对于每一列,扫描将返回在图像中垂直居中的那些像素的最小值。-->
        <param name="scan_height" value="30"/>
        <!--返回的最小范围(以米为单位)。小于该范围的输出将作为-Inf输出。-->
        <param name="range_min" value="0.25"/>
        <!--返回的最大范围(以米为单位)。大于此范围将输出为+ Inf。-->
        <param name="range_max" value="20.00"/>
      </node>
    
        <!--start gmapping node -->
        <node pkg="gmapping" type="slam_gmapping" name="simple_gmapping" output="screen">
            <param name="map_update_interval" value="5.0"/>  
            <param name="maxUrange" value="5.0"/> 
            <param name="maxRange" value="6.0"/> 
            <param name="sigma" value="0.05"/>  
            <param name="kernelSize" value="1"/>  
            <param name="lstep" value="0.05"/>  
            <param name="astep" value="0.05"/>  
            <param name="iterations" value="5"/>  
            <param name="lsigma" value="0.075"/>  
            <param name="ogain" value="3.0"/>  
            <param name="lskip" value="0"/>  
            <param name="minimumScore" value="50"/>  
            <param name="srr" value="0.1"/>  
            <param name="srt" value="0.2"/>  
            <param name="str" value="0.1"/>  
            <param name="stt" value="0.2"/>  
            <param name="linearUpdate" value="1.0"/>  
            <param name="angularUpdate" value="0.5"/>  
            <param name="temporalUpdate" value="3.0"/>  
            <param name="resampleThreshold" value="0.5"/>  
            <param name="particles" value="50"/>  
            <param name="xmin" value="-5.0"/>  
            <param name="ymin" value="-5.0"/>  
            <param name="xmax" value="5.0"/>  
            <param name="ymax" value="5.0"/>  
            <param name="delta" value="0.05"/>  
            <param name="llsamplerange" value="0.01"/>  
            <param name="llsamplestep" value="0.01"/>  
            <param name="lasamplerange" value="0.005"/>  
            <param name="lasamplestep" value="0.005"/>  
        </node>
    
        <!--start serial-port and odometry node-->
        <node name="base_controller" pkg="base_controller" type="base_controller"/>
    
        <!-- static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms -->  
      <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_base_link" args="0 0 0.5 0 0 0 base_footprint base_link 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0 0 0.5 0 0 0 base_link laser 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2laser" args="0 0 0.5 0 0 0 base_link kinect2_depth_frame 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2_link" args="0 0 0.5 -1.57 0 -1.57 base_link kinect2_link 50" />
    
    </launch>

    rviz显示

    Panels:
      - Class: rviz/Displays
        Help Height: 78
        Name: Displays
        Property Tree Widget:
          Expanded:
            - /Global Options1
            - /Status1
            - /Map1
          Splitter Ratio: 0.5
        Tree Height: 566
      - Class: rviz/Selection
        Name: Selection
      - Class: rviz/Tool Properties
        Expanded:
          - /2D Pose Estimate1
          - /2D Nav Goal1
          - /Publish Point1
        Name: Tool Properties
        Splitter Ratio: 0.588679
      - Class: rviz/Views
        Expanded:
          - /Current View1
        Name: Views
        Splitter Ratio: 0.5
      - Class: rviz/Time
        Experimental: false
        Name: Time
        SyncMode: 0
        SyncSource: LaserScan
    Visualization Manager:
      Class: ""
      Displays:
        - Alpha: 0.5
          Cell Size: 1
          Class: rviz/Grid
          Color: 160; 160; 164
          Enabled: true
          Line Style:
            Line Width: 0.03
            Value: Lines
          Name: Grid
          Normal Cell Count: 0
          Offset:
            X: 0
            Y: 0
            Z: 0
          Plane: XY
          Plane Cell Count: 10
          Reference Frame: <Fixed Frame>
          Value: true
        - Class: rviz/TF
          Enabled: true
          Frame Timeout: 15
          Frames:
            All Enabled: true
            base_footprint:
              Value: true
            base_link:
              Value: true
            kinect2_depth_frame:
              Value: true
            kinect2_ir_optical_frame:
              Value: true
            kinect2_link:
              Value: true
            kinect2_rgb_optical_frame:
              Value: true
            laser:
              Value: true
            map:
              Value: true
            odom:
              Value: true
          Marker Scale: 1
          Name: TF
          Show Arrows: true
          Show Axes: true
          Show Names: true
          Tree:
            map:
              odom:
                base_footprint:
                  base_link:
                    kinect2_depth_frame:
                      {}
                    kinect2_link:
                      kinect2_rgb_optical_frame:
                        kinect2_ir_optical_frame:
                          {}
                    laser:
                      {}
          Update Interval: 0
          Value: true
        - Alpha: 1
          Autocompute Intensity Bounds: true
          Autocompute Value Bounds:
            Max Value: 1
            Min Value: 1
            Value: true
          Axis: Z
          Channel Name: intensity
          Class: rviz/LaserScan
          Color: 255; 255; 255
          Color Transformer: AxisColor
          Decay Time: 0
          Enabled: true
          Invert Rainbow: false
          Max Color: 255; 255; 255
          Max Intensity: 4096
          Min Color: 0; 0; 0
          Min Intensity: 0
          Name: LaserScan
          Position Transformer: XYZ
          Queue Size: 10
          Selectable: true
          Size (Pixels): 3
          Size (m): 0.01
          Style: Flat Squares
          Topic: /scan
          Unreliable: false
          Use Fixed Frame: true
          Use rainbow: true
          Value: true
        - Alpha: 0.7
          Class: rviz/Map
          Color Scheme: map
          Draw Behind: false
          Enabled: true
          Name: Map
          Topic: /map
          Unreliable: false
          Value: true
      Enabled: true
      Global Options:
        Background Color: 48; 48; 48
        Fixed Frame: odom
        Frame Rate: 30
      Name: root
      Tools:
        - Class: rviz/Interact
          Hide Inactive Objects: true
        - Class: rviz/MoveCamera
        - Class: rviz/Select
        - Class: rviz/FocusCamera
        - Class: rviz/Measure
        - Class: rviz/SetInitialPose
          Topic: /initialpose
        - Class: rviz/SetGoal
          Topic: /move_base_simple/goal
        - Class: rviz/PublishPoint
          Single click: true
          Topic: /clicked_point
      Value: true
      Views:
        Current:
          Class: rviz/Orbit
          Distance: 70.1093
          Enable Stereo Rendering:
            Stereo Eye Separation: 0.06
            Stereo Focal Distance: 1
            Swap Stereo Eyes: false
            Value: false
          Focal Point:
            X: 3.9777
            Y: -3.7323
            Z: -7.60875
          Name: Current View
          Near Clip Distance: 0.01
          Pitch: 0.355398
          Target Frame: <Fixed Frame>
          Value: Orbit (rviz)
          Yaw: 0.0404091
        Saved: ~
    Window Geometry:
      Displays:
        collapsed: false
      Height: 846
      Hide Left Dock: false
      Hide Right Dock: true
      QMainWindow State: 000000ff00000000fd00000004000000000000016a000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000d600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ac00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000002f600fffffffb0000000800540069006d0065010000000000000450000000000000000000000340000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
      Selection:
        collapsed: false
      Time:
        collapsed: false
      Tool Properties:
        collapsed: false
      Views:
        collapsed: true
      Width: 1200
      X: 50
      Y: 45

    参考:https://blog.csdn.net/qq_16481211/article/details/84763291

    程序分为dashgo节点,载入小车模型,启动Kinect,载入地图,AMCL,TF转换move.bash导航文件加载全局global_costmap等

    <launch>
    
     <node name="arduino" pkg="dashgo_bringup" type="dashgo_driver.py" output="screen">
          <rosparam file="$(find dashgo_bringup)/config/my_dashgo_params.yaml" command="load" />
      </node>
    <!-- 启动小车模型 -->
    <include file="$(find dashgo_description)/launch/dashgo_description.launch"/>
    
    <!-- 启动kinect2 -->            
        <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch">
            <arg name="base_name"         value="kinect2"/>
            <arg name="sensor"            value=""/>
            <arg name="publish_tf"        value="true"/>
            <arg name="base_name_tf"      value="kinect2"/>
            <arg name="fps_limit"         value="-1.0"/>
            <arg name="calib_path"        value="$(find kinect2_bridge)/data/"/>
            <arg name="use_png"           value="false"/>
            <arg name="jpeg_quality"      value="90"/>
            <arg name="png_level"         value="1"/>
            <arg name="depth_method"      value="default"/>
            <arg name="depth_device"      value="-1"/>
            <arg name="reg_method"        value="default"/>
            <arg name="reg_device"        value="-1"/>
            <arg name="max_depth"         value="12.0"/>
            <arg name="min_depth"         value="0.1"/>
            <arg name="queue_size"        value="5"/>
            <arg name="bilateral_filter"  value="true"/>
            <arg name="edge_aware_filter" value="true"/>
            <arg name="worker_threads"    value="4"/>
        </include>  
    
      <!-- Run the depthimage_to_laserscan node -->
      <node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen">
        <!--输入图像-->
        <remap from="image" to="/kinect2/qhd/image_depth_rect"/>
        <!--相关图像的相机信息。通常不需要重新变形,因为camera_info将从与图像相同的命名空间订阅。-->
        <remap from="camera_info" to="/kinect2/qhd/camera_info" />
        <!--输出激光数据的话题-->
        <remap from="scan" to="/scan" /> 
    
        <!--激光扫描的帧id。对于来自具有Z向前的“光学”帧的点云,该值应该被设置为具有X向前和Z向上的相应帧。-->
        <param name="output_frame_id" value="/kinect2_depth_frame"/>
        <!--用于生成激光扫描的像素行数。对于每一列,扫描将返回在图像中垂直居中的那些像素的最小值。-->
        <param name="scan_height" value="30"/>
        <!--返回的最小范围(以米为单位)。小于该范围的输出将作为-Inf输出。-->
        <param name="range_min" value="0.25"/>
        <!--返回的最大范围(以米为单位)。大于此范围将输出为+ Inf。-->
        <param name="range_max" value="20.00"/>
      </node>
    <!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割××××××××××××××××××××× -->
    
      <!-- 启动地图服务器载入地图 -->
        <node name="map_server" pkg="map_server" type="map_server" args="$(find dashgo_nav)/maps/my_pi_map.yaml"/>
    
    
    <!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ××××××××××××××××××××××××× -->  
    
      <!-- 启动 AMCL 节点 -->
      <node pkg="amcl" type="amcl" name="amcl" clear_params="true">
        <param name="use_map_topic" value="false"/>
        <!-- Publish scans from best pose at a max of 10 Hz -->
        <param name="odom_model_type" value="diff"/>
        <param name="odom_alpha5" value="0.1"/>
        <param name="gui_publish_rate" value="10.0"/>
        <param name="laser_max_beams" value="60"/>
        <param name="laser_max_range" value="12.0"/>
        <param name="min_particles" value="500"/>
        <param name="max_particles" value="2000"/>
        <param name="kld_err" value="0.05"/>
        <param name="kld_z" value="0.99"/>
        <param name="odom_alpha1" value="0.2"/>
        <param name="odom_alpha2" value="0.2"/>
        <!-- translation std dev, m -->
        <param name="odom_alpha3" value="0.2"/>
        <param name="odom_alpha4" value="0.2"/>
        <param name="laser_z_hit" value="0.5"/>
        <param name="laser_z_short" value="0.05"/>
        <param name="laser_z_max" value="0.05"/>
        <param name="laser_z_rand" value="0.5"/>
        <param name="laser_sigma_hit" value="0.2"/>
        <param name="laser_lambda_short" value="0.1"/>
        <param name="laser_model_type" value="likelihood_field"/>
        <!-- <param name="laser_model_type" value="beam"/> -->
        <param name="laser_likelihood_max_dist" value="2.0"/>
        <param name="update_min_d" value="0.25"/>
        <param name="update_min_a" value="0.2"/>
    
        <param name="odom_frame_id" value="odom"/>
    
        <param name="resample_interval" value="1"/>
        <!-- Increase tolerance because the computer can get quite busy -->
        <param name="transform_tolerance" value="1.0"/>
        <param name="recovery_alpha_slow" value="0.0"/>
        <param name="recovery_alpha_fast" value="0.0"/>
        <!-- scan topic -->
        <remap from="scan" to="scan"/>
      </node>
    
    <!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××× -->
        <!-- tf 转换 -->
        
      <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_base_link" args="0 0 0.5 0 0 0 base_footprint base_link 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0 0 0.5 0 0 0 base_link laser 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2laser" args="0 0 0.5 0 0 0 base_link kinect2_depth_frame 50" />
      <node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2_link" args="0 0 0.5 -1.57 0 -1.57 base_link kinect2_link 50" />
    <!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××× -->
    
      <!-- 启动 move_base 节点 -->
    <include file="$(find dashgo_nav)/launch/move_base.launch"/>
    
     
    </launch>

    多点导航

    #!/usr/bin/env python
    import rospy
    import actionlib
    from actionlib_msgs.msg import *
    from geometry_msgs.msg import Pose, PoseWithCovarianceStamped, Point, Quaternion, Twist
    from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
    from random import sample
    from math import pow, sqrt
     
    class NavTest():
        def __init__(self):
            rospy.init_node('nav_test', anonymous=True)
            rospy.on_shutdown(self.shutdown)
     
            # How long in seconds should the robot pause at each location?
            self.rest_time = rospy.get_param("~rest_time", 10)
     
            # Are we running in the fake simulator?
            self.fake_test = rospy.get_param("~fake_test", False)
     
            # Goal state return values
            goal_states = ['PENDING', 'ACTIVE', 'PREEMPTED','SUCCEEDED',
                           'ABORTED', 'REJECTED','PREEMPTING', 'RECALLING', 
                           'RECALLED','LOST']
     
            # Set up the goal locations. Poses are defined in the map frame.
            # An easy way to find the pose coordinates is to point-and-click
            # Nav Goals in RViz when running in the simulator.
            # Pose coordinates are then displayed in the terminal
            # that was used to launch RViz.
            locations = dict()
          
            locations['hall_foyer'] = Pose(Point(-2.758, -6.863, 0.000),
                                      Quaternion(0.000, 0.000, 0.161, 0.987))
            locations['hall_kitchen'] = Pose(Point(0.435, -5.498, 0.000),
                                        Quaternion(0.000, 0.000, 0.214, 0.977))
            locations['hall_bedroom'] = Pose(Point(1.365, -6.568, 0.000),
                                        Quaternion(0.000, 0.000, 0.984, -0.177))
     
            locations['hall_foyer'] = Pose(Point(-1.524, -7.555, 0.000),
                                      Quaternion(0.000, 0.000, 0.973, -0.230))
            #locations['hall_kitchen'] = Pose(Point(0.856, 2.858, 0.000),
             #                           Quaternion(0.000, 0.000, 0.192, 0.981))
            #locations['hall_bedroom'] = Pose(Point(1.781, 1.856, 0.000),
             #                           Quaternion(0.000, 0.000, 0.000, 1.000))
            #locations['living_room_1'] = Pose(Point(0.720, 2.229, 0.000),
                                         #Quaternion(0.000, 0.000, 0.786, 0.618))
            #locations['living_room_2'] = Pose(Point(1.471, 1.007, 0.000),
                                         #Quaternion(0.000, 0.000, 0.480, 0.877))
            #locations['dining_room_1'] = Pose(Point(-0.861, -0.019, 0.000),
                                         #Quaternion(0.000, 0.000, 0.892, -0.451))
     
            # Publisher to manually control the robot (e.g. to stop it)
            self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
     
            # Subscribe to the move_base action server
            self.move_base = actionlib.SimpleActionClient("move_base", MoveBaseAction)
            rospy.loginfo("Waiting for move_base action server...")
     
            # Wait 60 seconds for the action server to become available
            self.move_base.wait_for_server(rospy.Duration(60))
            rospy.loginfo("Connected to move base server")
            
            # A variable to hold the initial pose of the robot to be set by the user in RViz
            initial_pose = PoseWithCovarianceStamped()
            # Variables to keep track of success rate, running time, and distance traveled
            n_locations = len(locations)
            n_goals = 0
            n_successes = 0
            i = n_locations
            distance_traveled = 0
            start_time = rospy.Time.now()
            running_time = 0
            location = ""
            last_location = ""
            # Get the initial pose from the user
            rospy.loginfo("Click on the map in RViz to set the intial pose...")
            rospy.wait_for_message('initialpose', PoseWithCovarianceStamped)
            self.last_location = Pose()
            rospy.Subscriber('initialpose', PoseWithCovarianceStamped, self.update_initial_pose)
            # Make sure we have the initial pose
            while initial_pose.header.stamp == "":
                rospy.sleep(1)
            rospy.loginfo("Starting navigation test")
     
            # Begin the main loop and run through a sequence of locations
            while not rospy.is_shutdown():
     
            # If we've gone through the current sequence, start with a new random sequence
                if i == n_locations:
                    i = 0
                    sequence = sample(locations, n_locations)
                	# Skip over first location if it is the same as the last location
                    if sequence[0] == last_location:
                        i = 1
     
                # Get the next location in the current sequence
                location = sequence[i]
     
                # Keep track of the distance traveled.
                # Use updated initial pose if available.
                if initial_pose.header.stamp == "":
                    distance = sqrt(pow(locations[location].position.x
                               - locations[last_location].position.x, 2) +
                               pow(locations[location].position.y -
                               locations[last_location].position.y, 2))
                else:
                    rospy.loginfo("Updating current pose.")
                    distance = sqrt(pow(locations[location].position.x
                               - initial_pose.pose.pose.position.x, 2) +
                               pow(locations[location].position.y -
                               initial_pose.pose.pose.position.y, 2))
                    initial_pose.header.stamp = ""
     
                # Store the last location for distance calculations
                last_location = location
     
                # Increment the counters
                i += 1
                n_goals += 1
     
                # Set up the next goal location
                self.goal = MoveBaseGoal()
                self.goal.target_pose.pose = locations[location]
                self.goal.target_pose.header.frame_id = 'map'
                self.goal.target_pose.header.stamp = rospy.Time.now()
     
                # Let the user know where the robot is going next
                rospy.loginfo("Going to: " + str(location))
                # Start the robot toward the next location
                self.move_base.send_goal(self.goal)
     
                # Allow 5 minutes to get there
                finished_within_time = self.move_base.wait_for_result(rospy.Duration(300))
     
                # Check for success or failure
                if not finished_within_time:
                    self.move_base.cancel_goal()
                    rospy.loginfo("Timed out achieving goal")
                else:
                    state = self.move_base.get_state()
                    if state == GoalStatus.SUCCEEDED:
                        rospy.loginfo("Goal succeeded!")
                        n_successes += 1
                        distance_traveled += distance
                    else:
                        rospy.loginfo("Goal failed with error code: " + str(goal_states[state]))
     
                # How long have we been running?
                running_time = rospy.Time.now() - start_time
                running_time = running_time.secs / 60.0
     
                # Print a summary success/failure, distance traveled and time elapsed
                rospy.loginfo("Success so far: " + str(n_successes) + "/" +
                              str(n_goals) + " = " + str(100 * n_successes/n_goals) + "%")
                rospy.loginfo("Running time: " + str(trunc(running_time, 1)) +
                              " min Distance: " + str(trunc(distance_traveled, 1)) + " m")
                rospy.sleep(self.rest_time)
     
        def update_initial_pose(self, initial_pose):
            self.initial_pose = initial_pose
     
        def shutdown(self):
            rospy.loginfo("Stopping the robot...")
            self.move_base.cancel_goal()
            rospy.sleep(2)
            self.cmd_vel_pub.publish(Twist())
            rospy.sleep(1)
    def trunc(f, n):
     
        # Truncates/pads a float f to n decimal places without rounding
        slen = len('%.*f' % (n, f))
        return float(str(f)[:slen])
     
    if __name__ == '__main__':
        try:
            NavTest()
            rospy.spin()
        except rospy.ROSInterruptException:
            rospy.loginfo("AMCL navigation test finished.")

     

    amcl参数调节,对应不同情况,可调节一些参数,进行算法改进

     <!--- Run AMCL -->
      <node pkg="amcl" type="amcl" name="amcl" output="screen">
       <!-- Publish scans from best pose at a max of 10 Hz -->  //全部滤波器参数 
       <param name="min_particles" value="500"/>  //允许的粒子数量的最小值,默认100 
       <param name="max_particles" value="5000"/> //允许的例子数量的最大值,默认5000 
       <param name="kld_err" value="0.05"/>  //真实分布和估计分布之间的最大误差,默认0.01 
       <param name="kld_z" value="0.99"/>  //上标准分位数(1-p),其中p是估计分布上误差小于kld_err的概率,默认0.99 
       <param name="update_min_d" value="0.2"/>  //在执行滤波更新前平移运动的距离,默认0.2m 
       <param name="update_min_a" value="0.5"/>  //执行滤波更新前旋转的角度,默认pi/6 rad 
       <param name="resample_interval" value="1"/>  //在重采样前需要的滤波更新的次数,默认2 
       <param name="transform_tolerance" value="0.1"/>  //tf变换发布推迟的时间,为了说明tf变换在未来时间内是可用的 
       <param name="recovery_alpha_slow" value="0.0"/> //慢速的平均权重滤波的指数衰减频率,用作决定什么时候通过增加随机位姿来recover,默认0(disable),可能0.001是一个不错的值 
      <param name="recovery_alpha_fast" value="0.0"/>  //快速的平均权重滤波的指数衰减频率,用作决定什么时候通过增加随机位姿来recover,默认0(disable),可能0.1是个不错的值 
      <param name="gui_publish_rate" value="10.0"/>  //扫描和路径发布到可视化软件的最大频率,设置参数为-1.0意为失能此功能,默认-1.0 
      <param name="save_pose_rate" value="0.5"/>  //存储上一次估计的位姿和协方差到参数服务器的最大速率。被保存的位姿将会用在连续的运动上来初始化滤波器。-1.0失能。 
      <param name="use_map_topic" value="false"/>  //当设置为true时,AMCL将会订阅map话题,而不是调用服务返回地图。也就是说,当设置为true时,有另外一个节点实时的发布map话题,也就是机器人在实时的进行地图构建,并供给amcl话题使用;当设置为false时,通过map server,也就是调用已经构建完成的地图。在navigation 1.4.2中新加入的参数。 
      <param name="first_map_only" value="false"/>  //当设置为true时,AMCL将仅仅使用订阅的第一个地图,而不是每次接收到新的时更新为一个新的地图,在navigation 1.4.2中新加入的参数。  //激光模型参数 
      <param name="laser_min_range" value="-1.0"/>  //被考虑的最小扫描范围;参数设置为-1.0时,将会使用激光上报的最小扫描范围 
      <param name="laser_max_range" value="-1.0"/>  //被考虑的最大扫描范围;参数设置为-1.0时,将会使用激光上报的最大扫描范围 
      <param name="laser_max_beams" value="30"/>  //更新滤波器时,每次扫描中多少个等间距的光束被使用 
      <param name="laser_z_hit" value="0.5"/> //模型的z_hit部分的最大权值,默认0.95 
      <param name="laser_z_short" value="0.05"/> //模型的z_short部分的最大权值,默认0.1 
      <param name="laser_z_max" value="0.05"/> //模型的z_max部分的最大权值,默认0.05 
      <param name="laser_z_rand" value="0.5"/> //模型的z_rand部分的最大权值,默认0.05 
      <param name="laser_sigma_hit" value="0.2"/> //被用在模型的z_hit部分的高斯模型的标准差,默认0.2m 
      <param name="laser_lambda_short" value="0.1"/> //模型z_short部分的指数衰减参数,默认0.1 
      <param name="laser_likehood_max_dist" value="2.0"/> //地图上做障碍物膨胀的最大距离,用作likehood_field模型 
      <param name="laser_model_type" value="likelihood_field"/> //模型使用,可以是beam, likehood_field, likehood_field_prob(和likehood_field一样但是融合了beamskip特征),默认是“likehood_field”     //里程计模型参数 
      <param name="odom_model_type" value="omni"/> //模型使用,可以是"diff", "omni", "diff-corrected", "omni-corrected",后面两个是对老版本里程计模型的矫正,相应的里程计参数需要做一定的减小 
      <param name="odom_alpha1" value="0.2"/> //指定由机器人运动部分的旋转分量估计的里程计旋转的期望噪声,默认0.2 
      <param name="odom_alpha2" value="0.2"/> //制定由机器人运动部分的平移分量估计的里程计旋转的期望噪声,默认0.2 
      <!-- translation std dev, m --> 
      <param name="odom_alpha3" value="0.8"/> //指定由机器人运动部分的平移分量估计的里程计平移的期望噪声,默认0.2 
      <param name="odom_alpha4" value="0.2"/> //指定由机器人运动部分的旋转分量估计的里程计平移的期望噪声,默认0.2 
      <param name="odom_alpha5" value="0.1"/> //平移相关的噪声参数(仅用于模型是“omni”的情况) 
      <param name="odom_frame_id" value="odom"/>  //里程计默认使用的坐标系 
      <param name="base_frame_id" value="base_link"/>  //用作机器人的基坐标系 
      <param name="global_frame_id" value="map"/>  //由定位系统发布的坐标系名称 
      <param name="tf_broadcast" value="true"/>  //设置为false阻止amcl发布全局坐标系和里程计坐标系之间的tf变换  //机器人初始化数据设置 
      <param name="initial_pose_x" value="0.0"/> //初始位姿均值(x),用于初始化高斯分布滤波器。 
      <param name="initial_pose_y" value="0.0"/> //初始位姿均值(y),用于初始化高斯分布滤波器。 
      <param name="initial_pose_a" value="0.0"/> //初始位姿均值(yaw),用于初始化高斯分布滤波器。 
      <param name="initial_cov_xx" value="0.5*0.5"/> //初始位姿协方差(x*x),用于初始化高斯分布滤波器。 
      <param name="initial_cov_yy" value="0.5*0.5"/> //初始位姿协方差(y*y),用于初始化高斯分布滤波器。 
      <param name="initial_cov_aa" value="(π/12)*(π/12)"/> //初始位姿协方差(yaw*yaw),用于初始化高斯分布滤波器。
      </node>
    
      <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
    
        <rosparam file="$(find my_robot_name_2dnav)/costmap_common_params.yaml" command="load" ns="global_costmap" />
    
        <rosparam file="$(find my_robot_name_2dnav)/costmap_common_params.yaml" command="load" ns="local_costmap" />
    
        <rosparam file="$(find my_robot_name_2dnav)/local_costmap_params.yaml" command="load" />
    
        <rosparam file="$(find my_robot_name_2dnav)/global_costmap_params.yaml" command="load" />
    
        <rosparam file="$(find my_robot_name_2dnav)/base_local_planner_params.yaml" command="load" />
    
      </node>

    扩展卡尔曼滤波融合

    传感器名称:ATK:UB482

    用USB转TTL进行接线

    接好线后

    git clone https://github.com/ros-drivers/nmea_navsat_driver

    修改串口号:/dev/ttyUSB0

    roslaunch nmea_navsat_driver nmea_serial_driver.launch

    修改

    想接收数据需发送指令GPGGA  1,在nmea_serial_driver.py添加如上图指令。

    转换为ASCII为 senbuffer=[0x67,0x70,0x67,0x67,0x61,0x20,0x31,0x0D,0x0A]

    发送数据GPS.write(senbuffer);

    rostopic list

    gps设备发布的主题,代码文件driver.py文件里:

           self.fix_pub = rospy.Publisher('fix', NavSatFix, queue_size=1)
            self.vel_pub = rospy.Publisher('vel', TwistStamped, queue_size=1)
            self.heading_pub = rospy.Publisher(
                'heading', QuaternionStamped, queue_size=1)

    rostopic echo /fix

    室内无信号

    参考:https://blog.csdn.net/learning_tortosie/article/details/103349907

    将gps转换为里程计,为多传感器融合准备,使用的package:gps_umd

    cd ~/dashgo_ws/src

    git clone https://github.com/swri-robotics/gps_umd

    cd ..

    catkin_make

     fatal error: gps_common/GPSFix.h: 没有那个文件或目录

    解决方法:

    sudo apt-get install gpsd

    cd ~/dashgo_ws/src/gps_umd/gps_common

    rosmake

    如何将建好的GPS与转换模块连接参考下面

    http://wiki.ros.org/robot_pose_ekf/Tutorials/AddingGpsSensor

    gps运行产生的服务有/fix  /heading /vel /time_reference

    在使用gps_commen订阅的是GPS的/fix主题,具体看程序utm_odometry_node.cpp

    ros::Subscriber fix_sub = node.subscribe("fix", 10, callback);

    同时将他们重命名以保证扩展卡尔曼滤波使用robot_pose_ekf/src/odom_estimation_node.cpp

    if (vo_used_){
          ROS_DEBUG("VO sensor can be used");
          vo_sub_ = nh.subscribe("vo", 10, &OdomEstimationNode::voCallback, this);
        }

    remap将gps改名vo,gps可以用vo的,一个是三自由度转6自由度,但vo不可以转为gps的

    launch文件
     测试gps转换是否成功

    <launch>
    
    <include file="$(find nmea_navsat_driver)/launch/nmea_serial_driver.launch"/>
    
    <node name="gps_conv" pkg="gps_common" type="utm_odometry_node">
      <remap from="odom" to="vo"/>
      <param name="rot_covariance" value="99999" />
      <param name="frame_id" value="base_footprint" />
       <!--
      <remap from="fix" to="/gps/fix" />
    -->
    </node>
      <!--
    
    <node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf" output="screen">
      <param name="output_frame" value="odom"/>
      <param name="freq" value="30.0"/>
      <param name="debug" value="true"/>
      <param name="sensor_timeout" value="1.0"/>
      <param name="odom_used" value="true"/>
      <param name="imu_used" value="true"/>
      <param name="vo_used" value="true"/>
    
    </node>
    -->
    
    </launch>
    

     运行前测试gps_common是否能被找到

    插上GPS,运行 roslaunch robot_pose_ekf gps_odom_imu.launch

    如果使用网络连接的gps,在gps_umd中的gpscd_client中有相关代码,可参考

    传感器2:IMU honeywell  HG1120

    下载驱动 http://wiki.ros.org/hg_node

    roscore

    python ~/dashgo_ws/src/Integrated_navigation_system/driver/hg1120.py

     rostopic echo /imu/data

    robot_pose_ekf 中的imu订阅的消息为imu_data改为imu/data

        if (imu_used_){
          ROS_DEBUG("Imu sensor can be used");
          imu_sub_ = nh.subscribe("imu/data", 10,  &OdomEstimationNode::imuCallback, this);
        }

    里程计仿真:https://blog.csdn.net/JanKin_BY/article/details/87875124

    smartcar

    首先运行roslaunch smartcar_description smartcar_display.rviz.launch

    python ~/dashgo_ws/src/Integrated_navigation_system/driver/hg1120.py

    在运行roslaunch robot_pose_ekf gps_odom_imu.launch

    <launch>
    
    
    <include file="$(find nmea_navsat_driver)/launch/nmea_serial_driver.launch"/>
    
    <node name="gps_conv" pkg="gps_common" type="utm_odometry_node">
      <remap from="odom" to="vo"/>
      <param name="rot_covariance" value="99999" />
      <param name="frame_id" value="base_footprint" />
       <!--<remap from="fix" to="/gps/fix" /-->
    </node>
    
    <node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf" output="screen">
      <param name="output_frame" value="odom"/>
      <param name="freq" value="30.0"/>
      <param name="debug" value="true"/>
      <param name="sensor_timeout" value="1.0"/>
      <param name="odom_used" value="true"/>
      <param name="imu_used" value="true"/>
      <param name="vo_used" value="true"/>
    </node>
    
    </launch>

    目前阶段,只是通讯建完,后续还需进行协方差矩阵修改

     由于smartcar有源文件基于/opt/.....,协方差矩阵odom初始协方差不容易改

    所以选择用stm32+base_control作为odom输入

    里程计协方差矩阵添加参考:

    https://blog.csdn.net/ethan_guo/article/details/79635575

    /******************************************************************
    基于串口通信的ROS小车基础控制器,功能如下:
    1.实现ros控制数据通过固定的格式和串口通信,从而达到控制小车的移动
    2.订阅了/cmd_vel主题,只要向该主题发布消息,就能实现对控制小车的移动
    3.发布里程计主题/odm
    
    串口通信说明:
    1.写入串口
    (1)内容:左右轮速度,单位为mm/s
    (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]
    2.读取串口
    (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s
    (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
    *******************************************************************/
    #include "ros/ros.h"  //ros需要的头文件
    #include <geometry_msgs/Twist.h>
    #include <tf/transform_broadcaster.h>
    #include <nav_msgs/Odometry.h>
    //以下为串口通讯需要的头文件
    #include <string>        
    #include <iostream>
    #include <cstdio>
    #include <unistd.h>
    #include <math.h>
    #include "serial/serial.h"
    /****************************************************************************/
    using std::string;
    using std::exception;
    using std::cout;
    using std::cerr;
    using std::endl;
    using std::vector;
    /*****************************************************************************/
    float ratio = 1000.0f ;   //转速转换比例,执行速度调整比例
    float D = 0.412f ;    //两轮间距,单位是m
    float linear_temp=0,angular_temp=0;//暂存的线速度和角速度
    /****************************************************/
    unsigned char data_terminal0=0x0d;  //“/r"字符
    unsigned char data_terminal1=0x0a;  //“/n"字符
    unsigned char speed_data[10]={0};   //要发给串口的数据
    string rec_buffer;  //串口数据接收变量
    
    //发送给下位机的左右轮速度,里程计的坐标和方向
    union floatData //union的作用为实现char数组和float之间的转换
    {
        float d;
        unsigned char data[4];
    }right_speed_data,left_speed_data,position_x,position_y,oriention,vel_linear,vel_angular;
    /************************************************************/
    void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数
    {
        string port("/dev/ttyUSB0");    //小车串口号
        unsigned long baud = 115200;    //小车串口波特率
        serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口
    
        angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/s
        linear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s
    
        //将转换好的小车速度分量为左右轮速度
        left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;
        right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;
        //left_speed_data.d=angular_temp;
        //right_speed_data.d=linear_temp;
        //存入数据到要发布的左右轮速度消息
        left_speed_data.d*=ratio;   //放大1000倍,mm/s
        right_speed_data.d*=ratio;//放大1000倍,mm/s
    
        for(int i=0;i<4;i++)    //将左右轮速度存入数组中发送给串口
        {
            speed_data[i]=right_speed_data.data[i];
            speed_data[i+4]=left_speed_data.data[i];
        }
    
        //在写入串口的左右轮速度数据后加入”/r/n“
        speed_data[8]=data_terminal0;
        speed_data[9]=data_terminal1;
        //写入数据到串口
        my_serial.write(speed_data,10);
    }
    
    int main(int argc, char **argv)
    {
        string port("/dev/ttyUSB0");//小车串口号
        unsigned long baud = 115200;//小车串口波特率
        serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000));//配置串口
    
        ros::init(argc, argv, "base_controller");//初始化串口节点
        ros::NodeHandle n;  //定义节点进程句柄
    
        ros::Subscriber sub = n.subscribe("cmd_vel", 20, callback); //订阅/cmd_vel主题
        ros::Publisher odom_pub= n.advertise<nav_msgs::Odometry>("odom", 20); //定义要发布/odom主题
    
        static tf::TransformBroadcaster odom_broadcaster;//定义tf对象
        geometry_msgs::TransformStamped odom_trans;//创建一个tf发布需要使用的TransformStamped类型消息
        nav_msgs::Odometry odom;//定义里程计对象
        geometry_msgs::Quaternion odom_quat; //四元数变量
        //定义covariance矩阵,作用为解决文职和速度的不同测量的不确定性
        float covariance[36] = {0.01,   0,    0,     0,     0,     0,  // covariance on gps_x
                                0,  0.01, 0,     0,     0,     0,  // covariance on gps_y
                                0,  0,    99999, 0,     0,     0,  // covariance on gps_z
                                0,  0,    0,     99999, 0,     0,  // large covariance on rot x
                                0,  0,    0,     0,     99999, 0,  // large covariance on rot y
                                0,  0,    0,     0,     0,     0.01};  // large covariance on rot z 
        float ODOM_POSE_COVARIANCE[36] = {1e-3, 0, 0, 0, 0, 0,
                                0, 1e-3, 0, 0, 0, 0,
                                0, 0, 1e6, 0, 0, 0,
                                0, 0, 0, 1e6, 0, 0,
                                0, 0, 0, 0, 1e6, 0,
                                0, 0, 0, 0, 0, 1e3};
        float ODOM_POSE_COVARIANCE2[36] = {1e-9, 0, 0, 0, 0, 0,
                                 0, 1e-3, 1e-9, 0, 0, 0,
                                 0, 0, 1e6, 0, 0, 0,
                                 0, 0, 0, 1e6, 0, 0,
                                 0, 0, 0, 0, 1e6, 0,
                                 0, 0, 0, 0, 0, 1e-9};
    
       float ODOM_TWIST_COVARIANCE[36]= {1e-3, 0, 0, 0, 0, 0,
                                 0, 1e-3, 0, 0, 0, 0,
                                 0, 0, 1e6, 0, 0, 0,
                                 0, 0, 0, 1e6, 0, 0,
                                 0, 0, 0, 0, 1e6, 0,
                                 0, 0, 0, 0, 0, 1e3};
        float ODOM_TWIST_COVARIANCE2[36] = {1e-9, 0, 0, 0, 0, 0,
                                  0, 1e-3, 1e-9, 0, 0, 0,
                                  0, 0, 1e6, 0, 0, 0,
                                  0, 0, 0, 1e6, 0, 0,
                                  0, 0, 0, 0, 1e6, 0,
                                  0, 0, 0, 0, 0, 1e-9};
    
        ros::Rate loop_rate(10);//设置周期休眠时间
    
        while(ros::ok())
        {
            rec_buffer =my_serial.readline(25,"\n");    //获取串口发送来的数据
            const char *receive_data=rec_buffer.data(); //保存串口发送来的数据
            if(rec_buffer.length()==21) //串口接收的数据长度正确就处理并发布里程计数据消息
            {
                for(int i=0;i<4;i++)//提取X,Y坐标,方向,线速度,角速度
                {
                    position_x.data[i]=receive_data[i];
                    position_y.data[i]=receive_data[i+4];
                    oriention.data[i]=receive_data[i+8];
                    vel_linear.data[i]=receive_data[i+12];
                    vel_angular.data[i]=receive_data[i+16];
                }
                //将X,Y坐标,线速度缩小1000倍
                position_x.d/=1000; //m
                position_y.d/=1000; //m
                vel_linear.d/=1000; //m/s
    
                //里程计的偏航角需要转换成四元数才能发布
          odom_quat = tf::createQuaternionMsgFromYaw(oriention.d);//将偏航角转换成四元数
    
                //载入坐标(tf)变换时间戳
                odom_trans.header.stamp = ros::Time::now();
                //发布坐标变换的父子坐标系
                odom_trans.header.frame_id = "odom";     
                odom_trans.child_frame_id = "base_footprint";       
                //tf位置数据:x,y,z,方向
                odom_trans.transform.translation.x = position_x.d;
                odom_trans.transform.translation.y = position_y.d;
                odom_trans.transform.translation.z = 0.0;
                odom_trans.transform.rotation = odom_quat;        
                //发布tf坐标变化
                odom_broadcaster.sendTransform(odom_trans);
    
                //载入里程计时间戳
                odom.header.stamp = ros::Time::now(); 
                //里程计的父子坐标系
                odom.header.frame_id = "odom";
                odom.child_frame_id = "base_footprint";       
                //里程计位置数据:x,y,z,方向
                odom.pose.pose.position.x = position_x.d;     
                odom.pose.pose.position.y = position_y.d;
                odom.pose.pose.position.z = 0.0;
                odom.pose.pose.orientation = odom_quat;       
                //载入线速度和角速度
                odom.twist.twist.linear.x = vel_linear.d;
                //odom.twist.twist.linear.y = odom_vy;
                odom.twist.twist.angular.z = vel_angular.d;
                //载入covariance矩阵  https://blog.csdn.net/ethan_guo/article/details/79635575
                if (position_x.d== 0 and position_y.d == 0)
                 {
                    for(int i = 0; i < 36; i++)
                     {
                      odom.pose.covariance[i] = ODOM_POSE_COVARIANCE2[i];;
                      }
                    for(int i = 0; i < 36; i++)
                     {
                      odom.twist.covariance[i] = ODOM_TWIST_COVARIANCE2[i];
                     }
                 }
                else
                {
                     for(int i = 0; i < 36; i++)
                      {
                      odom.pose.covariance[i] = ODOM_POSE_COVARIANCE[i];;
                      }
                     for(int i = 0; i < 36; i++)
                      {
                       odom.twist.covariance[i] = ODOM_TWIST_COVARIANCE[i];
                      }
                }
                //发布里程计
                odom_pub.publish(odom);
    
                ros::spinOnce();//周期执行
          loop_rate.sleep();//周期休眠
            }
            //程序周期性调用
            //ros::spinOnce();  //callback函数必须处理所有问题时,才可以用到
        }
        return 0;
    }

    stm32与串口通讯参考:https://www.ncnynl.com/category/ros-car-b/ 

    还需将EKF位置与MOVE_BASE结合

    未完待续///

    展开全文
  • 卡尔曼滤波算法应用

    2021-08-29 10:48:19
    卡尔曼滤波算法应用Kalman算法简介Kalman算法应用场景Kalman滤波和贝叶斯滤波的关系Kalman滤波计算步骤Kalman计算公式和opencv对应关系 ...4.卡尔曼滤波算法本质就是利用两个正态分布的融合仍是正态分
  • 深入理解卡尔曼滤波算法

    千次阅读 2020-10-27 21:10:56
    卡尔曼滤波纸老虎 卡尔曼滤波也是一种最优估计算法,常见的最优估计算法有“最小二乘法”。...既然是加权,从而可以推导出卡尔曼滤波算法本质就是数据融合的操作(Data fusion),融合过程中的权重就是卡尔曼增益。 ...
  • 卡尔曼滤波算法

    千次阅读 2017-11-28 21:32:45
    Kalman Filter是一个高效的递归...本文介绍了卡尔曼滤波增益的由来,以及它在卡尔曼滤波理论中的作用,着重介绍了卡尔曼滤波增益的理论意义。由卡尔曼滤波增益可以更深入的理解卡尔曼滤波,把它更好地应用于实际中。
  • 通俗理解卡尔曼滤波及其算法实现(实例解析)

    万次阅读 多人点赞 2017-05-18 15:13:20
    1.简介(Brief Introduction)在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”。跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人!卡尔曼全名...
  • MPU6050_Kalman_PWM_remote 基于卡尔曼滤波的多传感器测量数据融合 MPU6050_卡尔曼滤波 KF算法流程 自平衡小车 双轮自平衡小车设计报告 陀螺仪+加速度计卡尔曼
  • 卡尔曼滤波算法介绍

    2014-11-04 09:42:10
    详细的总结了卡尔曼滤波算法的求解过程,及其在多传感器数据融合方面的应用。
  • 在信息融合中经常使用卡尔曼滤波,现在我们对其进行讲解: 百度百科上写到: 卡尔曼滤波公式如上 这是另一种表述,涉及的符号见下表: 对于联邦卡尔曼滤波: 对于一致性卡尔曼滤波: ...
  • 针对非线性系统模型参数未知情况下的状态估计问题, 提出一种融合极大后验估计的交互式容积卡尔曼滤波算法(InCKF). 该算法利用二阶斯特林插值公式和无迹变换对非线性函数的近似思想, 实现对模型未知参数的确定, 从而...
  • 卡尔曼滤波算法c实现

    2017-12-07 22:42:02
    卡尔曼滤波算法c实现 、飞行器的姿态结算,通过MPU6000/HMR5811进行数据融合处理
  • 由于研究需要,最近在看卡尔曼滤波,做个小总结。...卡尔曼滤波是以最小均方误差为估计的最佳准则,来寻求一套递推估计的算法,其基本思想是:采用信号与噪声的状态空间模型,利用前一时刻的估计值和现时刻的观
  • 卡尔曼的基本原理以及公式网上有很多,可以参照大神博客: ...request_id=162147991
  • 车辆稳定性控制系统能够提高...对于质心侧偏角的估算国内外学者也有进行不同程度的探索,但是大多采用的是积分算法卡尔曼滤波算法等等,但是在工程实际应用中却很少。 质心侧偏角通常定义为侧向车速与纵向车速的...
  • 基于模糊卡尔曼滤波的信息融合算法 应用自适应模糊逻辑系统原理
  • 在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”。跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人! 卡尔曼全名Rudolf Emil Kalman,匈牙利...
  • 经过处理效果和可实现性比对,有三种滤波算法脱颖而出:卡尔曼滤波(KF)、扩展卡尔曼滤波(EKF)以及互补滤波。其中我着重学习了卡尔曼滤波和扩展卡尔曼滤波,并对扩展卡尔曼滤波进行实现。 1. 卡尔曼滤波学习 ...
  • 卡尔曼滤波算法 matlab

    2009-05-09 12:13:08
    数据处理 卡尔曼滤波算法 matlab 传感器数据融合
  • MPU6050卡尔曼滤波算法及其推导过程,网上大部分都是只是代码,虽然可以用但是用起来总感觉怪怪的,特推导一下,如有错误请及时提醒,以免后来者再次犯错
  • 卡尔曼滤波个人理解两种信号状态变量(按照人类经验预测的状态)观测变量(根据生活工具测量的实际状态)噪声 个人理解   在卡尔曼滤波中,有两种变量。   第一种是我们预测的状态变量,是我们从日常的生活经验...
  • 平衡小车的卡尔曼滤波算法, 对小车的实例进行结合写出的算法和原理
  • 卡尔曼滤波与扩展卡尔曼滤波

    千次阅读 2018-04-22 10:51:43
    卡尔曼滤波(Kalman filtering)一种线性系统状态方程,对输入输出的观测数据进行最优估计的算法。由于观测数据中包括系统中的噪声和干扰的影响,所以最优估计也可看作是滤波过程。故求解最优估计的算法就称之为...
  • 一、用卡尔曼滤波的数据融合算法的原因 加速度求解的数学原理是三角函数关系。通过将测得的加速度矢量分解在三轴上,再根据反三角函数计算就可得到角度。在物体处于静止状态下时,此种方法的精度能够得到保证,但是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,053
精华内容 1,221
关键字:

卡尔曼滤波融合算法