自动驾驶Mapping-占位栅格图(Occupancy Grid Map)中介绍了概率占位栅格地图(Probabilistic Occupancy Grid)的原理,并推导了如何利用贝叶斯理论(Bayes Theorem)更新生成概率占位栅格地图。下面看看如何用Python代码实现未知环境中的运动车辆上安装的激光雷达(lidar)生成概率占位栅格图。

1、构建环境地图和车辆运动模型

在生成栅格地图之前,首先需要构造一个用于车辆运动的环境地图(这个地图是用于仿真的真值,对于车辆来说是未知的环境)。我们用0和1值来构造M*N的环境地图,0表示可行驶区域,1表示占用区域。

M = 50
N = 60
true_map = np.zeros((M, N))
true_map[0:10, 0:10] = 1
true_map[30:35, 40:45] = 1
true_map[3:6,40:60] = 1;
true_map[20:30,25:29] = 1;
true_map[40:50,5:25] = 1;

然后构建车辆的运动模型。这里实现了一个简单的运动模型:车辆遇到障碍物或者到达地图边界之前,沿一个方向一直行驶;遇到障碍物或者到达地图边界之后,调整方向继续行驶。

# Initializing the robot's location.
x_0 = [30, 30, 0]# The sequence of robot motions.
u = np.array([[3, 0, -3, 0], [0, 3, 0, -3]])
u_i = 1# Initialize the vector of states for our simulation.
x = np.zeros((3, len(time_steps)))
x[:, 0] = x_0while(Some Conditon...) :# Perform robot motion.move = np.add(x[0:2, t-1], u[:, u_i]) # If we hit the map boundaries, or a collision would occur, remain still.if (move[0] >= M - 1) or (move[1] >= N - 1) or (move[0] <= 0) or (move[1] <= 0) or true_map[int(round(move[0])), int(round(move[1]))] == 1:x[:, t] = x[:, t-1]u_i = (u_i + 1) % 4else:x[0:2, t] = move

车辆的运动效果如下所示:

最后要构建激光雷达(Lidar)的旋转模型。这里假设在车辆运动过程中,激光雷达(lidar)以0.3/Step的速度持续旋转,对周围的环境进行扫描。

x[2, t] = (x[2, t-1] + w[t]) % (2 * math.pi)

2、生成激光雷达(Lidar)测量数据

有了地图和车辆运动模型,我们看看如何生成运动车辆上的激光雷达(lidar)扫描数据。

首先,我们需要搞清楚激光雷达的外参和内参,并以此推导出激光雷达(lidar)在Map坐标系下的姿态(x, y,

)和激光雷达(lidar)的激光束的水平和垂直角度分布(激光束的水平和垂直角度分布跟激光雷达自身的硬件属性相关,一般可以从Lidar产品说明书中获取)。

其次,我们需要知道激光雷达(Lidar)的最大扫描范围,超出该范围的区域不能被当前位置的Lidar扫描到,因而是定义为未知区域。最大扫描范围其实也是跟激光雷达自身属性相关的参数

# Parameters for the sensor model.
meas_phi = np.arange(-0.4, 0.4, 0.05)
rmax = 30 # Max beam range.
alpha = 1 # Width of an obstacle (distance about measurement to fill in).
beta = 0.05 # Angular width of a beam.

基于已知环境地图、车辆位置、Lidar激光束分布和Lidar最大扫描范围获取Lidar扫描数据的详细的代码如下:

def get_ranges(true_map, X, meas_phi, rmax):(M, N) = np.shape(true_map)x = X[0]y = X[1]theta = X[2]meas_r = rmax * np.ones(meas_phi.shape)# Iterate for each measurement bearing.for i in range(len(meas_phi)):# Iterate over each unit step up to and including rmax.for r in range(1, rmax+1):# Determine the coordinates of the cell.xi = int(round(x + r * math.cos(theta + meas_phi[i])))yi = int(round(y + r * math.sin(theta + meas_phi[i])))# If not in the map, set measurement there and stop going further.if (xi <= 0 or xi >= M-1 or yi <= 0 or yi >= N-1):meas_r[i] = rbreak# If in the map, but hitting an obstacle, set the measurement range# and stop ray tracing.elif true_map[int(round(xi)), int(round(yi))] == 1:meas_r[i] = rbreakreturn meas_r

3、计算Inverse Scanner Model

获取激光雷达(Lidar)的测量数据之后,下一步就是将其关联匹配到地图的Map Cell上。主要流程是:

1)将 Lidar bearing与Map Cell相对于传感器的方位进行最小误差匹配,得到影响当前Map Cell的激光束;

匹配的代码如下:

r = math.sqrt((i - x)**2 + (j - y)**2)
phi = (math.atan2(j - y, i - x) - theta + math.pi) % (2 * math.pi) - math.pi# Find the range measurement associated with the relative bearing.
k = np.argmin(np.abs(np.subtract(phi, meas_phi)))

2) 计算每个Cell被占用的概率。计算完成之后,得到三种不同类型的区域:未探测区域、障碍物区域和非障碍物区域,并赋给它们不同的占用概率。这里将未探测区域的占用概率设为0.5,表示不确定是否占用;障碍物区域占用概率等于0.7,表示大概率被占用;可行驶区域占用概率0.3,表示小概率被占用。

完整的Inverse Scanner Model的实现代码如下:

def inverse_scanner(num_rows, num_cols, x, y, theta, meas_phi, meas_r, rmax, alpha, beta):m = np.zeros((M, N))for i in range(num_rows):for j in range(num_cols):# Find range and bearing relative to the input state (x, y, theta).r = math.sqrt((i - x)**2 + (j - y)**2)phi = (math.atan2(j - y, i - x) - theta + math.pi) % (2 * math.pi) - math.pi# Find the range measurement associated with the relative bearing.k = np.argmin(np.abs(np.subtract(phi, meas_phi)))# If the range is greater than the maximum sensor range, or behind our range# measurement, or is outside of the field of view of the sensor, then no# new information is available.if (r > min(rmax, meas_r[k] + alpha / 2.0)) or (abs(phi - meas_phi[k]) > beta / 2.0):m[i, j] = 0.5# If the range measurement lied within this cell, it is likely to be an object.elif (meas_r[k] < rmax) and (abs(r - meas_r[k]) < alpha / 2.0):m[i, j] = 0.7# If the cell is in front of the range measurement, it is likely to be empty.elif r < meas_r[k]:m[i, j] = 0.3return m

Inverse Scanner Model的测量结果如下图所示:

4、生成概率占位栅格地图(Probabilistic Occupancy Grid)

生成概率占位地图的过程就是循环对激光雷达(lidar)的测量结果应用Inverse Scanner Model,然后更新各个Map Cell的Log Odds的过程(详细推导过程参见:自动驾驶Mapping-占位栅格图(Occupancy Grid Map)):

其中:

是Inverse Measurement Model,
是网格i在t-1时刻的置信度(belif),
是Initial belief。

最后,将log odds还原为真实概率,得到每个网格的占位概率值。

生成概率占位地图的代码如下:

meas_rs = []
meas_r = get_ranges(true_map, x[:, 0], meas_phi, rmax)
meas_rs.append(meas_r)
invmods = []
invmod = inverse_scanner(M, N, x[0, 0], x[1, 0], x[2, 0], meas_phi, meas_r, rmax, alpha, beta)
invmods.append(invmod)
ms = []
ms.append(m)# Main simulation loop.
for t in range(1, len(time_steps)):# Perform robot motion.move = np.add(x[0:2, t-1], u[:, u_i]) # If we hit the map boundaries, or a collision would occur, remain still.if (move[0] >= M - 1) or (move[1] >= N - 1) or (move[0] &lt;= 0) or (move[1] &lt;= 0) or true_map[int(round(move[0])), int(round(move[1]))] == 1:x[:, t] = x[:, t-1]u_i = (u_i + 1) % 4else:x[0:2, t] = movex[2, t] = (x[2, t-1] + w[t]) % (2 * math.pi)# Gather the measurement range data, which we will convert to occupancy probabilitiesmeas_r = get_ranges(true_map, x[:, t], meas_phi, rmax)meas_rs.append(meas_r)# Given our range measurements and our robot location, apply inverse scanner modelinvmod = inverse_scanner(M, N, x[0, t], x[1, t], x[2, t], meas_phi, meas_r, rmax, alpha, beta)invmods.append(invmod)# Calculate and update the log odds of our occupancy grid, given our measured occupancy probabilities from the inverse model.L = np.log(np.divide(invmod, np.subtract(1, invmod))) + L - L0# Calculate a grid of probabilities from the log odds.m = np.divide(np.exp(L), np.add(1, np.exp(L)))ms.append(m)

生成概率占用地图的过程如下:

最终生成的概率占用栅格地图如下图所示。可以看看它基本反应了真实的实际车辆运行环境。


注:本文首发于微信公众号,转载请注明出处,谢谢!

公众号:半杯茶的小酒杯

个人博客地址:

http://www.banbeichadexiaojiubei.com​www.banbeichadexiaojiubei.com

参考链接

1、Course自动驾驶课程: Motion Planning for Self-Driving Cars的Weekly Assignment -Occupancy Grid Generation

相关文章

半杯茶的小酒杯:自动驾驶Mapping-占位栅格图(Occupancy Grid Map)​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶中的车辆运动学模型​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶定位算法(十五)基于多传感器融合的状态估计(muti-Sensors Fusion)​zhuanlan.zhihu.com

自动驾驶路径规划器-Lattice Planner详解​www.banbeichadexiaojiubei.com半杯茶的小酒杯:自动驾驶定位算法(十四)-递归贝叶斯滤波(Bayes Filter)​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶定位算法(十三)-粒子滤波(Particle Filter)​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶硬件系统(十二)-激光雷达(Lidar)测量模型​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶硬件(十一)-Global Navigation Satellite System-GNSS​zhuanlan.zhihu.com

半杯茶的小酒杯:自动驾驶硬件系统(十)- Inertial Measurement Unit (IMU)​zhuanlan.zhihu.com

自动驾驶定位算法(九)-直方图滤波(Histogram Filter)定位​www.banbeichadexiaojiubei.com

get占位符传多个参数_未知环境下的Lidar概率占位栅格图(Occupancy Grid Map) Python代码实现...相关推荐

  1. python中outside loop_未知环境下的Lidar概率占位栅格图(Occupancy Grid Map) Python代码实现...

    自动驾驶Mapping-占位栅格图(Occupancy Grid Map)中介绍了概率占位栅格地图(Probabilistic Occupancy Grid)的原理,并推导了如何利用贝叶斯理论(Bay ...

  2. get占位符传多个参数_mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法...

    useActualParamName配置 useActualParamName 允许使用方法签名中的名称作为语句参数名称. 为了使用该特性,你的工程必须采用Java 8编译,并且加上-paramete ...

  3. 自动驾驶之-MATLAB环境下利用单目摄像头和语义分割创建占位栅格(occupancy grid)

    准备写一些关于自动驾驶方面的东西,以前研究过一些,也比较感兴趣. 本文简单讲解如何使用深度学习语义分割估计车辆可行驶区域(free space),并创建占位栅格(occupancy grid),然后使 ...

  4. java word模板占位符_word模板导出的几种方式:第一种:占位符替换模板导出(只适用于word中含有表格形式的)...

    1.占位符替换模板导出(只适用于word中含有表格形式的): /// /// 使用替换模板进行到处word文件 /// public class WordUtility { private objec ...

  5. 支架预压弹性变形值计算_复杂环境下大跨度箱梁整体支架法现浇安全要点

    一.工程概况 跨广从公路特大桥位于广州市白云区太和镇境内,共38个墩台,其中22#-23#墩以1-96m系杆拱依次高.中压天然气管道.电力通信光缆.G105国道.海军光缆,移动联通光缆.交通监控系统光 ...

  6. python粘贴代码运行不了_老师上课总是不给PPT?于是我用几行python代码偷偷复制U盘文件...

    上大学的时候有老师不给上课的PPT,就总想有个程序能偷偷复制老师的U盘....其实用几行python代码就能搞定了.分两步,首先写出来python代码,其次把.py文件转换成exe文件,直接在wind ...

  7. golang 函数传多个参数_关于Golang中方法参数的传递

    结构体声明 为了说明函数以及方法调用的过程,这里先定义一个struct,在下面的描述中会使用到它. type Person struct { Name string Age uint16 } 普通函数 ...

  8. el-select change事件传多个参数_第8天 | 14天搞定Vue3.0,事件处理(详细)

    在JavaScript语言中,当用户与UI组件交互时,UI组件能够激发一个相应事件.例如,用户按动按钮.滚动文本.移动鼠标或按下按键等,都将产生一个相应的事件. Vue3.0使用v-on指令(缩写为@ ...

  9. bland c++_为什么要使用bland altman图进行ab测试python代码

    bland c++ 目录(Table of contents) Why using the Bland-Altman plot 为什么要使用Bland-Altman图 The used data 使用 ...

最新文章

  1. 资源在另一个编辑器中打开的错误处理办法
  2. JavaFX技巧7:使用CSS颜色常量/派生颜色
  3. JSP request response session
  4. Hyperledger Fabric学习笔记(二)- Fabric 2.2.1环境搭建
  5. EBay架构案例分析
  6. 怎么测试本地网页在不同分辨率下电脑显示效果_4K商用超值利器 飞利浦272P7VPTKEB显示器评测...
  7. B站游戏排行榜(No.1竟是‘原神‘)—— B站动态页面爬取
  8. 她每天吃一个煮熟的苹果,从此打开了通往新世界的大门~
  9. Request method ‘PUT‘ not supported
  10. API Design for ios 译文
  11. 文件管理(文件系统)
  12. 华为P20 Pro对比iPhone X:谁更能拍出人像高级美?
  13. Android win10 平板 省电,小编解答win10系统Mobile设置更省电的图文办法
  14. 我这些年从来没有用过算法,除了出去面试的时候
  15. 阿里云 验证四要素 服务
  16. JDK1.8下载与安装完整教程
  17. 二手房信息发布平台源码-得推微房产系统v2.1
  18. CSS Emmet 语法
  19. Redis数据类型-Hash-基本使用
  20. 邻家汇:广告+精准营销助商超转型升级

热门文章

  1. k8s系列~mgr的应用
  2. 【java】在分页查询结果中对最后的结果集List进行操作add()或remove()操作,报错:java.lang.UnsupportedOperationException...
  3. AWS Artifact如何处理企业的法规遵从?
  4. Netflix CEO哈斯廷斯:内容为王 公司潜力依然巨大
  5. Objective-C单例
  6. 管理表空间和数据文件——使用OMF方式管理表空间
  7. Windows 7 IIS (HTTP Error 500.21 - Internal Server Error)解决
  8. 零基础Java学习之类和对象
  9. 单例模式 之 单例模式——懒汉模式
  10. gradle加载spring包