想象你是一家繁忙餐厅的大厨。厨房里墙、灶台、岛台的位置是固定的,装修图纸上画得清清楚楚;但此刻地上有刚搬来的食材箱,传菜员来回穿梭,灶台上的油锅正冒着热气。你不会只看装修图纸就闷头冲过去——你会把图纸、眼前看到的人和“离热锅保持安全距离”的经验叠在一起,在脑子里形成一张“当下厨房工作台示意图”。ROS里这张会实时变化的示意图,就叫代价地图(Costmap)。 这张示意图不是一张图,而是三层“便签”叠出来的:最底下是装修图纸(静态层),中间是大厨实时看到的场景(动态层),最上面是安全距离规则(膨胀层)。三个图层每个栅格都写着一个 0~255 的数字,代表“走到这里有多少风险”。路径规划器就像大厨看示意图选路线——哪条路代价低、不撞墙、不碰人、还留有余量,就走哪条。这篇文章就用这张“大厨工作台示意图”串起代价地图的全部配置秘密。
学会这节内容,你能在真实机器人导航任务中快速定位撞墙、绕远、地图漂移等问题的根因,用 RViz 读懂每一层代价,成为团队里“会调导航”的那个人。
可视化演示
通过分层架构图、膨胀层代价梯度和机器人导航动画,直观展示Costmap2D多层融合机制与安全距离配置原理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Costmap2D分层架构 静态层:加载预建地图PGM 障碍层:实时传感器更新 cost = max(layer_i.cost) 各层取最大值融合为统一代价地图
代价地图概念
大厨不会只看装修图纸就端菜跑进厨房,因为图纸上画不出此刻地上多出的食材箱,也画不出正在走动的传菜员。他真正依赖的,是图纸、实时观察和安全经验叠出来的那张“工作台示意图”。ROS 导航里的代价地图(Costmap)就是机器人的这张示意图——一张会呼吸、会更新的网格图。
为什么单靠 SLAM 地图不够?SLAM 地图像装修图纸,只记录墙和固定结构,属于“昨天的知识”。代价地图则聪明得多:它把三层信息叠在同一个栅格上,每个小格子写一个 0~255 的整数,数字越大风险越高。0 表示畅通无阻,254 表示致命障碍必须绕开,中间的数值表示“能走但要小心”。
这三层分别是:静态层(Static Layer)吃进 SLAM 先验地图,提供“墙在哪”;动态层(Obstacle Layer)订阅激光雷达或深度相机,提供“此刻谁挡路”;膨胀层(Inflation Layer)按障碍距离生成安全缓冲。最终主代价地图逐栅格取三层中的最大值——这就是“最坏情况优先”的合成规则。
大厨的示意图永远比图纸“活”:图纸是死的,眼睛是活的,安全经验是保命的。三层便签一叠,哪张标的风险大就优先信哪张——代价地图用同样的哲学,让机器人每一步都走得保守而聪明。
- C_master(主代价地图栅格值)这是规划器最终查询的数值,每个栅格只有一个,代表综合三层的风险评分。
- max 合成规则对同一栅格的三层代价取最大,相当于“三张便签里哪张写的风险高就听哪张”。
- C_static(静态层代价)来自 SLAM 先验地图的固定障碍物代价,墙、柱子等不会移动的物体。
- C_obstacle(动态层代价)来自传感器实时观测的障碍物代价,会随环境变化而刷新。
- C_inflation(膨胀层代价)按栅格到最近障碍物的距离计算的安全缓冲代价,离障碍越近越高。
静态层配置
装修图纸是工作台示意图的底色。厨房结构不是每次做饭重新画的,早在装修阶段就定型了。静态层的角色完全一致:它把 SLAM 阶段构建好的先验地图(通常由 gmapping、Cartographer 生成)加载进来,告诉代价地图“墙和柱子的固定位置在哪”。
静态层为什么不可或缺?激光雷达只能看到当前视线内的障碍,看不到墙后面的结构、被货架挡住的空间。动态层负责“眼前”,静态层负责“全局”。没有这层底色,机器人在空旷走廊里会迷失约束,规划出的路径可能横穿墙体。
配置静态层通常在 costmap 的 plugins 里声明,再配一个静态层专属参数块。常用参数包括 map_topic(先验地图话题,默认 /map)、track_unknown_space(是否把未知区域当作障碍)、lethal_cost_threshold(超过该阈值的像素视为致命障碍)。
还有一个容易被忽略的关键点:静态地图数据在 map 坐标系下,而机器人实时位姿在 odom 坐标系下。代价地图要把图纸“对齐”到机器人当前所在的位置,靠的是 TF 坐标变换。
装修图纸是工作台示意图的定海神针。动态层和膨胀层再活跃,也得先把图纸铺平放正——静态层配错一个话题名或者 TF 断链,后面所有层都会跟着遭殃。
- p_map(地图坐标系下的点)表示一个位置在全局地图中的坐标,静态层的栅格都以此为准。
- T_map→odom(坐标变换矩阵)描述 map 到 odom 两个坐标系之间的平移与旋转,由 TF 树实时维护。
- p_odom(机器人坐标系下的点)机器人通过轮式里程计等推算出的位置,需要靠变换矩阵才能落到地图上。
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,用来“擦掉”已经消失的障碍——就像大厨目光扫过,发现刚才的传菜员已走开,就在心里把那张便签撕掉。
与静态层“永不更新”不同,动态层每个更新周期都会重新处理传感器数据。它的实时性直接决定机器人避障的灵敏度:更新太快噪声大、误报多;更新太慢,人走到面前了机器人才反应过来。
大厨的眼睛不可能永远盯着一个方向。动态层的价值在于:它让代价地图不再依赖昨天的图纸,而是跟着现实世界一起流动——有人挡路就绕行,人走开了就立刻把障碍擦干净。
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 处的膨胀代价按下式计算:
这个衰减公式是机器人“胆量”的调节旋钮。热汤端得稳不稳,就看大厨给自己留了多少安全距离——膨胀半径给的是范围,衰减系数给的是态度。参数调得好,机器人走位风骚却不碰锅沿;调不好,要么缩手缩脚绕大远,要么贴着墙胆战心惊地蹭过去。
cost_scaling_factor 越大,指数衰减越快,路径越贴着障碍走。- d(栅格到障碍物的距离)每个栅格与最近障碍物之间的欧氏距离,是膨胀代价的自变量。
- 254 致命段当距离小于内切半径 r_in 时,机器人本体必然与障碍碰撞,代价直接封顶。
- 指数衰减段在内切半径与膨胀半径之间,代价随距离按自然指数衰减,r_in 处代价最高。
- γ(衰减系数)由 cost_scaling_factor 映射而来,γ 越大曲线越陡,远处的代价快速归零。
inflation_layer: inflation_radius: 0.55 cost_scaling_factor: 3.0
更新机制
大厨不是看一次就把便签贴一辈子。他每隔一两秒扫一眼厨房,更新对每个位置的认识。代价地图也有自己的心跳:update_frequency 控制地图更新频率(通常 1~5 Hz),publish_frequency 控制地图发布给下游规划器的频率。更新太快浪费算力,太慢刹不住车。
仅靠“看一眼就覆盖”是不够的,单帧激光噪声可能把墙的影子当成障碍。动态层的更新用 log-odds 对数赔率做多帧融合:每来一帧观测,就在原有置信度上加一份证据,而不是推倒重来。这就是贝叶斯更新的简化形态:
配合这套置信度机制的,是“标记(marking)与清除(clearing)”双通道:命中点持续累加占据证据,射线路径持续累加空闲证据。真实环境里障碍物会移动,如果没有清除通道,机器人会看到一堆“幽灵墙”——就像大厨一直贴着某人站过的便签,直到那人再次走过才肯撕掉。
贴便签、撕便签都要果断但留记忆。一次看错不慌,持续看错才信——更新机制的本质,就是让机器人用统计的眼光看待这个世界,既不轻信也不健忘。
- l_t(当前占据置信度)用对数赔率表示的占据程度,正数偏向“被占据”,负数偏向“空闲”。
- l_obs(本次观测贡献)传感器命中障碍物时加正值,射线穿过时加负值,一帧一票。
- 递推融合新置信度等于旧置信度加新观测,历史信息不会因为一帧异常数据而清零。
- p_t(占据概率)将置信度通过 sigmoid 函数还原为直观概率,供代价换算使用。
路径规划
示意图是用来选路线的。大厨看一眼全局布局决定先去哪个灶台,迈出每一步时再用眼睛微调。ROS 把代价地图拆成两份,对应这两种决策尺度:全局代价地图和局部代价地图。
全局代价地图范围大、刷新慢(约 1 Hz),由 global_planner 或 navfn 使用,负责在迷宫般的厨房里规划从 A 到 B 的宏观路线——先决定“走哪个走廊、进哪个门”。局部代价地图则是一个随机器人移动的滚动小窗口,范围小、刷新快(约 5~10 Hz),由 DWA、TEB 这类本地规划器使用,负责微观避障——眼前突然出个人,立刻打方向盘。
两份代价地图共用同一套三层结构,但参数独立。全局图用静态地图铺底,保证宏观路线不穿墙;局部图靠动态层实时刷新,保证微观避障灵敏。规划器在每个栅格上计算“通行成本 = 基础代价 + 膨胀代价”,选一条累计代价最小的路径。代价地图不好,规划器再聪明也白搭:膨胀太小贴着墙走,膨胀太大死活绕远,动态层失效则直接撞人。
好厨子不仅会炒菜,更会走位。路径规划的质量下限由规划器决定,上限则由代价地图决定——全局图定大局,局部图保细节,两层配合才能让机器人在复杂厨房里端汤不洒。
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 演示
"""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()
def inflate(self, inflation_radius, cost_scaling_factor)模拟膨胀层,按指数衰减公式给障碍物周围生成代价值,对应正文的核心公式。cost = 252 * math.exp(-cost_scaling_factor * (d - inscribed))这正是膨胀衰减公式的代码形态,衰减系数越大,远处代价越小。if cost_map[ny][nx] >= 254A* 把致命代价栅格视为不可通行,机器人不会撞墙。step_cost = 1.0 + cost_map[ny][nx] / 255.0规划器把膨胀代价折算进通行成本,代价高的栅格更“贵”,路径自然绕开。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代价地图的图层构成,下列说法正确的是
- A.静态层代表实时传感器障碍
- B.动态层负责加载SLAM地图
- C.静态层来自SLAM先验地图← 正确答案
- D.膨胀层不参与代价合成
答案:C。静态层吃进 SLAM 构建的先验地图,提供固定结构信息;动态层才负责实时传感器障碍;膨胀层参与合成且是关键安全层。就像图纸、眼睛、安全距离三层便签,各司其职。
Q2. 代价地图中栅格代价值254通常表示
- A.完全空闲可自由通行
- B.致命障碍不可通行← 正确答案
- C.未知区域等待探索
- D.膨胀代价最低区域
答案:B。254 是致命代价,代表机器人该栅格位置必撞,规划器不得通行。0 表示空闲,未知区域通常取中间值或单独通道处理。相当于便签上写“此路绝对不通”。
Q3. 静态层地图数据通常来源于
- A.激光雷达实时扫描结果
- B.SLAM构建的先验地图← 正确答案
- C.深度相机点云数据
- D.轮式编码器里程计
答案:B。静态层由 map_server 加载 SLAM 阶段构建好的先验地图,是装修图纸;激光雷达实时扫描和深度相机点云是动态层的输入;里程计提供位姿推算,不是地图来源。
Q4. cost_scaling_factor参数增大后,膨胀代价会
- A.衰减更快,路径贴障碍走← 正确答案
- B.衰减更慢,路径绕大远
- C.完全归零不再生效
- D.膨胀半径自动增大
答案:A。衰减系数越大,指数衰减曲线越陡,远处栅格代价迅速降为 0,规划器感受不到威胁,路径就贴着障碍走。它控制的是“胆量曲线”的斜率,而非半径范围。
Q5. 动态层中marking与clearing的作用是
- A.标记障碍与清除误报← 正确答案
- B.压缩地图与解压地图
- C.加载与保存地图文件
- D.膨胀与收缩代价区域
答案:A。marking 把传感器命中点标记为占据,clearing 把射线穿过区域标记为空闲并清除“幽灵障碍”。两者配合才能让动态地图跟随真实世界流动,类似大厨贴便签和撕便签。
Q6. 局部代价地图相比全局代价地图
- A.范围更小且更新更快← 正确答案
- B.范围更大且更新更慢
- C.完全替代全局地图
- D.只包含静态图层
答案:A。局部代价地图用滚动窗口跟随机器人,范围小、更新频率高(约 5~10 Hz),用于微观避障;全局代价地图范围大、刷新慢,用于宏观规划。两者同时存在、分工配合,完全替代和只含静态层都不对。
Q7. 增大inflation_radius最可能导致的后果是
- A.路径绕远且窄道不可过← 正确答案
- B.障碍物识别速度变快
- C.传感器更新频率变高
- D.地图分辨率自动提升
答案:A。膨胀半径扩大后,障碍物周边大片区域代价升高,路径规划器会绕更大的圈;窄道两侧膨胀区可能连成一片形成“代价墙”,导致原本能过的通道变成不可通行。它不直接影响识别速度、更新频率或分辨率。
Q8. log-odds更新相比直接覆盖的优势是
- A.多帧融合抗单帧噪声← 正确答案
- B.计算速度一定更快
- C.无需传感器输入数据
- D.可以省略膨胀层配置
答案:A。log-odds 在历史置信度上累加观测证据,单帧噪声只投一票,被多帧稀释;直接覆盖一帧误报就把障碍标死。代价是多算一点数学,但换来稳定可靠。它当然需要传感器输入,也与是否配置膨胀层无关。
Q9. 下列属于动态层observation_sources配置内容的有
- 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. 代价地图中静态墙体出现漂移的可能原因有
- A.TF树坐标变换配置错误← 正确答案
- B.里程计标定不准累积漂移← 正确答案
- C.静态地图文件本身损坏
- D.膨胀半径被调得过大
答案:AB。墙体“漂移”本质是地图与机器人坐标没有对齐,TF 树错误或里程计漂移都会让对齐失效。静态地图文件损坏通常导致地图缺失或空白,不是漂移;膨胀半径只影响代价分布,不改变障碍位置。