将原有 TOYOTA_WILDLANDER 车型标识重命名为 TOYOTA_WILDLANDER_PHEV, 并更新相关指纹、平台名称和测试路由配置。同时增加该车型的 SRS 和 Hybrid ECU 固件版本信息。 此外,修改 dmonitoringd.py 中的监控逻辑,使在 always_on 模式下也能执行 DM.run_step 流程。 还更新了 launch_openpilot.sh 中的 API 和 ATHENA 服务地址。
883 lines
32 KiB
Python
Executable File
883 lines
32 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
import math
|
||
import os
|
||
|
||
from cereal import log, car
|
||
import cereal.messaging as messaging
|
||
from openpilot.common.constants import CV
|
||
from openpilot.common.git import get_short_branch
|
||
from openpilot.common.realtime import DT_CTRL
|
||
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
|
||
from openpilot.system.micd import SAMPLE_RATE, SAMPLE_BUFFER
|
||
from openpilot.selfdrive.ui.feedback.feedbackd import FEEDBACK_MAX_DURATION
|
||
|
||
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
|
||
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
|
||
StartupAlert, AlertCallbackType, wrong_car_mode_alert
|
||
|
||
|
||
AlertSize = log.SelfdriveState.AlertSize
|
||
AlertStatus = log.SelfdriveState.AlertStatus
|
||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||
EventName = log.OnroadEvent.EventName
|
||
|
||
|
||
# get event name from enum
|
||
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
|
||
|
||
|
||
class Events(EventsBase):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
|
||
|
||
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
|
||
return EVENTS
|
||
|
||
def get_event_name(self, event: int):
|
||
return EVENT_NAME[event]
|
||
|
||
def get_event_msg_type(self):
|
||
return log.OnroadEvent
|
||
|
||
|
||
|
||
# ********** helper functions **********
|
||
def get_display_speed(speed_ms: float, metric: bool) -> str:
|
||
speed = int(round(speed_ms * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)))
|
||
unit = 'km/h' if metric else 'mph'
|
||
return f"{speed} {unit}"
|
||
|
||
|
||
# ********** alert callback functions **********
|
||
|
||
|
||
def soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
|
||
def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
if soft_disable_time < int(0.5 / DT_CTRL):
|
||
return ImmediateDisableAlert(alert_text_2)
|
||
return SoftDisableAlert(alert_text_2)
|
||
return func
|
||
|
||
def user_soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
|
||
def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
if soft_disable_time < int(0.5 / DT_CTRL):
|
||
return ImmediateDisableAlert(alert_text_2)
|
||
return UserSoftDisableAlert(alert_text_2)
|
||
return func
|
||
|
||
def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
branch = get_short_branch() # Ensure get_short_branch is cached to avoid lags on startup
|
||
if "REPLAY" in os.environ:
|
||
branch = "replay"
|
||
|
||
return StartupAlert("警告:此分支未经测试", branch, alert_status=AlertStatus.userPrompt)
|
||
|
||
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
return NoEntryAlert(f"请将时速提高至 {get_display_speed(CP.minEnableSpeed, metric)} 来启用")
|
||
|
||
|
||
def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
return Alert(
|
||
f"转向在 {get_display_speed(CP.minSteerSpeed, metric)} 以下不可用",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.4)
|
||
|
||
|
||
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
first_word = '重新校准' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else '校准'
|
||
return Alert(
|
||
f"{first_word}进行中:{sm['liveCalibration'].calPerc:.0f}%",
|
||
f"请将时速提高至 {get_display_speed(MIN_SPEED_FILTER, metric)} 进行校准",
|
||
AlertStatus.normal, AlertSize.mid,
|
||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
|
||
|
||
|
||
def audio_feedback_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
duration = FEEDBACK_MAX_DURATION - ((sm['audioFeedback'].blockNum + 1) * SAMPLE_BUFFER / SAMPLE_RATE)
|
||
return NormalPermanentAlert(
|
||
"Recording Audio Feedback",
|
||
f"{round(duration)} second{'s' if round(duration) != 1 else ''} remaining. Press again to save early.",
|
||
priority=Priority.LOW)
|
||
|
||
|
||
# *** debug alerts ***
|
||
|
||
def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
full_perc = round(100. - sm['deviceState'].freeSpacePercent)
|
||
return NormalPermanentAlert("存储空间不足", f"已用 {full_perc}%")
|
||
|
||
|
||
def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
mdl = sm['modelV2'].velocity.x[0] if len(sm['modelV2'].velocity.x) else math.nan
|
||
err = CS.vEgo - mdl
|
||
msg = f"速度误差: {err:.1f} 米/秒"
|
||
return NoEntryAlert(msg, alert_text_1="Posenet速度无效")
|
||
|
||
|
||
def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning]
|
||
msg = ', '.join(not_running)
|
||
return NoEntryAlert(msg, alert_text_1="进程未运行")
|
||
|
||
|
||
def comm_issue_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
bs = [s for s in sm.data.keys() if not sm.all_checks([s, ])]
|
||
msg = ', '.join(bs[:4]) # can't fit too many on one line
|
||
return NoEntryAlert(msg, alert_text_1="进程间通信问题")
|
||
|
||
|
||
def camera_malfunction_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
all_cams = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
|
||
bad_cams = [s.replace('State', '') for s in all_cams if s in sm.data.keys() and not sm.all_checks([s, ])]
|
||
return NormalPermanentAlert("摄像头故障", ', '.join(bad_cams))
|
||
|
||
|
||
def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
rpy = sm['liveCalibration'].rpyCalib
|
||
yaw = math.degrees(rpy[2] if len(rpy) == 3 else math.nan)
|
||
pitch = math.degrees(rpy[1] if len(rpy) == 3 else math.nan)
|
||
angles = f"请重新安装设备 (俯仰角: {pitch:.1f}°, 偏航角: {yaw:.1f}°)"
|
||
return NormalPermanentAlert("校准无效", angles)
|
||
|
||
|
||
def paramsd_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
if not sm['liveParameters'].angleOffsetValid:
|
||
angle_offset_deg = sm['liveParameters'].angleOffsetDeg
|
||
title = "转向系统未对准"
|
||
text = f"角度偏移过大 (偏移量: {angle_offset_deg:.1f}°)"
|
||
elif not sm['liveParameters'].steerRatioValid:
|
||
steer_ratio = sm['liveParameters'].steerRatio
|
||
title = "转向传动比不匹配"
|
||
text = f"转向齿条几何可能不正确 (传动比: {steer_ratio:.1f})"
|
||
elif not sm['liveParameters'].stiffnessFactorValid:
|
||
stiffness_factor = sm['liveParameters'].stiffnessFactor
|
||
title = "轮胎刚度异常"
|
||
text = f"请检查轮胎、胎压或定位 (系数: {stiffness_factor:.1f})"
|
||
else:
|
||
return NoEntryAlert("paramsd 临时错误")
|
||
|
||
return NoEntryAlert(alert_text_1=title, alert_text_2=text)
|
||
|
||
def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
cpu = max(sm['deviceState'].cpuTempC, default=0.)
|
||
gpu = max(sm['deviceState'].gpuTempC, default=0.)
|
||
temp = max((cpu, gpu, sm['deviceState'].memoryTempC))
|
||
return NormalPermanentAlert("系统过热", f"{temp:.0f} °C")
|
||
|
||
|
||
def low_memory_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
return NormalPermanentAlert("内存不足", f"已用 {sm['deviceState'].memoryUsagePercent}%")
|
||
|
||
|
||
def high_cpu_usage_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
x = max(sm['deviceState'].cpuUsagePercent, default=0.)
|
||
return NormalPermanentAlert("CPU使用率过高", f"已用 {x}%")
|
||
|
||
|
||
def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
return NormalPermanentAlert("驾驶模型滞后", f"已丢帧 {sm['modelV2'].frameDropPerc:.1f}%")
|
||
|
||
|
||
def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
gb = sm['carControl'].actuators.accel / 4.
|
||
steer = sm['carControl'].actuators.torque
|
||
vals = f"油门: {round(gb * 100.)}%, 转向: {round(steer * 100.)}%"
|
||
return NormalPermanentAlert("操纵杆模式", vals)
|
||
|
||
|
||
def longitudinal_maneuver_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
ad = sm['alertDebug']
|
||
audible_alert = AudibleAlert.prompt if 'Active' in ad.alertText1 else AudibleAlert.none
|
||
alert_status = AlertStatus.userPrompt if 'Active' in ad.alertText1 else AlertStatus.normal
|
||
alert_size = AlertSize.mid if ad.alertText2 else AlertSize.small
|
||
return Alert(ad.alertText1, ad.alertText2,
|
||
alert_status, alert_size,
|
||
Priority.LOW, VisualAlert.none, audible_alert, 0.2)
|
||
|
||
|
||
def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
personality = str(personality).title()
|
||
personality_en = ""
|
||
if personality == "Aggressive":
|
||
personality_en = "激进"
|
||
elif personality == "Standard":
|
||
personality_en = "标准"
|
||
elif personality == "Relaxed":
|
||
personality_en = "舒适"
|
||
return NormalPermanentAlert(f"驾驶风格: {personality_en}", duration=1.5)
|
||
|
||
|
||
def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||
text = "请切换原厂LKAS状态以启用"
|
||
if CP.brand == "tesla":
|
||
text = "请切换到交通感知巡航控制以启用"
|
||
elif CP.brand == "mazda":
|
||
text = "请启用您的车辆LKAS以启用"
|
||
elif CP.brand == "nissan":
|
||
text = "请禁用您的车辆原厂LKAS以启用"
|
||
return NormalPermanentAlert("无效的LKAS设置", text)
|
||
|
||
|
||
|
||
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||
# ********** events with no alerts **********
|
||
|
||
EventName.stockFcw: {},
|
||
EventName.actuatorsApiUnavailable: {},
|
||
|
||
# ********** events only containing alerts displayed in all states **********
|
||
|
||
EventName.joystickDebug: {
|
||
ET.WARNING: joystick_alert,
|
||
ET.PERMANENT: NormalPermanentAlert("操纵杆模式"),
|
||
},
|
||
|
||
EventName.longitudinalManeuver: {
|
||
ET.WARNING: longitudinal_maneuver_alert,
|
||
ET.PERMANENT: NormalPermanentAlert("纵向操作模式",
|
||
"确保前方道路畅通"),
|
||
},
|
||
|
||
EventName.selfdriveInitializing: {
|
||
ET.NO_ENTRY: NoEntryAlert("系统初始化中"),
|
||
},
|
||
|
||
EventName.startup: {
|
||
ET.PERMANENT: StartupAlert("请随时准备接管您的车辆控制权")
|
||
},
|
||
|
||
EventName.startupMaster: {
|
||
ET.PERMANENT: startup_master_alert,
|
||
},
|
||
|
||
EventName.startupNoControl: {
|
||
ET.PERMANENT: StartupAlert("仅行车记录仪模式"),
|
||
ET.NO_ENTRY: NoEntryAlert("仅行车记录仪模式"),
|
||
},
|
||
|
||
EventName.startupNoCar: {
|
||
ET.PERMANENT: StartupAlert("不支持车辆的行车记录仪模式"),
|
||
},
|
||
|
||
EventName.startupNoSecOcKey: {
|
||
ET.PERMANENT: NormalPermanentAlert("仅行车记录仪模式",
|
||
"安全密钥不可用",
|
||
priority=Priority.HIGH),
|
||
},
|
||
|
||
EventName.dashcamMode: {
|
||
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
|
||
priority=Priority.LOWEST),
|
||
},
|
||
|
||
EventName.invalidLkasSetting: {
|
||
ET.PERMANENT: invalid_lkas_setting_alert,
|
||
ET.NO_ENTRY: NoEntryAlert("车道保持辅助系统(LKAS)设置无效"),
|
||
},
|
||
|
||
EventName.cruiseMismatch: {
|
||
#ET.PERMANENT: ImmediateDisableAlert("openpilot failed to cancel cruise"),
|
||
},
|
||
|
||
# openpilot doesn't recognize the car. This switches openpilot into a
|
||
# read-only mode. This can be solved by adding your fingerprint.
|
||
# See https://github.com/commaai/openpilot/wiki/Fingerprinting for more information
|
||
EventName.carUnrecognized: {
|
||
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
|
||
"车辆未识别",
|
||
priority=Priority.LOWEST),
|
||
},
|
||
|
||
EventName.aeb: {
|
||
ET.PERMANENT: Alert(
|
||
"刹车!",
|
||
"紧急制动:可能发生碰撞",
|
||
AlertStatus.critical, AlertSize.full,
|
||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
|
||
ET.NO_ENTRY: NoEntryAlert("AEB:可能发生碰撞"),
|
||
},
|
||
|
||
EventName.stockAeb: {
|
||
ET.PERMANENT: Alert(
|
||
"刹车!",
|
||
"原厂AEB:可能发生碰撞",
|
||
AlertStatus.critical, AlertSize.full,
|
||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
|
||
ET.NO_ENTRY: NoEntryAlert("原厂AEB:可能发生碰撞"),
|
||
},
|
||
|
||
EventName.fcw: {
|
||
ET.PERMANENT: Alert(
|
||
"刹车!",
|
||
"可能发生碰撞",
|
||
AlertStatus.critical, AlertSize.full,
|
||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
|
||
},
|
||
|
||
EventName.ldw: {
|
||
ET.PERMANENT: Alert(
|
||
"监测偏离车道",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
|
||
},
|
||
|
||
# ********** events only containing alerts that display while engaged **********
|
||
|
||
EventName.steerTempUnavailableSilent: {
|
||
ET.WARNING: Alert(
|
||
"转向暂时不可用",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.8),
|
||
},
|
||
|
||
EventName.preDriverDistracted: {
|
||
ET.PERMANENT: Alert(
|
||
"请注意",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.promptDriverDistracted: {
|
||
ET.PERMANENT: Alert(
|
||
"请注意",
|
||
"驾驶员分心",
|
||
AlertStatus.userPrompt, AlertSize.mid,
|
||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
|
||
},
|
||
|
||
EventName.driverDistracted: {
|
||
ET.PERMANENT: Alert(
|
||
"立即解除控制",
|
||
"驾驶员分心",
|
||
AlertStatus.critical, AlertSize.full,
|
||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
|
||
},
|
||
|
||
EventName.preDriverUnresponsive: {
|
||
ET.PERMANENT: Alert(
|
||
"触摸方向盘:未检测到面部",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.promptDriverUnresponsive: {
|
||
ET.PERMANENT: Alert(
|
||
"触摸方向盘",
|
||
"驾驶员无响应",
|
||
AlertStatus.userPrompt, AlertSize.mid,
|
||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
|
||
},
|
||
|
||
EventName.driverUnresponsive: {
|
||
ET.PERMANENT: Alert(
|
||
"立即解除控制",
|
||
"驾驶员无响应",
|
||
AlertStatus.critical, AlertSize.full,
|
||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
|
||
},
|
||
|
||
EventName.manualRestart: {
|
||
ET.WARNING: Alert(
|
||
"接管控制",
|
||
"请手动继续驾驶",
|
||
AlertStatus.userPrompt, AlertSize.mid,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
|
||
},
|
||
|
||
EventName.resumeRequired: {
|
||
ET.WARNING: Alert(
|
||
"按恢复键以解除停止状态",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
|
||
},
|
||
|
||
EventName.belowSteerSpeed: {
|
||
ET.WARNING: below_steer_speed_alert,
|
||
},
|
||
|
||
EventName.preLaneChangeLeft: {
|
||
ET.WARNING: Alert(
|
||
"请确认安全后进行左转变道",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.preLaneChangeRight: {
|
||
ET.WARNING: Alert(
|
||
"请确认安全后进行右转变道",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.laneChangeBlocked: {
|
||
ET.WARNING: Alert(
|
||
"盲点检测到车辆",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
|
||
},
|
||
|
||
EventName.laneChange: {
|
||
ET.WARNING: Alert(
|
||
"正在变道",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.steerSaturated: {
|
||
ET.WARNING: Alert(
|
||
"请接管控制",
|
||
"转向超出限制",
|
||
AlertStatus.userPrompt, AlertSize.mid,
|
||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 2.),
|
||
},
|
||
|
||
# Thrown when the fan is driven at >50% but is not rotating
|
||
EventName.fanMalfunction: {
|
||
ET.PERMANENT: NormalPermanentAlert("风扇故障", "可能是硬件问题"),
|
||
},
|
||
|
||
# Camera is not outputting frames
|
||
EventName.cameraMalfunction: {
|
||
ET.PERMANENT: camera_malfunction_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("摄像头故障"),
|
||
ET.NO_ENTRY: NoEntryAlert("摄像头故障:请重启设备"),
|
||
},
|
||
# Camera framerate too low
|
||
EventName.cameraFrameRate: {
|
||
ET.PERMANENT: NormalPermanentAlert("摄像头帧率低", "请重启设备"),
|
||
ET.SOFT_DISABLE: soft_disable_alert("摄像头帧率低"),
|
||
ET.NO_ENTRY: NoEntryAlert("摄像头帧率低:请重启设备"),
|
||
},
|
||
|
||
# Unused
|
||
|
||
EventName.locationdTemporaryError: {
|
||
ET.NO_ENTRY: NoEntryAlert("locationd临时错误"),
|
||
ET.SOFT_DISABLE: soft_disable_alert("locationd临时错误"),
|
||
},
|
||
|
||
EventName.locationdPermanentError: {
|
||
ET.NO_ENTRY: NoEntryAlert("locationd永久错误"),
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("locationd永久错误"),
|
||
ET.PERMANENT: NormalPermanentAlert("locationd永久错误"),
|
||
},
|
||
|
||
# openpilot tries to learn certain parameters about your car by observing
|
||
# how the car behaves to steering inputs from both human and openpilot driving.
|
||
# This includes:
|
||
# - steer ratio: gear ratio of the steering rack. Steering angle divided by tire angle
|
||
# - tire stiffness: how much grip your tires have
|
||
# - angle offset: most steering angle sensors are offset and measure a non zero angle when driving straight
|
||
# This alert is thrown when any of these values exceed a sanity check. This can be caused by
|
||
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
|
||
EventName.paramsdTemporaryError: {
|
||
ET.NO_ENTRY: paramsd_invalid_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("paramsd 临时错误"),
|
||
},
|
||
|
||
EventName.paramsdPermanentError: {
|
||
ET.NO_ENTRY: NoEntryAlert("paramsd永久错误"),
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd永久错误"),
|
||
ET.PERMANENT: NormalPermanentAlert("paramsd永久错误"),
|
||
},
|
||
|
||
# ********** events that affect controls state transitions **********
|
||
|
||
EventName.pcmEnable: {
|
||
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
|
||
},
|
||
|
||
EventName.buttonEnable: {
|
||
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
|
||
},
|
||
|
||
EventName.pcmDisable: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
},
|
||
|
||
EventName.buttonCancel: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: NoEntryAlert("取消按钮被按下"),
|
||
},
|
||
|
||
EventName.brakeHold: {
|
||
ET.WARNING: Alert(
|
||
"按恢复键以解除制动保持",
|
||
"",
|
||
AlertStatus.userPrompt, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
|
||
},
|
||
|
||
EventName.parkBrake: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: NoEntryAlert("停车制动已启用"),
|
||
},
|
||
|
||
EventName.pedalPressed: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: NoEntryAlert("踏板被按下",
|
||
visual_alert=VisualAlert.brakePressed),
|
||
},
|
||
|
||
EventName.steerDisengage: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: NoEntryAlert("方向盘被转动"),
|
||
},
|
||
|
||
EventName.preEnableStandstill: {
|
||
ET.PRE_ENABLE: Alert(
|
||
"释放制动以启用",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, creation_delay=1.),
|
||
},
|
||
|
||
EventName.gasPressedOverride: {
|
||
ET.OVERRIDE_LONGITUDINAL: Alert(
|
||
"",
|
||
"",
|
||
AlertStatus.normal, AlertSize.none,
|
||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.steerOverride: {
|
||
ET.OVERRIDE_LATERAL: Alert(
|
||
"",
|
||
"",
|
||
AlertStatus.normal, AlertSize.none,
|
||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1),
|
||
},
|
||
|
||
EventName.wrongCarMode: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: wrong_car_mode_alert,
|
||
},
|
||
|
||
EventName.resumeBlocked: {
|
||
ET.NO_ENTRY: NoEntryAlert("请按设定键以启用"),
|
||
},
|
||
|
||
EventName.wrongCruiseMode: {
|
||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||
ET.NO_ENTRY: NoEntryAlert("自适应巡航已禁用"),
|
||
},
|
||
|
||
EventName.steerTempUnavailable: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("转向暂时不可用"),
|
||
ET.NO_ENTRY: NoEntryAlert("转向暂时不可用"),
|
||
},
|
||
|
||
EventName.steerTimeLimit: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("车辆转向时间限制"),
|
||
ET.NO_ENTRY: NoEntryAlert("车辆转向时间限制"),
|
||
},
|
||
|
||
EventName.outOfSpace: {
|
||
ET.PERMANENT: out_of_space_alert,
|
||
ET.NO_ENTRY: NoEntryAlert("出库"),
|
||
},
|
||
|
||
EventName.belowEngageSpeed: {
|
||
ET.NO_ENTRY: below_engage_speed_alert,
|
||
},
|
||
|
||
EventName.sensorDataInvalid: {
|
||
ET.PERMANENT: Alert(
|
||
"传感器数据无效",
|
||
"可能是硬件问题",
|
||
AlertStatus.normal, AlertSize.mid,
|
||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=1.),
|
||
ET.NO_ENTRY: NoEntryAlert("传感器数据无效"),
|
||
ET.SOFT_DISABLE: soft_disable_alert("传感器数据无效"),
|
||
},
|
||
|
||
EventName.noGps: {
|
||
},
|
||
|
||
EventName.tooDistracted: {
|
||
ET.NO_ENTRY: NoEntryAlert("注意力分散程度过高"),
|
||
},
|
||
|
||
EventName.excessiveActuation: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"),
|
||
ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"),
|
||
},
|
||
|
||
EventName.overheat: {
|
||
ET.PERMANENT: overheat_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("系统过热"),
|
||
ET.NO_ENTRY: NoEntryAlert("系统过热"),
|
||
},
|
||
|
||
EventName.wrongGear: {
|
||
ET.SOFT_DISABLE: user_soft_disable_alert("挡位不在D挡"),
|
||
ET.NO_ENTRY: NoEntryAlert("挡位不在D挡"),
|
||
},
|
||
|
||
# This alert is thrown when the calibration angles are outside of the acceptable range.
|
||
# For example if the device is pointed too much to the left or the right.
|
||
# Usually this can only be solved by removing the mount from the windshield completely,
|
||
# and attaching while making sure the device is pointed straight forward and is level.
|
||
# See https://comma.ai/setup for more information
|
||
EventName.calibrationInvalid: {
|
||
ET.PERMANENT: calibration_invalid_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("校准无效:重新安装设备并重新校准"),
|
||
ET.NO_ENTRY: NoEntryAlert("校准无效:重新安装设备并重新校准"),
|
||
},
|
||
|
||
EventName.calibrationIncomplete: {
|
||
ET.PERMANENT: calibration_incomplete_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("校准未完成"),
|
||
ET.NO_ENTRY: NoEntryAlert("校准进行中"),
|
||
},
|
||
|
||
EventName.calibrationRecalibrating: {
|
||
ET.PERMANENT: calibration_incomplete_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("设备重新安装检测到:重新校准中"),
|
||
ET.NO_ENTRY: NoEntryAlert("设备重新安装检测到:重新校准中"),
|
||
},
|
||
|
||
EventName.doorOpen: {
|
||
ET.SOFT_DISABLE: user_soft_disable_alert("车门开启"),
|
||
ET.NO_ENTRY: NoEntryAlert("车门开启"),
|
||
},
|
||
|
||
EventName.seatbeltNotLatched: {
|
||
ET.SOFT_DISABLE: user_soft_disable_alert("安全带未系"),
|
||
ET.NO_ENTRY: NoEntryAlert("安全带未系"),
|
||
},
|
||
|
||
EventName.espDisabled: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("电子稳定控制系统已禁用"),
|
||
ET.NO_ENTRY: NoEntryAlert("电子稳定控制系统已禁用"),
|
||
},
|
||
|
||
EventName.lowBattery: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("电池电量低"),
|
||
ET.NO_ENTRY: NoEntryAlert("电池电量低"),
|
||
},
|
||
|
||
# Different openpilot services communicate between each other at a certain
|
||
# interval. If communication does not follow the regular schedule this alert
|
||
# is thrown. This can mean a service crashed, did not broadcast a message for
|
||
# ten times the regular interval, or the average interval is more than 10% too high.
|
||
EventName.commIssue: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("进程间通信问题"),
|
||
ET.NO_ENTRY: comm_issue_alert,
|
||
},
|
||
EventName.commIssueAvgFreq: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("进程间通信速率低"),
|
||
ET.NO_ENTRY: NoEntryAlert("进程间通信速率低"),
|
||
},
|
||
|
||
EventName.selfdrivedLagging: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("系统滞后"),
|
||
ET.NO_ENTRY: NoEntryAlert("自驾车进程滞后:请重启设备"),
|
||
},
|
||
|
||
# Thrown when manager detects a service exited unexpectedly while driving
|
||
EventName.processNotRunning: {
|
||
ET.NO_ENTRY: process_not_running_alert,
|
||
ET.SOFT_DISABLE: soft_disable_alert("进程未运行"),
|
||
},
|
||
|
||
EventName.radarFault: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("雷达错误:请重启车辆"),
|
||
ET.NO_ENTRY: NoEntryAlert("雷达错误:请重启车辆"),
|
||
},
|
||
|
||
EventName.radarTempUnavailable: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("雷达暂时不可用"),
|
||
ET.NO_ENTRY: NoEntryAlert("雷达暂时不可用"),
|
||
},
|
||
|
||
# Every frame from the camera should be processed by the model. If modeld
|
||
# is not processing frames fast enough they have to be dropped. This alert is
|
||
# thrown when over 20% of frames are dropped.
|
||
EventName.modeldLagging: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("驾驶模型滞后"),
|
||
ET.NO_ENTRY: NoEntryAlert("驾驶模型滞后"),
|
||
ET.PERMANENT: modeld_lagging_alert,
|
||
},
|
||
|
||
# Besides predicting the path, lane lines and lead car data the model also
|
||
# predicts the current velocity and rotation speed of the car. If the model is
|
||
# very uncertain about the current velocity while the car is moving, this
|
||
# usually means the model has trouble understanding the scene. This is used
|
||
# as a heuristic to warn the driver.
|
||
EventName.posenetInvalid: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("Posenet速度无效"),
|
||
ET.NO_ENTRY: posenet_invalid_alert,
|
||
},
|
||
|
||
# When the localizer detects an acceleration of more than 40 m/s^2 (~4G) we
|
||
# alert the driver the device might have fallen from the windshield.
|
||
EventName.deviceFalling: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("设备从支架掉落"),
|
||
ET.NO_ENTRY: NoEntryAlert("设备从支架掉落"),
|
||
},
|
||
|
||
EventName.lowMemory: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("内存不足:请重启设备"),
|
||
ET.PERMANENT: low_memory_alert,
|
||
ET.NO_ENTRY: NoEntryAlert("内存不足:请重启设备"),
|
||
},
|
||
|
||
EventName.accFaulted: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航故障:请重启车辆"),
|
||
ET.PERMANENT: NormalPermanentAlert("巡航故障:重启车辆以启用"),
|
||
ET.NO_ENTRY: NoEntryAlert("巡航故障:请重启车辆"),
|
||
},
|
||
|
||
EventName.espActive: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("电子稳定控制系统激活中"),
|
||
ET.NO_ENTRY: NoEntryAlert("电子稳定控制系统激活中"),
|
||
},
|
||
|
||
EventName.controlsMismatch: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("控制不匹配"),
|
||
ET.NO_ENTRY: NoEntryAlert("控制不匹配"),
|
||
},
|
||
|
||
# Sometimes the USB stack on the device can get into a bad state
|
||
# causing the connection to the panda to be lost
|
||
EventName.usbError: {
|
||
ET.SOFT_DISABLE: soft_disable_alert("USB错误:请重启设备"),
|
||
ET.PERMANENT: NormalPermanentAlert("USB错误:请重启设备"),
|
||
ET.NO_ENTRY: NoEntryAlert("USB错误:请重启设备"),
|
||
},
|
||
|
||
# This alert can be thrown for the following reasons:
|
||
# - No CAN data received at all
|
||
# - CAN data is received, but some message are not received at the right frequency
|
||
# If you're not writing a new car port, this is usually cause by faulty wiring
|
||
EventName.canError: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN总线错误"),
|
||
ET.PERMANENT: Alert(
|
||
"CAN总线错误:请检查连接",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
|
||
ET.NO_ENTRY: NoEntryAlert("CAN总线错误:请检查连接"),
|
||
},
|
||
|
||
EventName.canBusMissing: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN总线断开连接"),
|
||
ET.PERMANENT: Alert(
|
||
"CAN总线断开连接:可能电缆故障",
|
||
"",
|
||
AlertStatus.normal, AlertSize.small,
|
||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
|
||
ET.NO_ENTRY: NoEntryAlert("CAN总线断开连接:请检查连接"),
|
||
},
|
||
|
||
EventName.steerUnavailable: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS故障:请重启车辆"),
|
||
ET.PERMANENT: NormalPermanentAlert("LKAS故障:重启车辆以启用"),
|
||
ET.NO_ENTRY: NoEntryAlert("LKAS故障:请重启车辆"),
|
||
},
|
||
|
||
EventName.reverseGear: {
|
||
ET.PERMANENT: Alert(
|
||
"倒车中",
|
||
"",
|
||
AlertStatus.normal, AlertSize.full,
|
||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
|
||
ET.USER_DISABLE: ImmediateDisableAlert("倒档"),
|
||
ET.NO_ENTRY: NoEntryAlert("倒档"),
|
||
},
|
||
|
||
# On cars that use stock ACC the car can decide to cancel ACC for various reasons.
|
||
# When this happens we can no long control the car so the user needs to be warned immediately.
|
||
EventName.cruiseDisabled: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航已关闭"),
|
||
},
|
||
|
||
# When the relay in the harness box opens the CAN bus between the LKAS camera
|
||
# and the rest of the car is separated. When messages from the LKAS camera
|
||
# are received on the car side this usually means the relay hasn't opened correctly
|
||
# and this alert is thrown.
|
||
EventName.relayMalfunction: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("线束继电器故障"),
|
||
ET.PERMANENT: NormalPermanentAlert("线束继电器故障", "检查硬件"),
|
||
ET.NO_ENTRY: NoEntryAlert("线束继电器故障"),
|
||
},
|
||
|
||
EventName.speedTooLow: {
|
||
ET.IMMEDIATE_DISABLE: Alert(
|
||
"openpilot已取消",
|
||
"速度过低",
|
||
AlertStatus.normal, AlertSize.mid,
|
||
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
|
||
},
|
||
|
||
# When the car is driving faster than most cars in the training data, the model outputs can be unpredictable.
|
||
EventName.speedTooHigh: {
|
||
ET.WARNING: Alert(
|
||
"速度过高",
|
||
"在此速度下模型不稳定",
|
||
AlertStatus.userPrompt, AlertSize.mid,
|
||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
|
||
ET.NO_ENTRY: NoEntryAlert("减速以进行接合"),
|
||
},
|
||
|
||
EventName.vehicleSensorsInvalid: {
|
||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("车辆传感器无效"),
|
||
ET.PERMANENT: NormalPermanentAlert("车辆传感器校准中", "行驶以校准"),
|
||
ET.NO_ENTRY: NoEntryAlert("车辆传感器校准中"),
|
||
},
|
||
|
||
EventName.personalityChanged: {
|
||
ET.WARNING: personality_changed_alert,
|
||
},
|
||
|
||
EventName.userBookmark: {
|
||
ET.PERMANENT: NormalPermanentAlert("书签已保存", duration=1.5),
|
||
},
|
||
|
||
EventName.audioFeedback: {
|
||
ET.PERMANENT: audio_feedback_alert,
|
||
},
|
||
}
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# print all alerts by type and priority
|
||
from cereal.services import SERVICE_LIST
|
||
from collections import defaultdict
|
||
|
||
event_names = {v: k for k, v in EventName.schema.enumerants.items()}
|
||
alerts_by_type: dict[str, dict[Priority, list[str]]] = defaultdict(lambda: defaultdict(list))
|
||
|
||
CP = car.CarParams.new_message()
|
||
CS = car.CarState.new_message()
|
||
sm = messaging.SubMaster(list(SERVICE_LIST.keys()))
|
||
|
||
for i, alerts in EVENTS.items():
|
||
for et, alert in alerts.items():
|
||
if callable(alert):
|
||
alert = alert(CP, CS, sm, False, 1, log.LongitudinalPersonality.standard)
|
||
alerts_by_type[et][alert.priority].append(event_names[i])
|
||
|
||
all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {}
|
||
for et, priority_alerts in alerts_by_type.items():
|
||
all_alerts[et] = sorted(priority_alerts.items(), key=lambda x: x[0], reverse=True)
|
||
|
||
for status, evs in sorted(all_alerts.items(), key=lambda x: x[0]):
|
||
print(f"**** {status} ****")
|
||
for p, alert_list in evs:
|
||
print(f" {repr(p)}:")
|
||
print(" ", ', '.join(alert_list), "\n")
|