From aed1eaede5a8035a3b882096acf461cdd962b68c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Oct 2024 21:32:56 -0700 Subject: [PATCH] Deprecate carState.events (#33693) * add lkas bools * switch these two over * bump * deprecate low speed lockout * add lowSpeedAlert bool bump * GM vehicle speed is now signed! * reimagine * rm * do event * bump * STASH * comment * bump * no out! * format * move almost everything to selfdrived * add back CC_prev for cruise initialization * ok * errors are passed to radarState as well as freq check * deprecate! * use selfdrived for test models events * we only want noEntry from car events, not system, have to check pedalPressed * no more events * regen with buttonEvents set properly * update refs --- cereal/car.capnp | 3 +- selfdrive/car/car_specific.py | 70 +++++++++---------- selfdrive/car/card.py | 38 ++-------- selfdrive/car/tests/test_models.py | 15 ++-- selfdrive/selfdrived/selfdrived.py | 31 ++++++-- selfdrive/test/process_replay/README.md | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 4 +- 8 files changed, 79 insertions(+), 86 deletions(-) diff --git a/cereal/car.capnp b/cereal/car.capnp index 6eff704ecb..326f1eeef8 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -157,8 +157,6 @@ struct OnroadEvent @0x9b1657f34caf3ad3 { # all speeds in m/s struct CarState { - events @13 :List(OnroadEvent); - # CAN health canValid @26 :Bool; # invalid counter/checksums canTimeout @40 :Bool; # CAN bus dropped out @@ -296,6 +294,7 @@ struct CarState { steeringRateLimitedDEPRECATED @29 :Bool; canMonoTimesDEPRECATED @12: List(UInt64); canRcvTimeoutDEPRECATED @49 :Bool; + eventsDEPRECATED @13 :List(OnroadEvent); } # ******* radar state @ 20hz ******* diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py index ee2dee77de..23719a8c4f 100644 --- a/selfdrive/car/car_specific.py +++ b/selfdrive/car/car_specific.py @@ -2,7 +2,7 @@ from collections import deque from cereal import car import cereal.messaging as messaging from opendbc.car import DT_CTRL, structs -from opendbc.car.interfaces import MAX_CTRL_SPEED, CarStateBase +from opendbc.car.interfaces import MAX_CTRL_SPEED from opendbc.car.volkswagen.values import CarControllerParams as VWCarControllerParams from opendbc.car.hyundai.interface import ENABLE_BUTTONS as HYUNDAI_ENABLE_BUTTONS from opendbc.car.hyundai.carstate import PREV_BUTTON_SAMPLES as HYUNDAI_PREV_BUTTON_SAMPLES @@ -41,102 +41,102 @@ class CarSpecificEvents: self.cruise_buttons: deque = deque([], maxlen=HYUNDAI_PREV_BUTTON_SAMPLES) - def update(self, CS: CarStateBase, CS_prev: car.CarState, CC_prev: car.CarControl): + def update(self, CS: car.CarState, CS_prev: car.CarState, CC: car.CarControl): if self.CP.carName in ('body', 'mock'): events = Events() elif self.CP.carName in ('subaru', 'mazda'): - events = self.create_common_events(CS.out, CS_prev) + events = self.create_common_events(CS, CS_prev) elif self.CP.carName == 'ford': - events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.manumatic]) + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.manumatic]) elif self.CP.carName == 'nissan': - events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.brake]) + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.brake]) elif self.CP.carName == 'chrysler': - events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.low]) + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.low]) # Low speed steer alert hysteresis logic - if self.CP.minSteerSpeed > 0. and CS.out.vEgo < (self.CP.minSteerSpeed + 0.5): + if self.CP.minSteerSpeed > 0. and CS.vEgo < (self.CP.minSteerSpeed + 0.5): self.low_speed_alert = True - elif CS.out.vEgo > (self.CP.minSteerSpeed + 1.): + elif CS.vEgo > (self.CP.minSteerSpeed + 1.): self.low_speed_alert = False if self.low_speed_alert: events.add(EventName.belowSteerSpeed) elif self.CP.carName == 'honda': - events = self.create_common_events(CS.out, CS_prev, pcm_enable=False) + events = self.create_common_events(CS, CS_prev, pcm_enable=False) - if self.CP.pcmCruise and CS.out.vEgo < self.CP.minEnableSpeed: + if self.CP.pcmCruise and CS.vEgo < self.CP.minEnableSpeed: events.add(EventName.belowEngageSpeed) if self.CP.pcmCruise: # we engage when pcm is active (rising edge) - if CS.out.cruiseState.enabled and not CS_prev.cruiseState.enabled: + if CS.cruiseState.enabled and not CS_prev.cruiseState.enabled: events.add(EventName.pcmEnable) - elif not CS.out.cruiseState.enabled and (CC_prev.actuators.accel >= 0. or not self.CP.openpilotLongitudinalControl): + elif not CS.cruiseState.enabled and (CC.actuators.accel >= 0. or not self.CP.openpilotLongitudinalControl): # it can happen that car cruise disables while comma system is enabled: need to # keep braking if needed or if the speed is very low - if CS.out.vEgo < self.CP.minEnableSpeed + 2.: + if CS.vEgo < self.CP.minEnableSpeed + 2.: # non loud alert if cruise disables below 25mph as expected (+ a little margin) events.add(EventName.speedTooLow) else: events.add(EventName.cruiseDisabled) - if self.CP.minEnableSpeed > 0 and CS.out.vEgo < 0.001: + if self.CP.minEnableSpeed > 0 and CS.vEgo < 0.001: events.add(EventName.manualRestart) elif self.CP.carName == 'toyota': - events = self.create_common_events(CS.out, CS_prev) + events = self.create_common_events(CS, CS_prev) if self.CP.openpilotLongitudinalControl: - if CS.out.cruiseState.standstill and not CS.out.brakePressed: + if CS.cruiseState.standstill and not CS.brakePressed: events.add(EventName.resumeRequired) - if CS.out.vEgo < self.CP.minEnableSpeed: + if CS.vEgo < self.CP.minEnableSpeed: events.add(EventName.belowEngageSpeed) - if CC_prev.actuators.accel > 0.3: + if CC.actuators.accel > 0.3: # some margin on the actuator to not false trigger cancellation while stopping events.add(EventName.speedTooLow) - if CS.out.vEgo < 0.001: + if CS.vEgo < 0.001: # while in standstill, send a user alert events.add(EventName.manualRestart) elif self.CP.carName == 'gm': # The ECM allows enabling on falling edge of set, but only rising edge of resume - events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.sport, GearShifter.low, - GearShifter.eco, GearShifter.manumatic], + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport, GearShifter.low, + GearShifter.eco, GearShifter.manumatic], pcm_enable=self.CP.pcmCruise, enable_buttons=(ButtonType.decelCruise,)) if not self.CP.pcmCruise: - if any(b.type == ButtonType.accelCruise and b.pressed for b in CS.out.buttonEvents): + if any(b.type == ButtonType.accelCruise and b.pressed for b in CS.buttonEvents): events.add(EventName.buttonEnable) # Enabling at a standstill with brake is allowed # TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs - if CS.out.vEgo < self.CP.minEnableSpeed and not (CS.out.standstill and CS.out.brake >= 20 and - self.CP.networkLocation == NetworkLocation.fwdCamera): + if CS.vEgo < self.CP.minEnableSpeed and not (CS.standstill and CS.brake >= 20 and + self.CP.networkLocation == NetworkLocation.fwdCamera): events.add(EventName.belowEngageSpeed) - if CS.out.cruiseState.standstill: + if CS.cruiseState.standstill: events.add(EventName.resumeRequired) - if CS.out.vEgo < self.CP.minSteerSpeed: + if CS.vEgo < self.CP.minSteerSpeed: events.add(EventName.belowSteerSpeed) elif self.CP.carName == 'volkswagen': - events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic], + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic], pcm_enable=not self.CP.openpilotLongitudinalControl, enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise)) # Low speed steer alert hysteresis logic - if (self.CP.minSteerSpeed - 1e-3) > VWCarControllerParams.DEFAULT_MIN_STEER_SPEED and CS.out.vEgo < (self.CP.minSteerSpeed + 1.): + if (self.CP.minSteerSpeed - 1e-3) > VWCarControllerParams.DEFAULT_MIN_STEER_SPEED and CS.vEgo < (self.CP.minSteerSpeed + 1.): self.low_speed_alert = True - elif CS.out.vEgo > (self.CP.minSteerSpeed + 2.): + elif CS.vEgo > (self.CP.minSteerSpeed + 2.): self.low_speed_alert = False if self.low_speed_alert: events.add(EventName.belowSteerSpeed) if self.CP.openpilotLongitudinalControl: - if CS.out.vEgo < self.CP.minEnableSpeed + 0.5: + if CS.vEgo < self.CP.minEnableSpeed + 0.5: events.add(EventName.belowEngageSpeed) - if CC_prev.enabled and CS.out.vEgo < self.CP.minEnableSpeed: + if CC.enabled and CS.vEgo < self.CP.minEnableSpeed: events.add(EventName.speedTooLow) # TODO: this needs to be implemented generically in carState struct @@ -147,13 +147,13 @@ class CarSpecificEvents: # 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 - self.cruise_buttons.append(any(ev.type in HYUNDAI_ENABLE_BUTTONS for ev in CS.out.buttonEvents)) - events = self.create_common_events(CS.out, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=any(self.cruise_buttons)) + self.cruise_buttons.append(any(ev.type in HYUNDAI_ENABLE_BUTTONS for ev in CS.buttonEvents)) + events = self.create_common_events(CS, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=any(self.cruise_buttons)) # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) - if CS.out.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: + if CS.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: self.low_speed_alert = True - if CS.out.vEgo > (self.CP.minSteerSpeed + 4.): + if CS.vEgo > (self.CP.minSteerSpeed + 4.): self.low_speed_alert = False if self.low_speed_alert: events.add(EventName.belowSteerSpeed) diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 7f57edf866..380d5df431 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -20,9 +20,8 @@ from opendbc.car.car_helpers import get_car, get_radar_interface from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp from openpilot.selfdrive.car.cruise import VCruiseHelper -from openpilot.selfdrive.car.car_specific import CarSpecificEvents, MockCarState +from openpilot.selfdrive.car.car_specific import MockCarState from openpilot.selfdrive.car.helpers import convert_carControl, convert_to_capnp -from openpilot.selfdrive.selfdrived.events import Events, ET REPLAY = "REPLAY" in os.environ @@ -112,9 +111,9 @@ class Car: self.RI = RI # set alternative experiences from parameters - self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") + disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") self.CP.alternativeExperience = 0 - if not self.disengage_on_accelerator: + if not disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle") @@ -152,9 +151,6 @@ class Car: self.params.put_nonblocking("CarParamsCache", cp_bytes) self.params.put_nonblocking("CarParamsPersistent", cp_bytes) - self.events = Events() - - self.car_events = CarSpecificEvents(self.CP) self.mock_carstate = MockCarState() self.v_cruise_helper = VCruiseHelper(self.CP) @@ -196,30 +192,6 @@ class Car: return CS, RD - def update_events(self, CS: car.CarState, RD: structs.RadarData | None): - self.events.clear() - - CS.events = self.car_events.update(self.CI.CS, self.CS_prev, self.CC_prev).to_msg() - - self.events.add_from_msg(CS.events) - - if self.CP.notCar: - # wait for everything to init first - if self.sm.frame > int(5. / DT_CTRL) and self.initialized_prev: - # body always wants to enable - self.events.add(EventName.pcmEnable) - - # Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0 - if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \ - (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or \ - (CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)): - self.events.add(EventName.pedalPressed) - - if RD is not None and len(RD.errors): - self.events.add(EventName.radarFault) - - CS.events = self.events.to_msg() - def state_publish(self, CS: car.CarState, RD: structs.RadarData | None): """carState and carParams publish loop""" @@ -271,9 +243,7 @@ class Car: def step(self): CS, RD = self.state_update() - self.update_events(CS, RD) - - if not self.sm['carControl'].enabled and self.events.contains(ET.ENABLE): + if self.sm['carControl'].enabled and not self.CC_prev.enabled: self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode) self.state_publish(CS, RD) diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 460b9f196d..10620c146f 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -20,7 +20,9 @@ from opendbc.car.car_helpers import FRAME_FINGERPRINT, interfaces from opendbc.car.honda.values import CAR as HONDA, HondaFlags from opendbc.car.values import Platform from opendbc.car.tests.routes import non_tested_cars, routes, CarTestRoute -from openpilot.selfdrive.car.card import Car, convert_to_capnp +from openpilot.selfdrive.car.card import convert_to_capnp +from openpilot.selfdrive.selfdrived.events import ET +from openpilot.selfdrive.selfdrived.selfdrived import SelfdriveD from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT @@ -404,7 +406,8 @@ class TestCarModelBase(unittest.TestCase): controls_allowed_prev = False CS_prev = car.CarState.new_message() checks = defaultdict(int) - card = Car(CI=self.CI) + selfdrived = SelfdriveD(CP=self.CP) + selfdrived.initialized = True for idx, can in enumerate(self.can_msgs): CS = convert_to_capnp(self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), )))) for msg in filter(lambda m: m.src in range(64), can.can): @@ -449,10 +452,10 @@ class TestCarModelBase(unittest.TestCase): checks['cruiseState'] += CS.cruiseState.enabled != self.safety.get_cruise_engaged_prev() else: # Check for enable events on rising edge of controls allowed - card.update_events(CS, None) - card.CS_prev = CS - button_enable = (any(evt.enable for evt in CS.events) and - not any(evt == EventName.pedalPressed for evt in card.events.names)) + selfdrived.update_events(CS) + selfdrived.CS_prev = CS + button_enable = (selfdrived.events.contains(ET.ENABLE) and + EventName.pedalPressed not in selfdrived.events.names) mismatch = button_enable != (self.safety.get_controls_allowed() and not controls_allowed_prev) checks['controlsAllowed'] += mismatch controls_allowed_prev = self.safety.get_controls_allowed() diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index 63e078e6d7..160117faa8 100755 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -7,6 +7,7 @@ import cereal.messaging as messaging from cereal import car, log from msgq.visionipc import VisionIpcClient, VisionStreamType +from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params @@ -14,6 +15,7 @@ from openpilot.common.realtime import config_realtime_process, Priority, Ratekee from openpilot.common.swaglog import cloudlog from openpilot.common.gps import get_gps_location_service +from openpilot.selfdrive.car.car_specific import CarSpecificEvents from openpilot.selfdrive.selfdrived.events import Events, ET from openpilot.selfdrive.selfdrived.state import StateMachine from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert @@ -41,15 +43,21 @@ IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput) class SelfdriveD: - def __init__(self): + def __init__(self, CP=None): self.params = Params() # Ensure the current branch is cached, otherwise the first cycle lags build_metadata = get_build_metadata() - cloudlog.info("selfdrived is waiting for CarParams") - self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams) - cloudlog.info("selfdrived got CarParams") + if CP is None: + cloudlog.info("selfdrived is waiting for CarParams") + self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams) + cloudlog.info("selfdrived got CarParams") + else: + self.CP = CP + + self.car_events = CarSpecificEvents(self.CP) + self.disengage_on_accelerator = not (self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS) # Setup sockets self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents']) @@ -166,7 +174,20 @@ class SelfdriveD: # Add car events, ignore if CAN isn't valid if CS.canValid: - self.events.add_from_msg(CS.events) + car_events = self.car_events.update(CS, self.CS_prev, self.sm['carControl']).to_msg() + self.events.add_from_msg(car_events) + + if self.CP.notCar: + # wait for everything to init first + if self.sm.frame > int(5. / DT_CTRL) and self.initialized: + # body always wants to enable + self.events.add(EventName.pcmEnable) + + # Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0 + if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \ + (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or \ + (CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)): + self.events.add(EventName.pedalPressed) # Create events for temperature, disk space, and memory if self.sm['deviceState'].thermalStatus >= ThermalStatus.red: diff --git a/selfdrive/test/process_replay/README.md b/selfdrive/test/process_replay/README.md index 008a901010..381e4dcb7f 100644 --- a/selfdrive/test/process_replay/README.md +++ b/selfdrive/test/process_replay/README.md @@ -30,7 +30,7 @@ optional arguments: --whitelist-cars WHITELIST_CARS Whitelist given cars from the test (e.g. HONDA) --blacklist-procs BLACKLIST_PROCS Blacklist given processes from the test (e.g. controlsd) --blacklist-cars BLACKLIST_CARS Blacklist given cars from the test (e.g. HONDA) - --ignore-fields IGNORE_FIELDS Extra fields or msgs to ignore (e.g. carState.events) + --ignore-fields IGNORE_FIELDS Extra fields or msgs to ignore (e.g. driverMonitoringState.events) --ignore-msgs IGNORE_MSGS Msgs to ignore (e.g. onroadEvents) --update-refs Updates reference logs using current commit --upload-only Skips testing processes and uploads logs from previous test run diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 32609b0a8f..9aa61ab9c4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f9f1fd736c6bbef3aa2d3aea8e4f8e1c892234de \ No newline at end of file +fbf16d1e9b056830a12fcf29a5137e1fc0b01354 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 78090372a6..ec84f37d1f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -42,7 +42,7 @@ source_segments = [ segments = [ ("BODY", "regenA67A128BCD8|2024-08-30--02-36-22--0"), ("HYUNDAI", "regen9CBD921E93E|2024-08-30--02-38-51--0"), - ("HYUNDAI2", "regen12E0C4EA1A7|2024-08-30--02-42-40--0"), + ("HYUNDAI2", "regen306779F6870|2024-10-03--04-03-23--0"), ("TOYOTA", "regen1CA7A48E6F7|2024-08-30--02-45-08--0"), ("TOYOTA2", "regen6E484EDAB96|2024-08-30--02-47-37--0"), ("TOYOTA3", "regen4CE950B0267|2024-08-30--02-51-30--0"), @@ -135,7 +135,7 @@ if __name__ == "__main__": parser.add_argument("--blacklist-cars", type=str, nargs="*", default=[], help="Blacklist given cars from the test (e.g. HONDA)") parser.add_argument("--ignore-fields", type=str, nargs="*", default=[], - help="Extra fields or msgs to ignore (e.g. carState.events)") + help="Extra fields or msgs to ignore (e.g. driverMonitoringState.events)") parser.add_argument("--ignore-msgs", type=str, nargs="*", default=[], help="Msgs to ignore (e.g. carEvents)") parser.add_argument("--update-refs", action="store_true",