第 5.12 节

local_costmap(局部障碍代价地图)

作者:董佳辉

local_costmap(局部障碍代价地图)

实车先看:地图上的障碍来自哪里

当前局部代价地图是以gimbal_yaw_fake位置为中心、在odom中表达的约5×5 m滚动网格。 它按顺序合成静态二维地图、实时地形障碍和障碍周围的膨胀代价,供controller_server使用。

/map二维占用图 → static_layer ──────────────────────────────┐
                                                         │
terrain_map(odom系地形点,intensity为离地高差)            │
    → 观测缓冲:TF、来源高度筛选、雷达原点                  │
    → intensity_voxel_layer:高度、高差、量程与体素筛选 ───┤
                                                         ↓
                                        inflation_layer → 局部合成代价地图
                                                         ├─ controller_server读内存中的地图
                                                         └─ costmap/costmap_updates/costmap_raw供订阅者

本块直接接收近场terrain_map;全局代价地图接收terrain_map_ext,下一块再整理。pointcloud_to_laserscan生成的obstacle_scan用于二维建图,本局部障碍层不经过那份二维扫描。因此修改扫描转换器的高差门槛,不会直接修改这里的门槛。地形分析分工、二维扫描转换

实车上看到的现象先核对什么当前配置怎样理解
以为局部地图覆盖车周围5 m半径width、height与量程5 m是整张网格的边长,各轴只约覆盖中心两侧2.5 m;量程5 m不能扩展网格
2 m内的高障碍仍没有进入此层origin_z、z_resolution、z_voxels当前体素高度是odom中的[0,0.8) m,超过0.8 m的点不能进入标记;2 m高度门槛只是前置过滤
上坡高处或下坡低处的障碍消失odom高度基准、两级高度窗口、体素窗口高度窗口固定在odom,不随底盘z跟着升降;地形高差正确也可能被绝对高度裁掉
写了track_unknown_space=True,未探测区却像空闲参数所在层级当前版本读取节点顶层track_unknown_space;写在intensity_voxel_layer内没有配置到它,顶层缺省False
改unknown_threshold看不到效果自定义层的使用路径本实现没有用它计算未知列/二维未知状态;不能套用标准VoxelLayer的解释
障碍已经移开,却继续残留最新terrain_map、上游衰减、观测缓冲与静态层本层每轮重建,最新观测仍可能含上游历史点;数据停止时默认还会复用最后一份观测
以为cost_scaling_factor越大越保守膨胀公式与当前控制器用法越大,外围软代价衰减越快;当前PID只抽样检查高代价值,不用这套软梯度给轨迹打分

本次容器内nav2_costmap_2d、nav2_voxel_grid均为1.1.20,pb_nav2_plugins为1.0.1。本地自定义层实现与头文件和上游提交e6778ca44d9e88aa612a3c6c87d536a8cfa21705一致;以下按该版本核对。自定义层实现、体素换算与类定义

参数

下面保留发送的完整参数与原注释。实物/仿真段只有use_sim_time不同;源码缺省值及配置建议另列。

local_costmap:
  local_costmap:
    ros__parameters:
      use_sim_time: False
      update_frequency: 10.0
      publish_frequency: 5.0
      global_frame: odom
      robot_base_frame: gimbal_yaw_fake
      rolling_window: true
      width: 5
      height: 5
      resolution: 0.05
      robot_radius: 0.2
      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
        terrain_map:
          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
          sensor_frame: front_mid360
          min_obstacle_height: 0.0
          max_obstacle_height: 2.0
          obstacle_max_range: 5.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

两个local_costmap层级用于匹配命名空间和节点名。例如机器人命名空间为/red_standard_robot1时,当前controller_server创建的代价地图节点为/red_standard_robot1/local_costmap/local_costmap;发布话题通常位于/red_standard_robot1/local_costmap下面。坐标系字符串不会随这个命名空间自动加前缀。

ros__parameters(更新、坐标、网格与机器人轮廓)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
use_sim_timeFalse;仿真True不适用,布尔上实物前必须核对并正确配置选择ROS时钟,供TF、消息与发布判断使用不适用不适用经工程launch重写;应与点云及TF使用同一时间域;内部更新循环另用WallRate
update_frequency10.0Hz,目标更新频率实物运行时重点观察,有问题再针对性调整控制内部地图合成循环,当前目标100 ms/轮理想情况下更快处理变化,计算与锁负担增加内部障碍变化响应可能更迟不提高输入点云采样频率,也不保证每轮有新观测;当前回调不重建该更新线程节拍
publish_frequency5.0Hz,目标发布频率通常保持当前值,不作为优先调试项控制地图话题发布的时间门槛订阅者可能更及时,发布负担增加话题显示/订阅更新更稀,内部地图仍可按10 Hz更新发布判断在更新循环中;不保证实际5 Hz;控制器直接读内存,部分行为读地图话题或服务
global_frameodom不适用,坐标系名称上实物前必须核对并正确配置指定这张局部网格的坐标参考系不适用不适用点云最终转到此系;static_layer仍需将/map的map系转换到odom;高度门槛也按该系z计算
robot_base_framegimbal_yaw_fake不适用,坐标系名称上实物前必须核对并正确配置指定滚动中心、控制器参考点与轮廓的机体系不适用不适用与当前虚拟参考系设计配合;圆形轮廓中心在此原点,不能默认等于车体几何中心
rolling_windowtrue不适用,布尔通常保持当前值,不作为优先调试项随机器人位置移动平面网格原点不适用不适用滚动平面窗口不会使origin_z随车升降,也不让网格轴随底盘yaw旋转;False为固定窗口
width5m,网格x方向总边长实物运行时重点观察,有问题再针对性调整控制局部地图x方向覆盖范围可保留更远的已有障碍和路径,网格与计算增多范围变小,更容易在窗口外裁掉路径/障碍当前按5/0.05=100格;不是5格或5 m半径;本版本使用正整数米
height5m,网格y方向总边长实物运行时重点观察,有问题再针对性调整控制局部地图y方向覆盖范围覆盖更宽,网格与计算增多侧方范围变小,横移时可用环境更少这里的height是平面y边长,不是体素z高度;当前100格
resolution0.05m/平面格,5 cm实物运行时重点观察,有问题再针对性调整设置x、y格子边长格子更粗、格数更少,细障碍和窄通道表达可能变差格子更细、计算及缓存增多,但不能补回上游丢点当前100×100共10000格;两方向分辨率减半时格数约4倍;不等于定位精度
robot_radius0.2m,未填充轮廓的圆半径上实物前必须核对并正确配置没有显式footprint时,以此半径生成圆形轮廓车体占用与膨胀内圈变大,狭窄通道更受限占用变小,可能低估真实车体/云台包络当前无显式footprint,另有默认0.01 m padding;不是雷达盲区或膨胀半径,应按实际包络核对
pluginsstatic_layer、intensity_voxel_layer、inflation_layer不适用,有序ID列表上实物前必须核对并正确配置按顺序加载并合成三层不适用不适用当前先静态、再实时障碍、最后膨胀;各ID需有plugin类名;增删与换顺序会改变合成路径
always_send_full_costmapFalse不适用,布尔根据实际功能需求开启或设置选择OccupancyGrid每次强制全图或按条件使用增量不适用不适用False遇到尺寸、分辨率或滚动原点变化仍发全图;costmap_raw有订阅者时始终发完整原始代价图;不改变内部障碍判定
参数详解
update_frequency、publish_frequency与always_send_full_costmap(内部10 Hz与话题5 Hz各负责什么)

内部更新循环以WallRate运行,调用各层updateBounds、updateCosts合成地图。controller_server通过持有的local_costmap对象直接读取这张地图;它的20 Hz控制循环与本块10 Hz更新各自运行,部分控制轮次可能读到同一轮地图结果。

publish_frequency控制更新循环中是否到了发布时间,不是独立的5 Hz发布定时器;实际受更新时间、负载和ROS时钟影响。若以2.5 m/s运动,理想100 ms更新间隔内已移动0.25 m,即5个当前格距;这是时间尺度计算,不是本次实车测量。调频率需要结合整条感知和执行链延迟。更新与发布循环(1.1.20)

False不会保证只发增量:网格原点滚动、尺寸或分辨率变化时,OccupancyGrid会走全图分支;几何信息不变且有更新范围时,才可能发costmap_updates。costmap_raw不走这个增量选择,有订阅者就准备完整nav2_msgs/Costmap。使用地图话题的行为与读取服务的行为,还应各自核对数据接口。发布选择

global_frame、robot_base_frame与rolling_window(odom中的移动窗口)

网格轴按odom的x、y表达,中心跟踪gimbal_yaw_fake的平面位置,平面原点以格距对齐滚动;它不是随底盘姿态旋转的车体图。当前虚拟系的方向与速度转换关系见fake_vel_transform。

局部地图使用odom可以减少全局重定位修正直接作用到局部点云坐标的影响,但静态层仍从map系地图取样,需要有效map↔odom。只有odom至机器人TF,不证明三层合成所需TF已经全部可用。

窗口滚动只处理平面x、y。体素origin_z=0仍固定在odom的z基准上,机器人上坡、下坡不会自动平移这段垂直窗口。滚动原点实现

width、height与resolution(5×5 m,100×100格)

当前约覆盖参考点两侧各2.5 m,角落的平面距离约3.5 m;实际原点受格距对齐,不能把边界当成精确连续对称的圆。5 m观测量程用于筛点,最终落在网格外的点仍不能标记。

平面共有10000格。自定义层再为每个平面列记录16个高度状态,逻辑上约160000个体素;实现用每列32位打包,不是为每个体素存一份完整点云。减小z_voxels不等于平面列缓存内存按比例减少。

平面resolution与垂直z_resolution是独立参数,当前恰好都为0.05 m。改变平面格距还会影响障碍合并、轮廓栅格化、膨胀和控制器局部路径处理;它不能增加MID360回波密度或恢复地形分析已经过滤掉的小障碍。

robot_radius(围绕虚拟参考点的车体轮廓)

当前默认footprint="",因此用robot_radius=0.2生成近似圆形多边形,再按默认footprint_padding≈0.01 m填充。padding按多边形顶点方向实现,不应把最终轮廓简单等同于精确半径0.21 m的圆。轮廓建立与填充

该轮廓以gimbal_yaw_fake原点为中心。需按真实底盘、雷达、云台及其活动包络核对0.2是否覆盖,而不是继承示例半径;安装参考点偏置也要计入。膨胀不能替代正确的车体轮廓。

如果以后改成车体矩形footprint,须处理其坐标轴和真实底盘姿态:当前虚拟系在平面上抵消yaw,不会自动随底盘转向。可选择覆盖转动包络的轮廓,或按实际姿态提供正确的动态轮廓,不能直接填一个底盘固连矩形就认定方向已正确。

intensity_voxel_layer(地形高差与三维障碍筛选)

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

当前完整标记流程包括:来源缓冲高度筛选、本层高度筛选、地形高差筛选、相对传感器的三维量程筛选、平面与高度格范围,以及mark_threshold。通过其中一项不保证最终进入地图。

点的z是odom坐标;intensity是上游估计地面的高差。 假定量程、平面位置和其他条件都满足:

点在odom中的z地形高差intensity当前结果
0.2 m0.15 m两级高度、高差及体素范围都通过,可标为障碍
0.2 m0.05 m高差不足0.1 m,被删
0.9 m0.15 m0~2 m高度过滤通过,但超过当前体素上界,无法标记
-0.1 m0.15 m来源高度下界已删除,尚未到体素处理

当前整数高度索引为floor((z−0)/0.05),要求索引小于16,故有效范围为**[0,0.8) m**。z=0.8对应索引16,越界;上界不包含。这段窗口固定在odom,odom的z=0并不凭名称保证就是实车当前地面。

上坡高处、下坡低处的障碍即使地形高差正确,也可能被高度窗口删掉。若需要改变覆盖,必须一起核对来源高度、本层高度、origin_z与16层限制内的z_resolution;只把max_obstacle_height从2调到3不能解决体素上界。也不能为了放行坡面就把所有危险低障碍一起过滤。实际筛点与索引转换

min_obstacle_intensity与max_obstacle_intensity(是否把地形高差当障碍)

近场terrain_analysis已经把intensity改成相对估计地面的高差,当前下界0.1即10 cm。它不是“车辆能跨10 cm”,也不是坡度门槛。正常坡面若被错误估成15 cm凸起,满足其他窗口时仍可能成为障碍;应先看地面估计与坐标,再按真实车辆和场地调整门槛。

上游当前近场正常高差输出受vehicleHeight=0.5 m限制,所以这里2 m上限通常不会进一步裁剪正常点。若改输入、上游规则或出现特殊标记点,需要重新判断。直接改接原始雷达点云后,intensity可能变回反射强度,不能沿用“0.1 m/2 m”的解释。

mark_threshold(数高度格,不数原始点)

VoxelGrid用位记录每个平面列的已标记高度格;已标记格数严格大于mark_threshold才返回可标障碍。当前0表示一格就够。设1则至少要两格,设2至少三格;同一高度格里再来很多点,不会增加高度格计数。标记计数实现

本层每次更新都会先重置二维图与体素,所以门槛统计来自本轮取得的观测内容;它不会靠连续多个更新周期逐渐凑够格数。但最新terrain_map本身包含上游历史点,不能把“一份最新观测”理解成一份纯实时原始扫描。

低矮物、薄障碍、稀疏回波可能只占一个高度格,提高门槛可能让它们消失;能否过滤噪声应按实物观察,不保证越大越稳。

track_unknown_space与unknown_threshold(层级错误和未使用的门槛)

自定义层调用ObstacleLayer::onInitialize,后者读的是节点顶层track_unknown_space;Costmap2DROS及StaticLayer也读该顶层键。当前层内True没有进入这条读取路径,顶层未配置时默认False,主图和障碍层默认按FREE_SPACE重置;静态图的未知值也会按该设置转为空闲。父类读取位置、静态未知值解释

若要表达原配置“跟踪未知空间”的True意图,正确层级为:

local_costmap:
  local_costmap:
    ros__parameters:
      track_unknown_space: true

此时应移除无效的层内同名键,重新核对未知区在规划与控制中的处理。若任务选择不跟踪未知,则应明确顶层False;错误是当前写入层级,不是要求所有任务必须使用True。 这里只提供修正说明,没有修改工程配置。

unknown_threshold另属自定义成员:初始化保存5+(16−z_voxels),当前仍为5,但后续没有用它清体素射线、统计未知列或生成二维未知状态。调整5不会改善当前未知空间判定。成员赋值与更新路径

即使顶层改True,本层也只是以未知默认二维格重置,再标出障碍和轮廓内空闲,不会因此自动得到标准VoxelLayer的完整射线空闲/未知推断。没有回波或点被过滤,不等于真实空地。

每轮重建、轮廓清空与清地图服务(几种清除各有范围)

该自定义updateBounds先resetMaps,再拿marking observations重建障碍,最后清本层轮廓内二维代价。它不调用getClearingObservations或raytraceFreespace,直接把来源clearing改True也不会给当前实现补上射线清空。

footprint_clearing_enabled=True只清本层二维轮廓,不擦除已保存的体素标记;当前Max合成也不会用FREE_SPACE覆盖static_layer的静态墙。轮廓、点云自车滤除和静态地图错误应分开核对。

清地图服务还需区分:类的isClearable=False使按区域的ClearAround/ClearExcept服务跳过它;但ClearEntirely调用resetLayers,会重置主图并调用所有层的reset,包括本层。前面的BT使用的是ClearEntireCostmap,因此不能说它因为isClearable=False就完全不重置。重置也不丢弃上游地形缓存,下一轮相同观测/静态图仍可能把障碍加回来。区域与整图服务、整图层重置

本层内部重建不保证主图所有旧格立即变空;合成还受各层更新范围、滚动、静态占用和最新观测影响。动态残留应结合上游terrain_analysis衰减与实际话题观察。

combination_method(当前Max保留已有障碍)

当前1调用updateWithMax:本层未知格跳过;已知格可以替换主图未知格,或在代价更高时写入。FREE_SPACE不会降低前面静态层的已知障碍;不能简单把255未知当作普通数字最大值来推断全部合成结果。Max合成

0为Overwrite,可用本层非未知代价覆盖之前的图层;当前顶层缺省不跟踪未知、重置大量格为FREE_SPACE,改0可能擦掉静态层的已知障碍。其他整数在当前父类switch中不做合成;新版文档中的其他枚举不代表本版本可用。

intensity_voxel_layer.terrain_map(地形观测源)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
data_typePointCloud2不适用,消息类型名称上实物前必须核对并正确配置为来源建立PointCloud2订阅及缓冲不适用不适用当前自定义迭代器需要float XYZ与intensity字段;父类可订阅LaserScan,不代表本层改类型后仍有需要的intensity
topic<robot_namespace>/terrain_map不适用,话题名称上实物前必须核对并正确配置指定实际近场地形点云输入不适用不适用工程bringup先展开占位符;通常为/red_standard_robot1/terrain_map;绕过launch时原字符串不会自行展开
sensor_framefront_mid360不适用,传感器原点系名称上实物前必须核对并正确配置取得量程筛选用的传感器原点不适用不适用按点云时间戳查front_mid360至odom;点坐标仍按消息header.frame_id转换,不被强行当作雷达系点
min_obstacle_height0.0m,odom中点z的来源下界上实物前必须核对并正确配置观测缓冲阶段先删除低于0的点提前删除更多低处点允许更多低处点进入本层,仍受本层及体素限制与上一组同名但属独立阶段;两处均为0,边界可通过;只改本层下界不能恢复此处已删点
max_obstacle_height2.0m,odom中点z的来源上界上实物前必须核对并正确配置观测缓冲阶段先删除高于2 m的点来源窗口扩大,后续仍可删掉高点降到体素有效窗口内才进一步减少当前可标记点当前还受本层2 m和体素0.8 m上界限制;来源缺省上界为0.0,不自动继承本层2 m,不能随意省略;在odom中筛高度
obstacle_max_range5.0m,相对雷达原点的三维距离实物运行时重点观察,有问题再针对性调整删除距离front_mid360原点达到/超过5 m的点接纳更远已有点,仍受地形输出和网格边界限制删除更多远点当前距离包含z;等于上界也删除;不是局部地图宽度或底盘周围5 m圆
obstacle_min_range0.2m,相对雷达原点的三维距离上实物前必须核对并正确配置删除距雷达原点不超过0.2 m的点排掉更多近点,也可能漏掉近车障碍保留更多近点,可能包含自车回波当前自定义代码使用≤下界删除;不是robot_radius,也不是完整车体掩膜
参数详解
topic、data_type与sensor_frame(点云坐标和测距原点分别取哪里)

bringup_launch先把<robot_namespace>替换为空或“/+机器人命名空间”,随后参数重写和加载;当前配置通常订阅/red_standard_robot1/terrain_map。占位符没有在层源码中自行处理,直接启动原始参数文件时必须完成对应替换。

terrain_map的点坐标当前在odom中。ObservationBuffer按header.frame_id把点云转换到global_frame;另以sensor_frame指定的原点、同一消息时间戳取得odom中的雷达位置,再供量程计算。因此sensor_frame不会把odom点重新解释成雷达局部点。观测缓冲换系与原点

显式设置front_mid360后,消息过滤器还要求对应传感器系可变换。TF、时间域、命名空间和QoS都需要匹配;有地形话题不证明本层已成功接收缓冲。输入订阅采用SensorDataQoS,父类配置队列深度50;队列不是50 Hz或50 ms。

来源高度与量程(高度在odom,距离从雷达量)

来源高度先在转换后的odom点坐标上筛选,并保留包括intensity在内的原点字段;本层再次检查自己的高度门槛。当前两级0~2 m相同,实际可标记的上界仍受0.8 m体素覆盖制约。

量程使用sqrt((x−x_sensor)²+(y−y_sensor)²+(z−z_sensor)²),当前严格保留0.2~5 m之间的点。与二维扫描转换器按底盘虚拟中心计算水平距离不同,雷达安装偏移、云台转动和上下坡会影响这个三维距离。

近场地形输出和局部窗口本就有限。增大量程不会扩大5×5 m网格、不能恢复上游被删的点,也不会让MID360采样更远;最小量程也不能滤掉距雷达超过0.2 m的全部自车结构。

static_layer(静态二维地图接入)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
pluginnav2_costmap_2d::StaticLayer不适用,类名通常保持当前值,不作为优先调试项将订阅到的二维占用图采样到局部滚动网格不适用不适用常规导航来源为map_server,建图时来源为slam_toolbox;读取地图话题,不直接读PCD或地图图片文件
map_subscribe_transient_localTrue不适用,QoS耐久性选择上实物前必须核对并正确配置用Transient Local、Reliable、KeepLast(1)订阅完整地图不适用不适用发布端需兼容,才能取得保留的最近地图;不是保存地图到磁盘,也不是开启map_updates订阅
参数详解
static_layer(map图仍要经过map↔odom变换)

静态层订阅完整OccupancyGrid,保存其尺寸、分辨率、原点和header.frame_id。滚动模式不会强行把主图变成整张静态地图的大小;它根据当前odom格子的世界位置,查询map_frame←odom的最新变换,到静态图中取样。因此local_costmap在odom中运行,仍需正确的全局定位变换。滚动静态图采样

当前顶层track_unknown_space缺省False,静态图未知格转为FREE_SPACE;已知墙仍保留。没有收到地图或对应TF查询失败时,点云这一路即使存在,也不能证明静态层已正常合成。当前controller_server还会等待代价地图current状态,地图输入和各层状态要一起看。

map_subscribe_transient_local(保留地图消息与更新话题各自独立)

True让较晚启动的订阅者可以从兼容发布端取得保留的最近完整地图。若发布端只提供Volatile耐久性或可靠性不兼容,不能靠延长TF等待取得地图;应先核对发布端与订阅端的QoS。地图订阅QoS

当前subscribe_to_updates缺省False,不订阅/map_updates;这不阻止处理随后收到的完整/map消息。“static”表示图层输入方式,不表示完整地图永远不能更新。

inflation_layer(障碍周围的二维代价)

参数表
参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
pluginnav2_costmap_2d::InflationLayer不适用,类名通常保持当前值,不作为优先调试项在已合成障碍附近写入距离相关的二维代价不适用不适用当前位于三层最后,使静态墙和实时障碍都可成为膨胀源;不恢复被高度/高差筛掉的障碍
cost_scaling_factor4.0m⁻¹,指数衰减系数实物运行时重点观察,有问题再针对性调整控制轮廓内圈之外的软代价随距离衰减同样距离的外围代价更低、衰减更快;不加宽内圈外围代价更高、衰减更慢,在既定半径内更宽地维持较高代价不改0.7 m截断范围;当前PID没有使用1~252软代价评分,地图颜色变化不保证控制变化
inflation_radius0.7m,距致命障碍格的膨胀范围实物运行时重点观察,有问题再针对性调整确定障碍周围多远仍写膨胀代价代价影响范围扩大,计算增多,规划若使用梯度可能更早绕开影响范围缩小;不能小到不足以表达所需轮廓空间当前约14个5 cm格距;不是0.7 m全为禁止区,也不再自动加robot_radius成0.9 m
参数详解
cost_scaling_factor与inflation_radius(范围和代价下降速度)

内部代价值与发布后的OccupancyGrid占用值不同:

内部代价含义
0空闲
1~252非致命的软代价,越高通常越不希望经过
253轮廓内切半径范围的高代价
254致命障碍
255未知状态

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

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

所以4变大时,外围代价更快降低;变小时,较高软代价维持得更远。0.7决定影响范围,4决定范围内的衰减,不能把两个参数当同一作用。代价公式(1.1.20)

仅为说明公式,假设r_ins=0.2 m、d=0.4 m:当前4对应约113,改为8约50,改为2约169。实际轮廓含padding、栅格化和最近障碍距离,不能把这个假设值当运行读数。

0.7 m以内并非全部致命或253,也不是保证车体距墙至少0.7 m。轮廓定义、真实包络、地图误差和路径使用方式都影响实际通过距离。

当前PID怎样使用这些代价(软梯度不等于已经参与避障评分)

当前OmniPidPursuitController从局部路径抽10个点,检查落格代价是否达到INSCRIBED_INFLATED_OBSTACLE,即≥253;它不按1~252的软梯度给候选轨迹打分。改变局部cost_scaling_factor或扩大外围软代价,可能改变RViz颜色,却没有直接改变本插件的碰撞通过条件。

robot_radius及padding改变的内切半径会影响253内圈;静态墙/实时障碍本身也参与高代价检查。全局路径又由另一张global_costmap规划,其膨胀设置需下一块单独核对,不能把两张地图的参数影响混为一谈。当前控制器地图使用方式

前文还记录了抽样数量及地图外点的处理缺口。这里的膨胀范围不是完整车体扫掠碰撞检查的替代,也不补回本障碍层遗漏的高度点。

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

参数表

以下12项补充真正读取的节点顶层设置、观测缓冲与未知膨胀行为;不表示本次已向工程YAML追加。

参数名当前值单位实车处理建议作用调大效果调小效果生效条件/备注
track_unknown_spaceFalse,节点顶层源码默认不适用,布尔上实物前必须核对并正确配置决定主图、障碍层默认未知表示及静态未知格解释不适用不适用真正被读取的键;与前面层内未生效的True不同,需明确实际未知区策略
footprint"[]",源码默认不适用,轮廓顶点字符串上实物前必须核对并正确配置指定显式多边形轮廓,空值时使用圆半径不适用不适用当前用robot_radius;有效多边形会优先使用;还可通过footprint话题更新,须核对参考系
footprint_padding约0.01,源码默认m,轮廓填充量上实物前必须核对并正确配置在轮廓外增加填充,影响内切半径和清轮廓区域有效轮廓增大有效轮廓减小不是补偿未量出的完整车体尺寸;按顶点实现,不能简单保证圆半径恰好加0.01
transform_tolerance0.3,节点顶层源码默认s,TF查询等待通常保持当前值,不作为优先调试项供机器人位姿、观测缓冲和静态层等取得变换可等待更久,也可能增加延迟更快结束缺失TF查询不允许0.3 rad/m误差,也不补偿外参;运行中改顶层值不会自动更新已构建的所有缓冲成员
intensity_voxel_layer.terrain_map.markingTrue,父类默认不适用,布尔通常保持当前值,不作为优先调试项将此来源加入标记观测列表不适用不适用当前自定义层使用该标记列表;关闭后此来源不再贡献障碍
intensity_voxel_layer.terrain_map.clearingFalse,父类默认不适用,布尔当前运行不使用这个参数,暂不调整父类可把来源加入清空列表,本自定义更新未使用该列表不适用不适用改True不会自动开启本层射线清空;对应raytrace量程也不会因添加配置就参与当前处理
intensity_voxel_layer.terrain_map.observation_persistence0.0,父类默认s,观测缓存保留设置通常保持当前值,不作为优先调试项决定缓存一份还是一定时间内的多份观测正值时可能保留更多历史观测,动态残留增多正值减小时历史窗口变短;0另走特殊分支0表示只留最后一份,不表示最后一份在0 s后过期;不清上游terrain_map历史
intensity_voxel_layer.terrain_map.expected_update_rate0.0,父类默认s,期望消息间隔实物运行时重点观察,有问题再针对性调整正值时用于判断观测是否按期更新允许更长消息间隔后仍算current正值变小使停更更快被判断;0关闭这项检查名字虽带rate,代码按秒建Duration;当前停更不因这项自动变为不current
static_layer.map_topic"",层私有默认;转用节点默认机器人namespace下的map不适用,话题名称上实物前必须核对并正确配置指定完整静态图话题不适用不适用当前通常/red_standard_robot1/map;不是/red_standard_robot1/local_costmap/map;以实际namespace/重映射为准
static_layer.subscribe_to_updatesFalse,源码默认不适用,布尔根据实际功能需求开启或设置是否另外接收map_topic加_updates的增量图不适用不适用False仍接收后续完整地图;与地图Transient Local订阅设置独立
inflation_layer.inflate_unknownFalse,源码默认不适用,布尔根据实际功能需求开启或设置控制已知障碍膨胀到未知格时是否写入软代价不适用不适用False也可能在未知格写入≥253的内圈代价;不等于把未知格都当膨胀源
inflation_layer.inflate_around_unknownFalse,源码默认不适用,布尔根据实际功能需求开启或设置是否将未知格本身也作为膨胀起点不适用不适用当前不主动围绕未知格膨胀;与上一项是不同步骤,顶层未知策略变化后需重新核对
观测停更与默认未知状态

observation_persistence=0只删除比最新观测更旧的观测,保留最后一份;expected_update_rate=0直接将缓冲判为current。于是点云停止到达时,本层可能继续每轮重建同一份旧地形,而不是自动清空障碍或停止控制。还需结合静态层、其他层状态和完整系统的数据监测判断,不能只看地图话题仍发布。缓存保留与current判断

如果以后设置正的expected_update_rate,按秒的消息间隔理解,再核对正常数据周期与延迟;不能填10就当成10 Hz。只改变buffer保留时间也不去除terrain_map内部已经累计的历史点。

动态参数、启动来源与验证范围

动态修改的实际范围

自定义层没有另写覆盖体素、高差和发布器的动态回调,使用父类ObstacleLayer的回调;因此运行中参数设置成功,不代表所有成员已经更新。

参数类别当前实现应怎样核对
robot_radius、footprint_padding、footprint、publish_frequency节点回调会更新相应轮廓或发布门槛核对实际轮廓、膨胀内圈及地图话题;动态轮廓须符合当前参考系
width、height、resolution当前未锁尺寸时回调重建网格,并调用各层matchSize注意观察缓存与范围变化;width/height采用正整数,resolution为正double
update_frequency、global_frame、rolling_window、plugins、track_unknown_space、always_send_full_costmap当前没有完整动态联动更新路径重新配置/重启后核对有效行为,不仅看参数列表
intensity_voxel_layer.enabled、footprint_clearing_enabled、两项层高度、combination_method父类回调更新对应成员分支改变后核对实际合成;层高度变了不会同时重建来源高度过滤
origin_z、z_resolution、z_voxels、mark_threshold、unknown_threshold、两项intensity、publish_voxel_map当前自定义层无对应动态更新分支重新配置/重启;unknown_threshold重启后也仍无当前使用路径
terrain_map的话题、类型、原点系、来源高度、量程、缓存及期望间隔初始化时建订阅器和ObservationBuffer重新配置/重启,不能只修改成员外的同名ROS值
static_layer地图话题、Transient Local、subscribe_to_updates当前回调明确拒绝这类运行中修改修改配置并重新启动订阅后验证
inflation_radius、cost_scaling_factor及未知膨胀开关膨胀层回调更新、必要时重算缓存并重新膨胀核对实际代价图及当前消费者是否使用软梯度

顶层transform_tolerance有成员更新分支,但已经创建的来源缓冲、消息过滤器和静态层各有初始化时保存的值;不能认为一次改值让所有TF等待同步变化。节点回调、父类层回调

启动与核对范围
启动方式本块来源与关系
整套realityconfig/reality/nav2_params.yaml,经bringup替换topic占位符、navigation_launch重写时钟并加载
整套simulationconfig/simulation/nav2_params.yaml,本块仅use_sim_time=True不同
组件/独立进程local_costmap由controller_server内部创建,读取同套命名空间下的节点参数;不是这份YAML自己启动一个进程
slam=True静态层接建图产生的完整/map;实时地形层仍用terrain_map
slam=False静态层接map_server的/map;实时地形层仍用terrain_map,地图定位依赖small_gicp等提供map↔odom
  • 本次已核对: 当前包版本、插件注册与liblayers.so存在;自定义层安装头文件与本地一致,本地实现与上游固定提交一致;Nav2的体素、合成与膨胀安装头文件匹配1.1.20;两份local_costmap段与安装副本一致,仿真仅时钟不同。
  • 源码能确认: 40项原配置的读取/使用条件;层内未知开关位置无效、unknown_threshold未参与计算;当前odom垂直标记区间[0,0.8) m;按不同高度格计标记;每轮重建但不射线清空;区域与整图清理不同;默认旧观测复用、膨胀方向和全图/增量发布条件。
  • 本次验证范围: 未启动新的地图或导航任务,未观察运行节点有效参数、坡道点、未知区、动态障碍消失时间或车旁碰撞;窗口、体素和膨胀例子是配置/源码计算。
  • 实物待核实: odom地面高度基准、上下坡与高低障碍是否过窗口、真实车体轮廓与虚拟参考点、点云字段与TF时间、观察源停更处理、静态图对齐/QoS、未知区策略、动态残留以及控制器实际地图使用。