跳转至

Python 脚本判定开发指南

版本说明

Lua 判定脚本逐步不再维护,后续脚本支持开发工作都将在 Python 分支上进行。

1. Python 脚本原理

Python 脚本内嵌在 CybertronJudgeConsole(后简称 Judge)程序中运行,Judge 程序通过从热区获取到所有 actors 每帧的状态,完成一些状态或者动作的判定,比如车辆是否压线、是否闯红灯等。同时 Judge 也可以将这些 actors 的状态传递给内嵌的 Python 程序,让 Python 程序完成更多的自定义判定。

2. Python 判定脚本结构

在 SimOne 中上传使用的自定义脚本判定包,是一个至少包含了 interface.py 文件的 ZIP 压缩包。

打包注意

压缩 ZIP 包时,直接对文件压缩,不要对包含文件的目录压缩。

interface.py 需要提供以下 3 个关键函数:

def on_init(config_str, main_vehicle_id):
    """案例启动时调用。main_vehicle_id 为主车 ID。"""
    ...

def on_loop(pre_actors, cur_actors, cur_t):
    """每帧调用。pre_actors 为上一帧状态,cur_actors 为当前帧状态,cur_t 为时间戳。"""
    ...

def on_exit():
    """案例结束前调用。"""
    ...
  • on_init(config_str, main_vehicle_id):在案例启动时被调用。main_vehicle_id 为主车 ID。初始化成功须返回 True
  • on_loop(pre_actors, cur_actors, cur_t):在运行的每一帧被调用。pre_actors 是上一帧所有 actors 的状态,cur_actors 是当前帧所有 actors 的状态,cur_t 是当前时间戳。如果要执行实时判定,应该放在此函数中逐帧检测。
  • on_exit():在案例结束前被调用。

每个 actor 代表场景中的一个动态实体(车辆、行人、自行车),具有位置、尺寸、所在车道等属性,可在 on_loop 中逐帧检测。

3. on_loop 返回值说明

on_loop 需要返回 (return_code, message) 元组:

返回码 说明
CheckResult.PENDING 当前没有判定结果(感兴趣的事件未发生),message 为空
CheckResult.PENDING_WITH_REPORT 有感兴趣的事件发生,message 为自定义事件描述,此信息会发送到外界
CheckResult.FAIL 事件已发生,立刻以失败状态结束案例,message 为自定义事件描述
CheckResult.SUC 事件已发生,立刻以成功状态结束案例,message 为自定义事件描述

命名别名

以上常量也可通过 simone 名字空间访问,例如 simone.PENDINGsimone.FAILsimone.SUCC,与 CheckResult.X 写法等价。

4. 单机版调试说明

推荐在单机版上测试开发 Python 脚本,测试通过后再上传云端(如需云端运行)。

从安装包里启动 StartAllDebug.bat,在启动案例后可以看到 CybertronJudgeConsole 控制台,这样就可以在 Python 脚本中打印日志,然后在控制台观测日志,或者直接用 pdb 在线调试。

为了减轻频繁打包、上传 Python 脚本、测试的流程,可以将判定名称在 SimOne 案例编辑界面改为以下特殊字符串:

87da536b-c9ac-4567-8e9e-7213b1e01349-test-only

然后将判定代码放在 C:\simone_scripts 中并在此目录修改调试,这样每次案例运行时将直接使用该目录中的代码,而不是 ZIP 包中的代码,省去了频繁修改代码 → 压缩打包 → 上传脚本的测试流程。

5. API 字段说明

simone 名字空间

判定暴露的方法和属性都在 simone 名字空间下。

方法 返回类型 说明
log_info(string) 打印日志到控制台和文件
log_error(string) 打印错误日志
log_warning(string) 打印警告日志
get_left_lane(string) string 获取某个车道的左车道,如 simone.get_left_lane(lane_name)
get_right_lane(string) string 获取某个车道的右车道,如 simone.get_right_lane(lane_name)
get_traffic_light(int id) string 按 opendrive id 查询交通灯当前状态,返回 'yellow''red''green''unknown' 之一

actor 对象

actor 表示场景中的一辆车或行人,包含多种属性,通过索引值和类型确定。

方法 返回类型 说明
get_bool(index) bool 获取布尔值属性,如 actor.get_bool(simone.ActorAttr.STOPPED)
get_double(index) double 获取数值属性,如 actor.get_double(simone.ActorAttr.DIST_TO_LEFT_LANE_LINE)
get_vec3(index) vec3 获取 vec3 属性,如 actor.get_vec3(simone.ActorAttr.POS)
get_int(index) int 获取 int 属性,如 actor.get_int(ActorAttr.LEADING_VEHICLE_ID)
get_string(index) string 获取 string 属性,如 actor.get_string(simone.ActorAttr.CENTER_LANE_NAME)
get_id() int 获取车辆 id
get_type() int 获取车辆类型(主车、对手车、自行车等)

vec3 类型:具有 .x.y.z 属性。

ActorAttr 属性索引

根据属性类型用对应方法获取,如 actor.get_bool(simone.ActorAttr.STOPPED)

属性索引 类型 说明
TIME double 车辆属性获取时的时间戳
NAME string actor 名字
POS vec3 车辆位置
YAW double 车辆 yaw 角度
SIZE_3D vec3 车辆尺寸
LONG_SPEED double 车辆纵向速度
LAT_SPEED double 车辆横向速度
LONG_ACCEL double 车辆纵向加速度
LAT_ACCEL double 车辆横向加速度
LEFT_LIGHT_ON bool 左车灯是否打开
RIGHT_LIGHT_ON bool 右车灯是否打开
WARNING_LIGHT_ON bool 双闪是否打开
STOPPED bool 是否处于停车状态
STOPPED_TIME double 停止时间
DIST_TO_LANE_LINE double 到左右车道线距离(取最小值)
DIST_TO_LEFT_LANE_LINE double 到左车道线距离
DIST_TO_RIGHT_LANE_LINE double 到右车道线距离
DIST_TO_CENTER_LANE_LINE double 到车道中心线距离
DIST_TO_STOPLINE_WHEN_STOP double 停止状态时到停止线的距离(运动状态时返回 NaN)
TTC double TTC
LEADING_VEHICLE_DISTANCE double 前车距离
LEADING_VEHICLE_ID int 前车 ID
TOUCH_DASH_LANE_LINE bool 是否压了虚线
TOUCH_SOLID_LANE_LINE bool 是否压了实线
OUT_OF_ROAD bool 是否开出路外
CENTER_LANE_NAME string 车辆中心点所在车道名字
WHOLE_LANE_NAME string 整车所在车道名字
THROTTLE double 油门数值(0 ~ 1)
STEERING double 方向盘转角,左负右正(角度)
BRAKE double 刹车数值(0 ~ 1)
GEAR int 当前挡位,-1 为倒挡
PRIVATE_VEHICLE_DIR vec3 车辆方向
PRIVATE_ACCEL_3D vec3 车辆加速度
PRIVATE_SPEED_3D vec3 车辆速度
PRIVATE_CENTER_TO_LEFT_LANE_LINE double 车辆中心点到左车道线距离
PRIVATE_CENTER_TO_RIGHT_LANE_LINE double 车辆中心点到右车道线距离
PRIVATE_TOUCH_LEFT_LANE_LINE bool 是否压了左车道线
PRIVATE_TOUCH_RIGHT_LANE_LINE bool 是否压了右车道线

hdmap 接口

方法 说明
hdmap.get_all_parking_space_ids() 获取所有停车位 id
hdmap.get_parking_space_by_id(id) 获取某个车位信息,返回 {"pts": [pt_a, pt_b, pt_c, pt_d], "road_id": "..."} (ab: 左, bc: 后, cd: 右, da: 前)

ActorType

常量 说明
ActorType.MAIN_VEHICLE 主车
ActorType.PEDESTRIAN 行人
ActorType.BICYCLE 两轮车
ActorType.STATIC_OBJECT 静态物体

6. 多判定组合说明

单 Python 环境限制

目前因架构原因,Judge 内只有一个 Python 环境,所以如果一个案例有多个 Python 判定,interface.py 中的 on_initon_loop 等函数会相互覆盖,无法正常运行。

推荐做法:在一个 Python 判定包中包含多个子判定 py 文件,例如判定压线的 touch_lane_line.py、判定红灯的 traffic_light.py,这些子判定都由入口 interface.py 引用,以满足多种判定需求。

7. 示例:碰撞检测脚本

以下示例演示如何检测对手车辆与主车的碰撞(使用 shapely 计算多边形距离):

import json
from simone import *
import shapely
from shapely.geometry import Polygon

main_vehicle_id = -1
threshold_distance = 0.5  # 碰撞判定距离阈值(米)

def get_polygon(actor):
    """根据 actor 的位置、朝向、尺寸构造旋转矩形多边形。"""
    pos = actor.get_vec3(ActorAttr.POS)
    yaw = actor.get_double(ActorAttr.YAW)
    size = actor.get_vec3(ActorAttr.SIZE_3D)
    width, length = size.x, size.y

    rect = Polygon([
        (pos.x - length / 2, pos.y - width / 2),
        (pos.x + length / 2, pos.y - width / 2),
        (pos.x + length / 2, pos.y + width / 2),
        (pos.x - length / 2, pos.y + width / 2),
    ])
    return shapely.affinity.rotate(rect, yaw, origin='center', use_radians=True)

def on_init(config_str, main_v_id):
    global main_vehicle_id
    main_vehicle_id = main_v_id

    # 示例:读取地图停车位信息
    ids = hdmap.get_all_parking_space_ids()
    if len(ids) > 0:
        parking = hdmap.get_parking_space_by_id(ids[0])
        log_info(f'first parking slot info: {parking}')

    return True

def on_loop(pre_actors, cur_actors, cur_t):
    main_actor = cur_actors[main_vehicle_id]
    main_polygon = get_polygon(main_actor)

    for actor_id, actor in cur_actors.items():
        if actor.get_id() == main_vehicle_id:
            continue

        target_polygon = get_polygon(actor)
        leading_id = actor.get_int(ActorAttr.LEADING_VEHICLE_ID)
        min_distance = main_polygon.distance(target_polygon)

        if min_distance <= threshold_distance and leading_id == main_vehicle_id:
            return (CheckResult.PENDING_WITH_REPORT, 'crash with main vehicle')

    return (CheckResult.PENDING, '')

def on_exit():
    print('python script exit')

另请参阅

  • Lua 脚本判定管理 — 在 SimOne 界面上传和绑定脚本判定包的操作步骤(Python 脚本包的上传入口相同)