diff --git a/CHANGELOGS.md b/CHANGELOGS.md index 787da4b9a1..381d8e0326 100644 --- a/CHANGELOGS.md +++ b/CHANGELOGS.md @@ -1,10 +1,36 @@ -sunnypilot - 0.9.5.1 (202x-xx-xx) +sunnypilot - 0.9.5.1 (2023-09-27) ======================== -* UPDATED: Synced with commaai's master commit 338288d +* UPDATED: Synced with commaai's 0.9.5 release * NEW❗: Non-Inflatable driving model +* NEW❗: Onroad Settings Panel + * Onroad buttons (i.e., DLP, GAC) moved to its dedicated panel + * Driving Personality + * Dynamic Lane Profile (DLP) + * Speed Limit Control (SLC) +* NEW❗: Display main feature status on onroad view in real-time + * GAP - Driving Personality + * DLP - Dynamic Lane Profile + * SLC - Speed Limit Control +* NEW❗: Subaru - Stop and Go auto-resume support thanks to martinl! + * Global (excluding Gen 2 and Hybrid) and Pre-Global support +* NEW❗: Toyota - Stop and Go hack + * Allow some Toyota/Lexus cars to auto resume during stop and go traffic + * Only applicable to certain models and model years * NEW❗: Wide camera view when the steering angle is more than 45° -* Custom Stock Longitudinal Control +* NEW❗: Toyota: ZSS support thanks to dragonpilot-community and ErichMoraga! +* openpilot Longitudianl Control capable cars only + * UPDATED: Gap Adjust Cruise is now a part of Driving Personality + * [DISTANCE/FOLLOW DISTANCE/GAP DISTANCE] physical button on the steering wheel to select Driving Personality on by default + * Status now viewable in onroad view or Onroad Settings Panel + * REMOVED: Gap Adjust Cruise toggle +* UPDATED: Custom Stock Longitudinal Control * RE-ENABLED: Hyundai/Kia/Genesis CAN-FD platforms +* UPDATED: Auto-detect custom Mapbox token + * REMOVED: "Enable Mapbox Navigation" toggle +* UPDATED: Developer UI: Bottom row now hidden when there are active alerts +* FIXED: Map stuck in "Map Loading" if comma Prime is active +* FIXED: UI elements adjustments +* Kia Seltos Non-SCC 2023-24 support thanks to Moodkiller and jeroid_! sunnypilot - 0.9.4.1 (2023-08-11) ======================== diff --git a/common/params.cc b/common/params.cc index 59f6ca1816..0c19b6dc76 100644 --- a/common/params.cc +++ b/common/params.cc @@ -224,7 +224,6 @@ std::unordered_map keys = { {"CarModelText", PERSISTENT}, {"ChevronInfo", PERSISTENT}, {"CustomBootScreen", PERSISTENT}, - {"CustomMapbox", PERSISTENT}, {"CustomMapboxTokenPk", PERSISTENT}, {"CustomMapboxTokenSk", PERSISTENT}, {"CustomOffsets", PERSISTENT}, @@ -234,6 +233,8 @@ std::unordered_map keys = { {"DevUIInfo", PERSISTENT}, {"DisableOnroadUploads", PERSISTENT}, {"DisengageLateralOnBrake", PERSISTENT}, + {"DynamicExperimentalControl", PERSISTENT}, + {"DynamicExperimentalControlToggle", PERSISTENT}, {"DynamicLaneProfile", PERSISTENT}, {"DynamicLaneProfileToggle", PERSISTENT}, {"EnableAmap", PERSISTENT}, @@ -254,13 +255,16 @@ std::unordered_map keys = { {"HideVEgoUi", PERSISTENT}, {"HkgSmoothStop", PERSISTENT}, {"HotspotOnBoot", PERSISTENT}, + {"HotspotOnBootConfirmed", PERSISTENT}, {"LastCarModel", PERSISTENT}, {"LastSpeedLimitSignTap", PERSISTENT}, {"LiveTorque", PERSISTENT}, + {"LiveTorqueRelaxed", PERSISTENT}, {"LkasToggle", PERSISTENT}, {"MadsCruiseMain", PERSISTENT}, {"MadsIconToggle", PERSISTENT}, {"MapboxFullScreen", PERSISTENT}, + {"Map3DBuildings", PERSISTENT}, {"MaxTimeOffroad", PERSISTENT}, {"OnroadScreenOff", PERSISTENT}, {"OnroadScreenOffBrightness", PERSISTENT}, @@ -287,9 +291,12 @@ std::unordered_map keys = { {"SpeedLimitOffsetType", PERSISTENT}, {"StandStillTimer", PERSISTENT}, {"StockLongToyota", PERSISTENT}, + {"SubaruManualParkingBrakeSng", PERSISTENT}, {"TorqueDeadzoneDeg", PERSISTENT}, {"TorqueFriction", PERSISTENT}, {"TorqueMaxLatAccel", PERSISTENT}, + {"TorquedOverride", PERSISTENT}, + {"ToyotaSnG", PERSISTENT}, {"ToyotaTSS2Long", PERSISTENT}, {"TrueVEgoUi", PERSISTENT}, {"TurnSpeedControl", PERSISTENT}, diff --git a/panda b/panda index cd1cc939b4..92aaeb38b0 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit cd1cc939b43e6f53b4df60e5a922aaf7ea08da5c +Subproject commit 92aaeb38b08d24912c1433721afcfa1d52a049db diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 6f9f66a925..fc36ce27f8 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -115,6 +115,7 @@ class CarState(CarStateBase): ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0 and self.mainEnabled ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1 ret.cruiseState.standstill = False + ret.cruiseState.nonAdaptive = False elif self.CP.carFingerprint in NON_SCC_CAR: ret.cruiseState.available = cp.vl['EMS16']['CRUISE_LAMP_M'] != 0 ret.cruiseState.enabled = cp.vl["LVR12"]['CF_Lvr_CruiseSet'] != 0 diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index 696f18150a..00f62df231 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -39,7 +39,8 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, - CAR.AZERA_6TH_GEN, CAR.ELANTRA_2022_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC): + CAR.AZERA_6TH_GEN, CAR.ELANTRA_2022_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC, + CAR.KIA_SELTOS_2023_NON_SCC): values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsOpt_USM"] = 2 diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 85b9f06d7d..4aeb12018a 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -65,6 +65,7 @@ class CarInterface(CarInterfaceBase): if 0x2AB in fingerprint[0]: ret.spFlags |= HyundaiFlagsSP.SP_ENHANCED_SCC.value + ret.radarUnavailable = False ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 @@ -160,7 +161,7 @@ class CarInterface(CarInterfaceBase): ret.tireStiffnessFactor = 0.385 if candidate == CAR.KIA_NIRO_PHEV: ret.minSteerSpeed = 32 * CV.MPH_TO_MS - elif candidate == CAR.KIA_SELTOS: + elif candidate in (CAR.KIA_SELTOS, CAR.KIA_SELTOS_2023_NON_SCC): ret.mass = 1337. ret.wheelbase = 2.63 ret.steerRatio = 14.56 diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py index bf08e2d130..05d368b817 100644 --- a/selfdrive/car/hyundai/radar_interface.py +++ b/selfdrive/car/hyundai/radar_interface.py @@ -10,12 +10,13 @@ RADAR_MSG_COUNT = 32 def get_radar_can_parser(CP): - if (CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC) and DBC[CP.carFingerprint]['radar'] is None: - messages = ("ESCC", 50) - return CANParser(DBC[CP.carFingerprint]['pt'], messages, 0) - else: - if DBC[CP.carFingerprint]['radar'] is None: + if DBC[CP.carFingerprint]['radar'] is None: + if CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC: + lead_src, bus = "ESCC", 0 + else: return None + messages = [(lead_src, 50)] + return CANParser(DBC[CP.carFingerprint]['pt'], messages, bus) messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)] return CANParser(DBC[CP.carFingerprint]['radar'], messages, 1) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index e02e4561cd..9c9cc4e0b5 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -124,6 +124,7 @@ class CAR: KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_SELTOS = "KIA SELTOS 2021" + KIA_SELTOS_2023_NON_SCC = "KIA SELTOS 2023 NON-SCC" KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN" KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_SORENTO_4TH_GEN = "KIA SORENTO 4TH GEN" @@ -297,6 +298,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.ELANTRA_2022_NON_SCC: HyundaiCarInfo("Hyundai Elantra Non-SCC 2022", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_k])), CAR.KIA_FORTE_2019_NON_SCC: HyundaiCarInfo("Kia Forte Non-SCC 2019", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_g])), CAR.KIA_FORTE_2021_NON_SCC: HyundaiCarInfo("Kia Forte Non-SCC 2021", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_g])), + CAR.KIA_SELTOS_2023_NON_SCC: HyundaiCarInfo("Kia Seltos Non-SCC 2023-24", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_l])), CAR.GENESIS_G70_2021_NON_SCC: HyundaiCarInfo("Genesis G70 Non-SCC 2021", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_f])), } @@ -1639,6 +1641,28 @@ FW_VERSIONS = { b'\xf1\x87954A22D200\xf1\x81T01950A1 \xf1\000T0190XBL T01950A1 DSP2T16X4X950NS8\r\xfe\x9c\x8b', ], }, + CAR.KIA_SELTOS_2023_NON_SCC: { + (Ecu.abs, 0x7d1, None): [ + b'\xf1\x00SP ESC \t 101"\t\x01 58910-Q5510', + b'\xf1\x00SP ESC \r 100"\x04\x01 58910-Q5510', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81616K0051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x81616G2051\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00SP2 MDPS C 1.00 1.04 56310Q5240 4SPSC104', + b'\xf1\x00SP2 MDPS C 1.00 1.01 56300Q5920 ', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00SP2 MFC AT USA LHD 1.00 1.03 99210-Q5500 230208', + b'\xf1\x00SP2 MFC AT AUS RHD 1.00 1.02 99210-Q5500 220624', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x006V2B0_C2\x00\x006V2D5051\x00\x00CSP2N20NL0\x00\x00\x00\x00', + b'\xf1\x006V2B0_C2\x00\x006V2D4051\x00\x00CSP2N20KL1\x00\x00\x00\x00', + ], + }, CAR.KIA_OPTIMA_G4: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4100 ', @@ -2055,7 +2079,7 @@ FW_VERSIONS = { CHECKSUM = { "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.KIA_K5_HEV_2020, - CAR.ELANTRA_2022_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC], + CAR.ELANTRA_2022_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC, CAR.KIA_SELTOS_2023_NON_SCC], "6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS], } @@ -2098,7 +2122,8 @@ LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.KIA_OPTIMA_ # these cars have not been verified to work with longitudinal yet - radar disable, sending correct messages, etc. UNSUPPORTED_LONGITUDINAL_CAR = LEGACY_SAFETY_MODE_CAR | {CAR.KIA_NIRO_PHEV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4_FL} -NON_SCC_CAR = {CAR.KIA_FORTE_2021_NON_SCC, CAR.ELANTRA_2022_NON_SCC, CAR.KIA_FORTE_2019_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC} +NON_SCC_CAR = {CAR.KIA_FORTE_2021_NON_SCC, CAR.ELANTRA_2022_NON_SCC, CAR.KIA_FORTE_2019_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC, + CAR.KIA_SELTOS_2023_NON_SCC} NON_SCC_NO_FCA_CAR = {CAR.KIA_FORTE_2019_NON_SCC, } NON_SCC_RADAR_FCA_CAR = {CAR.GENESIS_G70_2021_NON_SCC, } @@ -2134,6 +2159,7 @@ DBC = { CAR.KIA_OPTIMA_G4_FL: dbc_dict('hyundai_kia_generic', None), CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None), CAR.KIA_SELTOS: dbc_dict('hyundai_kia_generic', None), + CAR.KIA_SELTOS_2023_NON_SCC: dbc_dict('hyundai_kia_generic', None), CAR.KIA_SORENTO: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format CAR.KIA_STINGER: dbc_dict('hyundai_kia_generic', None), CAR.KIA_STINGER_2022: dbc_dict('hyundai_kia_generic', None), diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 2e1156d849..0ebab681cf 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -127,8 +127,12 @@ class CarInterfaceBase(ABC): def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool, docs: bool): ret = CarInterfaceBase.get_std_params(candidate) ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs) - if Params().get_bool("EnforceTorqueLateral") and ret.steerControlType != car.CarParams.SteerControlType.angle: + + params = Params() + if params.get_bool("EnforceTorqueLateral") and ret.steerControlType != car.CarParams.SteerControlType.angle: ret = CarInterfaceBase.sp_configure_torque_tune(candidate, ret) + if params.get_bool("CustomTorqueLateral"): + ret = CarInterfaceBase.sp_configure_custom_torque_tune(ret, params) # Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload if not ret.notCar: @@ -226,6 +230,12 @@ class CarInterfaceBase(ABC): CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) return ret + @staticmethod + def sp_configure_custom_torque_tune(ret, params): + ret.lateralTuning.torque.friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.01 + ret.lateralTuning.torque.latAccelFactor = float(params.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01 + return ret + @abstractmethod def _update(self, c: car.CarControl) -> car.CarState: pass @@ -472,9 +482,10 @@ class CarInterfaceBase(ABC): def toggle_gac(self, cs_out, CS, gac_button, gac_min, gac_max, gac_default, inc_dec): if not self.CP.openpilotLongitudinalControl: - CS.gac_tr = 2 CS.gac_tr_cluster = gac_default - put_nonblocking("LongitudinalPersonality", 2) + if CS.gac_tr != 2: + CS.gac_tr = 2 + put_nonblocking("LongitudinalPersonality", "2") return cs_out, CS if gac_button: self.gac_button_counter += 1 diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 03a2d01235..6c22b75103 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,14 +1,20 @@ +from cereal import car +from typing import Tuple from openpilot.common.numpy_fast import clip, interp +from openpilot.common.params import Params from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.subaru import subarucan -from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, STEER_RATE_LIMITED, CanBus, CarControllerParams, SubaruFlags +from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, STEER_RATE_LIMITED, CanBus, CarControllerParams, SubaruFlags, SubaruFlagsSP # FIXME: These limits aren't exact. The real limit is more than likely over a larger time period and # involves the total steering angle change rather than rate, but these limits work well for now MAX_STEER_RATE = 25 # deg/s MAX_STEER_RATE_FRAMES = 7 # tx control frames needed before torque can be cut +_SNG_ACC_MIN_DIST = 3 +_SNG_ACC_MAX_DIST = 4.5 + class CarController: def __init__(self, dbc_name, CP, VM): @@ -19,6 +25,21 @@ class CarController: self.cruise_button_prev = 0 self.steer_rate_counter = 0 + self.param_s = Params() + + if CP.spFlags & SubaruFlagsSP.SP_SUBARU_SNG: + self.subaru_sng = True + self.manual_parking_brake = self.param_s.get_bool("SubaruManualParkingBrakeSng") + self.throttle_cnt = -1 + self.brake_pedal_cnt = -1 + self.prev_close_distance = 0 + self.prev_standstill = False + self.standstill_start = 0 + self.sng_acc_resume = False + self.sng_acc_resume_cnt = -1 + self.manual_hold = False + self.prev_cruise_state = 0 + self.p = CarControllerParams(CP) self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) @@ -27,6 +48,9 @@ class CarController: hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel + if self.frame % 250 == 0 and self.subaru_sng: + self.manual_parking_brake = self.param_s.get_bool("SubaruManualParkingBrakeSng") + can_sends = [] # *** steering *** @@ -56,6 +80,9 @@ class CarController: self.apply_steer_last = apply_steer + # *** stop and go *** + throttle_cmd, speed_cmd = self.stop_and_go(CC, CS) + # *** longitudinal *** if CC.longActive: @@ -92,6 +119,9 @@ class CarController: can_sends.append(subarucan.create_preglobal_es_distance(self.packer, cruise_button, CS.es_distance_msg)) + if self.subaru_sng: + can_sends.append(subarucan.create_preglobal_throttle(self.packer, CS.throttle_msg, throttle_cmd)) + else: if self.frame % 10 == 0: can_sends.append(subarucan.create_es_dashstatus(self.packer, self.frame // 10, CS.es_dashstatus_msg, CC.enabled, self.CP.openpilotLongitudinalControl, @@ -104,6 +134,12 @@ class CarController: if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT: can_sends.append(subarucan.create_es_infotainment(self.packer, self.frame // 10, CS.es_infotainment_msg, hud_control.visualAlert)) + if self.subaru_sng: + can_sends.append(subarucan.create_throttle(self.packer, CS.throttle_msg, throttle_cmd)) + + if self.frame % 2 == 0: + can_sends.append(subarucan.create_brake_pedal(self.packer, CS.brake_pedal_msg, speed_cmd, pcm_cancel_cmd)) + if self.CP.openpilotLongitudinalControl: if self.frame % 5 == 0: can_sends.append(subarucan.create_es_status(self.packer, self.frame // 5, CS.es_status_msg, @@ -125,3 +161,58 @@ class CarController: self.frame += 1 return new_actuators, can_sends + + # Stop and Go auto-resume thanks to martinl from subaru-community + def stop_and_go(self, CC: car.CarControl, CS: car.CarState, throttle_cmd: bool = False, speed_cmd: bool = False) -> Tuple[bool, bool]: + if not self.subaru_sng: + return throttle_cmd, speed_cmd + if self.CP.carFingerprint in PREGLOBAL_CARS: + # Initiate the ACC resume sequence if conditions are met + if (CC.enabled # ACC active + and CS.car_follow == 1 # lead car + and CS.out.standstill # must be standing still + and CS.close_distance > _SNG_ACC_MIN_DIST # acc resume trigger low threshold + and CS.close_distance < _SNG_ACC_MAX_DIST # acc resume trigger high threshold + and CS.close_distance > self.prev_close_distance): # distance with lead car is increasing + self.sng_acc_resume = True + elif self.CP.carFingerprint not in (GLOBAL_GEN2 | HYBRID_CARS): + if self.manual_parking_brake: + # Send brake message with non-zero speed in standstill to avoid non-EPB ACC disengage + if (CC.enabled # ACC active + and CS.car_follow == 1 # lead car + and CS.out.standstill + and self.frame > self.standstill_start + 50): # standstill for >0.5 second + speed_cmd = True + else: + # Record manual hold set while in standstill and no car in front + if CS.out.standstill and self.prev_cruise_state == 1 and CS.cruise_state == 3 and CS.car_follow == 0: + self.manual_hold = True + # Cancel manual hold when car starts moving + if not CS.out.standstill: + self.manual_hold = False + # Initiate the ACC resume sequence if conditions are met + if (CC.enabled # ACC active + and not self.manual_hold + and CS.car_follow == 1 # lead car + and CS.cruise_state == 3 # ACC HOLD (only with EPB) + and CS.close_distance > _SNG_ACC_MIN_DIST # acc resume trigger low threshold + and CS.close_distance < _SNG_ACC_MAX_DIST # acc resume trigger high threshold + and CS.close_distance > self.prev_close_distance): # distance with lead car is increasing + self.sng_acc_resume = True + + if CS.out.standstill and not self.prev_standstill: + self.standstill_start = self.frame + self.prev_standstill = CS.out.standstill + self.prev_cruise_state = CS.cruise_state + + if self.sng_acc_resume: + if self.sng_acc_resume_cnt < 5: + throttle_cmd = True + self.sng_acc_resume_cnt += 1 + else: + self.sng_acc_resume = False + self.sng_acc_resume_cnt = -1 + + self.prev_close_distance = CS.close_distance + + return throttle_cmd, speed_cmd diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index ce352e9da6..aa4e8acc8f 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser -from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, CanBus, SubaruFlags +from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, CanBus, SubaruFlags, SubaruFlagsSP from openpilot.selfdrive.car import CanSignalRateCalculator @@ -123,8 +123,16 @@ class CarState(CarStateBase): self.es_status_msg = copy.copy(cp_es_status.vl["ES_Status"]) self.cruise_control_msg = copy.copy(cp_cruise.vl["CruiseControl"]) + if self.CP.spFlags & SubaruFlagsSP.SP_SUBARU_SNG: + self.cruise_state = cp_cam.vl["ES_DashStatus"]["Cruise_State"] + self.brake_pedal_msg = copy.copy(cp.vl["Brake_Pedal"]) + if self.car_fingerprint not in HYBRID_CARS: self.es_distance_msg = copy.copy(cp_es_distance.vl["ES_Distance"]) + if self.CP.spFlags & SubaruFlagsSP.SP_SUBARU_SNG: + self.throttle_msg = copy.copy(cp.vl["Throttle"]) + self.car_follow = cp_es_distance.vl["ES_Distance"]["Car_Follow"] + self.close_distance = cp_es_distance.vl["ES_Distance"]["Close_Distance"] self.es_dashstatus_msg = copy.copy(cp_cam.vl["ES_DashStatus"]) if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT: diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index bc157589ff..0780ee4351 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from openpilot.selfdrive.car import get_safety_config, create_mads_event from openpilot.selfdrive.car.interfaces import CarInterfaceBase -from openpilot.selfdrive.car.subaru.values import CAR, LKAS_ANGLE, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, SubaruFlags +from openpilot.selfdrive.car.subaru.values import CAR, LKAS_ANGLE, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, SubaruFlags, SubaruFlagsSP ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -35,6 +35,11 @@ class CarInterface(CarInterfaceBase): if candidate in GLOBAL_GEN2: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_GEN2 + if candidate not in (GLOBAL_GEN2 | HYBRID_CARS): + ret.autoResumeSng = True + ret.spFlags |= SubaruFlagsSP.SP_SUBARU_SNG.value + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_SNG + ret.steerLimitTimer = 0.4 ret.steerActuatorDelay = 0.1 diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index f73c23420b..411b034323 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -291,3 +291,67 @@ def create_preglobal_es_distance(packer, cruise_button, es_distance_msg): values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_Distance") return packer.make_can_msg("ES_Distance", CanBus.main, values) + + +def create_brake_pedal(packer, brake_pedal_msg, speed_cmd, brake_cmd): + values = {s: brake_pedal_msg[s] for s in [ + "COUNTER", + "Signal1", + "Speed", + "Signal2", + "Brake_Lights", + "Signal3", + "Brake_Pedal", + "Signal4", + ]} + + if speed_cmd: + values["Speed"] = 3 + if brake_cmd: + values["Brake_Pedal"] = 5 + values["Brake_Lights"] = 1 + + return packer.make_can_msg("Brake_Pedal", CanBus.camera, values) + + +def create_throttle(packer, throttle_msg, throttle_cmd): + values = {s: throttle_msg[s] for s in [ + "CHECKSUM", + "COUNTER", + "Signal1", + "Engine_RPM", + "Signal2", + "Throttle_Pedal", + "Throttle_Cruise", + "Throttle_Combo", + "Signal3", + "Off_Accel", + ]} + + if throttle_cmd: + values["Throttle_Pedal"] = 5 + + return packer.make_can_msg("Throttle", 2, values) + + +def create_preglobal_throttle(packer, throttle_msg, throttle_cmd): + values = {s: throttle_msg[s] for s in [ + "Throttle_Pedal", + "COUNTER", + "Signal1", + "Not_Full_Throttle", + "Signal2", + "Engine_RPM", + "Off_Throttle", + "Signal3", + "Throttle_Cruise", + "Throttle_Combo", + "Throttle_Body", + "Off_Throttle_2", + "Signal4", + ]} + + if throttle_cmd: + values["Throttle_Pedal"] = 5 + + return packer.make_can_msg("Throttle", 2, values) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 5a820fd46a..e5554904e7 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -60,6 +60,10 @@ class SubaruFlags(IntFlag): SEND_INFOTAINMENT = 1 +class SubaruFlagsSP(IntFlag): + SP_SUBARU_SNG = 1 + + class CanBus: main = 0 alt = 1 diff --git a/selfdrive/car/sunnypilot_carname.json b/selfdrive/car/sunnypilot_carname.json index e22c2a13cf..de48bc420d 100644 --- a/selfdrive/car/sunnypilot_carname.json +++ b/selfdrive/car/sunnypilot_carname.json @@ -65,6 +65,7 @@ "Honda Passport 2019-23": "HONDA PILOT 2017", "Honda Pilot 2016-22": "HONDA PILOT 2017", "Honda Ridgeline 2017-23": "HONDA RIDGELINE 2017", + "Hyundai Azera 2022": "HYUNDAI AZERA 6TH GEN", "Hyundai Elantra 2017-19": "HYUNDAI ELANTRA 2017", "Hyundai Elantra 2021-23": "HYUNDAI ELANTRA 2021", "Hyundai Elantra GT 2017-19": "HYUNDAI ELANTRA 2017", @@ -84,7 +85,7 @@ "Hyundai Ioniq Plug-in Hybrid 2020-22": "HYUNDAI IONIQ PHEV 2020", "Hyundai Kona 2020": "HYUNDAI KONA 2020", "Hyundai Kona Electric 2018-21": "HYUNDAI KONA ELECTRIC 2019", - "Hyundai Kona Electric 2022": "HYUNDAI KONA ELECTRIC 2022", + "Hyundai Kona Electric 2022-23": "HYUNDAI KONA ELECTRIC 2022", "Hyundai Kona Electric (with HDA II, Korea only) 2023": "HYUNDAI KONA ELECTRIC 2ND GEN", "Hyundai Kona Hybrid 2020": "HYUNDAI KONA HYBRID 2020", "Hyundai Palisade 2020-22": "HYUNDAI PALISADE 2020", @@ -104,7 +105,7 @@ "Hyundai Veloster 2019-20": "HYUNDAI VELOSTER 2019", "Jeep Grand Cherokee 2016-18": "JEEP GRAND CHEROKEE V6 2018", "Jeep Grand Cherokee 2019-21": "JEEP GRAND CHEROKEE 2019", - "Kia Carnival 2023": "KIA CARNIVAL 4TH GEN", + "Kia Carnival 2023-24": "KIA CARNIVAL 4TH GEN", "Kia Carnival (China only) 2023": "KIA CARNIVAL 4TH GEN", "Kia Ceed 2019": "KIA CEED INTRO ED 2019", "Kia EV6 (Southeast Asia only) 2022-23": "KIA EV6 2022", @@ -116,6 +117,7 @@ "Kia Forte Non-SCC 2021": "KIA FORTE LXS 2021 NON-SCC", "Kia K5 2021-22": "KIA K5 2021", "Kia K5 Hybrid 2020": "KIA K5 HYBRID 2020", + "Kia K8 Hybrid (with HDA II) 2023": "KIA K8 HYBRID 1ST GEN", "Kia Niro EV 2019": "KIA NIRO EV 2020", "Kia Niro EV 2020": "KIA NIRO EV 2020", "Kia Niro EV 2021": "KIA NIRO EV 2020", @@ -128,6 +130,7 @@ "Kia Optima 2017": "KIA OPTIMA 4TH GEN", "Kia Optima 2019-20": "KIA OPTIMA 4TH GEN FACELIFT", "Kia Seltos 2021": "KIA SELTOS 2021", + "Kia Seltos Non-SCC 2023-24": "KIA SELTOS 2023 NON-SCC", "Kia Sorento 2018": "KIA SORENTO GT LINE 2018", "Kia Sorento 2019": "KIA SORENTO GT LINE 2018", "Kia Sorento 2021-23": "KIA SORENTO 4TH GEN", diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index e2ef4627e4..38fd35feb0 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -27,6 +27,7 @@ KIA FORTE 2019 NON-SCC: HYUNDAI SONATA 2020 KIA FORTE LXS 2021 NON-SCC: HYUNDAI SONATA 2020 KIA CEED INTRO ED 2019: HYUNDAI SONATA 2020 KIA SELTOS 2021: HYUNDAI SONATA 2020 +KIA SELTOS 2023 NON-SCC: HYUNDAI SONATA 2020 KIA NIRO HYBRID 2019: KIA NIRO EV 2020 KIA NIRO HYBRID 2021: KIA NIRO EV 2020 HYUNDAI VELOSTER 2019: HYUNDAI SONATA 2019 diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 8ce4270be6..1dc7e3926a 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -44,6 +44,7 @@ class CarController: self.param_s = Params() self._reverse_acc_change = self.param_s.get_bool("ReverseAccChange") + self._sng_hack = self.param_s.get_bool("ToyotaSnG") def update(self, CC, CS, now_nanos): actuators = CC.actuators @@ -119,7 +120,8 @@ class CarController: pcm_cancel_cmd = 1 # on entering standstill, send standstill request - if CS.out.standstill and not self.last_standstill and (self.CP.carFingerprint not in NO_STOP_TIMER_CAR or self.CP.enableGasInterceptor): + if CS.out.standstill and not self.last_standstill and (self.CP.carFingerprint not in NO_STOP_TIMER_CAR or self.CP.enableGasInterceptor) and \ + not self._sng_hack: self.standstill_req = True if CS.pcm_acc_status != 8: # pcm entered standstill or it's disabled diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index c012ff0065..88c8123229 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -8,7 +8,7 @@ from openpilot.common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from openpilot.selfdrive.car.interfaces import CarStateBase -from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ +from openpilot.selfdrive.car.toyota.values import ToyotaFlags, ToyotaFlagsSP, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR SteerControlType = car.CarParams.SteerControlType @@ -61,6 +61,11 @@ class CarState(CarStateBase): self.gac_send_counter = 0 self.follow_distance = 0 + if CP.spFlags & ToyotaFlagsSP.SP_ZSS: + self.zss_compute = False + self.zss_cruise_active_last = False + self.zss_angle_offset = 0. + def update(self, cp, cp_cam): ret = car.CarState.new_message() @@ -128,6 +133,21 @@ class CarState(CarStateBase): ret.steeringAngleOffsetDeg = self.angle_offset.x ret.steeringAngleDeg = torque_sensor_angle_deg - self.angle_offset.x + # ZSS support thanks to dragonpilot and ErichMoraga + if self.CP.spFlags & ToyotaFlagsSP.SP_ZSS: + zorro_steer = cp.vl["SECONDARY_STEER_ANGLE"]["ZORRO_STEER"] + # Only compute ZSS offset when acc is active + if bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) and not self.zss_cruise_active_last: + self.zss_compute = True # Cruise was just activated, so allow offset to be recomputed + self.zss_cruise_active_last = bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) + + # Compute ZSS offset + if self.zss_compute: + if abs(ret.steeringAngleDeg) > 1e-3 and abs(zorro_steer) > 1e-3: + self.zss_angle_offset = zorro_steer - ret.steeringAngleDeg + # Apply offset + ret.steeringAngleDeg = zorro_steer - self.zss_angle_offset + ret.steeringRateDeg = cp.vl["STEER_ANGLE_SENSOR"]["STEER_RATE"] can_gear = int(cp.vl["GEAR_PACKET"]["GEAR"]) @@ -343,6 +363,9 @@ class CarState(CarStateBase): if CP.flags & ToyotaFlags.SMART_DSU: messages.append(("SDSU", 33)) + if CP.spFlags & ToyotaFlagsSP.SP_ZSS: + messages.apend(("SECONDARY_STEER_ANGLE", 0)) + return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0) @staticmethod diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 20ae720c1c..c6bf4c8bd1 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -4,7 +4,7 @@ from openpilot.common.numpy_fast import clip from openpilot.common.params import Params, put_nonblocking from panda import Panda from panda.python import uds -from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ +from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, ToyotaFlagsSP, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR from openpilot.selfdrive.car import create_button_events, get_safety_config, create_mads_event from openpilot.selfdrive.car.disable_ecu import disable_ecu @@ -51,21 +51,25 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.25 ret.steerLimitTimer = 0.8 + if 0x23 in fingerprint[0]: # Detect if ZSS is present + ret.spFlags |= ToyotaFlagsSP.SP_ZSS.value + ret.stoppingControl = False # Toyota starts braking more when it thinks you want to stop stop_and_go = candidate in TSS2_CAR if candidate == CAR.PRIUS: + zss = ret.spFlags & ToyotaFlagsSP.SP_ZSS stop_and_go = True ret.wheelbase = 2.70 - ret.steerRatio = 15.74 # unknown end-to-end spec + ret.steerRatio = 15.0 if zss else 15.74 # unknown end-to-end spec ret.tireStiffnessFactor = 0.6371 # hand-tune - ret.mass = 3045. * CV.LB_TO_KG + ret.mass = (3370. if zss else 3045.) * CV.LB_TO_KG # Only give steer angle deadzone to for bad angle sensor prius for fw in car_fw: if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00': ret.steerActuatorDelay = 0.25 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.2) + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.0 if zss else 0.2) elif candidate == CAR.PRIUS_V: stop_and_go = True @@ -324,7 +328,9 @@ class CarInterface(CarInterfaceBase): self.CS.madsEnabled = self.get_acc_mads(ret.cruiseState.enabled, self.CS.accEnabled, self.CS.madsEnabled) if not self.CP.openpilotLongitudinalControl: self.CS.gac_tr_cluster = 3 - put_nonblocking("LongitudinalPersonality", 2) + if self.CS.gac_tr != 2: + self.CS.gac_tr = 2 + put_nonblocking("LongitudinalPersonality", "2") else: gap_dist_button = bool(self.CS.gap_dist_button) if gap_dist_button: diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index fd0a54b349..07def65d37 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -46,6 +46,10 @@ class ToyotaFlags(IntFlag): DISABLE_RADAR = 4 +class ToyotaFlagsSP(IntFlag): + SP_ZSS = 1 + + class CAR: # Toyota ALPHARD_TSS2 = "TOYOTA ALPHARD 2020" diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 8789e930e0..8976ae468f 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -205,7 +205,7 @@ class Controls: self.reverse_acc_change = False self.live_torque = self.params.get_bool("LiveTorque") - self.custom_torque = self.params.get_bool("CustomTorqueLateral") + self.torqued_override = self.params.get_bool("TorquedOverride") self.process_not_running = False @@ -635,7 +635,7 @@ class Controls: # Update Torque Params if self.CP.lateralTuning.which() == 'torque': torque_params = self.sm['liveTorqueParameters'] - if self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.live_torque) and not self.custom_torque: + if self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.live_torque) and not self.torqued_override: self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered, torque_params.frictionCoefficientFiltered) @@ -918,6 +918,9 @@ class Controls: self.lane_change_set_timer = int(self.params.get("AutoLaneChangeTimer", encoding="utf8")) self.reverse_acc_change = self.params.get_bool("ReverseAccChange") + if self.sm.frame % int(2.5 / DT_CTRL) == 0: + self.live_torque = self.params.get_bool("LiveTorque") + # Sample data from sockets and get a carState CS = self.data_sample() cloudlog.timestamp("Data sampled") diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py index 5227757f0e..b32ccbd237 100644 --- a/selfdrive/controls/lib/lane_planner.py +++ b/selfdrive/controls/lib/lane_planner.py @@ -1,9 +1,10 @@ import numpy as np from cereal import log -from common.filter_simple import FirstOrderFilter -from common.numpy_fast import interp -from common.realtime import DT_MDL -from system.swaglog import cloudlog +from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.common.numpy_fast import interp +from openpilot.common.params import Params +from openpilot.common.realtime import DT_MDL +from openpilot.system.swaglog import cloudlog TRAJECTORY_SIZE = 33 @@ -33,10 +34,29 @@ class LanePlanner: self.l_lane_change_prob = 0. self.r_lane_change_prob = 0. - self.camera_offset = -CAMERA_OFFSET - self.path_offset = -PATH_OFFSET + self.camera_offset = CAMERA_OFFSET + self.path_offset = PATH_OFFSET + + self.param_s = Params() + self.custom_offsets = self.param_s.get_bool("CustomOffsets") + self._frame = 0 + + def update_custom_offsets(self): + self._frame += 1 + if self._frame % 50 == 0: + self.custom_offsets = self.param_s.get_bool("CustomOffsets") + if not self.custom_offsets: + self._frame = 0 + self.camera_offset = CAMERA_OFFSET + self.path_offset = PATH_OFFSET + return + + self.camera_offset = float(self.param_s.get("CameraOffset", encoding="utf8")) * 0.01 + self.path_offset = float(self.param_s.get("PathOffset", encoding="utf8")) * 0.01 + self._frame = 0 def parse_model(self, md): + self.update_custom_offsets() lane_lines = md.laneLines if len(lane_lines) == 4 and len(lane_lines[0].t) == TRAJECTORY_SIZE: self.ll_t = (np.array(lane_lines[1].t) + np.array(lane_lines[2].t))/2 diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 914fea81f4..bde6989dcb 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -33,7 +33,7 @@ class LatControlTorque(LatControl): self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg self.param_s = Params() - self.custom_torque = self.param_s.get_bool("CustomTorqueLateral") + self.torqued_override = self.param_s.get_bool("TorquedOverride") self._frame = 0 def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction): @@ -42,13 +42,15 @@ class LatControlTorque(LatControl): self.torque_params.friction = friction def update_live_tune(self): - if not self.custom_torque: - return self._frame += 1 - if self._frame % 300 == 0: + if self._frame % 250 == 0: + self._frame = 0 + self.torqued_override = self.param_s.get_bool("TorquedOverride") + if not self.torqued_override: + return + self.torque_params.latAccelFactor = float(self.param_s.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01 self.torque_params.friction = float(self.param_s.get("TorqueFriction", encoding="utf8")) * 0.01 - self._frame = 0 def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): self.update_live_tune() diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 7a0f232aa7..e4aa6e328d 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -115,12 +115,11 @@ class LateralPlanner: low_speed = v_ego_car < 10 * CV.MPH_TO_MS if not self.get_dynamic_lane_profile(sm['longitudinalPlan']) and not low_speed: - d_path_xyz = self.LP.get_d_path(self.v_ego, self.t_idxs, self.path_xyz) + self.path_xyz = self.LP.get_d_path(self.v_ego, self.t_idxs, self.path_xyz) self.dynamic_lane_profile_status = False else: - d_path_xyz = self.path_xyz + self.path_xyz[:, 1] += self.LP.path_offset self.dynamic_lane_profile_status = True - self.path_xyz = d_path_xyz self.lat_mpc.set_weights(PATH_COST, LATERAL_MOTION_COST, LATERAL_ACCEL_COST, LATERAL_JERK_COST, diff --git a/selfdrive/gpxd/gpx_uploader.py b/selfdrive/gpxd/gpx_uploader.py index bb78c65d0b..d02889d512 100644 --- a/selfdrive/gpxd/gpx_uploader.py +++ b/selfdrive/gpxd/gpx_uploader.py @@ -24,8 +24,9 @@ import os import time from common.params import Params -from common.realtime import Ratekeeper +from common.realtime import set_core_affinity, Ratekeeper from selfdrive.athena.registration import register +from system.swaglog import cloudlog from system.version import get_version # for uploader @@ -139,10 +140,18 @@ class GpxUploader(): print(f'Upload error: {e}') return False + def gpx_uploader_thread(self): + try: + set_core_affinity([0, 1, 2, 3]) + except Exception: + cloudlog.exception("gpx_uploader: failed to set core affinity") + + self.update() + def main(): gpx_uploader = GpxUploader() - gpx_uploader.update() + gpx_uploader.gpx_uploader_thread() if __name__ == "__main__": diff --git a/selfdrive/gpxd/gpxd.py b/selfdrive/gpxd/gpxd.py index 4c463c485a..0b69b4b65f 100644 --- a/selfdrive/gpxd/gpxd.py +++ b/selfdrive/gpxd/gpxd.py @@ -27,7 +27,7 @@ import datetime import signal import subprocess import threading -from common.realtime import Ratekeeper +from common.realtime import set_core_affinity, Ratekeeper from cereal import log from system.swaglog import cloudlog @@ -164,6 +164,10 @@ class GpxD: return gpx_str def gpxd_thread(self): + try: + set_core_affinity([0, 1, 2, 3]) + except Exception: + cloudlog.exception("gpxd: failed to set core affinity") while True: self.sm.update(0) self.log() diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index ddb95e944c..b1eed3f9c6 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -120,6 +120,16 @@ class TorqueEstimator: self.offline_friction = CP.lateralTuning.torque.friction self.offline_latAccelFactor = CP.lateralTuning.torque.latAccelFactor + params = Params() + if params.get_bool("EnforceTorqueLateral"): + if params.get_bool("CustomTorqueLateral"): + self.offline_friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.01 + self.offline_latAccelFactor = float(params.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01 + if params.get_bool("LiveTorqueRelaxed"): + self.min_bucket_points = np.array([0, 200, 300, 500, 500, 300, 200, 0]) / (10 if decimated else 1) + self.factor_sanity = FACTOR_SANITY_QLOG if decimated else 1.0 + self.friction_sanity = FRICTION_SANITY_QLOG if decimated else 1.0 + self.reset() initial_params = { @@ -135,7 +145,6 @@ class TorqueEstimator: self.max_friction = (1.0 + self.friction_sanity) * self.offline_friction # try to restore cached params - params = Params() params_cache = params.get("LiveTorqueCarParams") torque_cache = params.get("LiveTorqueParameters") if params_cache is not None and torque_cache is not None: diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 8f6f29d07a..111017e822 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -58,7 +58,7 @@ def manager_init() -> None: ("CustomTorqueLateral", "0"), ("CameraControl", "2"), ("CameraControlToggle", "0"), - ("CameraOffset", "0"), + ("CameraOffset", "4"), ("CarModel", ""), ("CarModelText", ""), ("ChevronInfo", "1"), @@ -286,9 +286,6 @@ def main() -> None: cloudlog.warning("shutdown") HARDWARE.shutdown() - if params.get_bool("HotspotOnBoot"): - os.system('nmcli con up Hotspot') - if __name__ == "__main__": unblock_stdout() diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index bcc5ff4faf..fd1ba29868 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -85,7 +85,7 @@ procs = [ NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None), always_watchdog=True), PythonProcess("gpxd", "selfdrive.gpxd.gpxd", only_onroad), - PythonProcess("gpxd_uploader", "selfdrive.gpxd.gpx_uploader", always_run), + PythonProcess("gpxd_uploader", "selfdrive.gpxd.gpx_uploader", only_offroad), PythonProcess("mapd", "selfdrive.mapd.mapd", only_onroad), PythonProcess("otisserv", "selfdrive.navd.otisserv", always_run), PythonProcess("fleet_manager", "system.fleetmanager.fleet_manager", only_offroad), diff --git a/selfdrive/mapd/mapd.py b/selfdrive/mapd/mapd.py index db40c16abb..42bcae50cd 100644 --- a/selfdrive/mapd/mapd.py +++ b/selfdrive/mapd/mapd.py @@ -7,7 +7,7 @@ from time import strftime, gmtime from cereal import log import cereal.messaging as messaging from common.params import Params -from common.realtime import Ratekeeper +from common.realtime import set_core_affinity, Ratekeeper from selfdrive.mapd.lib.osm import OSM from selfdrive.mapd.lib.geo import distance_to_points from selfdrive.mapd.lib.WayCollection import WayCollection @@ -260,6 +260,10 @@ class MapD(): # provides live map data information def mapd_thread(sm=None, pm=None): + try: + set_core_affinity([0, 1, 2, 3]) + except Exception: + cloudlog.exception("mapd: failed to set core affinity") mapd = MapD() rk = Ratekeeper(1., print_delay_threshold=None) # Keeps rate at 1 hz diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index fb9f0a3ee0..6318336699 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -48,8 +48,8 @@ class RouteEngine: self.reroute_counter = 0 - if self.params.get_bool("CustomMapbox") or "MAPBOX_TOKEN" in os.environ: - self.mapbox_token = self.params.get("CustomMapboxTokenSk") if self.params.get_bool("CustomMapbox") else os.environ["MAPBOX_TOKEN"] + if "MAPBOX_TOKEN" in os.environ: + self.mapbox_token = os.environ["MAPBOX_TOKEN"] self.mapbox_host = "https://api.mapbox.com" else: try: @@ -59,6 +59,10 @@ class RouteEngine: self.mapbox_token = "" self.mapbox_host = "https://maps.comma.ai" + if self.mapbox_token != "" and self.params.get("CustomMapboxTokenSk") is not None: + self.mapbox_token = self.params.get("CustomMapboxTokenSk") + self.mapbox_host = "https://api.mapbox.com" + def update(self): self.sm.update(0) diff --git a/selfdrive/navd/otisserv.py b/selfdrive/navd/otisserv.py index 1dbf2a5335..33e51b86e1 100644 --- a/selfdrive/navd/otisserv.py +++ b/selfdrive/navd/otisserv.py @@ -29,6 +29,8 @@ import requests import math from common.basedir import BASEDIR from common.params import Params +from common.realtime import set_core_affinity +from system.swaglog import cloudlog params = Params() hostName = "" @@ -407,6 +409,10 @@ class OtisServ(BaseHTTPRequestHandler): params.put("ApiCache_NavDestinations", json.dumps(dests).rstrip("\n\r")) def main(): + try: + set_core_affinity([0, 1, 2, 3]) + except Exception: + cloudlog.exception("otisserv: failed to set core affinity") webServer = HTTPServer((hostName, serverPort), OtisServ) try: diff --git a/selfdrive/sentry.py b/selfdrive/sentry.py index 12275983eb..2852afa455 100644 --- a/selfdrive/sentry.py +++ b/selfdrive/sentry.py @@ -12,7 +12,6 @@ from openpilot.system.version import get_branch, get_commit, get_origin, get_ver import os import traceback -from cereal import car from datetime import datetime @@ -24,27 +23,7 @@ class SentryProject(Enum): CRASHES_DIR = '/data/community/crashes/' -ret = car.CarParams.new_message() -candidate = ret.carFingerprint -params = Params() -#uniqueID = op_params.get('uniqueID') -try: - dongle_id = params.get("DongleId").decode('utf8') -except AttributeError: - dongle_id = "None" -try: - gitname = params.get("GithubUsername", encoding='utf-8') -except Exception: - gitname = "" -error_tags = { - 'dirty': is_dirty(), - 'dongle_id': dongle_id, - 'branch': get_branch(), - 'remote': get_origin(), - 'fingerprintedAs': candidate, - 'gitname': gitname -} -ip = "{{auto}}" +IP_ADDRESS = "{{auto}}" def report_tombstone(fn: str, message: str, contents: str) -> None: @@ -60,7 +39,6 @@ def report_tombstone(fn: str, message: str, contents: str) -> None: def capture_exception(*args, **kwargs) -> None: save_exception(traceback.format_exc()) cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) - bind_user(id=dongle_id, ip_address=ip, username=gitname) try: sentry_sdk.capture_exception(*args, **kwargs) @@ -85,26 +63,18 @@ def save_exception(exc_text): print('Logged current crash to {}'.format(files)) -def bind_user(**kwargs) -> None: - sentry_sdk.set_user(kwargs) - sentry_sdk.flush() - - def capture_warning(warning_string): - bind_user(id=dongle_id, ip_address=ip, name=gitname) sentry_sdk.capture_message(warning_string, level='warning') sentry_sdk.flush() def capture_info(info_string): - bind_user(id=dongle_id, ip_address=ip, name=gitname) sentry_sdk.capture_message(info_string, level='info') sentry_sdk.flush() def set_tag(key: str, value: str) -> None: sentry_sdk.set_tag(key, value) - sentry_sdk.flush() def init(project: SentryProject) -> None: @@ -116,7 +86,6 @@ def init(project: SentryProject) -> None: #env = "release" if is_tested_branch() else "master" env = get_branch_type() dongle_id = Params().get("DongleId", encoding='utf-8') - ip = "{{auto}}" gitname = Params().get("GithubUsername", encoding='utf-8') integrations = [] @@ -134,7 +103,7 @@ def init(project: SentryProject) -> None: send_default_pii=True) sentry_sdk.set_user({"id": dongle_id}) - sentry_sdk.set_user({"ip_address": ip}) + sentry_sdk.set_user({"ip_address": IP_ADDRESS}) sentry_sdk.set_user({"username": gitname}) sentry_sdk.set_tag("dirty", is_dirty()) sentry_sdk.set_tag("origin", get_origin()) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 32cfe11c39..256db7d061 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -156,6 +156,8 @@ def hw_state_thread(end_event, hw_queue): cloudlog.warning("configuring modem") HARDWARE.configure_modem() modem_configured = True + if Params().get_bool("HotspotOnBoot") and Params().get_bool("HotspotOnBootConfirmed"): + os.system('nmcli con up Hotspot') prev_hw_state = hw_state except Exception: diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 26fde649e7..fcb7626430 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -172,15 +172,15 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { #else left_widget->addWidget(new DriveStats); #endif - custom_mapbox = params.getBool("CustomMapbox") && QString::fromStdString(params.get("CustomMapboxTokenSk")) != ""; + custom_mapbox = QString::fromStdString(params.get("CustomMapboxTokenSk")) != ""; if (!custom_mapbox) { left_widget->addWidget(new PrimeAdWidget); } left_widget->setStyleSheet("border-radius: 10px;"); - left_widget->setCurrentIndex(!custom_mapbox ? uiState()->hasPrime() ? 0 : 1 : 0); - connect(uiState(), &UIState::primeChanged, [=](int prime) { - left_widget->setCurrentIndex(!custom_mapbox ? prime ? 0 : 1 : 0); + left_widget->setCurrentIndex((uiState()->hasPrime() || custom_mapbox) ? 0 : 1); + connect(uiState(), &UIState::primeChanged, [=](bool prime) { + left_widget->setCurrentIndex((prime || custom_mapbox) ? 0 : 1); }); home_layout->addWidget(left_widget, 1); diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index db56fcdcfc..ab776ccd8b 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -112,6 +112,49 @@ void MapWindow::initLayers() { // TODO: remove, symbol-sort-key does not seem to matter outside of each layer m_map->setLayoutProperty("carPosLayer", "symbol-sort-key", 0); } + if ((!m_map->layerExists("buildingsLayer")) && uiState()->scene.map_3d_buildings) { // Could put this behind the cellular metered toggle in case it increases data usage + qDebug() << "Initializing buildingsLayer"; + QVariantMap buildings; + buildings["id"] = "buildingsLayer"; + buildings["source"] = "composite"; + buildings["source-layer"] = "building"; + buildings["type"] = "fill-extrusion"; + buildings["minzoom"] = 15; + m_map->addLayer(buildings); + m_map->setFilter("buildingsLayer", QVariantList({"==", "extrude", "true"})); + + QVariantList fillExtrusionHeight = { // scale buildings as you zoom in + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "height"} + }; + + QVariantList fillExtrusionBase = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "min_height"} + }; + + QVariantList fillExtrusionOpacity = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, // transparent at zoom level 15 + 15.5, .6, // fade in + 17, .6, // begin fading out + 20, 0 // fade out when zoomed in + }; + + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-color", QColor("grey")); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-opacity", fillExtrusionOpacity); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-height", fillExtrusionHeight); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-base", fillExtrusionBase); + m_map->setLayoutProperty("buildingsLayer", "visibility", "visible"); + } } void MapWindow::updateState(const UIState &s) { diff --git a/selfdrive/ui/qt/maps/map_helpers.h b/selfdrive/ui/qt/maps/map_helpers.h index d0dd65e7a6..b72c301f4f 100644 --- a/selfdrive/ui/qt/maps/map_helpers.h +++ b/selfdrive/ui/qt/maps/map_helpers.h @@ -13,7 +13,7 @@ #include "cereal/messaging/messaging.h" #include "common/params.h" -const QString MAPBOX_TOKEN = Params().getBool("CustomMapbox") ? QString::fromStdString(Params().get("CustomMapboxTokenSk")) : util::getenv("MAPBOX_TOKEN").c_str(); +const QString MAPBOX_TOKEN = QString::fromStdString(Params().get("CustomMapboxTokenSk")) != "" ? QString::fromStdString(Params().get("CustomMapboxTokenSk")) : util::getenv("MAPBOX_TOKEN").c_str(); const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str(); const QString MAPS_CACHE_PATH = "/data/mbgl-cache-navd.db"; diff --git a/selfdrive/ui/qt/network/networking.cc b/selfdrive/ui/qt/network/networking.cc index e7865b11a7..57c9973add 100644 --- a/selfdrive/ui/qt/network/networking.cc +++ b/selfdrive/ui/qt/network/networking.cc @@ -125,7 +125,8 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid ListWidget *list = new ListWidget(this); // Enable tethering layout - tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled()); + const bool set_hotspot_on_boot = params.getBool("HotspotOnBoot") && params.getBool("HotspotOnBootConfirmed"); + tetheringToggle = new ToggleControl(tr("Enable Tethering"), "", "", wifi->isTetheringEnabled() || set_hotspot_on_boot); list->addItem(tetheringToggle); QObject::connect(tetheringToggle, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering); @@ -201,7 +202,7 @@ void AdvancedNetworking::refresh() { } void AdvancedNetworking::toggleTethering(bool enabled) { - params.putBool("HotspotOnBoot", enabled); + params.putBool("HotspotOnBootConfirmed", enabled); wifi->setTetheringEnabled(enabled); tetheringToggle->setEnabled(false); } diff --git a/selfdrive/ui/qt/offroad/sunnypilot_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot_settings.cc index 6ce6c7fdf6..b12ae2474b 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot_settings.cc @@ -202,16 +202,28 @@ SPControlsPanel::SPControlsPanel(QWidget *parent) : ListWidget(parent) { "../assets/offroad/icon_calibration.png", }, { - "CustomTorqueLateral", - tr("Torque Lateral Control Live Tune"), - tr("Enables live tune for Torque lateral control."), - "../assets/offroad/icon_calibration.png", + "LiveTorque", + tr("Enable Self-Tune"), + tr("Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default."), + "../assets/offroad/icon_blank.png", }, { - "LiveTorque", - tr("Torque Lateral Controller Self-Tune"), - tr("Enables self-tune for Torque lateral control."), - "../assets/offroad/icon_calibration.png", + "LiveTorqueRelaxed", + tr("Less Restrict Settings for Self-Tune (Beta)"), + tr("Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values."), + "../assets/offroad/icon_blank.png", + }, + { + "CustomTorqueLateral", + tr("Enable Custom Tuning"), + tr("Enables custom tuning for Torque lateral control. Modifying FRICTION and LAT_ACCEL_FACTOR below will override the offline values indicated in the YAML files within \"selfdrive/torque_data\". The values will also be used live when \"Override Self-Tune\" toggle is enabled."), + "../assets/offroad/icon_blank.png", + }, + { + "TorquedOverride", + tr("Manual Real-Time Tuning"), + tr("Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values."), + "../assets/offroad/icon_blank.png", }, { "HandsOnWheelMonitoring", @@ -267,19 +279,15 @@ SPControlsPanel::SPControlsPanel(QWidget *parent) : ListWidget(parent) { // toggle names to trigger updateToggles() when toggleFlipped std::vector updateTogglesNames{ - "EnableMads", "CustomOffsets", "EnforceTorqueLateral", - "SpeedLimitPercOffset", "SpeedLimitControl" + "EnableMads", "CustomOffsets", "EnforceTorqueLateral", "SpeedLimitPercOffset", "SpeedLimitControl", + "CustomTorqueLateral", "LiveTorque", "TorquedOverride" }; connect(dynamic_lane_profile, &DynamicLaneProfile::updateExternalToggles, this, &SPControlsPanel::updateToggles); - // toggle names to trigger updateToggles() when toggleFlipped and display ConfirmationDialog::alert - std::vector updateTogglesNamesAlert{ - "CustomTorqueLateral", "LiveTorque" - }; - // toggle names to trigger updateToggles() when toggleFlipped and display ConfirmationDialog::alert + // toggle for offroadTransition when going onroad/offroad std::vector toggleOffroad{ "EnableMads", "DisengageLateralOnBrake", "AccMadsCombo", "MadsCruiseMain", "BelowSpeedPause", "EnforceTorqueLateral", - "CustomTorqueLateral", "LiveTorque" + "LiveTorqueRelaxed" }; // Controls: Camera Offset (cm) @@ -336,7 +344,7 @@ SPControlsPanel::SPControlsPanel(QWidget *parent) : ListWidget(parent) { addItem(auto_lane_change_timer); } - if (param == "CustomTorqueLateral") { + if (param == "TorquedOverride") { // Control: FRICTION addItem(friction); @@ -359,14 +367,6 @@ SPControlsPanel::SPControlsPanel(QWidget *parent) : ListWidget(parent) { }); } - // trigger updateToggles() and display ConfirmationDialog::alert when toggleFlipped - if (std::find(updateTogglesNamesAlert.begin(), updateTogglesNamesAlert.end(), param.toStdString()) != updateTogglesNamesAlert.end()) { - connect(toggle, &ToggleControl:: toggleFlipped, [=](bool state) { - updateToggles(); - ConfirmationDialog::alert(tr("You must restart your car or your device to apply these changes."), this); - }); - } - // trigger offroadTransition when going onroad/offroad if (std::find(toggleOffroad.begin(), toggleOffroad.end(), param.toStdString()) != toggleOffroad.end()) { connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { @@ -383,6 +383,27 @@ SPControlsPanel::SPControlsPanel(QWidget *parent) : ListWidget(parent) { params.remove("OsmLocalDb"); } }); + + // update "FRICTION" and "LAT_ACCEL_FACTOR" titles when going onroad/offroad + connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + friction->setEnabled(offroad); + lat_accel_factor->setEnabled(offroad); + + friction->refresh(); + lat_accel_factor->refresh(); + }); + + // update "FRICTION" and "LAT_ACCEL_FACTOR" titles when TorquedOverride is flipped + connect(toggles["TorquedOverride"], &ToggleControl::toggleFlipped, [=](bool state) { + friction->setEnabled(params.getBool("IsOffroad") || state); + lat_accel_factor->setEnabled(params.getBool("IsOffroad") || state); + + friction->setTitle(state ? "FRICTION - Live && Offline" : "FRICTION - Offline Only"); + lat_accel_factor->setTitle(state ? "LAT_ACCEL_FACTOR - Live && Offline" : "LAT_ACCEL_FACTOR - Offline Only"); + + friction->refresh(); + lat_accel_factor->refresh(); + }); } void SPControlsPanel::showEvent(QShowEvent *event) { @@ -394,7 +415,7 @@ void SPControlsPanel::updateToggles() { std::vector enableMadsGroup{"DisengageLateralOnBrake", "AccMadsCombo", "MadsCruiseMain"}; for (const auto& enableMadstoggle : enableMadsGroup) { if (toggles.find(enableMadstoggle) != toggles.end()) { - toggles[enableMadstoggle]->setVisible(params.getBool("EnableMads")); + toggles[enableMadstoggle]->setVisible(toggles["EnableMads"]->isToggled()); } } @@ -404,55 +425,44 @@ void SPControlsPanel::updateToggles() { // toggle names to update when CustomOffsets is flipped std::vector customOffsetsGroup{camera_offset, path_offset}; for (const auto& customOffsetsControl : customOffsetsGroup) { - customOffsetsControl->setVisible(params.getBool("CustomOffsets")); + customOffsetsControl->setVisible(toggles["CustomOffsets"]->isToggled()); } // toggle names to update when AutoLaneChangeTimer is not "Nudge" toggles["AutoLaneChangeBsmDelay"]->setVisible(QString::fromStdString(params.get("AutoLaneChangeTimer")) != "0"); + auto enforce_torque_lateral = toggles["EnforceTorqueLateral"]; auto custom_torque_lateral = toggles["CustomTorqueLateral"]; auto live_torque = toggles["LiveTorque"]; + auto live_torque_relaxed = toggles["LiveTorqueRelaxed"]; + auto torqued_override = toggles["TorquedOverride"]; + + auto speed_limit_control = toggles["SpeedLimitControl"]; + auto speed_limit_perc_offset = toggles["SpeedLimitPercOffset"]; // toggle names to update when EnforceTorqueLateral is flipped - std::vector enforceTorqueGroup{"CustomTorqueLateral", "LiveTorque"}; + std::vector enforceTorqueGroup{"CustomTorqueLateral", "LiveTorque", "TorquedOverride"}; for (const auto& enforceTorqueToggle : enforceTorqueGroup) { if (toggles.find(enforceTorqueToggle) != toggles.end()) { - toggles[enforceTorqueToggle]->setVisible(params.getBool("EnforceTorqueLateral")); + toggles[enforceTorqueToggle]->setVisible(enforce_torque_lateral->isToggled()); } } // toggle names to update when CustomTorqueLateral is flipped std::vector customTorqueGroup{friction, lat_accel_factor}; for (const auto& customTorqueControl : customTorqueGroup) { - customTorqueControl->setVisible(params.getBool("CustomTorqueLateral")); + customTorqueControl->setVisible(custom_torque_lateral->isToggled()); } // toggle names to update when SpeedLimitControl is flipped std::vector speedLimitControlGroup{slo_type, slvo}; for (const auto& speedLimitControl : speedLimitControlGroup) { - speedLimitControl->setVisible(params.getBool("SpeedLimitControl")); + speedLimitControl->setVisible(speed_limit_control->isToggled()); } - if (params.getBool("EnforceTorqueLateral")) { - if (params.getBool("CustomTorqueLateral")) { - live_torque->setEnabled(false); - params.putBool("LiveTorque", false); - } else { - live_torque->setEnabled(true); - } - - if (params.getBool("LiveTorque")) { - custom_torque_lateral->setEnabled(false); - params.putBool("CustomTorqueLateral", false); - for (const auto& customTorqueControl : customTorqueGroup) { - customTorqueControl->setVisible(false); - } - } else { - custom_torque_lateral->setEnabled(true); - } - - live_torque->refresh(); - custom_torque_lateral->refresh(); + if (enforce_torque_lateral->isToggled()) { + live_torque_relaxed->setVisible(live_torque->isToggled()); + torqued_override->setVisible(custom_torque_lateral->isToggled()); } else { params.putBool("LiveTorque", false); params.putBool("CustomTorqueLateral", false); @@ -461,8 +471,8 @@ void SPControlsPanel::updateToggles() { } } - if (params.getBool("SpeedLimitControl")) { - if (params.getBool("SpeedLimitPercOffset")) { + if (speed_limit_control->isToggled()) { + if (speed_limit_perc_offset->isToggled()) { slvo->setVisible(QString::fromStdString(params.get("SpeedLimitOffsetType")) != "0"); slo_type->setVisible(true); } else { @@ -477,7 +487,7 @@ void SPControlsPanel::updateToggles() { } // toggle names to update when SpeedLimitControl is flipped - toggles["SpeedLimitPercOffset"]->setVisible(params.getBool("SpeedLimitControl")); + speed_limit_perc_offset->setVisible(speed_limit_control->isToggled()); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { @@ -486,7 +496,7 @@ void SPControlsPanel::updateToggles() { cereal::CarParams::Reader CP = cmsg.getRoot(); if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { - toggles["EnforceTorqueLateral"]->setEnabled(false); + enforce_torque_lateral->setEnabled(false); params.remove("EnforceTorqueLateral"); } } @@ -548,6 +558,8 @@ SPVehiclesPanel::SPVehiclesPanel(QWidget *parent) : QWidget(parent) { SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(SPVehiclesPanel *parent) : ListWidget(parent) { setSpacing(50); + + // Hyundai/Kia/Genesis addItem(new LabelControl(tr("Hyundai/Kia/Genesis"))); auto hkgSmoothStop = new ParamControl( "HkgSmoothStop", @@ -558,6 +570,18 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(SPVehiclesPanel *parent) : ListWi hkgSmoothStop->setConfirmation(true, false); addItem(hkgSmoothStop); + // Subaru + addItem(new LabelControl(tr("Subaru"))); + auto subaruManualParkingBrakeSng = new ParamControl( + "SubaruManualParkingBrakeSng", + tr("Manual Parking Brake: Stop and Go (Beta)"), + tr("Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation!"), + "../assets/offroad/icon_blank.png" + ); + subaruManualParkingBrakeSng->setConfirmation(true, false); + addItem(subaruManualParkingBrakeSng); + + // Toyota/Lexus addItem(new LabelControl(tr("Toyota/Lexus"))); stockLongToyota = new ParamControl( "StockLongToyota", @@ -589,10 +613,20 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(SPVehiclesPanel *parent) : ListWi toyotaTss2LongTune->setConfirmation(true, false); addItem(toyotaTss2LongTune); + auto toyotaSngHack = new ParamControl( + "ToyotaSnG", + "Enable Stop and Go Hack", + "sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models. Use at your own risk.", + "../assets/offroad/icon_blank.png" + ); + toyotaSngHack->setConfirmation(true, false); + addItem(toyotaSngHack); + // trigger offroadTransition when going onroad/offroad connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { hkgSmoothStop->setEnabled(offroad); toyotaTss2LongTune->setEnabled(offroad); + toyotaSngHack->setEnabled(offroad); }); } @@ -635,19 +669,6 @@ SPVisualsPanel::SPVisualsPanel(QWidget *parent) : ListWidget(parent) { tr("OSM: Show UI elements that aid debugging."), "../assets/offroad/icon_calibration.png", }, - { - "CustomMapbox", - tr("Enable Mapbox Navigation*"), - QString("%1
" - "%2
" - "%3
" - "

%4

") - .arg(tr("Enable built-in navigation on sunnypilot, powered by Mapbox.")) - .arg(tr("Access via the web interface: \"http://:8082\"")) - .arg(tr("If you do not have comma Prime, you will need to provide your own Mapbox token at https://mapbox.com/. Reach out to sunnyhaibin#0865 on Discord for more information.")) - .arg(tr("Huge thanks to the dragonpilot team for making this possible!")), - "../assets/img_map.png", - }, { "TrueVEgoUi", tr("Speedometer: Display True Speed"), @@ -666,6 +687,12 @@ SPVisualsPanel::SPVisualsPanel(QWidget *parent) : ListWidget(parent) { tr("Enable this will display an icon that appears when the End-to-end model decides to start or stop."), "../assets/offroad/icon_road.png", }, + { + "Map3DBuildings", + tr("Map: Display 3D Buildings"), + tr("Parse and display 3D buildings on map. Thanks to jakethesnake420 for this implementation."), + "../assets/img_map.png", + }, }; // Visuals: Developer UI Info (Dev UI) @@ -701,14 +728,6 @@ SPVisualsPanel::SPVisualsPanel(QWidget *parent) : ListWidget(parent) { // trigger offroadTransition when going onroad/offroad connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - toggles["CustomMapbox"]->setEnabled(offroad); - }); - - // trigger hardwrae reboot if user confirms the selection - connect(toggles["CustomMapbox"], &ToggleControl::toggleFlipped, [=](bool state) { - if (ConfirmationDialog::confirm(tr("\"Enable Mapbox Navigation\"\nYou must restart your car or your device to apply these changes.\nReboot now?"), "Reboot", parent)) { - Hardware::reboot(); - } }); } @@ -717,7 +736,7 @@ void SPVisualsPanel::showEvent(QShowEvent *event) { } void SPVisualsPanel::updateToggles() { - dev_ui_info->setVisible(params.getBool("DevUI")); + dev_ui_info->setVisible(toggles["DevUI"]->isToggled()); } // Max Time Offroad (Shutdown timer) @@ -835,10 +854,10 @@ void BrightnessControl::refresh() { // Camera Offset Value CameraOffset::CameraOffset() : SPOptionControl ( "CameraOffset", - tr("Camera Offset (cm)"), - tr("Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately."), + tr("Camera Offset - Laneful Only (cm)"), + tr("Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm"), "../assets/offroad/icon_blank.png", - {-10, 10}) { + {-20, 20}) { refresh(); } @@ -896,7 +915,7 @@ void AutoLaneChangeTimer::refresh() { TorqueFriction::TorqueFriction() : SPOptionControl ( "TorqueFriction", tr("FRICTION"), - tr("Adjust Friction for the Torque Lateral Controller"), + tr("Adjust Friction for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), "../assets/offroad/icon_blank.png", {0, 50}) { @@ -906,13 +925,14 @@ TorqueFriction::TorqueFriction() : SPOptionControl ( void TorqueFriction::refresh() { QString torqueFrictionStr = QString::fromStdString(params.get("TorqueFriction")); float valuef = torqueFrictionStr.toInt() * 0.01; + setTitle(params.getBool("TorquedOverride") ? "FRICTION - Live && Offline" : "FRICTION - Offline Only"); setLabel(QString::number(valuef)); } TorqueMaxLatAccel::TorqueMaxLatAccel() : SPOptionControl ( "TorqueMaxLatAccel", tr("LAT_ACCEL_FACTOR"), - tr("Adjust Max Lateral Acceleration for the Torque Lateral Controller"), + tr("Adjust Max Lateral Acceleration for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), "../assets/offroad/icon_blank.png", {1, 500}) { @@ -922,6 +942,7 @@ TorqueMaxLatAccel::TorqueMaxLatAccel() : SPOptionControl ( void TorqueMaxLatAccel::refresh() { QString torqueMaxLatAccelStr = QString::fromStdString(params.get("TorqueMaxLatAccel")); float valuef = torqueMaxLatAccelStr.toInt() * 0.01; + setTitle(params.getBool("TorquedOverride") ? "LAT_ACCEL_FACTOR - Live && Offline" : "LAT_ACCEL_FACTOR - Offline Only"); setLabel(QString::number(valuef)); } @@ -1043,7 +1064,7 @@ void SidebarTemp::showEvent(QShowEvent *event) { } void SidebarTemp::updateToggles() { - sidebar_temp_setting->setVisible(params.getBool("SidebarTemperature")); + sidebar_temp_setting->setVisible(sidebarTemperature->isToggled()); } DynamicLaneProfile::DynamicLaneProfile(QWidget *parent) : QWidget(parent), outer_layout(this) { @@ -1090,7 +1111,7 @@ void DynamicLaneProfile::showEvent(QShowEvent *event) { void DynamicLaneProfile::updateToggles() { // toggle names to update when DynamicLaneProfile is flipped - dlp_settings->setVisible(params.getBool("DynamicLaneProfileToggle")); + dlp_settings->setVisible(dynamicLaneProfile->isToggled()); } void DynamicLaneProfile::updateButtons() { diff --git a/selfdrive/ui/qt/offroad/sunnypilot_settings.h b/selfdrive/ui/qt/offroad/sunnypilot_settings.h index fb05095842..b7ff48d7f3 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot_settings.h +++ b/selfdrive/ui/qt/offroad/sunnypilot_settings.h @@ -79,6 +79,12 @@ public: inline void setLabel(const QString &text) { label.setText(text); } + void setEnabled(bool enabled) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enabled); + } + } + signals: void updateLabels(); void updateOtherToggles(); diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 82c0ed4f0b..f05e9d89cf 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -235,8 +235,7 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { void OnroadWindow::offroadTransition(bool offroad) { if (!offroad) { #ifdef ENABLE_MAPS - bool custom_mapbox = params.getBool("CustomMapbox") && QString::fromStdString(params.get("CustomMapboxTokenSk")) != ""; - if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty() || custom_mapbox)) { + if (map == nullptr && (uiState()->hasPrime() || !MAPBOX_TOKEN.isEmpty())) { auto m = new MapPanel(get_mapbox_settings()); map = m; @@ -480,8 +479,10 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par #ifdef ENABLE_DASHCAM void AnnotatedCameraWidget::offroadTransition(bool offroad) { - if (offroad && recorder) { - recorder->stop(); + if (offroad) { + if (recorder) recorder->stop(); + + roadName = ""; } } #endif @@ -586,7 +587,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { steeringTorqueEps = car_state.getSteeringTorqueEps(); bearingAccuracyDeg = gpsLocationExternal.getBearingAccuracyDeg(); bearingDeg = gpsLocationExternal.getBearingDeg(); - torquedUseParams = s.scene.live_torque_toggle && !s.scene.custom_torque_toggle; + torquedUseParams = ltp.getUseParams() || s.scene.live_torque_toggle; latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); liveValid = ltp.getLiveValid(); @@ -642,11 +643,11 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { showDebugUI = s.scene.show_debug_ui; const auto lmd = sm["liveMapData"].getLiveMapData(); - QString road_name = QString::fromStdString(lmd.getCurrentRoadName()); const auto data_type = int(lmd.getDataType()); const QString data_type_draw(data_type == 2 ? "🌐 " : ""); - roadName = !road_name.isEmpty() ? data_type_draw + road_name : ""; + roadName = QString::fromStdString(lmd.getCurrentRoadName()); + roadName = !roadName.isEmpty() ? data_type_draw + roadName : ""; float speed_limit_slc = lp.getSpeedLimit() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); const float speed_limit_offset = lp.getSpeedLimitOffset() * (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); @@ -1417,7 +1418,7 @@ void AnnotatedCameraWidget::drawE2eStatus(QPainter &p, int x, int y, int w, int p.drawEllipse(e2eStatusIcon); } -void AnnotatedCameraWidget::drawLeftTurnSignal(QPainter &painter, int x, int y, int state) { +void AnnotatedCameraWidget::drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { painter.setRenderHint(QPainter::Antialiasing, true); QColor circle_color, circle_color_0, circle_color_1; @@ -1443,17 +1444,16 @@ void AnnotatedCameraWidget::drawLeftTurnSignal(QPainter &painter, int x, int y, } // Draw the circle - int circleSize = 120; int circleX = x; int circleY = y; painter.setPen(Qt::NoPen); painter.setBrush(circle_color); - painter.drawEllipse(circleX, circleY, circleSize, circleSize); + painter.drawEllipse(circleX, circleY, circle_size, circle_size); // Draw the arrow int arrowSize = 50; - int arrowX = circleX + (circleSize - arrowSize) / 4; - int arrowY = circleY + (circleSize - arrowSize) / 2; + int arrowX = circleX + (circle_size - arrowSize) / 4; + int arrowY = circleY + (circle_size - arrowSize) / 2; painter.setPen(Qt::NoPen); painter.setBrush(arrow_color); @@ -1474,7 +1474,7 @@ void AnnotatedCameraWidget::drawLeftTurnSignal(QPainter &painter, int x, int y, painter.fillRect(tailRect, arrow_color); } -void AnnotatedCameraWidget::drawRightTurnSignal(QPainter &painter, int x, int y, int state) { +void AnnotatedCameraWidget::drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state) { painter.setRenderHint(QPainter::Antialiasing, true); QColor circle_color, circle_color_0, circle_color_1; @@ -1501,17 +1501,16 @@ void AnnotatedCameraWidget::drawRightTurnSignal(QPainter &painter, int x, int y, // Draw the circle - int circleSize = 120; int circleX = x; int circleY = y; painter.setPen(Qt::NoPen); painter.setBrush(circle_color); - painter.drawEllipse(circleX, circleY, circleSize, circleSize); + painter.drawEllipse(circleX, circleY, circle_size, circle_size); // Draw the arrow int arrowSize = 50; - int arrowX = circleX + (circleSize - arrowSize) / 2 + (arrowSize / 2.5) - 3; - int arrowY = circleY + (circleSize - arrowSize) / 2; + int arrowX = circleX + (circle_size - arrowSize) / 2 + (arrowSize / 2.5) - 3; + int arrowY = circleY + (circle_size - arrowSize) / 2; painter.setPen(Qt::NoPen); painter.setBrush(arrow_color); @@ -1966,11 +1965,13 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { if (left_blinker || right_blinker) { blinker_frame++; int state = blinkerPulse(blinker_frame); + int blinker_x = splitPanelVisible ? 150 : 180; + int blinker_y = splitPanelVisible ? 220 : 90; if (left_blinker) { - drawLeftTurnSignal(painter, rect().center().x() - 300, splitPanelVisible ? 210 : 90, state); + drawLeftTurnSignal(painter, rect().center().x() - (blinker_x + blinker_size), blinker_y, blinker_size, state); } if (right_blinker) { - drawRightTurnSignal(painter, rect().center().x() + 180, splitPanelVisible ? 210 : 90, state); + drawRightTurnSignal(painter, rect().center().x() + blinker_x, blinker_y, blinker_size, state); } } else { blinker_frame = 0; diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 7c729c5189..d679a74efe 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -20,6 +20,7 @@ const int btn_size = 192; const int img_size = (btn_size / 4) * 3; const int subsign_img_size = 35; +const int blinker_size = 120; // ***** onroad widgets ***** class OnroadAlerts : public QWidget { @@ -117,8 +118,8 @@ private: void drawE2eStatus(QPainter &p, int x, int y, int w, int h, int e2e_long_status); - void drawLeftTurnSignal(QPainter &painter, int x, int y, int state); - void drawRightTurnSignal(QPainter &painter, int x, int y, int state); + void drawLeftTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); + void drawRightTurnSignal(QPainter &painter, int x, int y, int circle_size, int state); int blinkerPulse(int frame); void updateButtonsLayout(); @@ -170,7 +171,7 @@ private: bool showDebugUI = false; - QString roadName; + QString roadName = ""; bool showSpeedLimit = false; float speedLimitSLC; diff --git a/selfdrive/ui/qt/onroad_settings.cc b/selfdrive/ui/qt/onroad_settings.cc index cc74a620ee..988b49f8e8 100644 --- a/selfdrive/ui/qt/onroad_settings.cc +++ b/selfdrive/ui/qt/onroad_settings.cc @@ -60,14 +60,14 @@ OnroadSettings::OnroadSettings(bool closeable, QWidget *parent) : QFrame(parent) options_layout->setContentsMargins(0, 32, 0, 32); options_layout->setSpacing(20); - // Dynamic Lane Profile - options_layout->addWidget(dlp_widget = new OptionWidget(this)); - QObject::connect(dlp_widget, &OptionWidget::updateParam, this, &OnroadSettings::changeDynamicLaneProfile); - // Gap Adjust Cruise options_layout->addWidget(gac_widget = new OptionWidget(this)); QObject::connect(gac_widget, &OptionWidget::updateParam, this, &OnroadSettings::changeGapAdjustCruise); + // Dynamic Lane Profile + options_layout->addWidget(dlp_widget = new OptionWidget(this)); + QObject::connect(dlp_widget, &OptionWidget::updateParam, this, &OnroadSettings::changeDynamicLaneProfile); + // Speed Limit Control options_layout->addWidget(slc_widget = new OptionWidget(this)); QObject::connect(slc_widget, &OptionWidget::updateParam, this, &OnroadSettings::changeSpeedLimitControl); @@ -147,6 +147,12 @@ void OnroadSettings::refresh() { param_watcher->addParam("LongitudinalPersonality"); param_watcher->addParam("SpeedLimitControl"); + UIScene &scene = uiState()->scene; + // Update live params on Feature Status on camera view + scene.dynamic_lane_profile = std::atoi(params.get("DynamicLaneProfile").c_str()); + scene.longitudinal_personality = std::atoi(params.get("LongitudinalPersonality").c_str()); + scene.speed_limit_control_enabled = params.getBool("SpeedLimitControl"); + if (!isVisible()) return; setUpdatesEnabled(false); diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index fe4742722c..44d7f49300 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -183,6 +183,8 @@ public: refresh(); } + bool isToggled() { return params.getBool(key); } + private: void setIcon(bool state) { if (state && !active_icon_pixmap.isNull()) { diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 66c2d8ce1f..62bd20f090 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -252,6 +252,8 @@ void ui_update_params(UIState *s) { s->scene.e2e_long_alert_light = params.getBool("EndToEndLongAlertLight"); s->scene.e2e_long_alert_lead = params.getBool("EndToEndLongAlertLead"); s->scene.e2e_long_alert_ui = params.getBool("EndToEndLongAlertUI"); + s->scene.map_3d_buildings = params.getBool("Map3DBuildings"); + s->scene.live_torque_toggle = params.getBool("LiveTorque"); // Handle Onroad Screen Off params if (s->scene.onroadScreenOff > 0) { @@ -304,23 +306,12 @@ void UIState::updateStatus() { if (scene.started) { status = STATUS_DISENGAGED; scene.started_frame = sm->frame; - scene.live_torque_toggle = params.getBool("LiveTorque"); - scene.custom_torque_toggle = params.getBool("CustomTorqueLateral"); } started_prev = scene.started; emit offroadTransition(!scene.started); } if (scene.started) { - // Update live params when the camera view is on - { - if (sm->frame % (UI_FREQ / 2) == 0) { // Update every 2 Hz - scene.dynamic_lane_profile = std::atoi(params.get("DynamicLaneProfile").c_str()); - scene.longitudinal_personality = std::atoi(params.get("LongitudinalPersonality").c_str()); - scene.speed_limit_control_enabled = params.getBool("SpeedLimitControl"); - } - } - // Auto hide UI button state machine { if (scene.button_auto_hide) { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index e31602c782..76911b6211 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -217,7 +217,6 @@ typedef struct UIScene { int dev_ui_info; int rn_offset; bool live_torque_toggle; - bool custom_torque_toggle; bool touch_to_wake = false; int sleep_btn = -1; @@ -237,6 +236,8 @@ typedef struct UIScene { float mads_path_range = DRIVING_PATH_WIDE - DRIVING_PATH_NARROW; // 0.9 - 0.25 = 0.65 bool onroad_settings_visible; + + bool map_3d_buildings; } UIScene; class UIState : public QObject { diff --git a/system/fleetmanager/fleet_manager.py b/system/fleetmanager/fleet_manager.py index bf1ed190a8..aed9c556df 100755 --- a/system/fleetmanager/fleet_manager.py +++ b/system/fleetmanager/fleet_manager.py @@ -5,8 +5,10 @@ import secrets import threading import time from flask import Flask, render_template, Response, request, send_from_directory, session, redirect, url_for -import system.fleetmanager.helpers as fleet -from system.loggerd.config import ROOT as REALDATA +from openpilot.common.realtime import set_core_affinity +import openpilot.system.fleetmanager.helpers as fleet +from openpilot.system.hardware.hw import Paths +from openpilot.system.swaglog import cloudlog app = Flask(__name__) @@ -41,7 +43,7 @@ def login(): def full(cameratype, route): chunk_size = 1024 * 512 # 5KiB file_name = cameratype + (".ts" if cameratype == "qcamera" else ".hevc") - vidlist = "|".join(REALDATA + "/" + segment + "/" + file_name for segment in fleet.segments_in_route(route)) + vidlist = "|".join(Paths.log_root() + "/" + segment + "/" + file_name for segment in fleet.segments_in_route(route)) def generate_buffered_stream(): with fleet.ffmpeg_mp4_concat_wrap_process_builder(vidlist, cameratype, chunk_size) as process: @@ -55,7 +57,7 @@ def full(cameratype, route): def fcamera(cameratype, segment): if not fleet.is_valid_segment(segment): return render_template("error.html", error="invalid segment") - file_name = REALDATA + "/" + segment + "/" + cameratype + (".ts" if cameratype == "qcamera" else ".hevc") + file_name = Paths.log_root() + "/" + segment + "/" + cameratype + (".ts" if cameratype == "qcamera" else ".hevc") return Response(fleet.ffmpeg_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4') @@ -153,6 +155,10 @@ def update_pin(): def main(): + try: + set_core_affinity([0, 1, 2, 3]) + except Exception: + cloudlog.exception("fleet_manager: failed to set core affinity") app.secret_key = secrets.token_hex(32) schedule_pin_generate() app.run(host="0.0.0.0", port=5050) diff --git a/system/fleetmanager/helpers.py b/system/fleetmanager/helpers.py index fb1c4889f2..2271fba6ed 100644 --- a/system/fleetmanager/helpers.py +++ b/system/fleetmanager/helpers.py @@ -3,10 +3,10 @@ import subprocess from flask import render_template, request, session from functools import wraps from pathlib import Path -from common.params import Params -from system.hardware import PC -from system.loggerd.config import ROOT as REALDATA -from system.loggerd.uploader import listdir_by_creation +from openpilot.common.params import Params +from openpilot.system.hardware import PC +from openpilot.system.hardware.hw import Paths +from openpilot.system.loggerd.uploader import listdir_by_creation from tools.lib.route import SegmentName @@ -37,7 +37,7 @@ def list_files(path): def is_valid_segment(segment): try: - segment_to_segment_name(REALDATA, segment) + segment_to_segment_name(Paths.log_root(), segment) return True except AssertionError: return False @@ -50,9 +50,9 @@ def segment_to_segment_name(data_dir, segment): def all_segment_names(): segments = [] - for segment in listdir_by_creation(REALDATA): + for segment in listdir_by_creation(Paths.log_root()): try: - segments.append(segment_to_segment_name(REALDATA, segment)) + segments.append(segment_to_segment_name(Paths.log_root(), segment)) except AssertionError: pass return segments