占据栅格地图(Occupancy Grid Map)
转载自:https://zhuanlan.zhihu.com/p/21738718
写在前面:这篇文章是Coursera上的课程(Robotics: Estimation and Learning),权当笔记,激光传感器的数据可以在课程内下载。这一周的内容比较简单,但十分实用。
在这片文章中,我们将会介绍:
- 机器人世界的几种地图;
- 占据栅格地图的表示方法与更新方法;
- 利用激光传感器数据构建占据栅格地图。
1. 机器人地图的分类
地图有很多种表示方式,例如,用经纬度标识地方的世界地图,城市的地铁图,校园指引图。
第一种我们称为尺度地图(Metric Map),每一个地点都可以用坐标来表示,比如北京在东经116°23′17'',北纬39°54′27'';第二种我们称为拓扑地图(Topological Map),每一个地点用一个点来表示,用边来连接相邻的点,即图论中的图(Graph),比如从地铁路线图中我们知道地铁红磡站与旺角东站和尖东站相连;第三种我们称为语义地图(Semantic Map),其中每一个地点和道路都会用标签的集合来表示,例如,有人问我中山大学教学楼E栋在哪里,我会说在图书馆正门右手边靠近图书馆的一侧。
在机器人领域,尺度地图常用于定位于地图构建(Mapping)、定位(Localization)和同时定位与地图构建(Simultaneous Localization And Mapping,SLAM),拓扑地图常用于路径规划(Path Planning),而语义地图常用于人机交互(Human Robot Interaction)。
这节课我们将介绍如何用机器人传感器数据绘制尺度地图。这有什么难点呢?首先也是最重要的一点,传感器数据有噪音。用激光传感器检测前方障碍物距离机器人多远,不可能检测到一个准确的数值。如果准确值是米,有时会测出1.42米,有时甚至1.35米。另外,传感器数据是本地坐标系的,而机器人要构建的是一个全局的地图。最后,机器人会运动,运动也是有噪音的。总结起来就两个字,噪音。通俗点来讲,“不准”。
在专栏的第一篇文章中,我们详细提到了如何对噪音进行建模,用的是概率分布(高斯分布)。在这篇文章中,我们同样利用“概率”这一神奇的数学武器来处理机器人Mapping的问题。
2. 占据栅格地图
我们首先来介绍机器人Mapping用到的的传感器,它叫做激光传感器(Laser Sensor),如下图所示:
激光传感器会向固定的方向发射激光束,发射出的激光遇到障碍物会被反射,这样就能得到激光从发射到收到的时间差,乘以速度除以二就得到了传感器到该方向上最近障碍物的距离。
这样看来,似乎利用激光传感器,机器人能够很好地完成Mapping这一任务。但是我们前面提到了,传感器数据是有噪音的。例如,假如我们在此时检测到距离障碍物4米,下一时刻检测到距离障碍物4.1米,我们是不是应该把4米和4.1米的地方都标记为障碍物?又或者怎么办呢?
为了解决这一问题,我们引入占据栅格地图(Occupancy Grid Map)的概念。
我们首先来解释这里的占据率(Occupancy)指的是什么。在通常的尺度地图中,对于一个点,它要么有(Occupied状态,下面用1来表示)障碍物,要么没有(Free状态,下面用0来表示)障碍物(旁白:那么问题来了,薛定谔状态呢?)。在占据栅格地图中,对于一个点,我们用来表示它是Free状态的概率,用来表示它是Occupied状态的概率,当然两者的和为。两个值太多了,我们引入两者的比值来作为点的状态:。
对于一个点,新来了一个测量值(Measurement,)之后我们需要更新它的状态。假设测量值来之前,该点的状态为,我们要更新它为:。这种表达方式类似于条件概率,表示在发生的条件下的状态。
根据贝叶斯公式,我们有:
带入之后,我们得
我们对两边取对数得:
这样,含有测量值的项就只剩下了。我们称这个比值为测量值的模型(Measurement Model),标记为。测量值的模型只有两种:和,而且都是定值。
这样,如果我们用来表示位置的状态的话,我们的更新规则就进一步简化成了:。其中和分别表示测量值之后和之前的状态。
另外,在没有任何测量值的初始状态下,一个点的初始状态。
经过这样的建模,更新一个点的状态就只需要做简单的加减法了。这,就是数学的魅力。
例如,假设我们设定,。那么, 一个点状态的数值越大,就表示越肯定它是Occupied状态,相反数值越小,就表示越肯定它是Free状态。
上图就展示了用两个激光传感器的数据更新地图的过程。在结果中,一个点颜色越深表示越肯定它是Free的,颜色越浅表示越肯定它是Occupied的。
3. 利用激光传感器构建占据栅格地图
前面讲到通常用激光传感器数据来构占据栅格地图,这一节我们将详细介绍其中的实现细节。具体来说,我们需要编写函数:
function myMap = occGridMapping(ranges, scanAngles, pose, param)
其中,scanAngles是一个的数组,表示激光传感器的个激光发射方向(与机器人朝向的夹角,定值);ranges是一个的数组,表示个时间采样点激光传感器的读数(距离障碍物的距离);pose是一个的数组,表示个时间采样点机器人的位置和朝向信息(前两维为位置,第三维为朝向角度);param是一些传入的参数,param.origin是机器人的起点,param.lo_occ和param.lo_free分别是第二节中的和,param.max和param.min表示位置状态的阈值(超过则置为阈值边界),param.resol表示地图的分辨率,即实际地图中一米所表示的格点数目,param.size表示地图的大小。
首先,我们解决如何将真实世界中的坐标转化为栅格地图中的坐标。
考虑一维的情况:
图中是真实世界中的坐标,为离散化了的地图(栅格地图)中的坐标,为一格的长度,表示分辨率,显然我们有:。
同理,二维情况下:。
其次,我们来计算每一条激光所检测出的障碍物和非障碍物在栅格地图中的位置。
假设机器人的状态为,激光与机器人朝向的夹角为,测量的障碍物的距离为(途中未标明,不好意思):
计算障碍物所在点的实际位置:
再计算障碍物在栅格地图中的位置,以及机器人在栅格地图中的位置。根据这两个坐标可以使用Bresenham算法来计算非障碍物格点的集合。
最后,利用第二节中的结论,我们使用简单的加减法不断更新格点的状态即可。
完整的Matlab代码如下:
function myMap = occGridMapping(ranges, scanAngles, pose, param)resol = param.resol; % the number of grids for 1 meter.
myMap = zeros(param.size); % the initial map size in pixels
origin = param.origin; % the origin of the map in pixels% Log-odd parameters
lo_occ = param.lo_occ;
lo_free = param.lo_free;
lo_max = param.lo_max;
lo_min = param.lo_min;lidarn = size(scanAngles,1); % number of rays per timestamp
N = size(ranges,2); % number of timestampfor i = 1:N % for each timestamptheta = pose(3,i); % orientation of robot% coordinate of robot in real worldx = pose(1,i);y = pose(2,i);% local coordinates of occupied points in real worldlocal_occs = [ranges(:,i).*cos(scanAngles+theta), -ranges(:,i).*sin(scanAngles+theta)];% coordinate of robot in metric mapgrid_rob = ceil(resol * [x; y]);% calc coordinates of occupied and free points in metric mapfor j=1:lidarnreal_occ = local_occs(j,:) + [x, y]; % global coordinate of occ in real worldgrid_occ = ceil(resol * real_occ); % coordinate of occ in metric map% coordinates of free in metric map (by breshnham's algorithm)[freex, freey] = bresenham(grid_rob(1),grid_rob(2),grid_occ(1),grid_occ(2));% convert coordinate to offset to arrayfree = sub2ind(size(myMap),freey+origin(2),freex+origin(1));occ = sub2ind(size(myMap), grid_occ(2)+origin(2), grid_occ(1)+origin(1));% update metric mapmyMap(free) = myMap(free) - lo_free;myMap(occ) = myMap(occ) + lo_occ;end
end% reassign value if out of range
myMap(myMap < lo_min) = lo_min;
myMap(myMap > lo_max) = lo_max;
使用课程给的数据,我们最终画出下面这样的占据栅格地图(用灰度图显示出来 的):
结语:地图构建(Mapping)是机器人领域的一个重要问题,本文介绍了占据栅格地图的表示方法和利用激光传感器构建占据栅格地图的方法。但是,我们不难发现,使用的数据中机器人的位置和朝向是给定的。然而在实际的应用中,机器人不仅需要为未知环境构建地图,还要在未知环境中定位(Localization)以完成其他任务。我们发现,Mapping和Localization是相辅相成、不可分割的两部分,这就是同时定位与地图构建(SLAM)问题,机器人领域中的一个重要问题。
占据栅格地图(Occupancy Grid Map)相关推荐
- 占用栅格地图(occupancy grid map)
机器人地图分类 尺度地图(metric map):每一个地点都可以用坐标来表示,比如经纬度. 拓扑地图(topological map):每一个地点用一个点来表示,用边来连接相邻的点,即图论中的图. ...
- 9 概率机器人 Probabilistic Robotics 二值贝叶斯滤波 占据栅格地图 occupancy grid mapping
文章目录 1 前言 2 二值贝叶斯滤波 2.1 理论基础 2.2 算法流程 2.3 重要公式推导 3 实例:占据栅格地图(occupancy grid mapping) 4 参考文献 1 前言 如果通 ...
- get占位符传多个参数_未知环境下的Lidar概率占位栅格图(Occupancy Grid Map) Python代码实现...
自动驾驶Mapping-占位栅格图(Occupancy Grid Map)中介绍了概率占位栅格地图(Probabilistic Occupancy Grid)的原理,并推导了如何利用贝叶斯理论(Bay ...
- python中outside loop_未知环境下的Lidar概率占位栅格图(Occupancy Grid Map) Python代码实现...
自动驾驶Mapping-占位栅格图(Occupancy Grid Map)中介绍了概率占位栅格地图(Probabilistic Occupancy Grid)的原理,并推导了如何利用贝叶斯理论(Bay ...
- 二维占用栅格地图Occupancy grid maps
机器人的地图表示方式有多种,如拓扑地图.特征地图.直接表征法.栅格地图等.其中,栅格地图应用广泛,方便用于机器人的导航规划中.下面就是一个占用栅格地图的例子: 一般有一个地图和一个.yaml文件. m ...
- 机器人的地图——占据栅格地图
1. 机器人地图的分类 地图有很多种表示方式,例如,用经纬度标识地方的世界地图,城市的地铁图,校园指引图. 第一种我们称为尺度地图(Metric Map),每一个地点都可以用坐标来表示,比如北京在东经 ...
- 占据栅格地图构建(Occupancy Grid Map)
移动机器人地图构建问题,主要以gmapping为例,讲解了地图构建的整个流程.看过前面文章的小伙伴肯定都知道,gmapping算法把SLAM问题分解成两个部分,定位问题和地图构建问题.而gmappin ...
- 机器人学习--栅格地图(occupancy grid map)构建(部分代码解析)
转自: 占据栅格地图构建(Occupancy Grid Map) - 知乎 占据栅格地图构建(Occupancy Grid Map)_「小白学移动机器人」一个专注分享移动机器人相关知识的公众号!-CS ...
- Motion planning for self-driving cars课程笔记1:应用雷达数据生成占用栅格地图(Occupancy Grid Map)
此文章为Motion planning for self-driving cars上第二课的笔记,主要讲述占据栅格地图的生成.由于课程中算法也是参考<probability robot>这 ...
最新文章
- 口腔菌群让你心口一致——牙疼和心脏病都会犯
- [C1W3] Neural Networks and Deep Learning - Shallow neural networks
- 曲线绕x轴旋转曲面方程_空间曲线绕空间直线旋转生成的旋转曲面方程
- 电脑键盘按钮功能注释大全
- java 后台自动刷新请求_spring oauth2+JWT后端自动刷新access_token
- 直接选择排序与冒泡排序
- linux内核IDR机制详解【转】
- VC6 程序 在VS2019或其他高版本上编译运行
- 风火编程--繁体转简体
- 微信小程序—智能停车
- SRE 到底是干什么的??
- bzoj4200: [Noi2015]小园丁与老司机(可行流+dp)
- [大数据技术] 淘宝双11数据分析与预测实验
- 东华助手 v1.6.5
- 西安交通大学计算机博士名单,2017年西安交通大学博士生拟录取名单公示(3)
- Internet 协议与分析——期末复习总结
- 搭建内网ntp时间同步服务器
- Exchange server 2010系列教程之九 配置exchange server 2010 OWA(3)
- 计算机操作员中级上机,计算机操作员中级上机(范文).doc
- FIRST集和FOLLOW集的计算
热门文章
- java怎么改变数据类型_java数据类型之间的转换,是怎么回事啊? - 收获啦
- python定义的关键数据类型_Python基本数据类型
- pta 哈利·波特的考试
- c++ 小游戏_C/C++编程笔记:C语言写推箱子小游戏,大一学习C语言练手项目
- 不要用JWT替代session管理(上):全面了解Token,JWT,OAuth,SAML,SSO
- 基于java的IO流的文件读取系统
- Angular2:从AngularJS 1.x 中学到的经验
- Android App监听软键盘按键的三种方式(转)
- iOS开发-简单解析JSON数据
- HttpClient的一种简单实现Demo