第 5.13 节

global_costmap(全局规划代价地图)

作者:董佳辉

global_costmap(全局规划代价地图)

实车先看:整张地图和车周围的实时障碍怎样一起参与规划

当前全局代价地图在map中表达,默认不滚动;接收静态二维地图后,整张网格的尺寸、分辨率与平面原点由静态地图决定。 它先铺静态图,再加入terrain_map_ext筛出的障碍,最后膨胀,供planner_server中的Theta*规划器选择全局路径。

map_server/slam_toolbox的/map → static_layer ───────────────────────┐
    └─ 地图宽高、分辨率、平面原点 → 调整并锁定全局网格              │
                                                                  │
terrain_map_ext(odom系,intensity为地形高差)                       │
    → 按消息时间转到map,并取得front_mid360原点                     │
    → 来源高度、本层高度、高差、三维量程、体素筛选                  │
    → intensity_voxel_layer:加入符合条件的障碍 ────────────────────┤
                                                                  ↓
                                      inflation_layer → 全局合成代价地图
                                                       ├─ Theta*直接读内存规划
                                                       ├─ get_costmap服务提供当前图
                                                       └─ costmap/updates/raw供订阅者

全局图可以覆盖整个静态地图,但本实时障碍来源只保留距雷达严格0.2~10 m之间、又落在地图和高度窗口内的有效点。10 m不是整张地图的宽度,也不保证10 m内每处都已被观测。上游扩展地形当前在4 m内借用近场结果,4 m外使用自己的远场结果,两部分都从这里进入全局障碍层。扩展地形分析

实车上看到的现象先核对什么当前配置怎样理解
YAML写5 cm,显示/服务中的格距却不同/map的info.resolution与实际costmap元数据非滚动static_layer会按完整地图重建全局网格;YAML值不保证是最终格距
以为全局图也是5×5 m随车移动rolling_window缺省值与静态地图当前缺省False,网格覆盖和原点随静态地图确定,不围绕车滚动
开了未知区域记录,路径仍经过灰色区域顶层track_unknown_space与规划器allow_unknown实物顶层True保留255未知状态;当前Theta*缺省allow_unknown=True,仍可能规划经过
仿真和实物对未探索区域表现不同两份YAML的顶层未知开关仿真缺少顶层键,实际缺省False;层内同名True没有被读取
0.9 m处的障碍有地形点却没进入此层转到map后的z及体素范围两级0~2 m高度过滤之外,当前体素标记范围只有map中的[0,0.8) m
局部有障碍,全局却没有,或反过来输入、TF、高度窗口和两张地图局部用terrain_map与odom;全局用terrain_map_ext与map,同一组高度数值不保证选中同一批点
增大cost_scaling_factor后路径反而更贴墙膨胀衰减公式与Theta*路径评分数值越大,外围软代价降得越快;当前全局规划器实际使用这些代价
清全局图后障碍很快回来静态图、最后观测与上游历史点整图服务会重置本层,但不会删除静态墙或terrain_map_ext的历史观测内容

本次容器内nav2_costmap_2d、nav2_voxel_grid、nav2_planner、nav2_theta_star_planner均为1.1.20,pb_nav2_plugins为1.0.1。自定义层实现与头文件和上游提交e6778ca44d9e88aa612a3c6c87d536a8cfa21705一致;Theta*安装头文件也与1.1.20一致。以下按这些版本解释,通用Humble笔记用来对照术语;自定义层的实际使用条件以源码为准。自定义层实现、类与体素索引

参数

下面保留发送的完整38项参数与原注释。当前源码及安装副本的reality段均与此配置一致;simulation段除use_sim_time=True外,还缺少顶层track_unknown_space,不是只差时钟。

global_costmap:
  global_costmap:
    ros__parameters:
      use_sim_time: False
      update_frequency: 5.0
      publish_frequency: 2.0
      global_frame: map
      robot_base_frame: gimbal_yaw_fake
      robot_radius: 0.2
      resolution: 0.05
      track_unknown_space: true
      plugins: ["static_layer", "intensity_voxel_layer", "inflation_layer"]
      intensity_voxel_layer:
        plugin: pb_nav2_costmap_2d::IntensityVoxelLayer
        enabled: true
        track_unknown_space: true
        footprint_clearing_enabled: true
        publish_voxel_map: false
        combination_method: 1
        mark_threshold: 0
        origin_z: 0.0
        unknown_threshold: 5
        z_resolution: 0.05
        z_voxels: 16
        min_obstacle_height: 0.0
        max_obstacle_height: 2.0
        min_obstacle_intensity: 0.1
        max_obstacle_intensity: 2.0
        observation_sources: terrain_map_ext
        terrain_map_ext:
          data_type: PointCloud2
          # '<robot_namespace>' keyword shall be replaced with 'namespace' where user defined.
          # It doesn't need to start with '/'
          topic: <robot_namespace>/terrain_map_ext
          sensor_frame: front_mid360
          min_obstacle_height: 0.0
          max_obstacle_height: 2.0
          obstacle_max_range: 10.0
          obstacle_min_range: 0.2
      static_layer:
        plugin: "nav2_costmap_2d::StaticLayer"
        map_subscribe_transient_local: True
      inflation_layer:
        plugin: "nav2_costmap_2d::InflationLayer"
        cost_scaling_factor: 4.0
        inflation_radius: 0.7
      always_send_full_costmap: False

两个global_costmap层级用于匹配命名空间和节点名。当前planner_server内部创建此地图节点;机器人namespace为/red_standard_robot1时,其全名为/red_standard_robot1/global_costmap/global_costmap,相关地图话题通常在/red_standard_robot1/global_costmap下。坐标系字符串map、gimbal_yaw_fake、front_mid360不会随节点namespace自动加前缀。全局地图节点创建

ros__parameters(更新、坐标、轮廓与未知区域)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
use_sim_timeFalse;仿真True不适用,布尔上实物前必须核对并正确配置选择ROS时钟,供TF、消息和发布判断使用不适用不适用工程launch还会重写;需与地形点和TF同一时间域,内部更新循环使用WallRate
update_frequency5.0Hz,目标更新频率实物运行时重点观察,有问题再针对性调整控制内部三层地图合成循环,目标200 ms/轮理想情况下更快更新实时障碍,计算和锁竞争增加内部障碍变化响应可能更迟不等于BT规划请求频率,也不提高雷达/地形输入频率;当前动态回调不重建此线程节拍
publish_frequency2.0Hz,目标发布频率通常保持当前值,不作为优先调试项控制地图话题的发布时间门槛订阅者可能更及时,发布负担增多显示/订阅更新更稀判断在5 Hz更新循环内,实际不保证独立精确2 Hz;Theta*读内存地图,服务也不等待下次话题发布
global_framemap不适用,坐标系名称上实物前必须核对并正确配置设置全局网格及地形观测的参考系不适用不适用当前非滚动静态层按相同格索引合成,要求与/map.header.frame_id的坐标约定一致;高度也按map中的z筛选
robot_base_framegimbal_yaw_fake不适用,坐标系名称上实物前必须核对并正确配置取得机器人在map中的位姿,并放置本图轮廓不适用不适用当前不滚动,位姿变化不会移动整图原点;仍影响轮廓清空和规划参考点,需正确map至此系的TF
robot_radius0.2m,未填充轮廓的圆半径上实物前必须核对并正确配置无显式footprint时生成圆形多边形轮廓车体占用与253膨胀内圈增大,通道可能受限占用减小,可能低估真实转动/横移包络当前还用默认约0.01 m padding;以虚拟系原点为中心,不等于雷达盲区或inflation_radius
resolution0.05;收图后以/map元数据为准m/平面格,初始5 cm上实物前必须核对并正确配置为初始化网格给出格距若最终地图格距也增大,格子更粗、计算通常减少若最终地图格距也减小,细节更细、格数和负担增加当前static_layer会重建并锁尺寸;单独改这个YAML值不保证有效网格改变,也不能据此断言全图格数
track_unknown_spacetrue,节点顶层不适用,布尔根据实际功能需求开启或设置让主图、障碍层默认格及静态图未知格保留未知表示不适用不适用此键实际被读取;True不等于禁止规划经过未知格,当前Theta*缺省allow_unknown=True;仿真缺省False
pluginsstatic_layer、intensity_voxel_layer、inflation_layer不适用,有序ID列表上实物前必须核对并正确配置加载并按顺序合成三层不适用不适用当前先静态、再实时障碍、最后膨胀;各ID对应下方plugin类名,换顺序会改变最终图
always_send_full_costmapFalse不适用,布尔根据实际功能需求开启或设置选择OccupancyGrid强制全图或条件增量发布不适用不适用False遇尺寸、格距或原点变化仍发全图;costmap_raw有订阅者时始终发完整原始代价图,不影响内存规划
参数详解
update_frequency与publish_frequency(内部5 Hz、话题2 Hz、规划请求各自运行)

内部更新循环以WallRate运行,目标每200 ms完成一次三层合成;更新时会锁地图,Theta*创建路径也锁同一张地图。增大更新频率需要看整图大小、点云处理、膨胀和规划耗时,不能只凭局部图10 Hz就照搬。

Theta*直接使用planner_server持有的Costmap2D对象;它不靠订阅2 Hz的OccupancyGrid取得地图。当前BackUpFreeSpace配置的global_costmap/get_costmap服务同样提供当前内存图。使用costmap_raw话题的其他消费者,则还受发布周期影响。

publish_frequency只是更新循环中的ROS时间门槛,理想500 ms发布间隔也会受200 ms循环采样和负载影响。若以2.5 m/s运动,理想200 ms内移动0.5 m;这是配置时间尺度计算,未包含感知、TF、规划、控制和执行延迟,也不是本次实测。更新/发布循环

BT中的RateController hz=3控制规划请求节奏,planner_server.expected_planner_frequency主要用于耗时检查,二者都不会把此5 Hz地图循环改成另一个频率。行为树调度

resolution与未配置的rolling_window(最终尺寸来自/map)

当前rolling_window未写,源码缺省False。初始化暂用缺省width=5 m、height=5 m、origin_x=origin_y=0和本块resolution=0.05;这组初始参数不是收到静态地图后的最终全局网格。

非滚动StaticLayer收到完整地图时,如果主图的宽高格数、分辨率、平面原点不匹配,或尚未锁定尺寸,就调用resizeMap并锁定尺寸,所有层随之matchSize。最终依据是:

全局x格数 = /map.info.width
全局y格数 = /map.info.height
全局平面格距 = /map.info.resolution
全局平面原点 = /map.info.origin.position.x、y
平面总格数 = width格数 × height格数

例如假设收到800×600、0.05 m/格的地图,全局覆盖40×30 m、共480000格;它不会缩成5×5 m。这仅说明换算,未读取当前运行/map,不能作为本次实际尺寸。

自定义体素层的x、y格数也跟随整张全局图,不只是为10 m量程单独分配一个局部窗口。每个平面列用32位打包高度状态;在固定物理覆盖下,把实际地图格距减半会使平面格数约4倍,也增加体素列、膨胀缓存和规划负担。

锁尺寸后,运行中设置resolution、width、height、origin_x/y可能改变ROS参数值及节点成员,但当前节点回调不会重新resize已锁地图。后续完整/map元数据改变仍可让StaticLayer重新调整。要核对有效尺寸,应看实际costmap消息/服务元数据及StaticLayer的Resizing日志,不能只看参数列表。地图重建与锁定、运行中尺寸回调

global_frame与robot_base_frame(同一张map中的点云、地图和机器人)

当前完整地图通常以map为header.frame_id,全局网格也选择map。1.1.20的StaticLayer在非滚动分支直接按对应格索引合成;只有滚动分支才查询地图坐标系与global_frame之间的TF并取样。因此不能把本块global_frame随意改为odom,再期待静态层自动重投影整图。非滚动与滚动合成分支

地形点云仍按自己的header.frame_id,经消息时间戳的TF转到map;机器人轮廓放在map中的gimbal_yaw_fake位姿上。应一起核对静态地图、先验定位和点云的坐标约定,以及map↔odom↔front_mid360/gimbal_yaw_fake链。话题名带机器人namespace不证明这些坐标系已经隔离或正确对齐。

robot_radius=0.2生成近似圆形多边形,再按默认footprint_padding约0.01 m填充。实现按顶点方向填充,最终内切半径不能简单等同于精确0.21 m圆。需测量虚拟原点到真实车体边界、云台和转动包络;局部与全局轮廓都应符合这套几何关系。轮廓生成与填充

如果改成矩形footprint,还须处理当前虚拟参考系抵消底盘yaw的设计:底盘固连矩形不会仅因填入顶点就自动按真实底盘方向转动。相关参考系关系见fake_vel_transform。

track_unknown_space(保留未知状态与是否允许规划经过是两件事)

实物顶层True让主图和障碍层以NO_INFORMATION=255为默认值,并让静态图未知像素保留255。已知空闲仍为0,墙仍为254;这不是把整张静态地图都设为未知。

当前planner_server.GridBased实际使用nav2_theta_star_planner/ThetaStarPlanner,未显式配置allow_unknown,1.1.20缺省True。常规搜索会允许未知格参与候选,同时给它较高的经过代价;因此未知区保留为灰色后,仍可能出现穿过它的路径。若任务要求禁止未知区,应单独核对规划器策略,不能用unknown_threshold=5实现。Theta*缺省allow_unknown、搜索中的未知格判断

当前仿真文件缺少顶层track_unknown_space,缺省False会把静态图未知值转为空闲,并让障碍层默认空闲。此时原来的未知身份已经丢掉,之后只把规划器allow_unknown改False也不能从0恢复它。需要一起明确地图保留未知的方式、膨胀怎样处理未知、规划器是否放行。

当前配置节点顶层值层内同名值实际未知表示
reality/global_costmapTrueTrue,但未读取主图/障碍层默认未知;静态未知像素保留255
simulation/global_costmap未写,默认FalseTrue,但未读取主图/障碍层默认空闲;静态未知像素转0
当前local_costmap,两套配置未写,默认FalseTrue,但未读取与全局实物图的未知策略不同

这些差异是配置与源码核对结果,未对运行节点做参数快照。切换到仿真时不要只检查use_sim_time;是否统一未知策略取决于任务,本文保留原YAML并记录差异。真正读取顶层键、静态未知像素解释

intensity_voxel_layer(扩展地形障碍的筛选与合成)

参数表(工作方式)
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
pluginpb_nav2_costmap_2d::IntensityVoxelLayer不适用,类名上实物前必须核对并正确配置加载按地形intensity筛点的自定义层不适用不适用继承ObstacleLayer,另建体素网格;不是标准VoxelLayer,不能直接套其射线清空和未知列逻辑
enabledtrue不适用,布尔通常保持当前值,不作为优先调试项是否标记并合成本层实时障碍不适用不适用False不关闭静态图与膨胀,也不自动停止所有输入订阅;只靠静态图仍可能规划
track_unknown_spacetrue,层内键未读取不适用,布尔当前运行不使用这个参数,暂不调整当前层内同名设置没有使用路径不适用不适用实物真正生效的是前面的节点顶层True;此处冗余,不能靠它让仿真开启未知记录
footprint_clearing_enabledtrue不适用,布尔通常保持当前值,不作为优先调试项将本层二维轮廓内代价设为空闲不适用不适用不直接清体素位;当前Max合成不会擦掉静态墙,但可将静态未知格中的本层已知轮廓区写为空闲
publish_voxel_mapfalse不适用,布尔根据实际功能需求开启或设置是否建立并发布voxel_grid调试话题不适用不适用发布整个体素网格便于核对map高度窗口,增加开销;不控制计算;当前无运行中重建发布器回调
combination_method1不适用,枚举通常保持当前值,不作为优先调试项选择本层与静态结果的合成方法不适用不适用1为Max;0为Overwrite;本版本其他整数没有对应合成分支,不套用新版枚举2的说明
unknown_threshold5计数;当前未参与未知列计算当前运行不使用这个参数,暂不调整初始化声明并保存未知体素门槛当前无计算效果当前无计算效果保存5+(16−16)=5,后续没有读取它统计未知列或清线;不能用它控制Theta*放行未知格
observation_sourcesterrain_map_ext不适用,空白分隔的来源ID字符串上实物前必须核对并正确配置建立下方来源分组的缓冲与订阅不适用不适用ID用于找参数分组,实际输入由其topic决定;多来源需空白分隔并逐个配置
参数表(体素、高度与地形高差)
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
mark_threshold0每个平面列的已标记高度格数量门槛实物运行时重点观察,有问题再针对性调整占用高度格数严格超过门槛时标成二维障碍要更多不同高度格才能标记,可能减噪也漏薄/低障碍更少高度格即可标记;当前0已是一格就够不是同一格内的点数;重复很多点仍只算一个高度格;门槛应小于有效层数
origin_z0.0m,map中的体素下界上实物前必须核对并正确配置设置垂直体素窗口起点窗口整体上移窗口整体下移不随车升降;通过高度过滤但低于它的点会压到最底格;本自定义缺省16.0 m,不能按标准默认随意省略显式0
z_resolution0.05m/高度格,5 cm上实物前必须核对并正确配置决定每个高度格厚度固定层数时覆盖更高,垂直表达更粗覆盖更矮、表达更细,高处点更易越界应为有限正值;当前16×0.05=0.8 m;独立于从静态图取得的平面格距
z_voxels16高度格数通常保持当前值,不作为优先调试项设置垂直格数合法范围内覆盖更高;当前已达16上限垂直覆盖变小,高处点更易越界当前库最多16层,不能直接设40层覆盖2 m;每列打包内存不会随层数同比缩小
min_obstacle_height0.0m,map中点z的本层下界上实物前必须核对并正确配置本层删除z低于0的点删除更多低处/下坡点接纳更低点,但仍受来源过滤与体素范围限制两级下界都为0,边界可通过;不是点离局部地面的高差
max_obstacle_height2.0m,map中点z的本层上界上实物前必须核对并正确配置本层删除z高于2 m的点前置窗口变宽,不会扩展0.8 m体素窗口降到有效体素窗口内才进一步裁掉当前可标记点2 m不是最终有效标记高度;z≥0.8 m仍会因体素越界被删
min_obstacle_intensity0.1m,当前地形高差下界实物运行时重点观察,有问题再针对性调整高差至少10 cm才进入标记忽略更多小高差,可能减轻误判也漏低障碍接纳更多低障碍、地面噪声与坡面误差当前不是雷达反射强度;0.1边界可通过;上游远场高差取绝对值,低侧也可能过门槛
max_obstacle_intensity2.0m,当前地形高差上界通常保持当前值,不作为优先调试项删除高差超过2 m的点接纳更多大高差删掉更多大高差近场借入点受0.5 m上游限制,自算远场受1.0 m限制;正常输出通常不被2 m再裁剪,但代码确实执行此筛选
参数详解
map中的z、上游高差与体素覆盖(三个不同概念)

ObservationBuffer先把terrain_map_ext从消息坐标系转到map,再按来源0~2 m筛z;本层再次按0~2 m筛z,同时按intensity=0.1~2 m筛地形高差。通过这些门槛之后,还需满足三维量程、平面地图边界、垂直格索引和mark_threshold。

高度窗口用的是map中的点z;intensity沿用上游计算的地形高差。 TF改变XYZ,不会把intensity重算成map地面高差。地形点并未被压平到地面上。

当前高度格索引为floor((z_map−0)/0.05),要求0≤索引<16;两级高度下界又排除了负z,因此有效标记区间为map中的[0,0.8) m。z=0.8对应索引16,越界。网格不会随底盘爬坡自动向上移动,map的z=0也不能仅凭名称认定就是每处实际地面。

假定点已满足量程与平面位置地形高差当前筛选结果
z_map=0.2 m0.15 m高度、高差与体素都通过,可标记
z_map=0.2 m0.05 m高差不足10 cm,被删
z_map=0.9 m0.15 m通过0~2 m过滤,但体素越界,不能标记
z_map=-0.1 m0.15 m来源高度过滤已删除

局部使用odom中的[0,0.8),全局使用map中的[0,0.8)。只有map←odom变换保持相同z且不混合竖直方向时,这两个窗口才选中相同高度。若有z平移或roll/pitch修正,同一个odom点转入map后的z可能不同;定位修正也可能让地图上的实时障碍位置变化。

例如假设odom点z=0.6 m、map←odom只有z平移+0.3 m,则全局看到z_map=0.9 m并丢掉,而局部仍可能标记。这只是坐标换算例子,未测得当前TF偏移。实车应先核对静态图对齐、地面高度基准和定位变换,再决定怎样共同配置两级高度、origin_z与z_resolution;只把max_obstacle_height从2调到3无效。实际筛点、体素换算

min_obstacle_intensity(10 cm高差并不等于可通过台阶)

当前4 m内借入近场terrain_map,远处自己计算abs(点高度−估计地面高度)。远场的较高侧和较低侧都可能出现0.15 m高差,满足其他窗口时都可成为障碍;正常坡面也可能因分片地面估计而过门槛。4 m交接处还存在两套上游网格、点密度和高度规则的差异。近远场交接及绝对高差

0.1只决定高差筛选下界,不是车辆可跨10 cm或可爬某坡度的结论。先看地面估计和真实障碍回波,再结合车辆能力调整;提高门槛可能放掉需要避让的低矮物。

上游当前正常近场高差不足0.5 m,自算远场不足1.0 m,所以本层2.0 m高差上限通常不会进一步裁剪正常输出。若换输入或改上游规则,就要重新解释。接原始雷达点云时intensity可能是反射强度,不能沿用此处的米单位。

mark_threshold与unknown_threshold(已标记高度格和未使用成员)

mark_threshold按一个平面列中不同高度格的占用数量判断,严格超过门槛才标二维障碍。当前0表示1个高度格就够,1表示至少2格,2表示至少3格;同一高度格里有100个点也只算1格。每轮体素重置后重新计数,不靠多个更新周期累计凑数;最新地形点云自身仍可能包含历史点。VoxelGrid标记计数

unknown_threshold在初始化保存为5+(16−z_voxels),当前为5;本自定义实现后续没有使用它计算未知列、清射线或投影二维未知状态。调这个值不会改变当前未知区域,也不会改变规划器的allow_unknown。它与节点顶层track_unknown_space的使用路径不同。

层内track_unknown_space=True同样没有被父类读取;实物已有有效的顶层True,所以本块是冗余键,不能照搬局部那块“缺少顶层设置”的结论。即使顶层True,本层也不会自动获得标准VoxelLayer的射线空闲推断。自定义初始化与更新

combination_method与footprint_clearing_enabled(实时障碍如何加到静态图)

当前1为Max,但不是简单把255当最大数:本层自身未知格被跳过;主图原来未知、本层为已知时会写入本层值;两者都是已知则取较大代价。当前合成顺序和默认use_maximum=False使静态层先写静态结果,之后本层叠加实时障碍。Max的未知格处理

static_layer当前结果本层当前结果Max合成后,膨胀前
0,已知空闲254,实时障碍254
254,静态墙0,轮廓内空闲254,不擦静态墙
0,已知空闲255,本层未标记0
255,静态未知255,本层未标记255
255,静态未知0,轮廓内空闲0
255,静态未知254,实时障碍254

本层每轮resetMaps重建,不是把本轮10 m范围外全部判成空闲。顶层True时,未标记区域默认未知;合成会跳过这些未知格,原静态图仍起作用。没有点或者点被过滤,不能由此证明区域可通行。

轮廓清空仅将本层二维多边形内设0,不清体素位,也不通过Max降低静态墙。错误或过大的轮廓可能删掉本层车旁真实障碍;在静态未知区还会写出局部已知空闲,需按实际几何核对。

每轮重建、旧观测与清全局图服务

自定义updateBounds每轮先重置自身二维图和体素,再取标记观测重新标记。它不调用getClearingObservations或raytraceFreespace,直接把来源clearing设True不会补上射线清空。默认observation_persistence=0只留最后一份观测,最后一份并不会立即过期;expected_update_rate=0也不检查停更。

所以动态障碍残留可能来自最新terrain_map_ext中的历史点、最后一份停更观测或静态地图,而不是简单由“全局图不滚动”导致。主图按各层提供的更新边界重新合成,膨胀层还会扩展到上一轮边界;本层重置整张内部图不意味着每轮都完整发布或重写整张合成图。合成更新边界、膨胀更新边界

本类isClearable=False使ClearAround/ClearExcept等区域清理跳过它;但BT所用ClearEntireCostmap对应整图服务,会resetLayers并调用所有层reset,包含本层。重置不删除上游地形缓存,也不把最后观测彻底丢弃,下一轮相同内容仍可重建障碍;静态墙也会重新铺回。区域/整图清理、整图重置

intensity_voxel_layer.terrain_map_ext(观测来源)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
data_typePointCloud2不适用,消息类型名称上实物前必须核对并正确配置建立点云订阅与观测缓冲不适用不适用自定义迭代器需要float XYZ和intensity字段;父类支持LaserScan不代表换成扫描仍满足本层字段要求
topic<robot_namespace>/terrain_map_ext不适用,话题名称上实物前必须核对并正确配置指定扩展地形点云输入不适用不适用bringup展开占位符;通常/red_standard_robot1/terrain_map_ext;原字符串不会被本层自行替换
sensor_framefront_mid360不适用,传感器原点系名称上实物前必须核对并正确配置获取量程筛选所用的雷达原点不适用不适用按点云时间戳查此系到map;点坐标按消息header.frame_id转换,不被重新解释为雷达系点
min_obstacle_height0.0m,map中点z的来源下界上实物前必须核对并正确配置缓冲阶段先删除z低于0的点提前删更多低处/下坡点允许更低点进入后续筛选与本层同名键属独立阶段;只改本层下界不能恢复这里已删点;边界可通过
max_obstacle_height2.0m,map中点z的来源上界上实物前必须核对并正确配置缓冲阶段先删除z高于2 m的点来源窗口变宽,后续体素仍可越界缩窄来源窗口,可能漏高处障碍源码缺省0.0,不自动继承本层2 m;不能随意省略;当前最终仍受体素0.8 m限制
obstacle_max_range10.0m,距雷达原点的三维距离实物运行时重点观察,有问题再针对性调整删除距离达到/超过10 m的点接纳更远已有点,仍受上游和地图边界限制实时障碍参与范围缩小当前包含z,严格小于10 m才通过;不是静态地图范围或扩展节点4 m交接半径
obstacle_min_range0.2m,距雷达原点的三维距离上实物前必须核对并正确配置删除距雷达不超过0.2 m的点排掉更多近点,也可能漏近车障碍接纳更多近点,也可能包含自车回波当前使用≤下界删除;不是围绕gimbal_yaw_fake的robot_radius,也不能代替完整自车滤除
参数详解
topic、sensor_frame与TF(点在哪里,距离从哪里量)

工程bringup先用机器人namespace替换<robot_namespace>,再加载参数;绕过该启动流程时需完成替换。当前terrain_map_ext输出header.frame_id为odom;ObservationBuffer按消息时间把XYZ转到map,并按同一时间取得front_mid360原点在map中的位置,保留包括intensity在内的点字段。

sensor_frame决定量程原点,不覆盖消息header.frame_id。显式设置front_mid360后,消息过滤器还要求此系可变换。输入采用SensorDataQoS,父类队列深度50;有点云话题不证明本层缓冲已经成功接收,也不证明TF时间匹配。观测换系与原点

量程计算为sqrt((x−x_sensor)²+(y−y_sensor)²+(z−z_sensor)²),严格保留0.2<距离<10 m。相同刚体变换下距离保持不变,但变换后的绝对z可以改变;所以量程通过不证明map高度窗口通过。

10 m筛选也不能创造上游没输出的点,不能把地图外点写进网格,不能补回远处被地形高差上限删掉的障碍。近场/远场交接按上游输入位置的水平距离判断,此处量程按雷达原点的三维距离判断,两种边界不能混用。

static_layer(完整二维地图与网格几何)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
pluginnav2_costmap_2d::StaticLayer不适用,类名通常保持当前值,不作为优先调试项读取完整OccupancyGrid并铺入全局网格不适用不适用当前非滚动,静态图还决定整张网格几何;读取/map消息,不直接读PCD或图片文件
map_subscribe_transient_localTrue不适用,QoS耐久性选择上实物前必须核对并正确配置用Transient Local、Reliable、KeepLast(1)订阅完整地图不适用不适用发布端需兼容才能接到保留地图;不是保存地图到磁盘,也不是启用map_updates
参数详解

正常导航时完整图来自map_server,建图时来自slam_toolbox。缺省层私有map_topic为空,转用节点默认的机器人namespace/map,通常/red_standard_robot1/map。它不是global_costmap/costmap,更不是先验PCD直接输入。

当前默认trinary_costmap=True、lethal_cost_threshold=100、unknown_cost_value=255:OccupancyGrid的-1转成255后按顶层track_unknown_space保留未知或转空闲;已知值达到100为致命障碍,其余低于门槛的已知值按三态规则转为空闲。占用概率与膨胀后的内部软代价不是同一套数值。静态像素解释

当前use_maximum=False使非滚动静态层在更新区域先完整覆写静态结果,再由本实时层Max添加障碍;不要把本层combination_method=1误认为静态层也使用同一个参数。静态层自己的footprint_clearing_enabled缺省False,本块明确开启的是实时层的轮廓清空。

True的地图订阅QoS使晚启动的订阅者可取得兼容发布端保留的完整图。如果发布端耐久性或可靠性不兼容,应核对QoS;延长TF等待无法修复订阅不兼容。当前subscribe_to_updates=False不订阅map_topic加_updates的增量,但仍处理后来收到的完整/map;建图产生的新完整地图也可更新尺寸与内容。订阅QoS及更新话题

inflation_layer(全局路径的障碍距离代价)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
pluginnav2_costmap_2d::InflationLayer不适用,类名通常保持当前值,不作为优先调试项对已合成的静态墙和实时障碍建立距离代价不适用不适用位于最后一层;不能恢复被高度、量程或高差过滤掉的障碍
cost_scaling_factor4.0m⁻¹,指数衰减系数实物运行时重点观察,有问题再针对性调整控制内切轮廓之外软代价下降速度同样距离的外围代价更低,衰减更快,路径可能更贴近障碍外围代价更高、衰减更慢,通常更强地惩罚近障碍经过当前Theta*使用软代价;影响还取决于w_traversal_cost等,不改0.7 m范围或轮廓内切半径
inflation_radius0.7m,距致命障碍格的膨胀范围实物运行时重点观察,有问题再针对性调整决定多远仍写距离代价影响范围扩大、计算增加,可能更早绕离障碍影响范围缩小,外围路径代价减少仅有效格距确为0.05时约14格距;不是0.7 m全禁行,也不再加robot_radius成为0.9 m
参数详解
两项膨胀参数与当前Theta*(软代价实际参与路径评分)

内部代价0表示空闲,1~252通常称软代价,253为轮廓内切半径的高代价,254为致命障碍,255为未知。发布成OccupancyGrid后数值经过转换,不能拿RViz消息中的占用数直接代替内部值。

设d为距致命障碍格的实际平面距离,r_ins为填充后轮廓的内切半径。障碍格为254,内圈为253;内圈外、膨胀范围内按下式计算并取整数:

cost = 252 × exp(−cost_scaling_factor × (d − r_ins))

因此4增大时外圈代价更快降到低值,减小时高代价保持得更远;0.7决定写代价的范围。仅为说明公式,假设r_ins=0.2 m、d=0.4 m,系数4约得113,8约得50,2约得169;实际轮廓含padding,格距以/map为准,不能把这些假设数当实测。膨胀代价公式

当前Theta*常规搜索使用地图代价计算经过费用,当前配置w_traversal_cost=10.0,因此外围代价变化可以改变全局路径选择。1.1.20常规搜索将普通格的内部代价252及以上视为不可用,另对255按allow_unknown处理;这与当前局部PID抽样使用≥253阈值不同。“非致命软代价”不保证每一种规划器都放行。Theta*代价与通行判断

0.7 m膨胀区不会全部变成障碍,也不保证路径距墙至少0.7 m。需要结合有效轮廓、地图格距、定位误差、规划器代价权重和实际路径观察。局部图中改变外圈颜色不一定改变当前PID的抽样通过条件;全局图中这些代价则会进入Theta*路径评分,两张图的调参效果不能直接互推。当前局部控制器用法

未知格与膨胀开关(当前不把未知本身当障碍种子)

当前inflate_around_unknown缺省False,不主动以255未知格为膨胀起点;inflate_unknown缺省False,已知障碍扩到未知格时,不用1~252外围软代价覆盖未知,但仍可能写入≥253的内圈高代价。

这两个开关独立于顶层track_unknown_space,也独立于Theta*的allow_unknown。未知身份保留、边界膨胀和规划经过策略需一起检查;改其中一个不能默认得到另外两个的效果。未知格写入条件

always_send_full_costmap(固定整图也可以发增量)

False时,尺寸、分辨率和平面原点不变且有更新范围,可发布costmap_updates;首次发布或完整地图几何变化仍走全图分支。当前没有随车滚动原点,比局部图更容易满足几何不变条件,但不能保证每次都是增量。

costmap_raw有订阅者时始终准备完整nav2_msgs/Costmap,不受此开关改成增量;内部地图和get_costmap服务也不按该开关缩成更新块。因此这个开关主要影响OccupancyGrid发布方式,不能提高内部障碍刷新或控制Theta*读图频率。全图/增量与raw发布

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

参数表

下面20项为网格初始化、轮廓、观测缓冲和未知膨胀的源码默认设置;最后一项属于planner_server,用于解释本图的当前消费者。不是本次向原工程追加了这些参数。

参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
rolling_windowFalse,节点默认不适用,布尔通常保持当前值,不作为优先调试项选择固定全局网格或随车滚动窗口不适用不适用当前非滚动,static_layer决定整图几何;开启后会换成另一套尺寸与静态取样逻辑,不能只当显示开关
width5,节点初始化默认m,初始x总边长通常保持当前值,不作为优先调试项无静态地图前的初始x范围仅未被静态图接管时增加覆盖与格数仅未被接管时减少覆盖收到/map后以info.width格数为准;缺省5不证明全局覆盖5 m
height5,节点初始化默认m,初始y总边长通常保持当前值,不作为优先调试项无静态地图前的初始y范围仅未被静态图接管时增加覆盖与格数仅未被接管时减少覆盖是平面y,不是z高度;之后以/map.info.height格数为准
origin_x0.0,节点初始化默认m,初始平面原点x通常保持当前值,不作为优先调试项放置初始网格x下界初始网格沿x正向平移初始网格沿x负向平移后续以/map原点x为准,不是跟随机器人或先验定位偏移的调参入口
origin_y0.0,节点初始化默认m,初始平面原点y通常保持当前值,不作为优先调试项放置初始网格y下界初始网格沿y正向平移初始网格沿y负向平移后续以/map原点y为准;与体素origin_z独立
footprint"[]",节点默认不适用,轮廓顶点字符串上实物前必须核对并正确配置指定显式多边形,空值时使用圆半径不适用不适用当前使用robot_radius;有效多边形优先;也可通过footprint话题更新,需符合虚拟参考系约定
footprint_padding约0.01,节点默认m,轮廓填充量上实物前必须核对并正确配置扩大有效轮廓,影响清空范围与膨胀内圈轮廓及高代价内圈增大轮廓及内圈减小按顶点填充;不能代替测量真实车体、活动包络与中心偏置
transform_tolerance0.3,节点默认s,TF查询等待通常保持当前值,不作为优先调试项供机器人位姿、观测缓冲等取得变换可等待更久,延迟也可能增加缺失TF时更快结束查询不是允许0.3 m/rad外参误差;运行中改顶层值不会同步改所有已建缓冲中的副本
intensity_voxel_layer.terrain_map_ext.markingTrue,父类默认不适用,布尔通常保持当前值,不作为优先调试项把来源加入标记观测列表不适用不适用本自定义更新使用该列表,关闭后此来源不再贡献实时障碍
intensity_voxel_layer.terrain_map_ext.clearingFalse,父类默认不适用,布尔当前运行不使用这个参数,暂不调整父类可加入清空列表,但本实现未使用不适用不适用True不自动开启raytrace;追加raytrace量程也不会让当前自定义更新使用它
intensity_voxel_layer.terrain_map_ext.observation_persistence0.0,父类默认s,观测缓存保留设置通常保持当前值,不作为优先调试项选择最后一份或一定时间内的多份观测正值时保留更长历史,可能增多残留正值减小时历史窗口缩短;0走特殊分支0只保留最新一份,并非0 s后过期;不能清除上游扩展地形的历史点
intensity_voxel_layer.terrain_map_ext.expected_update_rate0.0,父类默认s,期望消息间隔实物运行时重点观察,有问题再针对性调整正值时检查来源是否按期更新允许更长停顿仍算current正值变小更快判停更;0关闭检查名字带rate,代码按秒建Duration;当前停更可能继续用旧观测且仍current
static_layer.map_topic"",层默认;转用节点namespace/map不适用,话题名称上实物前必须核对并正确配置指定完整二维地图输入不适用不适用当前通常/red_standard_robot1/map,不在global_costmap子namespace下;以实际重映射为准
static_layer.subscribe_to_updatesFalse,层默认不适用,布尔根据实际功能需求开启或设置是否另外订阅map_topic加_updates的增量图不适用不适用False仍可接收后续完整地图;与Transient Local独立
static_layer.footprint_clearing_enabledFalse,层默认不适用,布尔通常保持当前值,不作为优先调试项是否在静态层自身清轮廓区不适用不适用与实时层同名True不同;当前静态墙不会被实时层Max空闲值擦掉
use_maximumFalse,节点默认,供静态层读取不适用,布尔通常保持当前值,不作为优先调试项决定静态层覆写或取Max合成不适用不适用当前非滚动用TrueOverwrite铺静态图;不等于实时层combination_method,也不是多雷达强度合并开关
trinary_costmapTrue,节点默认不适用,布尔通常保持当前值,不作为优先调试项将静态占用值按未知、障碍、空闲解释不适用不适用缺省致命门槛100、未知值255;True时低于致命门槛的已知格为空闲,膨胀软代价另算
inflation_layer.inflate_unknownFalse,层默认不适用,布尔根据实际功能需求开启或设置控制已知障碍膨胀到未知格时是否写软代价不适用不适用False仍可写≥253内圈;不能简单理解成保留所有未知格毫不变化
inflation_layer.inflate_around_unknownFalse,层默认不适用,布尔根据实际功能需求开启或设置是否把未知格本身也作为膨胀起点不适用不适用当前不围绕未知本身膨胀;与前一项及allow_unknown各有独立作用
planner_server.GridBased.allow_unknownTrue,Theta*默认;不属于本地图节点不适用,布尔根据实际功能需求开启或设置决定当前规划器是否允许未知格参与常规搜索不适用不适用地图先保留255才有身份可判断;False不能恢复已被静态层转成0的未知区

observation_persistence=0和expected_update_rate=0共同意味着:消息停止时最后一份观测可能继续被重建,且不会因该来源超时自动变为不current。地图继续发布不证明感知继续更新,应观察terrain_map_ext时间戳、来源缓冲与系统的数据停更处理。缓存保留和current判断

与local_costmap的关系、动态修改与验证范围

当前两张地图的主要区别
项目global_costmaplocal_costmap
主要消费者planner_server中的Theta*,决定全局路径controller_server中的OmniPidPursuitController,跟踪路径及抽样碰撞检查
坐标参考mapodom
平面范围默认不滚动,完整/map决定网格几何5×5 m、0.05 m格距的滚动窗口
实时地形输入terrain_map_ext,包含借入近场与自算远场terrain_map,近场结果
三维量程筛选严格0.2~10 m,且必须落在静态地图边界内严格0.2~5 m,且必须落在局部窗口内
内部更新/话题目标频率5 Hz/2 Hz10 Hz/5 Hz
当前有效体素高度map中的[0,0.8) modom中的[0,0.8) m
顶层未知设置实物True;仿真未写,默认False两套均未写,默认False
同样膨胀数值的使用Theta*常规搜索使用软代价,普通格≥252不放行,未知另判断当前PID仅抽10点检查≥253,不按外围软梯度评分

障碍出现差异时,先沿“上游输入→TF后的z→高差→量程→平面范围→合成→消费者”定位。只让两张地图的YAML数字相同,不能保证实际选点、未知策略或路径通过条件相同。局部代价地图

动态修改的实际范围
参数类别当前实现核对方式
robot_radius、footprint_padding、footprint、publish_frequency节点回调会更新轮廓或发布门槛观察实际轮廓、内切膨胀圈与发布结果;不能只看设置成功
robot_base_frame节点回调先检查到global_frame的TF,再接受变更即使接受,也需核对整套参考点、轮廓和控制链是否使用同一约定
width、height、resolution、origin_x/y未锁尺寸时可resize;当前static_layer收图后锁定当前锁定状态下参数值改变不代表网格改变,以实际地图元数据为准
update_frequency、global_frame、rolling_window、plugins、track_unknown_space、always_send_full_costmap无完整动态联动更新路径重新配置/重启并检查有效行为;改变未知设置需让静态图重新按策略解释
本层enabled、footprint_clearing_enabled、两项层高度、combination_method父类ObstacleLayer回调更新对应成员改层高度不更新来源缓冲自己的高度窗口
origin_z、z_resolution、z_voxels、mark_threshold、unknown_threshold、两项intensity、publish_voxel_map自定义层没有对应动态分支重新配置/重启;unknown_threshold重启后仍未参与当前计算
terrain_map_ext的来源参数初始化时创建订阅器及ObservationBuffer修改配置后重新配置/重启,再核对来源、TF、过滤和停更状态
静态图话题、Transient Local、subscribe_to_updatesStaticLayer回调明确拒绝这些运行中修改重建订阅后验证QoS与实际图来源
膨胀半径、衰减系数和未知膨胀开关膨胀层回调更新成员,必要时重算缓存/重膨胀核对全局代价和实际Theta*路径,结合有效地图格距判断

顶层transform_tolerance虽有节点成员更新分支,已建ObservationBuffer、消息过滤器及静态层另有初始化时保存的值;一次修改不保证所有等待同步更新。节点动态回调、障碍父类回调

启动来源与本次核对
启动方式本块来源与关系
整套realityconfig/reality/nav2_params.yaml,经bringup展开topic占位符、navigation_launch重写时钟加载;顶层未知True
整套simulationconfig/simulation/nav2_params.yaml;时钟True,顶层未知缺省False,不能说只差时钟
组件/独立进程此地图节点由planner_server内部创建,读取相应namespace下参数;不是这份YAML自行启动进程
slam=True静态图来自建图产生的完整/map;实时层仍用terrain_map_ext
slam=False静态图来自map_server;实时层仍用terrain_map_ext,需要定位链对齐map与odom
  • 本次已核对: 相关安装包版本、已有自定义层注册/库/头文件;本地自定义实现与固定上游提交一致;Theta*安装头文件与1.1.20一致;源码和安装副本的两套global_costmap段一致,实物/仿真差异为时钟与顶层未知键。
  • 源码能确认: 38项原参数的实际读取/使用条件;静态图重建并锁定非滚动网格;实物顶层未知开关生效、层内同名键与unknown_threshold未参与相应计算;map垂直标记窗口[0,0.8) m;三维严格量程;每轮重建但不射线清空;旧观测保留;Max合成、膨胀方向及当前Theta*的未知/软代价使用。
  • 本次验证范围: 未启动新的导航或建图任务,未取得运行/map与costmap元数据、有效参数快照或路径对比;没有实测map←odom的高度偏移、坡道筛点、动态障碍残留或未知区经过行为。文中尺寸、高度和时间例子均为配置/源码计算。
  • 实物待核实: 实际静态图尺寸/格距/原点与坐标约定、先验地图对齐、map高度基准、真实轮廓与虚拟参考点、点云字段和TF时间、来源停更处理、近远场交接、未知规划策略以及全局路径到局部执行的通过空间。