华为云用户手册

  • 动作 lane_offset 动作主体:车辆vehicle 结束时间:当动作主体actor 到达目标偏移offset 处时,动作结束. 是否支持modifier:否 参数:参数如下表,支持位置参数和关键字参数.参数target 非必选项,不设置target 时采用绝对偏移,设置target 时采用相对偏移. 表1 lane_offset参数 Parameter Type Mandatory Description offset length yes Signed number in meters the vehicle should respect as an offset from the center of the current lane. rate_peak speed yes Target value for the peak lateral velocity that must be achieved during the action. dynamics_shape dynamics_shape yes Geometrical shape of the LaneOffsetAction's dynamics. target entity no Reference entity. offset值不能超出当前所在lane的宽度范围. 绝对偏移 m_shape: dynamics_shape = step Ego.lane_offset(0.8m, 0.5mps, m_shape) 相对偏移 m_shape: dynamics_shape = linear side_vehicle.lane_offset(offset:1.0m, rate_peak: 1.5mps, dynamics_shape:m_shape, target: Ego) 父主题: 动作 Actions
  • distance_mode 用于触发条件object_distance和point_distance. distance_mode list ENUM_DISTANCE_MODE = ("reference_points", "bounding_boxes") reference_points:测量参考点之间的距离. bounding_boxes:测量边界框之间的距离. 父主题: Enum Lists
  • 编辑评测指标 评测类型为内置评测配置时,可为评测添加或删除评测指标,便于管理。 单击评测名称,在评测项目详情页,自定义评测配置部分,单击“编辑”。 单击“添加评测指标”,选择需要添加的指标,单击“确认”。 图3 添加评测指标 单击,对阈值进行设置,也可对重要度以及评分方案进行选择。 图4 阈值设置 重要度:可选主要和次要。 评分方案:可选主要次要log函数、主要次要均匀权重、全部均匀权重。具体介绍请查看评测分数计算介绍。 删除评测指标。 单击评测指标后“操作”栏内“删除”,删除该评测指标。 被任务使用的评测项目和镜像不能删除。 以上信息选择无误后,单击“保存”,评测指标编辑完成。
  • 仿真服务简介 Octopus仿真服务支持多种功能操作。包括用户在云上以类似操作远程桌面方式操作图形化界面的仿真软件的在线仿真服务,基于OpenSCENARIO等标准格式的仿真场景管理。泛化大量仿真场景,规控算法工程管理,多场景并行高速运行的批量仿真服务,和多样式的仿真报告查看和对比方式以及仿真过程回放等。用户可通过仿真服务完成在线仿真、仿真场景,创建仿真评测任务等。仿真服务开发流程如下。 图1 仿真服务开发流程 仿真服务操作引导如下: 在线仿真:提供类似本地开发的体验,支持客户直接使用线上仿真器开发,并无痛对接云端的场景管理:包含加载、绘制、保存等操作,并支持对仿真结果的录制文件的回放等功能。 算法管理:用于对接客户的上云算法,并支持算法的版本级管理,并可自动化触发关联的批量算法。 评测管理:支持内置评测配置和自定义评测镜像,对仿真任务中的算法展开评测。 场景管理:包含场景、场景库、逻辑场景、逻辑场景库、测试用例、测试套件等。支持页面上传、路测数据生成、泛化、在线仿真编辑等场景录入方式,支持地图、场景的在线预览,并支持场景标签等功能。 任务管理:选择仿真算法和仿真场景创建仿真任务,从行车安全、驾驶行为、乘员舒适性等角度衡量仿真算法控制效果,支持可视化仿真结果,生成任务报告。 父主题: 仿真服务
  • eva.proto的关键字段解释 在利用Octopus仿真平台进行批量仿真时,每个场景都会有一个评测结果,单个场景的评测结果全部保存在如数据类图所示的Evaluation类中。 Evaluation类包含以下的7个字段。 表1 Evaluation类包含的字段 字段 说明 version 用于表示当前Octopus_eva.proto的版本。 score 用户保存批量仿真中单个场景下评测算法计算出的评测得分,Octopus的评分取值为[0, 100]。 avg_speed 单个场景下自动驾驶算法控制下主车的平均车速,单位m/s。 distance 单个场景下自动驾驶算法控制下主车的行驶里程,单位m。 vis 主车关键状态量的(如速度、加速度)的时间序列数据,用于前端进行可视化曲线展示。 metrics Octopus内置了一批大类评测指标,并且每个大类评测指标下会多个子类指标。 该字段用于保存每个大类和子类评测指标的通过/未通过/无效的结果状态。 其中无效状态表示该指标在特定场景下是没意义的,如在没有交通灯的场景下,主车在交通灯前的行为检测是没有意义的。 source 是一个Source枚举类型,表示该评测算法的结果来源类型。 source共有6种类型,具体参考source。 表2 source 字段 说明 SOURCE_UNSPECIFIED 表示评测算法类型未定义。 SOURCE_CUSTOMIZED_REALTIME 用户自定义实时评测算法结果。 SOURCE_CUSTOMIZED_OFFLINE 用户自定义延时评测算法结果。 SOURCE_DEFAULT_REALTIME 八爪鱼内置实时评测算法结果。 SOURCE_DEFAULT_OFFLINE 八爪鱼内置延时评测结果。 SOURCE_MERGED 融合后的评测结果。 Evaluation中两个比较关键且复杂的字段是vis和metrics,其中vis字段类型是Visualization,metrics字段的类型是repeated Metric。 Visualization和Metric的成员组成如上数据类图所示,各个关键成员的含义如下所示。 Visualization类型包含的各个字段及其含义如下所示。 表3 Visualization类型字段 字段 说明 sim_times 仿真过程的时间序列点,以仿真开始时刻(t0)为0点,相邻时刻的时间间隔为仿真器的周期,单位为秒(s)。 frame_nums 每个仿真时刻对应的数据帧数,表明这是第几帧的数据。 stats 统计类型的数据值,是指某数据在一段时间内统计值才有展示分析的意义,如加速度均方根值(arms),随着仿真时刻不断后移,需要不断计算初始时刻(t0)到当前仿真时刻(t)的arms值。 stats字段的类型是Statistic,Statistic类型的成员具体参考stats。 vector 向量类型的数据值,是指每个时刻都会有一个对应的数据值,如加速度、速度等物理量。 vector字段的类型是Vector,Vector类型的成员具体参考vector。 表4 stats 字段 说明 type 是一个Type的枚举类型,表示该数据是哪种Octopus内置的Statistic类型。 value 该数据在每个仿真时刻对应的数值。 diplay_name 存储用户自定义的Statistic类型名称,用户自定义的数据无需对type赋值。 source 表示该数据的评测结果来源类型。 importance 表示该数据是重要类型还是次要类型。 module 表示该数据是来源于哪个算法模块。 performance 表示该数据是表示的哪个类别的算法性能。 表5 vector 字段 说明 type 是一个Type的枚举类型,表示该数据是哪种Octopus内置的Vector类型。 value 该数据在每个仿真时刻对应的数值。 diplay_name 存储用户自定义的Vector类型名称,用户自定义的数据无需对type赋值。 source 表示该数据的评测结果来源类型。 importance 表示该数据是重要类型还是次要类型。 module 表示该数据是来源于哪个算法模块。 performance 表示该数据是表示的哪个类别的算法性能。 Metric类型包含的各个字段及其含义如下所示。 表6 Metric类型字段 字段 说明 type 是一个Enum类型,表示该数据是哪种Octopus内置的大类指标类型。 status 是一个Result的枚举类型,用于表示该大类指标的评测结果。 其中Result有三种类型,分别为: RESULT_UNSPECIFIED:该状态的结果表示评测指标是无效的,如对于红绿灯检测指标,如果仿真完成后评测函数发现场景中不存在红绿灯,则该项指标的评测是没有意义的,故评测结果展示为无效。 RESULT_PASSED: 该状态的结果表示评测结果为通过。 RESULT_FAILED:该状态的结果表示评测结果为未通过。 anomalies 用于保存每个大类指标下对应的子类指标发生异常的时间点,其数据类型为repeated Anomaly,其中Anomaly类型成员如下所示: status: 是一个Result类型,与上述大类指标的status的表示相同,该字段用于存储子类指标的三种不同状态结果。 subtype:是一个Subtype的枚举类型,表示该子类指标是哪种Octopus内置的子类指标类型。 其中,对于某些没有子类指标的大类指标来说,其subtype赋值为SUBTYPE_UNSPECIFIED。 point_type:是一个PointType的枚举类型,表示该子类指标发生特殊状态(一般是指发生异常)时的时刻点用哪种形式存储起来。 其中PointType共有5种类型,参考PointType。 Points:是repeated float类型,保存每个子类指标发生特殊状态的具体时间点的值。 Stats_indices:是repeated ui32类型,表示该子指标关联的统计类数值列表。 Vector_indices:是repeated ui32类型,表示该子指标关联的时间序列数值列表。 display_name 存储用户自定义的Anomaly类型名称,表示其自定义的子类指标,用户自定义的数据无需对sub_type赋值。 importance 表示该指标的重要程度。具体参考importance。 source 表示该数据的评测结果来源类型。 module 表示该数据是来源于哪个算法模块。具体参考module。 performance 表示该数据是表示的哪个类别的算法性能。具体参考performance。 表7 PointType 字段 说明 POINT_TYPE_UNSPECIFIED 未定义的类型,遵循proto定义格式,Octopus未使用该类型,用户可根据需要对该类型赋予特定含义。 POINT_TYPE_POINT 表示该子类指标的异常时间点是离散的时间点形式,在任何时刻都可能发生异常。 POINT_TYPE_REGION 表示该子类指标的异常时间点是区间形式,一旦在某个时刻开始发生异常,则在随后一段时间内都会处于异常状态。 POINT_TYPE_ALL 表示该类指标的异常时间点是布尔形式的,从仿真开始到当前时刻的状态要么是完全通过,要么全过程都是异常的,统计类型的指标需要以这种形式表示。 POINT_TYPE_NORMAL 该类型与其他类型相反,如果该类型的点存在,则表示对应的子类指标是通过的,Octopus用该类型保存主车到达终点的时间值。 表8 importance 字段 取值 说明 CATEGORY_UNSPECIFIED 0 未定义 CATEGORY_MAJOR 1 主要 CATEGORY_MINOR 2 次要 表9 module 字段 取值 说明 MODULE_UNSPECIFIED 0 未定义 MODULE_NAVIGATION 1 导航 MODULE_LOCATION 2 定位 MODULE_PERCEPTION 3 感知 MODULE_PREDICTION 4 预测 MODULE_DECISION 5 决策 MODULE_PLANNING 6 规划 MODULE_CONTROL 7 控制 MODULE_WHOLE 8 整车 表10 performance 字段 取值 说明 PERFORMANCE_UNSPECIFIED 0 未定义 PERFORMANCE_SAFETY 1 安全性 PERFORMANCE_REGULATION 2 合规性 PERFORMANCE_COMFORT 3 舒适性 PERFORMANCE_INTELLIGENCE 4 智能型
  • 背景 Octopus内置一套评测算法,用于对自动驾驶系统的性能表现进行多维度评测。内置评测算法的评测结果按照eva.proto中的定义,序列化成pb文件保存起来。 Octopus仿真平台的前端通过解析评测pb对评测结果进行展示,目前前端展示主要分为两大方面: 各个评测指标的通过/未通过/无效的结果展示。 仿真过程中关键数据的时间序列曲线图展示。 另外,对于用户自研的评测算法的评测结果,也可以按照eva.proto,序列化成pb文件保存起来,这样Octopus的仿真平台前端能够展示用户自研评测算法的评测结果。
  • 绿灯通行(Drive Through Green Light)检测 绿灯通行检测的目的是判断主车在接近十字路口后, 如果是绿灯, 主车是否直接通行而没有停止。 另外,当交通灯由红灯变为绿灯后, 主车重新启动的时间是否太大。 本设计认为在绿灯状态下, 如果前方没有行人和引导车的情况下, 主车在停止线前20m范围内发生停车行为, 则绿灯前直接通行不通过。 当交通灯由红灯变为绿灯后, 如果主车重新启动的时间大于一定阈值(本设计取3s), 则绿灯后重新启动时间太大。 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • 动作 Actions 用户首先使用初始动作InitActions 来初始化实体entities ,接着使用其他动作Actions 展开实体entities 的场景故事story . 初始动作 assign_init_speed 初始动作 assign_init_position 初始动作 acquire_position_init 动作 change_speed 动作 change_lane 动作 activate_controller 动作 lane_offset 动作 acquire_position 父主题: 代码样例 Code Examples
  • 评测列表 在评测列表,还可以进行以下操作: 表1 评测列表相关操作 任务 操作步骤 搜索评测 在搜索框中输入关键字搜索相关评测。支持通过评测名称和评测ID搜索。 查看评测详情 单击评测名称,页面跳转至评测详情页。 编辑评测 单击操作栏中的“编辑”,可编辑评测的信息。 说明: 当内置评测是system_default时,只支持编辑“评测模式”。 删除评测 单击操作栏中的“删除”,可删除该评测。 父主题: 评测管理
  • 修饰器 lane 用途:设定动作主体actor 所处的车道.可以修饰初始动作assign_init_position. 参数: 表1 lane参数 Parameter Type Mandatory Description lane int no Relative value of the target lane_id. same_as entity no Option to specify that the vehicle must be in the same lane as the referenced vehicle. side_of entity no Option to specify that the vehicle must be in another lane than the referenced vehicle. side side_left_right no Depending on the value the actor shall be on the right or left side of the referenced entity. How many lanes right or left of that entity is specified by the lane-parameter. offset length no Lateral offset to the target lane. side_of和same_as必须设置且仅设置一个. 使用side_of来设置车道时,必须同时使用lane和side. 使用lane+side_of m_left: side_left_right = left cut_in_vehicle.assign_init_position() with: lane(lane: 1, side_of: Ego, side: m_left) position(distance: 85.0m, behind: ego) 使用same_as m_left: side_left_right = left cut_in_vehicle.assign_init_position() with: lane(same_as: Ego) position(distance: 85.0m, behind: ego) 父主题: 修饰器 Modifiers
  • 逆行(Reverse Direction Driving)检测 逆行检测的目的是判断主车行使过程中是否按车道规定的方向行使。 根据OPNENDRIVE中对车道的lane id的定义, 沿着道路的reference line的前进方向, reference line右侧的lane id 由0逐渐递减, 左侧的lane id由0逐渐递增。 当主车前进方向与道路的方向相同时, 使标记值flag=1, 当主车与道路前进的方向相反时, 使标记值flag=-1。 当flag与主车所在的lane id的乘积大于0时, 则可以判定主车发生逆向行使。 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • 预警系统激活(Warning)检测 预警系统激活用于评价算法是否激活以下五项预警功能: 盲区预警 前方碰撞预警 车道偏离预警 泊车碰撞预警 后方横向车流预警 当算法pb中检测到预警项且状态为STATE_ACTIVE,则视该预警为激活态,否则为非激活态;当预警状态从非激活态转变为激活态,视为激活一次; 有些场景本身不需要激活预警:例如当一个场景中主车未泊车时,不需要激活泊车碰撞预警,此时如果激活预警反而说明主车算法出错;也有一些场景需要特定次数的激活预警:例如当一个场景中主车驾驶过程中会碰到n个盲区,此时必须正好激活n次才能证明主车算法通过;因此我们支持让用户设置各项子指标是否需要预警和期望的预警次数; 默认期望的预警次数为-1,此时只要该预警功能激活至少一次,则评测项通过;当设置期望的预警次数为正数或0时(0代表期望预警功能不被激活),只有当预警功能激活次数和期望预警次数相同时,评测项才通过; 该指标仅对有算法pb的场景有效。当算法pb中未设置预警项,或预警项状态皆为STATE_UNKNOWN时,该指标也视为无效; 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_ALL。 父主题: 内置评测指标说明
  • 逻辑场景管理 逻辑场景功能可批量生成仿真场景,扩充仿真场景库,为自动驾驶开发提供海量仿真场景。自定义逻辑场景的可以进行修改、删除操作,并支持仿真器A和仿真器B。创建泛化场景时,由于仿真器A的不同版本之间存在主车id不固定的问题,为了保证规控算法和评测算法能正确判断找到主车,泛化的场景文件的主车名称(name)字段应该为Ego。 逻辑场景中场景是完全独立存储与使用的,在逻辑场景生成的泛化场景非常多,其中有价值的场景比例低,如果存储到场景中会对场景模块造成冲击,当前如果认为逻辑场景中保存的个别场景价值高,可以采用下载场景文件到本地再上传到场景模块的方式保留该逻辑场景。 逻辑场景 泛化场景 父主题: 场景管理
  • 逻辑场景 Logical scenario 逻辑场景的参数声明通过:范围型[最小值..最大值] 和枚举型[值1, 值2] 的方式来实现泛化: 范围型支持float和scalar类型 枚举型支持int, float, bool, str, enum和scalar类型,且需要保证枚举列表中的元素均为相同类型. 例1:范围型 m_value: float = [2.0..3.0] v: speed = [5mps..10mps] delay: time = [40s..60s] m_a: acceleration = [0.00mpss..0.03mpss] 例2:枚举型 m_ id: int = [-1, 2] m_value: float = [2.0, 3.0] m_on_road: bool = [true, false] Ego_name: string = ["Audi_A3_2009_black", "Audi_A3_2009_red"] m_shape: dynamics_shape = [linear, sinusoidal] m_side: side_left_right = [left, right] v: speed = [5mps, 7mps, 10mps] m_a: acceleration = [0.01mpss, 0.03mpss] delay: time = [40s, 60s, 100s] 通过泛化参数,可以实现实体entity 、动作act ,以及修饰器modifier 的泛化. Struct类型不能直接泛化,而是通过泛化参数来进行泛化. 例1:entity泛化 Ego_name: string = ["Audi_A3_2009_black", "Audi_A3_2009_red"] Ego_controller: string = "DefaultDriver" Ego: vehicle with: keep(it.name == Ego_name) keep(it.initial_bm == Ego_controller) 例2:act泛化 m_lateral: bool = [true, false] m_speed: speed = [5mps..15mps] m_rate_profile: dynamics_shape = linear Ego.activate_controller(m_lateral, true) Ego.change_speed(target: m_speed, rate_peak: 0.0mpss, rate_profile: m_rate_profile) 例3:modifier泛化 m_speed: speed = [5mps..15mps] Ego.assign_init_speed() with: speed(speed: m_speed) 例4:Struct类型泛化 m_lane_id: int = [-1, 2] m_odr: odr_point = map.create_odr_point(road_id: '0', lane_id:m_lane_id, s: 5.0m, t: 0.0m) m_x: distance = [2m..7.5m] m_position_3d: position_3d = map.create_xyz_point(x: m_x, y: 10.0m ,z: 0.0m) m_pose_3d: pose_3d with: keep(it.odr_point == m_odr) 父主题: 参数声明 Parameter Declarations
  • distance_direction 用于触发条件object_distance和point_distance. distance_direction list ENUM_DISTANCE_DIRECTION = ("longitudinal", "lateral", "euclidianDistance") longitudinal:在x坐标中测量距离.正表示引用位于参考实体的前面. lateral:在y坐标中测量距离.正表示引用位于参考实体的左侧. euclidianDistance:欧氏距离. 父主题: Enum Lists
  • 车头时距(Time Headway)检测 车头时距检测的目的是判断主车行驶过程中与其他交通车的车头时距是否台小。 车头时距是主车与引导车的相对相对距离除以主车的速度。 即使主车未发生碰撞, 当车头时距过小时(该阈值可用户自定义,本设计默认取2s), 发生碰撞的风险太大, 这样也是不合理的。 车头时距和碰撞时间两者都是描述碰撞风险大小的。 车头时距适合判断主车和引导车速度都很高, 但相对速度比较小的情况。 碰撞时间适合主车和引导车相对速度比较大的情况。 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • 红灯前行为(Run Red Light)检测 红灯前行为检测的目的是判断主车在遇到红灯时能否在停止线前停车, 并且与停止线的距离保持在合理的范围。 判断能否在停止线前停车是指当主车前端超出停止线后, 主车速度大于零时, 则主车没能在停止线前停车。 这要排除主车在非箭头红绿灯右转的情况。 判断主车停车后距离停止线是否合理时, 如果主车在距离停止线[2,20]范围内发生停车行为, 则停车后与停止线的距离不合理。 如果主车在停止线[0.1, 2]m范围内发生停车行为,判断停止距离合理。 父主题: 内置评测指标说明
  • road_aids_type 匝道类型,用于静态场景的split场景和merge场景 road_aids_type list ENUM_ROAD_AIDS_TYPE = ("DType-1", "DType-2", "PType") DType-1(直接式1): DType-1(直接式1)是指匝道合入(分流)时直接汇入(离开)主路,并且匝道部分逐渐收缩(扩展)直到合入(离开)主路,如下图所示: DType-2(直接式2): DType-2(直接式2)是指匝道合入(分流)时直接汇入(离开)主路,主路的车道数也随之发生变化,匝道部分不进行收缩(扩展),如下图所示: PType(平行式): PType(平行式)是指匝道合入(分流)时先有一段平行于主路,然后匝道再逐渐收缩(扩展)直到合入(离开)主路,如下图所示: 父主题: Enum Lists
  • OCTPS_DATASET_DIR OCTPS_DATASET_DIR 为数据集源数据的数据路径,根据不同的数据来源,所挂路径不同, 示例: 本地:/tmp/dataset-temp/local_import/6f91947c-cd47-434b-b654-8332da961d7a/f7c9a054-3c9e-49c7-8934-a1e1d668eb12/ 标注:/tmp/label-data/ 通用存储:/tmp/warehouse/ 生成子集,视图:/tmp/dataset-new/6f91947c-cd47-434b-b654-8332da961d7a/dataset/ OBS需通过用户桶的ak,sk依据OBS相关的sdk获取到用户所需筛选的源数据,示例: 图1 示例 #认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全。 #本示例以ak和sk保存在环境变量中来实现身份验证为例,运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。 # 如果进行了加密还需要进行解密操作。
  • TARGET_RESULT_DIR TARGET_RESULT_DIR 为存放数据集筛选结果的路径,示例: temp-data/dataset/c8a73760-b5df-4f61-81d7-17e144fa6d69/result/data/results.json. 筛选结果按照特定格式保存在results.json 文件中。结果文件如下所示: ["dataset/data/1630057162343/1630057162343.json", " dataset/data/1630057162343/1630057162343.pcd", " dataset/data/1630057162343/camera_encoded_1-1630057162338.jpg", " dataset/data/1630057162443/1630057162443.json", " dataset/data/1630057162443/1630057162443.pcd", " dataset/data/1630057162443/camera_encoded_1-1630057162438.jpg"]
  • SOURCE_DATASET_FILE_DIR SOURCE_DATASET_FILE_DIR 为标注或通用存储生成数据集时的源数据索引json文件,示例: 标注: /tmp/dataset-temp/{versionId}/f7c9a054-3c9e-49c7-8934-a1e1d668eb12/result_frame.json Json文件内容示例: 通用存储: /tmp/data-warehouse/warehouse-dataset/ 注:通用存储可能存在多个索引json文件,需遍历。(file_attributes_1.json, file_attributes_2.json……) Json文件内容示例:
  • 基于样例的拓展 本章的场景样例可以结合第一章介绍的各模块代码样例进行修改和拓展.以straigh场景的osc为例,设定初始位置时,除了使用st坐标系(odr_point,即osc1.0中的LanePosition)还可以使用xyz坐标系(xyz_point,即osc1.0中的WorldPosition)来替代: st坐标系(odr_point)写法: Ego_InitPosition_LaneId: string = ['-1', '-2'] Ego_InitPosition_s: length = [0m..30m] Ego_Odr: odr_point = map.create_odr_point(road_id: '10', lane_id: Ego_InitPosition_LaneId, s: Ego_InitPosition_s, t: 0.0m) Ego_InitPosition: pose_3d with: keep(it.odr_point == Ego_Odr) 对应xyz坐标系(xyz_point)写法,其中y值-1.5m和-4.5m分别对应车道宽度为3m时的'-1'和'-2'车道的中心位置: y: length = [-1.5m, -4.5m] x: length = [0m..30m] Ego_xyz: xyz_point = map.create_xyz_point(x: x, y: y, z: 0.0m) Ego_InitPosition: pose_3d with: keep(it.xyz_point == Ego_xyz) 以上对等替换仅存在于odr_point的road_id固定的情形,当road_id(仿真器A中的TrackId)是一个可泛化的值时,起点可以出现在多条道路上,对应多段x和y值的组合区间,无法使用一个xyz_point直接对等泛化.此时可以使用多个动态场景来实现同等的泛化,例如: 假设地图上存在多条road,且对odr_point的road_id进行了泛化: Ego_InitPosition_Road_id: string = ['10', '1'] Ego_InitPosition_LaneId: string = ['-1', '-2'] Ego_InitPosition_s: length = [0m..30m] Ego_Odr: odr_point = map.create_odr_point(road_id: Ego_InitPosition_Road_id, lane_id: Ego_InitPosition_LaneId, s: Ego_InitPosition_s, t: 0.0m) Ego_InitPosition: pose_3d with: keep(it.odr_point == Ego_Odr) 可以在两个动态场景文件中分别使用一组xyz_point来替代,例如: 第一组对应road_id为'10'的情况(同前例): y: length = [-1.5m, -4.5m] x: length = [0m..30m] Ego_xyz: xyz_point = map.create_xyz_point(x: x, y: y, z: 0.0m) Ego_InitPosition: pose_3d with: keep(it.xyz_point == Ego_xyz) 第二组对应road_id为'1'的情况,该道路与road_id为'10'的道路垂直,x值的101.5m和104.5m分别对应车道宽度为3m时的'-1'和'-2'车道的中心位置: y: length = [-40m..-10m] x: length = [101.5m, 104.5m] Ego_xyz: xyz_point = map.create_xyz_point(x: x, y: y, z: 0.0m) Ego_InitPosition: pose_3d with: keep(it.xyz_point == Ego_xyz) 父主题: 种子地图的逻辑场景样例(仿真器A)
  • 限速标志牌前限速(Speed Limit Sign)检测 限速标志牌前限速检测的目的是判断主车在行驶过程中遇到限速标志牌时, 速度是否符合要求。 限速标志牌分为最高限速和最低限速两种。 最高限速是指主车速度不能高于对应的限速数值, 并且不能低于最高限速的75%。 最低限速是指主车速度不能低于对应的限速数值。 当主车距离限速标志牌在道路方向的距离小于某一阈值(本设计取车辆最前端超过限速标志), 并且主车所在车道是限速标志牌的有效范围, 当主车速度高于最高限速标志数值或低于最低限速标志数值时, 限速标志牌限速检测不通过。 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • orientation_3d 定义:由Tait–Bryan角度的三个参数roll(横滚角,围绕x轴的角度)、pitch(俯仰角,围绕y轴的角度)和yaw(偏航角,围绕z轴的角度)定义的三维角度. 用途:设置实体的朝向角度、用于构成pose_3d. 参数:参数如下表. 表1 orientation_3d参数 Parameter Type Mandatory Description roll angle yes rotation angle around the x-axis. pitch angle yes rotation angle around the y-axis. yaw angle yes rotation angle around the z-axis. 根据ISO 8855的定义,角度旋转的顺序是:首先进行yaw(围绕z轴)、接着pitch(围绕新y轴),最后roll(围绕新x轴). 当实体的朝向与road0的方向相同时,无需设置orientation_3d. angle的单位一般为rad(弧度)而非degree(角度),rad = degree*pi/180, 1rad约等于57.3度(详见scalar units中的angle units一节) 与road 0的方向相反(相差180°) m_orientation: orientation_3d with: keep(it.roll == 0.0rad) keep(it.pitch == 0.0rad) keep(it.yaw == 3.14rad) 父主题: Struct
  • 急刹(Emergency Braking)检测 自动驾驶车辆急刹有两个典型阈值:ACC(Adaptive Cruise Control)的最大减速度,和AEB(Autonomous Emergency Braking)的最大减速度。 急刹检测的目的是判断主车在行使过程中是否达到ACC和AEB的最大减速度。 ACC的最大减速度通常为。 AEB的最大减速度通常为。 该两项子指标关联的内置可视化时间序列数据均为:accX。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • 敏感性分析 Octopus平台支持基于参数组合、回归训练、敏捷性评定三个参数空间分析得到的敏感性分析结果,主要对逻辑场景的参数空间进行敏感性分析。在泛化任务完成的批量仿真任务后加上敏感性分析,然后把敏感性分析结果展现在新的泛化任务创建界面上,来帮助客户更好调节参数创建泛化任务。 进入到创建泛化任务界面,参数设置,选择参数设置后的“灵敏度分析”。 图5 灵敏度分析 选择关联到该逻辑场景下泛化任务的仿真任务。 图6 选择仿真任务 单击“确定”,界面出现上次任务的敏感性分析结果,展示每个参数的灵敏度参数,该值的范围在[0,1],该值越大,说明该参数的变化对评测分数的影响越大。 图7 泛化参数 用户可根据敏感性分析结果,设置当前各项参数的数值。
  • Scalar Units speed units。 SPEED_UNIT = { "meter_per_second": 1.0, "mps": 1.0, "kilometer_per_hour": 0.277777778, "kmph": 0.277777778, "kph": 0.277777778, "mile_per_hour": 0.447038889, "mph": 0.447038889, "miph": 0.447038889, "mmph": 0.000000278, "millimeter_per_hour": 0.000000278 } acceleration units。 ACCELERATION_UNIT = { "meter_per_sec_sqr": 1.0, "mpsps": 1.0, "mpss": 1.0, "kilometer_per_hour_per_sec": 0.5270462769, "kmphps": 0.5270462769, "mile_per_hour_per_sec": 0.6686096686, "miphps": 0.6686096686 } length units。 LENGTH_UNIT = { "nanometer": 0.000000001, "nm": 0.000000001, "micrometer": 0.000001, "millimeter": 0.001, "mm": 0.001, "centimeter": 0.01, "cm": 0.01, "meter": 1.0, "m": 1.0, "kilometer": 1000.0, "km": 1000.0, "inch": 0.0254, "feet": 0.3048, "mile": 1609.344, "mi": 1609.344 } time units。 TIME_UNIT = { "millisecond": 0.001, "ms": 0.001, "second": 1.0, "sec": 1.0, "s": 1.0, "minute": 60.0, "min": 60.0, "hour": 3600.0, "h": 3600.0 } angle units。 ANGLE_UNIT = { "degree": 57.295779513, "deg": 57.295779513, "radian": 1.0, "rad": 1.0 } 父主题: 附录 Appendix
  • 碰撞(Collision)检测 碰撞检测的目的是判断主车是否与其它交通参与物发生碰撞。 在进行碰撞检测时,根据与主车碰撞的物体类型的不同对碰撞类型进行细分。 具体分为: 车车碰撞检测 追尾检测 被追尾检测 正面对碰检测 垂直角度碰撞检测 斜角侧碰检测 车人碰撞检测 自行车碰撞检测 自行车碰撞检测 摩托车碰撞检测 静态障碍物检测 道路周边设施碰撞检测 碰撞电线杆检测 碰撞房屋检测 碰撞树木检测 碰撞绿化植被检测 碰撞交通标志检测 碰撞路边栅栏检测 未知类型物体碰撞检测 在每个类型的碰撞检测上,会同时进行两种检测。分别为: 是否碰撞检测 是否减速响应检测 是否转向响应检测 其中是否碰撞检测判断该种碰撞是否发生,在碰撞发生的基础上,进一步地判断主车是否有提前响应的动作。 当主车有提前减速或者转向避让,但只是没能及时刹住,本设计认为这种情况比完全没有采取任何措施避免碰撞的表现要好。 是否响应的判断是基于碰撞发生时,主车是否制动减速或者转向,发生了制动减速的标准是减速度大于,发生了转向的标准是横摆角速度大于,则主车进行了避免碰撞的响应措施。 另外,对于车车碰撞,本设计根据碰撞方位进行了细分。 当主车和发生碰撞的副车的夹角在或者内,并且主车位于副车后方,则认为发生追尾碰撞。 当主车和发生碰撞的副车的夹角在或者内,并且副车位于主车后方,则认为发生被追尾碰撞。 当主车与副车的碰撞夹角在内时,则认为发生正面对碰。 当主车与副车的碰撞夹角在或者内时,则认为发生垂直角度碰撞。 当主车与副车的碰撞角度在或或或内时,则认为发生斜角侧碰。 该指标关联的内置可视化时间序列数据为:暂无。 该指标的异常时间点记录类型为:POINT_TYPE_POINT。 父主题: 内置评测指标说明
  • position_3d 定义:笛卡尔(XYZ)坐标系中的三维位置(position). 用途:设置坐标系中的三维位置,用于构成xyz_point. 参数:参数如下表. 表1 position_3d参数 Parameter Type Mandatory Description x length yes position on the x-axis. y length yes position on the y-axis. z length yes position on the z-axis. 代码样例 my_position: position_3d with: keep(it.x == 150.0m) keep(it.y == 200.0m) keep(it.z == 0.0m) 父主题: Struct
  • 示例代码 下面是rosbag脱敏的算子示例: # mask.py import json import logging import multiprocessing as mp import os import shutil import time from pathlib import Path from typing import cast import av import numpy as np import open3d from rosbags.highlevel import AnyReader from rosbags.interfaces import ConnectionExtRosbag1, ConnectionExtRosbag2 from rosbags.rosbag1 import Writer as Writer1 from rosbags.rosbag2 import Writer as Writer2 from rosbags.serde import cdr_to_ros1, serialize_cdr from rosbags.typesys import get_types_from_msg, register_types from rosbags.typesys.types import builtin_interfaces__msg__Time as Time from rosbags.typesys.types import \ sensor_msgs__msg__CompressedImage as CompressedImage from rosbags.typesys.types import std_msgs__msg__Header as Header logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', ) LOG = logging.getLogger(__file__) # Octopus数据服务拉起镜像时灌入的环境变量 # 获取环境变量 input_path = os.getenv('input_path', 'data/hangyan-move.bag.bak') raw_dir = os.getenv('raw_dir', 'empty_dir/raw') # 抽取的文件存放目录 desens_dir = os.getenv('desensitized_dir', 'empty_dir/desens') # 脱敏后的文件存放目录 output_dir = os.getenv('output_dir', 'empty_dir/output') lidar_process_num = os.getenv('lidar_process_num', 5) # lidar数据进程数 # 用户自定义环境变量 rosbag_version = os.getenv('rosbag_version', '1') # rosbag版本,取值为'1'或'2' image_topics = [ x.strip(' ') for x in os.getenv('image_topics', '/camera_encoded_1').split(',') ] # 图像数据的topic列表 gnss_topic = os.getenv('gnss_topic', '/inspvax') # gnss数据的topic,gnss数据只能有一个topic lidar_topics = [ x.strip(' ') for x in os.getenv('lidar_topic', '/pandar').split(',') ] # 点云数据的topic列表 # 注册自定义消息类型 Video_encoded_data_text = Path('msgs/Video_encoded_data.msg').read_text() NovatelMessageHeader_text = Path('msgs/NovatelMessageHeader.msg').read_text() NovatelExtendedSolutionStatus_text = Path( 'msgs/NovatelExtendedSolutionStatus.msg').read_text() NovatelReceiverStatus_text = Path('msgs/NovatelReceiverStatus.msg').read_text() Inspvax_text = Path('msgs/Inspvax.msg').read_text() add_types = {} add_types.update( get_types_from_msg( Video_encoded_data_text, 'kyber_msgs/msg/Video_encoded_data', )) add_types.update( get_types_from_msg( NovatelMessageHeader_text, 'novatel_gps_msgs/msg/NovatelMessageHeader', )) add_types.update( get_types_from_msg( NovatelExtendedSolutionStatus_text, 'novatel_gps_msgs/msg/NovatelExtendedSolutionStatus', )) add_types.update( get_types_from_msg( NovatelReceiverStatus_text, 'novatel_gps_msgs/msg/NovatelReceiverStatus', )) add_types.update( get_types_from_msg( Inspvax_text, 'novatel_gps_msgs/msg/Inspvax', )) register_types(add_types) # create gnss file gnss_file_path = Path(raw_dir, 'gnss') / f'{gnss_topic}.json'.strip('/') Path.mkdir(gnss_file_path.parent, parents=True, exist_ok=True) def extract_image(input_rosbag): '''从原始rosbag中抽取图像数据.''' LOG.info('Start extracting image.') codec_ctx = av.codec.Codec('hevc', 'r') h265_code = codec_ctx.create() with AnyReader([Path(input_rosbag)]) as reader: for connection, timestamp, data in reader.messages(): topic = connection.topic if topic in image_topics: deserialized_data = reader.deserialize(data, connection.msgtype) try: data = deserialized_data.raw_data packet = av.packet.Packet(data) out = h265_code.decode(packet) img = None for frame in out: if frame.format.name != 'rgb24': frame = frame.reformat(format='rgb24') img = frame.to_image() # 图像存放路径 file_name = f'{timestamp}.jpg' f_path = Path(raw_dir, 'image') / topic.strip('/') tmp_path = Path(raw_dir, 'tmp_image') / topic.strip('/') Path.mkdir(tmp_path, parents=True, exist_ok=True) tmp_file = tmp_path / file_name file = f_path / file_name # 当未建立目录时,先基于topic名称建立目录 Path.mkdir(file.parent, parents=True, exist_ok=True) img.save(tmp_file) os.chmod(tmp_file, 0o777) os.chmod(file.parent, 0o777) shutil.move(tmp_file, file) except Exception as e: LOG.info("%s frame can not trans to jpg, message: %s", timestamp, str(e)) LOG.info('Finish extracting image.') def extract_lidar(task_id, task_num, input_rosbag): '''从原始rosbag中抽取点云数据.''' LOG.info('Start extracting pcd.') with AnyReader([Path(input_rosbag)]) as reader: for i, (connection, timestamp, data) in enumerate(reader.messages()): if i % task_num != task_id: continue topic = connection.topic if topic in lidar_topics: deserialized_data = reader.deserialize(data, connection.msgtype) pcd = open3d.geometry.PointCloud() reshaped = deserialized_data.data.reshape( int(len(deserialized_data.data) / 3), 3) pcd.points = open3d.utility.Vector3dVector(reshaped) file_name = f'{timestamp}.pcd' f_path = Path(raw_dir, 'lidar') / topic.strip('/') tmp_path = Path(raw_dir, 'tmp_lidar') / topic.strip('/') Path.mkdir(tmp_path, parents=True, exist_ok=True) tmp_file = tmp_path / file_name file = f_path / file_name # 当未建立目录时,先基于topic名称建立目录 Path.mkdir(file.parent, parents=True, exist_ok=True) open3d.io.write_point_cloud(str(tmp_file), pcd) os.chmod(tmp_file, 0o777) os.chmod(file.parent, 0o777) shutil.move(tmp_file, file) LOG.info('Finish extracting pcd.') def extract_gnss(input_rosbag): '''从原始rosbag中抽取gnss数据.''' LOG.info('Start extracting rosbag.') gnss_file = open(gnss_file_path, 'w') gnss = dict() with AnyReader([Path(input_rosbag)]) as reader: for connection, timestamp, data in reader.messages(): topic = connection.topic if topic == gnss_topic: deserialized_data = reader.deserialize(data, connection.msgtype) # 这里以msgytpe为NavSatFix为例 latitude = deserialized_data.latitude longitude = deserialized_data.longitude altitude = deserialized_data.altitude gnss[timestamp] = { 'latitude': latitude, 'longitude': longitude, 'altitude': altitude } gnss_file.write(json.dumps(gnss)) gnss_file.close() LOG.info('Finish extracting gnss.') def _get_masked_image(topic, timestamp): '''从脱敏后的图像数据中获取目标图像数据.''' file = Path(desens_dir, 'image') / topic.strip('/') / f'{timestamp}.jpg' if file.is_file(): return np.fromfile(file, dtype='uint8') else: return None def _get_conn_map(rosbag_version: int, reader, writer): '''构建connection的索引.''' conn_map = {} if rosbag_version == '1': for conn in reader.connections: if conn.topic in image_topics: conn_map[conn.id] = writer.add_connection( '/image', CompressedImage.__msgtype__, ) else: ext = cast(ConnectionExtRosbag1, conn.ext) conn_map[conn.id] = writer.add_connection( conn.topic, conn.msgtype, conn.msgdef, conn.md5sum, ext.callerid, ext.latching, ) elif rosbag_version == '2': for conn in reader.connections: if conn.topic in image_topics: conn_map[conn.id] = writer.add_connection( '/image', CompressedImage.__msgtype__, ) else: ext = cast(ConnectionExtRosbag2, conn.ext) conn_map[conn.id] = writer.add_connection( conn.topic, conn.msgtype, ext.serialization_format, ext.offered_qos_profiles, ) return conn_map def _serialize_data(rosbag_version, data, msgtype): '''对数据进行序列化.''' if rosbag_version == '1': return cdr_to_ros1(serialize_cdr(data, msgtype), msgtype) elif rosbag_version == '2': return serialize_cdr(data, msgtype) def generate_rosbag(input_rosbag, output_rosbag): '''生成脱敏后rosbag.''' LOG.info('Start generating rosbag.') gnss_file = open( Path(desens_dir, 'gnss') / f'{gnss_topic}.json'.strip('/'), 'r') gnss_data = json.load(gnss_file) gnss_file.close() Writer = Writer1 if rosbag_version == '1' else Writer2 with AnyReader([Path(input_rosbag) ]) as reader, Writer(Path(output_rosbag)) as writer: conn_map = _get_conn_map(rosbag_version, reader, writer) for connection, timestamp, data in reader.messages(): topic = connection.topic # 当topic为图像数据的topic时,读取脱敏后图像数据 if topic in image_topics: masked_data = _get_masked_image(topic, timestamp) if masked_data is None: # 没有解析出图像文件时,不要该帧了 continue deserialized_data = CompressedImage( Header( stamp=Time( sec=int(timestamp // 10**9), nanosec=int(timestamp % 10**9), ), frame_id='0', ), format='jpg', data=masked_data, ) data = _serialize_data( rosbag_version, deserialized_data, CompressedImage.__msgtype__, ) # 当topic为gnss数据时,读取脱敏后gnss数据 elif topic == gnss_topic: deserialized_data = reader.deserialize(data, connection.msgtype) deserialized_data.latitude = gnss_data.get( str(timestamp)).get('latitude') deserialized_data.longitude = gnss_data.get( str(timestamp)).get('longitude') deserialized_data.altitude = gnss_data.get( str(timestamp)).get('altitude') data = _serialize_data( rosbag_version, deserialized_data, connection.msgtype, ) # 当topic为点云数据时,读取脱敏后点云数据 elif topic in lidar_topics: deserialized_data = reader.deserialize( data, connection.msgtype, ) file = Path( desens_dir, 'lidar', ) / topic.strip('/') / f'{timestamp}.pcd' point_cloud = open3d.io.read_point_cloud(str(file)) deserialized_data.data = np.asarray( point_cloud.points).flatten() writer.write(conn_map[connection.id], timestamp, data) # 生成_SUC CES S文件标识完成数据抽取 Path(output_dir, '_SUCCESS').touch() LOG.info('Finish generating rosbag.') if __name__ == "__main__": LOG.info('Start user operator.') process_image = mp.Process(target=extract_image, args=(input_path, )) pool_lidar = mp.Pool(processes=lidar_process_num) for i in range(lidar_process_num): pool_lidar.apply_async(extract_lidar, args=(i, lidar_process_num, input_path)) process_gnss = mp.Process(target=extract_gnss, args=(input_path, )) # 启动子进程 process_image.start() pool_lidar.close() process_gnss.start() process_image.join() pool_lidar.join() process_gnss.join() LOG.info('Child processes exit.') # 生成_SUCCESS文件标识完成数据抽取 Path(raw_dir, '_SUCCESS').touch() # 后面输出的rosbag文件与输入的rosbag文件保持同名 output_rosbag_file = Path(output_dir, Path(input_path).name) # 如果输出文件夹不存在,先创建文件夹 Path.mkdir(output_rosbag_file.parent, parents=True, exist_ok=True) # 检测到脱敏任务结束后,生成新的rosbag文件 while time.sleep(1) is None: if Path(desens_dir).joinpath('_SUCCESS').is_file(): generate_rosbag(Path(input_path), output_rosbag_file) break
共100000条