想象你是一家繁忙餐厅的大厨。厨房里墙、灶台、岛台的位置是固定的,装修图纸上画得清清楚楚;但此刻地上有刚搬来的食材箱,传菜员来回穿梭,灶台上的油锅正冒着热气。你不会只看装修图纸就闷头冲过去——你会把图纸、眼前看到的人和“离热锅保持安全距离”的经验叠在一起,在脑子里形成一张“当下厨房工作台示意图”。ROS里这张会实时变化的示意图,就叫代价地图(Costmap)。 这张示意图不是一张图,而是三层“便签”叠出来的:最底下是装修图纸(静态层),中间是大厨实时看到的场景(动态层),最上面是安全距离规则(膨胀层)。三个图层每个栅格都写着一个 0~255 的数字,代表“走到这里有多少风险”。路径规划器就像大厨看示意图选路线——哪条路代价低、不撞墙、不碰人、还留有余量,就走哪条。这篇文章就用这张“大厨工作台示意图”串起代价地图的全部配置秘密。

岗位关联

学会这节内容,你能在真实机器人导航任务中快速定位撞墙、绕远、地图漂移等问题的根因,用 RViz 读懂每一层代价,成为团队里“会调导航”的那个人。

目录
  1. 可视化演示
  2. 代价地图概念
  3. 静态层配置
  4. 动态层配置
  5. 膨胀层配置
  6. 更新机制
  7. 路径规划
  8. 调优排查
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

通过分层架构图、膨胀层代价梯度和机器人导航动画,直观展示Costmap2D多层融合机制与安全距离配置原理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Costmap2D分层架构 静态层:加载预建地图PGM 障碍层:实时传感器更新 cost = max(layer_i.cost) 各层取最大值融合为统一代价地图

代价地图概念

大厨不会只看装修图纸就端菜跑进厨房,因为图纸上画不出此刻地上多出的食材箱,也画不出正在走动的传菜员。他真正依赖的,是图纸、实时观察和安全经验叠出来的那张“工作台示意图”。ROS 导航里的代价地图(Costmap)就是机器人的这张示意图——一张会呼吸、会更新的网格图。

为什么单靠 SLAM 地图不够?SLAM 地图像装修图纸,只记录墙和固定结构,属于“昨天的知识”。代价地图则聪明得多:它把三层信息叠在同一个栅格上,每个小格子写一个 0~255 的整数,数字越大风险越高。0 表示畅通无阻,254 表示致命障碍必须绕开,中间的数值表示“能走但要小心”。

这三层分别是:静态层(Static Layer)吃进 SLAM 先验地图,提供“墙在哪”;动态层(Obstacle Layer)订阅激光雷达或深度相机,提供“此刻谁挡路”;膨胀层(Inflation Layer)按障碍距离生成安全缓冲。最终主代价地图逐栅格取三层中的最大值——这就是“最坏情况优先”的合成规则。

大厨的示意图永远比图纸“活”:图纸是死的,眼睛是活的,安全经验是保命的。三层便签一叠,哪张标的风险大就优先信哪张——代价地图用同样的哲学,让机器人每一步都走得保守而聪明。

Cmaster=max⁡(Cstatic,  Cobstacle,  Cinflation)\displaystyle C_{\text{master}} = \max\left(C_{\text{static}},\; C_{\text{obstacle}},\; C_{\text{inflation}}\right)
主代价地图的每个栅格值,等于三个图层中该栅格的最大值。哪一层判断“这里有危险”,机器人就信哪一层,保证决策永远偏向保守和安全。
  1. C_master(主代价地图栅格值)这是规划器最终查询的数值,每个栅格只有一个,代表综合三层的风险评分。
    Cmaster\displaystyle C_{\text{master}}
  2. max 合成规则对同一栅格的三层代价取最大,相当于“三张便签里哪张写的风险高就听哪张”。
    max⁡(⋅)\displaystyle \max\left(\cdot\right)
  3. C_static(静态层代价)来自 SLAM 先验地图的固定障碍物代价,墙、柱子等不会移动的物体。
    Cstatic\displaystyle C_{\text{static}}
  4. C_obstacle(动态层代价)来自传感器实时观测的障碍物代价,会随环境变化而刷新。
    Cobstacle\displaystyle C_{\text{obstacle}}
  5. C_inflation(膨胀层代价)按栅格到最近障碍物的距离计算的安全缓冲代价,离障碍越近越高。
    Cinflation\displaystyle C_{\text{inflation}}

静态层配置

装修图纸是工作台示意图的底色。厨房结构不是每次做饭重新画的,早在装修阶段就定型了。静态层的角色完全一致:它把 SLAM 阶段构建好的先验地图(通常由 gmapping、Cartographer 生成)加载进来,告诉代价地图“墙和柱子的固定位置在哪”。

静态层为什么不可或缺?激光雷达只能看到当前视线内的障碍,看不到墙后面的结构、被货架挡住的空间。动态层负责“眼前”,静态层负责“全局”。没有这层底色,机器人在空旷走廊里会迷失约束,规划出的路径可能横穿墙体。

配置静态层通常在 costmap 的 plugins 里声明,再配一个静态层专属参数块。常用参数包括 map_topic(先验地图话题,默认 /map)、track_unknown_space(是否把未知区域当作障碍)、lethal_cost_threshold(超过该阈值的像素视为致命障碍)。

还有一个容易被忽略的关键点:静态地图数据在 map 坐标系下,而机器人实时位姿在 odom 坐标系下。代价地图要把图纸“对齐”到机器人当前所在的位置,靠的是 TF 坐标变换。

装修图纸是工作台示意图的定海神针。动态层和膨胀层再活跃,也得先把图纸铺平放正——静态层配错一个话题名或者 TF 断链,后面所有层都会跟着遭殃。

pmap=Tmap→odom⋅podom\displaystyle p_{\text{map}} = T_{\text{map} \to \text{odom}} \cdot p_{\text{odom}}
静态层把机器人坐标系下的位置转换到地图坐标系,从而把墙体像素准确地铺在机器人周围。坐标系没对齐,墙就会“漂移”。
  1. p_map(地图坐标系下的点)表示一个位置在全局地图中的坐标,静态层的栅格都以此为准。
    pmap\displaystyle p_{\text{map}}
  2. T_map→odom(坐标变换矩阵)描述 map 到 odom 两个坐标系之间的平移与旋转,由 TF 树实时维护。
    Tmap→odom\displaystyle T_{\text{map} \to \text{odom}}
  3. p_odom(机器人坐标系下的点)机器人通过轮式里程计等推算出的位置,需要靠变换矩阵才能落到地图上。
    podom\displaystyle p_{\text{odom}}
yaml5 行
static_layer:  map_topic: /map  subscribe_to_updates: true  track_unknown_space: false  lethal_cost_threshold: 100

动态层配置

图纸之外,大厨更依赖此刻的眼睛。动态层就是代价地图的“实时眼睛”:它订阅激光雷达(LaserScan)或深度相机(PointCloud2),把传感器扫到的障碍物实时标注到栅格上。有人突然挡路、临时堆了个箱子,动态层都能立刻发现。

动态层的配置核心是 observation_sources 列表。每个传感器源要指定 sensor_frame(传感器坐标帧)、data_type(LaserScan 或 PointCloud2)、topic(传感器话题名)。其中两个开关决定了行为:marking: true 表示把激光命中点标记为障碍;clearing: true 表示把激光穿过的区域设为空闲——扫到的点是障碍,扫过的区域是空地,标记与清除配合才能让地图“活”起来。

两个范围参数也值得留意:obstacle_range 决定多大的距离内把点标记为障碍,超过这个距离的点不可信;raytrace_range 决定光线在多大范围内清除障碍,通常略大于 obstacle_range,用来“擦掉”已经消失的障碍——就像大厨目光扫过,发现刚才的传菜员已走开,就在心里把那张便签撕掉。

与静态层“永不更新”不同,动态层每个更新周期都会重新处理传感器数据。它的实时性直接决定机器人避障的灵敏度:更新太快噪声大、误报多;更新太慢,人走到面前了机器人才反应过来。

大厨的眼睛不可能永远盯着一个方向。动态层的价值在于:它让代价地图不再依赖昨天的图纸,而是跟着现实世界一起流动——有人挡路就绕行,人走开了就立刻把障碍擦干净。

yaml9 行
observation_sources: laser_scanlaser_scan:  sensor_frame: base_laser_link  data_type: LaserScan  topic: /scan  marking: true  clearing: true  obstacle_range: 3.0  raytrace_range: 3.5

膨胀层配置

你端着刚出锅的热汤,绝不会贴着灶台走。膨胀层就是代价地图里的“热汤安全距离”:它在所有障碍物周围生成一圈连续变化的代价缓冲,越靠近障碍物代价越高,逼着路径规划器留出足够的安全余量。

膨胀层有三个核心参数。inflation_radius 是膨胀范围,决定考虑多远距离的代价,通常设置为机器人半径加安全刹车距离;cost_scaling_factor 是衰减系数,决定代价下降的快慢;inscribed_radius 是内切半径,代表机器人本体碰到的禁区,小于这个距离必撞。距离障碍物 d 处的膨胀代价按下式计算:

这个衰减公式是机器人“胆量”的调节旋钮。热汤端得稳不稳,就看大厨给自己留了多少安全距离——膨胀半径给的是范围,衰减系数给的是态度。参数调得好,机器人走位风骚却不碰锅沿;调不好,要么缩手缩脚绕大远,要么贴着墙胆战心惊地蹭过去。

C(d)={254,d≤rinCmax⁡e−γ(d−rin),rin<d≤Rinf0,d>Rinf\displaystyle C(d) = \begin{cases} 254, & d \le r_{\text{in}} \\ C_{\max} e^{-\gamma (d - r_{\text{in}})}, & r_{\text{in}} < d \le R_{\text{inf}} \\ 0, & d > R_{\text{inf}} \end{cases}
膨胀代价分为三段:内切半径内直接给 254 致命价;内切半径到膨胀半径之间按指数衰减;超出膨胀半径归零。cost_scaling_factor 越大,指数衰减越快,路径越贴着障碍走。
  1. d(栅格到障碍物的距离)每个栅格与最近障碍物之间的欧氏距离,是膨胀代价的自变量。
    d\displaystyle d
  2. 254 致命段当距离小于内切半径 r_in 时,机器人本体必然与障碍碰撞,代价直接封顶。
    d≤rin⇒C(d)=254\displaystyle d \le r_{\text{in}} \Rightarrow C(d) = 254
  3. 指数衰减段在内切半径与膨胀半径之间,代价随距离按自然指数衰减,r_in 处代价最高。
    C(d)=Cmax⁡e−γ(d−rin)\displaystyle C(d) = C_{\max} e^{-\gamma (d - r_{\text{in}})}
  4. γ(衰减系数)由 cost_scaling_factor 映射而来,γ 越大曲线越陡,远处的代价快速归零。
    γ∝cost_scaling_factor\displaystyle \gamma \propto \text{cost\_scaling\_factor}
yaml3 行
inflation_layer:  inflation_radius: 0.55  cost_scaling_factor: 3.0

更新机制

大厨不是看一次就把便签贴一辈子。他每隔一两秒扫一眼厨房,更新对每个位置的认识。代价地图也有自己的心跳:update_frequency 控制地图更新频率(通常 1~5 Hz),publish_frequency 控制地图发布给下游规划器的频率。更新太快浪费算力,太慢刹不住车。

仅靠“看一眼就覆盖”是不够的,单帧激光噪声可能把墙的影子当成障碍。动态层的更新用 log-odds 对数赔率做多帧融合:每来一帧观测,就在原有置信度上加一份证据,而不是推倒重来。这就是贝叶斯更新的简化形态:

配合这套置信度机制的,是“标记(marking)与清除(clearing)”双通道:命中点持续累加占据证据,射线路径持续累加空闲证据。真实环境里障碍物会移动,如果没有清除通道,机器人会看到一堆“幽灵墙”——就像大厨一直贴着某人站过的便签,直到那人再次走过才肯撕掉。

贴便签、撕便签都要果断但留记忆。一次看错不慌,持续看错才信——更新机制的本质,就是让机器人用统计的眼光看待这个世界,既不轻信也不健忘。

lt=lt−1+lobs,pt=11+e−lt\displaystyle l_t = l_{t-1} + l_{\text{obs}}, \qquad p_t = \frac{1}{1 + e^{-l_t}}
每帧观测把栅格的“占据置信度”加一个增量,再把置信度还原成 0~1 的概率。多帧累计让单次误报被稀释,真正的障碍则越积越确定。
  1. l_t(当前占据置信度)用对数赔率表示的占据程度,正数偏向“被占据”,负数偏向“空闲”。
    lt\displaystyle l_t
  2. l_obs(本次观测贡献)传感器命中障碍物时加正值,射线穿过时加负值,一帧一票。
    lobs\displaystyle l_{\text{obs}}
  3. 递推融合新置信度等于旧置信度加新观测,历史信息不会因为一帧异常数据而清零。
    lt=lt−1+lobs\displaystyle l_t = l_{t-1} + l_{\text{obs}}
  4. p_t(占据概率)将置信度通过 sigmoid 函数还原为直观概率,供代价换算使用。
    pt=11+e−lt\displaystyle p_t = \frac{1}{1 + e^{-l_t}}

路径规划

示意图是用来选路线的。大厨看一眼全局布局决定先去哪个灶台,迈出每一步时再用眼睛微调。ROS 把代价地图拆成两份,对应这两种决策尺度:全局代价地图和局部代价地图。

全局代价地图范围大、刷新慢(约 1 Hz),由 global_planner 或 navfn 使用,负责在迷宫般的厨房里规划从 A 到 B 的宏观路线——先决定“走哪个走廊、进哪个门”。局部代价地图则是一个随机器人移动的滚动小窗口,范围小、刷新快(约 5~10 Hz),由 DWA、TEB 这类本地规划器使用,负责微观避障——眼前突然出个人,立刻打方向盘。

两份代价地图共用同一套三层结构,但参数独立。全局图用静态地图铺底,保证宏观路线不穿墙;局部图靠动态层实时刷新,保证微观避障灵敏。规划器在每个栅格上计算“通行成本 = 基础代价 + 膨胀代价”,选一条累计代价最小的路径。代价地图不好,规划器再聪明也白搭:膨胀太小贴着墙走,膨胀太大死活绕远,动态层失效则直接撞人。

好厨子不仅会炒菜,更会走位。路径规划的质量下限由规划器决定,上限则由代价地图决定——全局图定大局,局部图保细节,两层配合才能让机器人在复杂厨房里端汤不洒。

yaml13 行
global_costmap:  global_frame: map  robot_base_frame: base_link  update_frequency: 1.0  static_map: true local_costmap:  global_frame: odom  robot_base_frame: base_link  update_frequency: 5.0  rolling_window: true  width: 3.0  height: 3.0

调优排查

菜咸了加糖,汤淡了加盐。代价地图的参数同样需要“试菜”调试。刚接触导航的人常遇到症状,其实都能反推出对应的参数问题。

症状一:机器人贴着墙走、过窄道胆战心惊——膨胀半径 inflation_radius 太小或 cost_scaling_factor 太大,衰减太快导致远处代价归零,规划器感受不到墙的威胁。症状二:明明空无一物的地方显示有障碍——动态层 clearing 没开,或激光噪声没过滤,成了“幽灵障碍”。症状三:地图里的墙在漂移——这不是地图的问题,而是 TF 坐标树出错或里程计标定不准,静态层的坐标变换出了偏差。

调参要讲究顺序:先静态后动态,先地图后半径。第一步确认 RViz 里静态层墙体与真实环境对齐;第二步看动态层能否实时标记和清除障碍;第三步才去调膨胀层的半径和衰减系数。调试时用 RViz 打开 Costmap 和 Costmap2D 两个显示,红色是致命区域,黄色是警告区域,绿色是安全通行区——一眼就能看出每层的工作状态。

大厨靠试吃定咸淡,工程师靠 RViz 定参数。逐层查看每个图层就像反复尝一道菜的每一味调料:先摆正图纸(静态层),再擦亮眼睛(动态层),最后调好热汤安全距离(膨胀层),机器人自然走得又快又稳。

AI 应用场景

仓储 AMR 调度避障

阶段:机器人导航与感知部署

解决的问题:传统 AGV 走固定磁条轨道,无法应对人车混行的动态仓库。使用代价地图后,静态层吃进仓库货架布局,动态层用 2D 激光实时感知拣货员和叉车,膨胀层保证货架间安全通过,多台 AMR 同时作业也不碰撞。

具体案例:某电商仓的搬运机器人原本常因前方突然出现的拣货员急停,导致订单积压。工程师将局部代价地图更新频率调到 8 Hz,动态层开启 marking+clearing 双通道,调大膨胀半径后,机器人能从 0.8 m/s 持续巡航,人走近时提前绕行,拣货效率提升 35%。

医院配送机器人人流穿梭

阶段:传感器数据处理与参数调优

解决的问题:医院走廊人流密集、病床经常临时移位,固定地图完全不可靠。利用代价地图的多层融合,静态层保留墙体结构,动态层用深度相机实时识别行人,膨胀层保障与患者的安全距离。

具体案例:配送机器人原先在高峰时段频繁卡死,导航工程师通过 RViz 逐层排查,发现 cost_scaling_factor 偏大导致路径贴着墙走,行人一出现就无路可退。调小衰减系数并增大局部代价地图滚动窗口后,机器人学会了“绕远但不贴人”,配送准时率从 71% 提升到 94%。

工厂叉车 AGV 工位对接

阶段:静态地图与动态障碍协同

解决的问题:厂区产线固定但托盘和物料盒频繁更换,对接精度要求高。静态层保证产线设备不碰撞,动态层识别新放的物料盒,膨胀层参数经过反复尝试后,让 AGV 在狭窄工位间也能毫米级停靠。

具体案例:汽车零部件厂的潜伏顶升 AGV 在改造中,工程师使用代价地图插件加载 CAD 转换的高精度先验地图,将静态层 lethal_cost_threshold 调至 80,配合动态层 PointCloud2 数据,解决了对接时货叉撞到物料盒的问题,产线换型时间缩短一半。

Python 演示

python93 行
"""Costmap膨胀代价与路径规划模拟演示ROS代价地图核心思想,无需ROS环境直接运行."""import mathimport heapq  class CostmapDemo:    def __init__(self, width, height):        self.width = width        self.height = height        self.grid = [[0] * width for _ in range(height)]     def set_obstacle(self, x, y):        self.grid[y][x] = 255     def _distance_to_obstacle(self, x, y):        best = 1e9        for oy in range(self.height):            for ox in range(self.width):                if self.grid[oy][ox] == 255:                    d = math.hypot(x - ox, y - oy)                    if d < best:                        best = d        return best     def inflate(self, inflation_radius, cost_scaling_factor):        """膨胀层:离障碍物越近代价越高,指数衰减."""        inscribed = 1.0        result = [[0] * self.width for _ in range(self.height)]        for y in range(self.height):            for x in range(self.width):                if self.grid[y][x] == 255:                    result[y][x] = 254                    continue                d = self._distance_to_obstacle(x, y)                if d > inflation_radius:                    result[y][x] = 0                elif d <= inscribed:                    result[y][x] = 253                else:                    cost = 252 * math.exp(-cost_scaling_factor * (d - inscribed))                    result[y][x] = min(253, max(0, int(cost)))        return result     def plan(self, cost_map, start, goal):        """A*在代价图上搜索,代价混合距离与膨胀代价."""        open_heap = [(0, start)]        came_from = {}        cost_so_far = {start: 0}        while open_heap:            _, current = heapq.heappop(open_heap)            if current == goal:                break            cx, cy = current            for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):                nx, ny = cx + dx, cy + dy                if not (0 <= nx < self.width and 0 <= ny < self.height):                    continue                if cost_map[ny][nx] >= 254:                    continue                step_cost = 1.0 + cost_map[ny][nx] / 255.0                new_cost = cost_so_far[current] + step_cost                if (nx, ny) not in cost_so_far or new_cost < cost_so_far[(nx, ny)]:                    cost_so_far[(nx, ny)] = new_cost                    priority = new_cost + abs(nx - goal[0]) + abs(ny - goal[1])                    heapq.heappush(open_heap, (priority, (nx, ny)))                    came_from[(nx, ny)] = current        path = []        node = goal        while node in came_from:            path.append(node)            node = came_from[node]        path.reverse()        return path  def main():    demo = CostmapDemo(12, 10)    # 竖排障碍墙,中间留一个缺口    for y in range(10):        if y != 5:            demo.set_obstacle(3, y)    cost_map = demo.inflate(inflation_radius=2.0, cost_scaling_factor=0.8)    path = demo.plan(cost_map, (0, 3), (10, 3))    print("最短路径:", path)    total = sum(cost_map[y][x] for x, y in path)    print("路径膨胀代价累计:", total)    print("代价越大说明越贴障碍,越小越安全")  if __name__ == "__main__":    main()
目的:在纯 Python 环境模拟 ROS 代价地图的两大核心步骤——膨胀层代价值计算和 A* 路径规划,展示膨胀代价如何影响机器人选路。
  1. def inflate(self, inflation_radius, cost_scaling_factor)模拟膨胀层,按指数衰减公式给障碍物周围生成代价值,对应正文的核心公式。
  2. cost = 252 * math.exp(-cost_scaling_factor * (d - inscribed))这正是膨胀衰减公式的代码形态,衰减系数越大,远处代价越小。
  3. if cost_map[ny][nx] >= 254A* 把致命代价栅格视为不可通行,机器人不会撞墙。
  4. step_cost = 1.0 + cost_map[ny][nx] / 255.0规划器把膨胀代价折算进通行成本,代价高的栅格更“贵”,路径自然绕开。
  5. priority = new_cost + abs(nx - goal[0]) + abs(ny - goal[1])A* 的启发式函数,用曼哈顿距离引导搜索朝终点方向推进。

常见误区

误区我把 `inflation_radius` 直接设成机器人的外接圆半径 0.3 m,想着正好贴着机身一圈就行,结果机器人还是频频剐蹭货架。

正解膨胀半径应该等于机器人半径 + 安全刹车距离 + 定位误差余量。ROS 里 inscribed_radius 才是“必撞禁区”的半价,inflation_radius 是让规划器提前规划规避的范围——就像你端热汤时不会贴锅走,留出的距离比锅身直径大得多。

为何常见:参数名里带“半径”二字,初学者容易把它当成机器人的物理尺寸,忽略了它本质是“规划安全余量”。

误区我以为只要 SLAM 建好图,导航就用这张图,代价地图就是把 SLAM 地图换个名字而已。

正解SLAM 地图只是代价地图静态层的输入。真正的代价地图是多层实时叠加的产物:静态层吃先验地图,动态层每秒刷新传感器障碍,膨胀层叠加安全缓冲,主图逐栅格取最大。SLAM 地图是“装修图纸”,代价地图才是“随手更新的工作台示意图”。

为何常见:先学 SLAM 再学导航的人,在 RViz 里看到两张相似的栅格图,很容易误以为是同一个东西。

误区我觉得衰减系数调大,代价衰减更快,机器人障碍物附近更安全,就把 `cost_scaling_factor` 拉到 10。

正解衰减太快意味着障碍物周围一大片栅格的代价几乎归零,规划器根本“感受不到”危险,路径会贴着障碍物高速通过——这恰恰是最危险的。安全的做法是让代价在膨胀半径内平滑衰减,让规划器有充分的避让动机。衰减系数要配合膨胀半径一起调,不能孤立追求大或小。

为何常见:初学者直觉认为“数值大=更谨慎”,忽视了指数衰减把远处栅格全变成 0 的反效果。

误区我以为激光一照到障碍物,代价地图就立刻把这个位置永久标红,下一秒就绕开。

正解动态层基于 log-odds 多帧融合,单帧观测只是“投一票”,要连续几帧确认障碍才可靠;同时 clearing 通道会不断清除射线经过区域的障碍。障碍消失了,也要等射线扫过才会擦除——这既抗噪声,也带来了响应延迟。

为何常见:UI 动画里障碍瞬间出现很直观,让人忽略了背后统计融合的延迟,实际调参会发现“标记得慢、清除也慢”。

误区我以为静态层加载完就永远不动,机器人导航出问题只会去调动态层。

正解静态层的地图内容确实不变,但它与机器人的对齐依赖 TF 坐标变换。里程计漂移、IMU 未校准、TF 树配置错误,都会让静态墙体在代价地图上“漂移”看起来像障碍在动。排查时先看 rosrun tf view_frames,确认坐标树正常,再怀疑数据层。

为何常见:"static"这个词太有迷惑性,让人忽略它背后还有坐标系对齐这个动态环节。

面试题

Q1. 关于ROS代价地图的图层构成,下列说法正确的是

单选题 · easy

  • A.静态层代表实时传感器障碍
  • B.动态层负责加载SLAM地图
  • C.静态层来自SLAM先验地图← 正确答案
  • D.膨胀层不参与代价合成

答案:C。静态层吃进 SLAM 构建的先验地图,提供固定结构信息;动态层才负责实时传感器障碍;膨胀层参与合成且是关键安全层。就像图纸、眼睛、安全距离三层便签,各司其职。

Q2. 代价地图中栅格代价值254通常表示

单选题 · easy

  • A.完全空闲可自由通行
  • B.致命障碍不可通行← 正确答案
  • C.未知区域等待探索
  • D.膨胀代价最低区域

答案:B。254 是致命代价,代表机器人该栅格位置必撞,规划器不得通行。0 表示空闲,未知区域通常取中间值或单独通道处理。相当于便签上写“此路绝对不通”。

Q3. 静态层地图数据通常来源于

单选题 · easy

  • A.激光雷达实时扫描结果
  • B.SLAM构建的先验地图← 正确答案
  • C.深度相机点云数据
  • D.轮式编码器里程计

答案:B。静态层由 map_server 加载 SLAM 阶段构建好的先验地图,是装修图纸;激光雷达实时扫描和深度相机点云是动态层的输入;里程计提供位姿推算,不是地图来源。

Q4. cost_scaling_factor参数增大后,膨胀代价会

单选题 · mid

  • A.衰减更快,路径贴障碍走← 正确答案
  • B.衰减更慢,路径绕大远
  • C.完全归零不再生效
  • D.膨胀半径自动增大

答案:A。衰减系数越大,指数衰减曲线越陡,远处栅格代价迅速降为 0,规划器感受不到威胁,路径就贴着障碍走。它控制的是“胆量曲线”的斜率,而非半径范围。

Q5. 动态层中marking与clearing的作用是

单选题 · mid

  • A.标记障碍与清除误报← 正确答案
  • B.压缩地图与解压地图
  • C.加载与保存地图文件
  • D.膨胀与收缩代价区域

答案:A。marking 把传感器命中点标记为占据,clearing 把射线穿过区域标记为空闲并清除“幽灵障碍”。两者配合才能让动态地图跟随真实世界流动,类似大厨贴便签和撕便签。

Q6. 局部代价地图相比全局代价地图

单选题 · mid

  • A.范围更小且更新更快← 正确答案
  • B.范围更大且更新更慢
  • C.完全替代全局地图
  • D.只包含静态图层

答案:A。局部代价地图用滚动窗口跟随机器人,范围小、更新频率高(约 5~10 Hz),用于微观避障;全局代价地图范围大、刷新慢,用于宏观规划。两者同时存在、分工配合,完全替代和只含静态层都不对。

Q7. 增大inflation_radius最可能导致的后果是

单选题 · hard

  • A.路径绕远且窄道不可过← 正确答案
  • B.障碍物识别速度变快
  • C.传感器更新频率变高
  • D.地图分辨率自动提升

答案:A。膨胀半径扩大后,障碍物周边大片区域代价升高,路径规划器会绕更大的圈;窄道两侧膨胀区可能连成一片形成“代价墙”,导致原本能过的通道变成不可通行。它不直接影响识别速度、更新频率或分辨率。

Q8. log-odds更新相比直接覆盖的优势是

单选题 · hard

  • A.多帧融合抗单帧噪声← 正确答案
  • B.计算速度一定更快
  • C.无需传感器输入数据
  • D.可以省略膨胀层配置

答案:A。log-odds 在历史置信度上累加观测证据,单帧噪声只投一票,被多帧稀释;直接覆盖一帧误报就把障碍标死。代价是多算一点数学,但换来稳定可靠。它当然需要传感器输入,也与是否配置膨胀层无关。

Q9. 下列属于动态层observation_sources配置内容的有

多选题 · mid

  • A.data_type指定数据类型← 正确答案
  • B.topic指定传感器话题← 正确答案
  • C.inflation_radius设置膨胀半径
  • D.cost_scaling_factor控制衰减

答案:AB。动态层配置核心是 observation_sources 列表,每项含 sensor_frame、data_type、topic、marking、clearing 等字段。inflation_radius 和 cost_scaling_factor 属于膨胀层参数,不在动态层配置中。

Q10. 代价地图中静态墙体出现漂移的可能原因有

多选题 · extreme

  • A.TF树坐标变换配置错误← 正确答案
  • B.里程计标定不准累积漂移← 正确答案
  • C.静态地图文件本身损坏
  • D.膨胀半径被调得过大

答案:AB。墙体“漂移”本质是地图与机器人坐标没有对齐,TF 树错误或里程计漂移都会让对齐失效。静态地图文件损坏通常导致地图缺失或空白,不是漂移;膨胀半径只影响代价分布,不改变障碍位置。