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|[](##)|[](##)|J533||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
-|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[](##)|[](##)|OBD-II||
+|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[](##)|[](##)|OBD-II||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[](##)|[](##)|GM|
|
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[](##)|[](##)|GM||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[](##)|[](##)|GM||
-|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[](##)|[](##)|OBD-II|
|
+|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|OBD-II|
|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|FCA||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|FCA||
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[](##)|[](##)|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|[](##)|[](##)|Hyundai A||
|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Hyundai K||
|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[](##)|[](##)|Hyundai L||
-|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[](##)|[](##)|OBD-II|
|
+|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|OBD-II|
|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[](##)|[](##)|GM|
|
|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|Honda Bosch A|
|
|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|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|[](##)|[](##)|Toyota||
|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[](##)|[](##)|Toyota||
|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[](##)|[](##)|Toyota||
+|Toyota|C-HR Hybrid 2022|All|Stock|0 mph|0 mph|[](##)|[](##)|Toyota||
|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[](##)|[](##)|Toyota|
|
|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[](##)|[](##)|Toyota||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|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|[](##)|[](##)|J533||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
-|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
+|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|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 \