3、地图基础:地图类型、格式与创建编辑
说到导航,地图就是机器人的「眼睛」和「记忆」。没有地图,机器人就是个睁眼瞎。
我刚开始做机器人那会儿,用的还是自己手画的栅格地图,踩了不少坑。今天咱们就把地图这块彻底聊透。
3.1 地图类型:占用网格 vs 代价地图
ROS2导航栈里,地图主要分两种。说白了,一个管「能不能走」,一个管「好不好走」。
3.1.1 占用网格地图(Occupancy Grid Map)
这是最基础的地图。每个格子存一个值:0表示空闲,100表示障碍物,-1表示未知。
我习惯叫它「黑白地图」。它只告诉你:这地方有东西没东西?
核心特点:
- 每个格子独立存储,互不影响
- 值范围:0(空闲)到 100(占用),-1 表示未知
- 常用于SLAM建图和静态障碍物表示
举个例子,你拿激光雷达扫一圈,扫到墙的地方标100,没扫到的地方标0,没扫到的地方标-1。就这么简单。
3.1.2 代价地图(Costmap)
代价地图就高级一点了。它在占用网格的基础上,给每个格子加了一个「代价」值。
代价越高,机器人越不想走。比如靠近障碍物的地方,代价会逐渐升高,这叫「膨胀层」。
我的经验:代价地图分两种——全局代价地图和局部代价地图。全局的用于路径规划,局部的用于实时避障。我在项目里经常把全局代价地图的膨胀半径设大一点,让机器人走得更稳。
代价地图的组成其实挺有意思:
- 静态层:从占用网格地图加载的固定障碍物
- 障碍物层:传感器实时检测到的动态障碍物
- 膨胀层:把障碍物周围区域标记为高代价,防止机器人撞上
你想想看,如果只用占用网格,机器人规划路径时可能贴着墙走。有了代价地图,它就知道「离墙远一点更安全」。
3.2 地图格式:YAML + PGM/PNG
ROS2里地图文件通常是一对「双胞胎」:一个YAML配置文件,一个PGM或PNG图片文件。
3.2.1 YAML文件
YAML文件是地图的「身份证」,记录了地图的所有元信息。
image: map.pgm
resolution: 0.05
origin: [-10.0, -10.0, 0.0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196
每个字段什么意思?我一个个说:
| 字段 | 说明 | 我的建议 |
|---|---|---|
| image | 图片文件名,相对路径或绝对路径 | 建议用相对路径,方便移植 |
| resolution | 每个像素代表的实际距离(米/像素) | 0.05米比较常用,精度够用 |
| origin | 地图左下角在世界坐标系中的位置 [x, y, yaw] | 这个容易搞错,我吃过亏 |
| negate | 是否反转黑白(0或1) | 默认0,别乱改 |
| occupied_thresh | 像素值大于此阈值视为障碍物 | 0.65是个稳妥值 |
| free_thresh | 像素值小于此阈值视为空闲 | 0.196,别问我为什么是这个数 |
注意:origin这个参数我曾经搞错过一次。当时地图加载后机器人位置对不上,查了半天才发现origin设成了[0,0,0],但实际地图左下角在[-5,-5,0]。记住,origin是地图左下角的世界坐标,不是中心点。
3.2.2 PGM/PNG图片
图片就是地图的「肉身」。PGM是灰度图,PNG是便携式网络图形。
我个人更推荐PNG格式,因为文件小、压缩好,而且很多图像编辑软件都支持。
图片的像素值对应关系:
- 白色(255):空闲区域,机器人可以走
- 黑色(0):障碍物,机器人不能走
- 灰色(205左右):未知区域,没探测到
嗯,这里要注意:PGM文件是纯灰度,PNG可以是彩色但地图只用灰度通道。我见过有人用彩色PNG做地图,结果加载出来全是未知区域。
3.3 如何创建与编辑地图
创建地图的方法有好几种,我按使用场景给你捋一捋。
3.3.1 使用SLAM工具建图
这是最正规的方法。用激光雷达或深度相机,让机器人跑一圈,自动生成地图。
常用的SLAM工具:
- Cartographer:Google出品,精度高,适合大场景
- Gmapping:经典方案,适合小场景
- Hector SLAM:不需要里程计,纯激光匹配
我建议新手先用Cartographer,虽然配置复杂点,但效果确实好。记得我第一次用Cartographer建图,跑了50米长的走廊,回来一看地图几乎零误差。
3.3.2 手动绘制地图
有时候没有传感器,或者场景太简单,手动画一张也行。
步骤很简单:
- 用画图软件(比如GIMP、Photoshop)新建一张灰度图
- 白色画空闲区域,黑色画障碍物
- 保存为PGM或PNG
- 编写对应的YAML文件
小技巧:手动画地图时,记得留出机器人能通过的通道宽度。我一般至少画3个像素宽的通道,对应实际0.15米(分辨率0.05米)。太窄了机器人过不去。
3.3.3 编辑现有地图
建好的地图往往需要微调。比如有些动态障碍物被扫进去了,或者地图边缘有噪点。
我常用的编辑方法:
- GIMP:免费开源,用橡皮擦擦除噪点,用画笔补障碍物
- ROS的map_server:可以用命令行工具修改YAML参数
- 自己写脚本:用Python的PIL库批量处理像素
举个例子,我遇到过建图时有个纸箱被扫进去了,后来纸箱搬走了但地图上还有障碍物。这时候用GIMP打开PGM文件,把那个黑点涂成白色就行。
避坑指南:编辑地图后一定要重新检查YAML文件里的resolution和origin。我曾经改过图片尺寸但忘了更新resolution,结果机器人定位全乱了。记住,图片变了,元信息也得跟着变。
3.3.4 地图的坐标系对齐
地图建好后,最重要的一步是确认坐标系对齐。
ROS2里地图坐标系是固定的:
- X轴:向右
- Y轴:向上
- Z轴:朝向屏幕外(右手系)
YAML里的origin就是地图左下角在这个坐标系下的位置。如果你的地图原点不在(0,0),记得在origin里填对。
我习惯把地图原点设在机器人起始位置,这样调试起来方便。当然,你也可以设在房间角落,看个人喜好。
3.4 实战建议
最后给几个实战中的小建议:
- 分辨率别太高:0.05米够用了,0.01米的地图文件大得吓人
- 地图别太大:超过100米×100米的地图,导航性能会下降
- 定期更新:环境变了就重新建图,别死用旧地图
- 备份YAML:图片丢了还能重画,YAML丢了地图就废了
好了,地图基础就聊到这儿。下一章咱们讲怎么用map_server加载地图,以及怎么在Rviz里可视化。到时候我会演示一个完整的流程,从加载地图到机器人定位,一步到位。