openpilot/selfdrive/selfdrived/events.py
mouxangithub b40c885c6a feat(car): 更新 Toyota Wildlander PHEV 车型配置及依赖项
将原有 TOYOTA_WILDLANDER 车型标识重命名为 TOYOTA_WILDLANDER_PHEV,
并更新相关指纹、平台名称和测试路由配置。同时增加该车型的 SRS 和 Hybrid
ECU 固件版本信息。

此外,修改 dmonitoringd.py 中的监控逻辑,使在 always_on 模式下也能执行
DM.run_step 流程。

还更新了 launch_openpilot.sh 中的 API 和 ATHENA 服务地址。
2025-10-22 15:36:35 +08:00

883 lines
32 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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")