diff --git a/RELEASES.md b/RELEASES.md index d99fe8183f..ded06346c6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,6 +5,8 @@ Version 0.9.1 (2023-2-20) * UI updates * Driver monitoring icon shows driver's head pose * German translation thanks to Vrabetz and CzokNorris! +* New driving model + * 30% improved height estimation resulting in better driving performance for tall cars * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support @@ -12,6 +14,8 @@ Version 0.9.1 (2023-2-20) * Kia Niro Hybrid 2023 support thanks to sunnyhaibin! * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! +* Toyota C-HR 2021 support thanks to eFiniLan! +* Toyota C-HR Hybrid 2022 support thanks to Korben00! * Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! Version 0.9.0 (2022-11-21) diff --git a/docs/CARS.md b/docs/CARS.md index a72bf74278..74e64b969f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 235 Supported Cars +# 236 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -17,11 +17,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| @@ -36,7 +36,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| |Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| @@ -178,6 +178,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| @@ -241,7 +242,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| diff --git a/opendbc b/opendbc index 7f0e42faba..c354dbcdb1 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 7f0e42fabad327d019c33656471af15a718affcc +Subproject commit c354dbcdb1facca115b0fe742a25f59a9c52feff diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 00673a7e28..bcaf6f6f93 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -35,7 +35,7 @@ class CarController: torque -= deadband return torque - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): torque_l = 0 torque_r = 0 diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index a90c4cfb87..850a3538ad 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -43,5 +43,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 2559977206..e1f2b93943 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -19,7 +19,7 @@ class CarController: self.packer = CANPacker(dbc_name) self.params = CarControllerParams(CP) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] lkas_active = CC.latActive and self.lkas_control_bit_prev diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index 82fa1e6d06..ab0d23c5c0 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -84,8 +84,9 @@ class CarState(CarStateBase): if self.CP.carFingerprint in RAM_CARS: self.auto_high_beam = cp_cam.vl["DAS_6"]['AUTO_HIGH_BEAM_ON'] # Auto High Beam isn't Located in this message on chrysler or jeep currently located in 729 message - ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1 + ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1 else: + ret.steerFaultTemporary = cp.vl["EPS_2"]["LKAS_TEMPORARY_FAULT"] == 1 ret.steerFaultPermanent = cp.vl["EPS_2"]["LKAS_STATE"] == 4 # blindspot sensors @@ -139,6 +140,7 @@ class CarState(CarStateBase): ("COUNTER", "EPS_2",), ("COLUMN_TORQUE", "EPS_2"), ("EPS_TORQUE_MOTOR", "EPS_2"), + ("LKAS_TEMPORARY_FAULT", "EPS_2"), ("LKAS_STATE", "EPS_2"), ("COUNTER", "CRUISE_BUTTONS"), ] diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index a27731f926..a1be07cbc3 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -158,5 +158,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index e932238e6a..49f8a080cb 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -62,8 +62,7 @@ RAM_CARS = RAM_DT | RAM_HD # the increased steer rate hasn't been verified on these cars. # remove from this list once it's been tested and confirmed to not fault -CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, - CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} +CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} @dataclass class ChryslerCarInfo(CarInfo): diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 00fb461223..99072ae975 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -21,7 +21,7 @@ class CarController: self.lkas_enabled_last = False self.steer_alert_last = False - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] actuators = CC.actuators diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 8ce30e5d68..9e1366618c 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -78,5 +78,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 7486eff61e..feb595359f 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -13,6 +13,8 @@ LongCtrlState = car.CarControl.Actuators.LongControlState # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s CAMERA_CANCEL_DELAY_FRAMES = 10 +# Enforce a minimum interval between steering messages to avoid a fault +MIN_STEER_MSG_INTERVAL_MS = 15 class CarController: @@ -37,7 +39,7 @@ class CarController: self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis']) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl hud_alert = hud_control.visualAlert @@ -64,9 +66,10 @@ class CarController: self.lka_steering_cmd_counter += 1 self.sent_lka_steering_cmd = True - # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just - # received the ASCMLKASteeringCmd loopback confirmation in the current CS frame - if (self.frame - self.last_steer_frame) >= steer_step and not CS.loopback_lka_steering_cmd_updated: + # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we + # received the ASCMLKASteeringCmd loopback confirmation too recently + last_lka_steer_msg_ms = (now_nanos - CS.loopback_lka_steering_cmd_ts_nanos) * 1e-6 + if (self.frame - self.last_steer_frame) >= steer_step and last_lka_steer_msg_ms > MIN_STEER_MSG_INTERVAL_MS: # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus if not self.sent_lka_steering_cmd: self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index ea867f31e8..5ff914d1d3 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -17,7 +17,11 @@ class CarState(CarStateBase): super().__init__(CP) can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] + self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2. + self.cluster_min_speed = CV.KPH_TO_MS / 2. + self.loopback_lka_steering_cmd_updated = False + self.loopback_lka_steering_cmd_ts_nanos = 0 self.pt_lka_steering_cmd_counter = 0 self.cam_lka_steering_cmd_counter = 0 self.buttons_counter = 0 @@ -38,6 +42,7 @@ class CarState(CarStateBase): # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 + self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] if self.CP.networkLocation == NetworkLocation.fwdCamera: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index f6c2697477..375e51427a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -67,6 +67,7 @@ class CarInterface(CarInterfaceBase): ret.pcmCruise = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS + ret.minSteerSpeed = 10 * CV.KPH_TO_MS # Tuning for experimental long ret.longitudinalTuning.kpV = [2.0, 1.5] @@ -89,6 +90,7 @@ class CarInterface(CarInterfaceBase): ret.pcmCruise = False # stock non-adaptive cruise control is kept off # supports stop and go, but initial engage must (conservatively) be above 18mph ret.minEnableSpeed = 18 * CV.MPH_TO_MS + ret.minSteerSpeed = 7 * CV.MPH_TO_MS # Tuning ret.longitudinalTuning.kpV = [2.4, 1.5] @@ -100,8 +102,6 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. - # Some GMs need some tolerance above 10 kph to avoid a fault - ret.minSteerSpeed = 10.1 * CV.KPH_TO_MS ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 @@ -284,5 +284,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 4565d7fccc..adad1d04fa 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -124,7 +124,7 @@ class CarController: self.brake = 0.0 self.last_steer = 0.0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255 diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index bd923ef71a..dcf50b43f3 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -381,5 +381,5 @@ class CarInterface(CarInterfaceBase): # pass in a car.CarControl # to be called @ 100hz - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index e509b011f6..6246950a2c 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -58,7 +58,7 @@ class CarController: self.lat_disengage_init = False self.lat_active_last = False - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 26af207ad4..fce71c87e4 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -374,5 +374,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1c243b04c6..df4828d24f 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1559,6 +1559,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', + b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', ], }, CAR.TUCSON_4TH_GEN: { diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 003bd1c0e8..198f2d333d 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -247,7 +247,7 @@ class CarInterfaceBase(ABC): return reader @abstractmethod - def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]: + def apply(self, c: car.CarControl, now_nanos: int) -> Tuple[car.CarControl.Actuators, List[bytes]]: pass def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True, diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 027822cc3f..524a02a370 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -15,7 +15,7 @@ class CarController: self.brake_counter = 0 self.frame = 0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] apply_steer = 0 diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index e94b7272b4..297af73ca7 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -113,5 +113,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 3ac487dbb7..13210c86d5 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -57,7 +57,7 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): + def apply(self, c, now_nanos): # in mock no carcontrols actuators = car.CarControl.Actuators.new_message() return actuators, [] diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 0f61d937f2..d3cca764c6 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -23,7 +23,7 @@ class CarController: self.lat_disengage_init = False self.lat_active_last = False - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index bd88882530..f5b81ebea7 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -98,5 +98,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 6e2949e28c..20374468ee 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -19,7 +19,7 @@ class CarController: self.p = CarControllerParams(CP) self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index b53a653d1e..087c44795c 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -166,5 +166,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 6ac2637fa2..5c7d3f5e4d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -253,6 +253,7 @@ FW_VERSIONS = { b'\xca!f@\x07', b'\xca!fp\x07', b'\xf3"f@\x07', + b'\xe6!fp\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xe6\xf5\004\000\000', @@ -262,6 +263,7 @@ FW_VERSIONS = { b'\xf1\x00\xd7\x10@', b'\xe6\xf5D0\x00', b'\xe9\xf6F0\x00', + b'\xe9\xf5B0\x00', ], }, CAR.FORESTER: { diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index 6e2869d1c2..1f18c3d0ea 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -14,7 +14,7 @@ class CarController: self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.tesla_can = TeslaCAN(self.packer, self.pt_packer) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 6a73472108..70d49896cb 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -58,5 +58,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 98db2520c3..a4d2f55581 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -182,6 +182,7 @@ routes = [ CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR), CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.CHR_TSS2), CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH), + CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.CHRH_TSS2), CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V), CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1), diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 24c995a2d0..78ecbe425e 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -59,15 +59,15 @@ class TestCarInterfaces(unittest.TestCase): CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + car_interface.apply(CC, 0) + car_interface.apply(CC, 0) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + car_interface.apply(CC, 0) + car_interface.apply(CC, 0) # Test radar interface RadarInterface = importlib.import_module(f'selfdrive.car.{car_params.carName}.radar_interface').RadarInterface diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 4627b9a570..6fbe1436f1 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -149,7 +149,7 @@ class TestCarModelBase(unittest.TestCase): for i, msg in enumerate(self.can_msgs): CS = self.CI.update(CC, (msg.as_builder().to_bytes(),)) - self.CI.apply(CC) + self.CI.apply(CC, msg.logMonoTime) if CS.canValid: can_valid = True diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 1ac43efc39..61243424f0 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -9,6 +9,7 @@ TOYOTA ALPHARD 2020: TOYOTA SIENNA 2018 TOYOTA PRIUS v 2017 : TOYOTA PRIUS 2017 TOYOTA RAV4 2022: TOYOTA RAV4 HYBRID 2022 TOYOTA C-HR HYBRID 2018: TOYOTA C-HR 2018 +TOYOTA C-HR HYBRID 2022: TOYOTA C-HR 2021 LEXUS IS 2018: LEXUS NX 2018 LEXUS CT HYBRID 2018 : LEXUS NX 2018 LEXUS ES HYBRID 2018: TOYOTA CAMRY HYBRID 2018 diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 6ca10a7075..6c56dbf37e 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -34,7 +34,7 @@ class CarController: self.gas = 0 self.accel = 0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 9b1e86c308..2fe55b04d1 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -75,7 +75,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5533 ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - elif candidate in (CAR.CHR, CAR.CHRH, CAR.CHR_TSS2): + elif candidate in (CAR.CHR, CAR.CHRH, CAR.CHR_TSS2, CAR.CHRH_TSS2): stop_and_go = True ret.wheelbase = 2.63906 ret.steerRatio = 13.6 @@ -315,5 +315,5 @@ class CarInterface(CarInterfaceBase): # pass in a car.CarControl # to be called @ 100hz - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 7e801990a7..b6a556438d 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -51,6 +51,7 @@ class CAR: CHR = "TOYOTA C-HR 2018" CHR_TSS2 = "TOYOTA C-HR 2021" CHRH = "TOYOTA C-HR HYBRID 2018" + CHRH_TSS2 = "TOYOTA C-HR HYBRID 2022" COROLLA = "TOYOTA COROLLA 2017" COROLLA_TSS2 = "TOYOTA COROLLA TSS2 2019" # LSS2 Lexus UX Hybrid is same as a TSS2 Corolla Hybrid @@ -119,6 +120,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), + CAR.CHRH_TSS2: ToyotaCarInfo("Toyota C-HR Hybrid 2022"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ ToyotaCarInfo("Toyota Corolla 2020-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), @@ -233,7 +235,7 @@ FW_QUERY_CONFIG = FwQueryConfig( # FIXME: On some models, abs can sometimes be missing Ecu.abs: [CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_IS], # On some models, the engine can show on two different addresses - Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.LEXUS_IS, CAR.LEXUS_RC], + Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.CHR_TSS2, CAR.LEXUS_IS, CAR.LEXUS_RC], } ) @@ -637,18 +639,25 @@ FW_VERSIONS = { }, CAR.CHR_TSS2: { (Ecu.abs, 0x7b0, None): [ + b'F152610260\x00\x00\x00\x00\x00\x00', b'F1526F4270\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B10091\x00\x00\x00\x00\x00\x00', + b'8965B10110\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x0189663F459000\x00\x00\x00\x00', ], + (Ecu.engine, 0x7e0, None): [ + b'\x0331014000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', + ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821FF410200\x00\x00\x00\x00', b'\x018821FF410300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646FF410200\x00\x00\x00\x008646GF408200\x00\x00\x00\x00', b'\x028646FF411100\x00\x00\x00\x008646GF409000\x00\x00\x00\x00', ], }, @@ -705,6 +714,23 @@ FW_VERSIONS = { b'8646FF407000 ', ], }, + CAR.CHRH_TSS2: { + (Ecu.eps, 0x7a1, None): [ + b'8965B10092\x00\x00\x00\x00\x00\x00', + ], + (Ecu.abs, 0x7b0, None): [ + b'F152610041\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x0189663F438000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 15): [ + b'\x018821FF410500\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 109): [ + b'\x028646FF413100\x00\x00\x00\x008646GF411100\x00\x00\x00\x00', + ], + }, CAR.COROLLA: { (Ecu.engine, 0x7e0, None): [ b'\x0230ZC2000\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', @@ -2051,6 +2077,7 @@ DBC = { CAR.CHR: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CHR_TSS2: dbc_dict('toyota_nodsu_pt_generated', None), CAR.CHRH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), + CAR.CHRH_TSS2: dbc_dict('toyota_nodsu_pt_generated', None), CAR.CAMRY: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRYH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRY_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2092,7 +2119,7 @@ EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_I # Toyota/Lexus Safety Sense 2.0 and 2.5 TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, - CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2} + CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2, CAR.CHRH_TSS2} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} @@ -2100,9 +2127,9 @@ NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} # these cars have a radar which sends ACC messages instead of the camera -RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2} +RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2, CAR.CHRH_TSS2} -EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, +EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.CHRH_TSS2, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 39b7fc6d71..69e398f464 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -24,7 +24,7 @@ class CarController: self.hcaSameTorqueCount = 0 self.hcaEnabledFrameCount = 0 - def update(self, CC, CS, ext_bus): + def update(self, CC, CS, ext_bus, now_nanos): actuators = CC.actuators hud_control = CC.hudControl can_sends = [] diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 6d0f821cd1..18e7b62751 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -277,5 +277,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS, self.ext_bus) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, self.ext_bus, now_nanos) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 72fcc5d92d..cd30bef73b 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -222,7 +222,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { ], CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022"), CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_MQB_A0]), - CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22"), + CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2018-23"), CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), CAR.TRANSPORTER_T61: [ VWCarInfo("Volkswagen Caravelle 2020"), @@ -734,6 +734,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906027G \xf1\x899893', b'\xf1\x875N0906259 \xf1\x890002', + b'\xf1\x875NA906259H \xf1\x890002', b'\xf1\x875NA907115E \xf1\x890005', b'\xf1\x8783A907115B \xf1\x890005', b'\xf1\x8783A907115F \xf1\x890002', @@ -751,6 +752,7 @@ FW_VERSIONS = { b'\xf1\x870DL300013A \xf1\x893005', b'\xf1\x870DL300013G \xf1\x892119', b'\xf1\x870DL300013G \xf1\x892120', + b'\xf1\x870DL300014C \xf1\x893703', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AR\xf1\x890317\xf1\x82\02331310031333334313132573732379333313100', @@ -761,6 +763,7 @@ FW_VERSIONS = { b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140013750379333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140573752379333423100', b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1316143231313500314647021750179333613100', + b'\xf1\x875Q0959655CG\xf1\x890421\xf1\x82\x1331310031333300314240024050409333613100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603', @@ -768,6 +771,7 @@ FW_VERSIONS = { b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567A6000600', b'\xf1\x875QF909144A \xf1\x895581\xf1\x82\x0571A60834A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\00571A60634A1', + b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571A62A32A1', b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\00521A60804A1', diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 7cb8a0717a..493d26ac94 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -179,12 +179,12 @@ class Controls: self.enabled = False self.enabled_long = False self.active = False - self.can_rcv_timeout = False self.soft_disable_timer = 0 self.mismatch_counter = 0 self.mismatch_counter_long = 0 self.cruise_mismatch_counter = 0 - self.can_rcv_timeout_counter = 0 + self.can_rcv_timeout_counter = 0 # conseuctive timeout count + self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count self.last_blinker_frame = 0 self.last_steering_pressed_frame = 0 self.distance_traveled = 0 @@ -196,10 +196,12 @@ class Controls: self.steer_limited = False self.desired_curvature = 0.0 self.desired_curvature_rate = 0.0 + self.experimental_mode = False self.v_cruise_helper = VCruiseHelper(self.CP) # TODO: no longer necessary, aside from process replay self.sm['liveParameters'].valid = True + self.can_log_mono_time = 0 self.startup_event = get_startup_event(car_recognized, controller_available, len(self.CP.carFw) > 0) @@ -370,9 +372,10 @@ class Controls: self.events.add(EventName.canError) # generic catch-all. ideally, a more specific event should be added above instead + can_rcv_timeout = self.can_rcv_timeout_counter >= 5 has_disable_events = self.events.any(ET.NO_ENTRY) and (self.events.any(ET.SOFT_DISABLE) or self.events.any(ET.IMMEDIATE_DISABLE)) no_system_errors = (not has_disable_events) or (len(self.events) == num_events) - if (not self.sm.all_checks() or self.can_rcv_timeout) and no_system_errors: + if (not self.sm.all_checks() or can_rcv_timeout) and no_system_errors: if not self.sm.all_alive(): self.events.add(EventName.commIssue) elif not self.sm.all_freq_ok(): @@ -384,7 +387,7 @@ class Controls: 'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], - 'can_rcv_timeout': self.can_rcv_timeout, + 'can_rcv_timeout': can_rcv_timeout, } if logs != self.logged_comm_issue: cloudlog.event("commIssue", error=True, **logs) @@ -447,6 +450,8 @@ class Controls: # Update carState from CAN can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) CS = self.CI.update(self.CC, can_strs) + if len(can_strs) and REPLAY: + self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime self.sm.update(0) @@ -464,9 +469,9 @@ class Controls: # Check for CAN timeout if not can_strs: self.can_rcv_timeout_counter += 1 - self.can_rcv_timeout = True + self.can_rcv_cum_timeout_counter += 1 else: - self.can_rcv_timeout = False + self.can_rcv_timeout_counter = 0 # When the panda and controlsd do not agree on controls_allowed # we want to disengage openpilot. However the status from the panda goes through @@ -515,7 +520,7 @@ class Controls: # ENABLED if self.state == State.enabled: if CS.cruiseState.enabled and not self.CS_prev.cruiseState.enabled: - self.v_cruise_helper.initialize_v_cruise(CS) + self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode) # Block resume if cruise never previously enabled resume_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in CS.buttonEvents) if not self.CP.pcmCruise and not self.v_cruise_helper.v_cruise_initialized and resume_pressed: @@ -574,7 +579,7 @@ class Controls: self.state = State.enabled self.current_alert_types.append(ET.ENABLE) if CS.cruiseState.enabled: - self.v_cruise_helper.initialize_v_cruise(CS) + self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode) # Check if openpilot is engaged and actuators are enabled self.enabled = self.state in ENABLED_STATES @@ -769,7 +774,8 @@ class Controls: if not self.read_only and self.initialized: # send car controls over can - self.last_actuators, can_sends = self.CI.apply(CC) + now_nanos = self.can_log_mono_time if REPLAY else int(sec_since_boot() * 1e9) + self.last_actuators, can_sends = self.CI.apply(CC, now_nanos) self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) CC.actuatorsOutput = self.last_actuators if self.CP.steerControlType == car.CarParams.SteerControlType.angle: @@ -819,8 +825,8 @@ class Controls: controlsState.cumLagMs = -self.rk.remaining * 1000. controlsState.startMonoTime = int(start_time * 1e9) controlsState.forceDecel = bool(force_decel) - controlsState.canErrorCounter = self.can_rcv_timeout_counter - controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl + controlsState.canErrorCounter = self.can_rcv_cum_timeout_counter + controlsState.experimentalMode = self.experimental_mode lat_tuning = self.CP.lateralTuning.which() if self.joystick_mode: @@ -871,6 +877,7 @@ class Controls: self.prof.checkpoint("Ratekeeper", ignore=True) self.is_metric = self.params.get_bool("IsMetric") + self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl # Sample data from sockets and get a carState CS = self.data_sample() diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 3d5ec8ac1d..a332d06765 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -8,10 +8,12 @@ from selfdrive.modeld.constants import T_IDXS # WARNING: this value was determined based on the model's training distribution, # model predictions above this speed can be unpredictable -V_CRUISE_MAX = 145 # kph -V_CRUISE_MIN = 8 # kph -V_CRUISE_ENABLE_MIN = 40 # kph -V_CRUISE_INITIAL = 255 # kph +# V_CRUISE's are in kph +V_CRUISE_MIN = 8 +V_CRUISE_MAX = 145 +V_CRUISE_UNSET = 255 +V_CRUISE_INITIAL = 40 +V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 105 IMPERIAL_INCREMENT = 1.6 # should be CV.MPH_TO_KPH, but this causes rounding errors MIN_SPEED = 1.0 @@ -39,15 +41,15 @@ CRUISE_INTERVAL_SIGN = { class VCruiseHelper: def __init__(self, CP): self.CP = CP - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_kph = V_CRUISE_UNSET + self.v_cruise_cluster_kph = V_CRUISE_UNSET self.v_cruise_kph_last = 0 self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers} @property def v_cruise_initialized(self): - return self.v_cruise_kph != V_CRUISE_INITIAL + return self.v_cruise_kph != V_CRUISE_UNSET def update_v_cruise(self, CS, enabled, is_metric): self.v_cruise_kph_last = self.v_cruise_kph @@ -62,8 +64,8 @@ class VCruiseHelper: self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH else: - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_kph = V_CRUISE_UNSET + self.v_cruise_cluster_kph = V_CRUISE_UNSET def _update_v_cruise_non_pcm(self, CS, enabled, is_metric): # handle button presses. TODO: this should be in state_control, but a decelCruise press @@ -125,16 +127,18 @@ class VCruiseHelper: self.button_timers[b.type.raw] = 1 if b.pressed else 0 self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled} - def initialize_v_cruise(self, CS): + def initialize_v_cruise(self, CS, experimental_mode: bool) -> None: # initializing is handled by the PCM if self.CP.pcmCruise: return + initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode else V_CRUISE_INITIAL + # 250kph or above probably means we never had a set speed if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_kph_last < 250: self.v_cruise_kph = self.v_cruise_kph_last else: - self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, V_CRUISE_ENABLE_MIN, V_CRUISE_MAX))) + self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, initial, V_CRUISE_MAX))) self.v_cruise_cluster_kph = self.v_cruise_kph diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index cd1d31cf07..b83116af45 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -3,7 +3,7 @@ import numpy as np from parameterized import parameterized_class import unittest -from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN, IMPERIAL_INCREMENT +from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT from cereal import car from common.conversions import Conversions as CV from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver @@ -53,16 +53,16 @@ class TestVCruiseHelper(unittest.TestCase): for _ in range(2): self.v_cruise_helper.update_v_cruise(car.CarState(cruiseState={"available": False}), enabled=False, is_metric=False) - def enable(self, v_ego): + def enable(self, v_ego, experimental_mode): # Simulates user pressing set with a current speed - self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego)) + self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode) def test_adjust_speed(self): """ Asserts speed changes on falling edges of buttons. """ - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) for btn in (ButtonType.accelCruise, ButtonType.decelCruise): for pressed in (True, False): @@ -86,7 +86,7 @@ class TestVCruiseHelper(unittest.TestCase): CS.buttonEvents = [ButtonEvent(type=ButtonType.decelCruise, pressed=pressed)] self.v_cruise_helper.update_v_cruise(CS, enabled=enabled, is_metric=False) if pressed: - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) # Expected diff on enabling. Speed should not change on falling edge of pressed self.assertEqual(not pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) @@ -96,7 +96,7 @@ class TestVCruiseHelper(unittest.TestCase): Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill. """ - self.enable(0) + self.enable(0, False) for standstill in (True, False): for pressed in (True, False): @@ -116,7 +116,7 @@ class TestVCruiseHelper(unittest.TestCase): for v_ego in np.linspace(0, 100, 101): self.reset_cruise_speed_state() - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) # first decrement speed, then perform gas pressed logic expected_v_cruise_kph = self.v_cruise_helper.v_cruise_kph - IMPERIAL_INCREMENT @@ -137,13 +137,14 @@ class TestVCruiseHelper(unittest.TestCase): Asserts allowed cruise speeds on enabling with SET. """ - for v_ego in np.linspace(0, 100, 101): - self.reset_cruise_speed_state() - self.assertFalse(self.v_cruise_helper.v_cruise_initialized) + for experimental_mode in (True, False): + for v_ego in np.linspace(0, 100, 101): + self.reset_cruise_speed_state() + self.assertFalse(self.v_cruise_helper.v_cruise_initialized) - self.enable(float(v_ego)) - self.assertTrue(V_CRUISE_ENABLE_MIN <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) - self.assertTrue(self.v_cruise_helper.v_cruise_initialized) + self.enable(float(v_ego), experimental_mode) + self.assertTrue(V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) + self.assertTrue(self.v_cruise_helper.v_cruise_initialized) if __name__ == "__main__": diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 170beafe88..0081a20e21 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a6b17ab903022b42677abe2968f3c6e50c331980 +fbf92051507b7a7585907b58baadec6b8cc475af diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 4a7874b160..8c7a7072e2 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -382,6 +382,10 @@ void CameraWidget::vipcThread() { } } emit vipcThreadFrameReceived(); + } else { + if (!isVisible()) { + vipc_client->connected = false; + } } } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 134a162679..5063ec9dea 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -310,7 +310,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); axis_y = new QValueAxis(this); - axis_y->setLabelFormat("%.1f"); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); chart->legend()->layout()->setContentsMargins(16, 0, 40, 0); @@ -365,7 +364,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { } void ChartView::addSeries(const QString &msg_id, const Signal *sig) { - QXYSeries *series = createSeries(series_type); + QXYSeries *series = createSeries(series_type, getColor(sig)); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); @@ -519,8 +518,8 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; - s.series->setColor(getColor(s.sig)); } + s.series->setColor(getColor(s.sig)); struct Chunk { std::vector::const_iterator first, second; @@ -777,17 +776,22 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } -QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) { +QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor color) { QXYSeries *series = nullptr; if (type == QAbstractSeries::SeriesTypeLine) { series = new QLineSeries(this); } else { series = new QScatterSeries(this); } + series->setColor(color); // TODO: Due to a bug in CameraWidget the camera frames // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed #ifndef __APPLE__ series->setUseOpenGL(true); + // Qt doesn't properly apply device pixel ratio in OpenGL mode + QPen pen = series->pen(); + pen.setWidth(2.0 * qApp->devicePixelRatio()); + series->setPen(pen); #endif return series; } @@ -802,7 +806,7 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { s.series->deleteLater(); } for (auto &s : sigs) { - auto series = createSeries(series_type); + auto series = createSeries(series_type, getColor(s.sig)); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 953026d935..25949dd654 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -76,7 +76,7 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; std::tuple getNiceAxisNumbers(qreal min, qreal max, int tick_count); qreal niceNumber(qreal x, bool ceiling); - QXYSeries *createSeries(QAbstractSeries::SeriesType type); + QXYSeries *createSeries(QAbstractSeries::SeriesType type, QColor color); void updateSeriesPoints(); int y_label_width = 0; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 83f5fdb74a..3d565e7067 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -13,10 +13,16 @@ void DBCManager::open(const QString &dbc_file_name) { initMsgMap(); } -void DBCManager::open(const QString &name, const QString &content) { - std::istringstream stream(content.toStdString()); - dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - initMsgMap(); +bool DBCManager::open(const QString &name, const QString &content, QString *error) { + try { + std::istringstream stream(content.toStdString()); + dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); + initMsgMap(); + return true; + } catch (std::exception &e) { + if (error) *error = e.what(); + } + return false; } void DBCManager::initMsgMap() { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 03bd16f2a5..41471a6169 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -22,7 +22,7 @@ public: ~DBCManager(); void open(const QString &dbc_file_name); - void open(const QString &name, const QString &content); + bool open(const QString &name, const QString &content, QString *error = nullptr); QString generateDBC(); void addSignal(const QString &id, const Signal &sig); void updateSignal(const QString &id, const QString &sig_name, const Signal &sig); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index a7ad572dc1..25d9b3b9ca 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -32,7 +32,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); toolbar->addWidget(time_label); - name_label = new QLabel(this); + name_label = new ElidedLabel(this); + name_label->setContentsMargins(5, 0, 5, 0); name_label->setStyleSheet("font-weight:bold;"); name_label->setAlignment(Qt::AlignCenter); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index a62e23f226..0983f49924 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -5,6 +5,7 @@ #include #include +#include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" #include "tools/cabana/historylog.h" @@ -40,7 +41,8 @@ private: void updateState(const QHash * msgs = nullptr); QString msg_id; - QLabel *name_label, *time_label, *warning_icon, *warning_label; + QLabel *time_label, *warning_icon, *warning_label; + ElidedLabel *name_label; QWidget *warning_widget; QTabBar *tabbar; QTabWidget *tab_widget; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index b24c4e6dc4..bce6d313c8 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -220,9 +220,16 @@ void MainWindow::loadFile(const QString &fn) { QFile file(fn); if (file.open(QIODevice::ReadOnly)) { auto dbc_name = QFileInfo(fn).baseName(); - dbc()->open(dbc_name, file.readAll()); - setCurrentFile(fn); - statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); + QString error; + bool ret = dbc()->open(dbc_name, file.readAll(), &error); + if (ret) { + setCurrentFile(fn); + statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); + } else { + QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC file"), tr("Failed to parse DBC file %1").arg(fn)); + msg_box.setDetailedText(error); + msg_box.exec(); + } } } } @@ -251,11 +258,16 @@ void MainWindow::loadDBCFromOpendbc(const QString &name) { void MainWindow::loadDBCFromClipboard() { remindSaveChanges(); QString dbc_str = QGuiApplication::clipboard()->text(); - dbc()->open("from_clipboard.dbc", dbc_str); - if (dbc()->messages().size() > 0) { + QString error; + bool ret = dbc()->open("clipboard", dbc_str, &error); + if (ret && dbc()->messages().size() > 0) { QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } else { - QMessageBox::warning(this, tr("Load From Clipboard"), tr("Failed to parse dbc from clipboard!\nMake sure that you paste the text with correct format.")); + QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC from clipboard"), tr("Make sure that you paste the text with correct format.")); + if (!error.isEmpty()) { + msg_box.setDetailedText(error); + } + msg_box.exec(); } } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 359fe10f50..8279d08a5c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -182,11 +182,10 @@ void MessageListModel::sortMessages() { void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - bool update_all = new_msgs->size() == can->can_msgs.size(); - if (update_all || (filter_str.isEmpty() && msgs.size() != can->can_msgs.size())) { + if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { msgs = can->can_msgs.keys(); } - if (update_all || msgs.size() != prev_row_count) { + if (msgs.size() != prev_row_count) { sortMessages(); return; } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 2f1a968645..7988037c34 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -266,6 +266,7 @@ void SignalModel::handleSignalRemoved(const Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) { name_validator = new NameValidator(this); double_validator = new QDoubleValidator(this); + small_font.setPointSize(8); double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system } @@ -280,20 +281,19 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - QRect rc{option.rect.left() + 3, option.rect.top(), 22, option.rect.height()}; + QRect rc{option.rect.left(), option.rect.top(), 18, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); - painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 5, 5); + painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 3, 3); painter->setPen(item->highlight ? Qt::white : Qt::black); + painter->setFont(small_font); painter->drawText(rc, Qt::AlignCenter, QString::number(item->row() + 1)); // signal name - QFont font; - font.setBold(true); - painter->setFont(font); + painter->setFont(option.font); painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); QString text = index.data(Qt::DisplayRole).toString(); - QRect text_rect = option.rect.adjusted(rc.width() + 9, 0, 0, 0); + QRect text_rect = option.rect.adjusted(rc.width() + 6, 0, 0, 0); text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index ae88a5b13a..6a904e7328 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -68,6 +68,7 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; + QFont small_font; }; class SignalView : public QWidget { diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 94d653bcb0..13b154a7ea 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -72,6 +72,7 @@ void AbstractStream::updateLastMsgsTo(double sec) { m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); m.last_change_t = QVector(m.dat.size(), m.ts); + m.bit_change_counts.resize(m.dat.size()); } else { m.freq = m.count / std::max(1.0, m.ts); } diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 2806e175d7..454dd29b87 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -62,6 +62,7 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { void ChangeTracker::clear() { prev_dat.clear(); last_change_t.clear(); + bit_change_counts.clear(); colors.clear(); } @@ -82,6 +83,12 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); + auto byte_list = opt.text.split(" "); + if (byte_list.size() <= 1) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { painter->setPen(option.palette.color(QPalette::HighlightedText)); } else { @@ -98,7 +105,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QList colors = index.data(Qt::UserRole).toList(); int i = 0; - for (auto &byte : opt.text.split(" ")) { + for (auto &byte : byte_list) { if (i < colors.size()) { painter->fillRect(pos.marginsAdded(margins), colors[i].value()); } diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 5d5b44d63c..8ec4cda90c 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index d8d89a708c..cd3dc0b516 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -32,6 +32,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); play_btn = new QPushButton(); + play_btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); control_layout->addWidget(play_btn); QButtonGroup *group = new QButtonGroup(this); diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 09296ef94d..71bad2e8a2 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -86,6 +86,7 @@ function install_ubuntu_lts_latest_requirements() { install_ubuntu_common_requirements $SUDO apt-get install -y --no-install-recommends \ + g++-12 \ qtbase5-dev \ qtchooser \ qt5-qmake \