多AGV路径规划系统的验收测试,和普通功能测试完全是两码事。普通功能测试回答的是“这个功能能不能跑通”,而验收测试回答的是“这个系统是否达到了合同或需求里承诺的性能和可靠性指标”。前者是开发过程中的质量保障,后者是交付前的判定关卡。我最近正好完整走完了一个多AGV路径规划系统的验收测试框架搭建,踩了不少坑,也沉淀了一套可以复用的方法论,这篇就来把整个框架的设计思路、测试项拆解和实测过程掰开揉碎讲清楚。
1. 多AGV路径规划系统验收前的状态摸底
很多人拿到验收测试任务就直接写用例、铺场景,这是个很危险的思路。验收测试和开发测试最大的差异在于:你是在替甲方或决策层做出“能不能交付”的判定,这意味着你的测试框架必须具备可追溯性、可复现性和清晰的判定标准,而不是“能跑就过”。
1.1 验收测试和开发测试的差异
开发阶段的测试,说穿了是陪开发人员一起找bug,发现得越多越好,测试人员和开发是协作关系。验收测试不一样,它更像是在做审计,你得把系统的能力边界完整地测量出来,然后对照需求条目逐项给结论。
一个典型的这类项目,被测系统通常由几个模块组成:地图管理服务、路径规划引擎、多车调度中枢、车端运动控制器和通信中间件。验收的重点不会落在每个模块的内部实现上,而是落在“多车并发时路径规划是否真的不冲突”“高负载下任务完成时间是否仍然可控”“系统异常后能否自恢复”这些系统级行为上。
我通常在验收前会先做一件事:拉一张系统架构与数据流表。把每一个核心模块的对外接口、输入输出、依赖关系和可观测性指标列清楚。这样设计测试用例时就不至于在黑盒里瞎猜,也方便在出问题时快速划定排查范围。
| 模块 | 对外接口 | 关键输入 | 关键输出 | 可观测指标 |
|---|---|---|---|---|
| 地图管理服务 | 地图加载、图层更新 | 地图文件、障碍物坐标 | 栅格/拓扑地图数据 | 加载耗时、更新延迟 |
| 路径规划引擎 | 单车路径规划、路径重规划 | 起点、终点、当前位姿、障碍物 | 无碰撞路径点序列 | 规划耗时、路径长度、平滑度 |
| 多车调度中枢 | 任务分配、动态优先级调整 | 任务队列、车辆状态、位置 | 车辆指派、时间窗 | 吞吐量、任务等待时间、死锁次数 |
| 车端运动控制器 | 指令下发、状态上报 | 路径点、速度、当前位姿 | 电机指令、里程计、位姿 | 跟踪误差、停车精度 |
| 通信中间件 | 数据订阅/发布 | 传感器数据、指令 | 序列化消息 | 端到端延迟、丢包率 |
这张表既是测试设计的地图,也是后期争议仲裁的依据。比如在实测中发现某辆车的停车精度总是超差,通过这张表就可以先判断是车端控制问题还是路径末端的规划点数不够,而不是直接劈头盖脸定位到某一个模块。
1.2 验收前先搞清楚被测系统的几项关键参数
在动手设计测试框架前,还有一个很重要的工作是做参数摸底。做验收测试不能拿“我们认为系统应该支持20台车”这种模糊表述来设计,要把需求里的信息转化成可测量的参数。
这个项目当时的关键参数如下:
- 地图尺寸:约120m × 80m的室内仓储场景
- AGV数量:最多并发调度15台
- 单台AGV最大速度:1.5 m/s
- 任务类型:搬运、充电、异常回收、手动插单
- 多车冲突消解机制:预留路口申请制 + 路径代价动态调整
- 验收关键指标:并发15台车时吞吐量不低于80个任务/小时,单任务平均完成时间不高于65秒,不允许出现系统性死锁(偶发死锁自动恢复时间不超过20秒)
这些参数直接决定了测试用例的负载设计。比如吞吐量指标意味着测试时至少需要持续压入足够长时间的任务流,才能统计出稳定的每小时数据;平均完成时间则意味着需要对不同起终点距离的任务做加权统计,而不是只测近距离任务。
注意:验收测试前一定要拿到签字确认的需求指标。曾有项目在验收评审时才发现需求方和开发方对“平均完成时间”的理解不一致,一方指的是纯路径行驶时间,另一方指的是从任务下发到车辆完成搬运整个周期。这种口径问题越早对齐越好。
2. 搭建测试框架的核心设计思路
验收测试框架的设计,核心就三件事:场景怎么来、数据怎么采、结论怎么出。场景决定了测什么,数据决定了能用什么依据下结论,结论格式则直接关系到验收能否顺利收敛。
2.1 用仿真先行还是实车先行
很多测试团队一上来就铺实车场测,几百平米的场地摆满了车,看上去声势浩大,但两个问题很致命:一是场景复杂度不可控,现场总有不稳定因素干扰测试数据的可信度;二是可复现性极差,哪怕是同一个任务序列,稍微受一点环境干扰结果就漂了,验收评审时很难拿出让人信服的复现证据。
我个人的做法是“仿真先行、实车复核”的双轨模式。先在仿真环境里把大部分功能性和边界性用例跑完,再用实车环境跑关键场景和随机压力场景。仿真负责“找问题”,实车负责“给答案”。仿真环境可以批量执行、自动比对、注入各种极端工况;实车环境用来验证仿真结果在真实世界中是否成立,以及采集那些仿真给不了的物理层指标,比如停车精度、轮速跟踪响应。
这套双轨模式还有一个隐藏优势:一旦在实车阶段暴露了路径规划问题,可以迅速在仿真环境里回放同一场景做原因定位,不用占用有限的实车测试窗口。
2.2 可量化的观测指标体系怎么定
多AGV系统的验收指标,如果只盯任务完成率这一个数,会掩盖非常多的潜在问题。一个系统可能是所有任务都完成了,但其中几辆车频繁停车等待、路径绕行严重,这种状态在吞吐量指标上往往不怎么难看,可一旦作业量再往上顶一点,系统就会瞬间劣化。所以在设计框架时,我建立了一套多层级观测指标:
第一层是结果指标:任务完成数、任务完成率、平均任务完成时间、吞吐量。
第二层是过程指标:路径规划平均耗时、路径规划超时次数、车辆平均行驶速度与最大速度比值、停车等待时间占比、死锁发生次数、死锁自动恢复耗时。
第三层是细粒度指标:跟踪误差均方根值、停车到位精度、通信延迟P95值、地图更新后的路径切换延迟。
这三层指标不是平均用力,而是按测试目的各有侧重。功能测试侧重第一层,性能测试和压力测试看重第二层,耐久与稳定性测试则必须落到第三层。为了让这些指标在验收时有据可查,每一轮测试都需要保留原始数据,光有汇总报告是不够的。
2.3 数据链路与测试闭环怎么打通
测试框架的另一个设计关键点在于“数据闭环”。简单说,就是让所有的测试指令、车辆状态、系统日志和最终结论在同一个时间轴上对齐。没有这个闭环,你在问题排查时就会发现每个模块都在说自己正常,但现场的感知就是“系统不对”。
具体做法是,在测试部署时挂接一套统一的时间同步与日志采集服务:所有下发的任务指令都带上全局时间戳;每台AGV的状态上报也要做时间同步;调度中枢的决策日志、路径规划的请求与响应记录、通信中间件的消息帧,全部汇总到同一个数据仓库。这样在分析某个异常场景时,就能像放电影一样沿着时间轴把系统各部分的动作精确还原。
3. 测试用例设计与核心场景拆解
场景设计是整个验收测试框架里最容易做泛却最难做准的部分。泛,是因为多AGV系统的状态空间实在太大,随便组合一下就是天文数字;准,是因为真正有效的测试场景,往往要从需求指标和过往缺陷里反推出来。我把测试场景分成三大类:单车基础能力、多车协同能力、异常恢复能力。
3.1 单车基础路径测试:别小看这些“简单”场景
单车测试是看起来最不起眼但最容易出隐蔽问题的一类。很多人觉得单车测试无非是让一辆车从A点走到B点,看看能不能走到、停得准不准。但真正做起来,要在设计上覆盖到下面这些变体。
- 路径穿障:在起点到终点的直线中途布置障碍物,验证规划器能否生成绕行路径。
- 狭窄通道:通道宽度只比车体宽度富余10cm~20cm,验证规划器在极限净空下的通过性判断。
- 掉头空间受限:终点区域无法一次转弯完成,需要多次揉库动作,验证路径平滑性与控制器的配合。
- 动态障碍物切入:车行驶到一半时,侧方突然出现一个障碍点,验证路径重规划的触发灵敏度和新路径的连贯性。
这类用例的设计原则是“参数化”。比如狭窄通道用例,通道宽度不能写死,要作为测试参数用配置文件下发,这样可以很容易扫出一组宽度梯度:从富裕宽度逐渐收窄,直到系统判定不可通行,从而画出通过性边界。这个边界就是验收评审时非常有说服力的数据。
实操心得:单车用例也别忘了记录“规划耗时”和“路径长度”这两个过程指标。很多时候性能瓶颈不在调度层而在单车的路径规划引擎——规划耗时偶尔飙到几百毫秒在单车上看不出来,但一旦15台车同时发起规划请求,引擎资源就被打满了。
3.2 多车协同场景测试:重点在冲突压力的构建方式
多车协同场景是这套框架的重头戏,也是最难设计得科学的部分。常见的错误做法是只做“多车同时搬运”的简单组合——虽然并发车辆多,但起终点分布很散,车辆之间的路径交集很少,这种场景的冲突检测能力验证效果非常有限。
我在这类项目的测试场景里,专门设计了几组高冲突概率的作业流:
- 对向拥堵流:两组车辆从地图两端分别驶向对方的出发区,路径在地图中部形成高度交叠。
- 汇聚式任务流:多个起点不同的任务同时指向同一个目标站点,模拟多车同时来抢一个装卸位。
- 交叉路口重载:让连续任务流反复穿过一个窄路口,验证路口资源分配算法会不会在小空间内形成排队风暴。
这些场景构建的核心技巧是任务下发时间的相位控制。比如汇聚式任务流,如果任务下发间隔过大,先到的车可能已经完成任务离开了,前车不会对后车产生实际冲突压力。我通常会通过仿真预先跑一遍冲突热度,然后微调任务下发间隔,确保目标区域内车辆重叠率达到预设的强度。
在判据设计上,多车协同场景不能只看是否发生碰撞。要记录整个任务流执行过程中,所有车辆的瞬时停车次数、最长停车等待时间、以及车辆在路口区域的排队长度。这些数据反映的是系统在冲突压力下的“顺畅度”。有的系统能保证不撞,但是车辆在原地等很久才被放行,这种状态在仓库作业现场就是不可接受的。
3.3 故障注入与异常恢复测试:验收时容易被漏掉但现场必炸的场景
健壮性测试在自研系统的验收框架里尤其不能省。实际运行环境中,AGV毕竟是移动设备,通信掉线、定位跳变、任务执行超时这些问题几乎无法完全避免。系统能不能扛住,必须靠测试框架主动注故障去验证。
我在框架里设计了几类故障注入用例:
- 车辆通信中断:调度中枢下发任务后,人为断掉某台车的通信链路30秒,再恢复通信。观察中枢是否超时判定、任务是否被重新分配、车端恢复后如何重新同步状态。
- 节点实例宕机:整个调度服务或地图服务在一台设备上运行,人为杀掉进程,观察服务恢复后车辆是否重新建立连接、任务状态是否丢失。
- 位置跳变注入:在车辆行驶过程中人为修改地面上报的坐标,制造一个明显不连续的位置跳变,观察系统能否识别异常、是否触发急停、路径规划是否能绕开这个“虚假位置”。
- 任务非法参数:通过接口直接下发一个终点在地图边界之外的非法任务,观察系统是报错还是陷入未知状态。
故障注入用例的判据是:系统必须能在规定时间内完成感知、决策和恢复三步动作。比如通信中断30秒后,车辆应该能在恢复后自动接续任务,而不是需要人工介入复位;位置跳变注入时,调度系统应该能结合航位推算或其他传感器判定跳变异常,而不是盲目沿着错误位置继续派车。
4. 多AGV系统验收测试的实测执行过程
场景设计完毕,接下来是执行环节。验收测试的现场执行,最怕的就是打乱仗。我习惯把执行过程分成三个固定的阶段:环境合规检查、基准性能标定、正式测试与回归确认。节奏清晰,每一步都有明确的导出物,评审会上拿出来的不只是测试日志,而是一条完整执行的证据链。
4.1 部署环境与时序对齐的准备细节
测试正式开跑前,有一项容易被忽视的准备工作:数据时序一致性检查。不管你用的是什么通信框架,一旦系统里各节点的时间基准没有对齐,后面所有分析都像在流沙上盖楼。这个项目在第一次仿真联调时,就出现了“地图服务认为车辆已到达,调度中枢却始终显示车辆还在途中”的现象,追了半天根因,最后发现是容器内时间未与宿主机同步,两个服务的时间戳差了整整6秒。
所以第一步,先做全套时钟同步确认。所有参与测试的物理机和容器,必须使用同一套时间同步源,并在正式测试前通过日志里的时间戳,反推几个跨服务事件的延迟是否在预期范围内。
第二步是地图版本与车辆初始位姿的校准。很多验收争议都源于“不同测试轮次用的地图不一致”。设计中要在测试部署说明里写清楚:本次测试使用的地图文件名、分辨率、障碍物膨胀半径、车辆起始站点ID、充电站点ID。每一轮测试开始前,由脚本人为比对地图文件校验值,避免测试过程中不留神加载了旧版本。
第三步才是下发任务流。任务流里每个任务都要带全局唯一ID,并记录下发的单调时间戳。后续做吞吐量计算时,不需要再去日志里翻找“任务什么时候开始”,直接用这个时间戳作为查询入口就能贯通整条链路。
4.2 并发压力与端到端性能的实测操作
当环境合规检查全部通过,进入正式测试阶段。我习惯的做法是分三轮递进:
第一轮,把单车基础用例全部跑完。这一步相当于检查每辆车的能力基线。如果单车基本功都不稳定,后面多车并发时的任何性能抖动都无法归因,因为可能是某一辆车的控制差异贡献了很大一部分噪声。
第二轮,进入多车协同场景。这一轮是把场景和控制参数结合起来跑。每一组场景至少执行五遍以上,记录每遍的任务完成时间、死锁次数和其他过程指标。为什么要跑多遍?因为多AGV系统带有较强的时序敏感性,哪怕任务序列完全一样,车辆之间的微小时序差异也会导致执行轨迹不完全一致。单遍结果只能算是一次样本,只有多遍统计才能给出稳定的均值和方差数据。
第三轮,压力测试。压力测试的任务量不是拍脑袋定的,要按需求里的“15台车、每小时80个任务”换算成稳定的任务注入速率。简单算一笔账:80个任务每小时,队列深度至少要留出裕量。系统在任务积压状态下能不能保持稳定调度,和任务稀疏时是两种完全不同的表现。压力测试至少持续跑一个完整班次时长,才能把疲劳性问题和偶发性死锁统计出来。
在执行过程中,我会让测试脚本同步抓取两类数据:一类是任务级的业务数据,比如完成时间、等待时长;一类是系统级日志,比如路径规划耗时、消息延迟。任务级数据用于最终验收指标的统计计算,系统级日志用于任何异常发生后的回溯分析。
4.3 死锁判定的判据与回归确认机制
死锁在多AGV系统里是个敏感词。不是说系统不能发生任何死锁,而是在设计上要明确“什么程度的死锁可以接受”。我们当时和研发对齐了一套判定口径:
- 系统性死锁:同一场景重复触发、且系统无法自动恢复的死锁,验收定为不通过。
- 偶发性死锁:由于极端时序巧合触发、但系统能在20秒内自动解锁并继续执行任务的,验收可判为通过,但要给出发生次数和最长恢复时间。
- 人工干预死锁:系统自行无法恢复,需要调度员手动介入解锁的,验收基本就悬了。
这个口径一定要在测试设计阶段就确认下来,不能等出现死锁后临时争论。当时就遇到过一场扯皮:仿真环境里跑出了一个三车循环等待的死锁场景,其中两辆车的任务已经超时,但调度系统在18秒后通过路径重算自动解除僵局。按这套口径,这属于偶发性死锁且自动恢复合格,记录时长后放行;但如果没有提前对齐,这种场景很可能被直接放大成“系统有严重缺陷”。
回归确认机制也不可少。每次正式测试跑完,要将异常场景单独抽出来,在仿真环境里重新执行一遍,比对两次行为是否一致。这种回归不是为了证明系统没问题,而是为了确保后续排查时手里有“可复现的钥匙”。
5. 常见问题与排查技巧实录
在实际搭建和执行这套验收测试框架的过程中,现场发生过不少让人头痛的问题。整理几条对后续类似项目最有借鉴价值的,做成一个速查性的记录。
| 问题现象 | 可能的根因 | 排查思路 |
|---|---|---|
| 多车并发时任务完成时间明显劣化,且劣化曲线不线性 | 路径规划引擎线程池资源不足,任务请求排队 | 看规划耗时的P95是否显著抬高;查并发规划请求数 |
| 车辆在特定路口频繁停车,但单看每辆车路径都合理 | 路口资源分配算法存在优先级倒挂,后到的大任务占据路口过久 | 回放路口区域所有车辆的时序,分析占用时长分布 |
| 任务执行时间偶发飙高,但车辆本身未停车 | 通信延迟出现毛刺,导致车端状态上报延迟、调度中枢误判任务进展 | 抓通信帧时间戳,比对健康时段与异常时段 |
| 同一场景多次复跑结果离散度极大 | 任务下发时间间隔抖动或地图加载不一致 | 先检查时间同步与地图校验值,再检查测试脚本的注入任务方式 |
| 死锁自动恢复功能在仿真里正常,实车不触发 | 仿真里的速度模型和实车差异造成路径预估时间失真 | 将实车采集的加速度与最大速度参数回灌到仿真模型后再复跑 |
实操经验:验收测试过程中最容易拖垮进度的一环不是测试用例不够,而是环境配置漂移。测试框架里一定要加一道“环境确认”关卡:地图版本、车辆ID映射、站点编号、任务类型映射表,每一项都要在做完巡检后留痕存档。否则测试中途一旦有人改了配置,前面的测试结果就面临全部作废的风险。
还有一个非常值得记录的经验:测试过程中早期阶段,我们在仿真环境里发现一辆车的规划路径总是“贴边”,虽然不碰撞,但离墙边的安全余量只有不到2厘米。单看每台车都能完成任务,但这种贴边路径一旦到了实车执行,由于定位噪声和控制误差,车辆很可能擦碰货架或者频繁触发急停。后来复盘发现这是地图的障碍物膨胀半径设置偏小导致的。从这之后,我养成了一个新习惯:测试时不能只盯着“是否有碰撞”这种布尔判据,还要关注路径与障碍物的最小间距分布。这个数据是预判实车风险的极好窗口。
关于可扩展性,这套框架在项目回来后我一直复用,换过地图、换过车型、改过调度策略,大部分场景用例只要改配置文件和参数,不用动整体骨架。个人体会是:验收测试框架的寿命,不在于它一次性顶住了多大的验收压力,而在于它能否让人在下一次新项目时还愿意拿起来用。保持可配置、可复现、可回归,比什么都重要。