3. 地图基础:地图的表示方式、文件格式与坐标系

聊到导航,地图就是机器人的「眼睛」。没有地图,机器人就是个盲人。

我记得刚接触ROS时,第一件事就是折腾地图。那时候我天真地以为地图就是一张图片,后来才发现,这里面的门道还挺深。今天我们就把它彻底讲透。

3.1 占用网格:地图的「像素」思维

机器人用的地图,和我们手机里的导航地图不一样。它叫占用网格地图(Occupancy Grid Map)。

说白了,就是把真实世界切成一个个小格子。每个格子记录一个数字:

  • 0:空闲(Free),机器人可以走
  • 100:占用(Occupied),有障碍物,不能走
  • -1:未知(Unknown),还没探测到

你想想看,这多直观。每个格子就是一个像素,整张地图就是一张灰度图。白色是空地,黑色是墙,灰色是未知区域。

核心概念:占用网格地图的本质,是一个二维数组。数组的每个元素,代表对应物理位置被障碍物占据的概率。

我在项目中遇到过一个问题:地图分辨率设得太高(比如1cm/像素),结果建图时内存直接爆了。后来我学乖了,室内导航用5cm/像素就够用,室外甚至可以用10-20cm/像素。

3.2 地图文件格式:pgm + yaml 的组合拳

ROS2/Nav2 使用的地图文件,通常是两个文件配合使用:.pgm 和 .yaml。

3.2.1 PGM 文件:图像数据

PGM 是一种简单的灰度图像格式。每个像素的值就是占用概率。0是黑色(占用),255是白色(空闲)。

举个例子,一个 10x10 的地图,PGM 文件内容大概长这样:

P5
# 地图注释,可以忽略
10 10
255
...二进制像素数据...

嗯,这里要注意:PGM 有两种模式——ASCII 和二进制。Nav2 通常用二进制模式,文件更小,加载更快。

3.2.2 YAML 文件:地图的「身份证」

YAML 文件描述了地图的元信息。没有它,PGM 就是一张普通的图片。

image: map.pgm        # 地图图片文件路径
resolution: 0.05      # 每个像素代表的物理尺寸(米/像素)
origin: [-10.0, -10.0, 0.0]  # 地图左下角在世界坐标系中的位置 (x, y, yaw)
occupied_thresh: 0.65 # 占用阈值,高于此值视为障碍物
free_thresh: 0.196    # 空闲阈值,低于此值视为空闲
negate: 0             # 是否反转像素值(0表示不反转)

我刚开始用 Nav2 时,踩过一个坑:origin 参数写错了。结果机器人一启动,就认为自己在地图外面,死活不肯走。后来我养成了习惯,每次加载地图前,先用 map_server 的 map_saver 工具检查一下原点坐标。

避坑指南:occupied_thresh 和 free_thresh 的默认值分别是 0.65 和 0.196。如果你发现地图上明明有墙,但导航规划路径时直接穿墙而过,很可能是这两个阈值设置不合理。我曾经遇到过这种情况,把 occupied_thresh 降到 0.5 就解决了。

3.3 地图坐标系与TF树

地图有了,但机器人怎么知道自己在地图上的哪个位置?这就涉及到坐标系了。

3.3.1 三个核心坐标系

在 Nav2 中,我们主要关心三个坐标系:

  • map:世界坐标系,固定不变。地图的原点就在这里。
  • odom:里程计坐标系,随着机器人移动而漂移。它是局部参考系。
  • base_link:机器人本体坐标系,原点在机器人中心。

它们之间的关系,通过 TF 树来维护。说白了,TF 树就是坐标系之间的「翻译官」。

3.3.2 TF 树的结构

一个典型的 TF 树长这样:

map
  └── odom
        └── base_link
              ├── laser_frame
              └── camera_frame

为什么要有 odom 这个中间层?

因为里程计会累积误差。如果直接把 map 连到 base_link,一旦定位出问题,整个树就乱了。加一层 odom,相当于给定位误差一个缓冲。

个人经验:调试导航时,我经常用 tf2_echo map base_link 命令查看当前坐标变换。如果发现 x/y 值突然跳变,说明定位有问题。这时候别急着调参数,先检查 TF 树是否完整。

3.4 知识体系结构图

下面这张图,帮你理清本章的核心逻辑:

地图基础:知识体系 占用网格地图 地图文件格式 坐标系与TF树 存储为 定位需要 0=空闲, 100=占用, -1=未知 .pgm .yaml map → odom → base_link 三者关系 占用网格地图 → 保存为 .pgm + .yaml → 通过 TF 树与机器人坐标系关联

3.5 实战:如何检查一张地图

学完理论,我们来点实际的。拿到一张地图,怎么快速验证它是否可用?

  1. 检查文件完整性:确保 .pgm 和 .yaml 都在同一目录下。
  2. 查看 YAML 参数:用 cat map.yaml 确认 origin 和 resolution 是否合理。
  3. 可视化地图:用 map_server 加载地图,然后在 RViz2 中查看。
  4. 检查 TF 树:运行 ros2 run tf2_tools view_frames 生成 TF 树 PDF。

小技巧:我习惯在 map.yaml 里加一行注释,记录地图的创建时间和使用场景。比如 # 2024-03-15 实验室二楼走廊。时间久了,你会感谢这个习惯的。

好了,地图基础就讲到这里。记住一句话:地图是导航的基石,坐标系是导航的骨架。这两样搞明白了,后面的路径规划、避障什么的,都是锦上添花。