机械小鸽 bb09904bc1
汉化
2025-03-03 20:10:22 +08:00

1077 lines
38 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 bisect
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
from openpilot.common.git import get_short_branch
from openpilot.common.params import Params
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
AlertSize = log.SelfdriveState.AlertSize
AlertStatus = log.SelfdriveState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
EventName = log.OnroadEvent.EventName
# Alert priorities
class Priority(IntEnum):
LOWEST = 0
LOWER = 1
LOW = 2
MID = 3
HIGH = 4
HIGHEST = 5
# Event types
class ET:
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.event_counters = 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:
bisect.insort(self.static_events, event_name)
bisect.insort(self.events, event_name)
def clear(self) -> None:
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.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.event_counters[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:
bisect.insort(self.events, e.name.raw)
def to_msg(self):
ret = []
for event_name in self.events:
event = log.OnroadEvent.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.SelfdriveState.AlertStatus,
alert_size: log.SelfdriveState.AlertSize,
priority: Priority,
visual_alert: car.CarControl.HUDControl.VisualAlert,
audible_alert: car.CarControl.HUDControl.AudibleAlert,
duration: float,
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.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
EmptyAlert = Alert("" , "", AlertStatus.normal, AlertSize.none, Priority.LOWEST,
VisualAlert.none, AudibleAlert.none, 0)
class NoEntryAlert(Alert):
def __init__(self, alert_text_2: str,
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):
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),
self.alert_text_1 = "openpilot将解除控制"
class ImmediateDisableAlert(Alert):
def __init__(self, alert_text_2: str):
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):
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, log.ControlsState], 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, 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() # 确保缓存 get_short_branch 以避免启动时延迟
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"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, 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 = 'Recalibration' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else 'Calibration'
return Alert(
f"{first_word} in Progress: {sm['liveCalibration'].calPerc:.0f}%",
f"Drive Above {get_display_speed(MIN_SPEED_FILTER, metric)}",
AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
def torque_nn_load_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
model_name = Params().get("NNFFModelName", encoding='utf-8')
if model_name == "":
return Alert(
"NNFF扭矩控制器不可用",
"请将日志捐赠给Twilsonco以添加此功能",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 6.0)
else:
return Alert(
"NNFF扭矩控制器已加载",
model_name,
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.nnff, 5.0)
# *** 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("Out of Storage", f"{full_perc}% full")
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} 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, 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 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 wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
text = "启用自适应巡航以激活"
if CP.brand == "honda":
text = "启用主开关以激活"
return NoEntryAlert(text)
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.steer
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()
return NormalPermanentAlert(f"驾驶风格: {personality}", duration=1.5)
def car_parser_result(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
results = Params().get("CanParserResult")
if results is None:
results = ""
return Alert(
"CAN 错误: 检查连接!!",
results,
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.)
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: NormalPermanentAlert("无效的LKAS设置",
"切换原车LKAS以启用"),
ET.NO_ENTRY: NoEntryAlert("无效的LKAS设置"),
},
EventName.cruiseMismatch: {
#ET.PERMANENT: ImmediateDisableAlert("openpilot未能取消巡航"),
},
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.none, 1.8),
},
EventName.preDriverDistracted: {
ET.WARNING: Alert(
"请注意",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.promptDriverDistracted: {
ET.WARNING: Alert(
"请注意",
"驾驶员分心",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverDistracted: {
ET.WARNING: Alert(
"请立即解除控制",
"驾驶员分心",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.preDriverUnresponsive: {
ET.WARNING: Alert(
"请触摸方向盘:未检测到面部",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1),
},
EventName.promptDriverUnresponsive: {
ET.WARNING: Alert(
"请触摸方向盘",
"驾驶员未响应",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverUnresponsive: {
ET.WARNING: 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.none,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
"向右转动方向盘以开始变道(安全时)",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
"检测到盲区内有车辆",
"",
AlertStatus.userPrompt, AlertSize.none,
Priority.LOW, VisualAlert.none, AudibleAlert.bsdWarning, .1),
},
EventName.laneChange: {
ET.WARNING: Alert(
"正在变道",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.steerSaturated: {
ET.WARNING: Alert(
"请接管控制",
"转向超出限制",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1.),
},
# 当风扇驱动超过50%但未旋转时抛出
EventName.fanMalfunction: {
ET.PERMANENT: NormalPermanentAlert("风扇故障", "可能是硬件问题"),
},
# 相机未输出帧
EventName.cameraMalfunction: {
ET.PERMANENT: camera_malfunction_alert,
ET.SOFT_DISABLE: soft_disable_alert("相机故障"),
ET.NO_ENTRY: NoEntryAlert("相机故障:请重启设备"),
},
# 相机帧率过低
EventName.cameraFrameRate: {
ET.PERMANENT: NormalPermanentAlert("相机帧率过低", "请重启设备"),
ET.SOFT_DISABLE: soft_disable_alert("相机帧率过低"),
ET.NO_ENTRY: NoEntryAlert("相机帧率过低:请重启设备"),
},
# 未使用
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 通过观察车辆对人类和 openpilot 驾驶的转向输入的反应来学习某些参数。
# 包括:
# - 转向比:转向架的齿轮比。转向角除以轮胎角
# - 轮胎刚度:轮胎的抓地力
# - 角度偏移:大多数转向角传感器都有偏移,直行时测量非零角度
# 当这些值超过合理性检查时会抛出此警报。这可能是由于
# 不良的对齐或传感器数据不良。如果这种情况持续发生,请考虑在 GitHub 上创建问题
EventName.paramsdTemporaryError: {
ET.NO_ENTRY: NoEntryAlert("paramsd 临时错误"),
ET.SOFT_DISABLE: soft_disable_alert("paramsd 临时错误"),
},
EventName.paramsdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("paramsd 永久错误"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd 永久错误"),
ET.PERMANENT: NormalPermanentAlert("paramsd 永久错误"),
},
# ********** 影响控制状态转换的事件 **********
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.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: {
ET.PERMANENT: Alert(
"GPS信号差",
"确保设备有清晰的天空视野",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=600.)
},
EventName.tooDistracted: {
ET.NO_ENTRY: NoEntryAlert("分心程度过高"),
},
EventName.overheat: {
ET.PERMANENT: overheat_alert,
ET.SOFT_DISABLE: soft_disable_alert("系统过热"),
ET.NO_ENTRY: NoEntryAlert("系统过热"),
},
EventName.wrongGear: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage), #carrot
#ET.SOFT_DISABLE: user_soft_disable_alert("档位不是D"),
ET.NO_ENTRY: NoEntryAlert("档位不是D"),
},
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("电池电量低"),
},
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("雷达错误:请重启汽车"),
},
# 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("姿态网络速度无效"),
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.PERMANENT: car_parser_result,
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN错误"),
ET.NO_ENTRY: NoEntryAlert("CAN错误检查连接"),
},
EventName.canBusMissing: {
ET.PERMANENT: car_parser_result,
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN总线断开"),
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(
"倒车\n",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.reverseGear, .2, creation_delay=0.5),
ET.SOFT_DISABLE: SoftDisableAlert("倒车档"),
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.softHold: {
ET.WARNING: Alert(
"软保持激活",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.trafficStopping: {
ET.WARNING: EngagementAlert(AudibleAlert.stopping),
},
EventName.audioPrompt: {
ET.WARNING: EngagementAlert(AudibleAlert.prompt),
},
EventName.audioRefuse: {
ET.WARNING: EngagementAlert(AudibleAlert.refuse),
},
EventName.stopStop: {
ET.WARNING: EngagementAlert(AudibleAlert.stopStop),
},
EventName.audioLaneChange: {
ET.WARNING: EngagementAlert(AudibleAlert.laneChange),
},
EventName.audioTurn: {
ET.WARNING: EngagementAlert(AudibleAlert.audioTurn),
},
EventName.trafficSignGreen: {
ET.WARNING: EngagementAlert(AudibleAlert.trafficSignGreen),
},
EventName.trafficSignChanged: {
ET.WARNING: Alert(
"信号已改变",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.trafficSignChanged, 1.),
},
EventName.turningLeft: {
ET.WARNING: Alert(
"左转",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.turningRight: {
ET.WARNING: Alert(
"右转",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.audio1: {
ET.WARNING: EngagementAlert(AudibleAlert.audio1),
},
EventName.audio2: {
ET.WARNING: EngagementAlert(AudibleAlert.audio2),
},
EventName.audio3: {
ET.WARNING: EngagementAlert(AudibleAlert.audio3),
},
EventName.audio4: {
ET.WARNING: EngagementAlert(AudibleAlert.audio4),
},
EventName.audio5: {
ET.WARNING: EngagementAlert(AudibleAlert.audio5),
},
EventName.audio6: {
ET.WARNING: EngagementAlert(AudibleAlert.audio6),
},
EventName.audio7: {
ET.WARNING: EngagementAlert(AudibleAlert.audio7),
},
EventName.audio8: {
ET.WARNING: EngagementAlert(AudibleAlert.audio8),
},
EventName.audio9: {
ET.WARNING: EngagementAlert(AudibleAlert.audio9),
},
EventName.audio10: {
ET.WARNING: EngagementAlert(AudibleAlert.audio10),
},
EventName.audio0: {
ET.WARNING: EngagementAlert(AudibleAlert.longDisengaged),
},
EventName.torqueNNLoad: {
ET.PERMANENT: torque_nn_load_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")