HKG: only allow engagement on user button press (#24140)

* use deque for prev_cruise_buttons

* stash

* disallow engagement if resume or decel isn't pressed

* fix buttons

* reduce chances of causing 30-frame fault

Fix clu11

drive down cancel times

* Revert "reduce chances of causing 30-frame fault"

This reverts commit 0f54c051bf5a22b1f584718ec46e78bc3a82a0dd.

* consider pause/resume button

* stash

* Revert "stash"

This reverts commit 551ca7be6c45729f0747abc81cd81894cd621c32.

* sadly some cars need 8 op frames (identical to 4 updates from CLU11)

* add main button

* 6 should be safe

* use max

* clean up

* change to 4 samples and process all messages received, like panda

* bump panda

* test: replay segments with known re-engagements on-device

* Revert "test: replay segments with known re-engagements on-device"

This reverts commit 9730c3c14f942b82b6ed5ef2e81b8ae0126f3006.

* need prev_cruise_buttons as we don't run every CAN message through carstate

* more generic

* extend

* Update selfdrive/car/interfaces.py

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>

* 3% faster at 1000000 loops

* update refs

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
pull/24336/head
Shane Smiskol 3 years ago committed by GitHub
parent 60b7114024
commit efa98d2a06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      panda
  2. 15
      selfdrive/car/hyundai/carstate.py
  3. 14
      selfdrive/car/hyundai/interface.py
  4. 5
      selfdrive/car/interfaces.py
  5. 2
      selfdrive/test/process_replay/ref_commit

@ -1 +1 @@
Subproject commit 5eefc3ad62422dea3fc356f82267af58f9b1518a Subproject commit bb2aea1ac6bd9ab198ec5192268a6ea6eec6bbe5

@ -1,17 +1,24 @@
from collections import deque
import copy import copy
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES, EV_CAR, HYBRID_CAR from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES, EV_CAR, HYBRID_CAR, Buttons
from selfdrive.car.interfaces import CarStateBase from selfdrive.car.interfaces import CarStateBase
PREV_BUTTON_SAMPLES = 4
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
if self.CP.carFingerprint in FEATURES["use_cluster_gears"]: if self.CP.carFingerprint in FEATURES["use_cluster_gears"]:
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"] self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
elif self.CP.carFingerprint in FEATURES["use_tcu_gears"]: elif self.CP.carFingerprint in FEATURES["use_tcu_gears"]:
@ -19,7 +26,6 @@ class CarState(CarStateBase):
else: # preferred and elect gear methods use same definition else: # preferred and elect gear methods use same definition
self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"] self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
def update(self, cp, cp_cam): def update(self, cp, cp_cam):
ret = car.CarState.new_message() ret = car.CarState.new_message()
@ -108,8 +114,9 @@ class CarState(CarStateBase):
self.clu11 = copy.copy(cp.vl["CLU11"]) self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
self.brake_error = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED self.brake_error = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
self.prev_cruise_buttons = self.cruise_buttons self.prev_cruise_buttons = self.cruise_buttons[-1]
self.cruise_buttons = cp.vl["CLU11"]["CF_Clu_CruiseSwState"] self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
return ret return ret

@ -10,6 +10,8 @@ from selfdrive.car.disable_ecu import disable_ecu
ButtonType = car.CarState.ButtonEvent.Type ButtonType = car.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
@ -315,7 +317,11 @@ class CarInterface(CarInterfaceBase):
ret = self.CS.update(self.cp, self.cp_cam) ret = self.CS.update(self.cp, self.cp_cam)
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False 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) # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
# Main button also can trigger an engagement on these cars
allow_enable = any(btn in ENABLE_BUTTONS for btn in self.CS.cruise_buttons) or any(self.CS.main_buttons)
events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise, allow_enable=allow_enable)
if self.CS.brake_error: if self.CS.brake_error:
events.add(EventName.brakeUnavailable) events.add(EventName.brakeUnavailable)
@ -323,12 +329,12 @@ class CarInterface(CarInterfaceBase):
if self.CS.CP.openpilotLongitudinalControl: if self.CS.CP.openpilotLongitudinalControl:
buttonEvents = [] buttonEvents = []
if self.CS.cruise_buttons != self.CS.prev_cruise_buttons: if self.CS.cruise_buttons[-1] != self.CS.prev_cruise_buttons:
be = car.CarState.ButtonEvent.new_message() be = car.CarState.ButtonEvent.new_message()
be.type = ButtonType.unknown be.type = ButtonType.unknown
if self.CS.cruise_buttons != 0: if self.CS.cruise_buttons[-1] != 0:
be.pressed = True be.pressed = True
but = self.CS.cruise_buttons but = self.CS.cruise_buttons[-1]
else: else:
be.pressed = False be.pressed = False
but = self.CS.prev_cruise_buttons but = self.CS.prev_cruise_buttons

@ -131,7 +131,7 @@ class CarInterfaceBase(ABC):
def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]: def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]:
pass pass
def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True): def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True):
events = Events() events = Events()
if cs_out.doorOpen: if cs_out.doorOpen:
@ -175,8 +175,9 @@ class CarInterfaceBase(ABC):
events.add(EventName.steerUnavailable) events.add(EventName.steerUnavailable)
# we engage when pcm is active (rising edge) # we engage when pcm is active (rising edge)
# enabling can optionally be blocked by the car interface
if pcm_enable: if pcm_enable:
if cs_out.cruiseState.enabled and not self.CS.out.cruiseState.enabled: if cs_out.cruiseState.enabled and not self.CS.out.cruiseState.enabled and allow_enable:
events.add(EventName.pcmEnable) events.add(EventName.pcmEnable)
elif not cs_out.cruiseState.enabled: elif not cs_out.cruiseState.enabled:
events.add(EventName.pcmDisable) events.add(EventName.pcmDisable)

@ -1 +1 @@
fe7b24c1914046a3a7be19b6e812984e7e14301d 17141a8240bd8ec5defa1de2da937544c52ef0fe
Loading…
Cancel
Save