第 5.14 节

map_server(已有二维地图加载与发布)

作者:董佳辉

map_server(已有二维地图加载与发布)

实车先看:空路径由谁填写,读的是哪一张地图

map_server读取已有二维地图的YAML及配套图片,发布OccupancyGrid给静态代价层;当前工程通过launch的map参数填写yaml_filename。 因此这里的空字符串是启动时重写的占位值,不能单看这行就判断没有地图。

实物/仿真入口:map启动参数
    → bringup_launch → localization_launch
    → 重写map_server.ros__parameters.yaml_filename
    → map_server:读取地图YAML → 找到配套PGM/PNG → 转为二维占用网格
    → 配置、激活生命周期节点 → 发布namespace/map
    → local_costmap、global_costmap中的static_layer

prior_pcd_file → small_gicp:用实时三维点云匹配先验PCD,提供定位TF

二维图加载与三维PCD定位是不同的输入链。map_server不读取PCD,不把当前雷达点云拿去匹配二维图片,也不自行产生map→odom定位变换。两种地图仍须采用一致的尺度、方向和坐标约定。二维图与PCD的分工、先验点云定位

实车上看到的现象先核对什么当前配置怎样理解
YAML路径为空,却能够加载地图launch传入的map及有效yaml_filename当前重写流程会替换已有空值;实际路径来自启动参数
修改nav2_params.yaml中的路径,启动后仍用旧图上层map启动参数当前launch总会用map值重写该键;单改参数文件中的字符串可能被覆盖
实物入口默认启动失败,提示找不到地图实物默认地图文件是否存在当前默认map/reality/rmul_2024.yaml在源码和安装目录均不存在,需提供自己的有效二维图
节点启动了,/map却没有地图消息最终路径、文件读取及生命周期状态有节点/发布器不等于已经加载并激活地图;空路径可以配置,但不会自动产生地图
建图时没看到map_serverslam启动分支slam=True使用slam_toolbox发布/map;此节点在slam=False的定位分支启动
图片看起来灰色,加载后却成了空闲地图文件的mode、free_thresh与像素灰度保存和读取的门槛不是同一计算;本版本三态灰205与0.25的组合有已验证的未知状态丢失问题

本次安装的nav2_map_server为1.1.20,安装的map_server/map_io头文件与该版本一致。以下按此版本及当前工程启动文件说明。MapServer实现

参数

保留发送的参数与上方原注释。注释中的tb3_simulation_launch.py是通用示例名称;当前工程实际使用rm_navigation_reality_launch.py、rm_navigation_simulation_launch.py、bringup_launch.py和localization_launch.py。

# The yaml_filename does not need to be specified since it going to be set by defaults in launch.
# If you'd rather set it in the yaml, remove the default "map" value in the tb3_simulation_launch.py
# file & provide full path to map below. If CLI map configuration or launch default is provided, that will be used.
map_server:
  ros__parameters:
    yaml_filename: ""

ros__parameters(地图文件入口)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
yaml_filename"";整套启动时由map参数重写不适用,地图YAML文件路径字符串上实物前必须核对并正确配置指定初始加载的二维地图元数据文件不适用不适用当前可保留空值占位,通过map:=实际绝对路径配置;文件与图片均需存在;直接启动并留空则不加载初始地图
参数详解
yaml_filename(节点参数文件与地图文件是两种YAML)

nav2_params.yaml是ROS节点参数文件,里面有map_server、map_saver、costmap等参数分组。yaml_filename指向的是一张二维地图的元数据YAML,其中写image、resolution、origin等;不能把它设成nav2_params.yaml本身,也不能直接指向PGM、PNG或PCD。

1.1.20在configure阶段读取yaml_filename。非空时读取地图YAML和图片,失败会使配置过程失败;空字符串则跳过初始加载,建立话题与服务,允许之后通过load_map服务装入地图。空字符串不表示自动建图、不表示读取当前目录的某张图,也不表示使用PCD替代二维图。初始加载与空路径分支

当前安装的RewrittenYaml只替换已有叶子键,bare key形式的yaml_filename重写不会自动补入缺失键。保留yaml_filename这一行,空值可交给launch填写;不能按注释把整个键删掉。 MapServer源码声明的是字符串类型而不是一个自动场地路径默认值,路径默认来自工程launch。1.1.20参数重写

当前launch怎样决定最终地图
启动位置map参数来源对yaml_filename的作用
rm_navigation_reality_launch.py用户map:=路径;未指定时按world生成share/map/reality/场地名.yaml传给bringup;当前world缺省rmul_2024
rm_navigation_simulation_launch.py用户map:=路径;未指定时按world生成share/map/simulation/场地名.yaml传给bringup;当前world缺省rmuc_2025
bringup_launch.py接收上层map用RewrittenYaml重写已有yaml_filename,再传给定位分支
localization_launch.py接收map,单独启动时此参数无默认值再用map重写yaml_filename,独立进程与组件两种分支均加载结果
直接启动map_server并提供节点参数用户传入yaml_filename未经过上述重写时,直接使用节点得到的值;生命周期另需配置和激活

当前整套启动以map启动参数为准。 想改用自己的地图,优先明确传map:=地图YAML的绝对路径;修改nav2_params.yaml中的值并不能阻止两处重写。若要改成完全由节点参数文件决定,必须调整当前bringup与localization的重写逻辑,并核对上层必需参数;不是只去修改注释提到的TB3文件。本文只记录接线,没有修改启动文件。

实际重写位置见bringup_launch.py、localization_launch.py。

本次默认文件检查(实物默认图尚未提供)

当前安装包share目录为:

/home/tungchiahui/UserFolder/MySource/ysu2026_rm_sentry/ysu2026_rm_sentry_nav/install/pb2025_nav_bringup/share/pb2025_nav_bringup
默认入口默认相对share目录的路径本次静态检查
实物,world=rmul_2024map/reality/rmul_2024.yaml源码和安装副本均没有该文件;当前源码map/reality仅有reserve占位文件
仿真,world=rmuc_2025map/simulation/rmuc_2025.yaml源码和安装副本均存在,配套rmuc_2025.pgm也存在

这是对当前这份工作空间和默认入口的文件检查,不表示其他工作空间没有实物图,也不表示用户曾经指定的map路径失败。使用自己建的二维图时,还要给prior_pcd_file选择与之坐标一致的PCD,不能只让两份文件名看起来相同。

当前仿真默认地图元数据为:

image: rmuc_2025.pgm
mode: trinary
resolution: 0.05
origin: [-3.58, -9.44, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25

这里只引用已有地图文件说明格式,不是map_server的额外ROS参数。原文件见rmuc_2025.yaml。

地图元数据(图片如何变成真实坐标和占用值)
地图文件字段单位/含义当前应怎样核对
image配套图片路径相对路径按地图YAML所在目录解析;搬移时需同时保留图片,不能只复制YAML
resolutionm/图片像素决定真实平面格距;此例5 cm,不是定位精度;修改它会改变整图物理尺度
originx米、y米、yaw弧度第三个数是绕z的偏航角,不是z高度;载入的二维原点z设为0
negate0/1,像素明暗是否反转此例0:深色表示较高占用;不是把地图坐标轴反转
modetrinary/scale/rawtrinary按阈值输出0、100、-1;scale还表达中间值;raw按像素数直接解释,不能随意换模式后继续按普通黑白图理解
free_thresh、occupied_thresh无量纲,像素换算后的占用门槛加载时读的是本地图文件的值,不读取map_saver节点的default门槛

普通无透明通道灰度图、negate=0、trinary时,令灰度g为0~255,则占用比例为1−g/255;严格大于occupied_thresh设100,严格小于free_thresh设0,其余设-1。保存时对输入0~100占用值采用另一套包含边界的比较,不能把两种门槛比较混写。元数据解析与像素加载

本版本默认三态保存的未知灰205重新读取时,1−205/255≈0.19608,小于0.25,会变成空闲0。 本次已直接用安装的libmap_io在临时文件中验证:输入未知-1,用trinary、0.25/0.65保存再读取得到0;free改0.196后该未知格仍为-1。这个问题只针对满足上述读写条件的图片,不能据此断言所有来源的地图都丢未知。完整阈值条件、验证数据和处理建议见map_saver。

与global_costmap和三维定位的几何关系

前面global_costmap默认不滚动,StaticLayer会按/map元数据调整主图尺寸、格距和平面原点;这里加载哪张图,直接决定它的有效网格,而不是由costmap中的初始0.05独立决定。全局图的尺寸接管

MapServer把origin第三个数写入地图四元数,但当前Nav2 1.1.20的StaticLayer平面网格主要使用origin.position.x/y与格距,非滚动合成按同格索引,不按任意origin yaw重新旋转网格。当前示例yaw=0;若将地图YAML改为非零yaw,应单独核对消费者,不能认为所有节点都会自动正确旋转。静态层网格建立

frame_id只是消息坐标系名称。给图片改原点、旋转、裁剪或重采样后,需同时考虑PCD定位和map↔odom;仅把frame_id写成map不证明实际对齐。

相关源码默认项(原YAML未显式配置)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
topic_namemap,MapServer默认不适用,话题名称上实物前必须核对并正确配置选择完整OccupancyGrid发布话题不适用不适用相对名称按节点namespace解析;例如/red_standard_robot1/map;需与两张costmap的static_layer输入一致
frame_idmap,MapServer默认不适用,坐标系名称上实物前必须核对并正确配置设置地图消息header.frame_id不适用不适用不创建TF、不变换图片或原点;当前应与全局网格、PCD定位约定一致
use_sim_time原分组未写;标准ROS默认False不适用,布尔上实物前必须核对并正确配置决定MapServer填写加载时间和消息时间戳时使用的时钟不适用不适用当前bare-key重写只改已有键,没有给本分组补入此键;仿真不能只凭入口True推断本节点也True,外部覆盖需另查

两份节点参数文件的map_server段完全一致,均只有yaml_filename空字符串。当前默认接线未在此分组补入use_sim_time;在没有其他覆盖时标准默认为False,仿真入口传True不会经该重写自动补到这里。此结论来自参数及启动源码,未对运行节点取快照;需要统一时间域时应显式配置,再检查有效参数。加载后的时间戳

生命周期、换图与验证范围

发布与服务

MapServer是生命周期节点。configure时加载初始图并建立服务/发布器;activate时发布已加载完整图。当前localization_launch的lifecycle_manager_localization管理map_server,autostart=True时自动配置、激活;单独运行可执行程序不能只停在“进程已创建”。

完整地图使用Transient Local、Reliable、KeepLast(1),保留最近一张图供兼容的晚加入订阅者读取。它不是周期性重读磁盘或定时发布新地图;原文件改了不会自动热更新。地图发布与激活

接口默认名称,带机器人namespace时示例行为
完整地图话题/red_standard_robot1/map初始激活有图时发布;成功load_map后发布新图;保留最近完整图
GetMap服务/red_standard_robot1/map_server/map返回当前内存OccupancyGrid;Active状态才处理;Active但尚未加载图时不能当作已有有效地图
LoadMap服务/red_standard_robot1/map_server/load_map请求map_url加载地图YAML;Active状态才处理,成功后更新内存并发布新图

当前MapServer没有为yaml_filename、topic_name、frame_id建立运行中重读/重建的参数回调。参数设置成功不代表换图成功;换图应走LoadMap服务或重新配置/重启。服务加载成功也不自动更换small_gicp的目标PCD,切换场地时还要同步定位目标与坐标约定。服务加载

本次核对与后续实物检查
  • 本次已核对: nav2_map_server 1.1.20及安装头文件;两套节点参数与安装副本一致;五份相关launch与安装副本一致;实际map重写接线;实物默认地图缺失、仿真默认YAML/图片存在。
  • 本次离线验证: 在临时目录直接调用已安装地图IO库完成小地图保存/读取,确认trinary灰205、free=0.25会丢未知身份,0.196的对应例子保留;未启动ROS地图节点、话题或服务,未写入工程地图目录。
  • 源码能确认: 空路径分支、configure/activate行为、完整图QoS、Active服务条件、相对图片路径解析、地图元数据含义,以及参数重写与运行中换图的边界。
  • 实物待核实: 启动时实际map与有效yaml_filename、二维图/PCD对齐、图中未知区域保存和重新加载、时间域、生命周期状态及静态层的有效地图元数据;本次未运行整套导航或进行实车验证。