目录
1. 背景介绍
在自动驾驶仿真领域,场景一直是大家关注的重中之重。因为自动驾驶仿真与传统的仿真的最大区别就是缺少了人。面对复杂的交通状况做出灵活应对,在自动驾驶之前一直是人类驾驶员的责任,而在自动驾驶面世之后,车辆本身需要对自己负责、对乘坐在其上的乘客负责。因此,需要在自动驾驶车辆上路之前,尽可能多的经历不同场景的测试和考验,才能让消费者放心,让厂商自己安心。
目前维智,没有人敢拍着胸脯说,TA家的场景可以覆盖任何一种有可能存在的情况,这还有很长的路要走,需要集合众人的智慧和付出才有可能。为了让自动驾驶的安全性至少在技术层面上能够早日令人放心,在我看来,全人类的合作是在所难免了,众人拾柴火焰高,可以以最高的效率尽快地尽可能多的完善自动驾驶场景库。而在这个愿景实现之前,统一标准是基础,如果没有一个统一的标准,大家各说各话,那么合作这件事就纯粹是痴人说梦。因此,业界都在期待有一种公开、共用的一套场景描述标准,在未来的产业分工合作中,大家能够实现场景共享。以上都是基于我个人的臆想,如果目的不是这样,那么可能是我把它给升华了,见谅!
OpenSCENARIO起源于VTD的企业标准,自被ASAM收购之后,目前的趋势很可能会实现大一统,至少在国内,它的呼声很高,目前都已经成立了C-ASAM工作组,在中汽研-数据中心的管辖下。也得力于这个中国小组,让我们国内的用户有幸可以看到中文版的技术标准。点赞!
首先声明,本人只是仿真工具从业者,非标准工作组相关人员,自己在工作中读了一遍标准后,遂撰文记录下学习心得,如果有同行业者,望赐教!
2. 本文参考
ASAM OpenSCENARIO: User Guide 用户指南
至于详细的标准内容,可参考以上链接。下面开始详细解释什么是OpenSCENARIO.
3. 标准详解
3.1 什么是场景
场景,对于车辆驾驶而言,就是描述驾驶员驾驶着本车,在何时何地何种天气条件下行驶在大马路上,可能会遭遇各种其他交通参与者(车、人)或者路边的设施的动态变化情况。
当然,本车及其他交通参与者都不会毫无目的地行驶在道路上,他们都会按照一定的策略(如导航到某一个目的地)参与其中。
这么看来,场景的定义其实是很宽泛的,也是很多变的。这也好理解,因为我们无时无刻都处在自己的场景或者他人的场景中,在我们自身的认知中,自己属于本体,但其实我们自己同时也处在别人的场景中扮演着一个匆匆过客。
那么OpenSCENARIO的职责就是要用一种语言去描述上述场景,让每个人手里拿到OpenSCENARIO文件时都能看懂这是怎么样的一个场景。
3.2 OpenSCENARIO的范围
由于场景的细节太多,OpenSCENARIO无法将其全部囊括其中。在标准中,也详细描述了其范畴。在这里,抓几个重点解释一下。
- 定义了动态内容(如交通参与者的行为),该标准不包含静态内容(如道路网络)。其实在OpenSCENARIO中,静态内容是采取索引的方式链接到其兄弟标准OpenDRIVE和OpenCRG中
- OpenSCENARIO并不包含待测系统的准确说明,例如详细的车辆配置,传感器位置,传感器模型等。在OpenSCENARIO中,重点是在描述主车可能遭遇的驾驶环境的变化,对于待测系统的准确说明,它是留给了各家的仿真工具来定义的,毕竟待测系统因各家仿真器(simulator)而异。实际上,OpenSCENARIO并不能被视为仿真器和其待测系统或其测试用例的完整说明。
- 本标准包含了对于驾驶员基本生理特征的描述,例如身高和体重, 但并不包括驾驶员的行为模型。这一点对于市面上绝大多数的仿真器而言可能都没有太多的考虑,可能大多数的仿真器都是在做无人驾驶仿真的,驾驶员并不是一个需要考虑的因素,因为没有驾驶员啊。而对于驾驶辅助而言,在真实世界的驾驶环境中,驾驶员模型其实是很重要的。因为不同的场景对于不同的驾驶员来说,其边界条件不一样,造成的结果也不一样。这一点可以这么理解,为什么交警部门要求大家要小心驾驶,不要超速、不要酒驾?原因就是在规范我们的驾驶员要合规驾驶。对于那些激进驾驶员来说,我想他们也需要配备更加高级的驾驶辅助吧。
- 尽管本标准以动力学的方式呈现了车辆操作(maneuvers),也定义了基本的车辆运动模型,但该标准并不包括高级动力学的所需要素。因为场景落实到不同的仿真器中,车辆动力学模型就受限于仿真器本身了,因为有些仿真器里面就没有详细的车辆动力学,所以OpenSCENARIO不会对其有详细的描述。这个其实也和上面第二点相关联。
以上,就是我觉得有必要备注的OpenSCENARIO的范围,更多详细内容,请参考标准。
3.3 概念
3.3.1 场景的构成:三个要素
- 道路网络:路网络
RoadNetwork
作为静态交通基础设施(包括交通信号灯TrafficSignals
),需由实体Entity
实例组成,此处的实体实例指的是车辆Vehicle
和行人Pedestrian
等道路使用者。 - 场景剧本:组成方案要求场景剧本Storyboard 内至少有一个或多个场景内容Story的实例存在。该场景内容Story的要素则被置于一个特定结构内
- 触发条件:定了行动者
Actor
最终采取的动作Action
是由条件Condition
来触发的,此处的行动者Actor
指的是参与动作的实体Entity实例。
以上三个定义都是直接从标准中拷贝出来的概念,但在我详细看了OpenSCENARIO的数据后,我个人其实并不是按照标准上写的三个要素来理解的。在OpenSCENARIO数据文件中,其XML的层级结构其实是RoadNetwork, Entities, StoryBoard,我个人觉得这个更好方便我理解,场景其实是在一个道路网路中,每一个交通参与者(实体Entities)将按照场景剧本如何推演。而触发条件如果放到场景剧本中,貌似更加好一些。Anyway,并没有质疑标准的意思,只是提出了我的疑问。为何标准没有与XML的层级结构匹配?
3.3.2 场景剧本
场景剧本是一个场景的核心所在,这里面回答了场景中“谁”在“什么时候”做“什么”这些基本问题。每个场景剧本包含一个初始化要素(Init),其次是一个或多个场景内容Story
要素。
下面总结了一个导图,通过一个例子来解释场景剧本里面各个元素的关系。
- Init 初始化要素,定义了场景的初始条件,例如实体的初始位置和速度等信息。这里以变道超车做一个例子,初始化两辆车,分别行驶在道路的哪个位置,分别以多少的时速在行进。
- Story 场景内容,定义了这个场景将会发生的内容
- Act 动作集,回答诸如事情在场景内容时间线中何时发生这一问题,包含ManeuverGroup和StartTrigger。只有在启动触发器 startTrigger 的判定为真时,动作集所包含的操作组
ManeuverGroup
才能被执行。- ManeuverGroup 操作组,定义了一个操作序列。解答了哪个实体
Entity
实例(谁)在场景中作为行动者Actor
被分配到操作Maneuver
这一问题- Actors 动作实体,即是”谁“在操作
- Maneuver 操作,即“做什么”的定义。一个变道超车操作可以想象至少包含有两个“事情”要发生:首先是借道超车,然后再回到原车道
- Event 事件,往左变道
- Action 动作,用于创建或修改场景的动态要素,这里才是一个场景真正起到“变化”的核心,只有发生了具体的动作,场景的动态要素才发生变化
- StartTrigger 启动触发器,条件判定为“真”时,触发Action动作的执行,如在这个例子中,只有当后车与前车的距离小于30m时,才触发“往左变道”这个动作
- Event 事件,往右变道
- Action 动作,往右变道 - 超车后回原车道(这才是应该有的驾驶操作,国内交通基本不考虑这个问题)...
- StartTrigger 启动触发器 ...
- Event 事件,往左变道
- StartTrigger 启动触发器,规定了这个操作组是从什么时候就开始触发,比如,在仿真一开始就触发这个变道超车操作组
- ManeuverGroup 操作组,定义了一个操作序列。解答了哪个实体
- Act 动作集,回答诸如事情在场景内容时间线中何时发生这一问题,包含ManeuverGroup和StartTrigger。只有在启动触发器 startTrigger 的判定为真时,动作集所包含的操作组
注意:动作集Act
的启动会连带着启动其操作组ManeuverGroup
和操作Maneuver
,但是并不会牵扯到事件Event
,因为它们配有独立的启动触发器 startTrigger
3.3.3 动作
在场景定义中,除了动作,其他部分基本上都只是描述,而动作是涉及到仿真器的执行层面的。个人觉得这个部分是仿真器需要重点考虑的部分。
动作分为三类:
-
PrivateAction
s 专属动作 -
GlobalAction
s 全局动作 -
UserDefinedAction
s 用户定义的动作
在标准的附录A中,定义了完整的Action Tables动作表
下面,就拿上面变道超车场景中发生的三个动作做一下简要分析。
这三个动作分别是纵向动作LongitudinalAction、横向动作LateralAction和传送动作TeleportAction,这应该是三个最常用的动作。
1)纵向动作
在【变道超车】这个场景中,初始化中用到了纵向动作,初始化的时候两车都是以一定的速度直线行驶在道路上,这就是一个纵向动作。
在纵向动作中,一类是速度动作SpeedAction,这个动作的转换动力学特性SpeedActionDynamics是:指定一种转换方式(有step阶跃, linear线性, cubic三次方, sinusoidal正弦)、值和值的语义(rate变化率、time时间、distance距离);这个动作还需要指定一个速度目标SpeedActionTarget。
在此例中,转换方式dynamicsShape="step“ 阶跃方式,值value="0",值的语义dynamicsDimension="time”;翻译过来就是:在时间跨度为零范围内,以阶跃方式达到目标速度3.61e+01 m/s (130km/h)。
在动作表中,纵向动作还有一个值-连续性 continuous ,如果连续 = "伪"时,目标为"绝对"或"相对",动作在达到纵向速度后立即结束。连续 = "真"时,目标为"相对",纵向速度达到后并保持相对纵向速度继续行驶。
但是,在此例中没有看到这个值的定义。
2)传送动作
在传送动作中,定义实体需要传送到的位置,定位的方式有好几种,此例中用到的是世界坐标位置worldPosition,有6个参数,分别是位置x,y,z,和朝向h,p,r。通过传送动作给实体定义了一个初始位置。
3)横向动作
在横向动作中,一类是变道动作LaneChangeAction,这个动作的转换动力学特性与上述的纵向-速度动作一样,并指定一个变道目标LaneChangeTarget(相对目标车道RelativeTargetLane,1为往左变一个车道,-1为往右变一个车道)。在此例中,转换方式dynamicsShap="sinussoidal",值value="5",值的语义dynamicsDimension="time";翻译过来是:在时间跨度为5秒内,以正弦转换方式往左变换一个车道。
3.3.4 条件和触发器
场景汇总了一系列有意义的动作Action
,而触发器Trigger
掌握着对此类动作的控制权。因此,触发器Trigger
在场景如何衍变方面起着重要作用。在复杂的场景中,单个触发器可能需要使用一整组条件Condition
之间的关系。
条件Condition有两种控制方式,分别是byEntityCondition和byValueCondition,前者以场景中某一个实体的状态作为判定条件,后者是以场景中的一个值作为判定条件。
在此例中,以实体的状态作为判定条件,而实体条件EntityCondition则选取了距离条件DistanceCondition,判定规则为如果$owner的位置与"Ego“的相对位置小于3.0e+01(30m)。
这里面涉及到很多对象的属性,罗列如下:
1) Condition的属性
Condition Properties | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
ConditionEdge有几种条件边界的判定方式,主要是基于当前时间点和前一个采样时间点的逻辑表达式的结果作为返回值的判定(解释起来好拗口),直接看下图和下表的整理。
说实话,这个条件在实际中是如何工作的,有和具体区别,本人还不是很清楚。望有了解的同学赐教。
ConditionEdge | Previous Logical expr | Now Logical expr | Return |
Rising | false | true | true |
true | false | false | |
Falling | true | false | true |
false | true | false | |
risingOrFalling | false | true | true |
true | false | true | |
none | return true if its logical expression is true, and false if its logical expression is false. |
2)byEndityCondition的属性
byEntityCondition Properties | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
3)EntityCondition的属性
EntityCondition Properties | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4)RelativeObjectPosition的属性
这个对象定义了相对于目标实体Entity,相对位置为dx,dy,dz。本例中Entity="Ego", dx="0",dy="0",其实就是"Ego”自身的位置,如果dx,dy不为零,则是以"Ego"为原点相对dx,dy的位置作为相对目标的位置。
注意区分参考实体和触发实体,在此例中,"Ego”是参考位置的实体,"$owner"是触发条件对比的实体。
RelativeObjectPosition Properties | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4. 示例
上面第三节的举例就是基于标准中的示例。
这一场景描述的交通情况为:本车 Ego vehicle 在一条三车道高速公路的最右车道上,而一辆速度更快的车正在接近它。
在初始化阶段,本车 Ego vehicle 被初始化后,以每小时 130 公里的速度行驶在最右车道上。另一车辆以每小时 150 公里的速度行驶在本车相同车道上的后方 79 米。
仿真运行时,当速度更快的车辆接近本车 Ego vehicle 30 米处,它便以正弦曲线方式进行向左变道。当该车辆到达了本车 Ego vehicle 前方并拉开 5 米的距离时,它即回到最右车道上。