1177 lines
41 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import math
import os
from enum import IntEnum
from collections.abc import Callable
from cereal import log, car
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
2024-05-24 02:41:19 -07:00
from openpilot.common.params import Params
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.system.version import get_short_branch
2024-05-24 02:41:19 -07:00
params = Params()
params_memory = Params("/dev/shm/params")
AlertSize = log.ControlsState.AlertSize
AlertStatus = log.ControlsState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
EventName = car.CarEvent.EventName
# Alert priorities
class Priority(IntEnum):
LOWEST = 0
LOWER = 1
LOW = 2
MID = 3
HIGH = 4
HIGHEST = 5
# Event types
class ET:
2025-03-26 17:35:28 +08:00
ENABLE = 'enable'
PRE_ENABLE = 'preEnable'
OVERRIDE_LATERAL = 'overrideLateral'
OVERRIDE_LONGITUDINAL = 'overrideLongitudinal'
NO_ENTRY = 'noEntry'
WARNING = 'warning'
USER_DISABLE = 'userDisable'
SOFT_DISABLE = 'softDisable'
IMMEDIATE_DISABLE = 'immediateDisable'
PERMANENT = 'permanent'
# get event name from enum
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
class Events:
def __init__(self):
self.events: list[int] = []
self.static_events: list[int] = []
self.events_prev = dict.fromkeys(EVENTS.keys(), 0)
@property
def names(self) -> list[int]:
return self.events
def __len__(self) -> int:
return len(self.events)
def add(self, event_name: int, static: bool=False) -> None:
if static:
self.static_events.append(event_name)
self.events.append(event_name)
def clear(self) -> None:
self.events_prev = {k: (v + 1 if k in self.events else 0) for k, v in self.events_prev.items()}
self.events = self.static_events.copy()
def contains(self, event_type: str) -> bool:
return any(event_type in EVENTS.get(e, {}) for e in self.events)
def create_alerts(self, event_types: list[str], callback_args=None):
if callback_args is None:
callback_args = []
ret = []
for e in self.events:
types = EVENTS[e].keys()
for et in event_types:
if et in types:
alert = EVENTS[e][et]
if not isinstance(alert, Alert):
alert = alert(*callback_args)
if DT_CTRL * (self.events_prev[e] + 1) >= alert.creation_delay:
alert.alert_type = f"{EVENT_NAME[e]}/{et}"
alert.event_type = et
ret.append(alert)
return ret
def add_from_msg(self, events):
for e in events:
self.events.append(e.name.raw)
def to_msg(self):
ret = []
for event_name in self.events:
event = car.CarEvent.new_message()
event.name = event_name
for event_type in EVENTS.get(event_name, {}):
setattr(event, event_type, True)
ret.append(event)
return ret
class Alert:
def __init__(self,
alert_text_1: str,
alert_text_2: str,
alert_status: log.ControlsState.AlertStatus,
alert_size: log.ControlsState.AlertSize,
priority: Priority,
visual_alert: car.CarControl.HUDControl.VisualAlert,
audible_alert: car.CarControl.HUDControl.AudibleAlert,
duration: float,
alert_rate: float = 0.,
creation_delay: float = 0.):
self.alert_text_1 = alert_text_1
self.alert_text_2 = alert_text_2
self.alert_status = alert_status
self.alert_size = alert_size
self.priority = priority
self.visual_alert = visual_alert
self.audible_alert = audible_alert
self.duration = int(duration / DT_CTRL)
self.alert_rate = alert_rate
self.creation_delay = creation_delay
self.alert_type = ""
self.event_type: str | None = None
def __str__(self) -> str:
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
def __gt__(self, alert2) -> bool:
if not isinstance(alert2, Alert):
return False
return self.priority > alert2.priority
class NoEntryAlert(Alert):
def __init__(self, alert_text_2: str,
2025-03-26 08:48:53 +08:00
alert_text_1: str = "openpilot 不可用",
visual_alert: car.CarControl.HUDControl.VisualAlert=VisualAlert.none):
super().__init__(alert_text_1, alert_text_2, AlertStatus.normal,
AlertSize.mid, Priority.LOW, visual_alert,
AudibleAlert.refuse, 3.)
class SoftDisableAlert(Alert):
def __init__(self, alert_text_2: str):
2025-03-26 08:48:53 +08:00
super().__init__("立即接管控制", alert_text_2,
AlertStatus.userPrompt, AlertSize.full,
Priority.MID, VisualAlert.steerRequired,
AudibleAlert.warningSoft, 2.),
# less harsh version of SoftDisable, where the condition is user-triggered
class UserSoftDisableAlert(SoftDisableAlert):
def __init__(self, alert_text_2: str):
super().__init__(alert_text_2),
2025-03-26 08:48:53 +08:00
self.alert_text_1 = "openpilot 将解除控制"
class ImmediateDisableAlert(Alert):
def __init__(self, alert_text_2: str):
2025-03-26 08:48:53 +08:00
super().__init__("立即接管控制", alert_text_2,
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired,
AudibleAlert.warningImmediate, 4.),
class EngagementAlert(Alert):
def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert):
super().__init__("", "",
AlertStatus.normal, AlertSize.none,
Priority.MID, VisualAlert.none,
audible_alert, .2),
class NormalPermanentAlert(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str = "", duration: float = 0.2, priority: Priority = Priority.LOWER, creation_delay: float = 0.):
super().__init__(alert_text_1, alert_text_2,
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
priority, VisualAlert.none, AudibleAlert.none, duration, creation_delay=creation_delay),
class StartupAlert(Alert):
2025-03-26 08:48:53 +08:00
def __init__(self, alert_text_1: str, alert_text_2: str = "请始终保持双手在方向盘上,眼睛注视道路", alert_status=AlertStatus.normal):
super().__init__(alert_text_1, alert_text_2,
alert_status, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
# ********** 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 **********
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int], Alert]
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) -> 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) -> 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) -> Alert:
branch = get_short_branch() # Ensure get_short_branch is cached to avoid lags on startup
if "REPLAY" in os.environ:
branch = "replay"
2024-05-29 03:22:15 -07:00
return StartupAlert("Hippity hoppity this is my property", "so I do what I want 🐸", alert_status=AlertStatus.frogpilot)
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
return Alert(
2025-03-26 08:48:53 +08:00
f"转向在 {get_display_speed(CP.minSteerSpeed, metric)} 之下不可用",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
2025-03-26 08:48:53 +08:00
first_word = '重新校准' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else '校准'
return Alert(
2025-03-26 08:48:53 +08:00
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 no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
return Alert(
2025-03-26 08:48:53 +08:00
"GPS信号差",
"如果天空可见,则硬件故障",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=300.)
def torque_nn_load_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
model_name = params.get("NNFFModelName", encoding='utf-8')
if model_name == "":
return Alert(
2025-03-26 08:48:53 +08:00
"NNFF扭矩控制器不可用",
"请捐赠日志给Twilsonco以支持您的车辆",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 5.0)
else:
return Alert(
2025-03-26 08:48:53 +08:00
"NNFF扭矩控制器已加载",
model_name,
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.engage, 5.0)
# *** debug alerts ***
def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
full_perc = round(100. - sm['deviceState'].freeSpacePercent)
2025-03-26 08:48:53 +08:00
return NormalPermanentAlert("存储空间不足", f"{full_perc}% 已满")
def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
mdl = sm['modelV2'].velocity.x[0] if len(sm['modelV2'].velocity.x) else math.nan
err = CS.vEgo - mdl
2025-03-26 08:48:53 +08:00
msg = f"速度误差: {err:.1f} m/s"
return NoEntryAlert(msg, alert_text_1="姿态网络速度无效")
def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning]
msg = ', '.join(not_running)
2025-03-26 08:48:53 +08:00
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) -> 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
2025-03-26 08:48:53 +08:00
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) -> 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, ])]
2025-03-26 08:48:53 +08:00
return NormalPermanentAlert("摄像头故障", ', '.join(bad_cams))
def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> 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)
2025-03-26 08:48:53 +08:00
angles = f"重新安装设备 (俯仰: {pitch:.1f}°, 偏航: {yaw:.1f}°)"
return NormalPermanentAlert("校准无效", angles)
def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
cpu = max(sm['deviceState'].cpuTempC, default=0.)
gpu = max(sm['deviceState'].gpuTempC, default=0.)
temp = max((cpu, gpu, sm['deviceState'].memoryTempC))
2025-03-26 08:48:53 +08:00
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) -> Alert:
2025-03-26 08:48:53 +08:00
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) -> Alert:
x = max(sm['deviceState'].cpuUsagePercent, default=0.)
2025-03-26 08:48:53 +08:00
return NormalPermanentAlert("CPU使用率高", f"{x}% 已使用")
def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
2025-03-26 08:48:53 +08:00
return NormalPermanentAlert("驾驶模型滞后", f"{sm['modelV2'].frameDropPerc:.1f}% 帧丢失")
def wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
2025-03-26 08:48:53 +08:00
text = "启用自适应巡航以进行接入"
if CP.carName == "honda":
2025-03-26 08:48:53 +08:00
text = "启用主开关以进行接入"
return NoEntryAlert(text)
def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
axes = sm['testJoystick'].axes
gb, steer = list(axes)[:2] if len(axes) else (0., 0.)
2025-03-26 08:48:53 +08:00
vals = f"油门: {round(gb * 100.)}%, 转向: {round(steer * 100.)}%"
return NormalPermanentAlert("操纵杆模式", vals)
# FrogPilot Alerts
def holiday_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
holiday_messages = {
1: ("Happy April Fool's Day! 🤡", "aprilFoolsAlert"),
2: ("Merry Christmas! 🎄", "christmasAlert"),
3: ("¡Feliz Cinco de Mayo! 🌮", "cincoDeMayoAlert"),
4: ("Happy Easter! 🐰", "easterAlert"),
5: ("Happy Fourth of July! 🎆", "fourthOfJulyAlert"),
6: ("Happy Halloween! 🎃", "halloweenAlert"),
7: ("Happy New Year! 🎉", "newYearsDayAlert"),
8: ("Happy St. Patrick's Day! 🍀", "stPatricksDayAlert"),
9: ("Happy Thanksgiving! 🦃", "thanksgivingAlert"),
10: ("Happy Valentine's Day! ❤️", "valentinesDayAlert"),
11: ("Happy World Frog Day! 🐸", "worldFrogDayAlert"),
}
theme_id = params_memory.get_int("CurrentHolidayTheme")
message, alert_type = holiday_messages.get(theme_id, ("", ""))
return Alert(
message,
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 5.)
def no_lane_available_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
lane_width = sm['frogpilotPlan'].laneWidthLeft if CS.leftBlinker else sm['frogpilotPlan'].laneWidthRight
2025-03-26 08:48:53 +08:00
lane_width_msg = f"{lane_width:.1f}" if metric else f"{lane_width * CV.METER_TO_FOOT:.1f} 英尺"
return Alert(
2025-03-26 08:48:53 +08:00
"没有可用车道",
f"检测到的车道宽度仅为 {lane_width_msg}",
AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# ********** events with no alerts **********
EventName.stockFcw: {},
# ********** events only containing alerts displayed in all states **********
EventName.joystickDebug: {
ET.WARNING: joystick_alert,
ET.PERMANENT: NormalPermanentAlert("Joystick Mode"),
},
EventName.controlsInitializing: {
ET.NO_ENTRY: NoEntryAlert("System Initializing"),
},
EventName.startup: {
ET.PERMANENT: StartupAlert("Be ready to take over at any time")
},
EventName.startupMaster: {
ET.PERMANENT: startup_master_alert,
},
2025-03-26 08:48:53 +08:00
# 车辆已识别,但仅标记为行车记录仪模式
EventName.startupNoControl: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: StartupAlert("行车记录仪模式"),
ET.NO_ENTRY: NoEntryAlert("行车记录仪模式"),
},
2025-03-26 08:48:53 +08:00
# 车辆未被识别
EventName.startupNoCar: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: StartupAlert("不支持的车辆的行车记录仪模式"),
},
EventName.startupNoFw: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: StartupAlert("车辆未识别",
"检查逗号电源连接",
alert_status=AlertStatus.userPrompt),
},
EventName.dashcamMode: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
priority=Priority.LOWEST),
},
EventName.invalidLkasSetting: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("库存LKAS已开启",
"关闭库存LKAS以启用"),
},
EventName.cruiseMismatch: {
2025-03-26 08:48:53 +08:00
#ET.PERMANENT: ImmediateDisableAlert("openpilot未能取消巡航"),
},
2025-03-26 08:48:53 +08:00
# openpilot未能识别车辆。这将使openpilot切换到一个
# read-only mode. This can be solved by adding your fingerprint.
# See https://github.com/commaai/openpilot/wiki/Fingerprinting for more information
EventName.carUnrecognized: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
"车辆未识别",
priority=Priority.LOWEST),
},
EventName.stockAeb: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"刹车!",
"库存AEB碰撞风险",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("库存AEB碰撞风险"),
},
EventName.fcw: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"刹车!",
"碰撞风险",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
},
EventName.ldw: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"检测到车道偏离",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
},
# ********** events only containing alerts that display while engaged **********
EventName.steerTempUnavailableSilent: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"转向暂时不可用",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.8),
},
EventName.preDriverDistracted: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"请注意",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.promptDriverDistracted: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"请注意",
"驾驶员分心",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverDistracted: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"立即脱离控制",
"驾驶员分心",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.preDriverUnresponsive: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"触摸方向盘:未检测到面部",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1, alert_rate=0.75),
},
EventName.promptDriverUnresponsive: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"触摸方向盘",
"驾驶员未响应",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverUnresponsive: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"立即脱离控制",
"驾驶员未响应",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.manualRestart: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"接管控制",
"手动恢复驾驶",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.resumeRequired: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"按下恢复以退出静止状态",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.MID, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.belowSteerSpeed: {
ET.WARNING: below_steer_speed_alert,
},
EventName.preLaneChangeLeft: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"向左转动以在安全时开始变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, alert_rate=0.75),
},
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"向右转动以在安全时开始变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, alert_rate=0.75),
},
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"盲区内检测到车辆",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventName.laneChange: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"正在变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.steerSaturated: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"接管控制",
"转向超过限制",
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: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("风扇故障", "可能的硬件问题"),
},
# Camera is not outputting frames
EventName.cameraMalfunction: {
ET.PERMANENT: camera_malfunction_alert,
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("相机故障"),
ET.NO_ENTRY: NoEntryAlert("相机故障:重启设备"),
},
# Camera framerate too low
EventName.cameraFrameRate: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("相机帧率过低", "重启设备"),
ET.SOFT_DISABLE: soft_disable_alert("相机帧率过低"),
ET.NO_ENTRY: NoEntryAlert("相机帧率过低:重启设备"),
},
# Unused
EventName.gpsMalfunction: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("GPS故障", "可能的硬件问题"),
},
EventName.locationdTemporaryError: {
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("locationd临时错误"),
ET.SOFT_DISABLE: soft_disable_alert("locationd临时错误"),
},
EventName.locationdPermanentError: {
2025-03-26 08:48:53 +08:00
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: {
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("paramsd 临时错误"),
ET.SOFT_DISABLE: soft_disable_alert("paramsd 临时错误"),
},
EventName.paramsdPermanentError: {
2025-03-26 08:48:53 +08:00
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),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("取消按下"),
},
EventName.brakeHold: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("刹车保持激活"),
},
EventName.parkBrake: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("驻车制动已启用"),
},
EventName.pedalPressed: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("踏板已按下",
visual_alert=VisualAlert.brakePressed),
},
EventName.preEnableStandstill: {
ET.PRE_ENABLE: Alert(
2025-03-26 08:48:53 +08:00
"释放刹车以启用",
"",
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: {
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("按下设置以启用"),
},
EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("自适应巡航已禁用"),
},
EventName.steerTempUnavailable: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("转向暂时不可用"),
ET.NO_ENTRY: NoEntryAlert("转向暂时不可用"),
},
EventName.steerTimeLimit: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("车辆转向时间限制"),
ET.NO_ENTRY: NoEntryAlert("车辆转向时间限制"),
},
EventName.outOfSpace: {
ET.PERMANENT: out_of_space_alert,
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("存储空间不足"),
},
EventName.belowEngageSpeed: {
ET.NO_ENTRY: below_engage_speed_alert,
},
EventName.sensorDataInvalid: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"传感器数据无效",
"可能的硬件问题",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=1.),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("传感器数据无效"),
ET.SOFT_DISABLE: soft_disable_alert("传感器数据无效"),
},
EventName.noGps: {
ET.PERMANENT: no_gps_alert,
},
EventName.soundsUnavailable: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("未找到扬声器", "请重启设备"),
ET.NO_ENTRY: NoEntryAlert("未找到扬声器"),
},
EventName.tooDistracted: {
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("分心程度过高"),
},
EventName.overheat: {
ET.PERMANENT: overheat_alert,
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),
ET.NO_ENTRY: NoEntryAlert("System Overheated"),
},
EventName.wrongGear: {
ET.SOFT_DISABLE: user_soft_disable_alert("Gear not D"),
ET.NO_ENTRY: NoEntryAlert("Gear not 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,
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("校准无效:重新安装设备并重新校准"),
ET.NO_ENTRY: NoEntryAlert("校准无效:重新安装设备并重新校准"),
},
EventName.calibrationIncomplete: {
ET.PERMANENT: calibration_incomplete_alert,
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("校准不完整"),
ET.NO_ENTRY: NoEntryAlert("校准进行中"),
},
EventName.calibrationRecalibrating: {
ET.PERMANENT: calibration_incomplete_alert,
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("检测到设备重新安装:正在重新校准"),
ET.NO_ENTRY: NoEntryAlert("检测到重新安装:正在重新校准"),
},
EventName.doorOpen: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: user_soft_disable_alert("车门打开"),
ET.NO_ENTRY: NoEntryAlert("车门打开"),
},
EventName.seatbeltNotLatched: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: user_soft_disable_alert("安全带未扣好"),
ET.NO_ENTRY: NoEntryAlert("安全带未扣好"),
},
EventName.espDisabled: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("电子稳定控制已禁用"),
ET.NO_ENTRY: NoEntryAlert("电子稳定控制已禁用"),
},
EventName.lowBattery: {
2025-03-26 08:48:53 +08:00
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: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("进程间通信问题"),
ET.NO_ENTRY: comm_issue_alert,
},
EventName.commIssueAvgFreq: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("进程间通信速率低"),
ET.NO_ENTRY: NoEntryAlert("进程间通信速率低"),
},
EventName.controlsdLagging: {
2025-03-26 08:48:53 +08:00
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,
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("进程未运行"),
},
EventName.radarFault: {
2025-03-26 08:48:53 +08:00
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: {
2025-03-26 08:48:53 +08:00
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: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("姿态网络速度无效"),
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: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("设备从支架上掉落"),
ET.NO_ENTRY: NoEntryAlert("设备从支架上掉落"),
},
EventName.lowMemory: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("内存不足:请重启设备"),
ET.PERMANENT: low_memory_alert,
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("内存不足:请重启设备"),
},
EventName.highCpuUsage: {
#ET.SOFT_DISABLE: soft_disable_alert("System Malfunction: Reboot Your Device"),
#ET.PERMANENT: NormalPermanentAlert("System Malfunction", "Reboot your Device"),
ET.NO_ENTRY: high_cpu_usage_alert,
},
EventName.accFaulted: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航故障:重启汽车"),
ET.PERMANENT: NormalPermanentAlert("巡航故障:重启汽车以启用"),
ET.NO_ENTRY: NoEntryAlert("巡航故障:重启汽车"),
},
EventName.controlsMismatch: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("控制不匹配"),
ET.NO_ENTRY: NoEntryAlert("控制不匹配"),
},
EventName.roadCameraError: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("摄像头 CRC 错误 - 道路",
duration=1.,
creation_delay=30.),
},
EventName.wideRoadCameraError: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("摄像头 CRC 错误 - 道路鱼眼",
duration=1.,
creation_delay=30.),
},
EventName.driverCameraError: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("摄像头 CRC 错误 - 驾驶员",
duration=1.,
creation_delay=30.),
},
2025-03-26 08:48:53 +08:00
# 有时设备上的 USB 堆栈可能会进入不良状态
# 导致与 panda 的连接丢失
EventName.usbError: {
2025-03-26 08:48:53 +08:00
ET.SOFT_DISABLE: soft_disable_alert("USB 错误:重启您的设备"),
ET.PERMANENT: NormalPermanentAlert("USB 错误:重启您的设备", ""),
ET.NO_ENTRY: NoEntryAlert("USB 错误:重启您的设备"),
},
2025-03-26 08:48:53 +08:00
# 此警报可能因以下原因触发:
# - 根本没有接收到 CAN 数据
# - 收到了 CAN 数据,但某些消息未按正确频率接收
# 如果您没有编写新的汽车端口,这通常是由于接线故障
EventName.canError: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN 错误"),
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"CAN 错误:检查连接",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("CAN 错误:检查连接"),
},
EventName.canBusMissing: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN 总线断开"),
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"CAN 总线断开:可能是故障电缆",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("CAN 总线断开:检查连接"),
},
EventName.steerUnavailable: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS 故障:重启汽车"),
ET.PERMANENT: NormalPermanentAlert("LKAS 故障:重启汽车以启用"),
ET.NO_ENTRY: NoEntryAlert("LKAS 故障:重启汽车"),
},
EventName.reverseGear: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"倒车\n",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
2025-03-26 08:48:53 +08:00
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: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航已关闭"),
},
EventName.relayMalfunction: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("线束继电器故障"),
ET.PERMANENT: NormalPermanentAlert("线束继电器故障", "检查硬件"),
ET.NO_ENTRY: NoEntryAlert("线束继电器故障"),
},
EventName.speedTooLow: {
ET.IMMEDIATE_DISABLE: Alert(
2025-03-26 08:48:53 +08:00
"openpilot已取消",
"速度过低",
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
},
EventName.speedTooHigh: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"速度过高",
"在此速度下模型不确定",
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("减速以启用"),
},
EventName.lowSpeedLockout: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("巡航故障:重启汽车以启用"),
ET.NO_ENTRY: NoEntryAlert("巡航故障:重启汽车"),
},
EventName.lkasDisabled: {
2025-03-26 08:48:53 +08:00
ET.PERMANENT: NormalPermanentAlert("LKAS已禁用启用LKAS以启用"),
ET.NO_ENTRY: NoEntryAlert("LKAS已禁用"),
},
EventName.vehicleSensorsInvalid: {
2025-03-26 08:48:53 +08:00
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("车辆传感器无效"),
ET.PERMANENT: NormalPermanentAlert("车辆传感器正在校准", "驾驶以校准"),
ET.NO_ENTRY: NoEntryAlert("车辆传感器正在校准"),
},
EventName.blockUser: {
2025-03-26 08:48:53 +08:00
ET.NO_ENTRY: NoEntryAlert("请不要使用 'Development' 分支!"),
},
EventName.goatSteerSaturated: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"转向超过限制",
"耶稣,请掌舵!!",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.goat, 2.),
},
EventName.greenLight: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"灯变为绿色",
"",
AlertStatus.frogpilot, AlertSize.small,
Priority.MID, VisualAlert.none, AudibleAlert.prompt, 3.),
},
EventName.holidayActive: {
ET.PERMANENT: holiday_alert,
},
EventName.laneChangeBlockedLoud: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"盲区检测到车辆",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.warningSoft, .1),
},
EventName.leadDeparting: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"前车已离开",
"",
AlertStatus.frogpilot, AlertSize.small,
Priority.MID, VisualAlert.none, AudibleAlert.prompt, 3.),
},
EventName.noLaneAvailable : {
ET.PERMANENT: no_lane_available_alert,
},
EventName.openpilotCrashed: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"openpilot 崩溃",
"请在 FrogPilot Discord 中发布错误日志!",
AlertStatus.normal, AlertSize.mid,
Priority.HIGHEST, VisualAlert.none, AudibleAlert.none, 10.),
},
EventName.pedalInterceptorNoBrake: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"刹车不可用",
"切换到 L",
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.wrongGear, AudibleAlert.promptRepeat, 4.),
},
EventName.speedLimitChanged: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"速度限制已更改",
"",
AlertStatus.frogpilot, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 3.),
},
EventName.torqueNNLoad: {
ET.PERMANENT: torque_nn_load_alert,
},
EventName.turningLeft: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"左转",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, alert_rate=0.75),
},
EventName.turningRight: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"右转",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, alert_rate=0.75),
},
# Random Events
EventName.accel30: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"哇,你开得有点快!",
"( ⁄•⁄ω⁄•⁄ )",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.uwu, 4.),
},
EventName.accel35: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"我不会给你树五十的",
"你这个该死的尼斯湖水怪!",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.nessie, 4.),
},
EventName.accel40: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"太棒了,斯科特!",
"🚗💨",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.doc, 4.),
},
EventName.firefoxSteerSaturated: {
ET.WARNING: Alert(
2025-03-26 08:48:53 +08:00
"转向超过限制",
"IE 已停止响应...",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.firefox, 4.),
},
EventName.openpilotCrashedRandomEvents: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"openpilot 崩溃 💩",
"请在 FrogPilot Discord 中发布错误日志!",
AlertStatus.normal, AlertSize.mid,
Priority.HIGHEST, VisualAlert.none, AudibleAlert.fart, 10.),
},
EventName.vCruise69: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"哈哈 69",
"",
AlertStatus.frogpilot, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.noice, 2.),
},
EventName.yourFrogTriedToKillMe: {
ET.PERMANENT: Alert(
2025-03-26 08:48:53 +08:00
"你的青蛙试图杀了我...",
"👺",
AlertStatus.frogpilot, AlertSize.mid,
Priority.MID, VisualAlert.none, AudibleAlert.angry, 5.),
},
}
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)
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")