1. 项目概述:当组合测试遇上自动驾驶场景生成
在自动驾驶系统的仿真测试里,有一个让所有测试工程师都头疼的经典难题:如何高效地生成那些能真正“考倒”自动驾驶算法、暴露其潜在缺陷的“刁钻”道路场景?如果只是漫无目的地随机生成弯道和直路,效率极低,就像大海捞针。而CRAG这个工具,提供了一种非常巧妙的解题思路——它将软件测试领域里成熟高效的“组合测试”方法,与“基于搜索的软件工程”相结合,专门用来生成能让自动驾驶车辆“开出路外”的测试道路。
简单来说,CRAG的核心工作流可以打个比方:它先像一个城市规划师,用“组合测试”快速勾勒出各种高层的、抽象的道路骨架配置(比如“急右弯接急右弯再接短直道”)。然后,它再像一个道路工程师,在这些骨架里,用“搜索”的方法去具体采样和微调每段路的精确曲率和长度,最终生成一条条具体的、可仿真的三维道路。它的聪明之处在于,它知道不是所有参数组合都值得测试。对于一条路来说,真正危险、能考验车辆控制极限的,往往是连续几个路段组合在一起形成的复杂路况(比如连续的S弯)。因此,CRAG特别专注于生成和探索这些“连续参数”的组合,把计算资源用在刀刃上。
在SBFT 2024信息物理系统测试竞赛中,CRAG用实际成绩证明了这套方法的有效性。面对BeamNG.AI和Dave-2这两种不同的自动驾驶代理(可以理解为不同算法或不同能力的“虚拟司机”),CRAG在综合评估指标上表现优异,尤其是在Dave-2的测试中取得了领先的覆盖率。这背后反映的,正是组合测试带来的系统性探索优势,它能确保各种有潜在风险的“路段排列组合”不被遗漏,从而生成大量且多样的车辆越界场景。接下来,我们就深入拆解一下CRAG是如何实现这一点的。
2. 核心设计思路:在“探索”与“利用”间寻找平衡
任何有效的搜索策略,本质上都是在“探索”未知空间和“利用”已知好区域之间做权衡。CRAG的设计哲学,正是将这两种策略进行了清晰的阶段化分工与融合。
2.1 分而治之:高层配置与具体几何的分离
首先,CRAG将道路生成问题分解为两个层次,这是其设计的关键。
高层道路配置:这是一个抽象描述,定义了道路的“骨架”或“模式”。它不关心弯道具体是5度还是6度,只关心这段路属于“急右弯”、“缓左弯”还是“长直道”这样的类别。在CRAG的模型中,一条路被分为N个路段,每个路段有两个参数:长度和曲率。通过将长度和曲率的取值范围各自离散化成M个等级,一个“配置”就变成了一个由这些等级索引组成的序列,例如[(长度等级2, 曲率等级1), (长度等级0, 曲率等级4), ...]。组合测试正是在这个抽象的、离散的配置空间上进行的。
具体道路几何:这是可以输入仿真器的、一条实实在在的3D道路。给定一个高层配置,我们需要为其中每个“长度等级”和“曲率等级”在对应的实际数值区间内,随机选取一个具体的长度值和曲率值。例如,“急右弯”等级可能对应曲率范围[-0.1, -0.08],我们就在这个区间里随机选一个值,比如-0.095。这样,一个高层配置可以对应无数条具体的道路几何,它们共享同一种“模式”,但细节不同。
注意:这种分离极大地缩小了搜索空间。与其直接在连续的、高维的几何空间里盲目搜索,不如先在离散的、语义明确的配置空间里进行系统性的组合覆盖,然后再在每个有希望的配置下进行局部采样。这相当于先用网格划分战场,再对重点区域进行精细侦察。
2.2 组合测试:系统性探索的引擎
组合测试是一种黑盒测试方法,其核心假设是:大多数软件缺陷是由少数几个参数间的交互触发的。因此,它旨在用最少的测试用例,覆盖所有参数之间“两两组合”、“三三组合”等情况。
在CRAG的语境下,“参数”就是每个路段的长度等级和曲率等级。传统的组合测试会要求覆盖所有参数间的所有组合,但这对于道路生成来说既冗余又低效。CRAG做了一个非常重要的优化:它只要求覆盖连续路段的参数组合。为什么?因为从车辆动力学的角度看,一段路的挑战性不仅取决于自身,更取决于它和前后路段的关系。一个急右弯本身可能不难,但如果它紧跟着另一个急右弯(形成“发夹弯”),或者紧接在一个长直道之后(车辆速度很高),挑战性就急剧上升。因此,专注于连续参数的组合,是贴合领域知识的、有针对性的探索策略。
2.3 基于搜索的利用:聚焦有希望的“苗子”
生成了大量道路并仿真后,我们会得到一批结果:有些道路让车辆轻微偏离,有些则让车辆严重冲出路面。CRAG的“利用”策略就体现在这里:它会分析这些结果,找出那些导致车辆偏离最严重的“参数组合模式”。
具体来说,假设我们当前在用“强度为2”(即两两组合)的测试套件进行探索。仿真结束后,CRAG会找出那些表现最好的“路段对”(例如“急右弯+短直道”这个组合总是导致大偏离)。当它要生成“强度为3”(三三组合)的测试用例时,它不会平等地考虑所有可能的三组合,而是会优先生成那些包含了之前表现好的二组合的三组合。例如,它会重点生成像“缓左弯 + 急右弯 + 短直道”这样的配置,因为其中包含了“急右弯+短直道”这个优秀二组合。
这个过程是迭代的、自适应的。随着组合强度从2增加到3、4...,搜索的焦点会越来越集中在那些由底层优秀小组合构建起来的、更复杂的道路模式上。这就像是在解一道难题时,先找到一些肯定正确的解题步骤(优秀二组合),然后尝试用这些步骤去构建更复杂的解法(高组合强度)。
3. 道路的数学表示与组合模型构建
要让计算机理解和生成道路,首先需要一种精确的、可计算的数学表示方法。CRAG采用了基于Frenet标架和曲率积分的表示法,这是一种在机器人路径规划和自动驾驶领域非常常见且高效的方法。
3.1 基于曲率的道路表示法
一条道路的几何形状,本质上就是车辆中心线在平面上的轨迹。CRAG将这条轨迹离散化为N个连续的路段。每个路段i由两个核心参数定义:
- 长度 l_i:该路段的长度,单位通常是米。它有一个允许的取值范围
L = [L_min, L_max]。L_min和L_max需要根据仿真地图的尺寸合理设定,避免生成过短无意义或过长超出地图的道路。 - 曲率 κ_i:该路段的恒定曲率。曲率表示道路弯曲的程度,其倒数就是曲率半径。直线曲率为0,右转弯曲率为负值,左转弯曲率为正值。其取值范围是
K = [K_min, K_max],且通常K_min = -K_max以保证对称。K_max的选取至关重要,需要避免生成曲率半径过小、现实中不可能存在的急弯。
因此,整条道路可以表示为一个序列:[(l_0, κ_0), (l_1, κ_1), ..., (l_{N-1}, κ_{N-1})]。给定起点坐标和航向角,通过积分这些带曲率的线段,就可以唯一地重建出整条道路的中心线坐标。这种方法比直接存储一系列点坐标更紧凑,且能保证道路的平滑性(曲率分段恒定)。
3.2 构建组合测试模型
有了连续的参数(l, κ),接下来需要为组合测试构建离散的输入模型。CRAG的做法是对每个参数的连续取值范围进行均匀分区。
假设我们将每个参数域(长度域L和曲率域K)都划分为M个等级。对于长度域L:
- 等级0对应最短的分区:
[L_min, L_min + (L_max - L_min)/M] - 等级1对应下一个分区,以此类推。
- 等级M-1对应最长的分区:
[L_max - (L_max - L_min)/M, L_max]这样,一个具体的长度值l_i所属的等级,就代表了“很短”、“中等”、“很长”这样的抽象语义。
对于曲率域K,划分方式类似,但语义不同:
- 等级0对应最急的右转弯(曲率最负)。
- 等级 M/2 (假设M为偶数)对应近似直道(曲率接近0)。
- 等级M-1对应最急的左转弯(曲率最正)。 中间等级代表不同程度的转弯。
于是,一条有N个路段的路,其组合模型就包含了2N个参数:N个长度等级参数和N个曲率等级参数。一个具体的“测试用例”就是这个2N维向量的一组取值,它定义了一个高层道路配置。例如,一个N=3的道路配置可能是:[长度等级1, 曲率等级0, 长度等级0, 曲率等级M-1, 长度等级2, 曲率等级M/2],这可以被解读为“一段中等长度的急右弯,接一段很短的急左弯,再接一段较长的大直道”。
实操心得:分区数M的选择是一个权衡。M太小,则分区粗糙,组合测试的探索粒度太粗,可能会错过一些关键场景。M太大,则组合空间会指数级膨胀,导致生成测试套件的计算成本过高。在实际使用中,需要根据计算预算和测试精度要求进行调优。通常可以从一个较小的M(如3或4)开始,根据测试结果再决定是否细化。
4. CRAG算法流程的逐步拆解
理解了核心概念和模型后,我们来看CRAG算法(对应原文Algorithm 1)的具体执行步骤。这个过程清晰地体现了“探索-利用”的迭代循环。
4.1 初始化与低强度探索
算法输入包括:组合模型M、最大组合强度S、总计算预算(如时间或生成道路数量上限)、以及待测的驾驶代理DA。
第一步(强度s=2的探索):
- 生成配置:调用
GenCombTestSuite(M, 2),生成一个强度为2的组合测试套件RC2。关键点在于,这里只考虑相邻参数的配对组合。对于一条路,这意味着只考虑“路段1-路段2”、“路段2-路段3”这样的连续路段对之间的长度和曲率等级组合。 - 采样具体道路:对于
RC2中的每一个高层配置,调用GenRoadGeometries。这个过程是随机的:对于配置中指定的每个长度等级和曲率等级,在其对应的连续数值分区内,均匀随机地选取一个具体的长度值和曲率值。这样就得到了一条具体的道路几何。生成后,必须进行有效性检查,例如使用其依赖的Frenetic库中的方法,确保道路没有自相交等无效情况,并随机旋转方向后放置在仿真地图中。所有有效道路的集合记为Roads2。 - 仿真评估:将
Roads2中的所有道路输入仿真器,让驾驶代理DA在上面运行,并记录仿真结果Sim2。核心评估指标就是车辆偏离车道中心线的最大距离或平均距离(即“越界”程度)。 - 记录结果:将
(Roads2, Sim2)这一组数据保存到最终的结果集Tests中。
至此,我们完成了一轮广泛的、低强度的探索,得到了大量道路及其测试表现,并初步识别出哪些“路段对”的组合更容易导致问题。
4.2 迭代式聚焦与高强度利用
接下来,算法进入一个循环,逐步增加组合强度s(从3到最大强度S)。
对于每一个新的强度s:
- 生成高层s强度配置:再次调用
GenCombTestSuite(M, s),生成一个覆盖所有相邻参数s组合的测试套件RC_s。 - 筛选优秀子组合:调用
GetBestTuples函数。这个函数分析上一轮(强度s-1)的结果。它检查RC_{s-1}中所有的 (s-1)-组合(即连续s-1个路段的配置模式),找出哪些组合出现在了那些导致车辆最大偏离的“优秀道路”中。这些表现优异的 (s-1)-组合被收集到集合SelTup_{s-1}中。这是利用策略的核心:我们认为,包含这些“优秀基因”的更复杂组合,有更高概率产生更具挑战性的场景。 - 过滤配置套件:调用
FilterTestSuite函数。它遍历RC_s中的每一个s强度配置,检查该配置是否至少包含一个SelTup_{s-1}中的 (s-1)-组合。如果包含,则保留该配置;否则,丢弃。过滤后的配置套件记为RC_filtered_s。这一步大幅缩减了需要进一步探索的配置数量,将计算资源集中到最有希望的搜索方向上。 - 采样与评估:与第一步类似,对
RC_filtered_s中的每个过滤后的配置进行具体道路几何采样,生成Roads_s,然后进行仿真得到Sim_s。 - 累积结果:将新一轮的结果
(Roads_s, Sim_s)合并到总结果集Tests中。
这个循环持续进行,直到达到最大组合强度S,或者总计算预算耗尽。最终,算法返回所有生成和测试过的道路及其仿真结果。
注意事项:最大强度S不宜设置过高。对于有N个路段的路,理论上的最大组合强度是2N(覆盖所有参数的组合)。但在实践中,S通常远小于2N。因为随着s增大,即使经过过滤,配置空间仍然会急剧膨胀,而且过于复杂的道路模式可能超出驾驶代理的能力范围,导致仿真无意义或失效。S的选择需要与路段数N和计算预算相匹配。
5. 关键实现细节与工程化考量
将算法从论文落地到可运行的CRAG工具,涉及到许多工程实现上的细节和选择,这些细节直接影响着工具的效率和效果。
5.1 组合测试套件的生成策略
GenCombTestSuite这个函数背后需要选择一个具体的组合测试生成算法。常用的有:
- IPO(In-Parameter-Order):一种贪心算法,逐参数扩展,力求用最少的用例覆盖所有t-way组合。
- PICT:微软开发的成对测试工具,算法高效,在实际工程中广泛应用。
- ACTS:美国NIST开发的支持高强度组合测试的工具库。
由于CRAG只要求覆盖“相邻参数”的组合,这实际上是一个约束条件。在实现时,可以在调用标准组合测试生成器后,再过滤掉那些包含非相邻参数组合的测试用例;或者更高效地,在算法内部进行优化,只对相邻的参数对、三元组等生成覆盖表。这能显著减少生成的配置数量,提升效率。
5.2 道路几何的有效性检查与拟合
从高层配置采样出具体的(l, κ)序列后,这只是一组数学参数。要得到一条能在仿真器中使用的道路,还需要两步:
- 有效性检查:通过积分计算道路中心线的坐标点,然后检查这条折线(或拟合后的曲线)是否与自己相交(自相交道路在物理上不可能)。还需要检查道路的总体长度和走向是否超出了预设的地图边界。CRAG使用了来自FreneticV工具的方法来进行这项检查。
- 地图拟合:一条有效的道路需要被放置到仿真地图的某个位置和朝向上。CRAG采用随机方向拟合,这意味着同一种几何形状的道路,可能会以不同的角度被放入地图。这增加了测试的多样性,因为车辆的起始状态(如初始横向偏移、航向误差)会随之变化,可能触发不同的行为。
5.3 驾驶代理的仿真与评估指标
仿真是最耗时的环节。CRAG需要与仿真环境(如BeamNG.tech, CARLA等)集成,将生成的道路文件导入,初始化驾驶代理(DA),然后运行仿真。
- 仿真循环:在每个仿真步长,仿真器提供当前车辆状态(位置、速度、朝向等)和环境感知信息给驾驶代理,驾驶代理输出控制指令(转向、油门、刹车),仿真器更新车辆状态。
- 终止条件:仿真通常持续到车辆到达道路终点,或发生“越界”事件(车辆中心偏离车道中心超过某个阈值),或达到最大仿真步数。
- 数据记录:需要全程记录车辆轨迹、与车道线的距离等。核心评估指标就是车辆轨迹与车道中心线的最大横向偏差。这个值越大,说明生成的道路场景对驾驶代理的挑战越大,测试效果越好。
5.4 性能优化与并行化
整个生成-仿真循环是计算密集型的,尤其是仿真步骤。为了在有限预算内生成更多场景,必须考虑性能优化:
- 并行采样:
GenRoadGeometries过程对每个配置的采样是独立的,可以很容易地并行化。 - 并行仿真:多条道路的仿真彼此独立,这是最理想的并行化目标。可以部署一个仿真集群,同时运行多个仿真实例,从而线性地缩短总时间。CRAG的工具链需要支持这种分布式执行模式。
- 缓存与重用:如果相同的驾驶代理需要在多条不同道路上测试,其模型加载等初始化过程可以只做一次。但需要注意,有些仿真环境或代理在不同运行实例间可能有状态干扰,需要隔离。
6. 实战应用:从配置到生成挑战性场景
让我们通过一个简化的虚构例子,来直观感受CRAG的工作过程。假设我们定义一条路由3个路段组成(N=3),每个参数(长度、曲率)分为3个等级(M=3)。长度等级:0(短),1(中),2(长)。曲率等级:0(右急弯),1(直道),2(左急弯)。
步骤1:构建组合模型与强度2探索组合模型有6个参数:[L0, K0, L1, K1, L2, K2]。生成强度为2的测试套件,且只覆盖相邻参数对,例如需要覆盖(L0,K0), (K0,L1), (L1,K1), (K1,L2), (L2,K2)这些参数对的所有值组合(3x3=9种组合每个对都要覆盖)。生成的一组配置可能包括:
- 配置A:
[L0=0, K0=0, L1=1, K1=1, L2=2, K2=2](短右急弯 -> 中直道 -> 长左急弯) - 配置B:
[L0=2, K0=1, L1=0, K1=0, L2=1, K2=1](长直道 -> 短右急弯 -> 中直道) - ...等等。
对每个配置采样具体值,仿真后,发现配置B中的“K0=1(直道)和L1=0(短)”这个路段组合,以及“L1=0(短)和K1=0(右急弯)”这个组合,出现在多条导致严重偏离的道路中。它们被标记为“优秀二元组”。
步骤2:强度3的聚焦搜索生成强度为3的测试套件RC3,它需要覆盖所有连续的参数三元组,如(L0,K0,L1), (K0,L1,K1)等。 然后进行过滤:只保留那些包含了步骤1中发现的“优秀二元组”的配置。例如,一个候选配置[L0=1, K0=1, L1=0, K1=0, L2=2, K2=1],它包含了“L1=0, K1=0”(短右急弯)这个优秀二元组,因此被保留。另一个配置如果不包含任何优秀二元组,则被过滤掉。 对过滤后的配置进行采样和仿真,期望能找到更具挑战性的场景,比如“长直道(高速)末端接一个极短的右急弯”。
结果分析:通过这种迭代,CRAG能够系统地探索从简单到复杂的道路模式,并自动将搜索重心偏向于已证明能产生问题的模式变体,从而高效地生成大量“拐点”场景。
7. 常见问题、调优与扩展方向
在实际部署和使用CRAG或类似方法时,会遇到一些典型问题,以下是一些排查思路和进阶思考。
7.1 常见问题与排查
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 生成的道路大量无效(自相交) | 曲率变化过于剧烈;路段长度与曲率不匹配;分区范围K_max设置过大。 | 1. 在采样后增加更严格的道路平滑度约束。2. 调整分区定义,在长度等级和曲率等级之间引入依赖关系(例如,高曲率等级不允许与超短长度等级组合)。3. 减小K_max,生成更符合实际道路设计规范(如AASHTO)的曲率。 |
| 仿真耗时过长,无法在预算内完成 | 生成的道路数量太多;单个仿真时间过长;并行化不足。 | 1. 调整组合测试生成策略,在满足覆盖要求下生成更少的配置。2. 为仿真设置更严格的超时条件(如最大仿真时间)。3. 优化仿真基础设施,采用更多并行实例。4. 考虑使用轻量级、更快的仿真器进行初步筛选。 |
| 生成的场景多样性不足 | 组合模型分区数M太小;搜索过于“贪婪”,过早聚焦导致陷入局部最优;随机采样方差不够。 | 1. 适当增加M,提供更细粒度的控制。2. 在“利用”策略中引入随机性,例如不是只选择Top-K个优秀组合,而是按性能加权随机选择。3. 在采样具体几何时,采用更智能的采样(如基于优化)而非纯随机,以探索分区内的边界值。 |
| 对某个驾驶代理效果很好,对另一个很差 | 驾驶代理的能力差异巨大;评估指标(单纯看最大横向偏差)可能不全面。 | 1. 针对不同代理,可能需要调整组合模型的参数(如曲率范围)。2. 引入更多样化的评估指标,如偏离速度、恢复能力、舒适度(加速度)等,构建多目标优化问题。 |
7.2 参数调优指南
CRAG的性能很大程度上依赖于几个关键参数:
- N(路段数):决定了道路的复杂度和组合空间的维度。N太小,道路过于简单,难以生成复杂场景;N太大,组合空间爆炸。建议从5-10开始尝试。
- M(分区数):决定了抽象的粒度。M=2(如长/短,左/右)可能太粗糙;M=5或6通常能在表达力和复杂度间取得较好平衡。
- S(最大组合强度):决定了搜索的深度。对于N=5的道路,强度2(覆盖连续路段对)是基础,强度3或4通常能发现更隐蔽的问题。强度再高可能收益递减。建议通过实验,观察在强度增加到多少后,新发现的“独特”坏场景数量开始饱和。
- 预算分配:如何在低强度探索和高强度利用之间分配仿真预算?一个经验法则是,将大部分预算(如60-70%)用于低强度(s=2,3)的广泛探索,确保不错过任何有潜力的简单组合模式;剩余预算用于对筛选出的模式进行高强度深化。
7.3 潜在的扩展方向
CRAG的框架是灵活且可扩展的:
- 引入更多道路特征:当前模型只考虑了纵向的几何形状(曲率、长度)。可以很容易地加入横向特征,如车道宽度变化、坡度、路面附着系数等,只需将这些新参数加入到组合模型中即可。
- 动态场景生成:目前生成的是静态道路。可以将其扩展为动态场景生成器。例如,将“时间”作为一个维度,参数可以包括其他交通参与者的出现时间、类型、行为等,与道路几何进行组合测试,生成更复杂的交互场景。
- 与形式化方法结合:组合测试保证了参数组合的覆盖度,但未考虑具体的需求或规约。可以结合时空逻辑等形式化规约,将“车辆应始终在车道内”作为属性,使用组合测试生成的场景作为反例搜索的种子,引导搜索更快地找到违反规约的场景。
- 多目标优化:当前的“利用”策略基于单一目标(最大横向偏差)。可以将其扩展为多目标搜索,同时优化场景的多样性、执行时间、覆盖不同的故障模式等,使用帕累托前沿等概念来筛选和保留配置。
CRAG工具的思路为自动驾驶测试场景生成提供了一个系统化、可解释且高效的范式。它成功地将经典的软件测试理论与前沿的搜索算法相结合,在保证覆盖度的前提下,显著提升了生成场景的针对性和有效性。对于从事自动驾驶仿真与测试的工程师而言,理解并掌握这种“组合+搜索”的混合策略,对于设计更强大的测试用例生成系统,无疑具有重要的借鉴意义。