add alert for CAN bus timeout (#24162)

* add alert for CAN bus timeout

* add alert

* set in interface

* cleanup

* cleanup

* add event

* fix mock

* bump

* bump opendbc

* update refs

* return reader
This commit is contained in:
Adeeb Shihadeh 2022-04-12 22:58:34 -07:00 committed by GitHub
parent 3ff14adbd6
commit 49c2164814
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 73 additions and 120 deletions

2
cereal

@ -1 +1 @@
Subproject commit d6c3cf6b33e699f82e5d78ae22c74cad978830b6
Subproject commit 932c44c6bda17d7e19e1f58cd26442560a562696

@ -1 +1 @@
Subproject commit eb56fff37a4a2738df7add08779db51a0a6f38e2
Subproject commit 004db342a825155f7bd03e7d08f3861e18b23795

View File

@ -37,13 +37,9 @@ class CarInterface(CarInterfaceBase):
return ret
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp)
ret.canValid = self.cp.can_valid
# wait for everything to init first
if self.frame > int(5. / DT_CTRL):
# body always wants to enable
@ -52,8 +48,7 @@ class CarInterface(CarInterfaceBase):
ret.events[0].enable = True
self.frame += 1
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
return self.CC.update(c, self.CS)

View File

@ -47,16 +47,9 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
# speeds
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
# events
@ -67,10 +60,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
# copy back carState packet to CS
self.CS.out = ret.as_reader()
return self.CS.out
return ret
# pass in a car.CarControl
# to be called @ 100hz

View File

@ -41,15 +41,9 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp)
ret.canValid = self.cp.can_valid
# events
events = self.create_common_events(ret)
@ -58,8 +52,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
# pass in a car.CarControl
# to be called @ 100hz

View File

@ -155,13 +155,9 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_loopback.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_loopback)
ret.canValid = self.cp.can_valid and self.cp_loopback.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
buttonEvents = []
@ -210,10 +206,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
# copy back carState packet to CS
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
ret = self.CC.update(c, self.CS)

View File

@ -328,17 +328,9 @@ class CarInterface(CarInterfaceBase):
disable_ecu(logcan, sendcan, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03')
# returns a car.CarState
def update(self, c, can_strings):
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
if self.cp_body:
self.cp_body.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid)
buttonEvents = []
if self.CS.cruise_buttons != self.CS.prev_cruise_buttons:
@ -412,11 +404,9 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
# pass in a car.CarControl
# to be called @ 100hz
def apply(self, c):
ret = self.CC.update(c, self.CS)
return ret
return self.CC.update(c, self.CS)

View File

@ -297,12 +297,8 @@ class CarInterface(CarInterfaceBase):
if CP.openpilotLongitudinalControl:
disable_ecu(logcan, sendcan, addr=0x7d0, com_cont_req=b'\x28\x83\x01')
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise)
@ -352,8 +348,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
ret = self.CC.update(c, self.CS)

View File

@ -33,12 +33,17 @@ class CarInterfaceBase(ABC):
self.low_speed_alert = False
self.silent_steer_warning = True
self.CS = None
self.can_parsers = []
if CarState is not None:
self.CS = CarState(CP)
self.cp = self.CS.get_can_parser(CP)
self.cp_cam = self.CS.get_cam_can_parser(CP)
self.cp_adas = self.CS.get_adas_can_parser(CP)
self.cp_body = self.CS.get_body_can_parser(CP)
self.cp_loopback = self.CS.get_loopback_can_parser(CP)
self.can_parsers = [self.cp, self.cp_cam, self.cp_adas, self.cp_body, self.cp_loopback]
self.CC = None
if CarController is not None:
@ -100,9 +105,28 @@ class CarInterfaceBase(ABC):
return ret
@abstractmethod
def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState:
def _update(self, c: car.CarControl) -> car.CarState:
pass
def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState:
# parse can
for cp in self.can_parsers:
if cp is not None:
cp.update_strings(can_strings)
# get CarState
ret = self._update(c)
ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None)
ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None)
# copy back for next iteration
reader = ret.as_reader()
if self.CS is not None:
self.CS.out = reader
return reader
@abstractmethod
def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]:
pass
@ -254,6 +278,10 @@ class CarStateBase(ABC):
def get_cam_can_parser(CP):
return None
@staticmethod
def get_adas_can_parser(CP):
return None
@staticmethod
def get_body_can_parser(CP):
return None

View File

@ -75,13 +75,8 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
# events
events = self.create_common_events(ret)
@ -93,8 +88,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
ret = self.CC.update(c, self.CS, self.frame)

View File

@ -48,7 +48,7 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
def _update(self, c):
# get basic data from phone and gps since CAN isn't connected
sensors = messaging.recv_sock(self.sensor)
if sensors is not None:
@ -63,7 +63,6 @@ class CarInterface(CarInterfaceBase):
# create message
ret = car.CarState.new_message()
ret.canValid = True
# speeds
ret.vEgo = self.speed
@ -83,7 +82,7 @@ class CarInterface(CarInterfaceBase):
curvature = self.yaw_rate / max(self.speed, 1.)
ret.steeringAngleDeg = curvature * self.CP.steerRatio * self.CP.wheelbase * CV.RAD_TO_DEG
return ret.as_reader()
return ret
def apply(self, c):
# in mock no carcontrols

View File

@ -5,9 +5,6 @@ from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness,
from selfdrive.car.interfaces import CarInterfaceBase
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController, CarState):
super().__init__(CP, CarController, CarState)
self.cp_adas = self.CS.get_adas_can_parser(CP)
@staticmethod
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
@ -53,15 +50,9 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
self.cp_adas.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_adas.can_valid and self.cp_cam.can_valid
buttonEvents = []
be = car.CarState.ButtonEvent.new_message()
be.type = car.CarState.ButtonEvent.Type.accelCruise
@ -74,8 +65,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
hud_control = c.hudControl

View File

@ -107,19 +107,15 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
ret.events = self.create_common_events(ret).to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
hud_control = c.hudControl

View File

@ -57,18 +57,12 @@ class CarInterface(CarInterfaceBase):
return ret
def update(self, c, can_strings):
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
events = self.create_common_events(ret)
ret.events = self.create_common_events(ret).to_msg()
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
ret = self.CC.update(c, self.CS)

View File

@ -240,14 +240,9 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
# events
@ -266,8 +261,7 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
# pass in a car.CarControl
# to be called @ 100hz

View File

@ -161,17 +161,10 @@ class CarInterface(CarInterfaceBase):
return ret
# returns a car.CarState
def update(self, c, can_strings):
def _update(self, c):
buttonEvents = []
# Process the most recent CAN message traffic, and check for validity
# The camera CAN has no signals we use at this time, but we process it
# anyway so we can test connectivity with can_valid
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
# Check for and process state-change events (button press or release) from
@ -204,8 +197,7 @@ class CarInterface(CarInterfaceBase):
self.displayMetricUnitsPrev = self.CS.displayMetricUnits
self.buttonStatesPrev = self.CS.buttonStates.copy()
self.CS.out = ret.as_reader()
return self.CS.out
return ret
def apply(self, c):
hud_control = c.hudControl

View File

@ -270,7 +270,9 @@ class Controls:
LaneChangeState.laneChangeFinishing):
self.events.add(EventName.laneChange)
if not CS.canValid:
if CS.canTimeout:
self.events.add(EventName.canBusMissing)
elif not CS.canValid:
self.events.add(EventName.canError)
for i, pandaState in enumerate(self.sm['pandaStates']):

View File

@ -757,7 +757,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
# - 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 Error: Check Connections"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error"),
ET.PERMANENT: Alert(
"CAN Error: Check Connections",
"",
@ -766,7 +766,15 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.NO_ENTRY: NoEntryAlert("CAN Error: Check Connections"),
},
EventName.canBusMissing: {},
EventName.canBusMissing: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Bus Disconnected"),
ET.PERMANENT: Alert(
"CAN Bus Disconnected: Likely Faulty Cable",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("CAN Bus Disconnected: Check Connections"),
},
EventName.steerUnavailable: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"),

View File

@ -1 +1 @@
de01f1544a1441f89c24c5ea587f3f99632f2b5a
dea753b12032ad2c50b4a163a3077a8530267800