二维占用栅格地图Occupancy grid maps

      机器人的地图表示方式有多种,如拓扑地图、特征地图、直接表征法、栅格地图等。其中,栅格地图应用广泛,方便用于机器人的导航规划中。下面就是一个占用栅格地图的例子:

 一般有一个地图和一个.yaml文件。 map_server是一个ROS node,可以从磁盘读取地图并使用ROS service提供地图。 目前实现的map_server可将地图中的颜色值转化成三种占用值:free (0), occupied (100), and unknown (-1). 未来可用0~100之间的不同值指示占用度。map_server使得地图的数据变成 ros 的service 可以被调用,其中以两种方式存储。一个是yaml文件,他存储了数据的元数据。一个是image file   他编码了地图的占据性情况。其中 image file 中白色像素是空的,黑色像素是被占据的。色彩或者灰色的是被接受的。 

地图的yaml格式中有:

  • image:包含占用数据的图像文件的路径; 可以是绝对的,或相对于YAML文件的位置
  • resolution:地图的分辨率,米/像素
  • origin:地图中左下像素的2-D姿态为(x,y,yaw),偏航为逆时针旋转(yaw = 0表示无旋转)。系统的许多部分目前忽略偏航。
  • occupancy_thresh:占据概率大于该阈值的像素被认为完全占用。
  • free_thresh:占有概率小于该阈值的像素被认为是完全自由的。
  • negate:白/黑自由/占用语义是否应该被反转(阈值的解释不受影响)

问题1:如何将orgin转换成实际地图中的位置?

1.确定地图的坐标系,为最右上角的像素为坐标(0,0)

整副地图都处于坐标系的第三像限

2.解析origin x=-2.5m y=-1.6m,将x,y的值除以分辨率resolution(米/像素)

得出x=-50个像素,y为-32个像素

从地图的最右上角像素数,往左数第50个像素,再往下数第32个像素,就是orgin所代表的机器人初始位置。

问题2:如何在导航中实时显示机器人的位置

1.确定机器人本身的坐标系,一般是base_footprint或者base_link,在2d的地图上这两者基本没有区别,可选取其中一个

2.获取从map到base_footprint的tf变换,代表机器人以orgin位置为原点的坐标系上位置。

3.orgin中的x,y(减去/加上)tf变换中的x,y,就是当前机器人的当前位置,再除以resolution,就是地图中机器人位置所在的像素。

map_server(地图服务器)  

map_server是一个ROS node,可以从磁盘读取地图并使用ROS service提供地图。 目前实现的map_server可将地图中的颜色值转化成三种占用值:free (0), occupied (100), and unknown (-1). 未来可用0~100之间的不同值指示占用度。

1.命令语法

map_server <map.yaml>

2. 示例

rosrun map_server map_server mymap.yaml

注意:map data可以通过指定topic或者 service来提取。service的方式最后可能要被废弃。

3 .发布的主题

map_metadata (nav_msgs/MapMetaData)

  • Receive the map metadata via this latched topic.

map (nav_msgs/OccupancyGrid)

  • Receive the map via this latched topic.

4. 服务

static_map (nav_msgs/GetMap)

  • Retrieve the map via this service.

5. 参数

~frame_id (string, default: "map") 

The frame to set in the header of the published map.

 

map_saver(地图保存器)

map_saver可以把地图保存到磁盘。 例如:from a SLAM mapping service.

1 .命令语法

rosrun map_server map_saver [-f mapname]

map_saver retrieves map data and writes it out to map.pgm and map.yaml. Use the -f option to provide a different base name for the output files.

2. 命令示例

rosrun map_server map_saver -f mymap

3. 订阅的主题

map (nav_msgs/OccupancyGrid) Map will be retrieved via this latched topic

更多的ROS中nav_msgs消息类型在这里,和这里

### 四足机器人Grid Mapping算法与实现 #### 1. 高斯网格地图 (Gaussian Grid Maps) 高斯网格地图是一种用于表示环境不确定性的方法。通过将环境划分为多个单元格,并为每个单元格分配一个均值和方差来描述该位置被占用的概率。这种方法能够有效地处理传感器噪声并提供更精确的地图。 对于四足机器人而言,在复杂地形上移动时,利用激光雷达或其他距离测量设备获取周围障碍物的信息后更新这些参数可以提高导航的安全性和准确性[^2]。 ```python import numpy as np def update_gaussian_grid_map(grid, measurement): """ 更新高斯网格地图 """ for cell in grid.cells: if is_in_sensor_range(cell.position, measurement.range): z = compute_measurement_likelihood(cell.position, measurement) # 使用贝叶斯公式更新先验分布 posterior_mean = ... posterior_variance = ... set_cell_probability(cell, posterior_mean, posterior_variance) ``` #### 2. 射线投射网格地图 (Ray Casting Grid Maps) 射线投射技术广泛应用于基于LiDAR数据创建二维或三维空间内的离散化模型。当接收到一组来自传感器的距离读数时,沿着每条光线方向标记第一个遇到的物体表面作为边界点;其余部分则保持为空闲状态。这有助于快速识别可通行区域以及潜在碰撞风险区。 针对四足行走装置的特点——即其较低的高度和灵活的姿态调整能力——采用此类映射方式可以在未知环境中实现实时避障功能的同时维持较高的运算效率[^4]。 ```cpp void cast_rays(const std::vector<LaserScan>& scans, OccupancyGrid& map) { for(auto scan : scans){ Point start_point(0,0); // 假设起点位于原点 for(size_t i=0; i<scan.ranges.size(); ++i){ double range = scan.ranges[i]; if(range != INFINITY){ Point end_point(cos(i)*range,sin(i)*range); while(start_point!=end_point){ int index=get_index_from_coordinates(map,start_point.x(),start_point.y()); if(index>=0 && index<=map.data().size()){ map.set_occupied(index,true); break; } move_along_ray(start_point,end_point); } } } } } ``` #### 3. SLAM 后期占据栅格建图 (Post-SLAM Occupancy Grid Mapping) 在完成同步定位与建模(SLAM)过程之后,通常会得到一张较为粗糙但覆盖范围广的地图。为了使这张地图更适合实际应用中的路径规划需求,可以通过后期占据栅格建图进一步细化它。具体来说就是重新评估各个像素点是否属于障碍物,并据此调整它们的状态标签(如自由/已知/未知),从而获得更加平滑且易于解析的结果图像[^3]。 ```matlab function updatedMap = refine_slam_output(slamOutput) % 对SLAM输出进行优化以适应后续任务要求 % 初始化新的占据栅格结构体变量 refinedMap = initialize_empty_occupancy_grid(); % 获取原始SLAM生成的地图尺寸信息 [rows, cols] = size(slamOutput); for rowIdx = 1:rows for colIdx = 1:cols currentCellValue = slamOutput(rowIdx,colIdx); switch true case isnan(currentCellValue)||isinf(currentCellValue) % 设置未探索过的区域为'未知' refinedMap(rowIdx,colIdx)=UNKNOWN_CELL_VALUE; case currentCellValue>OBSTACLE_THRESHOLD % 当前位置存在较大可能性含有实体,则将其设定成‘占有’ refinedMap(rowIdx,colIdx)=OCCUPIED_CELL_VALUE; otherwise % 默认情况下认为是开放的空间 refinedMap(rowIdx,colIdx)=FREE_SPACE_VALUE; end end end updatedMap = smoothed(refinedMap); end ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值