3. 场景与场景库概念

在CARLA大规模场景批量验证工程中,“场景”不是随手写的一段仿真脚本,而是可被描述、可被复用、可被批量执行、可被结果追溯的最小验证单元。理解场景的定义方式、标准格式、执行引擎以及场景库的组织逻辑,是后续搭建批量验证流水线的前提。本章围绕场景定义、OpenSCENARIO、CARLA ScenarioRunner、场景分类、参数化场景与场景库组织方式展开。

一、什么是场景:从“一次仿真”到“可复用验证单元”

场景(Scenario)是对一段交通情境的完整描述,通常包含道路环境、静态要素、动态参与者、初始状态、触发条件、行为序列以及成功/失败判据。它回答的是“在什么环境下,谁在什么时刻做了什么,系统应如何响应,结果如何判定”。

一个可工程化的场景至少应具备四个属性:

  • 可描述性:用结构化语言或参数表达,而非仅存在于工程师脑中。
  • 可复现性:给定相同随机种子与版本,能稳定重放。
  • 可参数化:关键变量(车速、距离、触发时刻)可外部注入。
  • 可判定性:有明确的通过/失败/无效判据。

在CARLA中,场景可以由Python API直接编写,也可以由OpenSCENARIO描述后交由ScenarioRunner执行。前者灵活但难复用,后者标准化但需要转换与适配。

二、OpenSCENARIO:场景的标准化描述语言

OpenSCENARIO是ASAM制定的场景描述标准,采用XML结构,核心由Storyboard、Init、Story、Act、Maneuver、Event、Action等层级组成。它把“谁在何时做什么”拆解为可组合的语义单元。

<ScenarioDefinition>
  <ParameterDeclarations>
    <ParameterDeclaration name="EgoSpeed" value="8.0"/>
    <ParameterDeclaration name="Gap" value="15.0"/>
  </ParameterDeclarations>
  <Storyboard>
    <Init>...</Init>
    <Story name="CutIn">
      <Act>
        <ManeuverGroup>
          <Actors><EntityRef entityRef="NPC"/></Actors>
          <Maneuver>
            <Event name="StartCutIn">
              <Action><LaneChange .../></Action>
            </Event>
          </Maneuver>
        </ManeuverGroup>
      </Act>
    </Story>
  </Storyboard>
</ScenarioDefinition>

OpenSCENARIO的优势在于跨仿真器可移植、便于版本管理与参数注入;局限在于CARLA对部分动作的支持需要ScenarioRunner做映射,复杂交互仍需自定义扩展。

三、CARLA ScenarioRunner:场景执行引擎

ScenarioRunner是CARLA官方提供的场景执行框架,负责解析OpenSCENARIO或Python场景定义,在仿真世界中生成参与者、绑定触发条件、执行动作并收集判据。其典型运行命令如下:

python scenario_runner.py \
  --scenario MyCutInScenario \
  --openscenario scenarios/cutin.xosc \
  --route routes/route_01.xml \
  --agent roach \
  --output results/run_001

ScenarioRunner的核心职责包括:场景加载、Actor生成与销毁、触发条件评估、行为执行、判据计算、结果输出。批量验证时,通常由外部调度器循环调用ScenarioRunner,或使用其Python API在单进程内批量执行,以减少启动开销。

建议在批量验证中固定CARLA版本、ScenarioRunner版本与地图版本,并将随机种子写入结果元数据,否则“可复现”无法保证。

四、场景分类与参数化场景

场景可按功能、交互形态、危险程度、来源等维度分类。工程中常用分类如下:

分类维度典型类别示例
功能场景跟车、换道、交叉口、行人横穿前车急刹、旁车切入
逻辑场景参数区间描述切入车速 5~15 m/s,间距 10~30 m
具体场景固定参数实例切入车速 8 m/s,间距 15 m
危险程度常规、边界、极端正常跟车、临界制动、鬼探头
来源法规、事故、专家、随机ECE R152、CIDAS事故库

参数化场景是把逻辑场景中的变量抽为参数,通过采样生成大量具体场景。例如切入场景可参数化为:ego_speed、npc_speed、gap、trigger_time、weather。批量验证的本质,就是在参数空间中进行有策略的采样与执行。

params:
  ego_speed: [6, 8, 10]
  npc_speed: [5, 8, 12]
  gap: [10, 15, 25]
  weather: [ClearNoon, HardRainNoon]
# 组合后共 3×3×3×2 = 54 个具体场景

五、场景库组织方式

场景库不是场景文件的简单堆叠,而应有清晰的目录结构、元数据与索引。推荐组织方式如下:

  • 按功能域分目录:cut_in/、follow/、intersection/、pedestrian/。
  • 场景文件与参数分离:.xosc或.py描述结构,.yaml描述参数集。
  • 元数据索引:记录场景ID、版本、地图、标签、判据、责任人。
  • 结果归档:按run_id保存日志、判据、轨迹与失败截图。
scenario_library/
├── cut_in/
│   ├── cutin_base.xosc
│   ├── cutin_params.yaml
│   └── meta.json
├── follow/
│   ├── follow_brake.xosc
│   └── follow_params.yaml
├── intersection/
└── index/
    └── scenario_index.csv

在批量验证工程中,场景库还应支持按标签筛选、按参数采样、按优先级排序,并与CI/CD流水线对接,实现“提交代码→自动采样→批量执行→生成报告”的闭环。

场景库的核心价值:让场景从“一次性脚本”变为“可检索、可组合、可回归的验证资产”。

六、常见误区与复盘

  • 误区一:把场景等同于测试用例。场景描述情境,测试用例还需绑定判据、阈值与预期结果。
  • 误区二:参数越多越好。参数爆炸会导致组合数失控,应优先筛选高敏感参数并采用正交或边界采样。
  • 误区三:忽略版本与种子。CARLA、地图、ScenarioRunner任一变化都可能改变结果,必须记录完整环境指纹。
  • 误区四:场景库无索引。没有元数据索引,场景无法被批量调度与结果追溯,规模一大就失控。

复盘建议:每次批量验证后,统计场景通过率、失败聚类与参数敏感度,将高价值失败场景反哺回场景库,形成持续演进的场景资产。

场景库组织与批量验证数据流 场景来源 法规标准 事故数据 专家经验 随机生成 路测回灌 边界挖掘 功能场景 / 逻辑场景 场景库 场景描述文件 .xosc / .py 参数集 .yaml / .json 元数据索引 ID / 标签 / 版本 判据定义 通过 / 失败 / 无效 结果归档 日志 / 轨迹 / 截图 可检索 · 可组合 · 可回归 批量执行与采样 参数采样 正交 / 边界 / 随机 场景实例化 逻辑→具体 CARLA ScenarioRunner 加载 · 触发 · 执行 · 判据 仿真世界 地图 / 天气 / 交通 结果判定 通过 / 失败 / 无效 批量报告与失败聚类 通过率 · 敏感度 · 回归对比 调度 · 并行 · 追溯 失败场景反哺场景库,形成持续演进闭环

综上,场景是验证的基本单元,OpenSCENARIO提供标准描述,ScenarioRunner负责执行,分类与参数化决定覆盖策略,场景库组织决定工程可扩展性。只有把四者打通,才能支撑CARLA大规模场景批量验证的稳定运行。