diff --git a/README.md b/README.md index 21928a86..596db65b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ FrogPilot is a fully open-sourced fork of openpilot, featuring clear and concise ------ FrogPilot was last updated on: -**October 21st, 2024** +**November 1st, 2024** Features ------ diff --git a/cereal/car.capnp b/cereal/car.capnp index ec40d92c..cd3f35a6 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -137,14 +137,15 @@ struct CarEvent @0x9b1657f34caf3ad3 { openpilotCrashedRandomEvent @137; pedalInterceptorNoBrake @138; speedLimitChanged @139; - torqueNNLoad @140; - trafficModeActive @141; - trafficModeInactive @142; - turningLeft @143; - turningRight @144; - vCruise69 @145; - yourFrogTriedToKillMe @146; - youveGotMail @147; + thisIsFineSteerSaturated @140; + torqueNNLoad @141; + trafficModeActive @142; + trafficModeInactive @143; + turningLeft @144; + turningRight @145; + vCruise69 @146; + yourFrogTriedToKillMe @147; + youveGotMail @148; radarCanErrorDEPRECATED @15; communityFeatureDisallowedDEPRECATED @62; @@ -453,7 +454,8 @@ struct CarControl { mail @16; nessie @17; noice @18; - uwu @19; + thisIsFine @19; + uwu @20; } } diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 6b5554fe..0fa09874 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -54,27 +54,29 @@ struct FrogPilotPlan @0x80ae746ee2596b11 { desiredFollowDistance @4 :Float32; experimentalMode @5 :Bool; forcingStop @6 :Bool; - frogpilotEvents @7 :List(Car.CarEvent); - lateralCheck @8 :Bool; - laneWidthLeft @9 :Float32; - laneWidthRight @10 :Float32; - maxAcceleration @11 :Float32; - minAcceleration @12 :Float32; - redLight @13 :Bool; - safeObstacleDistance @14 :Int32; - safeObstacleDistanceStock @15 :Int32; - slcOverridden @16 :Bool; - slcOverriddenSpeed @17 :Float32; - slcSpeedLimit @18 :Float32; - slcSpeedLimitOffset @19 :Float32; - speedJerk @20 :Float32; - speedJerkStock @21 :Float32; - speedLimitChanged @22 :Bool; - stoppedEquivalenceFactor @23 :Int32; - tFollow @24 :Float32; - unconfirmedSlcSpeedLimit @25 :Float32; - vCruise @26 :Float32; - vtscControllingCurve @27 :Bool; + forcingStopLength @7 :Float32; + frogpilotEvents @8 :List(Car.CarEvent); + lateralCheck @9 :Bool; + laneWidthLeft @10 :Float32; + laneWidthRight @11 :Float32; + maxAcceleration @12 :Float32; + minAcceleration @13 :Float32; + redLight @14 :Bool; + safeObstacleDistance @15 :Int64; + safeObstacleDistanceStock @16 :Int64; + slcOverridden @17 :Bool; + slcOverriddenSpeed @18 :Float32; + slcSpeedLimit @19 :Float32; + slcSpeedLimitOffset @20 :Float32; + speedJerk @21 :Float32; + speedJerkStock @22 :Float32; + speedLimitChanged @23 :Bool; + stoppedEquivalenceFactor @24 :Int64; + tFollow @25 :Float32; + togglesUpdated @26 :Bool; + unconfirmedSlcSpeedLimit @27 :Float32; + vCruise @28 :Float32; + vtscControllingCurve @29 :Bool; } struct CustomReserved5 @0xa5cd762cd951a455 { diff --git a/cereal/log.capnp b/cereal/log.capnp index 3b1df446..9a944eac 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -618,6 +618,10 @@ struct RadarState @0x9a185389d6fdd05f { leadOne @3 :LeadData; leadTwo @4 :LeadData; + leadLeft @13 :LeadData; + leadRight @14 :LeadData; + leadLeftFar @15 :LeadData; + leadRightFar @16 :LeadData; cumLagMs @5 :Float32; struct LeadData { diff --git a/cereal/services.py b/cereal/services.py index 1ac0ae47..6a15c967 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -74,13 +74,6 @@ _services: dict[str, tuple] = { "userFlag": (True, 0., 1), "microphone": (True, 10., 10), - # FrogPilot - "frogpilotCarControl": (True, 100., 10), - "frogpilotCarState": (True, 100., 10), - "frogpilotDeviceState": (True, 2., 1), - "frogpilotNavigation": (True, 1., 10), - "frogpilotPlan": (True, 20., 5), - # debug "uiDebug": (True, 0., 1), "testJoystick": (True, 0.), @@ -97,6 +90,13 @@ _services: dict[str, tuple] = { "customReservedRawData0": (True, 0.), "customReservedRawData1": (True, 0.), "customReservedRawData2": (True, 0.), + + # FrogPilot + "frogpilotCarControl": (True, 100., 10), + "frogpilotCarState": (True, 100., 10), + "frogpilotDeviceState": (True, 2., 1), + "frogpilotNavigation": (True, 1., 10), + "frogpilotPlan": (True, 20., 5), } SERVICE_LIST = {name: Service(*vals) for idx, (name, vals) in enumerate(_services.items())} diff --git a/common/conversions.py b/common/conversions.py index 8554646e..62c8debd 100644 --- a/common/conversions.py +++ b/common/conversions.py @@ -12,8 +12,6 @@ class Conversions: KNOTS_TO_MS = 1. / MS_TO_KNOTS # Distance - KM_TO_MILES = KPH_TO_MPH - MILES_TO_KM = MPH_TO_KPH METER_TO_FOOT = 3.28084 FOOT_TO_METER = 1. / METER_TO_FOOT CM_TO_INCH = 1. / 2.54 diff --git a/common/params.cc b/common/params.cc index 918f714f..08eee2fe 100644 --- a/common/params.cc +++ b/common/params.cc @@ -211,12 +211,11 @@ std::unordered_map keys = { // FrogPilot parameters {"AccelerationPath", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"AccelerationProfile", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, + {"AdjacentLeadsUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"AdjacentPath", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"AdjacentPathMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"AdvancedCustomUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"AdvancedLateralTune", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"AdvancedLongitudinalTune", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"AdvancedQOLDriving", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"AggressiveFollow", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"AggressiveJerkAcceleration", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"AggressiveJerkDanger", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, @@ -240,7 +239,6 @@ std::unordered_map keys = { {"BlindSpotMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"BlindSpotPath", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"BorderMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"CameraFPS", PERSISTENT}, {"CameraView", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"CancelModelDownload", PERSISTENT}, {"CancelThemeDownload", PERSISTENT}, @@ -266,6 +264,7 @@ std::unordered_map keys = { {"CESpeedLead", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"CEStatus", CLEAR_ON_OFFROAD_TRANSITION}, {"CEStoppedLead", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, + {"ClassicModels", PERSISTENT}, {"ClusterOffset", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"ColorToDownload", PERSISTENT}, {"Compass", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, @@ -281,18 +280,24 @@ std::unordered_map keys = { {"CustomCruiseLong", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"CustomDistanceIcons", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"CustomIcons", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"CustomPaths", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, + {"CustomizationLevel", PERSISTENT}, + {"CustomizationLevelConfirmed", PERSISTENT}, {"CustomPersonalities", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"CustomSignals", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"CustomSounds", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"CustomUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"DecelerationProfile", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, + {"DefaultModelName", CLEAR_ON_MANAGER_START}, {"DeveloperUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"DeviceManagement", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DeviceShutdown", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DisableCurveSpeedSmoothing", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DisableOnroadUploads", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DisableOpenpilotLongitudinal", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, + {"DissolvedOxygenCalibrationParams", PERSISTENT}, + {"DissolvedOxygenDrives", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, + {"DissolvedOxygenLiveTorqueParameters", PERSISTENT}, + {"DissolvedOxygenScore", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DistanceIconToDownload", PERSISTENT}, {"DisengageVolume", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"DoToggleReset", PERSISTENT}, @@ -303,10 +308,8 @@ std::unordered_map keys = { {"DownloadableSounds", PERSISTENT}, {"DownloadableWheels", PERSISTENT}, {"DownloadAllModels", PERSISTENT}, - {"DragonPilotTune", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"DriveRated", CLEAR_ON_ONROAD_TRANSITION}, {"DriverCamera", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"DrivingPersonalities", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DuckAmigoCalibrationParams", PERSISTENT}, {"DuckAmigoDrives", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"DuckAmigoLiveTorqueParameters", PERSISTENT}, @@ -334,6 +337,7 @@ std::unordered_map keys = { {"FrogPilotDrives", PERSISTENT | FROGPILOT_TRACKING}, {"FrogPilotKilometers", PERSISTENT | FROGPILOT_TRACKING}, {"FrogPilotMinutes", PERSISTENT | FROGPILOT_TRACKING}, + {"FrogPilotToggles", PERSISTENT}, {"FrogPilotTogglesUpdated", PERSISTENT}, {"FrogsGoMoo", PERSISTENT}, {"FrogsGoMoosTweak", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, @@ -353,8 +357,6 @@ std::unordered_map keys = { {"HideMapIcon", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HideMaxSpeed", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HideSpeed", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"HideSpeedUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"HideUIElements", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HolidayThemes", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HumanAcceleration", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"HumanFollowing", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, @@ -397,16 +399,15 @@ std::unordered_map keys = { {"MinimumLaneChangeSpeed", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"Model", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ModelDownloadProgress", PERSISTENT}, - {"ModelManagement", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ModelName", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ModelRandomizer", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ModelsDownloaded", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"ModelSelector", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ModelToDownload", PERSISTENT}, {"ModelUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"MTSCCurvatureCheck", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"MTSCEnabled", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"NavigationModels", PERSISTENT}, + {"NavigationUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"NextMapSpeedLimit", PERSISTENT}, {"NewLongAPI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"NewLongAPIGM", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, @@ -434,6 +435,7 @@ std::unordered_map keys = { {"OneLaneChange", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"OnroadDistanceButton", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"OnroadDistanceButtonPressed", PERSISTENT}, + {"openpilotMinutes", PERSISTENT}, {"OSMDownloadBounds", PERSISTENT}, {"OSMDownloadLocations", PERSISTENT}, {"OSMDownloadProgress", CLEAR_ON_MANAGER_START}, @@ -493,7 +495,6 @@ std::unordered_map keys = { {"ShowIP", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowMemoryUsage", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowSLCOffset", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"ShowSLCOffsetUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"ShowSteering", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowStoppingPoint", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowStoppingPointMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, @@ -503,6 +504,7 @@ std::unordered_map keys = { {"SidebarMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"SignalMetrics", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"SignalToDownload", PERSISTENT}, + {"SLCConfirmation", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmationHigher", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmationLower", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmed", PERSISTENT}, @@ -541,6 +543,7 @@ std::unordered_map keys = { {"TacoTune", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"TetheringEnabled", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_OTHER}, {"ThemeDownloadProgress", PERSISTENT}, + {"ThemeUpdated", PERSISTENT}, {"TombRaiderCalibrationParams", PERSISTENT}, {"TombRaiderDrives", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"TombRaiderLiveTorqueParameters", PERSISTENT}, @@ -564,7 +567,6 @@ std::unordered_map keys = { {"UseSI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"UseStockColors", CLEAR_ON_MANAGER_START}, {"UseVienna", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"VelocityModels", PERSISTENT}, {"VisionTurnControl", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"VoltSNG", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"WarningImmediateVolume", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 863c1c39..1369007e 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -16,7 +16,8 @@ from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.controls.lib.events import Events -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_utilities import update_frogpilot_toggles +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles REPLAY = "REPLAY" in os.environ @@ -28,7 +29,7 @@ class Car: def __init__(self, CI=None): self.can_sock = messaging.sub_sock('can', timeout=20) - self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents']) + self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents', 'frogpilotPlan']) self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'frogpilotCarState']) self.can_rcv_cum_timeout_counter = 0 @@ -74,10 +75,7 @@ class Car: self.rk = Ratekeeper(100, print_delay_threshold=None) # FrogPilot variables - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - - self.update_toggles = False + self.frogpilot_toggles = get_frogpilot_toggles(True) # set alternative experiences from parameters self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") @@ -97,6 +95,8 @@ class Car: self.params.put_nonblocking("CarParamsCache", cp_bytes) self.params.put_nonblocking("CarParamsPersistent", cp_bytes) + update_frogpilot_toggles() + def state_update(self) -> car.CarState: """carState update loop, driven by can""" @@ -199,11 +199,8 @@ class Car: self.rk.monitor_time() # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False + if self.sm['frogpilotPlan'].togglesUpdated: + self.frogpilot_toggles = get_frogpilot_toggles() def main(): config_realtime_process(4, Priority.CTRL_HIGH) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 4103e5f4..fc0dd012 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -97,9 +97,9 @@ class CarController(CarControllerBase): if self.CP.openpilotLongitudinalControl and (self.frame % CarControllerParams.ACC_CONTROL_STEP) == 0: # Both gas and accel are in m/s^2, accel is used solely for braking if frogpilot_toggles.sport_plus: - accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, get_max_allowed_accel(CS.out.vEgo))) + accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, get_max_allowed_accel(CS.out.vEgo))) else: - accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, CarControllerParams.ACCEL_MAX)) + accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, CarControllerParams.ACCEL_MAX)) gas = accel if not CC.longActive or gas < CarControllerParams.MIN_GAS: gas = CarControllerParams.INACTIVE_GAS diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 153a6784..9dd120ec 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -219,9 +219,9 @@ class CarController(CarControllerBase): if self.CP.carFingerprint in HONDA_BOSCH: if frogpilot_toggles.sport_plus: - self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, get_max_allowed_accel(CS.out.vEgo))) + self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, get_max_allowed_accel(CS.out.vEgo))) else: - self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, self.params.BOSCH_ACCEL_MAX)) + self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, self.params.BOSCH_ACCEL_MAX)) self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V) stopping = actuators.longControlState == LongCtrlState.stopping diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 92c0f5e4..ff037c11 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -82,9 +82,9 @@ class CarController(CarControllerBase): # accel + longitudinal if frogpilot_toggles.sport_plus: - accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, get_max_allowed_accel(CS.out.vEgo))) + accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, get_max_allowed_accel(CS.out.vEgo))) else: - accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, CarControllerParams.ACCEL_MAX)) + accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, CarControllerParams.ACCEL_MAX)) stopping = actuators.longControlState == LongCtrlState.stopping set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH) diff --git a/selfdrive/car/torque_data/lat_models/CHEVROLET_BOLT_EUV.json b/selfdrive/car/torque_data/lat_models/CHEVROLET_BOLT_EUV.json new file mode 100644 index 00000000..f228dcfa --- /dev/null +++ b/selfdrive/car/torque_data/lat_models/CHEVROLET_BOLT_EUV.json @@ -0,0 +1 @@ +{"input_std":[[9.281861],[1.8477924],[0.7977224],[0.047467366],[1.7969038],[1.8168812],[1.8351218],[1.785757],[1.7335743],[1.6658221],[1.5893887],[0.047346078],[0.0473731],[0.047383286],[0.047291175],[0.047300573],[0.04712479],[0.046799928]],"model_test_loss":0.027355343103408813,"input_size":18,"current_date_and_time":"2023-08-05_05-11-44","input_mean":[[21.655252],[-0.07694559],[-0.006081294],[-0.007598456],[-0.07309746],[-0.075890236],[-0.07804942],[-0.076106496],[-0.07184982],[-0.06528668],[-0.060404416],[-0.0077262702],[-0.0077046235],[-0.0076850485],[-0.007687444],[-0.007708868],[-0.0077959923],[-0.008017422]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.35776415],[-0.126288],[0.007988413],[0.03850029],[-0.056796823],[0.0072075897],[0.17376427]],"dense_1_W":[[0.010538558,6.7293744,-0.007391298,-1.035045,-0.47446147,1.0940393,0.08225446,-0.5795131,0.573115,1.82923,-0.16999252,0.8818023,0.03560901,-0.9470653,-1.042151,1.1532398,1.9009485,-1.2265956],[0.009010456,-1.3618345,0.039026346,0.22943486,-0.6669799,-0.768271,-0.16828564,-0.13406865,0.19760236,-0.18953702,-0.019137766,0.1468623,0.26367718,0.4732375,0.73679143,0.62450147,0.30198866,-0.93340015],[-0.044318866,2.2138615,9.620889,-0.66480356,-0.06849887,-0.038568456,-0.30580127,-0.088089585,0.31187677,0.5968372,-1.1462088,0.13234706,0.29166338,-0.69978577,-0.01790655,-0.097928315,-0.56950736,0.7560642],[1.3758256,0.8700429,-0.24295154,0.20832618,-0.7735097,1.0379355,-0.60753095,-0.5457418,-1.0892137,-0.6708325,0.24982774,0.09251328,0.08596103,-0.58034134,-0.3046114,-0.19754426,0.006461508,0.5989185],[0.06314328,-2.492993,-0.28200585,0.49902886,0.8513198,-0.5704965,1.0960953,-0.08426956,-0.76074624,0.10669376,0.02775254,-0.42194095,-0.34657434,-0.10863868,0.17019278,0.0963825,-0.10169116,0.21243806],[0.007984091,-1.9276509,-0.0013926353,0.04057924,1.4438432,1.3440262,-2.506722,1.700801,0.72410774,0.13471895,-0.18753268,0.7303607,0.018133093,-0.71643597,0.07050904,-0.30161944,0.085108586,0.061202843],[0.9413167,-0.9954305,-0.19510143,-0.4711845,-0.12398665,-0.45175523,1.0616771,0.28550953,-0.55543137,-0.21576759,-0.2364377,-0.012782618,-0.050565187,0.257694,-0.20975965,0.00022543047,-0.08760746,0.4983852]],"activation":"σ"},{"dense_2_W":[[-0.71804935,0.017023304,-0.099854074,-0.3262651,-0.402829,-0.12073083,0.13537839],[-0.44002575,-0.1071093,-0.58886194,-0.17319413,-0.21134079,0.23135148,0.0006880979],[-0.55711204,-0.8693639,-0.6443761,-0.7382846,0.18980889,-0.6082511,-0.63103676],[0.11338112,-0.5327033,0.2856197,0.32239884,-0.72682667,0.5302305,-0.45094746],[-0.35197002,-0.14440043,-0.025249843,-0.48697743,0.3340018,-0.25992322,0.0050561456],[0.34757507,0.15670523,-0.14263277,0.50704384,-0.020171141,0.6408679,-0.3074123],[0.40258837,-0.59363264,0.35948923,-0.060853776,-0.0072541097,0.89743376,-0.49789146],[-0.63476,0.29580453,0.1689314,-0.5061521,0.24901053,-0.23218995,0.57968193],[-0.66173035,0.50861925,-0.5845035,-0.6602214,0.8341883,-0.31437424,0.8046359],[0.038493533,0.15464582,-0.04848341,-0.57820857,-0.25891733,-0.47527292,0.21441916],[-0.15464531,-0.07454202,-0.8215851,-0.12614948,-0.5924209,0.00017916794,0.24154592],[0.6091424,-0.112086505,0.1144111,-0.31035227,-0.9237534,0.041003596,-0.3542808],[0.2989792,-0.23780549,0.116059326,-0.6056522,0.5499526,-0.9001413,0.5200723]],"activation":"σ","dense_2_b":[[-0.2638964],[-0.24607328],[-0.15493082],[-0.0071187904],[-0.23515384],[-0.09098133],[-0.034066215],[0.03609036],[-0.03842933],[-0.042302527],[-0.2439947],[-0.16342077],[-0.01030317]]},{"dense_3_W":[[0.45771673,-0.2084603,0.3570187,0.35835707,0.13684571,-0.582958,0.29889587,0.43543494,0.11841301,-0.26185623,-0.4988437,0.5752996,-0.28057483],[-0.19594137,0.050280698,-0.29057446,-0.2829161,-0.16987291,-0.21278952,-0.59946907,0.21295123,0.7040468,0.53549695,-0.52553934,-0.19560973,0.6233473],[-0.19091003,0.08669418,-0.5792192,0.57799137,-0.36263424,0.6037143,0.27898273,-0.30951327,-0.3572644,0.46720102,-0.5403428,0.32415462,-0.60570025]],"activation":"identity","dense_3_b":[[-0.0047377176],[0.023170695],[-0.021546118]]},{"dense_4_W":[[-0.12453941,-1.006034,0.96776205]],"dense_4_b":[[-0.02351544]],"activation":"identity"}]} \ No newline at end of file diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 032860e6..f1e1728a 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -54,7 +54,7 @@ class CarController(CarControllerBase): self.distance_button = 0 self.pcm_accel_compensation = 0.0 - self.permit_braking = 0.0 + self.permit_braking = True self.packer = CANPacker(dbc_name) self.accel = 0 @@ -141,10 +141,13 @@ class CarController(CarControllerBase): interceptor_gas_cmd = 0. # For cars where we allow a higher max acceleration of 2.0 m/s^2, compensate for PCM request overshoot and imprecise braking - # TODO: sometimes when switching from brake to gas quickly, CLUTCH->ACCEL_NET shows a slow unwind. make it go to 0 immediately if (self.CP.flags & ToyotaFlags.RAISED_ACCEL_LIMIT or self.CP.flags & ToyotaFlags.NEW_TOYOTA_TUNE) and CC.longActive and not CS.out.cruiseState.standstill: # calculate amount of acceleration PCM should apply to reach target, given pitch - accel_due_to_pitch = math.sin(CS.slope_angle) * ACCELERATION_DUE_TO_GRAVITY + if len(CC.orientationNED) == 3: + accel_due_to_pitch = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY + else: + accel_due_to_pitch = 0.0 + net_acceleration_request = actuators.accel + accel_due_to_pitch # let PCM handle stopping for now @@ -171,9 +174,9 @@ class CarController(CarControllerBase): self.permit_braking = True if frogpilot_toggles.sport_plus: - pcm_accel_cmd = clip(pcm_accel_cmd, self.params.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, get_max_allowed_accel(CS.out.vEgo))) + pcm_accel_cmd = clip(pcm_accel_cmd, self.params.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, get_max_allowed_accel(CS.out.vEgo))) else: - pcm_accel_cmd = clip(pcm_accel_cmd, self.params.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, self.params.ACCEL_MAX)) + pcm_accel_cmd = clip(pcm_accel_cmd, self.params.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, self.params.ACCEL_MAX)) # 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): diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 75130c2f..6d162c84 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -64,7 +64,6 @@ class CarState(CarStateBase): self.acc_type = 1 self.lkas_hud = {} self.pcm_accel_net = 0.0 - self.slope_angle = 0.0 # FrogPilot variables self.latActive_previous = False @@ -273,7 +272,6 @@ class CarState(CarStateBase): ("BODY_CONTROL_STATE", 3), ("BODY_CONTROL_STATE_2", 2), ("ESP_CONTROL", 3), - ("VSC1S07", 20), ("EPS_STATUS", 25), ("BRAKE_MODULE", 40), ("WHEEL_SPEEDS", 80), diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 292be96f..e3a918da 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -127,6 +127,7 @@ FW_VERSIONS = { b'\x018966333X0000\x00\x00\x00\x00', b'\x018966333X4000\x00\x00\x00\x00', b'\x01896633T16000\x00\x00\x00\x00', + b'\x01896633TA2000\x00\x00\x00\x00', b'\x028966306B2100\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306B2300\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306B2500\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', @@ -321,6 +322,7 @@ FW_VERSIONS = { b'F1526F4073\x00\x00\x00\x00\x00\x00', b'F1526F4121\x00\x00\x00\x00\x00\x00', b'F1526F4122\x00\x00\x00\x00\x00\x00', + b'F1526F4190\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B10011\x00\x00\x00\x00\x00\x00', @@ -337,6 +339,7 @@ FW_VERSIONS = { b'\x033F401200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', + b'\x033F435000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F0W01000 ', @@ -431,6 +434,7 @@ FW_VERSIONS = { CAR.TOYOTA_COROLLA_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896630A22000\x00\x00\x00\x00', + b'\x01896630A42000\x00\x00\x00\x00', b'\x01896630ZG2000\x00\x00\x00\x00', b'\x01896630ZG5000\x00\x00\x00\x00', b'\x01896630ZG5100\x00\x00\x00\x00', @@ -525,6 +529,7 @@ FW_VERSIONS = { b'8965B16011\x00\x00\x00\x00\x00\x00', b'8965B16101\x00\x00\x00\x00\x00\x00', b'8965B16170\x00\x00\x00\x00\x00\x00', + b'8965B16260\x00\x00\x00\x00\x00\x00', b'8965B76012\x00\x00\x00\x00\x00\x00', b'8965B76050\x00\x00\x00\x00\x00\x00', b'8965B76091\x00\x00\x00\x00\x00\x00', @@ -539,6 +544,7 @@ FW_VERSIONS = { b'\x01F15260A010\x00\x00\x00\x00\x00\x00', b'\x01F15260A050\x00\x00\x00\x00\x00\x00', b'\x01F15260A070\x00\x00\x00\x00\x00\x00', + b'\x01F15260A33000\x00\x00\x00\x00', b'\x01F152612641\x00\x00\x00\x00\x00\x00', b'\x01F152612651\x00\x00\x00\x00\x00\x00', b'\x01F152612862\x00\x00\x00\x00\x00\x00', @@ -598,6 +604,7 @@ FW_VERSIONS = { b'\x028646F1601100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1601200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1601300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', + b'\x028646F1601500\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F76020C0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F7603100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', @@ -1005,6 +1012,33 @@ FW_VERSIONS = { b'8646F4204000\x00\x00\x00\x00', ], }, + CAR.TOYOTA_RAV4_PRIME: { + (Ecu.engine, 0x700, None): [ + b'\x018966342S7000\x00\x00\x00\x00', + b'\x018966342Z1000\x00\x00\x00\x00', + b'\x018966342Z1100\x00\x00\x00\x00', + b'\x01896634AJ7000\x00\x00\x00\x00', + ], + (Ecu.abs, 0x7b0, None): [ + b'\x01F15264228300\x00\x00\x00\x00', + b'\x01F15264228500\x00\x00\x00\x00', + b'\x01F15264284100\x00\x00\x00\x00', + b'\x01F152642F3000\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x018965B4209000\x00\x00\x00\x00', + b'\x018965B4233100\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301400\x00\x00\x00\x00', + b'\x018821F6201400\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F4205200\x00\x00\x00\x008646G4202000\x00\x00\x00\x00', + b'\x028646F4205300\x00\x00\x00\x008646G4202100\x00\x00\x00\x00', + b'\x028646F4210100\x00\x00\x00\x008646G3305000\x00\x00\x00\x00', + ], + }, CAR.TOYOTA_RAV4_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896630R58000\x00\x00\x00\x00', @@ -1226,6 +1260,28 @@ FW_VERSIONS = { b'8646F0801100\x00\x00\x00\x00', ], }, + CAR.TOYOTA_SIENNA_4TH_GEN: { + (Ecu.engine, 0x700, None): [ + b'\x01896630841000\x00\x00\x00\x00', + b'\x01896630857101\x00\x00\x00\x00', + b'\x01896630864000\x00\x00\x00\x00', + ], + (Ecu.abs, 0x7b0, None): [ + b'\x01F15260815100\x00\x00\x00\x00', + b'\x01F15260815300\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x018965B4509100\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301500\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0802200\x00\x00\x00\x008646G4202100\x00\x00\x00\x00', + b'\x028646F0802300\x00\x00\x00\x008646G4202100\x00\x00\x00\x00', + b'\x028646F0802400\x00\x00\x00\x008646G4202100\x00\x00\x00\x00', + ], + }, CAR.LEXUS_CTH: { (Ecu.dsu, 0x791, None): [ b'881517601100\x00\x00\x00\x00', @@ -1644,6 +1700,7 @@ FW_VERSIONS = { b'8965B47070\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301300\x00\x00\x00\x00', b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 21c86700..63e55166 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -156,9 +156,6 @@ class CarInterface(CarInterfaceBase): tune.kiV = [3.6, 2.4, 1.5] if params.get_bool("FrogsGoMoosTweak"): - if ret.flags & ToyotaFlags.NEW_TOYOTA_TUNE or ret.flags & ToyotaFlags.RAISED_ACCEL_LIMIT: - tune.kiV = [0.3] - ret.stoppingDecelRate = 0.1 # reach stopping target smoothly ret.vEgoStopping = 0.15 ret.vEgoStarting = 0.15 diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 96bae142..7caa0efb 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -47,9 +47,7 @@ class CarControllerParams: class ToyotaFlags(IntFlag): # Detected flags HYBRID = 1 - SMART_DSU = 2 DISABLE_RADAR = 4 - RADAR_CAN_FILTER = 2048 # Static flags TSS2 = 8 @@ -59,14 +57,17 @@ class ToyotaFlags(IntFlag): # these cars use the Lane Tracing Assist (LTA) message for lateral control ANGLE_CONTROL = 128 NO_STOP_TIMER = 256 - # these cars are speculated to allow stop and go when the DSU is unplugged or disabled with sDSU + # these cars are speculated to allow stop and go when the DSU is unplugged SNG_WITHOUT_DSU = 512 # these cars can utilize 2.0 m/s^2 RAISED_ACCEL_LIMIT = 1024 + SECOC = 2048 # FrogPilot Toyota flags NEW_TOYOTA_TUNE = 4096 - ZSS = 8192 + RADAR_CAN_FILTER = 8192 + SMART_DSU = 16384 + ZSS = 32768 class Footnote(Enum): CAMRY = CarFootnote( @@ -254,6 +255,14 @@ class CAR(Platforms): TOYOTA_RAV4_TSS2.specs, flags=ToyotaFlags.RADAR_ACC | ToyotaFlags.ANGLE_CONTROL, ) + TOYOTA_RAV4_PRIME = PlatformConfig( + # TODO: Enable this docs entry when it can be suppressed from openpilot CARS.md + # [ToyotaCarDocs("Toyota RAV4 Prime 2021-23", min_enable_speed=MIN_ACC_SPEED)], + [], + CarSpecs(mass=4372. * CV.LB_TO_KG, wheelbase=2.68, steerRatio=16.88, tireStiffnessFactor=0.5533), + dbc_dict('toyota_rav4_prime_generated', 'toyota_tss2_adas'), + flags=ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC, + ) TOYOTA_MIRAI = ToyotaTSS2PlatformConfig( # TSS 2.5 [ToyotaCarDocs("Toyota Mirai 2021")], CarSpecs(mass=4300. * CV.LB_TO_KG, wheelbase=2.91, steerRatio=14.8, tireStiffnessFactor=0.8), @@ -264,6 +273,14 @@ class CAR(Platforms): dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), flags=ToyotaFlags.NO_STOP_TIMER, ) + TOYOTA_SIENNA_4TH_GEN = PlatformConfig( + # TODO: Enable this docs entry when it can be suppressed from openpilot CARS.md + # [ToyotaCarDocs("Toyota Sienna 2021-23", min_enable_speed=MIN_ACC_SPEED)], + [], + CarSpecs(mass=4625. * CV.LB_TO_KG, wheelbase=3.06, steerRatio=17.8, tireStiffnessFactor=0.444), + dbc_dict('toyota_rav4_prime_generated', 'toyota_tss2_adas'), + flags=ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC, + ) # Lexus LEXUS_CTH = PlatformConfig( @@ -547,6 +564,7 @@ FW_QUERY_CONFIG = FwQueryConfig( # Hybrid control computer can be on 0x7e2 (KWP) or 0x7d2 (UDS) depending on platform (Ecu.hybrid, 0x7e2, None), # Hybrid Control Assembly & Computer + (Ecu.hybrid, 0x7d2, None), # Hybrid Control Assembly & Computer (Ecu.srs, 0x780, None), # SRS Airbag # Transmission is combined with engine on some platforms, such as TSS-P RAV4 (Ecu.transmission, 0x701, None), @@ -577,6 +595,8 @@ RADAR_ACC_CAR = CAR.with_flags(ToyotaFlags.RADAR_ACC) ANGLE_CONTROL_CAR = CAR.with_flags(ToyotaFlags.ANGLE_CONTROL) +SECOC_CAR = CAR.with_flags(ToyotaFlags.SECOC) + # no resume button press required NO_STOP_TIMER_CAR = CAR.with_flags(ToyotaFlags.NO_STOP_TIMER) diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index e7e7ee1f..802a0ce4 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -83,9 +83,9 @@ class CarController(CarControllerBase): if self.frame % self.CCP.ACC_CONTROL_STEP == 0 and self.CP.openpilotLongitudinalControl: acc_control = self.CCS.acc_control_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive) if frogpilot_toggles.sport_plus: - accel = clip(actuators.accel, self.CCP.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, get_max_allowed_accel(CS.out.vEgo))) if CC.longActive else 0 + accel = clip(actuators.accel, self.CCP.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, get_max_allowed_accel(CS.out.vEgo))) if CC.longActive else 0 else: - accel = clip(actuators.accel, self.CCP.ACCEL_MIN, min(frogpilot_toggles.max_desired_accel, self.CCP.ACCEL_MAX)) if CC.longActive else 0 + accel = clip(actuators.accel, self.CCP.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, self.CCP.ACCEL_MAX)) if CC.longActive else 0 stopping = actuators.longControlState == LongCtrlState.stopping starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < self.CP.vEgoStopping) can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, CANBUS.pt, CS.acc_type, CC.longActive, accel, diff --git a/selfdrive/classic_modeld/classic_modeld.py b/selfdrive/classic_modeld/classic_modeld.py index 06c7cf81..c285acd6 100755 --- a/selfdrive/classic_modeld/classic_modeld.py +++ b/selfdrive/classic_modeld/classic_modeld.py @@ -27,7 +27,7 @@ from openpilot.selfdrive.classic_modeld.models.commonmodel_pyx import ModelFrame from openpilot.selfdrive.frogpilot.assets.model_manager import DEFAULT_MODEL from openpilot.selfdrive.frogpilot.frogpilot_functions import MODELS_PATH -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles PROCESS_NAME = "selfdrive.classic_modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') @@ -136,14 +136,11 @@ class ModelState: def main(demo=False): # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + frogpilot_toggles = get_frogpilot_toggles(True) enable_navigation = not frogpilot_toggles.navigationless_model radarless = frogpilot_toggles.radarless_model - update_toggles = False - cloudlog.warning("classic_modeld init") sentry.set_tag("daemon", PROCESS_NAME) @@ -347,11 +344,8 @@ def main(demo=False): last_vipc_frame_id = meta_main.frame_id # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - update_toggles = True - elif update_toggles: - FrogPilotVariables.update_frogpilot_params() - update_toggles = False + if sm['frogpilotPlan'].togglesUpdated: + frogpilot_toggles = get_frogpilot_toggles() if __name__ == "__main__": try: diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 4ce4dfcb..552bc90a 100644 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -32,7 +32,7 @@ from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_acceleration import get_max_allowed_accel -from openpilot.selfdrive.frogpilot.frogpilot_variables import NON_DRIVING_GEARS, FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import CRUISING_SPEED, NON_DRIVING_GEARS, get_frogpilot_toggles SOFT_DISABLE_TIME = 3 # seconds LDW_MIN_SPEED = 31 * CV.MPH_TO_MS @@ -99,7 +99,7 @@ class Controls: if REPLAY: # no vipc in replay will make them ignored anyways ignore += ['roadCameraState', 'wideRoadCameraState'] - if FrogPilotVariables.toggles.radarless_model: + if get_frogpilot_toggles(True).radarless_model: ignore += ['radarState'] self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman', @@ -164,7 +164,7 @@ class Controls: self.can_log_mono_time = 0 - self.startup_event = get_startup_event(car_recognized, not self.CP.passive, len(self.CP.carFw) > 0, self.block_user, FrogPilotVariables.toggles) + self.startup_event = get_startup_event(car_recognized, not self.CP.passive, len(self.CP.carFw) > 0, self.block_user, get_frogpilot_toggles(True)) if not sounds_available: self.events.add(EventName.soundsUnavailable, static=True) @@ -181,8 +181,7 @@ class Controls: self.rk = Ratekeeper(100, print_delay_threshold=None) # FrogPilot variables - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + self.frogpilot_toggles = get_frogpilot_toggles(True) self.params_memory = Params("/dev/shm/params") @@ -191,11 +190,12 @@ class Controls: self.fcw_event_triggered = False self.no_entry_alert_triggered = False self.onroad_distance_pressed = False - self.radarless_model = self.frogpilot_toggles.radarless_model self.resume_pressed = False self.resume_previously_pressed = False self.steer_saturated_event_triggered = False - self.update_toggles = False + + self.radarless_model = self.frogpilot_toggles.radarless_model + self.use_old_long = self.CP.carName == "hyundai" and not self.params.get_bool("NewLongAPI") self.use_old_long |= self.CP.carName == "gm" and not self.params.get_bool("NewLongAPIGM") @@ -626,7 +626,7 @@ class Controls: t_since_plan = (self.sm.frame - self.sm.recv_frame['longitudinalPlan']) * DT_CTRL actuators.accel = self.LoC.update_old_long(CC.longActive, CS, long_plan, pid_accel_limits, t_since_plan) else: - actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits) + actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop or self.sm['frogpilotPlan'].forcingStopLength <= 0, pid_accel_limits) if len(long_plan.speeds): actuators.speed = long_plan.speeds[-1] @@ -673,7 +673,7 @@ class Controls: good_speed = CS.vEgo > 5 max_torque = abs(self.sm['carOutput'].actuatorsOutput.steer) > 0.99 if undershooting and turning and good_speed and max_torque: - lac_log.active and self.events.add(EventName.goatSteerSaturated if self.frogpilot_toggles.goat_scream else EventName.steerSaturated) + lac_log.active and self.events.add(EventName.goatSteerSaturated if self.frogpilot_toggles.goat_scream_alert else EventName.steerSaturated) self.steer_saturated_event_triggered = True else: self.steer_saturated_event_triggered = False @@ -730,7 +730,7 @@ class Controls: self.always_on_lateral_active &= not (CS.brakePressed and CS.vEgo < self.frogpilot_toggles.always_on_lateral_pause_speed) or CS.standstill self.always_on_lateral_active = bool(self.always_on_lateral_active) - if self.frogpilot_toggles.conditional_experimental_mode or self.frogpilot_toggles.slc_fallback_experimental: + if self.frogpilot_toggles.conditional_experimental_mode or self.frogpilot_toggles.slc_fallback_experimental_mode: self.experimental_mode = self.sm['frogpilotPlan'].experimentalMode if any(be.pressed and be.type == FrogPilotButtonType.lkas for be in CS.buttonEvents): @@ -814,7 +814,7 @@ class Controls: if self.enabled: clear_event_types.add(ET.NO_ENTRY) - alerts = self.events.create_alerts(self.current_alert_types, [self.CP, CS, self.sm, self.is_metric, self.soft_disable_timer]) + alerts = self.events.create_alerts(self.current_alert_types, [self.CP, CS, self.sm, self.is_metric, self.soft_disable_timer, self.frogpilot_toggles]) self.AM.add_many(self.sm.frame, alerts) current_alert = self.AM.process_alerts(self.sm.frame, clear_event_types) if current_alert: @@ -941,11 +941,8 @@ class Controls: time.sleep(0.1) # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False + if self.sm['frogpilotPlan'].togglesUpdated: + self.frogpilot_toggles = get_frogpilot_toggles() def controlsd_thread(self): e = threading.Event() diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py index 2089bb55..0f3afa95 100644 --- a/selfdrive/controls/lib/desire_helper.py +++ b/selfdrive/controls/lib/desire_helper.py @@ -68,7 +68,7 @@ class DesireHelper: self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none self.turn_direction = TurnDirection.none - elif one_blinker and below_lane_change_speed and not carstate.standstill and frogpilot_toggles.turn_desires: + elif one_blinker and below_lane_change_speed and not carstate.standstill and frogpilot_toggles.use_turn_desires: self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none self.turn_direction = TurnDirection.turnLeft if carstate.leftBlinker else TurnDirection.turnRight diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index b0ccd98c..71461905 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -4,6 +4,7 @@ import math import os from enum import IntEnum from collections.abc import Callable +from types import SimpleNamespace from cereal import log, car import cereal.messaging as messaging @@ -212,31 +213,31 @@ AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, def soft_disable_alert(alert_text_2: str) -> AlertCallbackType: - def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: + def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: if soft_disable_time < int(0.5 / DT_CTRL): return ImmediateDisableAlert(alert_text_2) return SoftDisableAlert(alert_text_2) return func def user_soft_disable_alert(alert_text_2: str) -> AlertCallbackType: - def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: + def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: if soft_disable_time < int(0.5 / DT_CTRL): return ImmediateDisableAlert(alert_text_2) return UserSoftDisableAlert(alert_text_2) return func -def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: branch = get_short_branch() # Ensure get_short_branch is cached to avoid lags on startup if "REPLAY" in os.environ: branch = "replay" return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt) -def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage") -def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: return Alert( f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}", "", @@ -244,7 +245,7 @@ def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.S Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4) -def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: first_word = 'Recalibration' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else 'Calibration' return Alert( f"{first_word} in Progress: {sm['liveCalibration'].calPerc:.0f}%", @@ -253,54 +254,39 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2) -def torque_nn_load_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - model_name = Params().get("NNFFModelName", encoding='utf-8') - if model_name == "": - return Alert( - "NNFF Torque Controller not available", - "Donate logs to Twilsonco to get your car supported!", - AlertStatus.userPrompt, AlertSize.mid, - Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 10.0) - else: - return Alert( - "NNFF Torque Controller loaded", - model_name, - AlertStatus.frogpilot, AlertSize.mid, - Priority.LOW, VisualAlert.none, AudibleAlert.engage, 5.0) - # *** debug alerts *** -def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: full_perc = round(100. - sm['deviceState'].freeSpacePercent) return NormalPermanentAlert("Out of Storage", f"{full_perc}% full") -def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: mdl = sm['modelV2'].velocity.x[0] if len(sm['modelV2'].velocity.x) else math.nan err = CS.vEgo - mdl msg = f"Speed Error: {err:.1f} m/s" return NoEntryAlert(msg, alert_text_1="Posenet Speed Invalid") -def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning] msg = ', '.join(not_running) return NoEntryAlert(msg, alert_text_1="Process Not Running") -def comm_issue_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def comm_issue_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: bs = [s for s in sm.data.keys() if not sm.all_checks([s, ])] msg = ', '.join(bs[:4]) # can't fit too many on one line return NoEntryAlert(msg, alert_text_1="Communication Issue Between Processes") -def camera_malfunction_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def camera_malfunction_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: all_cams = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') bad_cams = [s.replace('State', '') for s in all_cams if s in sm.data.keys() and not sm.all_checks([s, ])] return NormalPermanentAlert("Camera Malfunction", ', '.join(bad_cams)) -def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: rpy = sm['liveCalibration'].rpyCalib yaw = math.degrees(rpy[2] if len(rpy) == 3 else math.nan) pitch = math.degrees(rpy[1] if len(rpy) == 3 else math.nan) @@ -308,34 +294,34 @@ def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging return NormalPermanentAlert("Calibration Invalid", angles) -def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: cpu = max(sm['deviceState'].cpuTempC, default=0.) gpu = max(sm['deviceState'].gpuTempC, default=0.) temp = max((cpu, gpu, sm['deviceState'].memoryTempC)) return NormalPermanentAlert("System Overheated", f"{temp:.0f} °C") -def low_memory_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def low_memory_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: return NormalPermanentAlert("Low Memory", f"{sm['deviceState'].memoryUsagePercent}% used") -def high_cpu_usage_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def high_cpu_usage_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: x = max(sm['deviceState'].cpuUsagePercent, default=0.) return NormalPermanentAlert("High CPU Usage", f"{x}% used") -def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: return NormalPermanentAlert("Driving Model Lagging", f"{sm['modelV2'].frameDropPerc:.1f}% frames dropped") -def wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: text = "Enable Adaptive Cruise to Engage" if CP.carName == "honda": text = "Enable Main Switch to Engage" return NoEntryAlert(text) -def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: +def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: axes = sm['testJoystick'].axes gb, steer = list(axes)[:2] if len(axes) else (0., 0.) vals = f"Gas: {round(gb * 100.)}%, Steer: {round(steer * 100.)}%" @@ -343,11 +329,22 @@ def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, # FrogPilot Alerts -def custom_startup_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - params = Params() - return StartupAlert(params.get("StartupMessageTop", encoding='utf-8') or "", params.get("StartupMessageBottom", encoding='utf-8') or "", alert_status=AlertStatus.frogpilot) +def custom_startup_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: + return StartupAlert(frogpilot_toggles.startup_alert_top, frogpilot_toggles.startup_alert_bottom, alert_status=AlertStatus.frogpilot) -def holiday_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: + +def forcing_stop_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: + model_length = sm['frogpilotPlan'].forcingStopLength + model_length_msg = f"{model_length:.1f} meters" if metric else f"{model_length * CV.METER_TO_FOOT:.1f} feet" + + return Alert( + f"Forcing the car to stop in {model_length_msg}", + "Press the gas pedal or 'Resume' button to override", + AlertStatus.frogpilot, AlertSize.mid, + Priority.MID, VisualAlert.none, AudibleAlert.prompt, 1.) + + +def holiday_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: holiday_messages = { "new_years": ("Happy New Year! 🎉", "newYearsDayAlert"), "valentines": ("Happy Valentine's Day! ❤️", "valentinesDayAlert"), @@ -362,7 +359,7 @@ def holiday_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, "christmas_week": ("Merry Christmas! 🎄", "christmasAlert") } - holiday_name = Params().get("CurrentHolidayTheme", encoding='utf-8') + holiday_name = frogpilot_toggles.current_holiday_theme message, alert_type = holiday_messages.get(holiday_name, ("", "")) return Alert( @@ -371,7 +368,8 @@ def holiday_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, AlertStatus.normal, AlertSize.small, Priority.LOWEST, VisualAlert.none, AudibleAlert.engage, 5.) -def no_lane_available_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: + +def no_lane_available_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: lane_width = sm['frogpilotPlan'].laneWidthLeft if CS.leftBlinker else sm['frogpilotPlan'].laneWidthRight lane_width_msg = f"{lane_width:.1f} meters" if metric else f"{lane_width * CV.METER_TO_FOOT:.1f} feet" @@ -381,6 +379,23 @@ def no_lane_available_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.S AlertStatus.normal, AlertSize.mid, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2) + +def torque_nn_load_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, frogpilot_toggles: SimpleNamespace) -> Alert: + model_name = Params().get("NNFFModelName", encoding='utf-8') + if model_name == "": + return Alert( + "NNFF Torque Controller not available", + "Donate logs to Twilsonco to get your car supported!", + AlertStatus.userPrompt, AlertSize.mid, + Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 10.0) + else: + return Alert( + "NNFF Torque Controller loaded", + model_name, + AlertStatus.frogpilot, AlertSize.mid, + Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.0) + + EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { # ********** events with no alerts ********** @@ -1020,11 +1035,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { }, EventName.forcingStop: { - ET.WARNING: Alert( - "Forcing the car to stop", - "Press the gas pedal or 'Resume' button to override", - AlertStatus.frogpilot, AlertSize.mid, - Priority.MID, VisualAlert.none, AudibleAlert.prompt, 1.), + ET.WARNING: forcing_stop_alert, }, EventName.goatSteerSaturated: { @@ -1072,7 +1083,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { "openpilot crashed", "Please post the 'Error Log' in the FrogPilot Discord!", AlertStatus.normal, AlertSize.mid, - Priority.HIGH, VisualAlert.none, AudibleAlert.none, 10.), + Priority.HIGHEST, VisualAlert.none, AudibleAlert.prompt, 10.), }, EventName.pedalInterceptorNoBrake: { @@ -1091,6 +1102,14 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 3.), }, + EventName.thisIsFineSteerSaturated: { + ET.WARNING: Alert( + "This is fine", + "☕", + AlertStatus.userPrompt, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.thisIsFine, 2.), + }, + EventName.torqueNNLoad: { ET.PERMANENT: torque_nn_load_alert, }, diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index b9cd1907..a1445743 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -326,10 +326,10 @@ class LongitudinalMpc: lead_xv = np.column_stack((x_lead_traj, v_lead_traj)) return lead_xv - def process_lead(self, lead, increased_distance=0): + def process_lead(self, lead): v_ego = self.x0[1] if lead is not None and lead.status: - x_lead = lead.dRel - increased_distance + x_lead = lead.dRel v_lead = lead.vLead a_lead = lead.aLeadK a_lead_tau = lead.aLeadTau @@ -355,12 +355,11 @@ class LongitudinalMpc: self.cruise_min_a = min_a self.max_a = max_a - def update(self, lead_one, lead_two, v_cruise, x, v, a, j, radarless_model, t_follow, trafficModeActive, frogpilot_toggles, personality=log.LongitudinalPersonality.standard): + def update(self, lead_one, lead_two, v_cruise, x, v, a, j, radarless_model, t_follow, trafficModeActive, personality=log.LongitudinalPersonality.standard): v_ego = self.x0[1] self.status = lead_one.status or lead_two.status - increased_distance = max(frogpilot_toggles.increase_stopped_distance + min(10 - v_ego, 0), 0) if not trafficModeActive else 0 - lead_xv_0 = self.process_lead(lead_one, increased_distance) + lead_xv_0 = self.process_lead(lead_one) lead_xv_1 = self.process_lead(lead_two) # To estimate a safe distance from a moving lead, we calculate how much stopping @@ -370,7 +369,8 @@ class LongitudinalMpc: lead_1_obstacle = lead_xv_1[:,0] + get_stopped_equivalence_factor(lead_xv_1[:,1]) self.params[:,0] = ACCEL_MIN - self.params[:,1] = self.max_a + # negative accel constraint causes problems because negative speed is not allowed + self.params[:,1] = max(0.0, self.max_a) # Update in ACC mode or ACC/e2e blend if self.mode == 'acc': @@ -379,6 +379,7 @@ class LongitudinalMpc: # Fake an obstacle for cruise, this ensures smooth acceleration to set speed # when the leads are no factor. v_lower = v_ego + (T_IDXS * self.cruise_min_a * 1.05) + # TODO does this make sense when max_a is negative? v_upper = v_ego + (T_IDXS * self.max_a * 1.05) v_cruise_clipped = np.clip(v_cruise * np.ones(N+1), v_lower, diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index c087005b..0280f3e9 100644 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -22,7 +22,7 @@ A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6] A_CRUISE_MAX_BP = [0., 10.0, 25., 40.] CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N] ALLOW_THROTTLE_THRESHOLD = 0.5 -ACCEL_LIMIT_MARGIN = 0.05 +MIN_ALLOW_THROTTLE_SPEED = 2.5 # Lookup table for turns _A_TOTAL_MAX_V = [1.7, 3.2] @@ -58,7 +58,10 @@ def get_accel_from_plan(CP, speeds, accels): a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, accels) v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds) - a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now + if v_target != v_target_now: + a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now + else: + a_target = a_target_now v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds) else: @@ -183,7 +186,7 @@ class LongitudinalPlanner: throttle_prob = 1.0 return x, v, a, j, throttle_prob - def update(self, radarless_model, secretgoodopenpilot_model, sm, frogpilot_toggles): + def update(self, classic_model, radarless_model, sm, frogpilot_toggles): self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc' if len(sm['carControl'].orientationNED) == 3: @@ -209,7 +212,8 @@ class LongitudinalPlanner: accel_limits = [sm['frogpilotPlan'].minAcceleration, sm['frogpilotPlan'].maxAcceleration] if self.mpc.mode == 'acc': - accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngleDeg, accel_limits, self.CP) + steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg + accel_limits_turns = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_limits, self.CP) else: accel_limits_turns = [ACCEL_MIN, ACCEL_MAX] @@ -223,12 +227,13 @@ class LongitudinalPlanner: # Compute model v_ego error self.v_model_error = get_speed_error(sm['modelV2'], v_ego) x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'], self.v_model_error, v_ego, frogpilot_toggles.taco_tune) - self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD + # Don't clip at low speeds since throttle_prob doesn't account for creep + self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED - if not self.allow_throttle and v_ego > 5.0 and secretgoodopenpilot_model: # Don't clip at low speeds since throttle_prob doesn't account for creep - # MPC breaks when accel limits would cause negative velocity within the MPC horizon, so we clip the max accel limit at vEgo/T_MAX plus a bit of margin - clipped_accel_coast = max(accel_coast, accel_limits_turns[0], -v_ego / T_IDXS_MPC[-1] + ACCEL_LIMIT_MARGIN) - accel_limits_turns[1] = min(accel_limits_turns[1], clipped_accel_coast) + if not self.allow_throttle and not classic_model: + clipped_accel_coast = max(accel_coast, accel_limits_turns[0]) + clipped_accel_coast_interp = interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_limits_turns[1], clipped_accel_coast]) + accel_limits_turns[1] = min(accel_limits_turns[1], clipped_accel_coast_interp) if force_slow_decel: v_cruise = 0.0 @@ -242,8 +247,9 @@ class LongitudinalPlanner: lead_states = [self.lead_one, self.lead_two] for index in range(len(lead_states)): if len(model_leads) > index: + distance_offset = max(frogpilot_toggles.increased_stopped_distance + min(10 - v_ego, 0), 0) if not sm['frogpilotCarState'].trafficModeActive else 0 model_lead = model_leads[index] - lead_states[index].update(model_lead.x[0], model_lead.y[0], model_lead.v[0], model_lead.a[0], model_lead.prob) + lead_states[index].update(model_lead.x[0] - distance_offset, model_lead.y[0], model_lead.v[0], model_lead.a[0], model_lead.prob) else: lead_states[index].reset() else: @@ -254,7 +260,7 @@ class LongitudinalPlanner: self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1]) self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) self.mpc.update(self.lead_one, self.lead_two, sm['frogpilotPlan'].vCruise, x, v, a, j, radarless_model, sm['frogpilotPlan'].tFollow, - sm['frogpilotCarState'].trafficModeActive, frogpilot_toggles, personality=sm['controlsState'].personality) + sm['frogpilotCarState'].trafficModeActive, personality=sm['controlsState'].personality) self.a_desired_trajectory_full = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.a_solution) self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution) diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 3bae4ca0..3c8f51ab 100644 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -6,7 +6,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner import cereal.messaging as messaging -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles def publish_ui_plan(sm, pm, longitudinal_planner): ui_send = messaging.new_message('uiPlan') @@ -30,31 +30,26 @@ def plannerd_thread(): longitudinal_planner = LongitudinalPlanner(CP) pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan']) - sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2', 'frogpilotCarControl', 'frogpilotCarState', 'frogpilotPlan'], + sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', + 'frogpilotCarControl', 'frogpilotCarState', 'frogpilotPlan'], poll='modelV2', ignore_avg_freq=['radarState']) # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + frogpilot_toggles = get_frogpilot_toggles(True) + classic_model = frogpilot_toggles.classic_model radarless_model = frogpilot_toggles.radarless_model - secretgoodopenpilot_model = frogpilot_toggles.secretgoodopenpilot_model - - update_toggles = False while True: sm.update() if sm.updated['modelV2']: - longitudinal_planner.update(radarless_model, secretgoodopenpilot_model, sm, frogpilot_toggles) + longitudinal_planner.update(classic_model, radarless_model, sm, frogpilot_toggles) longitudinal_planner.publish(sm, pm) publish_ui_plan(sm, pm, longitudinal_planner) # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - update_toggles = True - elif update_toggles: - FrogPilotVariables.update_frogpilot_params() - update_toggles = False + if sm['frogpilotPlan'].togglesUpdated: + frogpilot_toggles = get_frogpilot_toggles() def main(): plannerd_thread() diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 2f44a8d6..9249d623 100644 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -2,6 +2,7 @@ import importlib import math from collections import deque +from types import SimpleNamespace from typing import Any import capnp @@ -13,7 +14,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.common.simple_kalman import KF1D -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles # Default lead acceleration decay set to 50% at 1s _LEAD_ACCEL_TAU = 1.5 @@ -108,6 +109,19 @@ class Track: "radarTrackId": self.identifier, } + def potential_adjacent_lead(self, far: bool, lane_width: float, left: bool, model_data: capnp._DynamicStructReader): + adjacent_lane_max = float('inf') if far else lane_width * 1.5 + adjacent_lane_min = max(lane_width * 1.5, 4.5) if far else max(lane_width * 0.5, 1.5) + + y_delta = self.yRel + interp(self.dRel, model_data.position.x, model_data.position.y) + + if left and adjacent_lane_min < y_delta < adjacent_lane_max: + return True + elif not left and adjacent_lane_min < -y_delta < adjacent_lane_max: + return True + else: + return False + def potential_low_speed_lead(self, v_ego: float): # stop for stuff in front of you and low speed, even without model confirmation # Radar points closer than 0.75, are almost always glitches on toyota radars @@ -168,9 +182,9 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capnp._DynamicStructReader, - model_v_ego: float, lead_detection_threshold: float, low_speed_override: bool = True) -> dict[str, Any]: + model_v_ego: float, frogpilot_toggles: SimpleNamespace, frogpilotCarState: capnp._DynamicStructReader, low_speed_override: bool = True) -> dict[str, Any]: # Determine leads, this is where the essential logic happens - if len(tracks) > 0 and ready and lead_msg.prob > lead_detection_threshold: + if len(tracks) > 0 and ready and lead_msg.prob > frogpilot_toggles.lead_detection_probability: track = match_vision_to_track(v_ego, lead_msg, tracks) else: track = None @@ -178,7 +192,7 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn lead_dict = {'status': False} if track is not None: lead_dict = track.get_RadarState(lead_msg.prob) - elif (track is None) and ready and (lead_msg.prob > lead_detection_threshold): + elif (track is None) and ready and (lead_msg.prob > frogpilot_toggles.lead_detection_probability): lead_dict = get_RadarState_from_vision(lead_msg, v_ego, model_v_ego) if low_speed_override: @@ -190,11 +204,25 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn if (not lead_dict['status']) or (closest_track.dRel < lead_dict['dRel']): lead_dict = closest_track.get_RadarState() + if 'dRel' in lead_dict: + lead_dict['dRel'] -= max(frogpilot_toggles.increased_stopped_distance + min(10 - v_ego, 0), 0) if not frogpilotCarState.trafficModeActive else 0 + + return lead_dict + + +def get_lead_adjacent(tracks: dict[int, Track], model_data: capnp._DynamicStructReader, lane_width: float, left: bool = True, far: bool = False) -> dict[str, Any]: + lead_dict = {'status': False} + + adjacent_tracks = [c for c in tracks.values() if c.vLead > 1 and c.potential_adjacent_lead(far, lane_width, left, model_data)] + if len(adjacent_tracks) > 0: + closest_track = min(adjacent_tracks, key=lambda c: c.dRel) + lead_dict = closest_track.get_RadarState() + return lead_dict class RadarD: - def __init__(self, radar_ts: float, delay: int = 0): + def __init__(self, frogpilot_toggles, radar_ts: float, delay: int = 0): self.points: dict[int, tuple[float, float, float]] = {} self.current_time = 0.0 @@ -213,12 +241,9 @@ class RadarD: self.ready = False # FrogPilot variables - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + self.frogpilot_toggles = frogpilot_toggles - self.velocity_model = self.frogpilot_toggles.velocity_model - - self.update_toggles = False + self.classic_model = self.frogpilot_toggles.classic_model def update(self, sm: messaging.SubMaster, rr): self.ready = sm.seen['modelV2'] @@ -263,23 +288,26 @@ class RadarD: self.radar_state.radarErrors = list(radar_errors) self.radar_state.carStateMonoTime = sm.logMonoTime['carState'] - if self.velocity_model and len(sm['modelV2'].velocity.x): - model_v_ego = sm['modelV2'].velocity.x[0] - elif len(sm['modelV2'].temporalPose.trans): + if self.classic_model and len(sm['modelV2'].temporalPose.trans): model_v_ego = sm['modelV2'].temporalPose.trans[0] + elif len(sm['modelV2'].velocity.x): + model_v_ego = sm['modelV2'].velocity.x[0] else: model_v_ego = self.v_ego leads_v3 = sm['modelV2'].leadsV3 if len(leads_v3) > 1: - self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, self.frogpilot_toggles.lead_detection_threshold, low_speed_override=True) - self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, self.frogpilot_toggles.lead_detection_threshold, low_speed_override=False) + self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, self.frogpilot_toggles, sm['frogpilotCarState'], low_speed_override=True) + self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, self.frogpilot_toggles, sm['frogpilotCarState'], low_speed_override=False) + + if self.frogpilot_toggles.adjacent_lead_tracking and self.ready: + self.radar_state.leadLeft = get_lead_adjacent(self.tracks, sm['modelV2'], sm['frogpilotPlan'].laneWidthLeft, left=True) + self.radar_state.leadLeftFar = get_lead_adjacent(self.tracks, sm['modelV2'], sm['frogpilotPlan'].laneWidthLeft, left=True, far=True) + self.radar_state.leadRight = get_lead_adjacent(self.tracks, sm['modelV2'], sm['frogpilotPlan'].laneWidthRight, left=False) + self.radar_state.leadRightFar = get_lead_adjacent(self.tracks, sm['modelV2'], sm['frogpilotPlan'].laneWidthRight, left=False, far=True) # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False + if sm['frogpilotPlan'].togglesUpdated: + self.frogpilot_toggles = get_frogpilot_toggles() def publish(self, pm: messaging.PubMaster, lag_ms: float): assert self.radar_state is not None @@ -348,14 +376,14 @@ def main(): RI = RadarInterface(CP) rk = Ratekeeper(1.0 / CP.radarTimeStep, print_delay_threshold=None) - RD = RadarD(CP.radarTimeStep, RI.delay) # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + frogpilot_toggles = get_frogpilot_toggles(True) + + RD = RadarD(frogpilot_toggles, CP.radarTimeStep, RI.delay) if not frogpilot_toggles.radarless_model: - sm = messaging.SubMaster(['modelV2', 'carState'], frequency=int(1./DT_CTRL)) + sm = messaging.SubMaster(['modelV2', 'carState', 'frogpilotCarState', 'frogpilotPlan'], frequency=int(1./DT_CTRL)) pm = messaging.PubMaster(['radarState', 'liveTracks']) while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) diff --git a/selfdrive/frogpilot/assets/active_theme/colors/colors.json b/selfdrive/frogpilot/assets/active_theme/colors/colors.json index 80e70f35..bf527d51 100644 --- a/selfdrive/frogpilot/assets/active_theme/colors/colors.json +++ b/selfdrive/frogpilot/assets/active_theme/colors/colors.json @@ -23,12 +23,6 @@ "blue": 54, "alpha": 242 }, - "RoadEdges": { - "red": 23, - "green": 134, - "blue": 68, - "alpha": 242 - }, "Sidebar1": { "red": 23, "green": 134, diff --git a/selfdrive/frogpilot/assets/download_functions.py b/selfdrive/frogpilot/assets/download_functions.py index 9057c2db..0a642e53 100644 --- a/selfdrive/frogpilot/assets/download_functions.py +++ b/selfdrive/frogpilot/assets/download_functions.py @@ -1,7 +1,7 @@ import os import requests -from openpilot.selfdrive.frogpilot.frogpilot_functions import delete_file, is_url_pingable +from openpilot.selfdrive.frogpilot.frogpilot_utilities import delete_file, is_url_pingable GITHUB_URL = "https://raw.githubusercontent.com/FrogAi/FrogPilot-Resources/" GITLAB_URL = "https://gitlab.com/FrogAi/FrogPilot-Resources/-/raw/" @@ -44,10 +44,10 @@ def handle_error(destination, error_message, error, download_param, progress_par def handle_request_error(error, destination, download_param, progress_param, params_memory): error_map = { - requests.HTTPError: lambda e: f"Server error ({e.response.status_code})" if e.response else "Server error.", requests.ConnectionError: "Connection dropped.", - requests.Timeout: "Download timed out.", - requests.RequestException: "Network request error. Check connection." + requests.HTTPError: lambda e: f"Server error ({e.response.status_code})" if e.response else "Server error.", + requests.RequestException: "Network request error. Check connection.", + requests.Timeout: "Download timed out." } error_message = error_map.get(type(error), "Unexpected error.") @@ -75,19 +75,6 @@ def get_repository_url(): return GITLAB_URL return None -def link_valid(url): - try: - response = requests.head(url, allow_redirects=True, timeout=5) - response.raise_for_status() - return True - except requests.HTTPError as e: - if e.response.status_code != 404: - handle_request_error(e, None, None, None, None) - return False - except Exception as e: - handle_request_error(e, None, None, None, None) - return False - def verify_download(file_path, url, initial_download=True): remote_file_size = get_remote_file_size(url) if remote_file_size is None: diff --git a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/colors/colors.json b/selfdrive/frogpilot/assets/holiday_themes/halloween_week/colors/colors.json index 9fca3523..91690ba0 100644 --- a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/colors/colors.json +++ b/selfdrive/frogpilot/assets/holiday_themes/halloween_week/colors/colors.json @@ -23,12 +23,6 @@ "blue": 255, "alpha": 255 }, - "RoadEdges": { - "red": 242, - "green": 117, - "blue": 3, - "alpha": 255 - }, "Sidebar1": { "red": 134, "green": 47, diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/colors/colors.json b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/colors/colors.json new file mode 100644 index 00000000..bf527d51 --- /dev/null +++ b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/colors/colors.json @@ -0,0 +1,44 @@ +{ + "LaneLines": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + }, + "LeadMarker": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + }, + "Path": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + }, + "PathEdge": { + "red": 18, + "green": 107, + "blue": 54, + "alpha": 242 + }, + "Sidebar1": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + }, + "Sidebar2": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + }, + "Sidebar3": { + "red": 23, + "green": 134, + "blue": 68, + "alpha": 242 + } +} diff --git a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/aggressive.gif b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/aggressive.gif similarity index 100% rename from selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/aggressive.gif rename to selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/aggressive.gif diff --git a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/relaxed.gif b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/relaxed.gif similarity index 100% rename from selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/relaxed.gif rename to selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/relaxed.gif diff --git a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/standard.gif b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/standard.gif similarity index 100% rename from selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/standard.gif rename to selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/standard.gif diff --git a/selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/traffic.gif b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/traffic.gif similarity index 100% rename from selfdrive/frogpilot/assets/holiday_themes/halloween_week/distance_icons/traffic.gif rename to selfdrive/frogpilot/assets/holiday_themes/world_frog_day/distance_icons/traffic.gif diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/icons/button_home.gif b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/icons/button_home.gif index 6b20a726..133d8d34 100644 Binary files a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/icons/button_home.gif and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/icons/button_home.gif differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/traditional_100 b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/traditional_100 new file mode 100644 index 00000000..e69de29b diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_1.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_1.png index 43e0b446..8c2f7a54 100644 Binary files a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_1.png and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_1.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_2.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_2.png index e8e14797..3c7d2d9e 100644 Binary files a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_2.png and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_2.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_3.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_3.png index b59b003f..b495eeae 100644 Binary files a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_3.png and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_3.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_4.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_4.png index c3c1d204..024a0b03 100644 Binary files a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_4.png and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_4.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_5.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_5.png new file mode 100644 index 00000000..91eb05f1 Binary files /dev/null and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_5.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_6.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_6.png new file mode 100644 index 00000000..3c7d2d9e Binary files /dev/null and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_6.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_blindspot.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_blindspot.png new file mode 100644 index 00000000..b721266f Binary files /dev/null and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/signals/turn_signal_blindspot.png differ diff --git a/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/steering_wheel/wheel.png b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/steering_wheel/wheel.png new file mode 100644 index 00000000..71225598 Binary files /dev/null and b/selfdrive/frogpilot/assets/holiday_themes/world_frog_day/steering_wheel/wheel.png differ diff --git a/selfdrive/frogpilot/assets/model_manager.py b/selfdrive/frogpilot/assets/model_manager.py index b4913ac6..2085539c 100644 --- a/selfdrive/frogpilot/assets/model_manager.py +++ b/selfdrive/frogpilot/assets/model_manager.py @@ -1,26 +1,31 @@ import json import os import re +import requests import shutil import time +import urllib.parse import urllib.request from openpilot.common.basedir import BASEDIR -from openpilot.common.params import Params, UnknownKeyName +from openpilot.common.params import Params -from openpilot.selfdrive.frogpilot.assets.download_functions import GITHUB_URL, GITLAB_URL, download_file, get_remote_file_size, get_repository_url, handle_error, handle_request_error, verify_download -from openpilot.selfdrive.frogpilot.frogpilot_functions import MODELS_PATH, delete_file +from openpilot.selfdrive.frogpilot.assets.download_functions import GITHUB_URL, GITLAB_URL, download_file, get_repository_url, handle_error, handle_request_error, verify_download +from openpilot.selfdrive.frogpilot.frogpilot_functions import MODELS_PATH +from openpilot.selfdrive.frogpilot.frogpilot_utilities import delete_file -VERSION = "v9" +VERSION = "v10" DEFAULT_MODEL = "north-dakota" DEFAULT_MODEL_NAME = "North Dakota (Default)" + def process_model_name(model_name): cleaned_name = re.sub(r'[🗺️👀📡]', '', model_name) cleaned_name = re.sub(r'[^a-zA-Z0-9()-]', '', cleaned_name) return cleaned_name.replace(' ', '').replace('(Default)', '').replace('-', '') + class ModelManager: def __init__(self): self.params = Params() @@ -30,6 +35,63 @@ class ModelManager: self.download_param = "ModelToDownload" self.download_progress_param = "ModelDownloadProgress" + @staticmethod + def fetch_models(url): + try: + with urllib.request.urlopen(url, timeout=10) as response: + return json.loads(response.read().decode('utf-8'))['models'] + except Exception as error: + handle_request_error(error, None, None, None, None) + return [] + + @staticmethod + def fetch_all_model_sizes(repo_url): + project_path = "FrogAi/FrogPilot-Resources" + branch = "Models" + + if "github" in repo_url: + api_url = f"https://api.github.com/repos/{project_path}/contents?ref={branch}" + elif "gitlab" in repo_url: + api_url = f"https://gitlab.com/api/v4/projects/{urllib.parse.quote_plus(project_path)}/repository/tree?ref={branch}" + else: + raise ValueError(f"Unsupported repository URL format: {repo_url}. Supported formats are GitHub and GitLab URLs.") + + try: + response = requests.get(api_url) + response.raise_for_status() + thneed_files = [file for file in response.json() if file['name'].endswith('.thneed')] + + if "gitlab" in repo_url: + model_sizes = {} + for file in thneed_files: + file_path = file['path'] + metadata_url = f"https://gitlab.com/api/v4/projects/{urllib.parse.quote_plus(project_path)}/repository/files/{urllib.parse.quote_plus(file_path)}/raw?ref={branch}" + metadata_response = requests.head(metadata_url) + metadata_response.raise_for_status() + model_sizes[file['name'].replace('.thneed', '')] = int(metadata_response.headers.get('content-length', 0)) + return model_sizes + else: + return {file['name'].replace('.thneed', ''): file['size'] for file in thneed_files if 'size' in file} + + except requests.RequestException as e: + raise ConnectionError(f"Failed to fetch model sizes from {'GitHub' if 'github' in repo_url else 'GitLab'}: {e}") + + @staticmethod + def copy_default_model(): + classic_default_model_path = os.path.join(MODELS_PATH, f"{DEFAULT_MODEL}.thneed") + source_path = os.path.join(BASEDIR, "selfdrive", "classic_modeld", "models", "supercombo.thneed") + + if os.path.isfile(source_path): + shutil.copyfile(source_path, classic_default_model_path) + print(f"Copied the classic default model from {source_path} to {classic_default_model_path}") + + default_model_path = os.path.join(MODELS_PATH, "secret-good-openpilot.thneed") + source_path = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "supercombo.thneed") + + if os.path.isfile(source_path): + shutil.copyfile(source_path, default_model_path) + print(f"Copied the default model from {source_path} to {default_model_path}") + def handle_verification_failure(self, model, model_path): if self.params_memory.get_bool(self.cancel_download_param): return @@ -65,65 +127,53 @@ class ModelManager: else: self.handle_verification_failure(model_to_download, model_path) - def fetch_models(self, url): - try: - with urllib.request.urlopen(url, timeout=10) as response: - return json.loads(response.read().decode('utf-8'))['models'] - except Exception as error: - handle_request_error(error, None, None, None, None) - return [] + def queue_model_download(self, model, model_name=None): + while self.params_memory.get(self.download_param, encoding='utf-8'): + time.sleep(1) + + self.params_memory.put(self.download_param, model) + if model_name: + self.params_memory.put(self.download_progress_param, f"Downloading {model_name}...") def update_model_params(self, model_info, repo_url): - available_models, available_model_names, experimental_models, navigation_models, radarless_models, velocity_models = [], [], [], [], [], [] - + available_models = [] for model in model_info: available_models.append(model['id']) - available_model_names.append(model['name']) - - if model.get("e2e_longitudinal", False): - e2e_longitudinal_models.append(model['id']) - if model.get("experimental", False): - experimental_models.append(model['id']) - if model.get("gas_brake", False): - gas_brake_models.append(model['id']) - if model.get("velocity", False): - velocity_models.append(model['id']) - if "🗺️" in model['name']: - navigation_models.append(model['id']) - if "📡" not in model['name']: - radarless_models.append(model['id']) self.params.put_nonblocking("AvailableModels", ','.join(available_models)) - self.params.put_nonblocking("AvailableModelsNames", ','.join(available_model_names)) - self.params.put_nonblocking("ExperimentalModels", ','.join(experimental_models)) - self.params.put_nonblocking("NavigationModels", ','.join(navigation_models)) - self.params.put_nonblocking("RadarlessModels", ','.join(radarless_models)) - self.params.put_nonblocking("VelocityModels", ','.join(velocity_models)) + self.params.put_nonblocking("AvailableModelsNames", ','.join([model['name'] for model in model_info])) + self.params.put_nonblocking("ClassicModels", ','.join([model['id'] for model in model_info if model.get("classic_model", False)])) + self.params.put_nonblocking("ExperimentalModels", ','.join([model['id'] for model in model_info if model.get("experimental", False)])) + self.params.put_nonblocking("NavigationModels", ','.join([model['id'] for model in model_info if "🗺️" in model['name']])) + self.params.put_nonblocking("RadarlessModels", ','.join([model['id'] for model in model_info if "📡" not in model['name']])) print("Models list updated successfully.") if available_models: - models_downloaded = self.are_all_models_downloaded(available_models, available_model_names, repo_url) + models_downloaded = self.are_all_models_downloaded(available_models, repo_url) self.params.put_bool_nonblocking("ModelsDownloaded", models_downloaded) - def are_all_models_downloaded(self, available_models, available_model_names, repo_url): + def are_all_models_downloaded(self, available_models, repo_url): automatically_update_models = self.params.get_bool("AutomaticallyUpdateModels") all_models_downloaded = True + model_sizes = self.fetch_all_model_sizes(repo_url) download_queue = [] + for model in available_models: model_path = os.path.join(MODELS_PATH, f"{model}.thneed") - model_url = f"{repo_url}Models/{model}.thneed" + expected_size = model_sizes.get(model) + + if expected_size is None: + print(f"Size data for {model} not available.") + continue if os.path.isfile(model_path): - if automatically_update_models: - verify_result = verify_download(model_path, model_url, False) - if verify_result is None: - all_models_downloaded = False - elif not verify_result: - print(f"Model {model} is outdated. Re-downloading...") - delete_file(model_path) - download_queue.append(model) - all_models_downloaded = False + local_size = os.path.getsize(model_path) + if automatically_update_models and local_size != expected_size: + print(f"Model {model} is outdated. Re-downloading...") + delete_file(model_path) + download_queue.append(model) + all_models_downloaded = False else: if automatically_update_models: print(f"Model {model} isn't downloaded. Downloading...") @@ -135,14 +185,6 @@ class ModelManager: return all_models_downloaded - def queue_model_download(self, model, model_name=None): - while self.params_memory.get(self.download_param, encoding='utf-8'): - time.sleep(1) - - self.params_memory.put(self.download_param, model) - if model_name: - self.params_memory.put(self.download_progress_param, f"Downloading {model_name}...") - def validate_models(self): current_model = self.params.get("Model", encoding='utf-8') current_model_name = self.params.get("ModelName", encoding='utf-8') @@ -162,31 +204,11 @@ class ModelManager: for model_file in os.listdir(MODELS_PATH): model_name = model_file.replace(".thneed", "") if model_name not in available_models.split(','): - reason = "Model is not in the list of available models" if model_name == current_model: self.params.put_nonblocking("Model", DEFAULT_MODEL) self.params.put_nonblocking("ModelName", DEFAULT_MODEL_NAME) delete_file(os.path.join(MODELS_PATH, model_file)) - print(f"Deleted model file: {model_file} - Reason: {reason}") - - def copy_default_model(self): - default_model_path = os.path.join(MODELS_PATH, f"{DEFAULT_MODEL}.thneed") - source_path = os.path.join(BASEDIR, "selfdrive", "classic_modeld", "models", "supercombo.thneed") - - if os.path.isfile(source_path) and not os.path.isfile(default_model_path): - shutil.copyfile(source_path, default_model_path) - print(f"Copied default model from {source_path} to {default_model_path}") - else: - print(f"Source default model not found at {source_path}. Exiting...") - - sgo_model_path = os.path.join(MODELS_PATH, "secret-good-openpilot.thneed") - source_path = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "supercombo.thneed") - - if os.path.isfile(source_path) and not os.path.isfile(sgo_model_path): - shutil.copyfile(source_path, sgo_model_path) - print(f"Copied 'secret-good-openpilot' model from {source_path} to {sgo_model_path}") - else: - print(f"Source 'secret-good-openpilot' model not found at {source_path}. Exiting...") + print(f"Deleted model file: {model_file} - Reason: Model is not in the list of available models") def update_models(self, boot_run=False): if boot_run: @@ -197,12 +219,12 @@ class ModelManager: print("GitHub and GitLab are offline...") return + model_info = self.fetch_models(f"{repo_url}Versions/model_names_{VERSION}.json") + if model_info: + self.update_model_params(model_info, repo_url) + if boot_run: self.validate_models() - else: - model_info = self.fetch_models(f"{repo_url}Versions/model_names_{VERSION}.json") - if model_info: - self.update_model_params(model_info, repo_url) def download_all_models(self): repo_url = get_repository_url() @@ -230,10 +252,8 @@ class ModelManager: if not os.path.isfile(os.path.join(MODELS_PATH, f"{model}.thneed")): model_index = available_models.index(model) model_name = available_model_names[model_index] - cleaned_model_name = re.sub(r'[🗺️👀📡]', '', model_name).strip() print(f"Downloading model: {cleaned_model_name}") - self.queue_model_download(model, cleaned_model_name) while self.params_memory.get(self.download_param, encoding='utf-8'): diff --git a/selfdrive/frogpilot/assets/other_images/original_bg.jpg b/selfdrive/frogpilot/assets/other_images/original_bg.jpg deleted file mode 100644 index 13c36a7e..00000000 Binary files a/selfdrive/frogpilot/assets/other_images/original_bg.jpg and /dev/null differ diff --git a/selfdrive/frogpilot/assets/random_events/icons/this_is_fine.gif b/selfdrive/frogpilot/assets/random_events/icons/this_is_fine.gif new file mode 100644 index 00000000..3cc427f7 Binary files /dev/null and b/selfdrive/frogpilot/assets/random_events/icons/this_is_fine.gif differ diff --git a/selfdrive/frogpilot/assets/random_events/sounds/this_is_fine.wav b/selfdrive/frogpilot/assets/random_events/sounds/this_is_fine.wav new file mode 100644 index 00000000..e43f4e59 Binary files /dev/null and b/selfdrive/frogpilot/assets/random_events/sounds/this_is_fine.wav differ diff --git a/selfdrive/frogpilot/assets/theme_manager.py b/selfdrive/frogpilot/assets/theme_manager.py index dabf0608..1977a6ec 100644 --- a/selfdrive/frogpilot/assets/theme_manager.py +++ b/selfdrive/frogpilot/assets/theme_manager.py @@ -1,4 +1,5 @@ import glob +import json import os import re import requests @@ -11,12 +12,14 @@ from dateutil import easter from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params -from openpilot.selfdrive.frogpilot.assets.download_functions import GITHUB_URL, GITLAB_URL, download_file, get_repository_url, handle_error, handle_request_error, link_valid, verify_download -from openpilot.selfdrive.frogpilot.frogpilot_functions import ACTIVE_THEME_PATH, THEME_SAVE_PATH, update_frogpilot_toggles +from openpilot.selfdrive.frogpilot.assets.download_functions import GITHUB_URL, GITLAB_URL, download_file, get_repository_url, handle_error, handle_request_error, verify_download +from openpilot.selfdrive.frogpilot.frogpilot_functions import ACTIVE_THEME_PATH, THEME_SAVE_PATH +from openpilot.selfdrive.frogpilot.frogpilot_utilities import update_frogpilot_toggles CANCEL_DOWNLOAD_PARAM = "CancelThemeDownload" DOWNLOAD_PROGRESS_PARAM = "ThemeDownloadProgress" + def update_theme_asset(asset_type, theme, holiday_theme, params): save_location = os.path.join(ACTIVE_THEME_PATH, asset_type) @@ -49,6 +52,7 @@ def update_theme_asset(asset_type, theme, holiday_theme, params): shutil.copytree(asset_location, save_location) print(f"Copied {asset_location} to {save_location}") + def update_wheel_image(image, holiday_theme=None, random_event=True): wheel_save_location = os.path.join(ACTIVE_THEME_PATH, "steering_wheel") @@ -74,6 +78,7 @@ def update_wheel_image(image, holiday_theme=None, random_event=True): print(f"Copied {source_file} to {destination_file}") break + class ThemeManager: def __init__(self): self.params = Params() @@ -90,8 +95,83 @@ class ThemeManager: @staticmethod def is_within_week_of(target_date, now): start_of_week = target_date - timedelta(days=target_date.weekday()) - end_of_week = start_of_week + timedelta(days=6) - return start_of_week <= now <= end_of_week + return start_of_week <= now < target_date + + @staticmethod + def fetch_files(url): + try: + response = requests.get(url, timeout=10) + response.raise_for_status() + return [name for name in re.findall(r'href="[^"]*\/blob\/[^"]*\/([^"]*)"', response.text) if name.lower() != "license"] + except Exception as error: + handle_request_error(error, None, None, None, None) + return [] + + @staticmethod + def fetch_assets(repo_url): + repo = "FrogAi/FrogPilot-Resources" + branches = ["Themes", "Distance-Icons", "Steering-Wheels"] + + assets = { + "themes": {}, + "distance_icons": [], + "wheels": [] + } + + if "github" in repo_url: + base_api_url = "https://api.github.com/repos" + elif "gitlab" in repo_url: + base_api_url = "https://gitlab.com/api/v4/projects" + repo = repo.replace("/", "%2F") + else: + print(f"Unsupported repository URL: {repo_url}") + return assets + + for branch in branches: + if "github" in repo_url: + api_url = f"{base_api_url}/{repo}/git/trees/{branch}?recursive=1" + elif "gitlab" in repo_url: + api_url = f"{base_api_url}/{repo}/repository/tree?ref={branch}&recursive=true" + + try: + print(f"Fetching assets from branch '{branch}': {api_url}") + response = requests.get(api_url, timeout=10) + response.raise_for_status() + content = response.json() + + if "github" in repo_url: + items = content.get('tree', []) + elif "gitlab" in repo_url: + items = content + + for item in items: + if item["type"] != "blob": + continue + + item_path = item["path"].lower() + if branch == "Themes": + theme_name = item["path"].split('/')[0] + assets["themes"].setdefault(theme_name, set()) + if "icons" in item_path: + assets["themes"][theme_name].add("icons") + elif "signals" in item_path: + assets["themes"][theme_name].add("signals") + elif "sounds" in item_path: + assets["themes"][theme_name].add("sounds") + else: + assets["themes"][theme_name].add("colors") + + elif branch == "Distance-Icons": + assets["distance_icons"].append(item["path"]) + + elif branch == "Steering-Wheels": + assets["wheels"].append(item["path"]) + + except requests.exceptions.RequestException as error: + print(f"Error occurred when fetching from branch '{branch}': {error}") + + assets["themes"] = {k: list(v) for k, v in assets["themes"].items()} + return assets def update_holiday(self): now = date.today() @@ -150,6 +230,7 @@ class ThemeManager: "wheel_image": ("wheel_image", "stock") } + theme_changed = False for asset, (asset_type, current_value) in asset_mappings.items(): if current_value != self.previous_assets.get(asset) or current_holiday_theme != self.previous_assets.get("holiday_theme"): print(f"Updating {asset}: {asset_type} with value {current_holiday_theme if current_holiday_theme else current_value}") @@ -160,9 +241,13 @@ class ThemeManager: update_theme_asset(asset_type, current_value, current_holiday_theme, self.params) self.previous_assets[asset] = current_value + theme_changed = True - self.previous_assets["holiday_theme"] = current_holiday_theme - update_frogpilot_toggles() + if theme_changed: + if current_holiday_theme: + self.previous_assets["holiday_theme"] = current_holiday_theme + self.params_memory.put_bool("ThemeUpdated", True) + update_frogpilot_toggles() def extract_zip(self, zip_file, extract_path): print(f"Extracting {zip_file} to {extract_path}") @@ -242,26 +327,6 @@ class ThemeManager: self.handle_verification_failure(extentions, theme_component, theme_name, theme_param, download_path) - @staticmethod - def fetch_files(url): - try: - response = requests.get(url, timeout=10) - response.raise_for_status() - return [name for name in re.findall(r'href="[^"]*\/blob\/[^"]*\/([^"]*)"', response.text) if name.lower() != "license"] - except Exception as error: - handle_request_error(error, None, None, None, None) - return [] - - @staticmethod - def fetch_folders(url): - try: - response = requests.get(url, timeout=10) - response.raise_for_status() - return re.findall(r'href="[^"]*\/tree\/[^"]*\/([^"]*)"', response.text) - except Exception as error: - handle_request_error(error, None, None, None, None) - return [] - def update_theme_params(self, downloadable_colors, downloadable_distance_icons, downloadable_icons, downloadable_signals, downloadable_sounds, downloadable_wheels): def filter_existing_assets(assets, subfolder): existing_themes = { @@ -333,6 +398,7 @@ class ThemeManager: def update_themes(self, boot_run=False): if not os.path.exists(THEME_SAVE_PATH): + print(f"Theme save path does not exist: {THEME_SAVE_PATH}") return repo_url = get_repository_url() @@ -343,34 +409,34 @@ class ThemeManager: if boot_run: self.validate_themes() - if repo_url == GITHUB_URL: - base_url = "https://github.com/FrogAi/FrogPilot-Resources/blob/Themes/" - distance_icons_files = self.fetch_files("https://github.com/FrogAi/FrogPilot-Resources/blob/Distance-Icons") - wheel_files = self.fetch_files("https://github.com/FrogAi/FrogPilot-Resources/blob/Steering-Wheels") - else: - base_url = "https://gitlab.com/FrogAi/FrogPilot-Resources/-/blob/Themes/" - distance_icons_files = self.fetch_files("https://github.com/FrogAi/FrogPilot-Resources/blob/Distance-Icons") - wheel_files = self.fetch_files("https://gitlab.com/FrogAi/FrogPilot-Resources/-/blob/Steering-Wheels") + assets = self.fetch_assets(repo_url) - theme_folders = self.fetch_folders(base_url) downloadable_colors = [] downloadable_icons = [] downloadable_signals = [] downloadable_sounds = [] - for theme in theme_folders: + for theme, available_assets in assets["themes"].items(): theme_name = theme.replace('_', ' ').split('.')[0].title() + print(f"Checking theme: {theme_name}") - if link_valid(f"{base_url}{theme}/colors.zip"): + if "colors" in available_assets: downloadable_colors.append(theme_name) - if link_valid(f"{base_url}{theme}/icons.zip"): + if "icons" in available_assets: downloadable_icons.append(theme_name) - if link_valid(f"{base_url}{theme}/signals.zip"): + if "signals" in available_assets: downloadable_signals.append(theme_name) - if link_valid(f"{base_url}{theme}/sounds.zip"): + if "sounds" in available_assets: downloadable_sounds.append(theme_name) - downloadable_distance_icons = [distance_icons.replace('_', ' ').split('.')[0].title() for distance_icons in distance_icons_files] - downloadable_wheels = [wheel.replace('_', ' ').split('.')[0].title() for wheel in wheel_files] + downloadable_distance_icons = [distance_icon.replace('_', ' ').split('.')[0].title() for distance_icon in assets["distance_icons"]] + downloadable_wheels = [wheel.replace('_', ' ').split('.')[0].title() for wheel in assets["wheels"]] + + print(f"Downloadable Colors: {downloadable_colors}") + print(f"Downloadable Icons: {downloadable_icons}") + print(f"Downloadable Signals: {downloadable_signals}") + print(f"Downloadable Sounds: {downloadable_sounds}") + print(f"Downloadable Distance Icons: {downloadable_distance_icons}") + print(f"Downloadable Wheels: {downloadable_wheels}") self.update_theme_params(downloadable_colors, downloadable_distance_icons, downloadable_icons, downloadable_signals, downloadable_sounds, downloadable_wheels) diff --git a/selfdrive/frogpilot/assets/toggle_icons/advanced_quality_of_life.png b/selfdrive/frogpilot/assets/toggle_icons/advanced_quality_of_life.png deleted file mode 100644 index e84f90ac..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/advanced_quality_of_life.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_accessibility.png b/selfdrive/frogpilot/assets/toggle_icons/icon_accessibility.png new file mode 100644 index 00000000..cf80f5ef Binary files /dev/null and b/selfdrive/frogpilot/assets/toggle_icons/icon_accessibility.png differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced.png deleted file mode 100644 index 1b3c5239..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_calibration.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_calibration.png deleted file mode 100644 index 25e9f247..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_calibration.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_device.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_device.png index 6d577060..f849ec13 100644 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_device.png and b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_device.png differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png deleted file mode 100644 index 72a7e405..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_model.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_model.png deleted file mode 100644 index c299a1e7..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_model.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_personality.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_personality.png deleted file mode 100644 index 2ce09a56..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_personality.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_road.png b/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_road.png deleted file mode 100644 index 76513344..00000000 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_advanced_road.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_customization.png b/selfdrive/frogpilot/assets/toggle_icons/icon_customization.png new file mode 100644 index 00000000..8c2fa95c Binary files /dev/null and b/selfdrive/frogpilot/assets/toggle_icons/icon_customization.png differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_green_light.png b/selfdrive/frogpilot/assets/toggle_icons/icon_green_light.png index cb47d7a8..b0c06f82 100644 Binary files a/selfdrive/frogpilot/assets/toggle_icons/icon_green_light.png and b/selfdrive/frogpilot/assets/toggle_icons/icon_green_light.png differ diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_personality.png b/selfdrive/frogpilot/assets/toggle_icons/icon_personality.png new file mode 100644 index 00000000..4f552c59 Binary files /dev/null and b/selfdrive/frogpilot/assets/toggle_icons/icon_personality.png differ diff --git a/selfdrive/frogpilot/controls/frogpilot_planner.py b/selfdrive/frogpilot/controls/frogpilot_planner.py index 53789076..ad586694 100644 --- a/selfdrive/frogpilot/controls/frogpilot_planner.py +++ b/selfdrive/frogpilot/controls/frogpilot_planner.py @@ -12,7 +12,7 @@ from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_acceleration import Fr from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_events import FrogPilotEvents from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_following import FrogPilotFollowing from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_vcruise import FrogPilotVCruise -from openpilot.selfdrive.frogpilot.frogpilot_functions import MovingAverageCalculator, calculate_lane_width, calculate_road_curvature, update_frogpilot_toggles +from openpilot.selfdrive.frogpilot.frogpilot_utilities import MovingAverageCalculator, calculate_lane_width, calculate_road_curvature from openpilot.selfdrive.frogpilot.frogpilot_variables import CRUISING_SPEED, MODEL_LENGTH, NON_DRIVING_GEARS, PLANNER_TIME, THRESHOLD class FrogPilotPlanner: @@ -29,23 +29,21 @@ class FrogPilotPlanner: self.tracking_lead_mac = MovingAverageCalculator() self.lateral_check = False - self.lead_departing = False self.model_stopped = False self.slower_lead = False - self.taking_curve_quickly = False self.tracking_lead = False self.model_length = 0 self.road_curvature = 1 - self.tracking_lead_distance = 0 self.v_cruise = 0 def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState, frogpilotNavigation, modelData, radarless_model, radarState, frogpilot_toggles): if radarless_model: model_leads = list(modelData.leadsV3) if len(model_leads) > 0: + distance_offset = max(frogpilot_toggles.increased_stopped_distance + min(10 - v_ego, 0), 0) if not frogpilotCarState.trafficModeActive else 0 model_lead = model_leads[0] - self.lead_one.update(model_lead.x[0], model_lead.y[0], model_lead.v[0], model_lead.a[0], model_lead.prob) + self.lead_one.update(model_lead.x[0] - distance_offset, model_lead.y[0], model_lead.v[0], model_lead.a[0], model_lead.prob) else: self.lead_one.reset() else: @@ -55,41 +53,25 @@ class FrogPilotPlanner: v_ego = max(carState.vEgo, 0) v_lead = self.lead_one.vLead - driving_gear = carState.gearShifter not in NON_DRIVING_GEARS - - distance_offset = max(frogpilot_toggles.increase_stopped_distance + min(10 - v_ego, 0), 0) if not frogpilotCarState.trafficModeActive else 0 - lead_distance = self.lead_one.dRel - distance_offset - stopping_distance = STOP_DISTANCE + distance_offset - self.frogpilot_acceleration.update(controlsState, frogpilotCarState, v_cruise, v_ego, frogpilot_toggles) run_cem = frogpilot_toggles.conditional_experimental_mode or frogpilot_toggles.force_stops or frogpilot_toggles.green_light_alert or frogpilot_toggles.show_stopping_point - if run_cem and (controlsState.enabled or frogpilotCarControl.alwaysOnLateralActive) and driving_gear: - self.cem.update(carState, frogpilotNavigation, modelData, v_ego, v_lead, frogpilot_toggles) + if run_cem and (controlsState.enabled or frogpilotCarControl.alwaysOnLateralActive) and carState.gearShifter not in NON_DRIVING_GEARS: + self.cem.update(carState, frogpilotCarState, frogpilotNavigation, modelData, v_ego, v_lead, frogpilot_toggles) else: self.cem.stop_light_detected = False - self.frogpilot_events.update(carState, controlsState, frogpilotCarControl, frogpilotCarState, modelData, frogpilot_toggles) - self.frogpilot_following.update(carState.aEgo, controlsState, frogpilotCarState, lead_distance, stopping_distance, v_ego, v_lead, frogpilot_toggles) + self.frogpilot_events.update(carState, controlsState, frogpilotCarControl, frogpilotCarState, self.lead_one.dRel, modelData, v_lead, frogpilot_toggles) + self.frogpilot_following.update(carState.aEgo, controlsState, frogpilotCarState, self.lead_one.dRel, v_ego, v_lead, frogpilot_toggles) - check_lane_width = frogpilot_toggles.adjacent_lanes or frogpilot_toggles.adjacent_path_metrics or frogpilot_toggles.blind_spot_path or frogpilot_toggles.lane_detection - if check_lane_width and v_ego >= frogpilot_toggles.minimum_lane_change_speed: + check_lane_width = frogpilot_toggles.adjacent_paths or frogpilot_toggles.adjacent_path_metrics or frogpilot_toggles.blind_spot_path or frogpilot_toggles.lane_detection + if check_lane_width and v_ego >= frogpilot_toggles.minimum_lane_change_speed or frogpilot_toggles.adjacent_lead_tracking: self.lane_width_left = calculate_lane_width(modelData.laneLines[0], modelData.laneLines[1], modelData.roadEdges[0]) self.lane_width_right = calculate_lane_width(modelData.laneLines[3], modelData.laneLines[2], modelData.roadEdges[1]) else: self.lane_width_left = 0 self.lane_width_right = 0 - if frogpilot_toggles.lead_departing_alert and self.tracking_lead and driving_gear and carState.standstill: - if self.tracking_lead_distance == 0: - self.tracking_lead_distance = lead_distance - - self.lead_departing = lead_distance - self.tracking_lead_distance > 1 - self.lead_departing &= v_lead > 1 - else: - self.lead_departing = False - self.tracking_lead_distance = 0 - self.lateral_check = v_ego >= frogpilot_toggles.pause_lateral_below_speed self.lateral_check |= frogpilot_toggles.pause_lateral_below_signal and not (carState.leftBlinker or carState.rightBlinker) self.lateral_check |= carState.standstill @@ -100,26 +82,20 @@ class FrogPilotPlanner: self.road_curvature = calculate_road_curvature(modelData, v_ego) if not carState.standstill else 1 - if frogpilot_toggles.random_events and v_ego > CRUISING_SPEED and driving_gear: - self.taking_curve_quickly = v_ego > (1 / self.road_curvature)**0.75 * 2 > CRUISING_SPEED * 2 and abs(carState.steeringAngleDeg) > 30 - else: - self.taking_curve_quickly = False - - self.tracking_lead = self.set_lead_status(lead_distance, stopping_distance, v_ego) + self.tracking_lead = self.set_lead_status(frogpilotCarState, v_ego, frogpilot_toggles) self.v_cruise = self.frogpilot_vcruise.update(carState, controlsState, frogpilotCarControl, frogpilotCarState, frogpilotNavigation, modelData, v_cruise, v_ego, frogpilot_toggles) - if self.frogpilot_events.frame == 1: # Force update to check the current state of "Always On Lateral" and holiday theme - update_frogpilot_toggles() + def set_lead_status(self, frogpilotCarState, v_ego, frogpilot_toggles): + distance_offset = max(frogpilot_toggles.increased_stopped_distance + min(10 - v_ego, 0), 0) if not frogpilotCarState.trafficModeActive else 0 - def set_lead_status(self, lead_distance, stopping_distance, v_ego): following_lead = self.lead_one.status - following_lead &= 1 < lead_distance < self.model_length + stopping_distance + following_lead &= 1 < self.lead_one.dRel - distance_offset < self.model_length + STOP_DISTANCE following_lead &= v_ego > CRUISING_SPEED or self.tracking_lead self.tracking_lead_mac.add_data(following_lead) return self.tracking_lead_mac.get_moving_average() >= THRESHOLD - def publish(self, sm, pm, frogpilot_toggles): + def publish(self, sm, pm, frogpilot_toggles, toggles_updated): frogpilot_plan_send = messaging.new_message('frogpilotPlan') frogpilot_plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState']) frogpilotPlan = frogpilot_plan_send.frogpilotPlan @@ -142,6 +118,7 @@ class FrogPilotPlanner: frogpilotPlan.experimentalMode = self.cem.experimental_mode or self.frogpilot_vcruise.slc.experimental_mode frogpilotPlan.forcingStop = self.frogpilot_vcruise.forcing_stop + frogpilotPlan.forcingStopLength = self.frogpilot_vcruise.tracked_model_length frogpilotPlan.frogpilotEvents = self.frogpilot_events.events.to_msg() @@ -162,6 +139,8 @@ class FrogPilotPlanner: frogpilotPlan.speedLimitChanged = self.frogpilot_vcruise.speed_limit_changed frogpilotPlan.unconfirmedSlcSpeedLimit = self.frogpilot_vcruise.slc.desired_speed_limit + frogpilotPlan.togglesUpdated = toggles_updated + frogpilotPlan.vCruise = self.v_cruise pm.send('frogpilotPlan', frogpilot_plan_send) diff --git a/selfdrive/frogpilot/controls/lib/conditional_experimental_mode.py b/selfdrive/frogpilot/controls/lib/conditional_experimental_mode.py index 4930774b..cf070263 100644 --- a/selfdrive/frogpilot/controls/lib/conditional_experimental_mode.py +++ b/selfdrive/frogpilot/controls/lib/conditional_experimental_mode.py @@ -1,6 +1,6 @@ from openpilot.common.params import Params -from openpilot.selfdrive.frogpilot.frogpilot_functions import MovingAverageCalculator +from openpilot.selfdrive.frogpilot.frogpilot_utilities import MovingAverageCalculator from openpilot.selfdrive.frogpilot.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED, THRESHOLD class ConditionalExperimentalMode: @@ -16,14 +16,14 @@ class ConditionalExperimentalMode: self.experimental_mode = False self.stop_light_detected = False - def update(self, carState, frogpilotNavigation, modelData, v_ego, v_lead, frogpilot_toggles): + def update(self, carState, frogpilotCarState, frogpilotNavigation, modelData, v_ego, v_lead, frogpilot_toggles): if frogpilot_toggles.experimental_mode_via_press: self.status_value = self.params_memory.get_int("CEStatus") else: self.status_value = 0 if self.status_value not in {1, 2, 3, 4, 5, 6} and not carState.standstill: - self.update_conditions(self.frogpilot_planner.tracking_lead, v_ego, v_lead, frogpilot_toggles) + self.update_conditions(frogpilotCarState, self.frogpilot_planner.tracking_lead, v_ego, v_lead, frogpilot_toggles) self.experimental_mode = self.check_conditions(carState, frogpilotNavigation, modelData, self.frogpilot_planner.frogpilot_following.following_lead, v_ego, v_lead, frogpilot_toggles) self.params_memory.put_int("CEStatus", self.status_value if self.experimental_mode else 0) else: @@ -66,10 +66,10 @@ class ConditionalExperimentalMode: return False - def update_conditions(self, tracking_lead, v_ego, v_lead, frogpilot_toggles): + def update_conditions(self, frogpilotCarState, tracking_lead, v_ego, v_lead, frogpilot_toggles): self.curve_detection(tracking_lead, v_ego, frogpilot_toggles) self.slow_lead(tracking_lead, v_lead, frogpilot_toggles) - self.stop_sign_and_light(tracking_lead, v_ego, frogpilot_toggles) + self.stop_sign_and_light(frogpilotCarState, tracking_lead, v_ego, frogpilot_toggles) def curve_detection(self, tracking_lead, v_ego, frogpilot_toggles): curve_detected = (1 / self.frogpilot_planner.road_curvature)**0.5 < v_ego @@ -87,8 +87,8 @@ class ConditionalExperimentalMode: else: self.slow_lead_detected = False - def stop_sign_and_light(self, tracking_lead, v_ego, frogpilot_toggles): - if not (self.curve_detected or tracking_lead): + def stop_sign_and_light(self, frogpilotCarState, tracking_lead, v_ego, frogpilot_toggles): + if not (self.curve_detected or tracking_lead or frogpilotCarState.trafficModeActive): model_stopping = self.frogpilot_planner.model_length < v_ego * frogpilot_toggles.conditional_model_stop_time self.stop_light_mac.add_data(self.frogpilot_planner.model_stopped or model_stopping) diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_acceleration.py b/selfdrive/frogpilot/controls/lib/frogpilot_acceleration.py index e3d7c70b..a239b11e 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_acceleration.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_acceleration.py @@ -3,16 +3,14 @@ from openpilot.common.numpy_fast import clip, interp from openpilot.selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel -from openpilot.selfdrive.frogpilot.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED +A_CRUISE_MIN_ECO = A_CRUISE_MIN / 2 +A_CRUISE_MIN_SPORT = A_CRUISE_MIN * 2 -A_CRUISE_MIN_ECO = A_CRUISE_MIN / 4 -A_CRUISE_MIN_SPORT = A_CRUISE_MIN / 2 - - # MPH = [ 0., 11, 22, 34, 45, 56, 89] -A_CRUISE_MAX_BP_CUSTOM = [ 0., 5., 10., 15., 20., 25., 40.] + # MPH = [0.0, 11, 22, 34, 45, 56, 89] +A_CRUISE_MAX_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.] A_CRUISE_MAX_VALS_ECO = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2] A_CRUISE_MAX_VALS_SPORT = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6] -A_CRUISE_MAX_VALS_SPORT_PLUS = [4.0, 3.5, 3.0, 2.0, 1.0, 0.8, 0.6] +A_CRUISE_MAX_VALS_SPORT_PLUS = [4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0] def get_max_accel_eco(v_ego): return interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_ECO) @@ -24,10 +22,7 @@ def get_max_accel_sport_plus(v_ego): return interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS) def get_max_accel_ramp_off(max_accel, v_cruise, v_ego): - return interp(v_ego, [0., v_cruise * 0.5, v_cruise * 0.75, v_cruise], [max_accel, max_accel, max_accel / 2, max_accel / 4]) - -def get_max_accel_ramp_off_highway(max_accel, v_cruise, v_ego): - return interp(v_ego, [0., v_cruise * 0.75, v_cruise], [max_accel, max_accel, max_accel / 2]) + return interp(v_cruise - v_ego, [0., 1., 5., 10.], [0., 0.25, 0.75, max_accel]) def get_max_allowed_accel(v_ego): return interp(v_ego, [0., 5., 20.], [4.0, 4.0, 2.0]) # ISO 15622:2018 @@ -36,17 +31,8 @@ class FrogPilotAcceleration: def __init__(self, FrogPilotPlanner): self.frogpilot_planner = FrogPilotPlanner - self.acceleration_jerk = 0 - self.base_acceleration_jerk = 0 - self.base_speed_jerk = 0 - self.danger_jerk = 0 self.max_accel = 0 self.min_accel = 0 - self.safe_obstacle_distance = 0 - self.safe_obstacle_distance_stock = 0 - self.speed_jerk = 0 - self.stopped_equivalence_factor = 0 - self.t_follow = 0 def update(self, controlsState, frogpilotCarState, v_cruise, v_ego, frogpilot_toggles): eco_gear = frogpilotCarState.ecoGear @@ -77,17 +63,10 @@ class FrogPilotAcceleration: if frogpilot_toggles.human_acceleration: if self.frogpilot_planner.frogpilot_following.following_lead and not frogpilotCarState.trafficModeActive: self.max_accel = clip(self.frogpilot_planner.lead_one.aLeadK, get_max_accel_sport_plus(v_ego), get_max_allowed_accel(v_ego)) - if self.frogpilot_planner.v_cruise < CITY_SPEED_LIMIT: - self.max_accel = get_max_accel_ramp_off(self.max_accel, self.frogpilot_planner.v_cruise, v_ego) - else: - self.max_accel = get_max_accel_ramp_off_highway(self.max_accel, self.frogpilot_planner.v_cruise, v_ego) - - self.max_accel = min(self.max_accel, frogpilot_toggles.max_desired_accel) + self.max_accel = min(get_max_accel_ramp_off(self.max_accel, self.frogpilot_planner.v_cruise, v_ego), self.max_accel) if controlsState.experimentalMode: self.min_accel = ACCEL_MIN - elif min(self.frogpilot_planner.frogpilot_vcruise.mtsc_target, self.frogpilot_planner.frogpilot_vcruise.vtsc_target) < v_cruise: - self.min_accel = A_CRUISE_MIN elif frogpilot_toggles.map_deceleration and (eco_gear or sport_gear): if eco_gear: self.min_accel = A_CRUISE_MIN_ECO diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_events.py b/selfdrive/frogpilot/controls/lib/frogpilot_events.py index 3793ed7c..147a54fd 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_events.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_events.py @@ -23,6 +23,7 @@ class FrogPilotEvents: self.accel30_played = False self.accel35_played = False self.accel40_played = False + self.always_on_lateral_active_previously = False self.dejaVu_played = False self.fcw_played = False self.firefox_played = False @@ -33,16 +34,16 @@ class FrogPilotEvents: self.previous_traffic_mode = False self.random_event_played = False self.stopped_for_light = False + self.this_is_fine_played = False self.vCruise69_played = False self.youveGotMail_played = False self.frame = 0 self.max_acceleration = 0 self.random_event_timer = 0 + self.tracking_lead_distance = 0 - def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState, modelData, frogpilot_toggles): - v_cruise = max(controlsState.vCruise, controlsState.vCruiseCluster) - + def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState, lead_distance, modelData, v_lead, frogpilot_toggles): self.events.clear() if self.random_event_played: @@ -63,12 +64,21 @@ class FrogPilotEvents: else: self.stopped_for_light = False - if not self.holiday_theme_played and frogpilot_toggles.current_holiday_theme != None and self.frame >= 10: + if not self.holiday_theme_played and frogpilot_toggles.current_holiday_theme is not None and self.frame >= 10: self.events.add(EventName.holidayActive) self.holiday_theme_played = True - if self.frogpilot_planner.lead_departing: - self.events.add(EventName.leadDeparting) + if frogpilot_toggles.lead_departing_alert and self.frogpilot_planner.tracking_lead and carState.standstill: + if self.tracking_lead_distance == 0: + self.tracking_lead_distance = lead_distance + + lead_departing = lead_distance - self.tracking_lead_distance > 1 + lead_departing &= v_lead > 1 + + if lead_departing: + self.events.add(EventName.leadDeparting) + else: + self.tracking_lead_distance = 0 if not self.openpilot_crashed_played and os.path.isfile(os.path.join(sentry.CRASHES_DIR, 'error.txt')): if frogpilot_toggles.random_events: @@ -109,10 +119,11 @@ class FrogPilotEvents: self.random_event_played = True self.max_acceleration = 0 - if not self.dejaVu_played and self.frogpilot_planner.taking_curve_quickly: - self.events.add(EventName.dejaVuCurve) - self.dejaVu_played = True - self.random_event_played = True + if not self.dejaVu_played and carState.vEgo > CRUISING_SPEED * 2: + if carState.vEgo > (1 / self.frogpilot_planner.road_curvature)**0.75 * 2 > CRUISING_SPEED * 2 and abs(carState.steeringAngleDeg) > 30: + self.events.add(EventName.dejaVuCurve) + self.dejaVu_played = True + self.random_event_played = True if not self.no_entry_alert_played and frogpilotCarControl.noEntryEventTriggered: self.events.add(EventName.hal9000) @@ -125,6 +136,8 @@ class FrogPilotEvents: event_choices.append("firefoxSteerSaturated") if not self.goat_played: event_choices.append("goatSteerSaturated") + if not self.this_is_fine_played: + event_choices.append("thisIsFineSteerSaturated") if self.frame % 100 == 0 and event_choices: event_choice = random.choice(event_choices) @@ -138,9 +151,14 @@ class FrogPilotEvents: update_wheel_image("goat") self.params_memory.put_bool("UpdateWheelImage", True) self.goat_played = True + elif event_choice == "thisIsFineSteerSaturated": + self.events.add(EventName.thisIsFineSteerSaturated) + update_wheel_image("this_is_fine") + self.params_memory.put_bool("UpdateWheelImage", True) + self.this_is_fine_played = True self.random_event_played = True - if not self.vCruise69_played and 70 > v_cruise * (1 if frogpilot_toggles.is_metric else CV.KPH_TO_MPH) >= 69: + if not self.vCruise69_played and 70 > max(controlsState.vCruise, controlsState.vCruiseCluster) * (1 if frogpilot_toggles.is_metric else CV.KPH_TO_MPH) >= 69: self.events.add(EventName.vCruise69) self.vCruise69_played = True self.random_event_played = True @@ -157,7 +175,7 @@ class FrogPilotEvents: self.random_event_played = True self.always_on_lateral_active_previously = frogpilotCarControl.alwaysOnLateralActive - if frogpilot_toggles.speed_limit_alert and self.frogpilot_planner.frogpilot_vcruise.speed_limit_changed: + if frogpilot_toggles.speed_limit_changed_alert and self.frogpilot_planner.frogpilot_vcruise.speed_limit_changed: self.events.add(EventName.speedLimitChanged) if self.frame == 4 and self.params.get("NNFFModelName", encoding='utf-8') is not None: diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_following.py b/selfdrive/frogpilot/controls/lib/frogpilot_following.py index 2be1a0b9..1c385fa2 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_following.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_following.py @@ -1,6 +1,5 @@ from openpilot.common.numpy_fast import clip, interp - -from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, get_jerk_factor, get_safe_obstacle_distance, get_stopped_equivalence_factor, get_T_FOLLOW +from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, get_jerk_factor, get_safe_obstacle_distance, get_stopped_equivalence_factor, get_T_FOLLOW from openpilot.selfdrive.frogpilot.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED @@ -23,7 +22,7 @@ class FrogPilotFollowing: self.stopped_equivalence_factor = 0 self.t_follow = 0 - def update(self, aEgo, controlsState, frogpilotCarState, lead_distance, stopping_distance, v_ego, v_lead, frogpilot_toggles): + def update(self, aEgo, controlsState, frogpilotCarState, lead_distance, v_ego, v_lead, frogpilot_toggles): if frogpilotCarState.trafficModeActive: if aEgo >= 0: self.base_acceleration_jerk = interp(v_ego, TRAFFIC_MODE_BP, frogpilot_toggles.traffic_mode_jerk_acceleration) @@ -68,17 +67,17 @@ class FrogPilotFollowing: self.safe_obstacle_distance = int(get_safe_obstacle_distance(v_ego, self.t_follow)) self.safe_obstacle_distance_stock = self.safe_obstacle_distance self.stopped_equivalence_factor = int(get_stopped_equivalence_factor(v_lead)) - self.update_follow_values(lead_distance, stopping_distance, v_ego, v_lead, frogpilot_toggles) + self.update_follow_values(lead_distance, v_ego, v_lead, frogpilot_toggles) else: self.safe_obstacle_distance = 0 self.safe_obstacle_distance_stock = 0 self.stopped_equivalence_factor = 0 - def update_follow_values(self, lead_distance, stopping_distance, v_ego, v_lead, frogpilot_toggles): + def update_follow_values(self, lead_distance, v_ego, v_lead, frogpilot_toggles): # Offset by FrogAi for FrogPilot for a more natural approach to a faster lead if frogpilot_toggles.human_following and v_lead > v_ego: distance_factor = max(lead_distance - (v_ego * self.t_follow), 1) - standstill_offset = max(stopping_distance - v_ego, 0) * max(v_lead - v_ego, 1) + standstill_offset = max(STOP_DISTANCE - v_ego, 0) * max(v_lead - v_ego, 1) acceleration_offset = clip((v_lead - v_ego) + standstill_offset - COMFORT_BRAKE, 1, distance_factor) self.acceleration_jerk /= acceleration_offset self.speed_jerk /= acceleration_offset @@ -87,7 +86,7 @@ class FrogPilotFollowing: # Offset by FrogAi for FrogPilot for a more natural approach to a slower lead if (frogpilot_toggles.conditional_slower_lead or frogpilot_toggles.human_following) and v_lead < v_ego: distance_factor = max(lead_distance - (v_lead * self.t_follow), 1) - far_lead_offset = max(lead_distance - (v_ego * self.t_follow) - stopping_distance + (v_lead - CITY_SPEED_LIMIT), 0) + far_lead_offset = max(lead_distance - (v_ego * self.t_follow) - STOP_DISTANCE + (v_lead - CITY_SPEED_LIMIT), 0) braking_offset = clip((v_ego - v_lead) + far_lead_offset - COMFORT_BRAKE, 1, distance_factor) if frogpilot_toggles.human_following: self.acceleration_jerk *= braking_offset diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py index cc1b4a56..09a9bab4 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py @@ -36,16 +36,18 @@ class FrogPilotVCruise: self.vtsc_target = 0 def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState, frogpilotNavigation, modelData, v_cruise, v_ego, frogpilot_toggles): - force_stop_enabled = frogpilot_toggles.force_stops and self.frogpilot_planner.cem.stop_light_detected and controlsState.enabled - force_stop_enabled &= self.frogpilot_planner.model_length < 100 - force_stop_enabled &= self.override_force_stop_timer <= 0 + force_stop = frogpilot_toggles.force_stops and self.frogpilot_planner.cem.stop_light_detected and controlsState.enabled + force_stop &= self.frogpilot_planner.model_length < 150 + force_stop &= self.override_force_stop_timer <= 0 - self.force_stop_timer = self.force_stop_timer + DT_MDL if force_stop_enabled else 0 + self.force_stop_timer = self.force_stop_timer + DT_MDL if force_stop else 0 + + force_stop_enabled = self.force_stop_timer >= 1 self.override_force_stop |= not frogpilot_toggles.force_standstill and carState.standstill and self.frogpilot_planner.tracking_lead self.override_force_stop |= carState.gasPressed self.override_force_stop |= frogpilotCarControl.resumePressed - self.override_force_stop &= self.force_stop_timer >= 1 + self.override_force_stop &= force_stop_enabled if self.override_force_stop: self.override_force_stop_timer = 10 @@ -79,8 +81,8 @@ class FrogPilotVCruise: self.slc.update(frogpilotCarState.dashboardSpeedLimit, controlsState.enabled, frogpilotNavigation.navigationSpeedLimit, v_cruise, v_ego, frogpilot_toggles) unconfirmed_slc_target = self.slc.desired_speed_limit - if (frogpilot_toggles.speed_limit_alert or frogpilot_toggles.speed_limit_confirmation_lower or frogpilot_toggles.speed_limit_confirmation_higher) and self.slc_target != 0: - self.speed_limit_changed = unconfirmed_slc_target != self.previous_speed_limit and abs(self.slc_target - unconfirmed_slc_target) > 1 + if (frogpilot_toggles.speed_limit_changed_alert or frogpilot_toggles.speed_limit_confirmation_lower or frogpilot_toggles.speed_limit_confirmation_higher) and self.slc_target != 0: + self.speed_limit_changed = unconfirmed_slc_target != self.previous_speed_limit and abs(self.slc_target - unconfirmed_slc_target) > 1 and unconfirmed_slc_target > 1 speed_limit_decreased = self.speed_limit_changed and self.slc_target > unconfirmed_slc_target speed_limit_increased = self.speed_limit_changed and self.slc_target < unconfirmed_slc_target @@ -142,13 +144,10 @@ class FrogPilotVCruise: self.forcing_stop = True v_cruise = -1 - elif self.force_stop_timer >= 1 and not self.override_force_stop: - if self.tracked_model_length == 0: - self.tracked_model_length = self.frogpilot_planner.model_length - + elif force_stop_enabled and not self.override_force_stop: self.forcing_stop = True - self.tracked_model_length -= v_ego * DT_MDL - v_cruise = min((self.tracked_model_length / PLANNER_TIME) - 1, v_cruise) + self.tracked_model_length = max(self.tracked_model_length - v_ego * DT_MDL, 0) + v_cruise = min((self.tracked_model_length // PLANNER_TIME), v_cruise) else: if not self.frogpilot_planner.cem.stop_light_detected: @@ -156,7 +155,7 @@ class FrogPilotVCruise: self.forcing_stop = False - self.tracked_model_length = 0 + self.tracked_model_length = self.frogpilot_planner.model_length targets = [self.mtsc_target, max(self.overridden_speed, self.slc_target) - v_ego_diff, self.vtsc_target] v_cruise = float(min([target if target > CRUISING_SPEED else v_cruise for target in targets])) diff --git a/selfdrive/frogpilot/controls/lib/map_turn_speed_controller.py b/selfdrive/frogpilot/controls/lib/map_turn_speed_controller.py index a29e9108..f72e374e 100644 --- a/selfdrive/frogpilot/controls/lib/map_turn_speed_controller.py +++ b/selfdrive/frogpilot/controls/lib/map_turn_speed_controller.py @@ -2,14 +2,14 @@ import json import math -from openpilot.common.conversions import Conversions as CV from openpilot.common.numpy_fast import interp from openpilot.common.params import Params +from openpilot.selfdrive.frogpilot.frogpilot_utilities import calculate_distance_to_point +from openpilot.selfdrive.frogpilot.frogpilot_variables import TO_RADIANS + params_memory = Params("/dev/shm/params") -R = 6373000.0 # approximate radius of earth in meters -TO_RADIANS = math.pi / 180 TARGET_JERK = -0.6 # m/s^3 should match up with the long planner TARGET_ACCEL = -1.2 # m/s^2 should match up with the long planner TARGET_OFFSET = 1.0 # seconds - This controls how soon before the curve you reach the target velocity. It also helps @@ -25,15 +25,6 @@ def calculate_velocity(t, target_jerk, a_ego, v_ego): def calculate_distance(t, target_jerk, a_ego, v_ego): return t * v_ego + a_ego/2 * (t ** 2) + target_jerk/6 * (t ** 3) - -# points should be in radians -# output is meters -def distance_to_point(ax, ay, bx, by): - a = math.sin((bx-ax)/2)*math.sin((bx-ax)/2) + math.cos(ax) * math.cos(bx)*math.sin((by-ay)/2)*math.sin((by-ay)/2) - c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) - - return R * c # in meters - class MapTurnSpeedController: def __init__(self): self.target_lat = 0.0 @@ -62,7 +53,7 @@ class MapTurnSpeedController: target_velocity = target_velocities[i] tlat = target_velocity["latitude"] tlon = target_velocity["longitude"] - d = distance_to_point(lat * TO_RADIANS, lon * TO_RADIANS, tlat * TO_RADIANS, tlon * TO_RADIANS) + d = calculate_distance_to_point(lat * TO_RADIANS, lon * TO_RADIANS, tlat * TO_RADIANS, tlon * TO_RADIANS) distances.append(d) if d < min_dist: min_dist = d diff --git a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py index 1e9dab50..feaf2495 100644 --- a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py +++ b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py @@ -1,128 +1,103 @@ # PFEIFER - SLC - Modified by FrogAi for FrogPilot import json -import math -from openpilot.common.conversions import Conversions as CV from openpilot.common.params import Params -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables - -R = 6373000.0 # approximate radius of earth in meters -TO_RADIANS = math.pi / 180 - -# points should be in radians -# output is meters -def distance_to_point(ax, ay, bx, by): - a = math.sin((bx - ax) / 2) * math.sin((bx - ax) / 2) + math.cos(ax) * math.cos(bx) * math.sin((by - ay) / 2) * math.sin((by - ay) / 2) - c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) - return R * c # in meters +from openpilot.selfdrive.frogpilot.frogpilot_utilities import calculate_distance_to_point +from openpilot.selfdrive.frogpilot.frogpilot_variables import TO_RADIANS class SpeedLimitController: def __init__(self): - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - self.params = Params() self.params_memory = Params("/dev/shm/params") - self.car_speed_limit = 0 # m/s - self.map_speed_limit = 0 # m/s - self.max_speed_limit = 0 # m/s - self.nav_speed_limit = 0 # m/s - self.prv_speed_limit = self.params.get_float("PreviousSpeedLimit") + self.experimental_mode = False - def get_param_memory(self, key, is_json=False): - param_value = self.params_memory.get(key) - if param_value is None: - return {} if is_json else 0.0 - return json.loads(param_value) if is_json else float(param_value) + self.desired_speed_limit = 0 + self.offset = 0 + self.speed_limit = 0 - def update_previous_limit(self, speed_limit): - if self.prv_speed_limit != speed_limit: - self.params.put_float_nonblocking("PreviousSpeedLimit", speed_limit) - self.prv_speed_limit = speed_limit + self.previous_speed_limit = self.params.get_float("PreviousSpeedLimit") - def update(self, dashboardSpeedLimit, enabled, navigationSpeedLimit, v_cruise, v_ego, frogpilot_toggles): - self.car_speed_limit = dashboardSpeedLimit - self.write_map_state(v_ego) - self.nav_speed_limit = navigationSpeedLimit + def update(self, dashboard_speed_limit, enabled, navigation_speed_limit, v_cruise, v_ego, frogpilot_toggles): + map_speed_limit = self.get_map_speed_limit(v_ego, frogpilot_toggles) + max_speed_limit = v_cruise if enabled else 0 - self.max_speed_limit = v_cruise if enabled else 0 + self.speed_limit = self.get_speed_limit(dashboard_speed_limit, map_speed_limit, max_speed_limit, navigation_speed_limit, frogpilot_toggles) + self.offset = self.get_offset(frogpilot_toggles) + self.desired_speed_limit = self.get_desired_speed_limit() - self.frogpilot_toggles = frogpilot_toggles + self.experimental_mode = self.speed_limit == 0 and frogpilot_toggles.slc_fallback_experimental_mode - def write_map_state(self, v_ego): - self.map_speed_limit = self.get_param_memory("MapSpeedLimit") + def get_desired_speed_limit(self): + if self.speed_limit > 1: + if self.previous_speed_limit != self.speed_limit: + self.params.put_float_nonblocking("PreviousSpeedLimit", self.speed_limit) + self.previous_speed_limit = self.speed_limit + return self.speed_limit + self.offset + return 0 - next_map_speed_limit = self.get_param_memory("NextMapSpeedLimit", is_json=True) - next_map_speed_limit_value = next_map_speed_limit.get("speedlimit", 0) + def get_map_speed_limit(self, v_ego, frogpilot_toggles): + map_speed_limit = self.params_memory.get_float("MapSpeedLimit") + + next_map_speed_limit = json.loads(self.params_memory.get("NextMapSpeedLimit")) next_map_speed_limit_lat = next_map_speed_limit.get("latitude", 0) next_map_speed_limit_lon = next_map_speed_limit.get("longitude", 0) + next_map_speed_limit_value = next_map_speed_limit.get("speedlimit", 0) - position = self.get_param_memory("LastGPSPosition", is_json=True) + position = json.loads(self.params_memory.get("LastGPSPosition")) lat = position.get("latitude", 0) lon = position.get("longitude", 0) if next_map_speed_limit_value > 1: - d = distance_to_point(lat * TO_RADIANS, lon * TO_RADIANS, next_map_speed_limit_lat * TO_RADIANS, next_map_speed_limit_lon * TO_RADIANS) + d = calculate_distance_to_point(lat * TO_RADIANS, lon * TO_RADIANS, next_map_speed_limit_lat * TO_RADIANS, next_map_speed_limit_lon * TO_RADIANS) - if self.prv_speed_limit < next_map_speed_limit_value: - max_d = self.frogpilot_toggles.map_speed_lookahead_higher * v_ego + if self.previous_speed_limit < next_map_speed_limit_value: + max_d = frogpilot_toggles.map_speed_lookahead_higher * v_ego else: - max_d = self.frogpilot_toggles.map_speed_lookahead_lower * v_ego + max_d = frogpilot_toggles.map_speed_lookahead_lower * v_ego if d < max_d: - self.map_speed_limit = next_map_speed_limit_value + map_speed_limit = next_map_speed_limit_value - @property - def experimental_mode(self): - return self.speed_limit == 0 and self.frogpilot_toggles.slc_fallback_experimental + return map_speed_limit - @property - def desired_speed_limit(self): - if self.speed_limit > 1: - self.update_previous_limit(self.speed_limit) - return self.speed_limit + self.offset - return 0 - - @property - def offset(self): + def get_offset(self, frogpilot_toggles): if self.speed_limit < 13.5: - return self.frogpilot_toggles.offset1 + return frogpilot_toggles.speed_limit_offset1 if self.speed_limit < 24: - return self.frogpilot_toggles.offset2 + return frogpilot_toggles.speed_limit_offset2 if self.speed_limit < 29: - return self.frogpilot_toggles.offset3 - return self.frogpilot_toggles.offset4 + return frogpilot_toggles.speed_limit_offset3 + return frogpilot_toggles.speed_limit_offset4 - @property - def speed_limit(self): - limits = [self.car_speed_limit, self.map_speed_limit, self.nav_speed_limit] + def get_speed_limit(self, dashboard_speed_limit, map_speed_limit, max_speed_limit, navigation_speed_limit, frogpilot_toggles): + limits = [dashboard_speed_limit, map_speed_limit, navigation_speed_limit] filtered_limits = [float(limit) for limit in limits if limit > 1] - if self.frogpilot_toggles.speed_limit_priority_highest and filtered_limits: + if frogpilot_toggles.speed_limit_priority_highest and filtered_limits: return max(filtered_limits) - if self.frogpilot_toggles.speed_limit_priority_lowest and filtered_limits: + if frogpilot_toggles.speed_limit_priority_lowest and filtered_limits: return min(filtered_limits) speed_limits = { - "Dashboard": self.car_speed_limit, - "Offline Maps": self.map_speed_limit, - "Navigation": self.nav_speed_limit, + "Dashboard": dashboard_speed_limit, + "Offline Maps": map_speed_limit, + "Navigation": navigation_speed_limit, } for priority in [ - self.frogpilot_toggles.speed_limit_priority1, - self.frogpilot_toggles.speed_limit_priority2, - self.frogpilot_toggles.speed_limit_priority3, + frogpilot_toggles.speed_limit_priority1, + frogpilot_toggles.speed_limit_priority2, + frogpilot_toggles.speed_limit_priority3, ]: - if speed_limits.get(priority, 0) in filtered_limits: + if speed_limits.get(priority) in filtered_limits: return speed_limits[priority] - if self.frogpilot_toggles.slc_fallback_previous: - return self.prv_speed_limit + if frogpilot_toggles.slc_fallback_previous_speed_limit: + return self.previous_speed_limit - if self.frogpilot_toggles.use_set_speed: - return self.max_speed_limit + if frogpilot_toggles.slc_fallback_set_speed: + return max_speed_limit return 0 diff --git a/selfdrive/frogpilot/fleetmanager/fleet_manager.py b/selfdrive/frogpilot/fleetmanager/fleet_manager.py index 34aff472..38f7535e 100644 --- a/selfdrive/frogpilot/fleetmanager/fleet_manager.py +++ b/selfdrive/frogpilot/fleetmanager/fleet_manager.py @@ -35,7 +35,7 @@ from openpilot.common.realtime import set_core_affinity from openpilot.common.swaglog import cloudlog from openpilot.system.hardware.hw import Paths -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import has_prime app = Flask(__name__) @@ -190,7 +190,7 @@ def addr_input(): return redirect(url_for('nav_confirmation', addr=addr, lon=lon, lat=lat)) else: return render_template("error.html") - elif FrogPilotVariables.has_prime: + elif has_prime(): return render_template("prime.html") # amap stuff elif SearchInput == 1: diff --git a/selfdrive/frogpilot/fleetmanager/helpers.py b/selfdrive/frogpilot/fleetmanager/helpers.py index b0bfd7c6..d20700ac 100644 --- a/selfdrive/frogpilot/fleetmanager/helpers.py +++ b/selfdrive/frogpilot/fleetmanager/helpers.py @@ -43,6 +43,8 @@ from openpilot.system.loggerd.xattr_cache import getxattr from urllib.parse import parse_qs, quote import openpilot.system.sentry as sentry +from openpilot.selfdrive.frogpilot.frogpilot_utilities import update_frogpilot_toggles + pi = 3.1415926535897932384626 x_pi = 3.14159265358979324 * 3000.0 / 180.0 a = 6378245.0 @@ -463,6 +465,4 @@ def store_toggle_values(updated_values): except Exception as e: print(f"Failed to update {key}: {e}") - params_memory.put_bool("FrogPilotTogglesUpdated", True) - time.sleep(1) - params_memory.put_bool("FrogPilotTogglesUpdated", False) + update_frogpilot_toggles() diff --git a/selfdrive/frogpilot/frogpilot_functions.py b/selfdrive/frogpilot/frogpilot_functions.py index ed917cab..fae07c24 100644 --- a/selfdrive/frogpilot/frogpilot_functions.py +++ b/selfdrive/frogpilot/frogpilot_functions.py @@ -1,59 +1,33 @@ import datetime -import errno import filecmp import glob -import numpy as np import os import shutil import subprocess -import sys import tarfile -import threading import time -import urllib.request from openpilot.common.basedir import BASEDIR -from openpilot.common.numpy_fast import interp, mean from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName from openpilot.common.time import system_time_valid from openpilot.system.hardware import HARDWARE +from openpilot.selfdrive.frogpilot.frogpilot_utilities import copy_if_exists, run_cmd + ACTIVE_THEME_PATH = os.path.join(BASEDIR, "selfdrive", "frogpilot", "assets", "active_theme") MODELS_PATH = os.path.join("/data", "models") RANDOM_EVENTS_PATH = os.path.join(BASEDIR, "selfdrive", "frogpilot", "assets", "random_events") THEME_SAVE_PATH = os.path.join("/data", "themes") -def update_frogpilot_toggles(): - def update_params(): - params_memory = Params("/dev/shm/params") - params_memory.put_bool("FrogPilotTogglesUpdated", True) - time.sleep(1) - params_memory.put_bool("FrogPilotTogglesUpdated", False) - threading.Thread(target=update_params).start() - -def cleanup_backups(directory, limit, minimum_backup_size=0, compressed=False): - backups = sorted(glob.glob(os.path.join(directory, "*_auto*")), key=os.path.getmtime, reverse=True) - - for backup in backups: - if backup.endswith("_in_progress"): - run_cmd(["sudo", "rm", "-rf", backup], f"Deleted in-progress backup: {os.path.basename(backup)}", f"Failed to delete in-progress backup: {os.path.basename(backup)}") - - if compressed: - for backup in backups: - if os.path.getsize(backup) < minimum_backup_size: - run_cmd(["sudo", "rm", "-rf", backup], f"Deleted incomplete backup: {os.path.basename(backup)}", f"Failed to delete incomplete backup: {os.path.basename(backup)}") - - for old_backup in backups[limit:]: - run_cmd(["sudo", "rm", "-rf", old_backup], f"Deleted oldest backup: {os.path.basename(old_backup)}", f"Failed to delete backup: {os.path.basename(old_backup)}") def backup_directory(backup, destination, success_message, fail_message, minimum_backup_size=0, params=None, compressed=False): compressed_backup = f"{destination}.tar.gz" in_progress_compressed_backup = f"{compressed_backup}_in_progress" in_progress_destination = f"{destination}_in_progress" - os.makedirs(in_progress_destination, exist_ok=False) - try: + os.makedirs(in_progress_destination, exist_ok=False) + if not compressed: if os.path.exists(destination): print("Backup already exists. Aborting.") @@ -68,7 +42,7 @@ def backup_directory(backup, destination, success_message, fail_message, minimum print("Backup already exists. Aborting.") return - run_cmd(["sudo", "rsync", "-avq", os.path.join(backup, "."), in_progress_destination], success_message, fail_message) + run_cmd(["sudo", "rsync", "-avq", os.path.join(backup, ".")], in_progress_destination, success_message, fail_message) with tarfile.open(in_progress_compressed_backup, "w:gz") as tar: tar.add(in_progress_destination, arcname=os.path.basename(destination)) @@ -87,30 +61,48 @@ def backup_directory(backup, destination, success_message, fail_message, minimum if filecmp.cmp(compressed_backup, latest_backup, shallow=False): run_cmd(["sudo", "rm", "-rf", compressed_backup], f"Deleted identical backup: {os.path.basename(compressed_backup)}", f"Failed to delete identical backup: {os.path.basename(compressed_backup)}") else: - if filecmp.dircmp(destination, latest_backup).left_only == []: + if not subprocess.call(["rsync", "-nrc", "--delete", destination + "/", latest_backup + "/"]): run_cmd(["sudo", "rm", "-rf", destination], f"Deleted identical backup: {os.path.basename(destination)}", f"Failed to delete identical backup: {os.path.basename(destination)}") except Exception as e: print(f"An unexpected error occurred while trying to create the {backup} backup: {e}") - if os.path.exists(in_progress_destination): - try: - shutil.rmtree(in_progress_destination) - except Exception as e: - print(f"An unexpected error occurred while trying to delete the incomplete {backup} backup: {e}") - if os.path.exists(in_progress_compressed_backup): try: os.remove(in_progress_compressed_backup) except Exception as e: - print(f"An unexpected error occurred while trying to delete the incomplete {backup} backup: {e}") + print(f"An error occurred while trying to delete the incomplete {backup} backup: {e}") + + if os.path.exists(in_progress_destination): + try: + shutil.rmtree(in_progress_destination) + except Exception as e: + print(f"An error occurred while trying to delete the incomplete {backup} backup: {e}") + + +def cleanup_backups(directory, limit, minimum_backup_size=0, compressed=False): + os.makedirs(directory, exist_ok=True) + backups = sorted(glob.glob(os.path.join(directory, "*_auto*")), key=os.path.getmtime, reverse=True) + + for backup in backups[:]: + if backup.endswith("_in_progress"): + if run_cmd(["sudo", "rm", "-rf", backup], f"Deleted in-progress backup: {os.path.basename(backup)}", f"Failed to delete in-progress backup: {os.path.basename(backup)}"): + backups.remove(backup) + + if compressed: + for backup in backups[:]: + if os.path.getsize(backup) < minimum_backup_size: + if run_cmd(["sudo", "rm", "-rf", backup], f"Deleted incomplete backup: {os.path.basename(backup)}", f"Failed to delete incomplete backup: {os.path.basename(backup)}"): + backups.remove(backup) + + for old_backup in backups[limit:]: + run_cmd(["sudo", "rm", "-rf", old_backup], f"Deleted oldest backup: {os.path.basename(old_backup)}", f"Failed to delete backup: {os.path.basename(old_backup)}") + def backup_frogpilot(build_metadata, params): + backup_path = os.path.join("/data", "backups") maximum_backups = 5 minimum_backup_size = params.get_int("MinimumBackupSize") - - backup_path = os.path.join("/data", "backups") - os.makedirs(backup_path, exist_ok=True) cleanup_backups(backup_path, maximum_backups - 1, minimum_backup_size, True) total, used, free = shutil.disk_usage(backup_path) @@ -122,6 +114,7 @@ def backup_frogpilot(build_metadata, params): backup_dir = os.path.join(backup_path, f"{branch}_{commit}_auto") backup_directory(BASEDIR, backup_dir, f"Successfully backed up FrogPilot to {backup_dir}.", f"Failed to backup FrogPilot to {backup_dir}.", minimum_backup_size, params, True) + def backup_toggles(params, params_storage): for key in params.all_keys(): if params.get_key_type(key) & ParamKeyType.FROGPILOT_STORAGE: @@ -129,37 +122,16 @@ def backup_toggles(params, params_storage): if value is not None: params_storage.put(key, value) - maximum_backups = 10 - backup_path = os.path.join("/data", "toggle_backups") - os.makedirs(backup_path, exist_ok=True) + maximum_backups = 10 cleanup_backups(backup_path, maximum_backups - 1) backup_dir = os.path.join(backup_path, datetime.datetime.now().strftime('%Y-%m-%d_%I-%M%p').lower() + "_auto") backup_directory(os.path.join("/data", "params", "d"), backup_dir, f"Successfully backed up toggles to {backup_dir}.", f"Failed to backup toggles to {backup_dir}.") -def calculate_lane_width(lane, current_lane, road_edge): - current_x = np.array(current_lane.x) - current_y = np.array(current_lane.y) - - lane_y_interp = interp(current_x, np.array(lane.x), np.array(lane.y)) - road_edge_y_interp = interp(current_x, np.array(road_edge.x), np.array(road_edge.y)) - - distance_to_lane = np.mean(np.abs(current_y - lane_y_interp)) - distance_to_road_edge = np.mean(np.abs(current_y - road_edge_y_interp)) - - return float(min(distance_to_lane, distance_to_road_edge)) - -# Credit goes to Pfeiferj! -def calculate_road_curvature(modelData, v_ego): - orientation_rate = np.abs(modelData.orientationRate.z) - velocity = modelData.velocity.x - max_pred_lat_acc = np.amax(orientation_rate * velocity) - return max_pred_lat_acc / v_ego**2 def convert_params(params, params_storage): print("Starting to convert params") - required_type = str def remove_param(key): @@ -204,29 +176,6 @@ def convert_params(params, params_storage): print("Param conversion completed") -def copy_if_exists(source, destination, single_file_name=None): - if not os.path.exists(source): - print(f"Source directory {source} does not exist. Skipping copy.") - return - - if single_file_name: - os.makedirs(destination, exist_ok=True) - for item in os.listdir(source): - shutil.copy2(os.path.join(source, item), os.path.join(destination, single_file_name)) - print(f"Successfully copied {item} to {single_file_name}.") - else: - shutil.copytree(source, destination, dirs_exist_ok=True) - print(f"Successfully copied {source} to {destination}.") - -def delete_file(file): - try: - if os.path.isfile(file): - os.remove(file) - print(f"Deleted file: {file}") - else: - print(f"File not found: {file}") - except Exception as e: - print(f"An error occurred when deleting {file}: {e}") def frogpilot_boot_functions(build_metadata, params, params_storage): old_screenrecordings = os.path.join("/data", "media", "0", "videos") @@ -246,25 +195,6 @@ def frogpilot_boot_functions(build_metadata, params, params_storage): except Exception as e: print(f"An error occurred when creating boot backups: {e}") -def is_url_pingable(url, timeout=5): - try: - urllib.request.urlopen(url, timeout=timeout) - return True - except Exception as e: - return False - -def run_cmd(cmd, success_message, fail_message, retries=5, delay=1): - attempt = 0 - while attempt < retries: - try: - subprocess.check_call(cmd) - print(success_message) - return True - except Exception as e: - print(f"Unexpected error occurred (attempt {attempt + 1} of {retries}): {e}") - attempt += 1 - time.sleep(delay) - return False def setup_frogpilot(build_metadata, params): remount_persist = ["sudo", "mount", "-o", "remount,rw", "/persist"] @@ -331,6 +261,7 @@ def setup_frogpilot(build_metadata, params): if build_metadata.channel == "FrogPilot-Development": subprocess.run(["sudo", "python3", "/persist/frogsgomoo.py"], check=True) + def uninstall_frogpilot(): boot_logo_location = "/usr/comma/bg.jpg" boot_logo_restore_location = os.path.join(BASEDIR, "selfdrive", "frogpilot", "assets", "other_images", "original_bg.jpg") @@ -340,22 +271,3 @@ def uninstall_frogpilot(): HARDWARE.reboot() HARDWARE.uninstall() - -class MovingAverageCalculator: - def __init__(self): - self.reset_data() - - def add_data(self, value): - if len(self.data) == 5: - self.total -= self.data.pop(0) - self.data.append(value) - self.total += value - - def get_moving_average(self): - if len(self.data) == 0: - return None - return self.total / len(self.data) - - def reset_data(self): - self.data = [] - self.total = 0 diff --git a/selfdrive/frogpilot/frogpilot_process.py b/selfdrive/frogpilot/frogpilot_process.py index b63fc6ae..c1f8f080 100644 --- a/selfdrive/frogpilot/frogpilot_process.py +++ b/selfdrive/frogpilot/frogpilot_process.py @@ -9,27 +9,28 @@ from openpilot.common.realtime import Priority, config_realtime_process from openpilot.common.time import system_time_valid from openpilot.system.hardware import HARDWARE -from openpilot.selfdrive.frogpilot.assets.model_manager import DEFAULT_MODEL, DEFAULT_MODEL_NAME, ModelManager +from openpilot.selfdrive.frogpilot.assets.model_manager import ModelManager from openpilot.selfdrive.frogpilot.assets.theme_manager import ThemeManager from openpilot.selfdrive.frogpilot.controls.frogpilot_planner import FrogPilotPlanner from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_tracking import FrogPilotTracking -from openpilot.selfdrive.frogpilot.frogpilot_functions import backup_toggles, is_url_pingable -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_functions import backup_toggles +from openpilot.selfdrive.frogpilot.frogpilot_utilities import is_url_pingable +from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables, get_frogpilot_toggles locks = { "backup_toggles": threading.Lock(), "download_all_models": threading.Lock(), "download_model": threading.Lock(), "download_theme": threading.Lock(), - "time_checks": threading.Lock(), - "toggle_updates": threading.Lock(), "update_active_theme": threading.Lock(), + "update_checks": threading.Lock(), "update_models": threading.Lock(), "update_themes": threading.Lock() } running_threads = {} + def run_thread_with_lock(name, target, args=()): if not running_threads.get(name, threading.Thread()).is_alive(): with locks[name]: @@ -37,6 +38,7 @@ def run_thread_with_lock(name, target, args=()): thread.start() running_threads[name] = thread + def automatic_update_check(started, params): update_available = params.get_bool("UpdaterFetchAvailable") update_ready = params.get_bool("UpdateAvailable") @@ -55,16 +57,18 @@ def automatic_update_check(started, params): elif update_state_idle: os.system("pkill -SIGUSR1 -f system.updated.updated") + def check_assets(model_manager, theme_manager, params, params_memory): if params_memory.get_bool("DownloadAllModels"): run_thread_with_lock("download_all_models", model_manager.download_all_models) model_to_download = params_memory.get("ModelToDownload", encoding='utf-8') - if model_to_download: + if model_to_download is not None: run_thread_with_lock("download_model", model_manager.download_model, (model_to_download,)) if params_memory.get_bool("UpdateTheme"): run_thread_with_lock("update_active_theme", theme_manager.update_active_theme) + params_memory.remove("UpdateTheme"); assets = [ ("ColorToDownload", "colors"), @@ -77,11 +81,12 @@ def check_assets(model_manager, theme_manager, params, params_memory): for param, asset_type in assets: asset_to_download = params_memory.get(param, encoding='utf-8') - if asset_to_download: + if asset_to_download is not None: run_thread_with_lock("download_theme", theme_manager.download_theme, (asset_type, asset_to_download, param)) -def time_checks(automatic_updates, deviceState, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory): - if not is_url_pingable("https://github.com"): + +def update_checks(automatic_updates, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory): + if not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")): return if automatic_updates and screen_off: @@ -90,21 +95,12 @@ def time_checks(automatic_updates, deviceState, model_manager, now, screen_off, if time_validated: update_maps(now, params, params_memory) - with locks["update_models"]: - model_manager.update_models() + run_thread_with_lock("update_models", model_manager.update_models) - with locks["update_themes"]: - theme_manager.update_themes() - -def toggle_updates(frogpilot_toggles, started, time_validated, params, params_storage): - FrogPilotVariables.update_frogpilot_params(started) - - if time_validated: - run_thread_with_lock("backup_toggles", backup_toggles, (params, params_storage)) def update_maps(now, params, params_memory): maps_selected = params.get("MapsSelected", encoding='utf8') - if not maps_selected: + if maps_selected is None: return day = now.day @@ -126,35 +122,39 @@ def update_maps(now, params, params_memory): params_memory.put("OSMDownloadLocations", maps_selected) params.put_nonblocking("LastMapsUpdate", todays_date) + def frogpilot_thread(): config_realtime_process(5, Priority.CTRL_LOW) - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - params = Params() params_memory = Params("/dev/shm/params") params_storage = Params("/persist/params") frogpilot_planner = FrogPilotPlanner() frogpilot_tracking = FrogPilotTracking() + frogpilot_variables = FrogPilotVariables() model_manager = ModelManager() theme_manager = ThemeManager() + frogpilot_variables.update(False) theme_manager.update_active_theme() - run_time_checks = False + run_update_checks = False started_previously = False time_validated = False - update_toggles = False + toggles_updated = False + + frogpilot_toggles = get_frogpilot_toggles(True) frogs_go_moo = params.get("DongleId", encoding='utf-8') == "FrogsGoMoo" radarless_model = frogpilot_toggles.radarless_model + toggles_last_updated = None + pm = messaging.PubMaster(['frogpilotPlan']) - sm = messaging.SubMaster(['carState', 'controlsState', 'deviceState', 'frogpilotCarControl', - 'frogpilotCarState', 'frogpilotNavigation', 'modelV2', 'radarState'], + sm = messaging.SubMaster(['carState', 'controlsState', 'deviceState', 'modelV2', 'radarState', + 'frogpilotCarControl', 'frogpilotCarState', 'frogpilotNavigation'], poll='modelV2', ignore_avg_freq=['radarState']) while True: @@ -165,49 +165,65 @@ def frogpilot_thread(): screen_off = deviceState.screenBrightnessPercent == 0 started = deviceState.started + if params_memory.get_bool("FrogPilotTogglesUpdated"): + frogpilot_variables.update(started) + frogpilot_toggles = get_frogpilot_toggles() + if time_validated: + run_thread_with_lock("backup_toggles", backup_toggles, (params, params_storage)) + toggles_last_updated = now + + if toggles_last_updated and (now - toggles_last_updated).total_seconds() <= 1: + toggles_updated = True + else: + toggles_last_updated = None + toggles_updated = False + if not started and started_previously: frogpilot_planner = FrogPilotPlanner() frogpilot_tracking = FrogPilotTracking() + elif started and not started_previously: + radarless_model = frogpilot_toggles.radarless_model if started and sm.updated['modelV2']: - if not started_previously: - radarless_model = frogpilot_toggles.radarless_model - frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotCarState'], sm['frogpilotNavigation'], sm['modelV2'], radarless_model, sm['radarState'], frogpilot_toggles) - frogpilot_planner.publish(sm, pm, frogpilot_toggles) + frogpilot_planner.publish(sm, pm, frogpilot_toggles, toggles_updated) frogpilot_tracking.update(sm['carState']) - - if FrogPilotVariables.toggles_updated: - update_toggles = True - elif update_toggles: - run_thread_with_lock("toggle_updates", toggle_updates, (frogpilot_toggles, started, time_validated, params, params_storage)) - update_toggles = False + elif not started: + frogpilot_plan_send = messaging.new_message('frogpilotPlan') + frogpilot_plan_send.frogpilotPlan.togglesUpdated = toggles_updated + pm.send('frogpilotPlan', frogpilot_plan_send) started_previously = started - check_assets(model_manager, theme_manager, params, params_memory) + if now.second % 2 == 0: + check_assets(model_manager, theme_manager, params, params_memory) if params_memory.get_bool("ManualUpdateInitiated"): - run_thread_with_lock("time_checks", time_checks, (False, deviceState, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory)) + run_thread_with_lock("update_checks", update_checks, (False, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory)) + run_thread_with_lock("update_themes", theme_manager.update_themes()) elif now.second == 0: - run_time_checks = not screen_off and not started or now.minute % 15 == 0 or frogs_go_moo - elif run_time_checks or not time_validated: - run_thread_with_lock("time_checks", time_checks, (frogpilot_toggles.automatic_updates, deviceState, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory)) - run_time_checks = False + run_update_checks = not screen_off and not started or now.minute % 15 == 0 or frogs_go_moo + elif run_update_checks: + run_thread_with_lock("update_checks", update_checks, (frogpilot_toggles.automatic_updates, model_manager, now, screen_off, started, theme_manager, time_validated, params, params_memory)) + if time_validated: + theme_manager.update_holiday() + + run_update_checks = False + + elif not time_validated: + time_validated = system_time_valid() if not time_validated: - time_validated = system_time_valid() - if not time_validated: - continue - run_thread_with_lock("update_models", model_manager.update_models, (True,)) - run_thread_with_lock("update_themes", theme_manager.update_themes, (True,)) - + continue theme_manager.update_holiday() + run_thread_with_lock("update_models", model_manager.update_models, (True,)) + run_thread_with_lock("update_themes", theme_manager.update_themes, (True,)) def main(): frogpilot_thread() + if __name__ == "__main__": main() diff --git a/selfdrive/frogpilot/frogpilot_utilities.py b/selfdrive/frogpilot/frogpilot_utilities.py new file mode 100644 index 00000000..4f666d30 --- /dev/null +++ b/selfdrive/frogpilot/frogpilot_utilities.py @@ -0,0 +1,104 @@ +import math +import numpy as np +import os +import shutil +import subprocess +import threading +import time +import urllib.request + +from openpilot.common.numpy_fast import interp, mean +from openpilot.common.params_pyx import Params + +EARTH_RADIUS = 6378137 # Radius of the Earth in meters + +def update_frogpilot_toggles(): + Params("/dev/shm/params").put_bool("FrogPilotTogglesUpdated", True) + +def calculate_distance_to_point(ax, ay, bx, by): + a = math.sin((bx - ax) / 2) * math.sin((bx - ax) / 2) + math.cos(ax) * math.cos(bx) * math.sin((by - ay) / 2) * math.sin((by - ay) / 2) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + return EARTH_RADIUS * c + +def calculate_lane_width(lane, current_lane, road_edge): + current_x = np.array(current_lane.x) + current_y = np.array(current_lane.y) + + lane_y_interp = interp(current_x, np.array(lane.x), np.array(lane.y)) + road_edge_y_interp = interp(current_x, np.array(road_edge.x), np.array(road_edge.y)) + + distance_to_lane = np.mean(np.abs(current_y - lane_y_interp)) + distance_to_road_edge = np.mean(np.abs(current_y - road_edge_y_interp)) + + return float(min(distance_to_lane, distance_to_road_edge)) + +# Credit goes to Pfeiferj! +def calculate_road_curvature(modelData, v_ego): + orientation_rate = np.abs(modelData.orientationRate.z) + velocity = modelData.velocity.x + max_pred_lat_acc = np.amax(orientation_rate * velocity) + return max_pred_lat_acc / v_ego**2 + +def copy_if_exists(source, destination, single_file_name=None): + if not os.path.exists(source): + print(f"Source directory {source} does not exist. Skipping copy.") + return + + if single_file_name: + os.makedirs(destination, exist_ok=True) + for item in os.listdir(source): + shutil.copy2(os.path.join(source, item), os.path.join(destination, single_file_name)) + print(f"Successfully copied {item} to {single_file_name}.") + else: + shutil.copytree(source, destination, dirs_exist_ok=True) + print(f"Successfully copied {source} to {destination}.") + +def delete_file(file): + try: + if os.path.isfile(file): + os.remove(file) + print(f"Deleted file: {file}") + else: + print(f"File not found: {file}") + except Exception as e: + print(f"An error occurred when deleting {file}: {e}") + +def is_url_pingable(url, timeout=5): + try: + urllib.request.urlopen(urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}), timeout=timeout) + return True + except Exception as e: + print(f"Failed to ping {url}: {e}") + return False + +def run_cmd(cmd, success_message, fail_message, retries=5, delay=1): + for attempt in range(retries): + try: + subprocess.check_call(cmd) + print(success_message) + return True + except Exception as e: + print(f"Unexpected error occurred (attempt {attempt + 1} of {retries}): {e}") + time.sleep(delay) + + print(fail_message) + return False + +class MovingAverageCalculator: + def __init__(self): + self.reset_data() + + def add_data(self, value): + if len(self.data) == 5: + self.total -= self.data.pop(0) + self.data.append(value) + self.total += value + + def get_moving_average(self): + if len(self.data) == 0: + return None + return self.total / len(self.data) + + def reset_data(self): + self.data = [] + self.total = 0 diff --git a/selfdrive/frogpilot/frogpilot_variables.py b/selfdrive/frogpilot/frogpilot_variables.py index 4c7fe27f..bd467db0 100644 --- a/selfdrive/frogpilot/frogpilot_variables.py +++ b/selfdrive/frogpilot/frogpilot_variables.py @@ -1,3 +1,5 @@ +import json +import math import os import random @@ -5,7 +7,7 @@ from types import SimpleNamespace from cereal import car from openpilot.common.conversions import Conversions as CV -from openpilot.common.numpy_fast import interp +from openpilot.common.numpy_fast import clip, interp from openpilot.common.params import Params, UnknownKeyName from openpilot.selfdrive.controls.lib.desire_helper import LANE_CHANGE_SPEED_MIN from openpilot.selfdrive.modeld.constants import ModelConstants @@ -23,29 +25,339 @@ CRUISING_SPEED = 5 # Roughly the speed cars MODEL_LENGTH = ModelConstants.IDX_N # Minimum length of the model PLANNER_TIME = ModelConstants.T_IDXS[MODEL_LENGTH - 1] # Length of time the model projects out for THRESHOLD = 0.6 # 60% chance of condition being true +TO_RADIANS = math.pi / 180 # Conversion factor from degrees to radians + + +def get_frogpilot_toggles(block=False): + toggles_dict = json.loads(Params().get("FrogPilotToggles", block=block)) + return SimpleNamespace(**toggles_dict) + + +def has_prime(): + return Params().get_int("PrimeType") > 0 + + +frogpilot_default_params: list[tuple[str, str | bytes]] = [ + ("AccelerationPath", "1"), + ("AccelerationProfile", "2"), + ("AdjacentLeadsUI", "1"), + ("AdjacentPath", "0"), + ("AdjacentPathMetrics", "0"), + ("AdvancedCustomUI", "0"), + ("AdvancedLateralTune", "0"), + ("AggressiveFollow", "1.25"), + ("AggressiveJerkAcceleration", "50"), + ("AggressiveJerkDanger", "100"), + ("AggressiveJerkDeceleration", "50"), + ("AggressiveJerkSpeed", "50"), + ("AggressiveJerkSpeedDecrease", "50"), + ("AggressivePersonalityProfile", "1"), + ("AlertVolumeControl", "0"), + ("AlwaysOnLateral", "1"), + ("AlwaysOnLateralLKAS", "0"), + ("AlwaysOnLateralMain", "1"), + ("AMapKey1", ""), + ("AMapKey2", ""), + ("AutomaticallyUpdateModels", "1"), + ("AutomaticUpdates", "1"), + ("AvailableModels", ""), + ("AvailableModelsNames", ""), + ("BigMap", "0"), + ("BlacklistedModels", ""), + ("BlindSpotMetrics", "1"), + ("BlindSpotPath", "1"), + ("BorderMetrics", "1"), + ("CameraView", "3"), + ("CarMake", ""), + ("CarModel", ""), + ("CarModelName", ""), + ("CECurves", "1"), + ("CECurvesLead", "0"), + ("CELead", "0"), + ("CEModelStopTime", "8"), + ("CENavigation", "1"), + ("CENavigationIntersections", "0"), + ("CENavigationLead", "0"), + ("CENavigationTurns", "1"), + ("CertifiedHerbalistCalibrationParams", ""), + ("CertifiedHerbalistDrives", "0"), + ("CertifiedHerbalistLiveTorqueParameters", ""), + ("CertifiedHerbalistScore", "0"), + ("CESignalSpeed", "55"), + ("CESignalLaneDetection", "1"), + ("CESlowerLead", "0"), + ("CESpeed", "0"), + ("CESpeedLead", "0"), + ("CEStoppedLead", "0"), + ("ClassicModels", ""), + ("ClusterOffset", "1.015"), + ("Compass", "0"), + ("ConditionalExperimental", "1"), + ("CrosstrekTorque", "1"), + ("CurveSensitivity", "100"), + ("CurveSpeedControl", "0"), + ("CustomAlerts", "1"), + ("CustomColors", "frog"), + ("CustomCruise", "1"), + ("CustomCruiseLong", "5"), + ("CustomDistanceIcons", "stock"), + ("CustomIcons", "frog-animated"), + ("CustomizationLevel", "0"), + ("CustomizationLevelConfirmed", "0"), + ("CustomPersonalities", "0"), + ("CustomSignals", "frog"), + ("CustomSounds", "frog"), + ("CustomUI", "1"), + ("DecelerationProfile", "1"), + ("DefaultModelName", DEFAULT_MODEL_NAME), + ("DeveloperUI", "0"), + ("DeviceManagement", "1"), + ("DeviceShutdown", "9"), + ("DisableCurveSpeedSmoothing", "0"), + ("DisableOnroadUploads", "0"), + ("DisableOpenpilotLongitudinal", "0"), + ("DisengageVolume", "101"), + ("DissolvedOxygenCalibrationParams", ""), + ("DissolvedOxygenDrives", "0"), + ("DissolvedOxygenLiveTorqueParameters", ""), + ("DissolvedOxygenScore", "0"), + ("DriverCamera", "0"), + ("DuckAmigoCalibrationParams", ""), + ("DuckAmigoDrives", "0"), + ("DuckAmigoLiveTorqueParameters", ""), + ("DuckAmigoScore", "0"), + ("DynamicPathWidth", "0"), + ("DynamicPedalsOnUI", "1"), + ("EngageVolume", "101"), + ("ExperimentalGMTune", "0"), + ("ExperimentalModeActivation", "1"), + ("ExperimentalModels", ""), + ("ExperimentalModeViaDistance", "1"), + ("ExperimentalModeViaLKAS", "1"), + ("ExperimentalModeViaTap", "0"), + ("Fahrenheit", "0"), + ("ForceAutoTune", "0"), + ("ForceAutoTuneOff", "0"), + ("ForceFingerprint", "0"), + ("ForceMPHDashboard", "0"), + ("ForceStandstill", "0"), + ("ForceStops", "0"), + ("FPSCounter", "1"), + ("FrogPilotToggles", "{}"), + ("FrogsGoMoosTweak", "1"), + ("FullMap", "0"), + ("GasRegenCmd", "1"), + ("GMapKey", ""), + ("GoatScream", "0"), + ("GreenLightAlert", "0"), + ("HideAlerts", "0"), + ("HideAOLStatusBar", "0"), + ("HideCEMStatusBar", "0"), + ("HideLeadMarker", "0"), + ("HideMapIcon", "0"), + ("HideMaxSpeed", "0"), + ("HideSpeed", "0"), + ("HolidayThemes", "1"), + ("HumanAcceleration", "1"), + ("HumanFollowing", "1"), + ("IncreasedStoppedDistance", "3"), + ("IncreaseThermalLimits", "0"), + ("JerkInfo", "1"), + ("LaneChangeCustomizations", "0"), + ("LaneChangeTime", "1.0"), + ("LaneDetectionWidth", "9"), + ("LaneLinesWidth", "4"), + ("LateralMetrics", "1"), + ("LateralTune", "1"), + ("LeadDepartingAlert", "0"), + ("LeadDetectionThreshold", "35"), + ("LeadInfo", "1"), + ("LockDoors", "1"), + ("LongitudinalMetrics", "1"), + ("LongitudinalTune", "1"), + ("LongPitch", "1"), + ("LosAngelesCalibrationParams", ""), + ("LosAngelesDrives", "0"), + ("LosAngelesLiveTorqueParameters", ""), + ("LosAngelesScore", "0"), + ("LoudBlindspotAlert", "0"), + ("LowVoltageShutdown", str(VBATT_PAUSE_CHARGING)), + ("MapAcceleration", "0"), + ("MapDeceleration", "0"), + ("MapGears", "0"), + ("MapboxPublicKey", ""), + ("MapboxSecretKey", ""), + ("MapsSelected", ""), + ("MapStyle", "0"), + ("MaxDesiredAcceleration", "4.0"), + ("MinimumLaneChangeSpeed", str(LANE_CHANGE_SPEED_MIN / CV.MPH_TO_MS)), + ("Model", DEFAULT_MODEL), + ("ModelName", DEFAULT_MODEL_NAME), + ("ModelRandomizer", "0"), + ("ModelUI", "1"), + ("MTSCCurvatureCheck", "1"), + ("MTSCEnabled", "1"), + ("NavigationModels", ""), + ("NavigationUI", "1"), + ("NewLongAPI", "0"), + ("NewLongAPIGM", "1"), + ("NewToyotaTune", "0"), + ("NNFF", "1"), + ("NNFFLite", "1"), + ("NoLogging", "0"), + ("NorthDakotaCalibrationParams", ""), + ("NorthDakotaDrives", "0"), + ("NorthDakotaLiveTorqueParameters", ""), + ("NorthDakotaScore", "0"), + ("NotreDameCalibrationParams", ""), + ("NotreDameDrives", "0"), + ("NotreDameLiveTorqueParameters", ""), + ("NotreDameScore", "0"), + ("NoUploads", "0"), + ("NudgelessLaneChange", "0"), + ("NumericalTemp", "1"), + ("OfflineMode", "1"), + ("Offset1", "5"), + ("Offset2", "5"), + ("Offset3", "5"), + ("Offset4", "10"), + ("OneLaneChange", "1"), + ("OnroadDistanceButton", "0"), + ("openpilotMinutes", "0"), + ("PathEdgeWidth", "20"), + ("PathWidth", "6.1"), + ("PauseAOLOnBrake", "0"), + ("PauseLateralOnSignal", "0"), + ("PauseLateralSpeed", "0"), + ("PedalsOnUI", "0"), + ("PersonalizeOpenpilot", "1"), + ("PreferredSchedule", "2"), + ("PromptDistractedVolume", "101"), + ("PromptVolume", "101"), + ("QOLLateral", "1"), + ("QOLLongitudinal", "1"), + ("QOLVisuals", "1"), + ("RadarlessModels", ""), + ("RadicalTurtleCalibrationParams", ""), + ("RadicalTurtleDrives", "0"), + ("RadicalTurtleLiveTorqueParameters", ""), + ("RadicalTurtleScore", "0"), + ("RandomEvents", "0"), + ("RecertifiedHerbalistCalibrationParams", ""), + ("RecertifiedHerbalistDrives", "0"), + ("RecertifiedHerbalistLiveTorqueParameters", ""), + ("RecertifiedHerbalistScore", "0"), + ("RefuseVolume", "101"), + ("RelaxedFollow", "1.75"), + ("RelaxedJerkAcceleration", "100"), + ("RelaxedJerkDanger", "100"), + ("RelaxedJerkDeceleration", "100"), + ("RelaxedJerkSpeed", "100"), + ("RelaxedJerkSpeedDecrease", "100"), + ("RelaxedPersonalityProfile", "1"), + ("ResetFrogTheme", "0"), + ("ReverseCruise", "0"), + ("RoadEdgesWidth", "2"), + ("RoadNameUI", "1"), + ("RotatingWheel", "1"), + ("ScreenBrightness", "101"), + ("ScreenBrightnessOnroad", "101"), + ("ScreenManagement", "1"), + ("ScreenRecorder", "1"), + ("ScreenTimeout", "30"), + ("ScreenTimeoutOnroad", "30"), + ("SearchInput", "0"), + ("SecretGoodOpenpilotCalibrationParams", ""), + ("SecretGoodOpenpilotDrives", "0"), + ("SecretGoodOpenpilotLiveTorqueParameters", ""), + ("SecretGoodOpenpilotScore", "0"), + ("SetSpeedLimit", "0"), + ("SetSpeedOffset", "0"), + ("ShowCPU", "1"), + ("ShowGPU", "0"), + ("ShowIP", "0"), + ("ShowMemoryUsage", "1"), + ("ShowSLCOffset", "1"), + ("ShowSteering", "1"), + ("ShowStoppingPoint", "1"), + ("ShowStoppingPointMetrics", "0"), + ("ShowStorageLeft", "0"), + ("ShowStorageUsed", "0"), + ("Sidebar", "0"), + ("SidebarMetrics", "1"), + ("SignalMetrics", "0"), + ("SLCConfirmation", "1"), + ("SLCConfirmationHigher", "1"), + ("SLCConfirmationLower", "1"), + ("SLCFallback", "2"), + ("SLCLookaheadHigher", "5"), + ("SLCLookaheadLower", "5"), + ("SLCOverride", "1"), + ("SLCPriority1", "Dashboard"), + ("SLCPriority2", "Navigation"), + ("SLCPriority3", "Offline Maps"), + ("SNGHack", "1"), + ("SpeedLimitChangedAlert", "1"), + ("SpeedLimitController", "1"), + ("StartupMessageBottom", "so I do what I want 🐸"), + ("StartupMessageTop", "Hippity hoppity this is my property"), + ("StandardFollow", "1.45"), + ("StandardJerkAcceleration", "100"), + ("StandardJerkDanger", "100"), + ("StandardJerkDeceleration", "100"), + ("StandardJerkSpeed", "100"), + ("StandardJerkSpeedDecrease", "100"), + ("StandardPersonalityProfile", "1"), + ("StandbyMode", "0"), + ("StaticPedalsOnUI", "0"), + ("SteerFriction", "0.1"), + ("SteerFrictionStock", "0.1"), + ("SteerLatAccel", "2.5"), + ("SteerLatAccelStock", "2.5"), + ("SteerKP", "1"), + ("SteerKPStock", "1"), + ("SteerRatio", "15"), + ("SteerRatioStock", "15"), + ("StoppedTimer", "0"), + ("TacoTune", "0"), + ("ToyotaDoors", "1"), + ("TrafficFollow", "0.5"), + ("TrafficJerkAcceleration", "50"), + ("TrafficJerkDanger", "100"), + ("TrafficJerkDeceleration", "50"), + ("TrafficJerkSpeed", "50"), + ("TrafficJerkSpeedDecrease", "50"), + ("TrafficPersonalityProfile", "1"), + ("TuningInfo", "1"), + ("TurnAggressiveness", "100"), + ("TurnDesires", "0"), + ("UnlimitedLength", "1"), + ("UnlockDoors", "1"), + ("UseSI", "1"), + ("UseVienna", "0"), + ("VisionTurnControl", "1"), + ("VoltSNG", "0"), + ("WarningImmediateVolume", "101"), + ("WarningSoftVolume", "101"), + ("WD40CalibrationParams", ""), + ("WD40Drives", "0"), + ("WD40LiveTorqueParameters", ""), + ("WD40Score", "0"), + ("WheelIcon", "frog"), + ("WheelSpeed", "0") +] + class FrogPilotVariables: def __init__(self): + self.default_frogpilot_toggles = SimpleNamespace(**dict(frogpilot_default_params)) self.frogpilot_toggles = SimpleNamespace() self.params = Params() self.params_memory = Params("/dev/shm/params") - self.has_prime = self.params.get_int("PrimeType") > 0 - - self.update_frogpilot_params(False) - - @property - def toggles(self): - return self.frogpilot_toggles - - @property - def toggles_updated(self): - return self.params_memory.get_bool("FrogPilotTogglesUpdated") - - def update_frogpilot_params(self, started=True): + def update(self, started): toggle = self.frogpilot_toggles - openpilot_installed = self.params.get_bool("HasAcceptedTerms") key = "CarParams" if started else "CarParamsPersistent" @@ -57,185 +369,227 @@ class FrogPilotVariables: car_make = CP.carName car_model = CP.carFingerprint has_auto_tune = (car_model == "hyundai" or car_model == "toyota") and CP.lateralTuning.which == "torque" + has_bsm = CP.enableBsm + has_radar = not CP.radarUnavailable is_pid_car = CP.lateralTuning.which == "pid" - max_acceleration_allowed = key == "CarParams" and CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX - toggle.openpilot_longitudinal = CP.openpilotLongitudinalControl + max_acceleration_enabled = key == "CarParams" and CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX + openpilot_longitudinal = CP.openpilotLongitudinalControl pcm_cruise = CP.pcmCruise else: always_on_lateral_set = False car_make = "mock" car_model = "mock" has_auto_tune = False + has_bsm = False + has_radar = False is_pid_car = False - max_acceleration_allowed = False - toggle.openpilot_longitudinal = False + max_acceleration_enabled = False + openpilot_longitudinal = False pcm_cruise = False toggle.is_metric = self.params.get_bool("IsMetric") - distance_conversion = 1. if toggle.is_metric else CV.FOOT_TO_METER + distance_conversion = 1 if toggle.is_metric else CV.FOOT_TO_METER + small_distance_conversion = 1 if toggle.is_metric else CV.INCH_TO_CM speed_conversion = CV.KPH_TO_MS if toggle.is_metric else CV.MPH_TO_MS - advanced_custom_onroad_ui = self.params.get_bool("AdvancedCustomUI") - toggle.show_stopping_point = advanced_custom_onroad_ui and self.params.get_bool("ShowStoppingPoint") + toggle.advanced_custom_onroad_ui = self.params.get_bool("AdvancedCustomUI") + toggle.hide_lead_marker = toggle.advanced_custom_onroad_ui and self.params.get_bool("HideLeadMarker") + toggle.hide_speed = toggle.advanced_custom_onroad_ui and self.params.get_bool("HideSpeed") + toggle.hide_map_icon = toggle.advanced_custom_onroad_ui and self.params.get_bool("HideMapIcon") + toggle.hide_max_speed = toggle.advanced_custom_onroad_ui and self.params.get_bool("HideMaxSpeed") + toggle.hide_alerts = toggle.advanced_custom_onroad_ui and self.params.get_bool("HideAlerts") + toggle.use_wheel_speed = toggle.advanced_custom_onroad_ui and self.params.get_bool("WheelSpeed") - advanced_lateral_tune = self.params.get_bool("AdvancedLateralTune") + toggle.advanced_lateral_tuning = self.params.get_bool("AdvancedLateralTune") stock_steer_friction = self.params.get_float("SteerFrictionStock") - toggle.steer_friction = self.params.get_float("SteerFriction") if advanced_lateral_tune else stock_steer_friction + toggle.steer_friction = self.params.get_float("SteerFriction") if toggle.advanced_lateral_tuning else stock_steer_friction toggle.use_custom_steer_friction = toggle.steer_friction != stock_steer_friction and not is_pid_car - stock_steer_lat_accel_factor = self.params.get_float("SteerLatAccelStock") - toggle.steer_lat_accel_factor = self.params.get_float("SteerLatAccel") if advanced_lateral_tune else stock_steer_lat_accel_factor - toggle.use_custom_lat_accel_factor = toggle.steer_lat_accel_factor != stock_steer_lat_accel_factor and not is_pid_car stock_steer_kp = self.params.get_float("SteerKPStock") - toggle.steer_kp = self.params.get_float("SteerKP") if advanced_lateral_tune else stock_steer_kp + toggle.steer_kp = self.params.get_float("SteerKP") if toggle.advanced_lateral_tuning else stock_steer_kp toggle.use_custom_kp = toggle.steer_kp != stock_steer_kp and not is_pid_car + stock_steer_lat_accel_factor = self.params.get_float("SteerLatAccelStock") + toggle.steer_lat_accel_factor = self.params.get_float("SteerLatAccel") if toggle.advanced_lateral_tuning else stock_steer_lat_accel_factor + toggle.use_custom_lat_accel_factor = toggle.steer_lat_accel_factor != stock_steer_lat_accel_factor and not is_pid_car stock_steer_ratio = self.params.get_float("SteerRatioStock") - toggle.steer_ratio = self.params.get_float("SteerRatio") if advanced_lateral_tune else stock_steer_ratio + toggle.steer_ratio = self.params.get_float("SteerRatio") if toggle.advanced_lateral_tuning else stock_steer_ratio toggle.use_custom_steer_ratio = toggle.steer_ratio != stock_steer_ratio - toggle.force_auto_tune = advanced_lateral_tune and not has_auto_tune and self.params.get_bool("ForceAutoTune") - toggle.force_auto_tune_off = advanced_lateral_tune and has_auto_tune and self.params.get_bool("ForceAutoTuneOff") - toggle.taco_tune = advanced_lateral_tune and self.params.get_bool("TacoTune") - toggle.turn_desires = advanced_lateral_tune and self.params.get_bool("TurnDesires") - - advanced_longitudinal_tune = toggle.openpilot_longitudinal and self.params.get_bool("LongitudinalTune") - toggle.lead_detection_threshold = self.params.get_int("LeadDetectionThreshold") / 100. if advanced_longitudinal_tune else 0.5 - toggle.max_desired_accel = self.params.get_float("MaxDesiredAcceleration") if advanced_longitudinal_tune else 4.0 - - advanced_quality_of_life_driving = self.params.get_bool("AdvancedQOLDriving") - toggle.force_standstill = advanced_quality_of_life_driving and self.params.get_bool("ForceStandstill") - toggle.force_stops = advanced_quality_of_life_driving and self.params.get_bool("ForceStops") - toggle.set_speed_offset = self.params.get_int("SetSpeedOffset") * (1. if toggle.is_metric else CV.MPH_TO_KPH) if advanced_quality_of_life_driving and not pcm_cruise else 0 + toggle.force_auto_tune = toggle.advanced_lateral_tuning and not has_auto_tune and not is_pid_car and self.params.get_bool("ForceAutoTune") + toggle.force_auto_tune_off = toggle.advanced_lateral_tuning and has_auto_tune and not is_pid_car and self.params.get_bool("ForceAutoTuneOff") toggle.alert_volume_control = self.params.get_bool("AlertVolumeControl") - toggle.disengage_volume = self.params.get_int("DisengageVolume") if toggle.alert_volume_control else 100 - toggle.engage_volume = self.params.get_int("EngageVolume") if toggle.alert_volume_control else 100 - toggle.prompt_volume = self.params.get_int("PromptVolume") if toggle.alert_volume_control else 100 - toggle.promptDistracted_volume = self.params.get_int("PromptDistractedVolume") if toggle.alert_volume_control else 100 - toggle.refuse_volume = self.params.get_int("RefuseVolume") if toggle.alert_volume_control else 100 - toggle.warningSoft_volume = self.params.get_int("WarningSoftVolume") if toggle.alert_volume_control else 100 - toggle.warningImmediate_volume = max(self.params.get_int("WarningImmediateVolume"), 25) if toggle.alert_volume_control else 100 + toggle.disengage_volume = self.params.get_int("DisengageVolume") if toggle.alert_volume_control else 101 + toggle.engage_volume = self.params.get_int("EngageVolume") if toggle.alert_volume_control else 101 + toggle.prompt_volume = self.params.get_int("PromptVolume") if toggle.alert_volume_control else 101 + toggle.promptDistracted_volume = self.params.get_int("PromptDistractedVolume") if toggle.alert_volume_control else 101 + toggle.refuse_volume = self.params.get_int("RefuseVolume") if toggle.alert_volume_control else 101 + toggle.warningSoft_volume = self.params.get_int("WarningSoftVolume") if toggle.alert_volume_control else 101 + toggle.warningImmediate_volume = max(self.params.get_int("WarningImmediateVolume"), 25) if toggle.alert_volume_control else 101 toggle.always_on_lateral = always_on_lateral_set and self.params.get_bool("AlwaysOnLateral") toggle.always_on_lateral_lkas = toggle.always_on_lateral and car_make != "subaru" and self.params.get_bool("AlwaysOnLateralLKAS") toggle.always_on_lateral_main = toggle.always_on_lateral and self.params.get_bool("AlwaysOnLateralMain") toggle.always_on_lateral_pause_speed = self.params.get_int("PauseAOLOnBrake") if toggle.always_on_lateral else 0 + toggle.always_on_lateral_status_bar = toggle.always_on_lateral and not self.params.get_bool("HideAOLStatusBar") toggle.automatic_updates = self.params.get_bool("AutomaticUpdates") toggle.cluster_offset = self.params.get_float("ClusterOffset") if car_make == "toyota" else 1 - toggle.conditional_experimental_mode = toggle.openpilot_longitudinal and self.params.get_bool("ConditionalExperimental") - toggle.conditional_limit = self.params.get_int("CESpeed") * speed_conversion if toggle.conditional_experimental_mode else 0 - toggle.conditional_limit_lead = self.params.get_int("CESpeedLead") * speed_conversion if toggle.conditional_experimental_mode else 0 + toggle.conditional_experimental_mode = openpilot_longitudinal and self.params.get_bool("ConditionalExperimental") toggle.conditional_curves = toggle.conditional_experimental_mode and self.params.get_bool("CECurves") toggle.conditional_curves_lead = toggle.conditional_curves and self.params.get_bool("CECurvesLead") toggle.conditional_lead = toggle.conditional_experimental_mode and self.params.get_bool("CELead") toggle.conditional_slower_lead = toggle.conditional_lead and self.params.get_bool("CESlowerLead") toggle.conditional_stopped_lead = toggle.conditional_lead and self.params.get_bool("CEStoppedLead") + toggle.conditional_limit = self.params.get_int("CESpeed") * speed_conversion if toggle.conditional_experimental_mode else 0 + toggle.conditional_limit_lead = self.params.get_int("CESpeedLead") * speed_conversion if toggle.conditional_experimental_mode else 0 toggle.conditional_navigation = toggle.conditional_experimental_mode and self.params.get_bool("CENavigation") toggle.conditional_navigation_intersections = toggle.conditional_navigation and self.params.get_bool("CENavigationIntersections") toggle.conditional_navigation_lead = toggle.conditional_navigation and self.params.get_bool("CENavigationLead") toggle.conditional_navigation_turns = toggle.conditional_navigation and self.params.get_bool("CENavigationTurns") toggle.conditional_model_stop_time = self.params.get_int("CEModelStopTime") if toggle.conditional_experimental_mode else 0 toggle.conditional_signal = self.params.get_int("CESignalSpeed") if toggle.conditional_experimental_mode else 0 - toggle.conditional_signal_lane_detection = toggle.conditional_signal and self.params.get_bool("CESignalLaneDetection") + toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and self.params.get_bool("CESignalLaneDetection") + toggle.conditional_status_bar = toggle.conditional_experimental_mode and not self.params.get_bool("HideCEMStatusBar") if toggle.conditional_experimental_mode: self.params.put_bool("ExperimentalMode", True) + toggle.crosstrek_torque = car_model == "SUBARU_IMPREZA" and self.params.get_bool("CrosstrekTorque") + toggle.current_holiday_theme = self.params.get("CurrentHolidayTheme", encoding='utf-8') if self.params.get_bool("HolidayThemes") else None - curve_speed_controller = toggle.openpilot_longitudinal and self.params.get_bool("CurveSpeedControl") - toggle.map_turn_speed_controller = curve_speed_controller and self.params.get_bool("MTSCEnabled") + toggle.curve_speed_controller = openpilot_longitudinal and self.params.get_bool("CurveSpeedControl") + toggle.curve_sensitivity = self.params.get_int("CurveSensitivity") / 100 if toggle.curve_speed_controller else 1 + toggle.turn_aggressiveness = self.params.get_int("TurnAggressiveness") / 100 if toggle.curve_speed_controller else 1 + toggle.disable_curve_speed_smoothing = toggle.curve_speed_controller and self.params.get_bool("DisableCurveSpeedSmoothing") + toggle.map_turn_speed_controller = toggle.curve_speed_controller and self.params.get_bool("MTSCEnabled") toggle.mtsc_curvature_check = toggle.map_turn_speed_controller and self.params.get_bool("MTSCCurvatureCheck") - toggle.vision_turn_controller = curve_speed_controller and self.params.get_bool("VisionTurnControl") - toggle.curve_sensitivity = self.params.get_int("CurveSensitivity") / 100. if curve_speed_controller else 1 - toggle.turn_aggressiveness = self.params.get_int("TurnAggressiveness") / 100. if curve_speed_controller else 1 + toggle.vision_turn_controller = toggle.curve_speed_controller and self.params.get_bool("VisionTurnControl") - custom_alerts = self.params.get_bool("CustomAlerts") - toggle.goat_scream = toggle.current_holiday_theme is None and custom_alerts and self.params.get_bool("GoatScream") - toggle.green_light_alert = custom_alerts and self.params.get_bool("GreenLightAlert") - toggle.lead_departing_alert = custom_alerts and self.params.get_bool("LeadDepartingAlert") - toggle.loud_blindspot_alert = custom_alerts and self.params.get_bool("LoudBlindspotAlert") + toggle.custom_alerts = self.params.get_bool("CustomAlerts") + toggle.goat_scream_alert = toggle.current_holiday_theme is None and toggle.custom_alerts and self.params.get_bool("GoatScream") + toggle.green_light_alert = toggle.custom_alerts and self.params.get_bool("GreenLightAlert") + toggle.lead_departing_alert = toggle.custom_alerts and self.params.get_bool("LeadDepartingAlert") + toggle.loud_blindspot_alert = has_bsm and toggle.custom_alerts and self.params.get_bool("LoudBlindspotAlert") + toggle.speed_limit_changed_alert = toggle.custom_alerts and self.params.get_bool("SpeedLimitChangedAlert") - toggle.custom_personalities = toggle.openpilot_longitudinal and self.params.get_bool("CustomPersonalities") - aggressive_profile = toggle.custom_personalities and self.params.get_bool("AggressivePersonalityProfile") - toggle.aggressive_jerk_acceleration = self.params.get_int("AggressiveJerkAcceleration") / 100. if aggressive_profile else 0.5 - toggle.aggressive_jerk_deceleration = self.params.get_int("AggressiveJerkDeceleration") / 100. if aggressive_profile else 0.5 - toggle.aggressive_jerk_danger = self.params.get_int("AggressiveJerkDanger") / 100. if aggressive_profile else 0.5 - toggle.aggressive_jerk_speed = self.params.get_int("AggressiveJerkSpeed") / 100. if aggressive_profile else 0.5 - toggle.aggressive_jerk_speed_decrease = self.params.get_int("AggressiveJerkSpeedDecrease") / 100. if aggressive_profile else 0.5 - toggle.aggressive_follow = self.params.get_float("AggressiveFollow") if aggressive_profile else 1.25 - standard_profile = toggle.custom_personalities and self.params.get_bool("StandardPersonalityProfile") - toggle.standard_jerk_acceleration = self.params.get_int("StandardJerkAcceleration") / 100. if standard_profile else 1.0 - toggle.standard_jerk_deceleration = self.params.get_int("StandardJerkDeceleration") / 100. if standard_profile else 1.0 - toggle.standard_jerk_danger = self.params.get_int("StandardJerkDanger") / 100. if standard_profile else 0.5 - toggle.standard_jerk_speed = self.params.get_int("StandardJerkSpeed") / 100. if standard_profile else 1.0 - toggle.standard_jerk_speed_decrease = self.params.get_int("StandardJerkSpeedDecrease") / 100. if standard_profile else 1.0 - toggle.standard_follow = self.params.get_float("StandardFollow") if standard_profile else 1.45 - relaxed_profile = toggle.custom_personalities and self.params.get_bool("RelaxedPersonalityProfile") - toggle.relaxed_jerk_acceleration = self.params.get_int("RelaxedJerkAcceleration") / 100. if relaxed_profile else 1.0 - toggle.relaxed_jerk_deceleration = self.params.get_int("RelaxedJerkDeceleration") / 100. if relaxed_profile else 1.0 - toggle.relaxed_jerk_danger = self.params.get_int("RelaxedJerkDanger") / 100. if relaxed_profile else 0.5 - toggle.relaxed_jerk_speed = self.params.get_int("RelaxedJerkSpeed") / 100. if relaxed_profile else 1.0 - toggle.relaxed_jerk_speed_decrease = self.params.get_int("RelaxedJerkSpeedDecrease") / 100. if relaxed_profile else 1.0 - toggle.relaxed_follow = self.params.get_float("RelaxedFollow") if relaxed_profile else 1.75 - traffic_profile = toggle.custom_personalities and self.params.get_bool("TrafficPersonalityProfile") - toggle.traffic_mode_jerk_acceleration = [self.params.get_int("TrafficJerkAcceleration") / 100., toggle.aggressive_jerk_acceleration] if traffic_profile else [0.5, 0.5] - toggle.traffic_mode_jerk_deceleration = [self.params.get_int("TrafficJerkDeceleration") / 100., toggle.aggressive_jerk_deceleration] if traffic_profile else [0.5, 0.5] - toggle.traffic_mode_jerk_danger = [self.params.get_int("TrafficJerkDanger") / 100., toggle.aggressive_jerk_danger] if traffic_profile else [1.0, 1.0] - toggle.traffic_mode_jerk_speed = [self.params.get_int("TrafficJerkSpeed") / 100., toggle.aggressive_jerk_speed] if traffic_profile else [0.5, 0.5] - toggle.traffic_mode_jerk_speed_decrease = [self.params.get_int("TrafficJerkSpeedDecrease") / 100., toggle.aggressive_jerk_speed_decrease] if traffic_profile else [0.5, 0.5] - toggle.traffic_mode_t_follow = [self.params.get_float("TrafficFollow"), toggle.aggressive_follow] if traffic_profile else [0.5, 1.0] + toggle.custom_personalities = openpilot_longitudinal and self.params.get_bool("CustomPersonalities") + toggle.aggressive_profile = toggle.custom_personalities and self.params.get_bool("AggressivePersonalityProfile") + toggle.aggressive_jerk_acceleration = clip(self.params.get_int("AggressiveJerkAcceleration") / 100, 0.01, 5) if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_deceleration = clip(self.params.get_int("AggressiveJerkDeceleration") / 100, 0.01, 5) if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_danger = clip(self.params.get_int("AggressiveJerkDanger") / 100, 0.01, 5) if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_speed = clip(self.params.get_int("AggressiveJerkSpeed") / 100, 0.01, 5) if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_speed_decrease = clip(self.params.get_int("AggressiveJerkSpeedDecrease") / 100, 0.01, 5) if toggle.aggressive_profile else 0.5 + toggle.aggressive_follow = clip(self.params.get_float("AggressiveFollow"), 1, 5) if toggle.aggressive_profile else 1.25 + toggle.standard_profile = toggle.custom_personalities and self.params.get_bool("StandardPersonalityProfile") + toggle.standard_jerk_acceleration = clip(self.params.get_int("StandardJerkAcceleration") / 100, 0.01, 5) if toggle.standard_profile else 1.0 + toggle.standard_jerk_deceleration = clip(self.params.get_int("StandardJerkDeceleration") / 100, 0.01, 5) if toggle.standard_profile else 1.0 + toggle.standard_jerk_danger = clip(self.params.get_int("StandardJerkDanger") / 100, 0.01, 5) if toggle.standard_profile else 0.5 + toggle.standard_jerk_speed = clip(self.params.get_int("StandardJerkSpeed") / 100, 0.01, 5) if toggle.standard_profile else 1.0 + toggle.standard_jerk_speed_decrease = clip(self.params.get_int("StandardJerkSpeedDecrease") / 100, 0.01, 5) if toggle.standard_profile else 1.0 + toggle.standard_follow = clip(self.params.get_float("StandardFollow"), 1, 5) if toggle.standard_profile else 1.45 + toggle.relaxed_profile = toggle.custom_personalities and self.params.get_bool("RelaxedPersonalityProfile") + toggle.relaxed_jerk_acceleration = clip(self.params.get_int("RelaxedJerkAcceleration") / 100, 0.01, 5) if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_deceleration = clip(self.params.get_int("RelaxedJerkDeceleration") / 100, 0.01, 5) if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_danger = clip(self.params.get_int("RelaxedJerkDanger") / 100, 0.01, 5) if toggle.relaxed_profile else 0.5 + toggle.relaxed_jerk_speed = clip(self.params.get_int("RelaxedJerkSpeed") / 100, 0.01, 5) if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_speed_decrease = clip(self.params.get_int("RelaxedJerkSpeedDecrease") / 100, 0.01, 5) if toggle.relaxed_profile else 1.0 + toggle.relaxed_follow = clip(self.params.get_float("RelaxedFollow"), 1, 5) if toggle.relaxed_profile else 1.75 + toggle.traffic_profile = toggle.custom_personalities and self.params.get_bool("TrafficPersonalityProfile") + toggle.traffic_mode_jerk_acceleration = [clip(self.params.get_int("TrafficJerkAcceleration") / 100, 0.01, 5), toggle.aggressive_jerk_acceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_deceleration = [clip(self.params.get_int("TrafficJerkDeceleration") / 100, 0.01, 5), toggle.aggressive_jerk_deceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_danger = [clip(self.params.get_int("TrafficJerkDanger") / 100, 0.01, 5), toggle.aggressive_jerk_danger] if toggle.traffic_profile else [1.0, 1.0] + toggle.traffic_mode_jerk_speed = [clip(self.params.get_int("TrafficJerkSpeed") / 100, 0.01, 5), toggle.aggressive_jerk_speed] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_speed_decrease = [clip(self.params.get_int("TrafficJerkSpeedDecrease") / 100, 0.01, 5), toggle.aggressive_jerk_speed_decrease] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_t_follow = [clip(self.params.get_float("TrafficFollow"), 0.5, 5), toggle.aggressive_follow] if toggle.traffic_profile else [0.5, 1.0] - custom_ui = self.params.get_bool("CustomUI") - custom_paths = custom_ui and self.params.get_bool("CustomPaths") - toggle.adjacent_lanes = custom_paths and self.params.get_bool("AdjacentPath") - toggle.blind_spot_path = custom_paths and self.params.get_bool("BlindSpotPath") + toggle.custom_ui = self.params.get_bool("CustomUI") + toggle.acceleration_path = toggle.custom_ui and self.params.get_bool("AccelerationPath") + toggle.adjacent_paths = toggle.custom_ui and self.params.get_bool("AdjacentPath") + toggle.blind_spot_path = has_bsm and toggle.custom_ui and self.params.get_bool("BlindSpotPath") + toggle.compass = toggle.custom_ui and self.params.get_bool("Compass") + toggle.pedals_on_ui = toggle.custom_ui and self.params.get_bool("PedalsOnUI") + toggle.dynamic_pedals_on_ui = toggle.pedals_on_ui and self.params.get_bool("DynamicPedalsOnUI") + toggle.static_pedals_on_ui = toggle.pedals_on_ui and self.params.get_bool("StaticPedalsOnUI") + toggle.rotating_wheel = toggle.custom_ui and self.params.get_bool("RotatingWheel") - developer_ui = self.params.get_bool("DeveloperUI") - show_lateral = developer_ui and self.params.get_bool("LateralMetrics") - toggle.adjacent_path_metrics = show_lateral and self.params.get_bool("AdjacentPathMetrics") + toggle.developer_ui = self.params.get_bool("DeveloperUI") + toggle.border_metrics = toggle.developer_ui and self.params.get_bool("BorderMetrics") + toggle.blind_spot_metrics = has_bsm and toggle.border_metrics and self.params.get_bool("BlindSpotMetrics") + toggle.signal_metrics = toggle.border_metrics and self.params.get_bool("SignalMetrics") + toggle.steering_metrics = toggle.border_metrics and self.params.get_bool("ShowSteering") + toggle.show_fps = toggle.developer_ui and self.params.get_bool("FPSCounter") + toggle.lateral_metrics = toggle.developer_ui and self.params.get_bool("LateralMetrics") + toggle.adjacent_path_metrics = toggle.lateral_metrics and self.params.get_bool("AdjacentPathMetrics") + toggle.lateral_tuning_metrics = toggle.lateral_metrics and self.params.get_bool("TuningInfo") + toggle.longitudinal_metrics = toggle.developer_ui and self.params.get_bool("LongitudinalMetrics") + toggle.adjacent_lead_tracking = has_radar and toggle.longitudinal_metrics and self.params.get_bool("AdjacentLeadsUI") + toggle.lead_metrics = toggle.longitudinal_metrics and self.params.get_bool("LeadInfo") + toggle.jerk_metrics = toggle.longitudinal_metrics and self.params.get_bool("JerkInfo") + toggle.numerical_temp = toggle.developer_ui and self.params.get_bool("NumericalTemp") + toggle.fahrenheit = toggle.numerical_temp and self.params.get_bool("Fahrenheit") + toggle.sidebar_metrics = toggle.developer_ui and self.params.get_bool("SidebarMetrics") + toggle.cpu_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowCPU") + toggle.gpu_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowGPU") + toggle.ip_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowIP") + toggle.memory_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowMemoryUsage") + toggle.storage_left_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowStorageLeft") + toggle.storage_used_metrics = toggle.sidebar_metrics and self.params.get_bool("ShowStorageUsed") + toggle.use_si_metrics = toggle.developer_ui and self.params.get_bool("UseSI") toggle.device_management = self.params.get_bool("DeviceManagement") device_shutdown_setting = self.params.get_int("DeviceShutdown") if toggle.device_management else 33 toggle.device_shutdown_time = (device_shutdown_setting - 3) * 3600 if device_shutdown_setting >= 4 else device_shutdown_setting * (60 * 15) toggle.increase_thermal_limits = toggle.device_management and self.params.get_bool("IncreaseThermalLimits") - toggle.low_voltage_shutdown = self.params.get_float("LowVoltageShutdown") if toggle.device_management else VBATT_PAUSE_CHARGING + toggle.low_voltage_shutdown = clip(self.params.get_float("LowVoltageShutdown"), VBATT_PAUSE_CHARGING, 12.5) if toggle.device_management else VBATT_PAUSE_CHARGING + toggle.no_logging = toggle.device_management and self.params.get_bool("NoLogging") + toggle.no_uploads = toggle.device_management and self.params.get_bool("NoUploads") toggle.offline_mode = toggle.device_management and self.params.get_bool("OfflineMode") - toggle.experimental_mode_via_press = toggle.openpilot_longitudinal and self.params.get_bool("ExperimentalModeActivation") + toggle.experimental_gm_tune = openpilot_longitudinal and car_make == "gm" and self.params.get_bool("ExperimentalGMTune") + + toggle.experimental_mode_via_press = openpilot_longitudinal and self.params.get_bool("ExperimentalModeActivation") toggle.experimental_mode_via_distance = toggle.experimental_mode_via_press and self.params.get_bool("ExperimentalModeViaDistance") toggle.experimental_mode_via_lkas = not toggle.always_on_lateral_lkas and toggle.experimental_mode_via_press and car_make != "subaru" and self.params.get_bool("ExperimentalModeViaLKAS") + toggle.experimental_mode_via_tap = toggle.experimental_mode_via_press and self.params.get_bool("ExperimentalModeViaTap") - lane_change_customizations = self.params.get_bool("LaneChangeCustomizations") - toggle.lane_change_delay = self.params.get_int("LaneChangeTime") if lane_change_customizations else 0 - toggle.lane_detection_width = self.params.get_int("LaneDetectionWidth") * distance_conversion if lane_change_customizations else 0 + toggle.frogsgomoo_tweak = openpilot_longitudinal and car_make == "toyota" and self.params.get_bool("FrogsGoMoosTweak") + + toggle.lane_change_customizations = self.params.get_bool("LaneChangeCustomizations") + toggle.lane_change_delay = self.params.get_float("LaneChangeTime") if toggle.lane_change_customizations else 0 + toggle.lane_detection_width = self.params.get_float("LaneDetectionWidth") * distance_conversion if toggle.lane_change_customizations else 0 toggle.lane_detection = toggle.lane_detection_width != 0 - toggle.minimum_lane_change_speed = self.params.get_int("MinimumLaneChangeSpeed") * speed_conversion if lane_change_customizations else LANE_CHANGE_SPEED_MIN - toggle.nudgeless = lane_change_customizations and self.params.get_bool("NudgelessLaneChange") - toggle.one_lane_change = lane_change_customizations and self.params.get_bool("OneLaneChange") + toggle.minimum_lane_change_speed = self.params.get_int("MinimumLaneChangeSpeed") * speed_conversion if toggle.lane_change_customizations else LANE_CHANGE_SPEED_MIN + toggle.nudgeless = toggle.lane_change_customizations and self.params.get_bool("NudgelessLaneChange") + toggle.one_lane_change = toggle.lane_change_customizations and self.params.get_bool("OneLaneChange") - toggle.long_pitch = toggle.openpilot_longitudinal and car_make == "gm" and self.params.get_bool("LongPitch") - toggle.volt_sng = car_model == "CHEVROLET_VOLT" and self.params.get_bool("VoltSNG") + toggle.lateral_tuning = self.params.get_bool("LateralTune") + toggle.nnff = toggle.lateral_tuning and self.params.get_bool("NNFF") + toggle.smooth_curve_handling = toggle.lateral_tuning and self.params.get_bool("NNFFLite") + toggle.taco_tune = toggle.lateral_tuning and self.params.get_bool("TacoTune") + toggle.use_turn_desires = toggle.lateral_tuning and self.params.get_bool("TurnDesires") - longitudinal_tune = toggle.openpilot_longitudinal and self.params.get_bool("LongitudinalTune") - toggle.acceleration_profile = self.params.get_int("AccelerationProfile") if longitudinal_tune else 0 - toggle.sport_plus = max_acceleration_allowed and toggle.acceleration_profile == 3 - toggle.deceleration_profile = self.params.get_int("DecelerationProfile") if longitudinal_tune else 0 - toggle.human_acceleration = longitudinal_tune and self.params.get_bool("HumanAcceleration") - toggle.human_following = longitudinal_tune and self.params.get_bool("HumanFollowing") - toggle.increase_stopped_distance = self.params.get_int("IncreasedStoppedDistance") * distance_conversion if longitudinal_tune else 0 + toggle.long_pitch = openpilot_longitudinal and car_make == "gm" and self.params.get_bool("LongPitch") - toggle.model_manager = self.params.get_bool("ModelManagement", block=openpilot_installed) - available_models = self.params.get("AvailableModels", block=toggle.model_manager, encoding='utf-8') or "" - available_model_names = self.params.get("AvailableModelsNames", block=toggle.model_manager, encoding='utf-8') or "" - if toggle.model_manager and available_models: - toggle.model_randomizer = self.params.get_bool("ModelRandomizer") - if toggle.model_randomizer: + toggle.longitudinal_tuning = openpilot_longitudinal and self.params.get_bool("LongitudinalTune") + toggle.acceleration_profile = self.params.get_int("AccelerationProfile") if toggle.longitudinal_tuning else 0 + toggle.sport_plus = max_acceleration_enabled and toggle.acceleration_profile == 3 + toggle.deceleration_profile = self.params.get_int("DecelerationProfile") if toggle.longitudinal_tuning else 0 + toggle.human_acceleration = toggle.longitudinal_tuning and self.params.get_bool("HumanAcceleration") + toggle.human_following = toggle.longitudinal_tuning and self.params.get_bool("HumanFollowing") + toggle.increased_stopped_distance = self.params.get_int("IncreasedStoppedDistance") * distance_conversion if toggle.longitudinal_tuning else 0 + toggle.lead_detection_probability = clip(self.params.get_int("LeadDetectionThreshold") / 100, 0.01, 0.99) if toggle.longitudinal_tuning else 0.5 + toggle.max_desired_acceleration = clip(self.params.get_float("MaxDesiredAcceleration"), 0.1, 4.0) if toggle.longitudinal_tuning else 4.0 + + available_models = self.params.get("AvailableModels", block=openpilot_installed and started, encoding='utf-8') or "" + available_model_names = self.params.get("AvailableModelsNames", block=openpilot_installed and started, encoding='utf-8') or "" + if available_models: + if self.params.get_bool("ModelRandomizer"): blacklisted_models = (self.params.get("BlacklistedModels", encoding='utf-8') or "").split(',') existing_models = [model for model in available_models.split(',') if model not in blacklisted_models and os.path.exists(os.path.join(MODELS_PATH, f"{model}.thneed"))] toggle.model = random.choice(existing_models) if existing_models else DEFAULT_MODEL else: - toggle.model = self.params.get("Model", block=True, encoding='utf-8') + toggle.model = self.params.get("Model", block=openpilot_installed and started, encoding='utf-8') else: toggle.model = DEFAULT_MODEL if toggle.model in available_models.split(',') and os.path.exists(os.path.join(MODELS_PATH, f"{toggle.model}.thneed")): @@ -246,66 +600,558 @@ class FrogPilotVariables: self.params.check_key(toggle.part_model_param + "CalibrationParams") except UnknownKeyName: toggle.part_model_param = "" - elif toggle.model == "secret-good-openpilot": - toggle.part_model_param = "SecretGoodOpenpilot" else: toggle.model = DEFAULT_MODEL toggle.part_model_param = "" + classic_models = self.params.get("ClassicModels", encoding='utf-8') or "" + toggle.classic_model = classic_models and toggle.model in classic_models.split(',') navigation_models = self.params.get("NavigationModels", encoding='utf-8') or "" toggle.navigationless_model = navigation_models and toggle.model not in navigation_models.split(',') radarless_models = self.params.get("RadarlessModels", encoding='utf-8') or "" toggle.radarless_model = radarless_models and toggle.model in radarless_models.split(',') - toggle.secretgoodopenpilot_model = toggle.model == "secret-good-openpilot" - velocity_models = self.params.get("VelocityModels", encoding='utf-8') or "" - toggle.velocity_model = velocity_models and toggle.model in velocity_models.split(',') + + toggle.model_ui = self.params.get_bool("ModelUI") + toggle.dynamic_path_width = toggle.model_ui and self.params.get_bool("DynamicPathWidth") + toggle.lane_line_width = self.params.get_int("LaneLinesWidth") * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.path_edge_width = self.params.get_int("PathEdgeWidth") if toggle.model_ui else 20 + toggle.path_width = self.params.get_float("PathWidth") * distance_conversion / 2 if toggle.model_ui else 0.9 + toggle.road_edge_width = self.params.get_int("RoadEdgesWidth") * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.show_stopping_point = toggle.model_ui and self.params.get_bool("ShowStoppingPoint") + toggle.show_stopping_point_metrics = toggle.show_stopping_point and self.params.get_bool("ShowStoppingPointMetrics") + toggle.unlimited_road_ui_length = toggle.model_ui and self.params.get_bool("UnlimitedLength") + + toggle.navigation_ui = self.params.get_bool("NavigationUI") + toggle.big_map = toggle.navigation_ui and self.params.get_bool("BigMap") + toggle.full_map = toggle.big_map and self.params.get_bool("FullMap") + toggle.map_style = self.params.get_int("MapStyle") if toggle.navigation_ui else 0 + toggle.road_name_ui = toggle.navigation_ui and self.params.get_bool("RoadNameUI") + toggle.show_speed_limit_offset = toggle.navigation_ui and self.params.get_bool("ShowSLCOffset") + toggle.speed_limit_vienna = toggle.navigation_ui and self.params.get_bool("UseVienna") + + toggle.new_long_api_gm = openpilot_longitudinal and car_make == "gm" and self.params.get_bool("NewLongAPIGM") + toggle.new_long_api_hkg = openpilot_longitudinal and car_make == "hyundai" and self.params.get_bool("NewLongAPI") + + toggle.new_toyota_tune = openpilot_longitudinal and car_make == "toyota" and self.params.get_bool("NewToyotaTune") toggle.personalize_openpilot = self.params.get_bool("PersonalizeOpenpilot") - toggle.sound_pack = self.params.get("CustomSignals", encoding='utf-8') if toggle.personalize_openpilot else "stock" + toggle.color_scheme = self.params.get("CustomColors", encoding='utf-8') if toggle.personalize_openpilot else "stock" + toggle.distance_icons = self.params.get("CustomDistanceIcons", encoding='utf-8') if toggle.personalize_openpilot else "stock" + toggle.icon_pack = self.params.get("CustomIcons", encoding='utf-8') if toggle.personalize_openpilot else "stock" + toggle.signal_icons = self.params.get("CustomSignals", encoding='utf-8') if toggle.personalize_openpilot else "stock" + toggle.sound_pack = self.params.get("CustomSounds", encoding='utf-8') if toggle.personalize_openpilot else "stock" toggle.wheel_image = self.params.get("WheelIcon", encoding='utf-8') if toggle.personalize_openpilot else "stock" - quality_of_life_lateral = self.params.get_bool("QOLLateral") - toggle.pause_lateral_below_speed = self.params.get_int("PauseLateralSpeed") * speed_conversion if quality_of_life_lateral else 0 - - quality_of_life_longitudinal = self.params.get_bool("QOLLongitudinal") - toggle.custom_cruise_increase = self.params.get_int("CustomCruise") if quality_of_life_longitudinal and not pcm_cruise else 1 - toggle.custom_cruise_increase_long = self.params.get_int("CustomCruiseLong") if quality_of_life_longitudinal and not pcm_cruise else 5 - toggle.distance_icons = self.params.get("CustomDistanceIcons", encoding='utf-8') if quality_of_life_longitudinal and self.params.get_bool("OnroadDistanceButton") else "stock" - map_gears = quality_of_life_longitudinal and self.params.get_bool("MapGears") - toggle.map_acceleration = map_gears and self.params.get_bool("MapAcceleration") - toggle.map_deceleration = map_gears and self.params.get_bool("MapDeceleration") + toggle.quality_of_life_lateral = self.params.get_bool("QOLLateral") + toggle.pause_lateral_below_speed = self.params.get_int("PauseLateralSpeed") * speed_conversion if toggle.quality_of_life_lateral else 0 toggle.pause_lateral_below_signal = toggle.pause_lateral_below_speed != 0 and self.params.get_bool("PauseLateralOnSignal") - toggle.reverse_cruise_increase = quality_of_life_longitudinal and pcm_cruise and self.params.get_bool("ReverseCruise") + + toggle.quality_of_life_longitudinal = self.params.get_bool("QOLLongitudinal") + toggle.custom_cruise_increase = self.params.get_int("CustomCruise") if toggle.quality_of_life_longitudinal and not pcm_cruise else 1 + toggle.custom_cruise_increase_long = self.params.get_int("CustomCruiseLong") if toggle.quality_of_life_longitudinal and not pcm_cruise else 5 + toggle.force_standstill = toggle.quality_of_life_longitudinal and self.params.get_bool("ForceStandstill") + toggle.force_stops = toggle.quality_of_life_longitudinal and self.params.get_bool("ForceStops") + toggle.map_gears = toggle.quality_of_life_longitudinal and self.params.get_bool("MapGears") + toggle.map_acceleration = toggle.map_gears and self.params.get_bool("MapAcceleration") + toggle.map_deceleration = toggle.map_gears and self.params.get_bool("MapDeceleration") + toggle.reverse_cruise_increase = toggle.quality_of_life_longitudinal and pcm_cruise and self.params.get_bool("ReverseCruise") + toggle.set_speed_offset = self.params.get_int("SetSpeedOffset") * (1 if toggle.is_metric else CV.MPH_TO_KPH) if toggle.quality_of_life_longitudinal and not pcm_cruise else 0 + + toggle.quality_of_life_visuals = self.params.get_bool("QOLVisuals") + toggle.camera_view = self.params.get_int("CameraView") if toggle.quality_of_life_visuals else 0 + toggle.driver_camera_in_reverse = toggle.quality_of_life_visuals and self.params.get_bool("DriverCamera") + toggle.onroad_distance_button = toggle.quality_of_life_visuals and self.params.get_bool("OnroadDistanceButton") + toggle.standby_mode = toggle.quality_of_life_visuals and self.params.get_bool("StandbyMode") + toggle.stopped_timer = toggle.quality_of_life_visuals and self.params.get_bool("StoppedTimer") toggle.random_events = self.params.get_bool("RandomEvents") - toggle.sng_hack = toggle.openpilot_longitudinal and car_make == "toyota" and self.params.get_bool("SNGHack") + toggle.screen_management = self.params.get_bool("ScreenManagement") + toggle.screen_brightness = self.params.get_int("ScreenBrightness") if toggle.screen_management else 101 + toggle.screen_brightness_onroad = self.params.get_int("ScreenBrightnessOnroad") if toggle.screen_management else 101 + toggle.screen_recorder = toggle.screen_management and self.params.get_bool("ScreenRecorder") + toggle.screen_timeout = self.params.get_int("ScreenTimeout") if toggle.screen_management else 30 + toggle.screen_timeout_onroad = self.params.get_int("ScreenTimeoutOnroad") if toggle.screen_management else 10 - toggle.speed_limit_controller = toggle.openpilot_longitudinal and self.params.get_bool("SpeedLimitController") + toggle.sng_hack = openpilot_longitudinal and car_make == "toyota" and self.params.get_bool("SNGHack") + + toggle.speed_limit_controller = openpilot_longitudinal and self.params.get_bool("SpeedLimitController") toggle.force_mph_dashboard = toggle.speed_limit_controller and self.params.get_bool("ForceMPHDashboard") toggle.map_speed_lookahead_higher = self.params.get_int("SLCLookaheadHigher") if toggle.speed_limit_controller else 0 toggle.map_speed_lookahead_lower = self.params.get_int("SLCLookaheadLower") if toggle.speed_limit_controller else 0 - toggle.offset1 = self.params.get_int("Offset1") * speed_conversion if toggle.speed_limit_controller else 0 - toggle.offset2 = self.params.get_int("Offset2") * speed_conversion if toggle.speed_limit_controller else 0 - toggle.offset3 = self.params.get_int("Offset3") * speed_conversion if toggle.speed_limit_controller else 0 - toggle.offset4 = self.params.get_int("Offset4") * speed_conversion if toggle.speed_limit_controller else 0 toggle.set_speed_limit = toggle.speed_limit_controller and self.params.get_bool("SetSpeedLimit") - toggle.speed_limit_alert = toggle.speed_limit_controller and self.params.get_bool("SpeedLimitChangedAlert") - toggle.speed_limit_confirmation_higher = toggle.speed_limit_controller and self.params.get_bool("SLCConfirmationHigher") - toggle.speed_limit_confirmation_lower = toggle.speed_limit_controller and self.params.get_bool("SLCConfirmationLower") - speed_limit_controller_override = self.params.get_int("SLCOverride") if toggle.speed_limit_controller else 0 - toggle.speed_limit_controller_override_manual = speed_limit_controller_override == 1 - toggle.speed_limit_controller_override_set_speed = speed_limit_controller_override == 2 - toggle.use_set_speed = toggle.speed_limit_controller and self.params.get_int("SLCFallback") == 0 - toggle.slc_fallback_experimental = toggle.speed_limit_controller and self.params.get_int("SLCFallback") == 1 - toggle.slc_fallback_previous = toggle.speed_limit_controller and self.params.get_int("SLCFallback") == 2 + slc_fallback_method = self.params.get_int("SLCFallback") if toggle.speed_limit_controller else 0 + toggle.slc_fallback_experimental_mode = toggle.speed_limit_controller and slc_fallback_method == 1 + toggle.slc_fallback_previous_speed_limit = toggle.speed_limit_controller and slc_fallback_method == 2 + toggle.slc_fallback_set_speed = toggle.speed_limit_controller and slc_fallback_method == 0 + toggle.speed_limit_confirmation = toggle.speed_limit_controller and self.params.get_bool("SLCConfirmation") + toggle.speed_limit_confirmation_higher = toggle.speed_limit_confirmation and self.params.get_bool("SLCConfirmationHigher") + toggle.speed_limit_confirmation_lower = toggle.speed_limit_confirmation and self.params.get_bool("SLCConfirmationLower") + toggle.speed_limit_controller_override = self.params.get_int("SLCOverride") if toggle.speed_limit_controller else 0 + toggle.speed_limit_controller_override_manual = toggle.speed_limit_controller_override == 1 + toggle.speed_limit_controller_override_set_speed = toggle.speed_limit_controller_override == 2 + toggle.speed_limit_offset1 = self.params.get_int("Offset1") * speed_conversion if toggle.speed_limit_controller else 0 + toggle.speed_limit_offset2 = self.params.get_int("Offset2") * speed_conversion if toggle.speed_limit_controller else 0 + toggle.speed_limit_offset3 = self.params.get_int("Offset3") * speed_conversion if toggle.speed_limit_controller else 0 + toggle.speed_limit_offset4 = self.params.get_int("Offset4") * speed_conversion if toggle.speed_limit_controller else 0 toggle.speed_limit_priority1 = self.params.get("SLCPriority1", encoding='utf-8') if toggle.speed_limit_controller else None toggle.speed_limit_priority2 = self.params.get("SLCPriority2", encoding='utf-8') if toggle.speed_limit_controller else None toggle.speed_limit_priority3 = self.params.get("SLCPriority3", encoding='utf-8') if toggle.speed_limit_controller else None toggle.speed_limit_priority_highest = toggle.speed_limit_priority1 == "Highest" toggle.speed_limit_priority_lowest = toggle.speed_limit_priority1 == "Lowest" - toyota_doors = car_make == "toyota" and self.params.get_bool("ToyotaDoors") - toggle.lock_doors = toyota_doors and self.params.get_bool("LockDoors") - toggle.unlock_doors = toyota_doors and self.params.get_bool("UnlockDoors") + toggle.startup_alert_top = self.params.get("StartupMessageTop", encoding='utf-8') or "" + toggle.startup_alert_bottom = self.params.get("StartupMessageBottom", encoding='utf-8') or "" -FrogPilotVariables = FrogPilotVariables() + toggle.tethering_config = self.params.get_int("TetheringEnabled") + + toggle.toyota_doors = car_make == "toyota" and self.params.get_bool("ToyotaDoors") + toggle.lock_doors = toggle.toyota_doors and self.params.get_bool("LockDoors") + toggle.unlock_doors = toggle.toyota_doors and self.params.get_bool("UnlockDoors") + + toggle.volt_sng = car_model == "CHEVROLET_VOLT" and self.params.get_bool("VoltSNG") + + customization_level = self.params.get_int("CustomizationLevel") if self.params.get_bool("CustomizationLevelConfirmed") else 2 + + if customization_level == 0: + toggle.advanced_custom_onroad_ui = self.default_frogpilot_toggles.AdvancedCustomUI + toggle.hide_lead_marker = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideLeadMarker + toggle.hide_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideSpeed + toggle.hide_map_icon = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideMapIcon + toggle.hide_max_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideMaxSpeed + toggle.hide_alerts = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideAlerts + toggle.use_wheel_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.WheelSpeed + + toggle.advanced_lateral_tuning = self.default_frogpilot_toggles.AdvancedLateralTune + toggle.use_custom_steer_friction = False + toggle.use_custom_kp = False + toggle.use_custom_lat_accel_factor = False + toggle.use_custom_steer_ratio = False + toggle.force_auto_tune = toggle.advanced_lateral_tuning and not has_auto_tune and not is_pid_car and self.default_frogpilot_toggles.ForceAutoTune + toggle.force_auto_tune_off = toggle.advanced_lateral_tuning and has_auto_tune and not is_pid_car and self.default_frogpilot_toggles.ForceAutoTuneOff + + toggle.alert_volume_control = self.default_frogpilot_toggles.AlertVolumeControl + toggle.disengage_volume = self.default_frogpilot_toggles.DisengageVolume if toggle.alert_volume_control else 101 + toggle.engage_volume = self.default_frogpilot_toggles.EngageVolume if toggle.alert_volume_control else 101 + toggle.prompt_volume = self.default_frogpilot_toggles.PromptVolume if toggle.alert_volume_control else 101 + toggle.promptDistracted_volume = self.default_frogpilot_toggles.PromptDistractedVolume if toggle.alert_volume_control else 101 + toggle.refuse_volume = self.default_frogpilot_toggles.RefuseVolume if toggle.alert_volume_control else 101 + toggle.warningSoft_volume = self.default_frogpilot_toggles.WarningSoftVolume if toggle.alert_volume_control else 101 + toggle.warningImmediate_volume = self.default_frogpilot_toggles.WarningImmediateVolume if toggle.alert_volume_control else 101 + + toggle.always_on_lateral = always_on_lateral_set and self.default_frogpilot_toggles.AlwaysOnLateral + toggle.always_on_lateral_lkas = toggle.always_on_lateral and car_make != "subaru" and self.default_frogpilot_toggles.AlwaysOnLateralLKAS + toggle.always_on_lateral_main = toggle.always_on_lateral and self.default_frogpilot_toggles.AlwaysOnLateralMain + toggle.always_on_lateral_pause_speed = self.default_frogpilot_toggles.PauseAOLOnBrake if toggle.always_on_lateral else 0 + toggle.always_on_lateral_status_bar = toggle.always_on_lateral and not self.default_frogpilot_toggles.HideAOLStatusBar + + toggle.cluster_offset = self.default_frogpilot_toggles.ClusterOffset if car_make == "toyota" else 1 + + toggle.conditional_experimental_mode = openpilot_longitudinal and self.default_frogpilot_toggles.ConditionalExperimental + toggle.conditional_curves = toggle.conditional_experimental_mode and self.default_frogpilot_toggles.CECurves + toggle.conditional_curves_lead = toggle.conditional_curves and self.default_frogpilot_toggles.CECurvesLead + toggle.conditional_lead = toggle.conditional_experimental_mode and self.default_frogpilot_toggles.CELead + toggle.conditional_slower_lead = toggle.conditional_lead and self.default_frogpilot_toggles.CESlowerLead + toggle.conditional_stopped_lead = toggle.conditional_lead and self.default_frogpilot_toggles.CEStoppedLead + toggle.conditional_limit = self.default_frogpilot_toggles.CESpeed * speed_conversion if toggle.conditional_experimental_mode else 0 + toggle.conditional_limit_lead = self.default_frogpilot_toggles.CESpeedLead * speed_conversion if toggle.conditional_experimental_mode else 0 + toggle.conditional_navigation = toggle.conditional_experimental_mode and self.default_frogpilot_toggles.CENavigation + toggle.conditional_navigation_intersections = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationIntersections + toggle.conditional_navigation_lead = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationLead + toggle.conditional_navigation_turns = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationTurns + toggle.conditional_model_stop_time = self.default_frogpilot_toggles.CEModelStopTime if toggle.conditional_experimental_mode else 0 + toggle.conditional_signal = self.default_frogpilot_toggles.CESignalSpeed if toggle.conditional_experimental_mode else 0 + toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and self.default_frogpilot_toggles.CESignalLaneDetection + toggle.conditional_status_bar = toggle.conditional_experimental_mode and not self.default_frogpilot_toggles.HideCEMStatusBar + if toggle.conditional_experimental_mode: + self.params.put_bool("ExperimentalMode", True) + + toggle.crosstrek_torque = car_model == "SUBARU_IMPREZA" and self.default_frogpilot_toggles.CrosstrekTorque + + toggle.curve_speed_controller = openpilot_longitudinal and self.default_frogpilot_toggles.CurveSpeedControl + toggle.curve_sensitivity = self.default_frogpilot_toggles.CurveSensitivity / 100 if toggle.curve_speed_controller else 1 + toggle.turn_aggressiveness = self.default_frogpilot_toggles.TurnAggressiveness / 100 if toggle.curve_speed_controller else 1 + toggle.disable_curve_speed_smoothing = toggle.curve_speed_controller and self.default_frogpilot_toggles.DisableCurveSpeedSmoothing + toggle.map_turn_speed_controller = toggle.curve_speed_controller and self.default_frogpilot_toggles.MTSCEnabled + toggle.mtsc_curvature_check = toggle.map_turn_speed_controller and self.default_frogpilot_toggles.MTSCCurvatureCheck + toggle.vision_turn_controller = toggle.curve_speed_controller and self.default_frogpilot_toggles.VisionTurnControl + + toggle.custom_personalities = openpilot_longitudinal and self.default_frogpilot_toggles.CustomPersonalities + toggle.aggressive_profile = toggle.custom_personalities and self.default_frogpilot_toggles.AggressivePersonalityProfile + toggle.aggressive_jerk_deceleration = self.default_frogpilot_toggles.AggressiveJerkDeceleration / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_danger = self.default_frogpilot_toggles.AggressiveJerkDanger / 100 if toggle.aggressive_profile else 1.0 + toggle.aggressive_jerk_speed = self.default_frogpilot_toggles.AggressiveJerkSpeed / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_speed_decrease = self.default_frogpilot_toggles.AggressiveJerkSpeedDecrease / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_follow = self.default_frogpilot_toggles.AggressiveFollow if toggle.aggressive_profile else 1.25 + toggle.standard_profile = toggle.custom_personalities and self.default_frogpilot_toggles.StandardPersonalityProfile + toggle.standard_jerk_acceleration = self.default_frogpilot_toggles.StandardJerkAcceleration / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_deceleration = self.default_frogpilot_toggles.StandardJerkDeceleration / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_danger = self.default_frogpilot_toggles.StandardJerkDanger / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_speed = self.default_frogpilot_toggles.StandardJerkSpeed / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_speed_decrease = self.default_frogpilot_toggles.StandardJerkSpeedDecrease / 100 if toggle.standard_profile else 1.0 + toggle.standard_follow = self.default_frogpilot_toggles.StandardFollow if toggle.standard_profile else 1.45 + toggle.relaxed_profile = toggle.custom_personalities and self.default_frogpilot_toggles.RelaxedPersonalityProfile + toggle.relaxed_jerk_acceleration = self.default_frogpilot_toggles.RelaxedJerkAcceleration / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_deceleration = self.default_frogpilot_toggles.RelaxedJerkDeceleration / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_danger = self.default_frogpilot_toggles.RelaxedJerkDanger / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_speed = self.default_frogpilot_toggles.RelaxedJerkSpeed / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_speed_decrease = self.default_frogpilot_toggles.RelaxedJerkSpeedDecrease / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_follow = self.default_frogpilot_toggles.RelaxedFollow if toggle.relaxed_profile else 1.75 + toggle.traffic_profile = toggle.custom_personalities and self.default_frogpilot_toggles.TrafficPersonalityProfile + toggle.traffic_mode_jerk_acceleration = [self.default_frogpilot_toggles.TrafficJerkAcceleration / 100, toggle.aggressive_jerk_acceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_deceleration = [self.default_frogpilot_toggles.TrafficJerkDeceleration / 100, toggle.aggressive_jerk_deceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_danger = [self.default_frogpilot_toggles.TrafficJerkDanger / 100, toggle.aggressive_jerk_danger] if toggle.traffic_profile else [1.0, 1.0] + toggle.traffic_mode_jerk_speed = [self.default_frogpilot_toggles.TrafficJerkSpeed / 100, toggle.aggressive_jerk_speed] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_speed_decrease = [self.default_frogpilot_toggles.TrafficJerkSpeedDecrease / 100, toggle.aggressive_jerk_speed_decrease] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_t_follow = [self.default_frogpilot_toggles.TrafficFollow, toggle.aggressive_follow] if toggle.traffic_profile else [0.5, 1.0] + + toggle.custom_ui = self.default_frogpilot_toggles.CustomUI + toggle.acceleration_path = toggle.custom_ui and self.default_frogpilot_toggles.AccelerationPath + toggle.adjacent_paths = toggle.custom_ui and self.default_frogpilot_toggles.AdjacentPath + toggle.blind_spot_path = has_bsm and toggle.custom_ui and self.default_frogpilot_toggles.BlindSpotPath + toggle.compass = toggle.custom_ui and self.default_frogpilot_toggles.Compass + toggle.pedals_on_ui = toggle.custom_ui and self.default_frogpilot_toggles.PedalsOnUI + toggle.dynamic_pedals_on_ui = toggle.pedals_on_ui and self.default_frogpilot_toggles.DynamicPedalsOnUI + toggle.static_pedals_on_ui = toggle.pedals_on_ui and self.default_frogpilot_toggles.StaticPedalsOnUI + toggle.rotating_wheel = toggle.custom_ui and self.default_frogpilot_toggles.RotatingWheel + + toggle.developer_ui = self.default_frogpilot_toggles.DeveloperUI + toggle.border_metrics = toggle.developer_ui and self.default_frogpilot_toggles.BorderMetrics + toggle.blind_spot_metrics = has_bsm and toggle.border_metrics and self.default_frogpilot_toggles.BlindSpotMetrics + toggle.signal_metrics = toggle.border_metrics and self.default_frogpilot_toggles.SignalMetrics + toggle.steering_metrics = toggle.border_metrics and self.default_frogpilot_toggles.ShowSteering + toggle.show_fps = toggle.developer_ui and self.default_frogpilot_toggles.FPSCounter + toggle.lateral_metrics = toggle.developer_ui and self.default_frogpilot_toggles.LateralMetrics + toggle.adjacent_path_metrics = toggle.lateral_metrics and self.default_frogpilot_toggles.AdjacentPathMetrics + toggle.lateral_tuning_metrics = toggle.lateral_metrics and self.default_frogpilot_toggles.TuningInfo + toggle.longitudinal_metrics = toggle.developer_ui and self.default_frogpilot_toggles.LongitudinalMetrics + toggle.adjacent_lead_tracking = has_radar and toggle.longitudinal_metrics and self.default_frogpilot_toggles.AdjacentLeadsUI + toggle.lead_metrics = toggle.longitudinal_metrics and self.default_frogpilot_toggles.LeadInfo + toggle.jerk_metrics = toggle.longitudinal_metrics and self.default_frogpilot_toggles.JerkInfo + toggle.numerical_temp = toggle.developer_ui and self.default_frogpilot_toggles.NumericalTemp + toggle.fahrenheit = toggle.numerical_temp and self.default_frogpilot_toggles.Fahrenheit + toggle.sidebar_metrics = toggle.developer_ui and self.default_frogpilot_toggles.SidebarMetrics + toggle.cpu_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowCPU + toggle.gpu_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowGPU + toggle.ip_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowIP + toggle.memory_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowMemoryUsage + toggle.storage_left_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowStorageLeft + toggle.storage_used_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowStorageUsed + toggle.use_si_metrics = toggle.developer_ui and self.default_frogpilot_toggles.UseSI + + toggle.device_management = self.default_frogpilot_toggles.DeviceManagement + device_shutdown_setting = self.default_frogpilot_toggles.DeviceShutdown if toggle.device_management else 33 + toggle.device_shutdown_time = (device_shutdown_setting - 3) * 3600 if device_shutdown_setting >= 4 else device_shutdown_setting * (60 * 15) + toggle.increase_thermal_limits = toggle.device_management and self.default_frogpilot_toggles.IncreaseThermalLimits + toggle.low_voltage_shutdown = clip(self.default_frogpilot_toggles.LowVoltageShutdown, VBATT_PAUSE_CHARGING, 12.5) if toggle.device_management else VBATT_PAUSE_CHARGING + toggle.no_logging = toggle.device_management and self.default_frogpilot_toggles.NoLogging + toggle.no_uploads = toggle.device_management and self.default_frogpilot_toggles.NoUploads + toggle.offline_mode = toggle.device_management and self.default_frogpilot_toggles.OfflineMode + + toggle.experimental_gm_tune = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.ExperimentalGMTune + + toggle.experimental_mode_via_press = openpilot_longitudinal and self.default_frogpilot_toggles.ExperimentalModeActivation + toggle.experimental_mode_via_distance = toggle.experimental_mode_via_press and self.default_frogpilot_toggles.ExperimentalModeViaDistance + toggle.experimental_mode_via_lkas = not toggle.always_on_lateral_lkas and toggle.experimental_mode_via_press and car_make != "subaru" and self.default_frogpilot_toggles.ExperimentalModeViaLKAS + toggle.experimental_mode_via_tap = toggle.experimental_mode_via_press and self.default_frogpilot_toggles.ExperimentalModeViaTap + + toggle.frogsgomoo_tweak = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.FrogsGoMoosTweak + + toggle.lane_change_customizations = self.default_frogpilot_toggles.LaneChangeCustomizations + toggle.lane_change_delay = self.default_frogpilot_toggles.LaneChangeTime if toggle.lane_change_customizations else 0 + toggle.lane_detection_width = self.default_frogpilot_toggles.LaneDetectionWidth * distance_conversion if toggle.lane_change_customizations else 0 + toggle.lane_detection = toggle.lane_detection_width != 0 + toggle.minimum_lane_change_speed = self.default_frogpilot_toggles.MinimumLaneChangeSpeed * speed_conversion if toggle.lane_change_customizations else LANE_CHANGE_SPEED_MIN + toggle.nudgeless = toggle.lane_change_customizations and self.default_frogpilot_toggles.NudgelessLaneChange + toggle.one_lane_change = toggle.lane_change_customizations and self.default_frogpilot_toggles.OneLaneChange + + toggle.lateral_tuning = self.default_frogpilot_toggles.LateralTune + toggle.nnff = toggle.lateral_tuning and self.default_frogpilot_toggles.NNFF + toggle.smooth_curve_handling = toggle.lateral_tuning and self.default_frogpilot_toggles.NNFFLite + toggle.taco_tune = toggle.lateral_tuning and self.default_frogpilot_toggles.TacoTune + toggle.use_turn_desires = toggle.lateral_tuning and self.default_frogpilot_toggles.TurnDesires + + toggle.long_pitch = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.LongPitch + + toggle.human_acceleration = toggle.longitudinal_tuning and self.default_frogpilot_toggles.HumanAcceleration + toggle.human_following = toggle.longitudinal_tuning and self.default_frogpilot_toggles.HumanFollowing + toggle.increased_stopped_distance = self.default_frogpilot_toggles.IncreasedStoppedDistance * distance_conversion if toggle.longitudinal_tuning else 0 + toggle.lead_detection_probability = clip(self.default_frogpilot_toggles.LeadDetectionThreshold / 100, 0.01, 0.99) if toggle.longitudinal_tuning else 0.5 + toggle.max_desired_acceleration = clip(self.default_frogpilot_toggles.MaxDesiredAcceleration, 0.1, 4.0) if toggle.longitudinal_tuning else 4.0 + + toggle.model = DEFAULT_MODEL + toggle.part_model_param = "" + toggle.classic_model = classic_models and toggle.model in classic_models.split(',') + toggle.navigationless_model = navigation_models and toggle.model not in navigation_models.split(',') + toggle.radarless_model = radarless_models and toggle.model in radarless_models.split(',') + + toggle.model_ui = self.default_frogpilot_toggles.ModelUI + toggle.dynamic_path_width = toggle.model_ui and self.default_frogpilot_toggles.DynamicPathWidth + toggle.lane_line_width = self.default_frogpilot_toggles.LaneLinesWidth * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.path_edge_width = self.default_frogpilot_toggles.PathEdgeWidth if toggle.model_ui else 20 + toggle.path_width = self.default_frogpilot_toggles.PathWidth * distance_conversion / 2 if toggle.model_ui else 0.9 + toggle.road_edge_width = self.default_frogpilot_toggles.RoadEdgesWidth * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.show_stopping_point = toggle.model_ui and self.default_frogpilot_toggles.ShowStoppingPoint + toggle.show_stopping_point_metrics = toggle.show_stopping_point and self.default_frogpilot_toggles.ShowStoppingPointMetrics + toggle.unlimited_road_ui_length = toggle.model_ui and self.default_frogpilot_toggles.UnlimitedLength + + toggle.navigation_ui = self.default_frogpilot_toggles.NavigationUI + toggle.big_map = toggle.navigation_ui and self.params.get_bool("BigMap") + toggle.full_map = toggle.big_map and self.default_frogpilot_toggles.FullMap + toggle.map_style = self.default_frogpilot_toggles.MapStyle if toggle.navigation_ui else 0 + toggle.road_name_ui = toggle.navigation_ui and self.default_frogpilot_toggles.RoadNameUI + toggle.show_speed_limit_offset = toggle.navigation_ui and self.default_frogpilot_toggles.ShowSLCOffset + toggle.speed_limit_vienna = toggle.navigation_ui and self.default_frogpilot_toggles.UseVienna + + toggle.new_long_api_gm = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.NewLongAPIGM + toggle.new_long_api_hkg = openpilot_longitudinal and car_make == "hyundai" and self.default_frogpilot_toggles.NewLongAPI + + toggle.new_toyota_tune = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.NewToyotaTune + + toggle.quality_of_life_lateral = self.default_frogpilot_toggles.QOLLateral + toggle.pause_lateral_below_speed = self.default_frogpilot_toggles.PauseLateralSpeed * speed_conversion if toggle.quality_of_life_lateral else 0 + + toggle.quality_of_life_longitudinal = self.default_frogpilot_toggles.QOLLongitudinal + toggle.custom_cruise_increase = self.default_frogpilot_toggles.CustomCruise if toggle.quality_of_life_longitudinal and not pcm_cruise else 1 + toggle.custom_cruise_increase_long = self.default_frogpilot_toggles.CustomCruiseLong if toggle.quality_of_life_longitudinal and not pcm_cruise else 5 + toggle.force_standstill = toggle.quality_of_life_longitudinal and self.default_frogpilot_toggles.ForceStandstill + toggle.force_stops = toggle.quality_of_life_longitudinal and self.default_frogpilot_toggles.ForceStops + toggle.map_gears = toggle.quality_of_life_longitudinal and self.default_frogpilot_toggles.MapGears + toggle.map_acceleration = toggle.map_gears and self.default_frogpilot_toggles.MapAcceleration + toggle.map_deceleration = toggle.map_gears and self.default_frogpilot_toggles.MapDeceleration + toggle.pause_lateral_below_signal = toggle.pause_lateral_below_speed != 0 and self.default_frogpilot_toggles.PauseLateralOnSignal + toggle.reverse_cruise_increase = toggle.quality_of_life_longitudinal and pcm_cruise and self.default_frogpilot_toggles.ReverseCruise + toggle.set_speed_offset = self.default_frogpilot_toggles.SetSpeedOffset * (1 if toggle.is_metric else CV.MPH_TO_KPH) if toggle.quality_of_life_longitudinal and not pcm_cruise else 0 + + toggle.camera_view = self.default_frogpilot_toggles.CameraView if toggle.quality_of_life_visuals else 0 + toggle.driver_camera_in_reverse = toggle.quality_of_life_visuals and self.default_frogpilot_toggles.DriverCamera + toggle.standby_mode = toggle.quality_of_life_visuals and self.default_frogpilot_toggles.StandbyMode + toggle.stopped_timer = toggle.quality_of_life_visuals and self.default_frogpilot_toggles.StoppedTimer + + toggle.random_events = self.default_frogpilot_toggles.RandomEvents + + toggle.screen_management = self.default_frogpilot_toggles.ScreenManagement + toggle.screen_brightness = self.default_frogpilot_toggles.ScreenBrightness if toggle.screen_management else 101 + toggle.screen_brightness_onroad = self.default_frogpilot_toggles.ScreenBrightnessOnroad if toggle.screen_management else 101 + toggle.screen_recorder = toggle.screen_management and self.default_frogpilot_toggles.ScreenRecorder + toggle.screen_timeout = self.default_frogpilot_toggles.ScreenTimeout if toggle.screen_management else 30 + toggle.screen_timeout_onroad = self.default_frogpilot_toggles.ScreenTimeoutOnroad if toggle.screen_management else 10 + + toggle.sng_hack = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.SNGHack + + toggle.force_mph_dashboard = toggle.speed_limit_controller and self.default_frogpilot_toggles.ForceMPHDashboard + toggle.map_speed_lookahead_higher = self.default_frogpilot_toggles.SLCLookaheadHigher if toggle.speed_limit_controller else 0 + toggle.map_speed_lookahead_lower = self.default_frogpilot_toggles.SLCLookaheadLower if toggle.speed_limit_controller else 0 + toggle.set_speed_limit = toggle.speed_limit_controller and self.default_frogpilot_toggles.SetSpeedLimit + slc_fallback_method = self.default_frogpilot_toggles.SLCFallback if toggle.speed_limit_controller else 0 + toggle.slc_fallback_experimental_mode = toggle.speed_limit_controller and slc_fallback_method == 1 + toggle.slc_fallback_previous_speed_limit = toggle.speed_limit_controller and slc_fallback_method == 2 + toggle.slc_fallback_set_speed = toggle.speed_limit_controller and slc_fallback_method == 0 + toggle.speed_limit_controller_override = self.default_frogpilot_toggles.SLCOverride if toggle.speed_limit_controller else 0 + toggle.speed_limit_controller_override_manual = toggle.speed_limit_controller_override == 1 + toggle.speed_limit_controller_override_set_speed = toggle.speed_limit_controller_override == 2 + toggle.speed_limit_priority1 = self.default_frogpilot_toggles.SLCPriority1 if toggle.speed_limit_controller else None + toggle.speed_limit_priority2 = self.default_frogpilot_toggles.SLCPriority2 if toggle.speed_limit_controller else None + toggle.speed_limit_priority3 = self.default_frogpilot_toggles.SLCPriority3 if toggle.speed_limit_controller else None + toggle.speed_limit_priority_highest = toggle.speed_limit_priority1 == "Highest" + toggle.speed_limit_priority_lowest = toggle.speed_limit_priority1 == "Lowest" + toggle.speed_limit_vienna = toggle.speed_limit_controller and self.default_frogpilot_toggles.UseVienna + + toggle.startup_alert_top = self.default_frogpilot_toggles.StartupMessageTop + toggle.startup_alert_bottom = self.default_frogpilot_toggles.StartupMessageBottom + + toggle.volt_sng = car_model == "CHEVROLET_VOLT" and self.default_frogpilot_toggles.VoltSNG + + elif customization_level != 2: + toggle.advanced_custom_onroad_ui = self.default_frogpilot_toggles.AdvancedCustomUI + toggle.hide_lead_marker = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideLeadMarker + toggle.hide_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideSpeed + toggle.hide_map_icon = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideMapIcon + toggle.hide_max_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideMaxSpeed + toggle.hide_alerts = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.HideAlerts + toggle.use_wheel_speed = toggle.advanced_custom_onroad_ui and self.default_frogpilot_toggles.WheelSpeed + + toggle.advanced_lateral_tuning = self.default_frogpilot_toggles.AdvancedLateralTune + toggle.use_custom_steer_friction = False + toggle.use_custom_kp = False + toggle.use_custom_lat_accel_factor = False + toggle.use_custom_steer_ratio = False + toggle.force_auto_tune = toggle.advanced_lateral_tuning and not has_auto_tune and not is_pid_car and self.default_frogpilot_toggles.ForceAutoTune + toggle.force_auto_tune_off = toggle.advanced_lateral_tuning and has_auto_tune and not is_pid_car and self.default_frogpilot_toggles.ForceAutoTuneOff + + toggle.alert_volume_control = self.default_frogpilot_toggles.AlertVolumeControl + toggle.disengage_volume = self.default_frogpilot_toggles.DisengageVolume if toggle.alert_volume_control else 101 + toggle.engage_volume = self.default_frogpilot_toggles.EngageVolume if toggle.alert_volume_control else 101 + toggle.prompt_volume = self.default_frogpilot_toggles.PromptVolume if toggle.alert_volume_control else 101 + toggle.promptDistracted_volume = self.default_frogpilot_toggles.PromptDistractedVolume if toggle.alert_volume_control else 101 + toggle.refuse_volume = self.default_frogpilot_toggles.RefuseVolume if toggle.alert_volume_control else 101 + toggle.warningSoft_volume = self.default_frogpilot_toggles.WarningSoftVolume if toggle.alert_volume_control else 101 + toggle.warningImmediate_volume = self.default_frogpilot_toggles.WarningImmediateVolume if toggle.alert_volume_control else 101 + + toggle.always_on_lateral_status_bar = toggle.always_on_lateral and not self.default_frogpilot_toggles.HideAOLStatusBar + + toggle.cluster_offset = self.default_frogpilot_toggles.ClusterOffset if car_make == "toyota" else 1 + + toggle.conditional_navigation = toggle.conditional_experimental_mode and self.default_frogpilot_toggles.CENavigation + toggle.conditional_navigation_intersections = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationIntersections + toggle.conditional_navigation_lead = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationLead + toggle.conditional_navigation_turns = toggle.conditional_navigation and self.default_frogpilot_toggles.CENavigationTurns + toggle.conditional_signal = self.default_frogpilot_toggles.CESignalSpeed if toggle.conditional_experimental_mode else 0 + toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and self.default_frogpilot_toggles.CESignalLaneDetection + toggle.conditional_status_bar = toggle.conditional_experimental_mode and not self.default_frogpilot_toggles.HideCEMStatusBar + if toggle.conditional_experimental_mode: + self.params.put_bool("ExperimentalMode", True) + + toggle.crosstrek_torque = car_model == "SUBARU_IMPREZA" and self.default_frogpilot_toggles.CrosstrekTorque + + toggle.curve_sensitivity = self.default_frogpilot_toggles.CurveSensitivity / 100 if toggle.curve_speed_controller else 1 + toggle.turn_aggressiveness = self.default_frogpilot_toggles.TurnAggressiveness / 100 if toggle.curve_speed_controller else 1 + toggle.mtsc_curvature_check = toggle.map_turn_speed_controller and self.default_frogpilot_toggles.MTSCCurvatureCheck + + toggle.custom_personalities = openpilot_longitudinal and self.default_frogpilot_toggles.CustomPersonalities + toggle.aggressive_profile = toggle.custom_personalities and self.default_frogpilot_toggles.AggressivePersonalityProfile + toggle.aggressive_jerk_deceleration = self.default_frogpilot_toggles.AggressiveJerkDeceleration / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_danger = self.default_frogpilot_toggles.AggressiveJerkDanger / 100 if toggle.aggressive_profile else 1.0 + toggle.aggressive_jerk_speed = self.default_frogpilot_toggles.AggressiveJerkSpeed / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_jerk_speed_decrease = self.default_frogpilot_toggles.AggressiveJerkSpeedDecrease / 100 if toggle.aggressive_profile else 0.5 + toggle.aggressive_follow = self.default_frogpilot_toggles.AggressiveFollow if toggle.aggressive_profile else 1.25 + toggle.standard_profile = toggle.custom_personalities and self.default_frogpilot_toggles.StandardPersonalityProfile + toggle.standard_jerk_acceleration = self.default_frogpilot_toggles.StandardJerkAcceleration / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_deceleration = self.default_frogpilot_toggles.StandardJerkDeceleration / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_danger = self.default_frogpilot_toggles.StandardJerkDanger / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_speed = self.default_frogpilot_toggles.StandardJerkSpeed / 100 if toggle.standard_profile else 1.0 + toggle.standard_jerk_speed_decrease = self.default_frogpilot_toggles.StandardJerkSpeedDecrease / 100 if toggle.standard_profile else 1.0 + toggle.standard_follow = self.default_frogpilot_toggles.StandardFollow if toggle.standard_profile else 1.45 + toggle.relaxed_profile = toggle.custom_personalities and self.default_frogpilot_toggles.RelaxedPersonalityProfile + toggle.relaxed_jerk_acceleration = self.default_frogpilot_toggles.RelaxedJerkAcceleration / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_deceleration = self.default_frogpilot_toggles.RelaxedJerkDeceleration / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_danger = self.default_frogpilot_toggles.RelaxedJerkDanger / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_speed = self.default_frogpilot_toggles.RelaxedJerkSpeed / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_jerk_speed_decrease = self.default_frogpilot_toggles.RelaxedJerkSpeedDecrease / 100 if toggle.relaxed_profile else 1.0 + toggle.relaxed_follow = self.default_frogpilot_toggles.RelaxedFollow if toggle.relaxed_profile else 1.75 + toggle.traffic_profile = toggle.custom_personalities and self.default_frogpilot_toggles.TrafficPersonalityProfile + toggle.traffic_mode_jerk_acceleration = [self.default_frogpilot_toggles.TrafficJerkAcceleration / 100, toggle.aggressive_jerk_acceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_deceleration = [self.default_frogpilot_toggles.TrafficJerkDeceleration / 100, toggle.aggressive_jerk_deceleration] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_danger = [self.default_frogpilot_toggles.TrafficJerkDanger / 100, toggle.aggressive_jerk_danger] if toggle.traffic_profile else [1.0, 1.0] + toggle.traffic_mode_jerk_speed = [self.default_frogpilot_toggles.TrafficJerkSpeed / 100, toggle.aggressive_jerk_speed] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_jerk_speed_decrease = [self.default_frogpilot_toggles.TrafficJerkSpeedDecrease / 100, toggle.aggressive_jerk_speed_decrease] if toggle.traffic_profile else [0.5, 0.5] + toggle.traffic_mode_t_follow = [self.default_frogpilot_toggles.TrafficFollow, toggle.aggressive_follow] if toggle.traffic_profile else [0.5, 1.0] + + toggle.adjacent_paths = toggle.custom_ui and self.default_frogpilot_toggles.AdjacentPath + + toggle.developer_ui = self.default_frogpilot_toggles.DeveloperUI + toggle.border_metrics = toggle.developer_ui and self.default_frogpilot_toggles.BorderMetrics + toggle.blind_spot_metrics = has_bsm and toggle.border_metrics and self.default_frogpilot_toggles.BlindSpotMetrics + toggle.signal_metrics = toggle.border_metrics and self.default_frogpilot_toggles.SignalMetrics + toggle.steering_metrics = toggle.border_metrics and self.default_frogpilot_toggles.ShowSteering + toggle.show_fps = toggle.developer_ui and self.default_frogpilot_toggles.FPSCounter + toggle.lateral_metrics = toggle.developer_ui and self.default_frogpilot_toggles.LateralMetrics + toggle.adjacent_path_metrics = toggle.lateral_metrics and self.default_frogpilot_toggles.AdjacentPathMetrics + toggle.lateral_tuning_metrics = toggle.lateral_metrics and self.default_frogpilot_toggles.TuningInfo + toggle.longitudinal_metrics = toggle.developer_ui and self.default_frogpilot_toggles.LongitudinalMetrics + toggle.adjacent_lead_tracking = has_radar and toggle.longitudinal_metrics and self.default_frogpilot_toggles.AdjacentLeadsUI + toggle.lead_metrics = toggle.longitudinal_metrics and self.default_frogpilot_toggles.LeadInfo + toggle.jerk_metrics = toggle.longitudinal_metrics and self.default_frogpilot_toggles.JerkInfo + toggle.numerical_temp = toggle.developer_ui and self.default_frogpilot_toggles.NumericalTemp + toggle.fahrenheit = toggle.numerical_temp and self.default_frogpilot_toggles.Fahrenheit + toggle.sidebar_metrics = toggle.developer_ui and self.default_frogpilot_toggles.SidebarMetrics + toggle.cpu_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowCPU + toggle.gpu_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowGPU + toggle.ip_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowIP + toggle.memory_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowMemoryUsage + toggle.storage_left_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowStorageLeft + toggle.storage_used_metrics = toggle.sidebar_metrics and self.default_frogpilot_toggles.ShowStorageUsed + toggle.use_si_metrics = toggle.developer_ui and self.default_frogpilot_toggles.UseSI + + toggle.device_management = self.default_frogpilot_toggles.DeviceManagement + toggle.increase_thermal_limits = toggle.device_management and self.default_frogpilot_toggles.IncreaseThermalLimits + toggle.low_voltage_shutdown = clip(self.default_frogpilot_toggles.LowVoltageShutdown, VBATT_PAUSE_CHARGING, 12.5) if toggle.device_management else VBATT_PAUSE_CHARGING + toggle.no_logging = toggle.device_management and self.default_frogpilot_toggles.NoLogging + toggle.no_uploads = toggle.device_management and self.default_frogpilot_toggles.NoUploads + toggle.offline_mode = toggle.device_management and self.default_frogpilot_toggles.OfflineMode + + toggle.experimental_gm_tune = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.ExperimentalGMTune + + toggle.frogsgomoo_tweak = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.FrogsGoMoosTweak + + toggle.lane_detection_width = self.default_frogpilot_toggles.LaneDetectionWidth * distance_conversion if toggle.lane_change_customizations else 0 + toggle.lane_detection = toggle.lane_detection_width != 0 + toggle.minimum_lane_change_speed = self.default_frogpilot_toggles.MinimumLaneChangeSpeed * speed_conversion if toggle.lane_change_customizations else LANE_CHANGE_SPEED_MIN + + toggle.lateral_tuning = self.default_frogpilot_toggles.LateralTune + toggle.smooth_curve_handling = toggle.lateral_tuning and self.default_frogpilot_toggles.NNFFLite + toggle.taco_tune = toggle.lateral_tuning and self.default_frogpilot_toggles.TacoTune + toggle.use_turn_desires = toggle.lateral_tuning and self.default_frogpilot_toggles.TurnDesires + + toggle.long_pitch = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.LongPitch + + toggle.lead_detection_probability = clip(self.default_frogpilot_toggles.LeadDetectionThreshold / 100, 0.01, 0.99) if toggle.longitudinal_tuning else 0.5 + toggle.max_desired_acceleration = clip(self.default_frogpilot_toggles.MaxDesiredAcceleration, 0.1, 4.0) if toggle.longitudinal_tuning else 4.0 + + toggle.model = DEFAULT_MODEL + toggle.part_model_param = "" + toggle.classic_model = classic_models and toggle.model in classic_models.split(',') + toggle.navigationless_model = navigation_models and toggle.model not in navigation_models.split(',') + toggle.radarless_model = radarless_models and toggle.model in radarless_models.split(',') + + toggle.model_ui = self.default_frogpilot_toggles.ModelUI + toggle.dynamic_path_width = toggle.model_ui and self.default_frogpilot_toggles.DynamicPathWidth + toggle.lane_line_width = self.default_frogpilot_toggles.LaneLinesWidth * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.path_edge_width = self.default_frogpilot_toggles.PathEdgeWidth if toggle.model_ui else 20 + toggle.path_width = self.default_frogpilot_toggles.PathWidth * distance_conversion / 2 if toggle.model_ui else 0.9 + toggle.road_edge_width = self.default_frogpilot_toggles.RoadEdgesWidth * small_distance_conversion / 200 if toggle.model_ui else 0.025 + toggle.show_stopping_point = toggle.model_ui and self.default_frogpilot_toggles.ShowStoppingPoint + toggle.show_stopping_point_metrics = toggle.show_stopping_point and self.default_frogpilot_toggles.ShowStoppingPointMetrics + toggle.unlimited_road_ui_length = toggle.model_ui and self.default_frogpilot_toggles.UnlimitedLength + + toggle.map_style = self.default_frogpilot_toggles.MapStyle if toggle.navigation_ui else 0 + toggle.road_name_ui = toggle.navigation_ui and self.default_frogpilot_toggles.RoadNameUI + toggle.show_speed_limit_offset = toggle.navigation_ui and self.default_frogpilot_toggles.ShowSLCOffset + toggle.speed_limit_vienna = toggle.navigation_ui and self.default_frogpilot_toggles.UseVienna + + toggle.new_long_api_gm = openpilot_longitudinal and car_make == "gm" and self.default_frogpilot_toggles.NewLongAPIGM + toggle.new_long_api_hkg = openpilot_longitudinal and car_make == "hyundai" and self.default_frogpilot_toggles.NewLongAPI + + toggle.new_toyota_tune = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.NewToyotaTune + + toggle.quality_of_life_lateral = self.default_frogpilot_toggles.QOLLateral + toggle.pause_lateral_below_speed = self.default_frogpilot_toggles.PauseLateralSpeed * speed_conversion if toggle.quality_of_life_lateral else 0 + + toggle.custom_cruise_increase = self.default_frogpilot_toggles.CustomCruise if toggle.quality_of_life_longitudinal and not pcm_cruise else 1 + toggle.custom_cruise_increase_long = self.default_frogpilot_toggles.CustomCruiseLong if toggle.quality_of_life_longitudinal and not pcm_cruise else 5 + toggle.force_standstill = toggle.quality_of_life_longitudinal and self.default_frogpilot_toggles.ForceStandstill + toggle.force_stops = toggle.quality_of_life_longitudinal and self.default_frogpilot_toggles.ForceStops + toggle.pause_lateral_below_signal = toggle.pause_lateral_below_speed != 0 and self.default_frogpilot_toggles.PauseLateralOnSignal + toggle.reverse_cruise_increase = toggle.quality_of_life_longitudinal and pcm_cruise and self.default_frogpilot_toggles.ReverseCruise + toggle.set_speed_offset = self.default_frogpilot_toggles.SetSpeedOffset * (1 if toggle.is_metric else CV.MPH_TO_KPH) if toggle.quality_of_life_longitudinal and not pcm_cruise else 0 + + toggle.quality_of_life_visuals = self.default_frogpilot_toggles.QOLVisuals + toggle.camera_view = self.default_frogpilot_toggles.CameraView if toggle.quality_of_life_visuals else 0 + toggle.standby_mode = toggle.quality_of_life_visuals and self.default_frogpilot_toggles.StandbyMode + + toggle.screen_management = self.default_frogpilot_toggles.ScreenManagement + toggle.screen_brightness = self.default_frogpilot_toggles.ScreenBrightness if toggle.screen_management else 101 + toggle.screen_brightness_onroad = self.default_frogpilot_toggles.ScreenBrightnessOnroad if toggle.screen_management else 101 + toggle.screen_recorder = toggle.screen_management and self.default_frogpilot_toggles.ScreenRecorder + toggle.screen_timeout = self.default_frogpilot_toggles.ScreenTimeout if toggle.screen_management else 30 + toggle.screen_timeout_onroad = self.default_frogpilot_toggles.ScreenTimeoutOnroad if toggle.screen_management else 10 + + toggle.sng_hack = openpilot_longitudinal and car_make == "toyota" and self.default_frogpilot_toggles.SNGHack + + toggle.force_mph_dashboard = toggle.speed_limit_controller and self.default_frogpilot_toggles.ForceMPHDashboard + toggle.map_speed_lookahead_higher = self.default_frogpilot_toggles.SLCLookaheadHigher if toggle.speed_limit_controller else 0 + toggle.map_speed_lookahead_lower = self.default_frogpilot_toggles.SLCLookaheadLower if toggle.speed_limit_controller else 0 + toggle.set_speed_limit = toggle.speed_limit_controller and self.default_frogpilot_toggles.SetSpeedLimit + toggle.speed_limit_priority1 = self.default_frogpilot_toggles.SLCPriority1 if toggle.speed_limit_controller else None + toggle.speed_limit_priority2 = self.default_frogpilot_toggles.SLCPriority2 if toggle.speed_limit_controller else None + toggle.speed_limit_priority3 = self.default_frogpilot_toggles.SLCPriority3 if toggle.speed_limit_controller else None + toggle.speed_limit_priority_highest = toggle.speed_limit_priority1 == "Highest" + toggle.speed_limit_priority_lowest = toggle.speed_limit_priority1 == "Lowest" + toggle.speed_limit_vienna = toggle.speed_limit_controller and self.default_frogpilot_toggles.UseVienna + + toggle.startup_alert_top = self.default_frogpilot_toggles.StartupMessageTop + toggle.startup_alert_bottom = self.default_frogpilot_toggles.StartupMessageBottom + + toggle.volt_sng = car_model == "CHEVROLET_VOLT" and self.default_frogpilot_toggles.VoltSNG + + self.params.put("FrogPilotToggles", json.dumps(toggle.__dict__)) + self.params_memory.remove("FrogPilotTogglesUpdated") diff --git a/selfdrive/frogpilot/navigation/mapd.py b/selfdrive/frogpilot/navigation/mapd.py index 9fbd6f82..898fd48d 100644 --- a/selfdrive/frogpilot/navigation/mapd.py +++ b/selfdrive/frogpilot/navigation/mapd.py @@ -8,7 +8,7 @@ import urllib.request from openpilot.common.realtime import Ratekeeper -from openpilot.selfdrive.frogpilot.frogpilot_functions import is_url_pingable +from openpilot.selfdrive.frogpilot.frogpilot_utilities import is_url_pingable VERSION = 'v1' diff --git a/selfdrive/frogpilot/navigation/ui/maps_settings.cc b/selfdrive/frogpilot/navigation/ui/maps_settings.cc index c25150c0..91ea0bd0 100644 --- a/selfdrive/frogpilot/navigation/ui/maps_settings.cc +++ b/selfdrive/frogpilot/navigation/ui/maps_settings.cc @@ -8,14 +8,14 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) { std::vector scheduleOptions{tr("Manually"), tr("Weekly"), tr("Monthly")}; - preferredSchedule = new ButtonParamControl("PreferredSchedule", tr("Maps Scheduler"), - tr("Choose the frequency for updating maps with the latest OpenStreetMap (OSM) changes. " + preferredSchedule = new ButtonParamControl("PreferredSchedule", tr("Automatically Update Maps"), + tr("Controls the frequency at which maps update with the latest OpenStreetMap (OSM) changes. " "Weekly updates begin at midnight every Sunday, while monthly updates start at midnight on the 1st of each month."), "", scheduleOptions); addItem(preferredSchedule); - selectMapsButton = new FrogPilotButtonsControl(tr("Select Offline Maps"), tr("Select your maps to use with 'Curve Speed Control' and 'Speed Limit Controller'."), {tr("COUNTRIES"), tr("STATES")}); + selectMapsButton = new FrogPilotButtonsControl(tr("Select Offline Maps"), tr("Offline maps to use with 'Curve Speed Control' and 'Speed Limit Controller'."), {tr("COUNTRIES"), tr("STATES")}); QObject::connect(selectMapsButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) { if (id == 0) { countriesOpen = true; @@ -25,7 +25,7 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi }); addItem(selectMapsButton); - downloadMapsButton = new ButtonControl(tr("Download Maps"), tr("DOWNLOAD"), tr("Download your selected maps to use with 'Curve Speed Control' and 'Speed Limit Controller'.")); + downloadMapsButton = new ButtonControl(tr("Download Maps"), tr("DOWNLOAD"), tr("Downloads the selected maps to use with 'Curve Speed Control' and 'Speed Limit Controller'.")); QObject::connect(downloadMapsButton, &ButtonControl::clicked, [this] { if (downloadMapsButton->text() == tr("CANCEL")) { cancelDownload(); @@ -45,7 +45,7 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi downloadStatus->setVisible(false); downloadTimeElapsed->setVisible(false); - removeMapsButton = new ButtonControl(tr("Remove Maps"), tr("REMOVE"), tr("Remove your downloaded maps to clear up storage space.")); + removeMapsButton = new ButtonControl(tr("Remove Maps"), tr("REMOVE"), tr("Removes downloaded maps to clear up storage space.")); QObject::connect(removeMapsButton, &ButtonControl::clicked, [this] { if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to delete all of your downloaded maps?"), this)) { std::thread([this] { diff --git a/selfdrive/frogpilot/navigation/ui/primeless_settings.cc b/selfdrive/frogpilot/navigation/ui/primeless_settings.cc index f181ab04..230970c8 100644 --- a/selfdrive/frogpilot/navigation/ui/primeless_settings.cc +++ b/selfdrive/frogpilot/navigation/ui/primeless_settings.cc @@ -5,14 +5,14 @@ FrogPilotPrimelessPanel::FrogPilotPrimelessPanel(FrogPilotSettingsWindow *parent std::vector searchOptions{tr("MapBox"), tr("Amap"), tr("Google")}; searchInput = new ButtonParamControl("SearchInput", tr("Destination Search Provider"), - tr("Select a search provider for destination queries in Navigate on Openpilot. Options include MapBox (recommended), Amap, and Google Maps."), + tr("The search provider used for destination queries in 'Navigate on Openpilot'. Options include 'MapBox' (recommended), 'Amap', and 'Google Maps'."), "", searchOptions); addItem(searchInput); createMapboxKeyControl(publicMapboxKeyControl, tr("Public Mapbox Key"), "MapboxPublicKey", "pk."); createMapboxKeyControl(secretMapboxKeyControl, tr("Secret Mapbox Key"), "MapboxSecretKey", "sk."); - setupButton = new ButtonControl(tr("Mapbox Setup Instructions"), tr("VIEW"), tr("View the instructions to set up MapBox for 'Primeless Navigation'."), this); + setupButton = new ButtonControl(tr("MapBox Setup Instructions"), tr("VIEW"), tr("View the instructions to set up 'MapBox' for 'Primeless Navigation'."), this); QObject::connect(setupButton, &ButtonControl::clicked, [this]() { displayMapboxInstructions(true); openMapBoxInstructions(); @@ -91,6 +91,7 @@ void FrogPilotPrimelessPanel::hideEvent(QHideEvent *event) { } void FrogPilotPrimelessPanel::mousePressEvent(QMouseEvent *event) { + closeMapBoxInstructions(); displayMapboxInstructions(false); } diff --git a/selfdrive/frogpilot/navigation/ui/primeless_settings.h b/selfdrive/frogpilot/navigation/ui/primeless_settings.h index 690f0842..a5cd413f 100644 --- a/selfdrive/frogpilot/navigation/ui/primeless_settings.h +++ b/selfdrive/frogpilot/navigation/ui/primeless_settings.h @@ -9,6 +9,7 @@ public: explicit FrogPilotPrimelessPanel(FrogPilotSettingsWindow *parent); signals: + void closeMapBoxInstructions(); void openMapBoxInstructions(); private: diff --git a/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.cc deleted file mode 100644 index 9bff861e..00000000 --- a/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.cc +++ /dev/null @@ -1,935 +0,0 @@ -#include "selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.h" - -FrogPilotAdvancedDrivingPanel::FrogPilotAdvancedDrivingPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { - const std::vector> advancedToggles { - {"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("Advanced settings that control how openpilot manages steering."), "../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"}, - {"SteerFriction", steerFrictionStock != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(steerFrictionStock, 'f', 2)) : tr("Friction"), tr("The resistance in steering. Higher values provide more stable steering but can make it feel heavy, while lower values allow lighter steering but may feel too sensitive."), ""}, - {"SteerKP", steerKPStock != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKPStock, 'f', 2)) : tr("Kp Factor"), tr("How aggressively the car corrects its steering. Higher values offer quicker corrections but may feel jerky, while lower values make steering smoother but slower to respond."), ""}, - {"SteerLatAccel", steerLatAccelStock != 0 ? QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(steerLatAccelStock, 'f', 2)) : tr("Lateral Accel"), tr("Adjust how fast the car can steer from side to side. Higher values allow quicker lane changes but can feel unstable, while lower values provide smoother steering but may feel sluggish."), ""}, - {"SteerRatio", steerRatioStock != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatioStock, 'f', 2)) : tr("Steer Ratio"), tr("Adjust how much openpilot needs to turn the wheel to steer. Higher values feel like driving a truck, more stable at high speeds, but harder to steer quickly at low speeds, while lower values feel like a go-kart, easier to steer in tight spots but more sensitive and less stable at high speeds."), ""}, - {"TacoTune", tr("comma's 2022 Taco Bell Turn Hack"), tr("Use comma's hack they used to help handle left and right turns more precisely during their 2022 'Taco Bell' drive."), ""}, - {"ForceAutoTune", tr("Force Auto Tune On"), tr("Forces comma's auto lateral tuning for unsupported vehicles."), ""}, - {"ForceAutoTuneOff", tr("Force Auto Tune Off"), tr("Forces comma's auto lateral tuning off for supported vehicles."), ""}, - {"TurnDesires", tr("Force Turn Desires Below Lane Change Speed"), tr("Force the model to use turn desires when driving below the minimum lane change speed to help make left and right turns more precisely."), ""}, - - {"AdvancedLongitudinalTune", tr("Advanced Longitudinal Tuning"), tr("Advanced settings that control how openpilot manages speed and acceleration."), "../frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png"}, - {"LeadDetectionThreshold", tr("Lead Detection Confidence"), tr("How sensitive openpilot is to detecting vehicles ahead. A lower value can help detect vehicles sooner and from farther away, but may occasionally mistake other objects for vehicles."), ""}, - {"MaxDesiredAcceleration", tr("Maximum Acceleration Rate"), tr("Set a cap on how fast openpilot can accelerate to prevent high acceleration at low speeds."), ""}, - - {"AdvancedQOLDriving", tr("Advanced Quality of Life"), tr("Miscellaneous advanced features to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/advanced_quality_of_life.png"}, - {"ForceStandstill", tr("Force Keep openpilot in the Standstill State"), tr("Keep openpilot in the 'standstill' state until the gas pedal or 'resume' button is pressed."), ""}, - {"ForceStops", tr("Force Stop for 'Detected' Stop Lights/Signs"), tr("Whenever openpilot 'detects' a potential stop light/stop sign, force a stop where it originally detected it to prevent running the potential red light/stop sign."), ""}, - {"SetSpeedOffset", tr("Set Speed Offset"), tr("How much higher or lower the set speed should be compared to your current set speed. For example, if you prefer to drive 5 mph above the speed limit, this setting will automatically add that difference when you adjust your set speed."), ""}, - - {"CustomPersonalities", tr("Customize Driving Personalities"), tr("Customize the personality profiles to suit your preferences."), "../frogpilot/assets/toggle_icons/icon_advanced_personality.png"}, - {"TrafficPersonalityProfile", tr("Traffic Personality"), tr("Customize the 'Traffic' personality profile, tailored for navigating through traffic."), "../frogpilot/assets/stock_theme/distance_icons/traffic.png"}, - {"TrafficFollow", tr("Following Distance"), tr("The minimum following distance in 'Traffic Mode.' openpilot will adjust dynamically between this value and the 'Aggressive' profile distance based on your speed."), ""}, - {"TrafficJerkAcceleration", tr("Acceleration Sensitivity"), tr("How sensitive openpilot is to changes in acceleration in 'Traffic Mode.' Higher values result in smoother, more gradual acceleration and deceleration, while lower values allow for faster changes that may feel more abrupt."), ""}, - {"TrafficJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in deceleration in 'Traffic Mode.' Higher values result in smoother, more gradual braking, while lower values allow for quicker, more responsive braking that may feel abrupt."), ""}, - {"TrafficJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around other vehicles or obstacles in 'Traffic Mode.' Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""}, - {"TrafficJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot adjusts speed in 'Traffic Mode.' Higher values ensure smoother, more gradual speed changes, while lower values enable quicker adjustments that might feel sharper or less smooth."), ""}, - {"TrafficJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to decreasing speeds in 'Traffic Mode.' Higher values ensure smoother transitions when slowing down, while lower values allow for quicker, more responsive speed reductions that might feel sharper."), ""}, - {"ResetTrafficPersonality", tr("Reset Settings"), tr("Restore the 'Traffic Mode' settings to their default values."), ""}, - - {"AggressivePersonalityProfile", tr("Aggressive Personality"), tr("Customize the 'Aggressive' personality profile, designed for a more assertive driving style."), "../frogpilot/assets/stock_theme/distance_icons/aggressive.png"}, - {"AggressiveFollow", tr("Following Distance"), tr("Set the following distance for 'Aggressive' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.25 seconds."), ""}, - {"AggressiveJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to acceleration changes in 'Aggressive' mode. Higher values make acceleration and deceleration smoother but slower, while lower values allow quicker changes that may feel jerky.\n\nDefault: 0.5."), ""}, - {"AggressiveJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to deceleration in 'Aggressive' mode. Higher values result in smoother braking, while lower values allow for more immediate braking that may feel abrupt.\n\nDefault: 0.5."), ""}, - {"AggressiveJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around vehicles or obstacles in 'Aggressive' mode. Higher values make it more cautious, while lower values allow for closer following, increasing the risk of sudden braking.\n\nDefault: 1.0."), ""}, - {"AggressiveJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot adjusts speed in 'Aggressive' mode. Higher values result in smoother but slower speed changes, while lower values make speed adjustments quicker but potentially more abrupt.\n\nDefault: 0.5."), ""}, - {"AggressiveJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to speed reductions in 'Aggressive' mode. Higher values ensure smoother transitions when slowing down, while lower values allow for quicker, more responsive speed decreases that may feel sharp.\n\nDefault: 0.5."), ""}, - {"ResetAggressivePersonality", tr("Reset Settings"), tr("Restore the 'Aggressive' settings to their default values."), ""}, - - {"StandardPersonalityProfile", tr("Standard Personality"), tr("Customize the 'Standard' personality profile, optimized for balanced driving."), "../frogpilot/assets/stock_theme/distance_icons/standard.png"}, - {"StandardFollow", tr("Following Distance"), tr("Set the following distance for 'Standard' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.45 seconds."), ""}, - {"StandardJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to acceleration changes in 'Standard' mode. Higher values make acceleration and deceleration smoother but slower, while lower values allow quicker changes that may feel jerky.\n\nDefault: 1.0."), ""}, - {"StandardJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to deceleration in 'Standard' mode. Higher values result in smoother braking, while lower values allow for quicker, more immediate braking that may feel abrupt.\n\nDefault: 1.0."), ""}, - {"StandardJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around vehicles or obstacles in 'Standard' mode. Higher values make it more cautious, while lower values allow for closer following, increasing the risk of sudden braking.\n\nDefault: 1.0."), ""}, - {"StandardJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot adjusts speed in 'Standard' mode. Higher values result in smoother but slower speed changes, while lower values make speed adjustments quicker but potentially more abrupt.\n\nDefault: 1.0."), ""}, - {"StandardJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to speed reductions in 'Standard' mode. Higher values ensure smoother transitions when slowing down, while lower values allow for quicker, more responsive speed decreases that may feel sharp.\n\nDefault: 1.0."), ""}, - {"ResetStandardPersonality", tr("Reset Settings"), tr("Restore the 'Standard' settings to their default values."), ""}, - - {"RelaxedPersonalityProfile", tr("Relaxed Personality"), tr("Customize the 'Relaxed' personality profile, ideal for a more laid-back driving style."), "../frogpilot/assets/stock_theme/distance_icons/relaxed.png"}, - {"RelaxedFollow", tr("Following Distance"), tr("Set the following distance for 'Relaxed' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.75 seconds."), ""}, - {"RelaxedJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to acceleration changes in 'Relaxed' mode. Higher values make acceleration and deceleration smoother but slower, while lower values allow quicker changes that may feel jerky.\n\nDefault: 1.0."), ""}, - {"RelaxedJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to deceleration in 'Relaxed' mode. Higher values result in smoother braking, while lower values allow for quicker, more immediate braking that may feel abrupt.\n\nDefault: 1.0."), ""}, - {"RelaxedJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around vehicles or obstacles in 'Relaxed' mode. Higher values make it more cautious, while lower values allow for closer following, increasing the risk of sudden braking.\n\nDefault: 1.0."), ""}, - {"RelaxedJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot adjusts speed in 'Relaxed' mode. Higher values result in smoother but slower speed changes, while lower values make speed adjustments quicker but potentially more abrupt.\n\nDefault: 1.0."), ""}, - {"RelaxedJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to speed reductions in 'Relaxed' mode. Higher values ensure smoother transitions when slowing down, while lower values allow for quicker, more responsive speed decreases that may feel sharp.\n\nDefault: 1.0."), ""}, - {"ResetRelaxedPersonality", tr("Reset Settings"), tr("Restore the 'Relaxed' settings to their default values."), ""}, - - {"ModelManagement", tr("Model Management"), tr("Manage the driving models used by openpilot."), "../frogpilot/assets/toggle_icons/icon_advanced_model.png"}, - {"AutomaticallyUpdateModels", tr("Automatically Update and Download Models"), tr("Automatically download new or updated driving models."), ""}, - {"ModelRandomizer", tr("Model Randomizer"), tr("A random model is selected and can be reviewed at the end of each drive if it's longer than 15 minutes to help find your preferred model."), ""}, - {"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("Control which models are blacklisted and won't be used for future drives."), ""}, - {"ResetScores", tr("Reset Model Scores"), tr("Clear the ratings you've given to the driving models."), ""}, - {"ReviewScores", tr("Review Model Scores"), tr("View the ratings you've assigned to the driving models."), ""}, - {"DeleteModel", tr("Delete Model"), tr("Remove the selected driving model from your device."), ""}, - {"DownloadModel", tr("Download Model"), tr("Download undownloaded driving models."), ""}, - {"DownloadAllModels", tr("Download All Models"), tr("Download all undownloaded driving models."), ""}, - {"SelectModel", tr("Select Model"), tr("Select which model openpilot uses to drive."), ""}, - {"ResetCalibrations", tr("Reset Model Calibrations"), tr("Reset calibration settings for the driving models."), ""}, - }; - - for (const auto &[param, title, desc, icon] : advancedToggles) { - AbstractControl *advancedDrivingToggle; - - if (param == "AdvancedLateralTune") { - FrogPilotParamManageControl *advancedLateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(advancedLateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - std::set modifiedLateralTuneKeys = lateralTuneKeys; - - bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF"); - if (usingNNFF) { - modifiedLateralTuneKeys.erase("ForceAutoTune"); - modifiedLateralTuneKeys.erase("ForceAutoTuneOff"); - } else { - if (hasAutoTune) { - modifiedLateralTuneKeys.erase("ForceAutoTune"); - } else if (isPIDCar) { - modifiedLateralTuneKeys.erase("ForceAutoTuneOff"); - modifiedLateralTuneKeys.erase("SteerFriction"); - modifiedLateralTuneKeys.erase("SteerKP"); - modifiedLateralTuneKeys.erase("SteerLatAccel"); - } else { - modifiedLateralTuneKeys.erase("ForceAutoTuneOff"); - } - } - - if (!liveValid || usingNNFF) { - modifiedLateralTuneKeys.erase("SteerFriction"); - modifiedLateralTuneKeys.erase("SteerLatAccel"); - } - - showToggles(modifiedLateralTuneKeys); - }); - advancedDrivingToggle = advancedLateralTuneToggle; - } else if (param == "SteerFriction") { - std::vector steerFrictionToggleNames{"Reset"}; - advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0.01, 0.25, QString(), std::map(), 0.01, {}, steerFrictionToggleNames, false); - } else if (param == "SteerKP") { - std::vector steerKPToggleNames{"Reset"}; - advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerKPStock * 0.50, steerKPStock * 1.50, QString(), std::map(), 0.01, {}, steerKPToggleNames, false); - } else if (param == "SteerLatAccel") { - std::vector steerLatAccelToggleNames{"Reset"}; - advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerLatAccelStock * 0.25, steerLatAccelStock * 1.25, QString(), std::map(), 0.01, {}, steerLatAccelToggleNames, false); - } else if (param == "SteerRatio") { - std::vector steerRatioToggleNames{"Reset"}; - advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, QString(), std::map(), 0.01, {}, steerRatioToggleNames, false); - - } else if (param == "AdvancedLongitudinalTune") { - FrogPilotParamManageControl *advancedLongitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(advancedLongitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - std::set modifiedLongitudinalTuneKeys = longitudinalTuneKeys; - - bool radarlessModel = QString::fromStdString(params.get("RadarlessModels")).split(",").contains(QString::fromStdString(params.get("Model"))); - if (radarlessModel) { - modifiedLongitudinalTuneKeys.erase("LeadDetectionThreshold"); - } - - showToggles(modifiedLongitudinalTuneKeys); - }); - advancedDrivingToggle = advancedLongitudinalTuneToggle; - } else if (param == "LeadDetectionThreshold") { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, "%"); - } else if (param == "MaxDesiredAcceleration") { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.1, 4.0, "m/s", std::map(), 0.1); - - } else if (param == "AdvancedQOLDriving") { - FrogPilotParamManageControl *advancedQOLToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(advancedQOLToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - std::set modifiedQolKeys = qolKeys; - - if (hasPCMCruise) { - modifiedQolKeys.erase("SetSpeedOffset"); - } - - showToggles(modifiedQolKeys); - }); - advancedDrivingToggle = advancedQOLToggle; - } else if (param == "SetSpeedOffset") { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); - - } else if (param == "CustomPersonalities") { - FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(customDrivingPersonalityKeys); - }); - advancedDrivingToggle = customPersonalitiesToggle; - } else if (param == "ResetTrafficPersonality" || param == "ResetAggressivePersonality" || param == "ResetStandardPersonality" || param == "ResetRelaxedPersonality") { - FrogPilotButtonsControl *profileBtn = new FrogPilotButtonsControl(title, desc, {tr("Reset")}); - advancedDrivingToggle = profileBtn; - } else if (param == "TrafficPersonalityProfile") { - FrogPilotParamManageControl *trafficPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(trafficPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - customPersonalityOpen = true; - openSubParentToggle(); - showToggles(trafficPersonalityKeys); - }); - advancedDrivingToggle = trafficPersonalityToggle; - } else if (param == "AggressivePersonalityProfile") { - FrogPilotParamManageControl *aggressivePersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(aggressivePersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - customPersonalityOpen = true; - openSubParentToggle(); - showToggles(aggressivePersonalityKeys); - }); - advancedDrivingToggle = aggressivePersonalityToggle; - } else if (param == "StandardPersonalityProfile") { - FrogPilotParamManageControl *standardPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(standardPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - customPersonalityOpen = true; - openSubParentToggle(); - showToggles(standardPersonalityKeys); - }); - advancedDrivingToggle = standardPersonalityToggle; - } else if (param == "RelaxedPersonalityProfile") { - FrogPilotParamManageControl *relaxedPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(relaxedPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - customPersonalityOpen = true; - openSubParentToggle(); - showToggles(relaxedPersonalityKeys); - }); - advancedDrivingToggle = relaxedPersonalityToggle; - } else if (trafficPersonalityKeys.find(param) != trafficPersonalityKeys.end() || - aggressivePersonalityKeys.find(param) != aggressivePersonalityKeys.end() || - standardPersonalityKeys.find(param) != standardPersonalityKeys.end() || - relaxedPersonalityKeys.find(param) != relaxedPersonalityKeys.end()) { - if (param == "TrafficFollow" || param == "AggressiveFollow" || param == "StandardFollow" || param == "RelaxedFollow") { - if (param == "TrafficFollow") { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.5, 5, tr(" seconds"), std::map(), 0.01); - } else { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 5, tr(" seconds"), std::map(), 0.01); - } - } else { - advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 500, "%"); - } - - } else if (param == "ModelManagement") { - FrogPilotParamManageControl *modelManagementToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(modelManagementToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - availableModelNames = QString::fromStdString(params.get("AvailableModelsNames")).split(","); - availableModels = QString::fromStdString(params.get("AvailableModels")).split(","); - experimentalModels = QString::fromStdString(params.get("ExperimentalModels")).split(","); - - modelManagementOpen = true; - - QString currentModel = QString::fromStdString(params.get("Model")) + ".thneed"; - QStringList modelFiles = modelDir.entryList({"*.thneed"}, QDir::Files); - modelFiles.removeAll(currentModel); - haveModelsDownloaded = modelFiles.size() > 1; - modelsDownloaded = params.getBool("ModelsDownloaded"); - - showToggles(modelManagementKeys); - }); - advancedDrivingToggle = modelManagementToggle; - } else if (param == "ModelRandomizer") { - FrogPilotParamManageControl *modelRandomizerToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(modelRandomizerToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - openSubParentToggle(); - showToggles(modelRandomizerKeys); - updateModelLabels(); - }); - advancedDrivingToggle = modelRandomizerToggle; - } else if (param == "ManageBlacklistedModels") { - FrogPilotButtonsControl *blacklistBtn = new FrogPilotButtonsControl(title, desc, {tr("ADD"), tr("REMOVE")}); - QObject::connect(blacklistBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) { - QStringList blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",", QString::SkipEmptyParts); - QStringList selectableModels = availableModelNames; - - for (QString &model : blacklistedModels) { - selectableModels.removeAll(model); - if (model.contains("(Default)")) { - blacklistedModels.move(blacklistedModels.indexOf(model), 0); - } - } - - if (id == 0) { - if (selectableModels.size() == 1) { - FrogPilotConfirmationDialog::toggleAlert(tr("There's no more models to blacklist! The only available model is \"%1\"!").arg(selectableModels.first()), tr("OK"), this); - } else { - QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to add to the blacklist"), selectableModels, "", this); - if (!selectedModel.isEmpty()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to add the '%1' model to the blacklist?").arg(selectedModel), tr("Add"), this)) { - if (!blacklistedModels.contains(selectedModel)) { - blacklistedModels.append(selectedModel); - params.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); - paramsStorage.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); - } - } - } - } - } else if (id == 1) { - QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to remove from the blacklist"), blacklistedModels, "", this); - if (!selectedModel.isEmpty()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to remove the '%1' model from the blacklist?").arg(selectedModel), tr("Remove"), this)) { - if (blacklistedModels.contains(selectedModel)) { - blacklistedModels.removeAll(selectedModel); - params.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); - paramsStorage.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); - } - } - } - } - }); - advancedDrivingToggle = blacklistBtn; - } else if (param == "ResetScores") { - ButtonControl *resetCalibrationsBtn = new ButtonControl(title, tr("RESET"), desc); - QObject::connect(resetCalibrationsBtn, &ButtonControl::clicked, [this]() { - if (FrogPilotConfirmationDialog::yesorno(tr("Reset all model scores?"), this)) { - for (const QString &model : availableModelNames) { - QString cleanedModel = processModelName(model); - params.remove(QString("%1Drives").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1Drives").arg(cleanedModel).toStdString()); - params.remove(QString("%1Score").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1Score").arg(cleanedModel).toStdString()); - } - updateModelLabels(); - } - }); - advancedDrivingToggle = reinterpret_cast(resetCalibrationsBtn); - } else if (param == "ReviewScores") { - ButtonControl *reviewScoresBtn = new ButtonControl(title, tr("VIEW"), desc); - QObject::connect(reviewScoresBtn, &ButtonControl::clicked, [this]() { - openSubSubParentToggle(); - - for (LabelControl *label : labelControls) { - label->setVisible(true); - } - - for (auto &[key, toggle] : toggles) { - toggle->setVisible(false); - } - }); - advancedDrivingToggle = reinterpret_cast(reviewScoresBtn); - } else if (param == "DeleteModel") { - deleteModelBtn = new ButtonControl(title, tr("DELETE"), desc); - QObject::connect(deleteModelBtn, &ButtonControl::clicked, [this]() { - QStringList deletableModels, existingModels = modelDir.entryList({"*.thneed"}, QDir::Files); - QMap labelToFileMap; - QString currentModel = QString::fromStdString(params.get("Model")) + ".thneed"; - - for (int i = 0; i < availableModels.size(); ++i) { - QString modelFile = availableModels[i] + ".thneed"; - if (existingModels.contains(modelFile) && modelFile != currentModel && !availableModelNames[i].contains("(Default)")) { - deletableModels.append(availableModelNames[i]); - labelToFileMap[availableModelNames[i]] = modelFile; - } - } - - QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to delete"), deletableModels, "", this); - if (!selectedModel.isEmpty()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to delete the '%1' model?").arg(selectedModel), tr("Delete"), this)) { - std::thread([=]() { - modelDeleting = true; - modelsDownloaded = false; - update(); - - params.putBoolNonBlocking("ModelsDownloaded", false); - deleteModelBtn->setValue(tr("Deleting...")); - - QFile::remove(modelDir.absoluteFilePath(labelToFileMap[selectedModel])); - deleteModelBtn->setValue(tr("Deleted!")); - - util::sleep_for(1000); - deleteModelBtn->setValue(""); - modelDeleting = false; - - QStringList modelFiles = modelDir.entryList({"*.thneed"}, QDir::Files); - modelFiles.removeAll(currentModel); - - haveModelsDownloaded = modelFiles.size() > 1; - update(); - }).detach(); - } - } - }); - advancedDrivingToggle = reinterpret_cast(deleteModelBtn); - } else if (param == "DownloadModel") { - downloadModelBtn = new ButtonControl(title, tr("DOWNLOAD"), desc); - QObject::connect(downloadModelBtn, &ButtonControl::clicked, [this]() { - if (downloadModelBtn->text() == tr("CANCEL")) { - paramsMemory.remove("ModelToDownload"); - paramsMemory.putBool("CancelModelDownload", true); - cancellingDownload = true; - - device()->resetInteractiveTimeout(30); - } else { - QMap labelToModelMap; - QStringList existingModels = modelDir.entryList({"*.thneed"}, QDir::Files); - QStringList downloadableModels; - - for (int i = 0; i < availableModels.size(); ++i) { - QString modelFile = availableModels[i] + ".thneed"; - if (!existingModels.contains(modelFile) && !availableModelNames[i].contains("(Default)")) { - downloadableModels.append(availableModelNames[i]); - labelToModelMap.insert(availableModelNames[i], availableModels[i]); - } - } - - QString modelToDownload = MultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableModels, "", this); - if (!modelToDownload.isEmpty()) { - device()->resetInteractiveTimeout(300); - - modelDownloading = true; - paramsMemory.put("ModelToDownload", labelToModelMap.value(modelToDownload).toStdString()); - paramsMemory.put("ModelDownloadProgress", "0%"); - - downloadModelBtn->setValue(tr("Downloading %1...").arg(modelToDownload.remove(QRegularExpression("[🗺️👀📡]")).trimmed())); - - QTimer *progressTimer = new QTimer(this); - progressTimer->setInterval(100); - - QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { - QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); - bool downloadComplete = progress.contains(QRegularExpression("downloaded", QRegularExpression::CaseInsensitiveOption)); - bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); - - if (!progress.isEmpty() && progress != "0%") { - downloadModelBtn->setValue(progress); - } - - if (downloadComplete || downloadFailed) { - bool lastModelDownloaded = downloadComplete; - - if (downloadComplete) { - haveModelsDownloaded = true; - update(); - } - - if (downloadComplete) { - for (const QString &model : availableModels) { - if (!QFile::exists(modelDir.filePath(model + ".thneed"))) { - lastModelDownloaded = false; - break; - } - } - } - - downloadModelBtn->setValue(progress); - - paramsMemory.remove("CancelModelDownload"); - paramsMemory.remove("ModelDownloadProgress"); - - progressTimer->stop(); - progressTimer->deleteLater(); - - QTimer::singleShot(2000, this, [=]() { - cancellingDownload = false; - modelDownloading = false; - - downloadModelBtn->setValue(""); - - if (lastModelDownloaded) { - modelsDownloaded = true; - update(); - - params.putBoolNonBlocking("ModelsDownloaded", modelsDownloaded); - } - - device()->resetInteractiveTimeout(30); - }); - } - }); - progressTimer->start(); - } - } - }); - advancedDrivingToggle = reinterpret_cast(downloadModelBtn); - } else if (param == "DownloadAllModels") { - downloadAllModelsBtn = new ButtonControl(title, tr("DOWNLOAD"), desc); - QObject::connect(downloadAllModelsBtn, &ButtonControl::clicked, [this]() { - if (downloadAllModelsBtn->text() == tr("CANCEL")) { - paramsMemory.remove("DownloadAllModels"); - paramsMemory.putBool("CancelModelDownload", true); - cancellingDownload = true; - - device()->resetInteractiveTimeout(30); - } else { - device()->resetInteractiveTimeout(300); - - startDownloadAllModels(); - } - }); - advancedDrivingToggle = reinterpret_cast(downloadAllModelsBtn); - } else if (param == "SelectModel") { - selectModelBtn = new ButtonControl(title, tr("SELECT"), desc); - QObject::connect(selectModelBtn, &ButtonControl::clicked, [this]() { - QSet modelFilesBaseNames = QSet::fromList(modelDir.entryList({"*.thneed"}, QDir::Files).replaceInStrings(QRegExp("\\.thneed$"), "")); - QStringList selectableModels; - - for (int i = 0; i < availableModels.size(); ++i) { - if (modelFilesBaseNames.contains(availableModels[i]) || availableModelNames[i].contains("(Default)")) { - selectableModels.append(availableModelNames[i]); - } - } - - QString modelToSelect = MultiOptionDialog::getSelection(tr("Select a model - 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), selectableModels, "", this); - if (!modelToSelect.isEmpty()) { - selectModelBtn->setValue(modelToSelect); - int modelIndex = availableModelNames.indexOf(modelToSelect); - - params.putNonBlocking("Model", availableModels.at(modelIndex).toStdString()); - params.putNonBlocking("ModelName", modelToSelect.toStdString()); - - if (experimentalModels.contains(availableModels.at(modelIndex))) { - FrogPilotConfirmationDialog::toggleAlert(tr("WARNING: This is a very experimental model and may drive dangerously!"), tr("I understand the risks."), this); - } - - QString model = availableModelNames.at(modelIndex); - QString part_model_param = processModelName(model); - - if (!params.checkKey(part_model_param.toStdString() + "CalibrationParams") || !params.checkKey(part_model_param.toStdString() + "LiveTorqueParameters")) { - if (FrogPilotConfirmationDialog::yesorno(tr("Start with a fresh calibration for the newly selected model?"), this)) { - params.remove("CalibrationParams"); - params.remove("LiveTorqueParameters"); - } - } - - if (started) { - if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) { - Hardware::reboot(); - } - } - } - }); - selectModelBtn->setValue(QString::fromStdString(params.get("ModelName"))); - advancedDrivingToggle = reinterpret_cast(selectModelBtn); - } else if (param == "ResetCalibrations") { - FrogPilotButtonsControl *resetCalibrationsBtn = new FrogPilotButtonsControl(title, desc, {tr("RESET ALL"), tr("RESET ONE")}); - QObject::connect(resetCalibrationsBtn, &FrogPilotButtonsControl::showDescriptionEvent, this, &FrogPilotAdvancedDrivingPanel::updateCalibrationDescription); - QObject::connect(resetCalibrationsBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) { - if (id == 0) { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset all of your model calibrations?"), this)) { - for (const QString &model : availableModelNames) { - QString cleanedModel = processModelName(model); - params.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); - params.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); - } - } - } else if (id == 1) { - QStringList selectableModelLabels; - for (int i = 0; i < availableModels.size(); ++i) { - selectableModelLabels.append(availableModelNames[i]); - } - - QString modelToReset = MultiOptionDialog::getSelection(tr("Select a model to reset"), selectableModelLabels, "", this); - if (!modelToReset.isEmpty()) { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset this model's calibrations?"), this)) { - QString cleanedModel = processModelName(modelToReset); - params.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); - params.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); - paramsStorage.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); - } - } - } - }); - advancedDrivingToggle = resetCalibrationsBtn; - - } else { - advancedDrivingToggle = new ParamControl(param, title, desc, icon); - } - - addItem(advancedDrivingToggle); - toggles[param] = advancedDrivingToggle; - - makeConnections(advancedDrivingToggle); - - if (FrogPilotParamManageControl *frogPilotManageToggle = qobject_cast(advancedDrivingToggle)) { - QObject::connect(frogPilotManageToggle, &FrogPilotParamManageControl::manageButtonClicked, this, &FrogPilotAdvancedDrivingPanel::openParentToggle); - } - - QObject::connect(advancedDrivingToggle, &AbstractControl::showDescriptionEvent, [this]() { - update(); - }); - } - - QObject::connect(static_cast(toggles["ModelManagement"]), &ToggleControl::toggleFlipped, [this](bool state) { - modelManagement = state; - }); - - QObject::connect(static_cast(toggles["ModelRandomizer"]), &ToggleControl::toggleFlipped, [this](bool state) { - modelRandomizer = state; - if (state && !modelsDownloaded) { - if (FrogPilotConfirmationDialog::yesorno(tr("The 'Model Randomizer' only works with downloaded models. Do you want to download all the driving models?"), this)) { - startDownloadAllModels(); - } - } - }); - - steerFrictionToggle = static_cast(toggles["SteerFriction"]); - QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { - params.putFloat("SteerFriction", steerFrictionStock); - steerFrictionToggle->refresh(); - updateFrogPilotToggles(); - }); - - steerKPToggle = static_cast(toggles["SteerKP"]); - QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { - params.putFloat("SteerKP", steerKPStock); - steerKPToggle->refresh(); - updateFrogPilotToggles(); - }); - - steerLatAccelToggle = static_cast(toggles["SteerLatAccel"]); - QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { - params.putFloat("SteerLatAccel", steerLatAccelStock); - steerLatAccelToggle->refresh(); - updateFrogPilotToggles(); - }); - - steerRatioToggle = static_cast(toggles["SteerRatio"]); - QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { - params.putFloat("SteerRatio", steerRatioStock); - steerRatioToggle->refresh(); - updateFrogPilotToggles(); - }); - - FrogPilotParamValueControl *trafficFollowToggle = static_cast(toggles["TrafficFollow"]); - FrogPilotParamValueControl *trafficAccelerationToggle = static_cast(toggles["TrafficJerkAcceleration"]); - FrogPilotParamValueControl *trafficDecelerationToggle = static_cast(toggles["TrafficJerkDeceleration"]); - FrogPilotParamValueControl *trafficDangerToggle = static_cast(toggles["TrafficJerkDanger"]); - FrogPilotParamValueControl *trafficSpeedToggle = static_cast(toggles["TrafficJerkSpeed"]); - FrogPilotParamValueControl *trafficSpeedDecreaseToggle = static_cast(toggles["TrafficJerkSpeedDecrease"]); - FrogPilotButtonsControl *trafficResetButton = static_cast(toggles["ResetTrafficPersonality"]); - QObject::connect(trafficResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Traffic Mode' personality?"), this)) { - params.putFloat("TrafficFollow", 0.5); - params.putFloat("TrafficJerkAcceleration", 50); - params.putFloat("TrafficJerkDeceleration", 50); - params.putFloat("TrafficJerkDanger", 100); - params.putFloat("TrafficJerkSpeed", 50); - params.putFloat("TrafficJerkSpeedDecrease", 50); - trafficFollowToggle->refresh(); - trafficAccelerationToggle->refresh(); - trafficDecelerationToggle->refresh(); - trafficDangerToggle->refresh(); - trafficSpeedToggle->refresh(); - trafficSpeedDecreaseToggle->refresh(); - updateFrogPilotToggles(); - } - }); - - FrogPilotParamValueControl *aggressiveFollowToggle = static_cast(toggles["AggressiveFollow"]); - FrogPilotParamValueControl *aggressiveAccelerationToggle = static_cast(toggles["AggressiveJerkAcceleration"]); - FrogPilotParamValueControl *aggressiveDecelerationToggle = static_cast(toggles["AggressiveJerkDeceleration"]); - FrogPilotParamValueControl *aggressiveDangerToggle = static_cast(toggles["AggressiveJerkDanger"]); - FrogPilotParamValueControl *aggressiveSpeedToggle = static_cast(toggles["AggressiveJerkSpeed"]); - FrogPilotParamValueControl *aggressiveSpeedDecreaseToggle = static_cast(toggles["AggressiveJerkSpeedDecrease"]); - FrogPilotButtonsControl *aggressiveResetButton = static_cast(toggles["ResetAggressivePersonality"]); - QObject::connect(aggressiveResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Aggressive' personality?"), this)) { - params.putFloat("AggressiveFollow", 1.25); - params.putFloat("AggressiveJerkAcceleration", 50); - params.putFloat("AggressiveJerkDeceleration", 50); - params.putFloat("AggressiveJerkDanger", 100); - params.putFloat("AggressiveJerkSpeed", 50); - params.putFloat("AggressiveJerkSpeedDecrease", 50); - aggressiveFollowToggle->refresh(); - aggressiveAccelerationToggle->refresh(); - aggressiveDecelerationToggle->refresh(); - aggressiveDangerToggle->refresh(); - aggressiveSpeedToggle->refresh(); - aggressiveSpeedDecreaseToggle->refresh(); - updateFrogPilotToggles(); - } - }); - - FrogPilotParamValueControl *standardFollowToggle = static_cast(toggles["StandardFollow"]); - FrogPilotParamValueControl *standardAccelerationToggle = static_cast(toggles["StandardJerkAcceleration"]); - FrogPilotParamValueControl *standardDecelerationToggle = static_cast(toggles["StandardJerkDeceleration"]); - FrogPilotParamValueControl *standardDangerToggle = static_cast(toggles["StandardJerkDanger"]); - FrogPilotParamValueControl *standardSpeedToggle = static_cast(toggles["StandardJerkSpeed"]); - FrogPilotParamValueControl *standardSpeedDecreaseToggle = static_cast(toggles["StandardJerkSpeedDecrease"]); - FrogPilotButtonsControl *standardResetButton = static_cast(toggles["ResetStandardPersonality"]); - QObject::connect(standardResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Standard' personality?"), this)) { - params.putFloat("StandardFollow", 1.45); - params.putFloat("StandardJerkAcceleration", 100); - params.putFloat("StandardJerkDeceleration", 100); - params.putFloat("StandardJerkDanger", 100); - params.putFloat("StandardJerkSpeed", 100); - params.putFloat("StandardJerkSpeedDecrease", 100); - standardFollowToggle->refresh(); - standardAccelerationToggle->refresh(); - standardDecelerationToggle->refresh(); - standardDangerToggle->refresh(); - standardSpeedToggle->refresh(); - standardSpeedDecreaseToggle->refresh(); - updateFrogPilotToggles(); - } - }); - - FrogPilotParamValueControl *relaxedFollowToggle = static_cast(toggles["RelaxedFollow"]); - FrogPilotParamValueControl *relaxedAccelerationToggle = static_cast(toggles["RelaxedJerkAcceleration"]); - FrogPilotParamValueControl *relaxedDecelerationToggle = static_cast(toggles["RelaxedJerkDeceleration"]); - FrogPilotParamValueControl *relaxedDangerToggle = static_cast(toggles["RelaxedJerkDanger"]); - FrogPilotParamValueControl *relaxedSpeedToggle = static_cast(toggles["RelaxedJerkSpeed"]); - FrogPilotParamValueControl *relaxedSpeedDecreaseToggle = static_cast(toggles["RelaxedJerkSpeedDecrease"]); - FrogPilotButtonsControl *relaxedResetButton = static_cast(toggles["ResetRelaxedPersonality"]); - QObject::connect(relaxedResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { - if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Relaxed' personality?"), this)) { - params.putFloat("RelaxedFollow", 1.75); - params.putFloat("RelaxedJerkAcceleration", 100); - params.putFloat("RelaxedJerkDeceleration", 100); - params.putFloat("RelaxedJerkDanger", 100); - params.putFloat("RelaxedJerkSpeed", 100); - params.putFloat("RelaxedJerkSpeedDecrease", 100); - relaxedFollowToggle->refresh(); - relaxedAccelerationToggle->refresh(); - relaxedDecelerationToggle->refresh(); - relaxedDangerToggle->refresh(); - relaxedSpeedToggle->refresh(); - relaxedSpeedDecreaseToggle->refresh(); - updateFrogPilotToggles(); - } - }); - - QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotAdvancedDrivingPanel::hideToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::closeSubParentToggle, this, &FrogPilotAdvancedDrivingPanel::hideSubToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubParentToggle, this, &FrogPilotAdvancedDrivingPanel::hideSubSubToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotAdvancedDrivingPanel::updateCarToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotAdvancedDrivingPanel::updateMetric); - QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotAdvancedDrivingPanel::updateState); - - updateMetric(); -} - -void FrogPilotAdvancedDrivingPanel::updateMetric() { - bool previousIsMetric = isMetric; - isMetric = params.getBool("IsMetric"); - - if (isMetric != previousIsMetric) { - double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE; - - params.putFloatNonBlocking("SetSpeedOffset", params.getFloat("SetSpeedOffset") * speedConversion); - } - - FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast(toggles["SetSpeedOffset"]); - - if (isMetric) { - setSpeedOffsetToggle->updateControl(0, 150, tr("kph")); - } else { - setSpeedOffsetToggle->updateControl(0, 99, tr("mph")); - } -} - -void FrogPilotAdvancedDrivingPanel::showEvent(QShowEvent *event) { - modelManagement = params.getBool("ModelManagement"); - modelRandomizer = params.getBool("ModelRandomizer"); -} - -void FrogPilotAdvancedDrivingPanel::updateCarToggles() { - disableOpenpilotLongitudinal = parent->disableOpenpilotLongitudinal; - hasAutoTune = parent->hasAutoTune; - hasNNFFLog = parent->hasNNFFLog; - hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; - hasPCMCruise = parent->hasPCMCruise; - isPIDCar = parent->isPIDCar; - liveValid = parent->liveValid; - steerFrictionStock = parent->steerFrictionStock; - steerKPStock = parent->steerKPStock; - steerLatAccelStock = parent->steerLatAccelStock; - steerRatioStock = parent->steerRatioStock; - - steerFrictionToggle->setTitle(QString(tr("Friction (Default: %1)")).arg(QString::number(steerFrictionStock, 'f', 2))); - steerKPToggle->setTitle(QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKPStock, 'f', 2))); - steerKPToggle->updateControl(steerKPStock * 0.50, steerKPStock * 1.50); - steerLatAccelToggle->setTitle(QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(steerLatAccelStock, 'f', 2))); - steerLatAccelToggle->updateControl(steerLatAccelStock * 0.75, steerLatAccelStock * 1.25); - steerRatioToggle->setTitle(QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatioStock, 'f', 2))); - steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25); - - hideToggles(); -} - -void FrogPilotAdvancedDrivingPanel::updateState(const UIState &s) { - if (!isVisible()) return; - - if (modelManagementOpen) { - downloadAllModelsBtn->setText(modelDownloading && allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD")); - downloadModelBtn->setText(modelDownloading && !allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD")); - - deleteModelBtn->setEnabled(!modelDeleting && !modelDownloading); - downloadAllModelsBtn->setEnabled(s.scene.online && !cancellingDownload && !modelDeleting && (!modelDownloading || allModelsDownloading) && !modelsDownloaded); - downloadModelBtn->setEnabled(s.scene.online && !cancellingDownload && !modelDeleting && !allModelsDownloading && !modelsDownloaded); - selectModelBtn->setEnabled(!modelDeleting && !modelDownloading && !modelRandomizer); - } - - started = s.scene.started; -} - -void FrogPilotAdvancedDrivingPanel::startDownloadAllModels() { - allModelsDownloading = true; - modelDownloading = true; - - paramsMemory.putBool("DownloadAllModels", true); - - downloadAllModelsBtn->setValue(tr("Downloading models...")); - - QTimer *progressTimer = new QTimer(this); - progressTimer->setInterval(100); - - QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { - QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); - bool downloadComplete = progress.contains(QRegularExpression("All models downloaded!", QRegularExpression::CaseInsensitiveOption)); - bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); - - if (!progress.isEmpty() && progress != "0%") { - downloadAllModelsBtn->setValue(progress); - } - - if (downloadComplete || downloadFailed) { - if (downloadComplete) { - haveModelsDownloaded = true; - update(); - } - - downloadAllModelsBtn->setValue(progress); - - paramsMemory.remove("CancelModelDownload"); - paramsMemory.remove("ModelDownloadProgress"); - - progressTimer->stop(); - progressTimer->deleteLater(); - - QTimer::singleShot(2000, this, [=]() { - cancellingDownload = false; - modelDownloading = false; - - paramsMemory.remove("DownloadAllModels"); - - downloadAllModelsBtn->setValue(""); - - device()->resetInteractiveTimeout(30); - }); - } - }); - progressTimer->start(); -} - -void FrogPilotAdvancedDrivingPanel::updateCalibrationDescription() { - QString model = QString::fromStdString(params.get("ModelName")); - QString part_model_param = processModelName(model); - - QString desc = - tr("openpilot requires the device to be mounted within 4° left or right and " - "within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required."); - std::string calib_bytes = params.get(part_model_param.toStdString() + "CalibrationParams"); - if (!calib_bytes.empty()) { - try { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(calib_bytes.data(), calib_bytes.size())); - auto calib = cmsg.getRoot().getLiveCalibration(); - if (calib.getCalStatus() != cereal::LiveCalibrationData::Status::UNCALIBRATED) { - double pitch = calib.getRpyCalib()[1] * (180 / M_PI); - double yaw = calib.getRpyCalib()[2] * (180 / M_PI); - desc += tr(" Your device is pointed %1° %2 and %3° %4.") - .arg(QString::number(std::abs(pitch), 'g', 1), pitch > 0 ? tr("down") : tr("up"), - QString::number(std::abs(yaw), 'g', 1), yaw > 0 ? tr("left") : tr("right")); - } - } catch (kj::Exception) { - qInfo() << "invalid CalibrationParams"; - } - } - qobject_cast(sender())->setDescription(desc); -} - -void FrogPilotAdvancedDrivingPanel::updateModelLabels() { - QVector> modelScores; - for (QString &model : availableModelNames) { - QString cleanedModel = processModelName(model); - int score = params.getInt((cleanedModel + "Score").toStdString()); - - if (model.contains("(Default)")) { - modelScores.prepend(qMakePair(model, score)); - } else { - modelScores.append(qMakePair(model, score)); - } - } - - labelControls.clear(); - - for (QPair &pair : modelScores) { - QString scoreDisplay = pair.second == 0 ? "N/A" : QString::number(pair.second) + "%"; - LabelControl *labelControl = new LabelControl(pair.first, scoreDisplay, ""); - labelControls.append(labelControl); - addItem(labelControl); - } - - for (LabelControl *label : labelControls) { - label->setVisible(false); - } -} - -void FrogPilotAdvancedDrivingPanel::showToggles(const std::set &keys) { - setUpdatesEnabled(false); - - for (auto &[key, toggle] : toggles) { - toggle->setVisible(keys.find(key) != keys.end()); - } - - setUpdatesEnabled(true); - update(); -} - -void FrogPilotAdvancedDrivingPanel::hideToggles() { - setUpdatesEnabled(false); - - customPersonalityOpen = false; - modelManagementOpen = false; - - for (LabelControl *label : labelControls) { - label->setVisible(false); - } - - std::set longitudinalKeys = {"AdvancedLongitudinalTune", "CustomPersonalities"}; - for (auto &[key, toggle] : toggles) { - bool subToggles = aggressivePersonalityKeys.find(key) != aggressivePersonalityKeys.end() || - customDrivingPersonalityKeys.find(key) != customDrivingPersonalityKeys.end() || - lateralTuneKeys.find(key) != lateralTuneKeys.end() || - longitudinalTuneKeys.find(key) != longitudinalTuneKeys.end() || - modelManagementKeys.find(key) != modelManagementKeys.end() || - modelRandomizerKeys.find(key) != modelRandomizerKeys.end() || - qolKeys.find(key) != qolKeys.end() || - relaxedPersonalityKeys.find(key) != relaxedPersonalityKeys.end() || - standardPersonalityKeys.find(key) != standardPersonalityKeys.end() || - trafficPersonalityKeys.find(key) != trafficPersonalityKeys.end(); - - if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { - if (longitudinalKeys.find(key) != longitudinalKeys.end()) { - toggle->setVisible(false); - continue; - } - } - - toggle->setVisible(!subToggles); - } - - setUpdatesEnabled(true); - update(); -} - -void FrogPilotAdvancedDrivingPanel::hideSubToggles() { - if (customPersonalityOpen) { - customPersonalityOpen = false; - showToggles(customDrivingPersonalityKeys); - } else if (modelManagementOpen) { - for (LabelControl *label : labelControls) { - label->setVisible(false); - } - showToggles(modelManagementKeys); - } -} - -void FrogPilotAdvancedDrivingPanel::hideSubSubToggles() { - if (modelManagementOpen) { - for (LabelControl *label : labelControls) { - label->setVisible(false); - } - showToggles(modelRandomizerKeys); - } -} diff --git a/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.h b/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.h deleted file mode 100644 index 2e89c0a9..00000000 --- a/selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h" - -class FrogPilotAdvancedDrivingPanel : public FrogPilotListWidget { - Q_OBJECT - -public: - explicit FrogPilotAdvancedDrivingPanel(FrogPilotSettingsWindow *parent); - -signals: - void openParentToggle(); - void openSubParentToggle(); - void openSubSubParentToggle(); - -protected: - void showEvent(QShowEvent *event) override; - -private: - void hideSubToggles(); - void hideSubSubToggles(); - void hideToggles(); - void showToggles(const std::set &keys); - - void startDownloadAllModels(); - void updateCalibrationDescription(); - void updateCarToggles(); - void updateMetric(); - void updateModelLabels(); - void updateState(const UIState &s); - - std::set aggressivePersonalityKeys = { - "AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", - "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", - "ResetAggressivePersonality" - }; - - std::set customDrivingPersonalityKeys = { - "AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", - "TrafficPersonalityProfile" - }; - - std::set lateralTuneKeys = { - "ForceAutoTune", "ForceAutoTuneOff", "SteerFriction", - "SteerLatAccel", "SteerKP", "SteerRatio", "TacoTune", - "TurnDesires" - }; - - std::set longitudinalTuneKeys = { - "LeadDetectionThreshold", "MaxDesiredAcceleration" - }; - - std::set modelManagementKeys = { - "AutomaticallyUpdateModels", "DeleteModel", "DownloadModel", - "DownloadAllModels", "ModelRandomizer", "ResetCalibrations", - "SelectModel" - }; - - std::set modelRandomizerKeys = { - "ManageBlacklistedModels", "ResetScores", "ReviewScores" - }; - - std::set qolKeys = { - "ForceStandstill", "ForceStops", "SetSpeedOffset" - }; - - std::set relaxedPersonalityKeys = { - "RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", - "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", - "ResetRelaxedPersonality" - }; - - std::set standardPersonalityKeys = { - "StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", - "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", - "ResetStandardPersonality" - }; - - std::set trafficPersonalityKeys = { - "TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", - "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", - "ResetTrafficPersonality" - }; - - ButtonControl *deleteModelBtn; - ButtonControl *downloadAllModelsBtn; - ButtonControl *downloadModelBtn; - ButtonControl *selectModelBtn; - - FrogPilotParamValueButtonControl *steerFrictionToggle; - FrogPilotParamValueButtonControl *steerLatAccelToggle; - FrogPilotParamValueButtonControl *steerKPToggle; - FrogPilotParamValueButtonControl *steerRatioToggle; - - FrogPilotSettingsWindow *parent; - - Params params; - Params paramsMemory{"/dev/shm/params"}; - Params paramsStorage{"/persist/params"}; - - QDir modelDir{"/data/models/"}; - - QList labelControls; - - QStringList availableModelNames; - QStringList availableModels; - QStringList experimentalModels; - - bool allModelsDownloading; - bool cancellingDownload; - bool customPersonalityOpen; - bool disableOpenpilotLongitudinal; - bool hasAutoTune; - bool hasNNFFLog; - bool hasOpenpilotLongitudinal; - bool hasPCMCruise; - bool haveModelsDownloaded; - bool isMetric = params.getBool("IsMetric"); - bool isPIDCar; - bool liveValid; - bool modelDeleting; - bool modelDownloading; - bool modelManagement; - bool modelManagementOpen; - bool modelRandomizer; - bool modelsDownloaded; - bool started; - - float steerFrictionStock; - float steerLatAccelStock; - float steerKPStock; - float steerRatioStock; - - std::map toggles; -}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.cc deleted file mode 100644 index c66d0c6e..00000000 --- a/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.cc +++ /dev/null @@ -1,226 +0,0 @@ -#include "selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.h" - -FrogPilotAdvancedVisualsPanel::FrogPilotAdvancedVisualsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { - const std::vector> advancedToggles { - {"AdvancedCustomUI", tr("Advanced Onroad UI Widgets"), tr("Advanced user customizations for the Onroad UI."), "../frogpilot/assets/toggle_icons/icon_advanced_road.png"}, - {"CameraView", tr("Camera View"), tr("Camera view for the onroad UI. This is purely a visual change and doesn't impact how openpilot drives."), ""}, - {"ShowStoppingPoint", tr("Display Stopping Points"), tr("Display an image on the screen where openpilot is detecting a potential red light/stop sign."), ""}, - {"HideLeadMarker", tr("Hide Lead Marker"), tr("Hide the marker for the vehicle ahead on the screen."), ""}, - {"HideSpeed", tr("Hide Speed"), tr("Hide the speed indicator in the onroad UI. Additional toggle allows it to be hidden/shown via tapping the speed itself."), ""}, - {"HideUIElements", tr("Hide UI Elements"), tr("Hide the selected UI elements from the onroad screen."), ""}, - {"WheelSpeed", tr("Use Wheel Speed"), tr("Use the wheel speed instead of the cluster speed in the onroad UI."), ""}, - - {"DeveloperUI", tr("Developer UI"), tr("Show detailed information about openpilot's internal operations."), "../frogpilot/assets/toggle_icons/icon_advanced_device.png"}, - {"BorderMetrics", tr("Border Metrics"), tr("Display performance metrics around the edge of the screen while driving."), ""}, - {"FPSCounter", tr("FPS Display"), tr("Display the 'Frames Per Second' (FPS) at the bottom of the screen while driving."), ""}, - {"LateralMetrics", tr("Lateral Metrics"), tr("Display metrics related to steering control at the top of the screen while driving."), ""}, - {"LongitudinalMetrics", tr("Longitudinal Metrics"), tr("Display metrics related to acceleration, speed, and desired following distance at the top of the screen while driving."), ""}, - {"NumericalTemp", tr("Numerical Temperature Gauge"), tr("Show exact temperature readings instead of general status labels like 'GOOD', 'OK', or 'HIGH' in the sidebar."), ""}, - {"SidebarMetrics", tr("Sidebar"), tr("Display system information like CPU, GPU, RAM usage, IP address, and storage space in the sidebar."), ""}, - {"UseSI", tr("Use International System of Units"), tr("Display measurements using the 'International System of Units' (SI)."), ""}, - - {"ModelUI", tr("Model UI"), tr("Customize the model visualizations on the screen."), "../frogpilot/assets/toggle_icons/icon_advanced_calibration.png"}, - {"LaneLinesWidth", tr("Lane Lines Width"), tr("How thick the lane lines appear on the display.\n\nDefault matches the MUTCD standard of 4 inches."), ""}, - {"PathEdgeWidth", tr("Path Edges Width"), tr("The width of the edges of the driving path to represent different modes and statuses.\n\nDefault is 20% of the total path width.\n\nColor Guide:\n- Blue: Navigation\n- Light Blue: 'Always On Lateral'\n- Green: Default\n- Orange: 'Experimental Mode'\n- Red: 'Traffic Mode'\n- Yellow: 'Conditional Experimental Mode' Overridden"), ""}, - {"PathWidth", tr("Path Width"), tr("How wide the driving path appears on your screen.\n\nDefault (6.1 feet / 1.9 meters) matches the width of a 2019 Lexus ES 350."), ""}, - {"RoadEdgesWidth", tr("Road Edges Width"), tr("How thick the road edges appear on the display.\n\nDefault matches half of the MUTCD standard lane line width of 4 inches."), ""}, - {"UnlimitedLength", tr("'Unlimited' Road UI"), tr("Extend the display of the path, lane lines, and road edges as far as the model can see."), ""}, - }; - - for (const auto &[param, title, desc, icon] : advancedToggles) { - AbstractControl *advancedVisualToggle; - - if (param == "AdvancedCustomUI") { - FrogPilotParamManageControl *advancedCustomUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(advancedCustomUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(advancedCustomOnroadUIKeys); - }); - advancedVisualToggle = advancedCustomUIToggle; - } else if (param == "CameraView") { - std::vector cameraOptions{tr("Auto"), tr("Driver"), tr("Standard"), tr("Wide")}; - ButtonParamControl *preferredCamera = new ButtonParamControl(param, title, desc, icon, cameraOptions); - advancedVisualToggle = preferredCamera; - } else if (param == "HideSpeed") { - std::vector hideSpeedToggles{"HideSpeedUI"}; - std::vector hideSpeedToggleNames{tr("Control Via UI")}; - advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, hideSpeedToggles, hideSpeedToggleNames); - } else if (param == "HideUIElements") { - std::vector uiElementsToggles{"HideAlerts", "HideMapIcon", "HideMaxSpeed"}; - std::vector uiElementsToggleNames{tr("Alerts"), tr("Map Icon"), tr("Max Speed")}; - advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, uiElementsToggles, uiElementsToggleNames); - } else if (param == "ShowStoppingPoint") { - std::vector stoppingPointToggles{"ShowStoppingPointMetrics"}; - std::vector stoppingPointToggleNames{tr("Show Distance")}; - advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, stoppingPointToggles, stoppingPointToggleNames); - - } else if (param == "DeveloperUI") { - FrogPilotParamManageControl *developerUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(developerUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - borderMetricsBtn->setVisibleButton(0, hasBSM); - lateralMetricsBtn->setVisibleButton(1, hasAutoTune); - - std::set modifiedDeveloperUIKeys = developerUIKeys; - - if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { - modifiedDeveloperUIKeys.erase("LongitudinalMetrics"); - } - - showToggles(modifiedDeveloperUIKeys); - }); - advancedVisualToggle = developerUIToggle; - } else if (param == "BorderMetrics") { - std::vector borderToggles{"BlindSpotMetrics", "ShowSteering", "SignalMetrics"}; - std::vector borderToggleNames{tr("Blind Spot"), tr("Steering Torque"), tr("Turn Signal")}; - borderMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, borderToggles, borderToggleNames); - advancedVisualToggle = borderMetricsBtn; - } else if (param == "LateralMetrics") { - std::vector lateralToggles{"AdjacentPathMetrics", "TuningInfo"}; - std::vector lateralToggleNames{tr("Adjacent Path Metrics"), tr("Auto Tune")}; - lateralMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, lateralToggles, lateralToggleNames); - advancedVisualToggle = lateralMetricsBtn; - } else if (param == "LongitudinalMetrics") { - std::vector longitudinalToggles{"LeadInfo", "JerkInfo"}; - std::vector longitudinalToggleNames{tr("Lead Info"), tr("Jerk Values")}; - longitudinalMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, longitudinalToggles, longitudinalToggleNames); - advancedVisualToggle = longitudinalMetricsBtn; - } else if (param == "NumericalTemp") { - std::vector temperatureToggles{"Fahrenheit"}; - std::vector temperatureToggleNames{tr("Fahrenheit")}; - advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, temperatureToggles, temperatureToggleNames); - } else if (param == "SidebarMetrics") { - std::vector sidebarMetricsToggles{"ShowCPU", "ShowGPU", "ShowIP", "ShowMemoryUsage", "ShowStorageLeft", "ShowStorageUsed"}; - std::vector sidebarMetricsToggleNames{tr("CPU"), tr("GPU"), tr("IP"), tr("RAM"), tr("SSD Left"), tr("SSD Used")}; - FrogPilotButtonToggleControl *sidebarMetricsToggle = new FrogPilotButtonToggleControl(param, title, desc, sidebarMetricsToggles, sidebarMetricsToggleNames, false, 150); - QObject::connect(sidebarMetricsToggle, &FrogPilotButtonToggleControl::buttonClicked, [this](int index) { - if (index == 0) { - params.putBool("ShowGPU", false); - } else if (index == 1) { - params.putBool("ShowCPU", false); - } else if (index == 3) { - params.putBool("ShowStorageLeft", false); - params.putBool("ShowStorageUsed", false); - } else if (index == 4) { - params.putBool("ShowMemoryUsage", false); - params.putBool("ShowStorageUsed", false); - } else if (index == 5) { - params.putBool("ShowMemoryUsage", false); - params.putBool("ShowStorageLeft", false); - } - }); - advancedVisualToggle = sidebarMetricsToggle; - - } else if (param == "ModelUI") { - FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - std::set modifiedModelUIKeysKeys = modelUIKeys; - - if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { - modifiedModelUIKeysKeys.erase("HideLeadMarker"); - } - - showToggles(modifiedModelUIKeysKeys); - }); - advancedVisualToggle = modelUIToggle; - } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { - advancedVisualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, tr(" inches")); - } else if (param == "PathEdgeWidth") { - advancedVisualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, tr("%")); - } else if (param == "PathWidth") { - advancedVisualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet"), std::map(), 0.1); - - } else { - advancedVisualToggle = new ParamControl(param, title, desc, icon); - } - - addItem(advancedVisualToggle); - toggles[param] = advancedVisualToggle; - - makeConnections(advancedVisualToggle); - - if (FrogPilotParamManageControl *frogPilotManageToggle = qobject_cast(advancedVisualToggle)) { - QObject::connect(frogPilotManageToggle, &FrogPilotParamManageControl::manageButtonClicked, this, &FrogPilotAdvancedVisualsPanel::openParentToggle); - } - - QObject::connect(advancedVisualToggle, &AbstractControl::showDescriptionEvent, [this]() { - update(); - }); - } - - QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotAdvancedVisualsPanel::hideToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotAdvancedVisualsPanel::updateCarToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotAdvancedVisualsPanel::updateMetric); - - updateMetric(); -} - -void FrogPilotAdvancedVisualsPanel::updateCarToggles() { - disableOpenpilotLongitudinal = parent->disableOpenpilotLongitudinal; - hasAutoTune = parent->hasAutoTune; - hasBSM = parent->hasBSM; - hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; - - hideToggles(); -} - -void FrogPilotAdvancedVisualsPanel::updateMetric() { - bool previousIsMetric = isMetric; - isMetric = params.getBool("IsMetric"); - - if (isMetric != previousIsMetric) { - double smallDistanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; - double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; - - params.putFloatNonBlocking("LaneLinesWidth", params.getFloat("LaneLinesWidth") * smallDistanceConversion); - params.putFloatNonBlocking("RoadEdgesWidth", params.getFloat("RoadEdgesWidth") * smallDistanceConversion); - - params.putFloatNonBlocking("PathWidth", params.getFloat("PathWidth") * distanceConversion); - } - - FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); - FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); - FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); - - if (isMetric) { - laneLinesWidthToggle->setDescription(tr("Adjust how thick the lane lines appear on the display.\n\nDefault matches the Vienna standard of 10 centimeters.")); - roadEdgesWidthToggle->setDescription(tr("Adjust how thick the road edges appear on the display.\n\nDefault matches half of the Vienna standard of 10 centimeters.")); - - laneLinesWidthToggle->updateControl(0, 60, tr(" centimeters")); - roadEdgesWidthToggle->updateControl(0, 60, tr(" centimeters")); - - pathWidthToggle->updateControl(0, 3, tr(" meters")); - } else { - laneLinesWidthToggle->setDescription(tr("Adjust how thick the lane lines appear on the display.\n\nDefault matches the MUTCD standard of 4 inches.")); - roadEdgesWidthToggle->setDescription(tr("Adjust how thick the road edges appear on the display.\n\nDefault matches half of the MUTCD standard of 4 inches.")); - - laneLinesWidthToggle->updateControl(0, 24, tr(" inches")); - roadEdgesWidthToggle->updateControl(0, 24, tr(" inches")); - - pathWidthToggle->updateControl(0, 10, tr(" feet")); - } -} - -void FrogPilotAdvancedVisualsPanel::showToggles(const std::set &keys) { - setUpdatesEnabled(false); - - for (auto &[key, toggle] : toggles) { - toggle->setVisible(keys.find(key) != keys.end()); - } - - setUpdatesEnabled(true); - update(); -} - -void FrogPilotAdvancedVisualsPanel::hideToggles() { - setUpdatesEnabled(false); - - for (auto &[key, toggle] : toggles) { - bool subToggles = advancedCustomOnroadUIKeys.find(key) != advancedCustomOnroadUIKeys.end() || - developerUIKeys.find(key) != developerUIKeys.end() || - modelUIKeys.find(key) != modelUIKeys.end(); - - toggle->setVisible(!subToggles); - } - - setUpdatesEnabled(true); - update(); -} diff --git a/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.h b/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.h deleted file mode 100644 index 20ad9901..00000000 --- a/selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -#include "selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h" - -class FrogPilotAdvancedVisualsPanel : public FrogPilotListWidget { - Q_OBJECT - -public: - explicit FrogPilotAdvancedVisualsPanel(FrogPilotSettingsWindow *parent); - -signals: - void openParentToggle(); - -private: - void hideToggles(); - void showToggles(const std::set &keys); - void updateCarToggles(); - void updateMetric(); - - std::set advancedCustomOnroadUIKeys = { - "CameraView", "HideLeadMarker", "HideSpeed", - "HideUIElements", "ShowStoppingPoint", "WheelSpeed" - }; - - std::set developerUIKeys = { - "BorderMetrics", "FPSCounter", "LateralMetrics", - "LongitudinalMetrics", "NumericalTemp", - "SidebarMetrics", "UseSI" - }; - - std::set modelUIKeys = { - "LaneLinesWidth", "PathEdgeWidth", "PathWidth", - "RoadEdgesWidth", "UnlimitedLength" - }; - - FrogPilotButtonToggleControl *borderMetricsBtn; - FrogPilotButtonToggleControl *lateralMetricsBtn; - FrogPilotButtonToggleControl *longitudinalMetricsBtn; - - FrogPilotSettingsWindow *parent; - - Params params; - - bool disableOpenpilotLongitudinal; - bool hasAutoTune; - bool hasBSM; - bool hasOpenpilotLongitudinal; - bool isMetric = params.getBool("IsMetric"); - - std::map toggles; -}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/data_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/data_settings.cc index 930e82c9..dbc1d42f 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/data_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/data_settings.cc @@ -3,7 +3,7 @@ #include "selfdrive/frogpilot/ui/qt/offroad/data_settings.h" FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) { - ButtonControl *deleteDrivingDataBtn = new ButtonControl(tr("Delete Driving Footage and Data"), tr("DELETE"), tr("This button provides a swift and secure way to permanently delete all stored driving footage and data from your device. Ideal for maintaining privacy or freeing up space.")); + ButtonControl *deleteDrivingDataBtn = new ButtonControl(tr("Delete Driving Footage and Data"), tr("DELETE"), tr("Permanently deletes all stored driving footage and data from your device. Ideal for maintaining privacy or freeing up space.")); QObject::connect(deleteDrivingDataBtn, &ButtonControl::clicked, [=]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to permanently delete all of your driving footage and data?"), tr("Delete"), this)) { std::thread([=] { diff --git a/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc index f74da2bf..40e0ac12 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc @@ -1,21 +1,21 @@ #include "selfdrive/frogpilot/ui/qt/offroad/device_settings.h" -FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) { +FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { const std::vector> deviceToggles { {"DeviceManagement", tr("Device Settings"), tr("Device behavior settings."), "../frogpilot/assets/toggle_icons/icon_device.png"}, - {"DeviceShutdown", tr("Device Shutdown Timer"), tr("How long the device stays on after you stop driving."), ""}, - {"OfflineMode", tr("Disable Internet Requirement"), tr("The device can work without an internet connection for as long as you need."), ""}, - {"IncreaseThermalLimits", tr("Increase Thermal Safety Limit"), tr("The device can run at higher temperatures than recommended."), ""}, - {"LowVoltageShutdown", tr("Low Battery Shutdown Threshold"), tr("Shut down the device when the car's battery gets too low to prevent damage to the 12V battery."), ""}, - {"NoLogging", tr("Turn Off Data Tracking"), tr("Disable all tracking to improve privacy."), ""}, - {"NoUploads", tr("Turn Off Data Uploads"), tr("Stop the device from sending any data to the servers."), ""}, + {"DeviceShutdown", tr("Device Shutdown Timer"), tr("Controls how long the device stays on after you stop driving."), ""}, + {"OfflineMode", tr("Disable Internet Requirement"), tr("Allows the device to work without an internet connection."), ""}, + {"IncreaseThermalLimits", tr("Increase Thermal Safety Limit"), tr("Allows the device to run at higher temperatures than recommended."), ""}, + {"LowVoltageShutdown", tr("Low Battery Shutdown Threshold"), tr("Manages the threshold for shutting down the device to protect the car's battery from excessive drain and potential damage."), ""}, + {"NoLogging", tr("Turn Off Data Tracking"), tr("Disables all data tracking to improve privacy."), ""}, + {"NoUploads", tr("Turn Off Data Uploads"), tr("Stops the device from sending any data to the servers."), ""}, {"ScreenManagement", tr("Screen Settings"), tr("Screen behavior settings."), "../frogpilot/assets/toggle_icons/icon_light.png"}, - {"ScreenBrightness", tr("Screen Brightness (Offroad)"), tr("The screen brightness when you're not driving."), ""}, - {"ScreenBrightnessOnroad", tr("Screen Brightness (Onroad)"), tr("The screen brightness while you're driving."), ""}, - {"ScreenRecorder", tr("Screen Recorder"), tr("Display a button in the onroad UI to record the screen."), ""}, - {"ScreenTimeout", tr("Screen Timeout (Offroad)"), tr("How long it takes for the screen to turn off when you're not driving."), ""}, - {"ScreenTimeoutOnroad", tr("Screen Timeout (Onroad)"), tr("How long it takes for the screen to turn off while you're driving."), ""} + {"ScreenBrightness", tr("Screen Brightness (Offroad)"), tr("Controls the screen brightness when you're not driving."), ""}, + {"ScreenBrightnessOnroad", tr("Screen Brightness (Onroad)"), tr("Controls the screen brightness while you're driving."), ""}, + {"ScreenRecorder", tr("Screen Recorder"), tr("Enables a button in the onroad UI to record the screen."), ""}, + {"ScreenTimeout", tr("Screen Timeout (Offroad)"), tr("Controls how long it takes for the screen to turn off when you're not driving."), ""}, + {"ScreenTimeoutOnroad", tr("Screen Timeout (Onroad)"), tr("Controls how long it takes for the screen to turn off while you're driving."), ""} }; for (const auto &[param, title, desc, icon] : deviceToggles) { @@ -24,7 +24,17 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr if (param == "DeviceManagement") { FrogPilotParamManageControl *deviceManagementToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(deviceManagementToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(deviceManagementKeys); + std::set modifiedDeviceManagementKeys = deviceManagementKeys; + + if (customizationLevel != 2) { + modifiedDeviceManagementKeys.erase("IncreaseThermalLimits"); + modifiedDeviceManagementKeys.erase("LowVoltageShutdown"); + modifiedDeviceManagementKeys.erase("NoLogging"); + modifiedDeviceManagementKeys.erase("NoUploads"); + modifiedDeviceManagementKeys.erase("OfflineMode"); + } + + showToggles(modifiedDeviceManagementKeys); }); deviceToggle = deviceManagementToggle; } else if (param == "DeviceShutdown") { @@ -43,14 +53,16 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr } else if (param == "ScreenManagement") { FrogPilotParamManageControl *screenToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(screenToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(screenKeys); + std::set modifiedScreenKeys = screenKeys; + + showToggles(modifiedScreenKeys); }); deviceToggle = screenToggle; } else if (param == "ScreenBrightness" || param == "ScreenBrightnessOnroad") { std::map brightnessLabels; int minBrightness = (param == "ScreenBrightnessOnroad") ? 0 : 1; - for (int i = 1; i <= 101; ++i) { - brightnessLabels[i] = (i == 101) ? tr("Auto") : QString::number(i) + "%"; + for (int i = 0; i <= 101; ++i) { + brightnessLabels[i] = i == 101 ? tr("Auto") : i == 0 ? tr("Screen Off") : QString::number(i) + "%"; } deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, minBrightness, 101, QString(), brightnessLabels, 1, false, true); } else if (param == "ScreenTimeout" || param == "ScreenTimeoutOnroad") { @@ -118,6 +130,12 @@ FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent) : Fr hideToggles(); } +void FrogPilotDevicePanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + toggles["ScreenManagement"]->setVisible(customizationLevel == 2); +} + void FrogPilotDevicePanel::updateState(const UIState &s) { started = s.scene.started; } @@ -142,6 +160,8 @@ void FrogPilotDevicePanel::hideToggles() { toggle->setVisible(!subToggles); } + toggles["ScreenManagement"]->setVisible(customizationLevel == 2); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/device_settings.h b/selfdrive/frogpilot/ui/qt/offroad/device_settings.h index d8d552b3..64133520 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/device_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/device_settings.h @@ -15,6 +15,7 @@ signals: private: void hideToggles(); + void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); void updateState(const UIState &s); @@ -28,9 +29,13 @@ private: "ScreenTimeout", "ScreenTimeoutOnroad" }; + FrogPilotSettingsWindow *parent; + Params params; bool started; + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc index 213a763c..7577aff6 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc @@ -5,13 +5,12 @@ #include "selfdrive/frogpilot/navigation/ui/maps_settings.h" #include "selfdrive/frogpilot/navigation/ui/primeless_settings.h" -#include "selfdrive/frogpilot/ui/qt/offroad/advanced_driving_settings.h" -#include "selfdrive/frogpilot/ui/qt/offroad/advanced_visual_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/data_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/device_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h" +#include "selfdrive/frogpilot/ui/qt/offroad/model_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/sounds_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/theme_settings.h" #include "selfdrive/frogpilot/ui/qt/offroad/utilities.h" @@ -45,13 +44,15 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram FrogPilotListWidget *list = new FrogPilotListWidget(frogpilotSettingsWidget); - FrogPilotAdvancedDrivingPanel *frogpilotAdvancedDrivingPanel = new FrogPilotAdvancedDrivingPanel(this); - QObject::connect(frogpilotAdvancedDrivingPanel, &FrogPilotAdvancedDrivingPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); - QObject::connect(frogpilotAdvancedDrivingPanel, &FrogPilotAdvancedDrivingPanel::openSubParentToggle, this, &FrogPilotSettingsWindow::openSubParentToggle); - QObject::connect(frogpilotAdvancedDrivingPanel, &FrogPilotAdvancedDrivingPanel::openSubSubParentToggle, this, &FrogPilotSettingsWindow::openSubSubParentToggle); - - FrogPilotAdvancedVisualsPanel *frogpilotAdvancedVisualsPanel = new FrogPilotAdvancedVisualsPanel(this); - QObject::connect(frogpilotAdvancedVisualsPanel, &FrogPilotAdvancedVisualsPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); + std::vector toggle_presets{tr("Basic"), tr("Standard"), tr("Advanced")}; + ButtonParamControl *toggle_preset = new ButtonParamControl("CustomizationLevel", tr("Customization Level"), + tr("Choose your preferred customization level. 'Standard' is recommended for most users, offering a balanced experience and automatically managing more 'Advanced' features," + " while 'Basic' is designed for those new to customization or seeking simplicity."), + "../frogpilot/assets/toggle_icons/icon_customization.png", + toggle_presets); + QObject::connect(toggle_preset, &ButtonParamControl::buttonClicked, this, &FrogPilotSettingsWindow::updatePanelVisibility); + QObject::connect(toggle_preset, &ButtonParamControl::buttonClicked, this, &updateFrogPilotToggles); + list->addItem(toggle_preset); FrogPilotDevicePanel *frogpilotDevicePanel = new FrogPilotDevicePanel(this); QObject::connect(frogpilotDevicePanel, &FrogPilotDevicePanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); @@ -63,10 +64,15 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubParentToggle, this, &FrogPilotSettingsWindow::openSubParentToggle); + FrogPilotModelPanel *frogpilotModelPanel = new FrogPilotModelPanel(this); + QObject::connect(frogpilotModelPanel, &FrogPilotModelPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); + QObject::connect(frogpilotModelPanel, &FrogPilotModelPanel::openSubParentToggle, this, &FrogPilotSettingsWindow::openSubParentToggle); + FrogPilotMapsPanel *frogpilotMapsPanel = new FrogPilotMapsPanel(this); QObject::connect(frogpilotMapsPanel, &FrogPilotMapsPanel::openMapSelection, this, &FrogPilotSettingsWindow::openMapSelection); FrogPilotPrimelessPanel *frogpilotPrimelessPanel = new FrogPilotPrimelessPanel(this); + QObject::connect(frogpilotPrimelessPanel, &FrogPilotPrimelessPanel::closeMapBoxInstructions, this, &FrogPilotSettingsWindow::closeMapBoxInstructions); QObject::connect(frogpilotPrimelessPanel, &FrogPilotPrimelessPanel::openMapBoxInstructions, this, &FrogPilotSettingsWindow::openMapBoxInstructions); FrogPilotSoundsPanel *frogpilotSoundsPanel = new FrogPilotSoundsPanel(this); @@ -79,9 +85,8 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram QObject::connect(frogpilotVisualsPanel, &FrogPilotVisualsPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); std::vector>> panels = { - {tr("Advanced Settings"), {frogpilotAdvancedDrivingPanel, frogpilotAdvancedVisualsPanel}}, {tr("Alerts and Sounds"), {frogpilotSoundsPanel}}, - {tr("Driving Controls"), {frogpilotLongitudinalPanel, frogpilotLateralPanel}}, + {tr("Driving Controls"), {frogpilotModelPanel, frogpilotLongitudinalPanel, frogpilotLateralPanel}}, {tr("Navigation"), {frogpilotMapsPanel, frogpilotPrimelessPanel}}, {tr("System Management"), {new FrogPilotDataPanel(this), frogpilotDevicePanel, new UtilitiesPanel(this)}}, {tr("Theme and Appearance"), {frogpilotVisualsPanel, frogpilotThemesPanel}}, @@ -89,7 +94,6 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram }; std::vector icons = { - "../frogpilot/assets/toggle_icons/icon_advanced.png", "../frogpilot/assets/toggle_icons/icon_sound.png", "../frogpilot/assets/toggle_icons/icon_steering.png", "../frogpilot/assets/toggle_icons/icon_map.png", @@ -99,7 +103,6 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram }; std::vector descriptions = { - tr("Advanced FrogPilot features for more experienced users."), tr("Options to customize FrogPilot's sound alerts and notifications."), tr("FrogPilot features that impact acceleration, braking, and steering."), tr("Offline maps downloader and 'Navigate On openpilot (NOO)' settings."), @@ -109,9 +112,8 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram }; std::vector> buttonLabels = { - {tr("DRIVING"), tr("VISUALS")}, {tr("MANAGE")}, - {tr("GAS / BRAKE"), tr("STEERING")}, + {tr("DRIVING MODEL"), tr("GAS / BRAKE"), tr("STEERING")}, {tr("OFFLINE MAPS"), tr("PRIMELESS NAVIGATION")}, {tr("DATA"), tr("DEVICE"), tr("UTILITIES")}, {tr("APPEARANCE"), tr("THEME")}, @@ -119,7 +121,7 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram }; for (size_t i = 0; i < panels.size(); ++i) { - addPanelControl(list, panels[i].first, descriptions[i], buttonLabels[i], icons[i], panels[i].second, panels[i].first == tr("Driving Controls"), panels[i].first == tr("Navigation")); + addPanelControl(list, panels[i].first, descriptions[i], buttonLabels[i], icons[i], panels[i].second, panels[i].first); } frogpilotSettingsLayout->addWidget(new ScrollView(list, frogpilotSettingsWidget)); @@ -133,11 +135,8 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram QObject::connect(parent, &SettingsWindow::closePanel, this, &FrogPilotSettingsWindow::closePanel); QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotSettingsWindow::closeParentToggle); QObject::connect(parent, &SettingsWindow::closeSubParentToggle, this, &FrogPilotSettingsWindow::closeSubParentToggle); - QObject::connect(parent, &SettingsWindow::closeSubSubParentToggle, this, &FrogPilotSettingsWindow::closeSubSubParentToggle); QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotSettingsWindow::updateMetric); QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotSettingsWindow::updateCarVariables); - - updateCarVariables(); } void FrogPilotSettingsWindow::showEvent(QShowEvent *event) { @@ -152,10 +151,18 @@ void FrogPilotSettingsWindow::closePanel() { } void FrogPilotSettingsWindow::updatePanelVisibility() { + customizationLevel = params.getInt("CustomizationLevel"); disableOpenpilotLongitudinal = params.getBool("DisableOpenpilotLongitudinal"); - drivingButton->setVisibleButton(0, hasOpenpilotLongitudinal && !disableOpenpilotLongitudinal); + if ((hasOpenpilotLongitudinal && !disableOpenpilotLongitudinal) || customizationLevel != 0) { + drivingButton->setVisibleButton(0, customizationLevel == 2); + drivingButton->setVisibleButton(1, hasOpenpilotLongitudinal && !disableOpenpilotLongitudinal); + drivingButton->setVisibleButton(2, customizationLevel != 0); + } else { + drivingButton->setVisible(false); + } navigationButton->setVisibleButton(1, !uiState()->hasPrime()); + systemButton->setVisibleButton(1, customizationLevel != 0); mainLayout->setCurrentWidget(frogpilotSettingsWidget); } @@ -183,7 +190,9 @@ void FrogPilotSettingsWindow::updateCarVariables() { hasNNFFLog = checkNNFFLogFileExists(carFingerprint); hasOpenpilotLongitudinal = hasLongitudinalControl(CP); hasPCMCruise = CP.getPcmCruise(); + hasRadar = !CP.getRadarUnavailable(); hasSNG = CP.getMinEnableSpeed() <= 0; + isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV"; isGM = carModel == "gm"; isGMPCMCruise = CP.getCarName() == "gm" && CP.getPcmCruise(); isHKGCanFd = carModel == "hyundai" && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD; @@ -236,17 +245,21 @@ void FrogPilotSettingsWindow::updateCarVariables() { hasNNFFLog = true; hasOpenpilotLongitudinal = true; hasPCMCruise = true; + hasRadar = true; hasSNG = false; + isGM = true; isGMPCMCruise = false; isHKGCanFd = true; isImpreza = true; - isSubaru = false; + isPIDCar = false; + isSubaru = true; isToyota = true; + isToyotaTuneSupported = true; isVolt = true; } std::string liveTorqueParamsKey; - if (params.getBool("ModelManagement")) { + if (customizationLevel == 2) { QString model = QString::fromStdString(params.get("ModelName")); QString part_model_param = processModelName(model); liveTorqueParamsKey = part_model_param.toStdString() + "LiveTorqueParameters"; @@ -255,13 +268,13 @@ void FrogPilotSettingsWindow::updateCarVariables() { } if (params.checkKey(liveTorqueParamsKey)) { - auto torqueParams = params.get(liveTorqueParamsKey); + std::string torqueParams = params.get(liveTorqueParamsKey); if (!torqueParams.empty()) { AlignedBuffer aligned_buf; capnp::FlatArrayMessageReader cmsg(aligned_buf.align(torqueParams.data(), torqueParams.size())); cereal::Event::Reader LTP = cmsg.getRoot(); - auto liveTorqueParams = LTP.getLiveTorqueParameters(); + cereal::LiveTorqueParametersData::Reader liveTorqueParams = LTP.getLiveTorqueParameters(); liveValid = liveTorqueParams.getLiveValid(); } else { @@ -274,7 +287,7 @@ void FrogPilotSettingsWindow::updateCarVariables() { emit updateCarToggles(); } -void FrogPilotSettingsWindow::addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector &button_labels, QString &icon, std::vector &panels, bool isDrivingPanel, bool isNavigationPanel) { +void FrogPilotSettingsWindow::addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector &button_labels, QString &icon, std::vector &panels, QString ¤tPanel) { std::vector panelContainers; panelContainers.reserve(panels.size()); @@ -287,12 +300,15 @@ void FrogPilotSettingsWindow::addPanelControl(FrogPilotListWidget *list, QString } FrogPilotButtonsControl *button; - if (isDrivingPanel) { + if (currentPanel == tr("Driving Controls")) { drivingButton = new FrogPilotButtonsControl(title, desc, button_labels, false, true, icon); button = drivingButton; - } else if (isNavigationPanel) { + } else if (currentPanel == tr("Navigation")) { navigationButton = new FrogPilotButtonsControl(title, desc, button_labels, false, true, icon); button = navigationButton; + } else if (currentPanel == tr("System Management")) { + systemButton = new FrogPilotButtonsControl(title, desc, button_labels, false, true, icon); + button = systemButton; } else { button = new FrogPilotButtonsControl(title, desc, button_labels, false, true, icon); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h index be87b154..90e384ee 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h @@ -16,7 +16,9 @@ public: bool hasNNFFLog; bool hasOpenpilotLongitudinal; bool hasPCMCruise; + bool hasRadar; bool hasSNG; + bool isBolt; bool isGM; bool isGMPCMCruise; bool isHKGCanFd; @@ -34,23 +36,23 @@ public: float steerLatAccelStock; float steerRatioStock; + int customizationLevel; + signals: void closeMapBoxInstructions(); void closeMapSelection(); void closeParentToggle(); void closeSubParentToggle(); - void closeSubSubParentToggle(); void openMapBoxInstructions(); void openMapSelection(); void openPanel(); void openParentToggle(); void openSubParentToggle(); - void openSubSubParentToggle(); void updateCarToggles(); void updateMetric(); private: - void addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector &button_labels, QString &icon, std::vector &panels, bool isDrivingPanel, bool isNavigationPanel); + void addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector &button_labels, QString &icon, std::vector &panels, QString ¤tPanel); void closePanel(); void showEvent(QShowEvent *event) override; void updateCarVariables(); @@ -58,6 +60,7 @@ private: FrogPilotButtonsControl *drivingButton; FrogPilotButtonsControl *navigationButton; + FrogPilotButtonsControl *systemButton; Params params; diff --git a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc index c6040a91..2042570c 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc @@ -2,22 +2,32 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { const std::vector> lateralToggles { + {"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("Advanced settings for fine tuning openpilot's lateral controls."), "../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"}, + {"SteerFriction", steerFrictionStock != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(steerFrictionStock, 'f', 2)) : tr("Friction"), tr("Adjusts the resistance in steering. Higher values provide more stable steering but can make it feel heavy, while lower values allow lighter steering but may feel too sensitive."), ""}, + {"SteerKP", steerKPStock != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKPStock, 'f', 2)) : tr("Kp Factor"), tr("Adjusts how aggressively the car corrects its steering. Higher values offer quicker corrections but may feel jerky, while lower values make steering smoother but slower to respond."), ""}, + {"SteerLatAccel", steerLatAccelStock != 0 ? QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(steerLatAccelStock, 'f', 2)) : tr("Lateral Accel"), tr("Adjusts how fast the car can steer from side to side. Higher values allow quicker lane changes but can feel unstable, while lower values provide smoother steering but may feel sluggish."), ""}, + {"SteerRatio", steerRatioStock != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatioStock, 'f', 2)) : tr("Steer Ratio"), tr("Adjusts how much openpilot needs to turn the wheel to steer. Higher values feel like driving a truck, more stable at high speeds, but harder to steer quickly at low speeds, while lower values feel like a go-kart, easier to steer in tight spots but more sensitive and less stable at high speeds."), ""}, + {"ForceAutoTune", tr("Force Auto Tune On"), tr("Forces comma's auto lateral tuning for unsupported vehicles."), ""}, + {"ForceAutoTuneOff", tr("Force Auto Tune Off"), tr("Forces comma's auto lateral tuning off for supported vehicles."), ""}, + {"AlwaysOnLateral", tr("Always on Lateral"), tr("openpilot's steering control stays active even when the brake or gas pedals are pressed.\n\nDeactivate only occurs with the 'Cruise Control' button."), "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"}, - {"AlwaysOnLateralLKAS", tr("Control with LKAS Button"), tr("'Always on Lateral' gets turned on or off using the 'LKAS' button."), ""}, - {"AlwaysOnLateralMain", tr("Enable with Cruise Control"), tr("'Always on Lateral' gets turned on by pressing the 'Cruise Control' button bypassing the requirement to enable openpilot first."), ""}, - {"PauseAOLOnBrake", tr("Pause on Brake Below"), tr("'Always on Lateral' pauses when the brake pedal is pressed below the set speed."), ""}, - {"HideAOLStatusBar", tr("Hide the Status Bar"), tr("The status bar for 'Always on Lateral' is hidden."), ""}, + {"AlwaysOnLateralLKAS", tr("Control with LKAS Button"), tr("Controls the current state of 'Always on Lateral' with the 'LKAS' button."), ""}, + {"AlwaysOnLateralMain", tr("Enable with Cruise Control"), tr("Activates 'Always on Lateral' whenever 'Cruise Control' is active bypassing the requirement to enable openpilot first."), ""}, + {"PauseAOLOnBrake", tr("Pause on Brake Below"), tr("Pauses 'Always on Lateral' when the brake pedal is pressed below the set speed."), ""}, + {"HideAOLStatusBar", tr("Hide the Status Bar"), tr("Hides status bar for 'Always On Lateral'."), ""}, {"LaneChangeCustomizations", tr("Lane Change Settings"), tr("How openpilot handles lane changes."), "../frogpilot/assets/toggle_icons/icon_lane.png"}, - {"NudgelessLaneChange", tr("Hands-Free Lane Change"), tr("Lane changes are conducted without needing to touch the steering wheel upon turn signal activation."), ""}, - {"LaneChangeTime", tr("Lane Change Delay"), tr("How long openpilot waits before changing lanes."), ""}, - {"LaneDetectionWidth", tr("Lane Width Requirement"), tr("The minimum lane width for openpilot to detect a lane as a lane."), ""}, - {"MinimumLaneChangeSpeed", tr("Minimum Speed for Lane Change"), tr("The minimum speed required for openpilot to perform a lane change."), ""}, - {"OneLaneChange", tr("Single Lane Change Per Signal"), tr("Lane changes are limited to one per turn signal activation."), ""}, + {"NudgelessLaneChange", tr("Automatic Lane Changes"), tr("Conducts lane changes without needing to touch the steering wheel upon turn signal activation."), ""}, + {"LaneChangeTime", tr("Lane Change Delay"), tr("Delays lane changes by the set time to prevent sudden changes."), ""}, + {"LaneDetectionWidth", tr("Lane Width Requirement"), tr("Sets the minimum lane width for openpilot to detect a lane as a lane."), ""}, + {"MinimumLaneChangeSpeed", tr("Minimum Speed for Lane Change"), tr("Sets the minimum speed required for openpilot to perform a lane change."), ""}, + {"OneLaneChange", tr("Only One Lane Change Per Signal"), tr("Limits lane changes to one per turn signal activation."), ""}, - {"LateralTune", tr("Lateral Tuning"), tr("Settings that control how openpilot manages steering."), "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, - {"NNFF", tr("Neural Network Feedforward (NNFF)"), tr("Twilsonco's 'Neural Network FeedForward' for more precise steering control."), ""}, - {"NNFFLite", tr("Smooth Curve Handling"), tr("Smoother steering when entering and exiting curves with Twilsonco's torque adjustments."), ""}, + {"LateralTune", tr("Lateral Tuning"), tr("Settings for fine tuning openpilot's lateral controls."), "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, + {"TacoTune", tr("comma's 2022 Taco Bell Turn Hack"), tr("Uses comma's hack they used to help handle left and right turns more precisely during their 2022 'Taco Bell' drive."), ""}, + {"TurnDesires", tr("Force Turn Desires Below Lane Change Speed"), tr("Forces the model to use turn desires when driving below the minimum lane change speed to help make left and right turns more precisely."), ""}, + {"NNFF", tr("Neural Network Feedforward (NNFF)"), tr("Uses Twilsonco's 'Neural Network FeedForward' for more precise steering control."), ""}, + {"NNFFLite", tr("Smooth Curve Handling"), tr("Smoothens the steering control when entering and exiting curves by using Twilsonco's torque adjustments."), ""}, {"QOLLateral", tr("Quality of Life Improvements"), tr("Miscellaneous lateral focused features to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/quality_of_life.png"}, {"PauseLateralSpeed", tr("Pause Steering Below"), tr("Pauses steering control when driving below the set speed."), ""} @@ -26,7 +36,50 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : for (const auto &[param, title, desc, icon] : lateralToggles) { AbstractControl *lateralToggle; - if (param == "AlwaysOnLateral") { + if (param == "AdvancedLateralTune") { + FrogPilotParamManageControl *advancedLateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(advancedLateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + std::set modifiedAdvancedLateralTuneKeys = advancedLateralTuneKeys; + + bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF"); + if (usingNNFF) { + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTune"); + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); + } else { + if (hasAutoTune) { + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTune"); + } else if (isPIDCar) { + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + } else { + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); + } + } + + if (!liveValid || usingNNFF) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + } + + showToggles(modifiedAdvancedLateralTuneKeys); + }); + lateralToggle = advancedLateralTuneToggle; + } else if (param == "SteerFriction") { + std::vector steerFrictionToggleNames{"Reset"}; + lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0.01, 0.25, QString(), std::map(), 0.01, {}, steerFrictionToggleNames, false, false); + } else if (param == "SteerKP") { + std::vector steerKPToggleNames{"Reset"}; + lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerKPStock * 0.50, steerKPStock * 1.50, QString(), std::map(), 0.01, {}, steerKPToggleNames, false, false); + } else if (param == "SteerLatAccel") { + std::vector steerLatAccelToggleNames{"Reset"}; + lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerLatAccelStock * 0.25, steerLatAccelStock * 1.25, QString(), std::map(), 0.01, {}, steerLatAccelToggleNames, false, false); + } else if (param == "SteerRatio") { + std::vector steerRatioToggleNames{"Reset"}; + lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, QString(), std::map(), 0.01, {}, steerRatioToggleNames, false, false); + + } else if (param == "AlwaysOnLateral") { FrogPilotParamManageControl *aolToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(aolToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { std::set modifiedAOLKeys = aolKeys; @@ -35,12 +88,37 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : modifiedAOLKeys.erase("AlwaysOnLateralLKAS"); } + if (customizationLevel != 2) { + modifiedAOLKeys.erase("AlwaysOnLateralMain"); + modifiedAOLKeys.erase("HideAOLStatusBar"); + } + showToggles(modifiedAOLKeys); }); lateralToggle = aolToggle; } else if (param == "PauseAOLOnBrake") { lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); + } else if (param == "LaneChangeCustomizations") { + FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + std::set modifiedLaneChangeKeys = laneChangeKeys; + + if (customizationLevel != 2) { + modifiedLaneChangeKeys.erase("LaneDetectionWidth"); + modifiedLaneChangeKeys.erase("MinimumLaneChangeSpeed"); + } + + showToggles(modifiedLaneChangeKeys); + }); + lateralToggle = laneChangeToggle; + } else if (param == "LaneChangeTime") { + lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 5, tr(" seconds"), {{0, "Instant"}, {10, "1.0 second"}}, 0.1); + } else if (param == "LaneDetectionWidth") { + lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 15, tr(" feet"), std::map(), 0.1); + } else if (param == "MinimumLaneChangeSpeed") { + lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); + } else if (param == "LateralTune") { FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { @@ -53,6 +131,11 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : modifiedLateralTuneKeys.erase("NNFFLite"); } + if (customizationLevel != 2) { + modifiedLateralTuneKeys.erase("TacoTune"); + modifiedLateralTuneKeys.erase("TurnDesires"); + } + showToggles(modifiedLateralTuneKeys); }); lateralToggle = lateralTuneToggle; @@ -66,27 +149,10 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : } else if (param == "PauseLateralSpeed") { std::vector pauseLateralToggles{"PauseLateralOnSignal"}; std::vector pauseLateralToggleNames{"Turn Signal Only"}; - lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1, pauseLateralToggles, pauseLateralToggleNames); + lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1, pauseLateralToggles, pauseLateralToggleNames, true); } else if (param == "PauseLateralOnSignal") { lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); - } else if (param == "LaneChangeCustomizations") { - FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(laneChangeKeys); - }); - lateralToggle = laneChangeToggle; - } else if (param == "LaneChangeTime") { - std::map laneChangeTimeLabels; - for (int i = 0; i <= 10; ++i) { - laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds"; - } - lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, QString(), laneChangeTimeLabels); - } else if (param == "LaneDetectionWidth") { - lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 15, tr(" feet"), std::map(), 0.1); - } else if (param == "MinimumLaneChangeSpeed") { - lateralToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); - } else { lateralToggle = new ParamControl(param, title, desc, icon); } @@ -141,6 +207,34 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : }); } + steerFrictionToggle = static_cast(toggles["SteerFriction"]); + QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { + params.putFloat("SteerFriction", steerFrictionStock); + steerFrictionToggle->refresh(); + updateFrogPilotToggles(); + }); + + steerKPToggle = static_cast(toggles["SteerKP"]); + QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { + params.putFloat("SteerKP", steerKPStock); + steerKPToggle->refresh(); + updateFrogPilotToggles(); + }); + + steerLatAccelToggle = static_cast(toggles["SteerLatAccel"]); + QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { + params.putFloat("SteerLatAccel", steerLatAccelStock); + steerLatAccelToggle->refresh(); + updateFrogPilotToggles(); + }); + + steerRatioToggle = static_cast(toggles["SteerRatio"]); + QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() { + params.putFloat("SteerRatio", steerRatioStock); + steerRatioToggle->refresh(); + updateFrogPilotToggles(); + }); + QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotLateralPanel::hideToggles); QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotLateralPanel::updateCarToggles); QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotLateralPanel::updateMetric); @@ -149,10 +243,30 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : updateMetric(); } +void FrogPilotLateralPanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + toggles["AdvancedLateralTune"]->setVisible(customizationLevel == 2); +} + void FrogPilotLateralPanel::updateCarToggles() { hasAutoTune = parent->hasAutoTune; hasNNFFLog = parent->hasNNFFLog; + isPIDCar = parent->isPIDCar; isSubaru = parent->isSubaru; + liveValid = parent->liveValid; + steerFrictionStock = parent->steerFrictionStock; + steerKPStock = parent->steerKPStock; + steerLatAccelStock = parent->steerLatAccelStock; + steerRatioStock = parent->steerRatioStock; + + steerFrictionToggle->setTitle(QString(tr("Friction (Default: %1)")).arg(QString::number(steerFrictionStock, 'f', 2))); + steerKPToggle->setTitle(QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKPStock, 'f', 2))); + steerKPToggle->updateControl(steerKPStock * 0.50, steerKPStock * 1.50); + steerLatAccelToggle->setTitle(QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(steerLatAccelStock, 'f', 2))); + steerLatAccelToggle->updateControl(steerLatAccelStock * 0.75, steerLatAccelStock * 1.25); + steerRatioToggle->setTitle(QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatioStock, 'f', 2))); + steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25); hideToggles(); } @@ -214,7 +328,8 @@ void FrogPilotLateralPanel::hideToggles() { setUpdatesEnabled(false); for (auto &[key, toggle] : toggles) { - bool subToggles = aolKeys.find(key) != aolKeys.end() || + bool subToggles = advancedLateralTuneKeys.find(key) != advancedLateralTuneKeys.end() || + aolKeys.find(key) != aolKeys.end() || laneChangeKeys.find(key) != laneChangeKeys.end() || lateralTuneKeys.find(key) != lateralTuneKeys.end() || qolKeys.find(key) != qolKeys.end(); @@ -222,6 +337,8 @@ void FrogPilotLateralPanel::hideToggles() { toggle->setVisible(!subToggles); } + toggles["AdvancedLateralTune"]->setVisible(customizationLevel == 2); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h index 82d39415..e84845fa 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h @@ -15,30 +15,41 @@ signals: private: void hideToggles(); + void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); void updateMetric(); void updateCarToggles(); void updateState(const UIState &s); + std::set advancedLateralTuneKeys = { + "ForceAutoTune", "ForceAutoTuneOff", "SteerFriction", + "SteerLatAccel", "SteerKP", "SteerRatio" + }; + std::set aolKeys = { - "AlwaysOnLateralLKAS", "AlwaysOnLateralMain", - "HideAOLStatusBar", "PauseAOLOnBrake" + "AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "HideAOLStatusBar", + "PauseAOLOnBrake" }; std::set laneChangeKeys = { - "LaneChangeTime", "LaneDetectionWidth", - "MinimumLaneChangeSpeed", "NudgelessLaneChange", - "OneLaneChange" + "LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", + "NudgelessLaneChange", "OneLaneChange" }; std::set lateralTuneKeys = { - "NNFF", "NNFFLite" + "NNFF", "NNFFLite", "TacoTune", + "TurnDesires" }; std::set qolKeys = { "PauseLateralSpeed" }; + FrogPilotParamValueButtonControl *steerFrictionToggle; + FrogPilotParamValueButtonControl *steerLatAccelToggle; + FrogPilotParamValueButtonControl *steerKPToggle; + FrogPilotParamValueButtonControl *steerRatioToggle; + FrogPilotSettingsWindow *parent; Params params; @@ -46,8 +57,17 @@ private: bool hasAutoTune; bool hasNNFFLog; bool isMetric = params.getBool("IsMetric"); + bool isPIDCar; bool isSubaru; + bool liveValid; bool started; + float steerFrictionStock; + float steerLatAccelStock; + float steerKPStock; + float steerRatioStock; + + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc index 2f85dd0d..a3897f78 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc @@ -2,68 +2,169 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { const std::vector> longitudinalToggles { - {"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("Automatically switches to 'Experimental Mode' when specific conditions are met."), "../frogpilot/assets/toggle_icons/icon_conditional.png"}, - {"CESpeed", tr("Below"), tr("'Experimental Mode' is active when driving below the set speed without a lead vehicle."), ""}, - {"CECurves", tr("Curve Detected Ahead"), tr("'Experimental Mode' is active when a curve is detected in the road ahead."), ""}, - {"CELead", tr("Lead Detected Ahead"), tr("'Experimental Mode' is active when a slower or stopped vehicle is detected ahead."), ""}, - {"CENavigation", tr("Navigation Data"), tr("'Experimental Mode' is active based on navigation data, such as upcoming intersections or turns."), ""}, - {"CEModelStopTime", tr("openpilot Wants to Stop In"), tr("'Experimental Mode' is active when openpilot wants to stop such as for a stop sign or red light."), ""}, - {"CESignalSpeed", tr("Turn Signal Below"), tr("'Experimental Mode' is active when using turn signals below the set speed."), ""}, - {"HideCEMStatusBar", tr("Hide the Status Bar"), tr("The status bar for 'Conditional Experimental Mode' is hidden."), ""}, + {"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("Automatically switch to 'Experimental Mode' when specific conditions are met."), "../frogpilot/assets/toggle_icons/icon_conditional.png"}, + {"CESpeed", tr("Below"), tr("Triggers 'Experimental Mode' when driving below the set speed without a lead vehicle."), ""}, + {"CECurves", tr("Curve Detected Ahead"), tr("Triggers 'Experimental Mode' when a curve is detected in the road ahead."), ""}, + {"CELead", tr("Lead Detected Ahead"), tr("Triggers 'Experimental Mode' when a slower or stopped vehicle is detected ahead."), ""}, + {"CENavigation", tr("Navigation Data"), tr("Triggers 'Experimental Mode' based on navigation data, such as upcoming intersections or turns."), ""}, + {"CEModelStopTime", tr("openpilot Wants to Stop In"), tr("Triggers 'Experimental Mode' when openpilot wants to stop such as for a stop sign or red light."), ""}, + {"CESignalSpeed", tr("Turn Signal Below"), tr("Triggers 'Experimental Mode' when using turn signals below the set speed."), ""}, + {"HideCEMStatusBar", tr("Hide the Status Bar"), tr("Hides status bar for 'Conditional Experimental Mode'."), ""}, {"CurveSpeedControl", tr("Curve Speed Control"), tr("Automatically slow down for curves detected ahead or through the downloaded maps."), "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, - {"CurveDetectionMethod", tr("Curve Detection Method"), tr("The method used to detect curves."), ""}, - {"MTSCCurvatureCheck", tr("Curve Detection Failsafe"), tr("Curve control is triggered only when a curve is detected ahead. Use this as a failsafe to prevent false positives when using the 'Map Based' method."), ""}, - {"CurveSensitivity", tr("Curve Sensitivity"), tr("How sensitive openpilot is to detecting curves. Higher values trigger earlier responses at the risk of triggering too often, while lower values increase confidence at the risk of triggering too infrequently."), ""}, - {"TurnAggressiveness", tr("Turn Speed Aggressiveness"), tr("How aggressive openpilot takes turns. Higher values result in quicker turns, while lower values provide gentler turns."), ""}, + {"CurveDetectionMethod", tr("Curve Detection Method"), tr("Uses data from either the downloaded maps or the model to determine where curves are."), ""}, + {"MTSCCurvatureCheck", tr("Curve Detection Failsafe"), tr("Triggers 'Curve Speed Control' only when a curve is detected with the model as well when using the 'Map Based' method."), ""}, + {"CurveSensitivity", tr("Curve Detection Sensitivity"), tr("Controls how sensitive openpilot is to detecting curves. Higher values trigger earlier responses at the risk of triggering too often, while lower values increase confidence at the risk of triggering too infrequently."), ""}, + {"TurnAggressiveness", tr("Speed Aggressiveness"), tr("Controls how aggressive openpilot takes turns. Higher values result in faster turns, while lower values result in slower turns."), ""}, {"DisableCurveSpeedSmoothing", tr("Disable Speed Value Smoothing In the UI"), tr("Speed value smoothing is disabled in the UI to instead display the exact speed requested by the curve control."), ""}, - {"ExperimentalModeActivation", tr("Experimental Mode Activation"), tr("'Experimental Mode' is toggled off/on using the steering wheel buttons or the on-screen controls.\n\nThis overrides 'Conditional Experimental Mode'."), "../assets/img_experimental_white.svg"}, - {"ExperimentalModeViaLKAS", tr("Click the LKAS Button"), tr("'Experimental Mode' is toggled by pressing the 'LKAS' button on the steering wheel."), ""}, - {"ExperimentalModeViaTap", tr("Double-Tap the Screen"), tr("'Experimental Mode' is toggled by double-tapping the onroad UI within 0.5 seconds."), ""}, - {"ExperimentalModeViaDistance", tr("Long Press the Distance Button"), tr("'Experimental Mode' is toggled by holding the 'distance' button on the steering wheel for 0.5+ seconds."), ""}, + {"CustomPersonalities", tr("Customize Driving Personalities"), tr("Customize the personality profiles to suit your driving style."), "../frogpilot/assets/toggle_icons/icon_personality.png"}, + {"TrafficPersonalityProfile", tr("Traffic Personality"), tr("Customizes the 'Traffic' personality profile, tailored for navigating through traffic."), "../frogpilot/assets/stock_theme/distance_icons/traffic.png"}, + {"TrafficFollow", tr("Following Distance"), tr("Controls the minimum following distance in 'Traffic' mode. openpilot will automatically dynamically between this value and the 'Aggressive' profile distance based on your current speed."), ""}, + {"TrafficJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in acceleration in 'Traffic' mode. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""}, + {"TrafficJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in deceleration in 'Traffic' mode. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""}, + {"TrafficJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around other vehicles or obstacles in 'Traffic' mode. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time."), ""}, + {"TrafficJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot increases speed in 'Traffic' mode. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""}, + {"TrafficJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to decreasing speeds in 'Traffic' mode. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt."), ""}, + {"ResetTrafficPersonality", tr("Reset Settings"), tr("Restores the 'Traffic Mode' settings to their default values."), ""}, + + {"AggressivePersonalityProfile", tr("Aggressive Personality"), tr("Customize the 'Aggressive' personality profile, designed for a more assertive driving style."), "../frogpilot/assets/stock_theme/distance_icons/aggressive.png"}, + {"AggressiveFollow", tr("Following Distance"), tr("Sets the following distance for 'Aggressive' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.25 seconds."), ""}, + {"AggressiveJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in acceleration in 'Aggressive' mode. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 0.5."), ""}, + {"AggressiveJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in deceleration in 'Aggressive' mode. Higher values result in smoother, more gradual deceleration, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 0.5."), ""}, + {"AggressiveJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around other vehicles or obstacles in 'Aggressive' mode. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time.\n\nDefault: 1.0."), ""}, + {"AggressiveJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot increases speed in 'Aggressive' mode. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 0.5."), ""}, + {"AggressiveJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to decreasing speeds in 'Aggressive' mode. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 0.5."), ""}, + {"ResetAggressivePersonality", tr("Reset Settings"), tr("Restores the 'Aggressive' settings to their default values."), ""}, + + {"StandardPersonalityProfile", tr("Standard Personality"), tr("Customize the 'Standard' personality profile, optimized for balanced driving."), "../frogpilot/assets/stock_theme/distance_icons/standard.png"}, + {"StandardFollow", tr("Following Distance"), tr("Set the following distance for 'Standard' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.45 seconds."), ""}, + {"StandardJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in acceleration in 'Standard' mode. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"StandardJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in deceleration in 'Standard' mode. Higher values result in smoother braking, while lower values allow for quicker, more immediate braking that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"StandardJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around other vehicles or obstacles in 'Standard' mode. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time.\n\nDefault: 1.0."), ""}, + {"StandardJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot increases speed in 'Standard' mode. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"StandardJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to decreasing speeds in 'Standard' mode. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"ResetStandardPersonality", tr("Reset Settings"), tr("Restores the 'Standard' settings to their default values."), ""}, + + {"RelaxedPersonalityProfile", tr("Relaxed Personality"), tr("Customize the 'Relaxed' personality profile, ideal for a more laid-back driving style."), "../frogpilot/assets/stock_theme/distance_icons/relaxed.png"}, + {"RelaxedFollow", tr("Following Distance"), tr("Set the following distance for 'Relaxed' mode. This determines roughly how many seconds you'll follow behind the car ahead.\n\nDefault: 1.75 seconds."), ""}, + {"RelaxedJerkAcceleration", tr("Acceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in acceleration in 'Relaxed' mode. Higher values result in smoother, more gradual acceleration, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"RelaxedJerkDeceleration", tr("Deceleration Sensitivity"), tr("Controls how sensitive openpilot is to changes in deceleration in 'Relaxed' mode. Higher values result in smoother braking, while lower values allow for quicker, more immediate braking that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"RelaxedJerkDanger", tr("Safety Distance Sensitivity"), tr("Adjusts how cautious openpilot is around other vehicles or obstacles in 'Relaxed' mode. Higher values increase following distances and prioritize safety, leading to more cautious driving, while lower values allow for closer following but may reduce reaction time.\n\nDefault: 1.0."), ""}, + {"RelaxedJerkSpeed", tr("Speed Increase Responsiveness"), tr("Controls how quickly openpilot increases speed in 'Relaxed' mode. Higher values ensure smoother, more gradual speed changes when accelerating, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"RelaxedJerkSpeedDecrease", tr("Speed Decrease Responsiveness"), tr("Sets how quickly openpilot adjusts to decreasing speeds in 'Relaxed' mode. Higher values ensure smoother, more gradual speed changes when slowing down, while lower values allow for quicker, more responsive changes that may feel abrupt.\n\nDefault: 1.0."), ""}, + {"ResetRelaxedPersonality", tr("Reset Settings"), tr("Restores the 'Relaxed' settings to their default values."), ""}, + + {"ExperimentalModeActivation", tr("Experimental Mode Activation"), tr("Toggle 'Experimental Mode' on/off using either the steering wheel buttons or screen.\n\nThis overrides 'Conditional Experimental Mode'."), "../assets/img_experimental_white.svg"}, + {"ExperimentalModeViaLKAS", tr("Click the LKAS Button"), tr("Toggles 'Experimental Mode' by pressing the 'LKAS' button on the steering wheel."), ""}, + {"ExperimentalModeViaTap", tr("Double-Tap the Screen"), tr("Toggles 'Experimental Mode' by double-tapping the onroad UI within a 0.5 second period."), ""}, + {"ExperimentalModeViaDistance", tr("Long Press the Distance Button"), tr("Toggles 'Experimental Mode' by holding down the 'distance' button on the steering wheel for 0.5 seconds."), ""}, {"LongitudinalTune", tr("Longitudinal Tuning"), tr("Settings that control how openpilot manages speed and acceleration."), "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"}, - {"AccelerationProfile", tr("Acceleration Profile"), tr("Choose between a sporty or eco-friendly acceleration rate."), ""}, - {"DecelerationProfile", tr("Deceleration Profile"), tr("Choose between a sporty or eco-friendly deceleration rate."), ""}, - {"HumanAcceleration", tr("Human-Like Acceleration"), tr("Uses the lead's acceleration rate when at a takeoff and ramps off the acceleration rate when approaching the maximum set speed for a smoother max speed approach."), ""}, - {"HumanFollowing", tr("Human-Like Following Distance"), tr("Dynamically adjusts the following distance to feel more natural when approaching slower or stopped vehicles."), ""}, + {"AccelerationProfile", tr("Acceleration Profile"), tr("Enables either a sporty or eco-friendly acceleration rate. 'Sport+' aims to make openpilot accelerate as fast as possible."), ""}, + {"DecelerationProfile", tr("Deceleration Profile"), tr("Enables either a sporty or eco-friendly deceleration rate."), ""}, + {"HumanAcceleration", tr("Human-Like Acceleration"), tr("Uses the lead's acceleration rate when at a takeoff and ramps off the acceleration rate when approaching the maximum set speed for a more 'human-like' driving experience."), ""}, + {"HumanFollowing", tr("Human-Like Following Distance"), tr("Dynamically adjusts the following distance when approaching slower or stopped vehicles for a more 'human-like' driving experience."), ""}, {"IncreasedStoppedDistance", tr("Increase Stopped Distance"), tr("Increases the distance to stop behind vehicles."), ""}, + {"LeadDetectionThreshold", tr("Lead Detection Confidence"), tr("Controls how sensitive openpilot is to detecting vehicles ahead. A lower value can help detect vehicles sooner and from farther away, but increases the chance openpilot mistakes other objects for vehicles."), ""}, + {"MaxDesiredAcceleration", tr("Maximum Acceleration Rate"), tr("Sets a cap on how fast openpilot can accelerate."), ""}, {"QOLLongitudinal", tr("Quality of Life Improvements"), tr("Miscellaneous longitudinal focused features to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/quality_of_life.png"}, - {"CustomCruise", tr("Cruise Increase Interval"), tr("Interval used when increasing the cruise control speed."), ""}, - {"CustomCruiseLong", tr("Custom Cruise Interval (Long Press)"), tr("Interval used when increasing the cruise control speed when holding down the button for 0.5+ seconds."), ""}, - {"MapGears", tr("Map Accel/Decel to Gears"), tr("Map the acceleration and deceleration profiles to the 'Eco' or 'Sport' gear modes."), ""}, - {"OnroadDistanceButton", tr("Onroad Personality Button"), tr("The current driving personality is displayed on the screen. Tap to switch personalities, or long press for 2.5 seconds to activate 'Traffic Mode'."), ""}, - {"ReverseCruise", tr("Reverse Cruise Increase"), tr("The long press feature is reversed in order to increase speed by 5 mph instead of 1."), ""}, + {"CustomCruise", tr("Cruise Increase Interval"), tr("Controls the interval used when increasing the cruise control speed."), ""}, + {"CustomCruiseLong", tr("Custom Cruise Interval (Long Press)"), tr("Controls the interval used when increasing the cruise control speed while holding down the button for 0.5+ seconds."), ""}, + {"ForceStandstill", tr("Force Keep openpilot in the Standstill State"), tr("Keeps openpilot in the 'standstill' state until the gas pedal or 'resume' button is pressed."), ""}, + {"ForceStops", tr("Force Stop for 'Detected' Stop Lights/Signs"), tr("Forces a stop whenever openpilot 'detects' a potential red light/stop sign to prevent it from running the red light/stop sign."), ""}, + {"SetSpeedOffset", tr("Set Speed Offset"), tr("Controls how much higher or lower the set speed should be compared to your current set speed. For example, if you prefer to drive 5 mph above the speed limit, this setting will automatically add that difference when you adjust your set speed."), ""}, + {"MapGears", tr("Map Accel/Decel to Gears"), tr("Maps the acceleration and deceleration profiles to your car's 'Eco' or 'Sport' gear modes."), ""}, + {"ReverseCruise", tr("Reverse Cruise Increase"), tr("Reverses the long press cruise increase feature to increase the max speed by 5 mph instead of 1 on short presses."), ""}, - {"SpeedLimitController", tr("Speed Limit Controller"), tr("Automatically adjust your max speed to match the speed limit using 'Open Street Maps', 'Navigate on openpilot', or your car's dashboard (Toyota/Lexus/HKG only)."), "../assets/offroad/icon_speed_limit.png"}, - {"SLCConfirmation", tr("Confirm New Speed Limits"), tr("Require manual confirmation before using a new speed limit."), ""}, - {"SLCFallback", tr("Fallback Method"), tr("Choose what happens when no speed limit data is available."), ""}, - {"SLCOverride", tr("Override Method"), tr("Choose how you want to override the current speed limit.\n\n"), ""}, - {"SLCPriority", tr("Speed Limit Source Priority"), tr("Set the order of priority for speed limit data sources."), ""}, - {"SLCOffsets", tr("Speed Limit Offsets"), tr("Manage toggles related to 'Speed Limit Controller's controls."), ""}, - {"Offset1", tr("Speed Limit Offset (0-34 mph)"), tr("Set the speed limit offset for speeds between 0 and 34 mph."), ""}, - {"Offset2", tr("Speed Limit Offset (35-54 mph)"), tr("Set the speed limit offset for speeds between 35 and 54 mph."), ""}, - {"Offset3", tr("Speed Limit Offset (55-64 mph)"), tr("Set the speed limit offset for speeds between 55 and 64 mph."), ""}, - {"Offset4", tr("Speed Limit Offset (65-99 mph)"), tr("Set the speed limit offset for speeds between 65 and 99 mph."), ""}, + {"SpeedLimitController", tr("Speed Limit Controller"), tr("Automatically adjust your max speed to match the speed limit using downloaded 'Open Street Maps' data, 'Navigate on openpilot', or your car's dashboard (Toyota/Lexus/HKG only)."), "../assets/offroad/icon_speed_limit.png"}, + {"SLCConfirmation", tr("Confirm New Speed Limits"), tr("Enables manual confirmations before using a new speed limit."), ""}, + {"SLCFallback", tr("Fallback Method"), tr("Controls what happens when no speed limit data is available."), ""}, + {"SLCOverride", tr("Override Method"), tr("Controls how the current speed limit is overriden.\n\n"), ""}, {"SLCQOL", tr("Quality of Life Improvements"), tr("Miscellaneous 'Speed Limit Controller' focused features to improve your overall openpilot experience."), ""}, - {"ForceMPHDashboard", tr("Force MPH Readings from Dashboard"), tr("Force speed limit readings in MPH from the dashboard if it normally displays in KPH."), ""}, - {"SLCLookaheadHigher", tr("Prepare for Higher Speed Limits"), tr("Set a lookahead value to prepare for upcoming higher speed limits based on map data."), ""}, - {"SLCLookaheadLower", tr("Prepare for Lower Speed Limits"), tr("Set a lookahead value to prepare for upcoming lower speed limits based on map data."), ""}, - {"SetSpeedLimit", tr("Set Speed to Current Limit"), tr("Set your max speed to match the current speed limit when enabling openpilot."), ""}, - {"SLCVisuals", tr("Visual Settings"), tr("Manage visual settings for the 'Speed Limit Controller'."), ""}, - {"UseVienna", tr("Use Vienna-Style Speed Signs"), tr("Switch to Vienna-style (EU) speed limit signs instead of MUTCD (US)."), ""}, - {"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("Display the speed limit offset separately in the onroad UI when using the Speed Limit Controller."), ""}, + {"ForceMPHDashboard", tr("Force MPH Readings from Dashboard"), tr("Forces speed limit readings from the dashboard to MPH if it normally displays them in KPH."), ""}, + {"SLCLookaheadHigher", tr("Prepare for Higher Speed Limits"), tr("Sets a lookahead value to prepare for upcoming higher speed limits when using downloaded map data."), ""}, + {"SLCLookaheadLower", tr("Prepare for Lower Speed Limits"), tr("Sets a lookahead value to prepare for upcoming lower speed limits when using downloaded map data."), ""}, + {"SetSpeedLimit", tr("Set Speed to Current Limit"), tr("Sets your max speed to match the current speed limit when enabling openpilot."), ""}, + {"SLCPriority", tr("Speed Limit Source Priority"), tr("Sets the order of priority for speed limit data sources."), ""}, + {"SLCOffsets", tr("Speed Limit Offsets"), tr("Set speed limit offsets to drive over the posted speed limit."), ""}, + {"Offset1", tr("Speed Limit Offset (0-34 mph)"), tr("Sets the speed limit offset for speeds between 0 and 34 mph."), ""}, + {"Offset2", tr("Speed Limit Offset (35-54 mph)"), tr("Sets the speed limit offset for speeds between 35 and 54 mph."), ""}, + {"Offset3", tr("Speed Limit Offset (55-64 mph)"), tr("Sets the speed limit offset for speeds between 55 and 64 mph."), ""}, + {"Offset4", tr("Speed Limit Offset (65-99 mph)"), tr("Sets the speed limit offset for speeds between 65 and 99 mph."), ""}, }; for (const auto &[param, title, desc, icon] : longitudinalToggles) { AbstractControl *longitudinalToggle; - if (param == "ConditionalExperimental") { + if (param == "CustomPersonalities") { + FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + showToggles(customDrivingPersonalityKeys); + }); + longitudinalToggle = customPersonalitiesToggle; + } else if (param == "ResetTrafficPersonality" || param == "ResetAggressivePersonality" || param == "ResetStandardPersonality" || param == "ResetRelaxedPersonality") { + FrogPilotButtonsControl *profileBtn = new FrogPilotButtonsControl(title, desc, {tr("Reset")}); + longitudinalToggle = profileBtn; + } else if (param == "TrafficPersonalityProfile") { + FrogPilotParamManageControl *trafficPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(trafficPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + customPersonalityOpen = true; + openSubParentToggle(); + showToggles(trafficPersonalityKeys); + }); + longitudinalToggle = trafficPersonalityToggle; + } else if (param == "AggressivePersonalityProfile") { + FrogPilotParamManageControl *aggressivePersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(aggressivePersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + customPersonalityOpen = true; + openSubParentToggle(); + showToggles(aggressivePersonalityKeys); + }); + longitudinalToggle = aggressivePersonalityToggle; + } else if (param == "StandardPersonalityProfile") { + FrogPilotParamManageControl *standardPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(standardPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + customPersonalityOpen = true; + openSubParentToggle(); + showToggles(standardPersonalityKeys); + }); + longitudinalToggle = standardPersonalityToggle; + } else if (param == "RelaxedPersonalityProfile") { + FrogPilotParamManageControl *relaxedPersonalityToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(relaxedPersonalityToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + customPersonalityOpen = true; + openSubParentToggle(); + showToggles(relaxedPersonalityKeys); + }); + longitudinalToggle = relaxedPersonalityToggle; + } else if (trafficPersonalityKeys.find(param) != trafficPersonalityKeys.end() || + aggressivePersonalityKeys.find(param) != aggressivePersonalityKeys.end() || + standardPersonalityKeys.find(param) != standardPersonalityKeys.end() || + relaxedPersonalityKeys.find(param) != relaxedPersonalityKeys.end()) { + if (param == "TrafficFollow" || param == "AggressiveFollow" || param == "StandardFollow" || param == "RelaxedFollow") { + if (param == "TrafficFollow") { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.5, 5, tr(" seconds"), std::map(), 0.01); + } else { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 5, tr(" seconds"), std::map(), 0.01); + } + } else { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 500, "%"); + } + + } else if (param == "ConditionalExperimental") { FrogPilotParamManageControl *conditionalExperimentalToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(conditionalExperimentalToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(conditionalExperimentalKeys); + std::set modifiedConditionalExperimentalKeys = conditionalExperimentalKeys; + + if (customizationLevel != 2) { + modifiedConditionalExperimentalKeys.erase("CENavigation"); + modifiedConditionalExperimentalKeys.erase("CESignalSpeed"); + modifiedConditionalExperimentalKeys.erase("HideCEMStatusBar"); + } + + showToggles(modifiedConditionalExperimentalKeys); }); longitudinalToggle = conditionalExperimentalToggle; } else if (param == "CESpeed") { @@ -84,15 +185,11 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * std::vector navigationToggleNames{tr("Intersections"), tr("Turns"), tr("With Lead")}; longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, navigationToggles, navigationToggleNames); } else if (param == "CEModelStopTime") { - std::map modelStopTimeLabels; - for (int i = 0; i <= 10; ++i) { - modelStopTimeLabels[i] = (i == 0) ? tr("Off") : QString::number(i) + " seconds"; - } - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, QString(), modelStopTimeLabels); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" seconds"), {{0, "Off"}}); } else if (param == "CESignalSpeed") { std::vector ceSignalToggles{"CESignalLaneDetection"}; - std::vector ceSignalToggleNames{"Lane Detection"}; - longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1.0, ceSignalToggles, ceSignalToggleNames); + std::vector ceSignalToggleNames{"Only For Detected Lanes"}; + longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1.0, ceSignalToggles, ceSignalToggleNames, true); } else if (param == "CurveSpeedControl") { FrogPilotParamManageControl *curveControlToggle = new FrogPilotParamManageControl(param, title, desc, icon); @@ -107,6 +204,12 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * modifiedCurveSpeedKeys.erase("MTSCCurvatureCheck"); } + if (customizationLevel != 2) { + modifiedCurveSpeedKeys.erase("CurveSensitivity"); + modifiedCurveSpeedKeys.erase("MTSCCurvatureCheck"); + modifiedCurveSpeedKeys.erase("TurnAggressiveness"); + } + showToggles(modifiedCurveSpeedKeys); }); longitudinalToggle = curveControlToggle; @@ -162,19 +265,38 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * } else if (param == "LongitudinalTune") { FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(longitudinalTuneKeys); + std::set modifiedLongitudinalTuneKeys = longitudinalTuneKeys; + + if (customizationLevel == 0) { + modifiedLongitudinalTuneKeys.erase("HumanAcceleration"); + modifiedLongitudinalTuneKeys.erase("HumanFollowing"); + modifiedLongitudinalTuneKeys.erase("IncreasedStoppedDistance"); + modifiedLongitudinalTuneKeys.erase("LeadDetectionThreshold"); + modifiedLongitudinalTuneKeys.erase("MaxDesiredAcceleration"); + } else if (customizationLevel == 1) { + modifiedLongitudinalTuneKeys.erase("HumanAcceleration"); + modifiedLongitudinalTuneKeys.erase("HumanFollowing"); + modifiedLongitudinalTuneKeys.erase("LeadDetectionThreshold"); + modifiedLongitudinalTuneKeys.erase("MaxDesiredAcceleration"); + } + + showToggles(modifiedLongitudinalTuneKeys); }); longitudinalToggle = longitudinalTuneToggle; } else if (param == "AccelerationProfile") { - std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")}; - ButtonParamControl *profileSelection = new ButtonParamControl(param, title, desc, icon, profileOptions); - longitudinalToggle = profileSelection; + std::vector accelerationProfiles{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")}; + ButtonParamControl *accelerationProfileToggle = new ButtonParamControl(param, title, desc, icon, accelerationProfiles); + longitudinalToggle = accelerationProfileToggle; } else if (param == "DecelerationProfile") { - std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport")}; - ButtonParamControl *profileSelection = new ButtonParamControl(param, title, desc, icon, profileOptions); - longitudinalToggle = profileSelection; + std::vector decelerationProfiles{tr("Standard"), tr("Eco"), tr("Sport")}; + ButtonParamControl *decelerationProfileToggle = new ButtonParamControl(param, title, desc, icon, decelerationProfiles); + longitudinalToggle = decelerationProfileToggle; } else if (param == "IncreasedStoppedDistance") { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 15, tr(" feet")); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet")); + } else if (param == "LeadDetectionThreshold") { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, "%"); + } else if (param == "MaxDesiredAcceleration") { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.1, 4.0, "m/s", std::map(), 0.1); } else if (param == "QOLLongitudinal") { FrogPilotParamManageControl *qolLongitudinalToggle = new FrogPilotParamManageControl(param, title, desc, icon); @@ -186,12 +308,20 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * } else { modifiedQolKeys.erase("CustomCruise"); modifiedQolKeys.erase("CustomCruiseLong"); + modifiedQolKeys.erase("SetSpeedOffset"); } - if (!isToyota && !isGM && !isHKGCanFd) { + if (!(isGM || isHKGCanFd || isToyota)) { modifiedQolKeys.erase("MapGears"); } + if (customizationLevel != 2) { + modifiedQolKeys.erase("ForceStandstill"); + modifiedQolKeys.erase("ForceStops"); + modifiedQolKeys.erase("ReverseCruise"); + modifiedQolKeys.erase("SetSpeedOffset"); + } + showToggles(modifiedQolKeys); }); longitudinalToggle = qolLongitudinalToggle; @@ -203,58 +333,39 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * std::vector mapGearsToggles{"MapAcceleration", "MapDeceleration"}; std::vector mapGearsToggleNames{tr("Acceleration"), tr("Deceleration")}; longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, mapGearsToggles, mapGearsToggleNames); + } else if (param == "SetSpeedOffset") { + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); } else if (param == "SpeedLimitController") { FrogPilotParamManageControl *speedLimitControllerToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(speedLimitControllerToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - bool slcLower = params.getBool("SLCConfirmationLower"); - bool slcHigher = params.getBool("SLCConfirmationHigher"); + std::set modifiedSpeedLimitControllerKeys = speedLimitControllerKeys; - slcConfirmationBtn->setCheckedButton(0, slcLower); - slcConfirmationBtn->setCheckedButton(1, slcHigher); - slcConfirmationBtn->setCheckedButton(2, !(slcLower || slcHigher)); + if (customizationLevel == 0) { + modifiedSpeedLimitControllerKeys.erase("SLCFallback"); + modifiedSpeedLimitControllerKeys.erase("SLCOverride"); + modifiedSpeedLimitControllerKeys.erase("SLCPriority"); + modifiedSpeedLimitControllerKeys.erase("SLCQOL"); + } else if (customizationLevel != 2) { + modifiedSpeedLimitControllerKeys.erase("SLCPriority"); + modifiedSpeedLimitControllerKeys.erase("SLCQOL"); + } + + showToggles(modifiedSpeedLimitControllerKeys); slcOpen = true; - showToggles(speedLimitControllerKeys); }); longitudinalToggle = speedLimitControllerToggle; } else if (param == "SLCConfirmation") { - slcConfirmationBtn = new FrogPilotButtonsControl(title, desc, {tr("Lower Limits"), tr("Higher Limits"), tr("None")}, true, false); - QObject::connect(slcConfirmationBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) { - bool lowerEnabled = params.getBool("SLCConfirmationLower"); - bool higherEnabled = params.getBool("SLCConfirmationHigher"); - - if (id == 0) { - params.putBool("SLCConfirmationLower", !lowerEnabled); - slcConfirmationBtn->setCheckedButton(0, !lowerEnabled); - slcConfirmationBtn->setCheckedButton(2, false); - - if (lowerEnabled & !higherEnabled) { - slcConfirmationBtn->setCheckedButton(2, true); - } - } else if (id == 1) { - params.putBool("SLCConfirmationHigher", !higherEnabled); - slcConfirmationBtn->setCheckedButton(1, !higherEnabled); - slcConfirmationBtn->setCheckedButton(2, false); - - if (higherEnabled & !lowerEnabled) { - slcConfirmationBtn->setCheckedButton(2, true); - } - } else { - params.putBool("SLCConfirmationLower", false); - params.putBool("SLCConfirmationHigher", false); - slcConfirmationBtn->setCheckedButton(0, false); - slcConfirmationBtn->setCheckedButton(1, false); - slcConfirmationBtn->setCheckedButton(2, true); - } - }); - longitudinalToggle = slcConfirmationBtn; + std::vector confirmationToggles{"SLCConfirmationLower", "SLCConfirmationHigher"}; + std::vector confirmationToggleNames{tr("Lower Limits"), tr("Higher Limits")}; + longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, confirmationToggles, confirmationToggleNames); } else if (param == "SLCFallback") { std::vector fallbackOptions{tr("Set Speed"), tr("Experimental Mode"), tr("Previous Limit")}; ButtonParamControl *fallbackSelection = new ButtonParamControl(param, title, desc, icon, fallbackOptions); longitudinalToggle = fallbackSelection; } else if (param == "SLCOverride") { - std::vector overrideOptions{tr("None"), tr("Gas Pedal Press"), tr("Cruise Set Speed")}; + std::vector overrideOptions{tr("None"), tr("Set With Gas Pedal"), tr("Max Set Speed")}; ButtonParamControl *overrideSelection = new ButtonParamControl(param, title, desc, icon, overrideOptions); longitudinalToggle = overrideSelection; } else if (param == "SLCPriority") { @@ -269,7 +380,8 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * for (int i = 1; i <= 3; ++i) { QStringList currentPriorities = (i == 1) ? primaryPriorities : secondaryTertiaryPriorities; QStringList prioritiesToDisplay = currentPriorities; - for (const auto &selectedPriority : qAsConst(selectedPriorities)) { + + for (QString selectedPriority : qAsConst(selectedPriorities)) { prioritiesToDisplay.removeAll(selectedPriority); } @@ -284,12 +396,24 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * QString priorityKey = QString("SLCPriority%1").arg(i); QString selection = MultiOptionDialog::getSelection(priorityPrompts[i - 1], prioritiesToDisplay, "", this); - if (selection.isEmpty()) break; + if (selection.isEmpty()) { + break; + } params.putNonBlocking(priorityKey.toStdString(), selection.toStdString()); selectedPriorities.append(selection); - if (selection == tr("Lowest") || selection == tr("Highest") || selection == tr("None")) break; + if (selection == tr("None")) { + for (int j = i + 1; j <= 3; ++j) { + QString priorityKeyNext = QString("SLCPriority%1").arg(j); + params.putNonBlocking(priorityKeyNext.toStdString(), "None"); + } + break; + } + + if (selection == tr("Lowest") || selection == tr("Highest")) { + break; + } updateFrogPilotToggles(); } @@ -335,19 +459,8 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * longitudinalToggle = reinterpret_cast(manageSLCQOLBtn); } else if (param == "SLCLookaheadHigher" || param == "SLCLookaheadLower") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 60, tr(" seconds")); - } else if (param == "SLCVisuals") { - ButtonControl *manageSLCVisualsBtn = new ButtonControl(title, tr("MANAGE"), desc); - QObject::connect(manageSLCVisualsBtn, &ButtonControl::clicked, [this]() { - openSubParentToggle(); - showToggles(speedLimitControllerVisualsKeys); - }); - longitudinalToggle = reinterpret_cast(manageSLCVisualsBtn); } else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, -99, 99, tr("mph")); - } else if (param == "ShowSLCOffset") { - std::vector slcOffsetToggles{"ShowSLCOffsetUI"}; - std::vector slcOffsetToggleNames{tr("Control Via UI")}; - longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, slcOffsetToggles, slcOffsetToggleNames); } else { longitudinalToggle = new ParamControl(param, title, desc, icon); @@ -373,6 +486,106 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * } }); + FrogPilotParamValueControl *trafficFollowToggle = static_cast(toggles["TrafficFollow"]); + FrogPilotParamValueControl *trafficAccelerationToggle = static_cast(toggles["TrafficJerkAcceleration"]); + FrogPilotParamValueControl *trafficDecelerationToggle = static_cast(toggles["TrafficJerkDeceleration"]); + FrogPilotParamValueControl *trafficDangerToggle = static_cast(toggles["TrafficJerkDanger"]); + FrogPilotParamValueControl *trafficSpeedToggle = static_cast(toggles["TrafficJerkSpeed"]); + FrogPilotParamValueControl *trafficSpeedDecreaseToggle = static_cast(toggles["TrafficJerkSpeedDecrease"]); + FrogPilotButtonsControl *trafficResetButton = static_cast(toggles["ResetTrafficPersonality"]); + QObject::connect(trafficResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for 'Traffic Mode'?"), this)) { + params.putFloat("TrafficFollow", 0.5); + params.putFloat("TrafficJerkAcceleration", 50); + params.putFloat("TrafficJerkDeceleration", 50); + params.putFloat("TrafficJerkDanger", 100); + params.putFloat("TrafficJerkSpeed", 50); + params.putFloat("TrafficJerkSpeedDecrease", 50); + trafficFollowToggle->refresh(); + trafficAccelerationToggle->refresh(); + trafficDecelerationToggle->refresh(); + trafficDangerToggle->refresh(); + trafficSpeedToggle->refresh(); + trafficSpeedDecreaseToggle->refresh(); + updateFrogPilotToggles(); + } + }); + + FrogPilotParamValueControl *aggressiveFollowToggle = static_cast(toggles["AggressiveFollow"]); + FrogPilotParamValueControl *aggressiveAccelerationToggle = static_cast(toggles["AggressiveJerkAcceleration"]); + FrogPilotParamValueControl *aggressiveDecelerationToggle = static_cast(toggles["AggressiveJerkDeceleration"]); + FrogPilotParamValueControl *aggressiveDangerToggle = static_cast(toggles["AggressiveJerkDanger"]); + FrogPilotParamValueControl *aggressiveSpeedToggle = static_cast(toggles["AggressiveJerkSpeed"]); + FrogPilotParamValueControl *aggressiveSpeedDecreaseToggle = static_cast(toggles["AggressiveJerkSpeedDecrease"]); + FrogPilotButtonsControl *aggressiveResetButton = static_cast(toggles["ResetAggressivePersonality"]); + QObject::connect(aggressiveResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Aggressive' personality?"), this)) { + params.putFloat("AggressiveFollow", 1.25); + params.putFloat("AggressiveJerkAcceleration", 50); + params.putFloat("AggressiveJerkDeceleration", 50); + params.putFloat("AggressiveJerkDanger", 100); + params.putFloat("AggressiveJerkSpeed", 50); + params.putFloat("AggressiveJerkSpeedDecrease", 50); + aggressiveFollowToggle->refresh(); + aggressiveAccelerationToggle->refresh(); + aggressiveDecelerationToggle->refresh(); + aggressiveDangerToggle->refresh(); + aggressiveSpeedToggle->refresh(); + aggressiveSpeedDecreaseToggle->refresh(); + updateFrogPilotToggles(); + } + }); + + FrogPilotParamValueControl *standardFollowToggle = static_cast(toggles["StandardFollow"]); + FrogPilotParamValueControl *standardAccelerationToggle = static_cast(toggles["StandardJerkAcceleration"]); + FrogPilotParamValueControl *standardDecelerationToggle = static_cast(toggles["StandardJerkDeceleration"]); + FrogPilotParamValueControl *standardDangerToggle = static_cast(toggles["StandardJerkDanger"]); + FrogPilotParamValueControl *standardSpeedToggle = static_cast(toggles["StandardJerkSpeed"]); + FrogPilotParamValueControl *standardSpeedDecreaseToggle = static_cast(toggles["StandardJerkSpeedDecrease"]); + FrogPilotButtonsControl *standardResetButton = static_cast(toggles["ResetStandardPersonality"]); + QObject::connect(standardResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Standard' personality?"), this)) { + params.putFloat("StandardFollow", 1.45); + params.putFloat("StandardJerkAcceleration", 100); + params.putFloat("StandardJerkDeceleration", 100); + params.putFloat("StandardJerkDanger", 100); + params.putFloat("StandardJerkSpeed", 100); + params.putFloat("StandardJerkSpeedDecrease", 100); + standardFollowToggle->refresh(); + standardAccelerationToggle->refresh(); + standardDecelerationToggle->refresh(); + standardDangerToggle->refresh(); + standardSpeedToggle->refresh(); + standardSpeedDecreaseToggle->refresh(); + updateFrogPilotToggles(); + } + }); + + FrogPilotParamValueControl *relaxedFollowToggle = static_cast(toggles["RelaxedFollow"]); + FrogPilotParamValueControl *relaxedAccelerationToggle = static_cast(toggles["RelaxedJerkAcceleration"]); + FrogPilotParamValueControl *relaxedDecelerationToggle = static_cast(toggles["RelaxedJerkDeceleration"]); + FrogPilotParamValueControl *relaxedDangerToggle = static_cast(toggles["RelaxedJerkDanger"]); + FrogPilotParamValueControl *relaxedSpeedToggle = static_cast(toggles["RelaxedJerkSpeed"]); + FrogPilotParamValueControl *relaxedSpeedDecreaseToggle = static_cast(toggles["RelaxedJerkSpeedDecrease"]); + FrogPilotButtonsControl *relaxedResetButton = static_cast(toggles["ResetRelaxedPersonality"]); + QObject::connect(relaxedResetButton, &FrogPilotButtonsControl::buttonClicked, this, [=]() { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset your settings for the 'Relaxed' personality?"), this)) { + params.putFloat("RelaxedFollow", 1.75); + params.putFloat("RelaxedJerkAcceleration", 100); + params.putFloat("RelaxedJerkDeceleration", 100); + params.putFloat("RelaxedJerkDanger", 100); + params.putFloat("RelaxedJerkSpeed", 100); + params.putFloat("RelaxedJerkSpeedDecrease", 100); + relaxedFollowToggle->refresh(); + relaxedAccelerationToggle->refresh(); + relaxedDecelerationToggle->refresh(); + relaxedDangerToggle->refresh(); + relaxedSpeedToggle->refresh(); + relaxedSpeedDecreaseToggle->refresh(); + updateFrogPilotToggles(); + } + }); + QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotLongitudinalPanel::hideToggles); QObject::connect(parent, &FrogPilotSettingsWindow::closeSubParentToggle, this, &FrogPilotLongitudinalPanel::hideSubToggles); QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotLongitudinalPanel::updateCarToggles); @@ -381,6 +594,16 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * updateMetric(); } +void FrogPilotLongitudinalPanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + toggles["ConditionalExperimental"]->setVisible(customizationLevel != 0); + toggles["CurveSpeedControl"]->setVisible(customizationLevel != 0); + toggles["CustomPersonalities"]->setVisible(customizationLevel == 2); + toggles["ExperimentalModeActivation"]->setVisible(customizationLevel != 0); + toggles["QOLLongitudinal"]->setVisible(customizationLevel != 0); +} + void FrogPilotLongitudinalPanel::updateCarToggles() { hasDashSpeedLimits = parent->hasDashSpeedLimits; hasPCMCruise = parent->hasPCMCruise; @@ -411,6 +634,7 @@ void FrogPilotLongitudinalPanel::updateMetric() { params.putFloatNonBlocking("Offset2", params.getFloat("Offset2") * speedConversion); params.putFloatNonBlocking("Offset3", params.getFloat("Offset3") * speedConversion); params.putFloatNonBlocking("Offset4", params.getFloat("Offset4") * speedConversion); + params.putFloatNonBlocking("SetSpeedOffset", params.getFloat("SetSpeedOffset") * speedConversion); } FrogPilotDualParamControl *ceSpeedToggle = reinterpret_cast(toggles["CESpeed"]); @@ -422,6 +646,7 @@ void FrogPilotLongitudinalPanel::updateMetric() { FrogPilotParamValueControl *offset3Toggle = static_cast(toggles["Offset3"]); FrogPilotParamValueControl *offset4Toggle = static_cast(toggles["Offset4"]); FrogPilotParamValueControl *increasedStoppedDistanceToggle = static_cast(toggles["IncreasedStoppedDistance"]); + FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast(toggles["SetSpeedOffset"]); if (isMetric) { offset1Toggle->setTitle(tr("Speed Limit Offset (0-34 kph)")); @@ -429,10 +654,10 @@ void FrogPilotLongitudinalPanel::updateMetric() { offset3Toggle->setTitle(tr("Speed Limit Offset (55-64 kph)")); offset4Toggle->setTitle(tr("Speed Limit Offset (65-99 kph)")); - offset1Toggle->setDescription(tr("Set speed limit offset for limits between 0-34 kph.")); - offset2Toggle->setDescription(tr("Set speed limit offset for limits between 35-54 kph.")); - offset3Toggle->setDescription(tr("Set speed limit offset for limits between 55-64 kph.")); - offset4Toggle->setDescription(tr("Set speed limit offset for limits between 65-99 kph.")); + offset1Toggle->setDescription(tr("Sets the speed limit offset for speeds between 0-34 kph.")); + offset2Toggle->setDescription(tr("Sets the speed limit offset for speeds between 35-54 kph.")); + offset3Toggle->setDescription(tr("Sets the speed limit offset for speeds between 55-64 kph.")); + offset4Toggle->setDescription(tr("Sets the speed limit offset for speeds between 65-99 kph.")); ceSignal->updateControl(0, 150, tr("kph")); ceSpeedToggle->updateControl(0, 150, tr("kph")); @@ -442,18 +667,19 @@ void FrogPilotLongitudinalPanel::updateMetric() { offset2Toggle->updateControl(-99, 99, tr("kph")); offset3Toggle->updateControl(-99, 99, tr("kph")); offset4Toggle->updateControl(-99, 99, tr("kph")); + setSpeedOffsetToggle->updateControl(0, 150, tr("kph")); - increasedStoppedDistanceToggle->updateControl(0, 5, tr(" meters")); + increasedStoppedDistanceToggle->updateControl(0, 3, tr(" meters")); } else { offset1Toggle->setTitle(tr("Speed Limit Offset (0-34 mph)")); offset2Toggle->setTitle(tr("Speed Limit Offset (35-54 mph)")); offset3Toggle->setTitle(tr("Speed Limit Offset (55-64 mph)")); offset4Toggle->setTitle(tr("Speed Limit Offset (65-99 mph)")); - offset1Toggle->setDescription(tr("Set speed limit offset for limits between 0-34 mph.")); - offset2Toggle->setDescription(tr("Set speed limit offset for limits between 35-54 mph.")); - offset3Toggle->setDescription(tr("Set speed limit offset for limits between 55-64 mph.")); - offset4Toggle->setDescription(tr("Set speed limit offset for limits between 65-99 mph.")); + offset1Toggle->setDescription(tr("Sets the speed limit offset for speeds between 0-34 mph.")); + offset2Toggle->setDescription(tr("Sets the speed limit offset for speeds between 35-54 mph.")); + offset3Toggle->setDescription(tr("Sets the speed limit offset for speeds between 55-64 mph.")); + offset4Toggle->setDescription(tr("Sets the speed limit offset for speeds between 65-99 mph.")); ceSignal->updateControl(0, 99, tr("mph")); ceSpeedToggle->updateControl(0, 99, tr("mph")); @@ -463,8 +689,9 @@ void FrogPilotLongitudinalPanel::updateMetric() { offset2Toggle->updateControl(-99, 99, tr("mph")); offset3Toggle->updateControl(-99, 99, tr("mph")); offset4Toggle->updateControl(-99, 99, tr("mph")); + setSpeedOffsetToggle->updateControl(0, 99, tr("mph")); - increasedStoppedDistanceToggle->updateControl(0, 15, tr(" feet")); + increasedStoppedDistanceToggle->updateControl(0, 10, tr(" feet")); } } @@ -482,28 +709,51 @@ void FrogPilotLongitudinalPanel::showToggles(const std::set &keys) { void FrogPilotLongitudinalPanel::hideToggles() { setUpdatesEnabled(false); + customPersonalityOpen = false; slcOpen = false; for (auto &[key, toggle] : toggles) { - bool subToggles = conditionalExperimentalKeys.find(key) != conditionalExperimentalKeys.end() || + bool subToggles = aggressivePersonalityKeys.find(key) != aggressivePersonalityKeys.end() || + conditionalExperimentalKeys.find(key) != conditionalExperimentalKeys.end() || curveSpeedKeys.find(key) != curveSpeedKeys.end() || + customDrivingPersonalityKeys.find(key) != customDrivingPersonalityKeys.end() || experimentalModeActivationKeys.find(key) != experimentalModeActivationKeys.end() || longitudinalTuneKeys.find(key) != longitudinalTuneKeys.end() || qolKeys.find(key) != qolKeys.end() || + relaxedPersonalityKeys.find(key) != relaxedPersonalityKeys.end() || speedLimitControllerKeys.find(key) != speedLimitControllerKeys.end() || speedLimitControllerOffsetsKeys.find(key) != speedLimitControllerOffsetsKeys.end() || speedLimitControllerQOLKeys.find(key) != speedLimitControllerQOLKeys.end() || - speedLimitControllerVisualsKeys.find(key) != speedLimitControllerVisualsKeys.end(); + standardPersonalityKeys.find(key) != standardPersonalityKeys.end() || + trafficPersonalityKeys.find(key) != trafficPersonalityKeys.end(); toggle->setVisible(!subToggles); } + toggles["ConditionalExperimental"]->setVisible(customizationLevel != 0); + toggles["CurveSpeedControl"]->setVisible(customizationLevel != 0); + toggles["CustomPersonalities"]->setVisible(customizationLevel == 2); + toggles["ExperimentalModeActivation"]->setVisible(customizationLevel != 0); + toggles["QOLLongitudinal"]->setVisible(customizationLevel != 0); + setUpdatesEnabled(true); update(); } void FrogPilotLongitudinalPanel::hideSubToggles() { - if (slcOpen) { - showToggles(speedLimitControllerKeys); + if (customPersonalityOpen) { + customPersonalityOpen = false; + showToggles(customDrivingPersonalityKeys); + } else if (slcOpen) { + std::set modifiedSpeedLimitControllerKeys = speedLimitControllerKeys; + + if (customizationLevel == 0) { + modifiedSpeedLimitControllerKeys.erase("SLCFallback"); + modifiedSpeedLimitControllerKeys.erase("SLCOverride"); + modifiedSpeedLimitControllerKeys.erase("SLCPriority"); + modifiedSpeedLimitControllerKeys.erase("SLCQOL"); + } + + showToggles(modifiedSpeedLimitControllerKeys); } } diff --git a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h index 306abfc4..e18c86a9 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h @@ -17,40 +17,58 @@ signals: private: void hideSubToggles(); void hideToggles(); + void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); void updateCarToggles(); void updateMetric(); + std::set aggressivePersonalityKeys = { + "AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", + "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", + "ResetAggressivePersonality" + }; + std::set conditionalExperimentalKeys = { - "CESpeed", "CESpeedLead", "CECurves", "CELead", - "CEModelStopTime", "CENavigation", "CESignalSpeed", - "HideCEMStatusBar" + "CESpeed", "CESpeedLead", "CECurves", + "CELead", "CEModelStopTime", "CENavigation", + "CESignalSpeed", "HideCEMStatusBar" }; std::set curveSpeedKeys = { - "CurveDetectionMethod", "CurveSensitivity", - "DisableCurveSpeedSmoothing", "MTSCCurvatureCheck", - "TurnAggressiveness" + "CurveDetectionMethod", "CurveSensitivity", "DisableCurveSpeedSmoothing", + "MTSCCurvatureCheck", "TurnAggressiveness" + }; + + std::set customDrivingPersonalityKeys = { + "AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", + "TrafficPersonalityProfile" }; std::set experimentalModeActivationKeys = { - "ExperimentalModeViaDistance", "ExperimentalModeViaLKAS", - "ExperimentalModeViaTap" + "ExperimentalModeViaDistance", "ExperimentalModeViaLKAS", "ExperimentalModeViaTap" }; std::set longitudinalTuneKeys = { - "AccelerationProfile", "DecelerationProfile", - "HumanAcceleration", "HumanFollowing", "IncreasedStoppedDistance" + "AccelerationProfile", "DecelerationProfile", "HumanAcceleration", + "HumanFollowing", "IncreasedStoppedDistance", "LeadDetectionThreshold", + "MaxDesiredAcceleration" }; std::set qolKeys = { - "CustomCruise", "CustomCruiseLong", "MapGears", - "OnroadDistanceButton", "ReverseCruise" + "CustomCruise", "CustomCruiseLong", "ForceStandstill", + "ForceStops", "MapGears", "ReverseCruise", + "SetSpeedOffset" + }; + + std::set relaxedPersonalityKeys = { + "RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", + "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", + "ResetRelaxedPersonality" }; std::set speedLimitControllerKeys = { - "SLCConfirmation", "SLCOffsets", "SLCFallback", "SLCOverride", - "SLCPriority", "SLCQOL", "SLCVisuals" + "SLCConfirmation", "SLCOffsets", "SLCFallback", + "SLCOverride", "SLCPriority", "SLCQOL" }; std::set speedLimitControllerOffsetsKeys = { @@ -62,17 +80,26 @@ private: "SLCLookaheadLower" }; - std::set speedLimitControllerVisualsKeys = { - "ShowSLCOffset", "UseVienna" + std::set standardPersonalityKeys = { + "StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", + "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", + "ResetStandardPersonality" + }; + + std::set trafficPersonalityKeys = { + "TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", + "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", + "ResetTrafficPersonality" }; FrogPilotSettingsWindow *parent; FrogPilotButtonsControl *curveDetectionBtn; - FrogPilotButtonsControl *slcConfirmationBtn; Params params; + bool customPersonalityOpen; + bool disableOpenpilotLongitudinal; bool hasPCMCruise; bool hasDashSpeedLimits; bool isGM; @@ -82,5 +109,7 @@ private: bool isToyota; bool slcOpen; + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc new file mode 100644 index 00000000..396995d7 --- /dev/null +++ b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc @@ -0,0 +1,527 @@ +#include "selfdrive/frogpilot/ui/qt/offroad/model_settings.h" + +FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> modelToggles { + {"AutomaticallyUpdateModels", tr("Automatically Update and Download Models"), tr("Automatically downloads new models and updates them if needed."), ""}, + + {"ModelRandomizer", tr("Model Randomizer"), tr("Randomly selects a model each drive and brings up a prompt at the end of the drive to review the model if it's longer than 15 minutes to help find your preferred model."), ""}, + {"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("Controls which models are blacklisted and won't be used for future drives."), ""}, + {"ResetScores", tr("Reset Model Scores"), tr("Clears the ratings you've given to the driving models."), ""}, + {"ReviewScores", tr("Review Model Scores"), tr("Displays the ratings you've assigned to the driving models."), ""}, + + {"DeleteModel", tr("Delete Model"), tr("Removes the selected driving model from your device."), ""}, + {"DownloadModel", tr("Download Model"), tr("Downloads the selected driving model."), ""}, + {"DownloadAllModels", tr("Download All Models"), tr("Downloads all undownloaded driving models."), ""}, + {"SelectModel", tr("Select Model"), tr("Selects which model openpilot uses to drive."), ""}, + {"ResetCalibrations", tr("Reset Model Calibrations"), tr("Resets calibration settings for the driving models."), ""}, + }; + + for (const auto &[param, title, desc, icon] : modelToggles) { + AbstractControl *modelToggle; + + if (param == "ModelRandomizer") { + FrogPilotParamManageControl *modelRandomizerToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(modelRandomizerToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + showToggles(modelRandomizerKeys); + updateModelLabels(); + }); + modelToggle = modelRandomizerToggle; + } else if (param == "ManageBlacklistedModels") { + FrogPilotButtonsControl *blacklistBtn = new FrogPilotButtonsControl(title, desc, {tr("ADD"), tr("REMOVE")}); + QObject::connect(blacklistBtn, &FrogPilotButtonsControl::buttonClicked, [this](int id) { + QStringList blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",", QString::SkipEmptyParts); + QStringList selectableModels = availableModelNames; + + for (QString &model : blacklistedModels) { + selectableModels.removeAll(model); + if (model.contains("(Default)")) { + blacklistedModels.move(blacklistedModels.indexOf(model), 0); + } + } + + if (id == 0) { + if (selectableModels.size() == 1) { + FrogPilotConfirmationDialog::toggleAlert(tr("There's no more models to blacklist! The only available model is \"%1\"!").arg(selectableModels.first()), tr("OK"), this); + } else { + QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to add to the blacklist"), selectableModels, "", this); + if (!selectedModel.isEmpty()) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to add the '%1' model to the blacklist?").arg(selectedModel), tr("Add"), this)) { + if (!blacklistedModels.contains(selectedModel)) { + blacklistedModels.append(selectedModel); + params.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); + paramsStorage.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); + } + } + } + } + } else if (id == 1) { + QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to remove from the blacklist"), blacklistedModels, "", this); + if (!selectedModel.isEmpty()) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to remove the '%1' model from the blacklist?").arg(selectedModel), tr("Remove"), this)) { + if (blacklistedModels.contains(selectedModel)) { + blacklistedModels.removeAll(selectedModel); + params.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); + paramsStorage.putNonBlocking("BlacklistedModels", blacklistedModels.join(",").toStdString()); + } + } + } + } + }); + modelToggle = blacklistBtn; + } else if (param == "ResetScores") { + ButtonControl *resetCalibrationsBtn = new ButtonControl(title, tr("RESET"), desc); + QObject::connect(resetCalibrationsBtn, &ButtonControl::clicked, [this]() { + if (FrogPilotConfirmationDialog::yesorno(tr("Reset all model scores?"), this)) { + for (const QString &model : availableModelNames) { + QString cleanedModel = processModelName(model); + params.remove(QString("%1Drives").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1Drives").arg(cleanedModel).toStdString()); + params.remove(QString("%1Score").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1Score").arg(cleanedModel).toStdString()); + } + updateModelLabels(); + } + }); + modelToggle = reinterpret_cast(resetCalibrationsBtn); + } else if (param == "ReviewScores") { + ButtonControl *reviewScoresBtn = new ButtonControl(title, tr("VIEW"), desc); + QObject::connect(reviewScoresBtn, &ButtonControl::clicked, [this]() { + openSubParentToggle(); + + for (LabelControl *label : labelControls) { + label->setVisible(true); + } + + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + } + }); + modelToggle = reinterpret_cast(reviewScoresBtn); + } else if (param == "DeleteModel") { + deleteModelBtn = new ButtonControl(title, tr("DELETE"), desc); + QObject::connect(deleteModelBtn, &ButtonControl::clicked, [this]() { + QStringList deletableModels, existingModels = modelDir.entryList({"*.thneed"}, QDir::Files); + QMap labelToFileMap; + QString currentModel = QString::fromStdString(params.get("Model")) + ".thneed"; + + for (int i = 0; i < availableModels.size(); ++i) { + QString modelFile = availableModels[i] + ".thneed"; + if (existingModels.contains(modelFile) && modelFile != currentModel && !availableModelNames[i].contains("(Default)")) { + deletableModels.append(availableModelNames[i]); + labelToFileMap[availableModelNames[i]] = modelFile; + } + } + + QString selectedModel = MultiOptionDialog::getSelection(tr("Select a model to delete"), deletableModels, "", this); + if (!selectedModel.isEmpty()) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to delete the '%1' model?").arg(selectedModel), tr("Delete"), this)) { + std::thread([=]() { + modelDeleting = true; + modelsDownloaded = false; + update(); + + params.putBoolNonBlocking("ModelsDownloaded", false); + deleteModelBtn->setValue(tr("Deleting...")); + + QFile::remove(modelDir.absoluteFilePath(labelToFileMap[selectedModel])); + deleteModelBtn->setValue(tr("Deleted!")); + + util::sleep_for(1000); + deleteModelBtn->setValue(""); + modelDeleting = false; + + QStringList modelFiles = modelDir.entryList({"*.thneed"}, QDir::Files); + modelFiles.removeAll(currentModel); + + haveModelsDownloaded = modelFiles.size() > 1; + update(); + }).detach(); + } + } + }); + modelToggle = reinterpret_cast(deleteModelBtn); + } else if (param == "DownloadModel") { + downloadModelBtn = new ButtonControl(title, tr("DOWNLOAD"), desc); + QObject::connect(downloadModelBtn, &ButtonControl::clicked, [this]() { + if (downloadModelBtn->text() == tr("CANCEL")) { + paramsMemory.remove("ModelToDownload"); + paramsMemory.putBool("CancelModelDownload", true); + cancellingDownload = true; + + device()->resetInteractiveTimeout(30); + } else { + QMap labelToModelMap; + QStringList existingModels = modelDir.entryList({"*.thneed"}, QDir::Files); + QStringList downloadableModels; + + for (int i = 0; i < availableModels.size(); ++i) { + QString modelFile = availableModels[i] + ".thneed"; + if (!existingModels.contains(modelFile) && !availableModelNames[i].contains("(Default)")) { + downloadableModels.append(availableModelNames[i]); + labelToModelMap.insert(availableModelNames[i], availableModels[i]); + } + } + + QString modelToDownload = MultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableModels, "", this); + if (!modelToDownload.isEmpty()) { + device()->resetInteractiveTimeout(300); + + modelDownloading = true; + paramsMemory.put("ModelToDownload", labelToModelMap.value(modelToDownload).toStdString()); + paramsMemory.put("ModelDownloadProgress", "0%"); + + downloadModelBtn->setValue(tr("Downloading %1...").arg(modelToDownload.remove(QRegularExpression("[🗺️👀📡]")).trimmed())); + + QTimer *progressTimer = new QTimer(this); + progressTimer->setInterval(100); + + QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { + QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); + bool downloadComplete = progress.contains(QRegularExpression("downloaded", QRegularExpression::CaseInsensitiveOption)); + bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); + + if (!progress.isEmpty() && progress != "0%") { + downloadModelBtn->setValue(progress); + } + + if (downloadComplete || downloadFailed) { + bool lastModelDownloaded = downloadComplete; + + if (downloadComplete) { + haveModelsDownloaded = true; + update(); + } + + if (downloadComplete) { + for (const QString &model : availableModels) { + if (!QFile::exists(modelDir.filePath(model + ".thneed"))) { + lastModelDownloaded = false; + break; + } + } + } + + downloadModelBtn->setValue(progress); + + paramsMemory.remove("CancelModelDownload"); + paramsMemory.remove("ModelDownloadProgress"); + + progressTimer->stop(); + progressTimer->deleteLater(); + + QTimer::singleShot(2000, this, [=]() { + cancellingDownload = false; + modelDownloading = false; + + downloadModelBtn->setValue(""); + + if (lastModelDownloaded) { + modelsDownloaded = true; + update(); + + params.putBoolNonBlocking("ModelsDownloaded", modelsDownloaded); + } + + device()->resetInteractiveTimeout(30); + }); + } + }); + progressTimer->start(); + } + } + }); + modelToggle = reinterpret_cast(downloadModelBtn); + } else if (param == "DownloadAllModels") { + downloadAllModelsBtn = new ButtonControl(title, tr("DOWNLOAD"), desc); + QObject::connect(downloadAllModelsBtn, &ButtonControl::clicked, [this]() { + if (downloadAllModelsBtn->text() == tr("CANCEL")) { + paramsMemory.remove("DownloadAllModels"); + paramsMemory.putBool("CancelModelDownload", true); + cancellingDownload = true; + + device()->resetInteractiveTimeout(30); + } else { + device()->resetInteractiveTimeout(300); + + startDownloadAllModels(); + } + }); + modelToggle = reinterpret_cast(downloadAllModelsBtn); + } else if (param == "SelectModel") { + selectModelBtn = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(selectModelBtn, &ButtonControl::clicked, [this]() { + QSet modelFilesBaseNames = QSet::fromList(modelDir.entryList({"*.thneed"}, QDir::Files).replaceInStrings(QRegExp("\\.thneed$"), "")); + QStringList selectableModels; + + for (int i = 0; i < availableModels.size(); ++i) { + if (modelFilesBaseNames.contains(availableModels[i]) || availableModelNames[i].contains("(Default)")) { + selectableModels.append(availableModelNames[i]); + } + } + + QString modelToSelect = MultiOptionDialog::getSelection(tr("Select a model - 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), selectableModels, "", this); + if (!modelToSelect.isEmpty()) { + selectModelBtn->setValue(modelToSelect); + int modelIndex = availableModelNames.indexOf(modelToSelect); + + params.put("Model", availableModels.at(modelIndex).toStdString()); + params.put("ModelName", modelToSelect.toStdString()); + + if (experimentalModels.contains(availableModels.at(modelIndex))) { + FrogPilotConfirmationDialog::toggleAlert(tr("WARNING: This is a very experimental model and may drive dangerously!"), tr("I understand the risks."), this); + } + + QString model = availableModelNames.at(modelIndex); + QString part_model_param = processModelName(model); + + if (!params.checkKey(part_model_param.toStdString() + "CalibrationParams") || !params.checkKey(part_model_param.toStdString() + "LiveTorqueParameters")) { + if (FrogPilotConfirmationDialog::yesorno(tr("Start with a fresh calibration for the newly selected model?"), this)) { + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + } + } + + if (started) { + if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) { + Hardware::reboot(); + } + } + + updateFrogPilotToggles(); + } + }); + selectModelBtn->setValue(QString::fromStdString(params.get("ModelName"))); + modelToggle = reinterpret_cast(selectModelBtn); + } else if (param == "ResetCalibrations") { + FrogPilotButtonsControl *resetCalibrationsBtn = new FrogPilotButtonsControl(title, desc, {tr("RESET ALL"), tr("RESET ONE")}); + QObject::connect(resetCalibrationsBtn, &FrogPilotButtonsControl::showDescriptionEvent, this, &FrogPilotModelPanel::updateCalibrationDescription); + QObject::connect(resetCalibrationsBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) { + if (id == 0) { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset all of your model calibrations?"), this)) { + for (const QString &model : availableModelNames) { + QString cleanedModel = processModelName(model); + params.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); + params.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); + } + } + } else if (id == 1) { + QStringList selectableModelLabels; + for (int i = 0; i < availableModels.size(); ++i) { + selectableModelLabels.append(availableModelNames[i]); + } + + QString modelToReset = MultiOptionDialog::getSelection(tr("Select a model to reset"), selectableModelLabels, "", this); + if (!modelToReset.isEmpty()) { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely reset this model's calibrations?"), this)) { + QString cleanedModel = processModelName(modelToReset); + params.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1CalibrationParams").arg(cleanedModel).toStdString()); + params.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); + paramsStorage.remove(QString("%1LiveTorqueParameters").arg(cleanedModel).toStdString()); + } + } + } + }); + modelToggle = resetCalibrationsBtn; + + } else { + modelToggle = new ParamControl(param, title, desc, icon); + } + + addItem(modelToggle); + toggles[param] = modelToggle; + + makeConnections(modelToggle); + + if (FrogPilotParamManageControl *frogPilotManageToggle = qobject_cast(modelToggle)) { + QObject::connect(frogPilotManageToggle, &FrogPilotParamManageControl::manageButtonClicked, this, &FrogPilotModelPanel::openParentToggle); + } + + QObject::connect(modelToggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + } + + QObject::connect(static_cast(toggles["ModelRandomizer"]), &ToggleControl::toggleFlipped, [this](bool state) { + modelRandomizer = state; + if (state && !modelsDownloaded) { + if (FrogPilotConfirmationDialog::yesorno(tr("The 'Model Randomizer' only works with downloaded models. Do you want to download all the driving models?"), this)) { + startDownloadAllModels(); + } + } + }); + + QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotModelPanel::hideToggles); + QObject::connect(parent, &FrogPilotSettingsWindow::closeSubParentToggle, this, &FrogPilotModelPanel::hideSubToggles); + QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotModelPanel::updateState); + + hideToggles(); +} + +void FrogPilotModelPanel::showEvent(QShowEvent *event) { + QString currentModel = QString::fromStdString(params.get("Model")) + ".thneed"; + + availableModelNames = QString::fromStdString(params.get("AvailableModelsNames")).split(","); + availableModels = QString::fromStdString(params.get("AvailableModels")).split(","); + experimentalModels = QString::fromStdString(params.get("ExperimentalModels")).split(","); + + modelRandomizer = params.getBool("ModelRandomizer"); + modelsDownloaded = params.getBool("ModelsDownloaded"); + + QStringList modelFiles = modelDir.entryList({"*.thneed"}, QDir::Files); + modelFiles.removeAll(currentModel); + haveModelsDownloaded = modelFiles.size() > 1; +} + +void FrogPilotModelPanel::updateState(const UIState &s) { + if (!isVisible()) return; + + downloadAllModelsBtn->setText(modelDownloading && allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD")); + downloadModelBtn->setText(modelDownloading && !allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD")); + + deleteModelBtn->setEnabled(!modelDeleting && !modelDownloading); + downloadAllModelsBtn->setEnabled(s.scene.online && !cancellingDownload && !modelDeleting && (!modelDownloading || allModelsDownloading) && !modelsDownloaded); + downloadModelBtn->setEnabled(s.scene.online && !cancellingDownload && !modelDeleting && !allModelsDownloading && !modelsDownloaded); + selectModelBtn->setEnabled(!modelDeleting && !modelDownloading && !modelRandomizer); + + started = s.scene.started; +} + +void FrogPilotModelPanel::startDownloadAllModels() { + allModelsDownloading = true; + modelDownloading = true; + + paramsMemory.putBool("DownloadAllModels", true); + + downloadAllModelsBtn->setValue(tr("Downloading models...")); + + QTimer *progressTimer = new QTimer(this); + progressTimer->setInterval(100); + + QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { + QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); + bool downloadComplete = progress.contains(QRegularExpression("All models downloaded!", QRegularExpression::CaseInsensitiveOption)); + bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); + + if (!progress.isEmpty() && progress != "0%") { + downloadAllModelsBtn->setValue(progress); + } + + if (downloadComplete || downloadFailed) { + if (downloadComplete) { + haveModelsDownloaded = true; + update(); + } + + downloadAllModelsBtn->setValue(progress); + + paramsMemory.remove("CancelModelDownload"); + paramsMemory.remove("ModelDownloadProgress"); + + progressTimer->stop(); + progressTimer->deleteLater(); + + QTimer::singleShot(2000, this, [=]() { + cancellingDownload = false; + modelDownloading = false; + + paramsMemory.remove("DownloadAllModels"); + + downloadAllModelsBtn->setValue(""); + + device()->resetInteractiveTimeout(30); + }); + } + }); + progressTimer->start(); +} + +void FrogPilotModelPanel::updateCalibrationDescription() { + QString model = QString::fromStdString(params.get("ModelName")); + QString part_model_param = processModelName(model); + + QString desc = + tr("openpilot requires the device to be mounted within 4° left or right and " + "within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required."); + std::string calib_bytes = params.get(part_model_param.toStdString() + "CalibrationParams"); + if (!calib_bytes.empty()) { + try { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(calib_bytes.data(), calib_bytes.size())); + auto calib = cmsg.getRoot().getLiveCalibration(); + if (calib.getCalStatus() != cereal::LiveCalibrationData::Status::UNCALIBRATED) { + double pitch = calib.getRpyCalib()[1] * (180 / M_PI); + double yaw = calib.getRpyCalib()[2] * (180 / M_PI); + desc += tr(" Your device is pointed %1° %2 and %3° %4.") + .arg(QString::number(std::abs(pitch), 'g', 1), pitch > 0 ? tr("down") : tr("up"), + QString::number(std::abs(yaw), 'g', 1), yaw > 0 ? tr("left") : tr("right")); + } + } catch (kj::Exception) { + qInfo() << "invalid CalibrationParams"; + } + } + qobject_cast(sender())->setDescription(desc); +} + +void FrogPilotModelPanel::updateModelLabels() { + QVector> modelScores; + for (QString &model : availableModelNames) { + QString cleanedModel = processModelName(model); + int score = params.getInt((cleanedModel + "Score").toStdString()); + + if (model.contains("(Default)")) { + modelScores.prepend(qMakePair(model, score)); + } else { + modelScores.append(qMakePair(model, score)); + } + } + + labelControls.clear(); + + for (QPair &pair : modelScores) { + QString scoreDisplay = pair.second == 0 ? "N/A" : QString::number(pair.second) + "%"; + LabelControl *labelControl = new LabelControl(pair.first, scoreDisplay, ""); + labelControls.append(labelControl); + addItem(labelControl); + } + + for (LabelControl *label : labelControls) { + label->setVisible(false); + } +} + +void FrogPilotModelPanel::showToggles(const std::set &keys) { + setUpdatesEnabled(false); + + for (auto &[key, toggle] : toggles) { + toggle->setVisible(keys.find(key) != keys.end()); + } + + setUpdatesEnabled(true); + update(); +} + +void FrogPilotModelPanel::hideToggles() { + setUpdatesEnabled(false); + + for (LabelControl *label : labelControls) { + label->setVisible(false); + } + + for (auto &[key, toggle] : toggles) { + bool subToggles = modelRandomizerKeys.find(key) != modelRandomizerKeys.end(); + + toggle->setVisible(!subToggles); + } + + setUpdatesEnabled(true); + update(); +} + +void FrogPilotModelPanel::hideSubToggles() { + for (LabelControl *label : labelControls) { + label->setVisible(false); + } +} diff --git a/selfdrive/frogpilot/ui/qt/offroad/model_settings.h b/selfdrive/frogpilot/ui/qt/offroad/model_settings.h new file mode 100644 index 00000000..4b7fd1d7 --- /dev/null +++ b/selfdrive/frogpilot/ui/qt/offroad/model_settings.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h" + +class FrogPilotModelPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotModelPanel(FrogPilotSettingsWindow *parent); + +signals: + void openParentToggle(); + void openSubParentToggle(); + +protected: + void showEvent(QShowEvent *event) override; + +private: + void hideSubToggles(); + void hideToggles(); + void showToggles(const std::set &keys); + void startDownloadAllModels(); + void updateCalibrationDescription(); + void updateModelLabels(); + void updateState(const UIState &s); + + std::set modelRandomizerKeys = { + "ManageBlacklistedModels", "ResetScores", "ReviewScores" + }; + + ButtonControl *deleteModelBtn; + ButtonControl *downloadAllModelsBtn; + ButtonControl *downloadModelBtn; + ButtonControl *selectModelBtn; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + Params paramsStorage{"/persist/params"}; + + QDir modelDir{"/data/models/"}; + + QList labelControls; + + QStringList availableModelNames; + QStringList availableModels; + QStringList experimentalModels; + + bool allModelsDownloading; + bool cancellingDownload; + bool haveModelsDownloaded; + bool modelDeleting; + bool modelDownloading; + bool modelRandomizer; + bool modelsDownloaded; + bool started; + + std::map toggles; +}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc index 4aaf032c..e161c0c7 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc @@ -11,12 +11,12 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr {"WarningSoftVolume", tr("Warning Soft Volume"), tr("Related alerts:\n\nBRAKE!, Risk of Collision\nTAKE CONTROL IMMEDIATELY"), ""}, {"WarningImmediateVolume", tr("Warning Immediate Volume"), tr("Related alerts:\n\nDISENGAGE IMMEDIATELY, Driver Distracted\nDISENGAGE IMMEDIATELY, Driver Unresponsive"), ""}, - {"CustomAlerts", tr("Custom Alerts"), tr("Enable custom alerts for openpilot events."), "../frogpilot/assets/toggle_icons/icon_green_light.png"}, - {"GoatScream", tr("Goat Scream Steering Saturated Alert"), tr("Enable the famed 'Goat Scream' that has brought both joy and anger to FrogPilot users all around the world!"), ""}, - {"GreenLightAlert", tr("Green Light Alert"), tr("Get an alert when a traffic light changes from red to green."), ""}, - {"LeadDepartingAlert", tr("Lead Departing Alert"), tr("Get an alert when the lead vehicle starts departing when at a standstill."), ""}, - {"LoudBlindspotAlert", tr("Loud Blindspot Alert"), tr("Enable a louder alert for when a vehicle is detected in the blindspot when attempting to change lanes."), ""}, - {"SpeedLimitChangedAlert", tr("Speed Limit Change Alert"), tr("Trigger an alert when the speed limit changes."), ""}, + {"CustomAlerts", tr("Custom Alerts"), tr("Custom alerts for openpilot events."), "../frogpilot/assets/toggle_icons/icon_green_light.png"}, + {"GoatScream", tr("Goat Scream Steering Saturated Alert"), tr("Enables the famed 'Goat Scream' that has brought both joy and anger to FrogPilot users all around the world!"), ""}, + {"GreenLightAlert", tr("Green Light Alert"), tr("Plays an alert when a traffic light changes from red to green."), ""}, + {"LeadDepartingAlert", tr("Lead Departing Alert"), tr("Plays an alert when the lead vehicle starts departing when at a standstill."), ""}, + {"LoudBlindspotAlert", tr("Loud Blindspot Alert"), tr("Plays a louder alert for when a vehicle is detected in the blindspot when attempting to change lanes."), ""}, + {"SpeedLimitChangedAlert", tr("Speed Limit Change Alert"), tr("Plays an alert when the speed limit changes."), ""}, }; for (const auto &[param, title, desc, icon] : soundsToggles) { @@ -29,10 +29,14 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr }); soundsToggle = alertVolumeControlToggle; } else if (alertVolumeControlKeys.find(param) != alertVolumeControlKeys.end()) { + std::map volumeLabels; + for (int i = 0; i <= 101; ++i) { + volumeLabels[i] = i == 101 ? tr("Auto") : i == 0 ? tr("Muted") : QString::number(i) + "%"; + } if (param == "WarningImmediateVolume") { - soundsToggle = new FrogPilotParamValueControl(param, title, desc, icon, 25, 100, "%"); + soundsToggle = new FrogPilotParamValueControl(param, title, desc, icon, 25, 101, QString(), volumeLabels); } else { - soundsToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, "%"); + soundsToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, QString(), volumeLabels); } } else if (param == "CustomAlerts") { @@ -74,6 +78,12 @@ FrogPilotSoundsPanel::FrogPilotSoundsPanel(FrogPilotSettingsWindow *parent) : Fr QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotSoundsPanel::updateCarToggles); } +void FrogPilotSoundsPanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + toggles["AlertVolumeControl"]->setVisible(customizationLevel == 2); +} + void FrogPilotSoundsPanel::updateCarToggles() { hasBSM = parent->hasBSM; hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; @@ -101,6 +111,8 @@ void FrogPilotSoundsPanel::hideToggles() { toggle->setVisible(!subToggles); } + toggles["AlertVolumeControl"]->setVisible(customizationLevel == 2); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.h b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.h index 7414eeed..11929d59 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.h @@ -15,6 +15,7 @@ signals: private: void hideToggles(); + void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); void updateCarToggles(); @@ -36,5 +37,7 @@ private: bool hasBSM; bool hasOpenpilotLongitudinal; + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc index 88fb36a9..cb8e8da7 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc @@ -3,19 +3,19 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { const std::vector> themeToggles { {"PersonalizeOpenpilot", tr("Custom Theme"), tr("Custom openpilot themes."), "../frogpilot/assets/toggle_icons/frog.png"}, - {"CustomColors", tr("Color Scheme"), tr("Themed color schemes.\n\nWant to submit your own color scheme? Share it in the 'feature-request' channel on the FrogPilot Discord!"), ""}, - {"CustomDistanceIcon", "Distance Button", "Themed distance button icons.\n\nWant to submit your own icon pack? Share it in the 'feature-request' channel on the FrogPilot Discord!", ""}, - {"CustomIcons", tr("Icon Pack"), tr("Themed icon packs.\n\nWant to submit your own icons? Share them in the 'feature-request' channel on the FrogPilot Discord!"), ""}, - {"CustomSounds", tr("Sound Pack"), tr("Themed sound effects.\n\nWant to submit your own sounds? Share them in the 'feature-request' channel on the FrogPilot Discord!"), ""}, - {"WheelIcon", tr("Steering Wheel"), tr("Custom steering wheel icons."), ""}, - {"CustomSignals", tr("Turn Signal Animation"), tr("Themed turn signal animations.\n\nWant to submit your own animations? Share them in the 'feature-request' channel on the FrogPilot Discord!"), ""}, + {"CustomColors", tr("Color Scheme"), tr("Changes out openpilot's color scheme.\n\nWant to submit your own color scheme? Share it in the 'custom-themes' channel on the FrogPilot Discord!"), ""}, + {"CustomDistanceIcons", "Distance Button", "Changes out openpilot's distance button icons.\n\nWant to submit your own icon pack? Share it in the 'custom-themes' channel on the FrogPilot Discord!", ""}, + {"CustomIcons", tr("Icon Pack"), tr("Changes out openpilot's icon pack.\n\nWant to submit your own icons? Share them in the 'custom-themes' channel on the FrogPilot Discord!"), ""}, + {"CustomSounds", tr("Sound Pack"), tr("Changes out openpilot's sound effects.\n\nWant to submit your own sounds? Share them in the 'custom-themes' channel on the FrogPilot Discord!"), ""}, + {"WheelIcon", tr("Steering Wheel"), tr("Enables a custom steering wheel icon in the top right of the screen."), ""}, + {"CustomSignals", tr("Turn Signal Animation"), tr("Enables themed turn signal animations.\n\nWant to submit your own animations? Share them in the 'custom-themes' channel on the FrogPilot Discord!"), ""}, {"DownloadStatusLabel", tr("Download Status"), "", ""}, - {"HolidayThemes", tr("Holiday Themes"), tr("Change the openpilot theme based on the current holiday. Minor holidays last one day, while major holidays (Easter, Christmas, Halloween, etc.) last a week."), "../frogpilot/assets/toggle_icons/icon_calendar.png"}, + {"HolidayThemes", tr("Holiday Themes"), tr("Changes the openpilot theme based on the current holiday. Minor holidays last one day, while major holidays (Easter, Christmas, Halloween, etc.) last the entire week."), "../frogpilot/assets/toggle_icons/icon_calendar.png"}, - {"RandomEvents", tr("Random Events"), tr("Random cosmetic events that happen during certain driving conditions. These events are purely for fun and don't affect driving controls!"), "../frogpilot/assets/toggle_icons/icon_random.png"}, + {"RandomEvents", tr("Random Events"), tr("Enables random cosmetic events that happen during certain driving conditions. These events are purely for fun and don't affect driving controls!"), "../frogpilot/assets/toggle_icons/icon_random.png"}, - {"StartupAlert", tr("Startup Alert"), tr("Custom 'Startup' alert message that appears when you start driving."), "../frogpilot/assets/toggle_icons/icon_message.png"} + {"StartupAlert", tr("Startup Alert"), tr("Controls the text of the 'Startup' alert message that appears when you start the drive."), "../frogpilot/assets/toggle_icons/icon_message.png"} }; for (const auto &[param, title, desc, icon] : themeToggles) { @@ -162,7 +162,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } manageCustomColorsBtn->setValue(currentColor); themeToggle = manageCustomColorsBtn; - } else if (param == "CustomDistanceIcon") { + } else if (param == "CustomDistanceIcons") { manageDistanceIconsBtn = new FrogPilotButtonsControl(title, desc, {tr("DELETE"), tr("DOWNLOAD"), tr("SELECT")}); std::function formatIconName = [](QString name) -> QString { @@ -847,10 +847,10 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr params.put("StartupMessageTop", frogpilotTop.toStdString()); params.put("StartupMessageBottom", frogpilotBottom.toStdString()); } else if (id == 2) { - QString newTop = InputDialog::getText(tr("Enter your text for the top half"), this, tr("Characters: 0/%1").arg(maxLengthTop), false, -1, currentTop, maxLengthTop).trimmed(); + QString newTop = InputDialog::getText(tr("Enter the text for the top half"), this, tr("Characters: 0/%1").arg(maxLengthTop), false, -1, currentTop, maxLengthTop).trimmed(); if (newTop.length() > 0) { params.putNonBlocking("StartupMessageTop", newTop.toStdString()); - QString newBottom = InputDialog::getText(tr("Enter your text for the bottom half"), this, tr("Characters: 0/%1").arg(maxLengthBottom), false, -1, currentBottom, maxLengthBottom).trimmed(); + QString newBottom = InputDialog::getText(tr("Enter the text for the bottom half"), this, tr("Characters: 0/%1").arg(maxLengthBottom), false, -1, currentBottom, maxLengthBottom).trimmed(); if (newBottom.length() > 0) { params.putNonBlocking("StartupMessageBottom", newBottom.toStdString()); } @@ -859,6 +859,8 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr params.remove("StartupMessageTop"); params.remove("StartupMessageBottom"); } + + updateFrogPilotToggles(); }); themeToggle = startupAlertButton; @@ -889,7 +891,6 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr }); QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotThemesPanel::hideToggles); - QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotThemesPanel::updateCarToggles); QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotThemesPanel::updateState); } @@ -900,17 +901,17 @@ void FrogPilotThemesPanel::showEvent(QShowEvent *event) { signalsDownloaded = params.get("DownloadableSignals").empty(); soundsDownloaded = params.get("DownloadableSounds").empty(); wheelsDownloaded = params.get("DownloadableWheels").empty(); -} -void FrogPilotThemesPanel::updateCarToggles() { - disableOpenpilotLongitudinal = parent->disableOpenpilotLongitudinal; - hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; + customizationLevel = parent->customizationLevel; - hideToggles(); + toggles["RandomEvents"]->setVisible(customizationLevel != 0); + toggles["StartupAlert"]->setVisible(customizationLevel == 2); } void FrogPilotThemesPanel::updateState(const UIState &s) { - if (!isVisible()) return; + if (!isVisible()) { + return; + } if (personalizeOpenpilotOpen) { if (themeDownloading) { @@ -999,6 +1000,9 @@ void FrogPilotThemesPanel::hideToggles() { toggle->setVisible(!subToggles); } + toggles["RandomEvents"]->setVisible(customizationLevel != 0); + toggles["StartupAlert"]->setVisible(customizationLevel == 2); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h index ebfe2547..7c08fecb 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h @@ -19,11 +19,10 @@ signals: private: void hideToggles(); void showToggles(const std::set &keys); - void updateCarToggles(); void updateState(const UIState &s); std::set customThemeKeys = { - "CustomColors", "CustomDistanceIcon", "CustomIcons", + "CustomColors", "CustomDistanceIcons", "CustomIcons", "CustomSignals", "CustomSounds", "DownloadStatusLabel", "WheelIcon" }; @@ -45,10 +44,8 @@ private: bool cancellingDownload; bool colorDownloading; bool colorsDownloaded; - bool disableOpenpilotLongitudinal; bool distanceIconDownloading; bool distanceIconsDownloaded; - bool hasOpenpilotLongitudinal; bool iconDownloading; bool iconsDownloaded; bool personalizeOpenpilotOpen; @@ -61,5 +58,7 @@ private: bool wheelDownloading; bool wheelsDownloaded; + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/utilities.cc b/selfdrive/frogpilot/ui/qt/offroad/utilities.cc index 5b8462fb..b64a62db 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/utilities.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/utilities.cc @@ -3,7 +3,7 @@ #include "selfdrive/frogpilot/ui/qt/offroad/utilities.h" UtilitiesPanel::UtilitiesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) { - ButtonControl *flashPandaBtn = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("Use this button to flash the Panda device's firmware if you're running into issues.")); + ButtonControl *flashPandaBtn = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("Flashes the Panda device's firmware if you're running into issues.")); QObject::connect(flashPandaBtn, &ButtonControl::clicked, [=]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda?"), tr("Flash"), this)) { std::thread([=]() { @@ -26,7 +26,7 @@ UtilitiesPanel::UtilitiesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListW }); addItem(flashPandaBtn); - forceStartedBtn = new FrogPilotButtonsControl(tr("Force Started State"), tr("Force openpilot either offroad or onroad."), {tr("OFFROAD"), tr("ONROAD"), tr("OFF")}, true); + forceStartedBtn = new FrogPilotButtonsControl(tr("Force Started State"), tr("Forces openpilot either offroad or onroad."), {tr("OFFROAD"), tr("ONROAD"), tr("OFF")}, true); QObject::connect(forceStartedBtn, &FrogPilotButtonsControl::buttonClicked, [=](int id) { if (id == 0) { paramsMemory.putBool("ForceOffroad", true); @@ -43,7 +43,7 @@ UtilitiesPanel::UtilitiesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListW forceStartedBtn->setCheckedButton(2); addItem(forceStartedBtn); - ButtonControl *resetTogglesBtn = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("Reset your toggle settings back to their default settings.")); + ButtonControl *resetTogglesBtn = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("Resets your toggle settings back to their default settings.")); QObject::connect(resetTogglesBtn, &ButtonControl::clicked, [=]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to completely reset all of your toggle settings?"), tr("Reset"), this)) { std::thread([=] { diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc index d9ed9c4e..5589deee 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc @@ -110,11 +110,11 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) addItem(selectModelButton); selectModelButton->setVisible(false); - ParamControl *forceFingerprint = new ParamControl("ForceFingerprint", tr("Disable Automatic Fingerprint Detection"), tr("Forces the selected fingerprint and prevents it from ever changing."), ""); + forceFingerprint = new ParamControl("ForceFingerprint", tr("Disable Automatic Fingerprint Detection"), tr("Forces the selected fingerprint and prevents it from ever changing."), ""); addItem(forceFingerprint); bool disableOpenpilotLongState = params.getBool("DisableOpenpilotLongitudinal"); - disableOpenpilotLong = new ToggleControl(tr("Disable openpilot Longitudinal Control"), tr("Disable openpilot longitudinal control and use stock ACC instead."), "", disableOpenpilotLongState); + disableOpenpilotLong = new ToggleControl(tr("Disable openpilot Longitudinal Control"), tr("Disables openpilot longitudinal control and uses the car's stock ACC instead."), "", disableOpenpilotLongState); QObject::connect(disableOpenpilotLong, &ToggleControl::toggleFlipped, [this](bool state) { if (state) { if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely disable openpilot longitudinal control?"), this)) { @@ -134,20 +134,20 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) addItem(disableOpenpilotLong); std::vector> vehicleToggles { - {"VoltSNG", tr("2017 Volt Stop and Go Hack"), tr("Force stop and go for the 2017 Chevy Volt."), ""}, - {"ExperimentalGMTune", tr("Experimental GM Tune"), tr("FrogsGoMoo's experimental GM tune that is based on nothing but guesswork. Use at your own risk!"), ""}, - {"LongPitch", tr("Uphill/Downhill Smoothing"), tr("Smoothen the car’s gas and brake response when driving on slopes."), ""}, - {"NewLongAPIGM", tr("Use comma's New Longitudinal API"), tr("Comma's new longitudinal control system that has shown great improvement with acceleration and braking, but has a few issues on some GM vehicles."), ""}, + {"VoltSNG", tr("2017 Volt Stop and Go Hack"), tr("Forces stop and go for the 2017 Chevy Volt."), ""}, + {"ExperimentalGMTune", tr("Experimental GM Tune"), tr("Enables FrogsGoMoo's experimental GM tune that is based on nothing but guesswork. Use at your own risk!"), ""}, + {"LongPitch", tr("Uphill/Downhill Smoothing"), tr("Smoothens the gas and brake response when driving on slopes."), ""}, + {"NewLongAPIGM", tr("Use comma's New Longitudinal API"), tr("Enables comma's new control system that has shown great improvement with acceleration and braking, but has a few issues on some GM vehicles."), ""}, - {"NewLongAPI", tr("Use comma's New Longitudinal API"), tr("Use comma's new longitudinal control system that has shown great improvement with acceleration and braking, but has a few issues on Hyundai/Kia/Genesis."), ""}, + {"NewLongAPI", tr("Use comma's New Longitudinal API"), tr("Enables comma's new control system that has shown great improvement with acceleration and braking, but has a few issues on Hyundai/Kia/Genesis."), ""}, {"CrosstrekTorque", tr("Subaru Crosstrek Torque Increase"), tr("Increases the maximum allowed torque for the Subaru Crosstrek."), ""}, - {"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("Automatically lock the doors when in drive and unlock when in park."), ""}, - {"ClusterOffset", tr("Cluster Speed Offset"), tr("Set the cluster offset openpilot uses to try and match the speed displayed on the dash."), ""}, - {"NewToyotaTune", tr("comma's New Toyota/Lexus Tune"), tr("Activate comma's latest Toyota tuning, expertly crafted by Shane for enhanced vehicle performance."), ""}, - {"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("Use FrogsGoMoo's personal tweaks to the Toyota tune focused around his 2019 Lexus ES 350 to take off a bit quicker and stop a bit smoother."), ""}, - {"SNGHack", tr("Stop and Go Hack"), tr("Force stop and go for vehicles without stock stop and go functionality."), ""}, + {"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("Automatically locks the doors when in drive and unlocks when in park."), ""}, + {"ClusterOffset", tr("Cluster Speed Offset"), tr("Sets the cluster offset openpilot uses to try and match the speed displayed on the dash."), ""}, + {"NewToyotaTune", tr("comma's New Toyota/Lexus Tune"), tr("Enables comma's latest Toyota tuning, expertly crafted by Shane for enhanced vehicle performance."), ""}, + {"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("Enables FrogsGoMoo's personal tweaks to the Toyota tune focused around his 2019 Lexus ES 350 to take off a bit quicker and stop a bit smoother."), ""}, + {"SNGHack", tr("Stop and Go Hack"), tr("Forces stop and go for vehicles without stock stop and go functionality."), ""}, }; for (const auto &[param, title, desc, icon] : vehicleToggles) { @@ -159,7 +159,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) vehicleToggle = new FrogPilotButtonToggleControl(param, title, desc, lockToggles, lockToggleNames); } else if (param == "ClusterOffset") { std::vector clusterOffsetToggleNames{"Reset"}; - vehicleToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map(), 0.001, {}, clusterOffsetToggleNames, false); + vehicleToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map(), 0.001, {}, clusterOffsetToggleNames, false, false); } else { vehicleToggle = new ParamControl(param, title, desc, icon); @@ -216,11 +216,18 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVehiclesPanel::updateState); } +void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + updateToggles(); +} + void FrogPilotVehiclesPanel::updateCarToggles() { disableOpenpilotLongitudinal = parent->disableOpenpilotLongitudinal; hasExperimentalOpenpilotLongitudinal = parent->hasExperimentalOpenpilotLongitudinal; hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; hasSNG = parent->hasSNG; + isBolt = parent->isBolt; isGMPCMCruise = parent->isGMPCMCruise; isImpreza = parent->isImpreza; isToyotaTuneSupported = parent->isToyotaTuneSupported; @@ -230,7 +237,9 @@ void FrogPilotVehiclesPanel::updateCarToggles() { } void FrogPilotVehiclesPanel::updateState(const UIState &s) { - if (!isVisible()) return; + if (!isVisible()) { + return; + } started = s.scene.started; } @@ -243,7 +252,8 @@ void FrogPilotVehiclesPanel::setModels() { void FrogPilotVehiclesPanel::updateToggles() { setUpdatesEnabled(false); - disableOpenpilotLong->setVisible((hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && !isGMPCMCruise) || disableOpenpilotLongitudinal); + disableOpenpilotLong->setVisible((hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && !isGMPCMCruise && customizationLevel == 2) || disableOpenpilotLongitudinal); + forceFingerprint ->setVisible(customizationLevel == 2 || isBolt); selectMakeButton->setValue(carMake); selectModelButton->setValue(carModel); @@ -294,6 +304,14 @@ void FrogPilotVehiclesPanel::updateToggles() { toggle->setVisible(setVisible); } + toggles["ClusterOffset"]->setVisible(toggles["ClusterOffset"]->isVisible() && customizationLevel == 2); + toggles["CrosstrekTorque"]->setVisible(toggles["CrosstrekTorque"]->isVisible() && customizationLevel == 2); + toggles["ExperimentalGMTune"]->setVisible(toggles["ExperimentalGMTune"]->isVisible() && customizationLevel == 2); + toggles["FrogsGoMoosTweak"]->setVisible(toggles["FrogsGoMoosTweak"]->isVisible() && customizationLevel == 2); + toggles["LongPitch"]->setVisible(toggles["LongPitch"]->isVisible() && customizationLevel == 2); + toggles["NewLongAPI"]->setVisible(toggles["NewLongAPI"]->isVisible() && customizationLevel == 2); + toggles["NewToyotaTune"]->setVisible(toggles["NewToyotaTune"]->isVisible() && customizationLevel == 2); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h index 568798a1..1eb992d3 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h @@ -12,12 +12,14 @@ public: private: void setModels(); + void showEvent(QShowEvent *event) override; void updateCarToggles(); void updateState(const UIState &s); void updateToggles(); std::set gmKeys = { - "ExperimentalGMTune", "LongPitch", "NewLongAPIGM", "VoltSNG" + "ExperimentalGMTune", "LongPitch", "NewLongAPIGM", + "VoltSNG" }; std::set hyundaiKeys = { @@ -29,8 +31,8 @@ private: }; std::set longitudinalKeys = { - "ExperimentalGMTune", "LongPitch", "NewLongAPI", "NewLongAPIGM", - "SNGHack", "VoltSNG" + "ExperimentalGMTune", "LongPitch", "NewLongAPI", + "NewLongAPIGM", "SNGHack", "VoltSNG" }; std::set sngKeys = { @@ -42,8 +44,8 @@ private: }; std::set toyotaKeys = { - "ClusterOffset", "FrogsGoMoosTweak", "NewToyotaTune", "SNGHack", - "ToyotaDoors" + "ClusterOffset", "FrogsGoMoosTweak", "NewToyotaTune", + "SNGHack", "ToyotaDoors" }; std::set toyotaTuneKeys = { @@ -59,12 +61,14 @@ private: FrogPilotSettingsWindow *parent; + QMap carModels; + QString carMake; QString carModel; QStringList models; - QMap carModels; + ParamControl *forceFingerprint; Params params; @@ -74,11 +78,14 @@ private: bool hasExperimentalOpenpilotLongitudinal; bool hasOpenpilotLongitudinal; bool hasSNG; + bool isBolt; bool isGMPCMCruise; bool isImpreza; bool isToyotaTuneSupported; bool isVolt; bool started; + int customizationLevel; + std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc index bfa9b392..e058e474 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc @@ -2,40 +2,253 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { const std::vector> visualToggles { - {"CustomUI", tr("Onroad UI Widgets"), tr("Custom FrogPilot widgets used in the onroad user interface."), "../assets/offroad/icon_road.png"}, - {"Compass", tr("Compass"), tr("A compass in the onroad UI to show the current driving direction."), ""}, - {"DynamicPathWidth", tr("Dynamic Path Width"), tr("Automatically adjust the width of the driving path display based on the current engagement state:\n\nFully engaged = 100%\nAlways On Lateral Active = 75%\nFully disengaged = 50%"), ""}, - {"PedalsOnUI", tr("Gas/Brake Pedal Indicators"), tr("Pedal indicators in the onroad UI that change opacity based on the pressure applied."), ""}, - {"CustomPaths", tr("Paths"), tr("Projected acceleration path, detected lanes, and vehicles in the blind spot."), ""}, - {"RoadNameUI", tr("Road Name"), tr("The current road name is displayed at the bottom of the screen using data from 'OpenStreetMap'."), ""}, - {"RotatingWheel", tr("Rotating Steering Wheel"), tr("The steering wheel in the onroad UI rotates along with your steering wheel movements."), ""}, + {"QOLVisuals", tr("Accessibility"), tr("Visual features to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/icon_accessibility.png"}, + {"CameraView", tr("Camera View"), tr("Changes the camera view display. This is purely a visual change and doesn't impact how openpilot drives."), ""}, + {"OnroadDistanceButton", tr("Onroad Personality Button"), tr("Displays the current driving personality on the screen. Tap to switch personalities, or long press for 2.5 seconds to activate 'Traffic' mode."), ""}, + {"DriverCamera", tr("Show Driver Camera When In Reverse"), tr("Displays the driver camera feed when the vehicle is in reverse."), ""}, + {"StandbyMode", tr("Standby Mode"), tr("Turns the screen off when driving and automatically wakes it up if engagement state changes or important alerts occur."), ""}, + {"StoppedTimer", tr("Stopped Timer"), tr("Activates a timer when stopped to indicate how long the vehicle has been stopped for."), ""}, - {"QOLVisuals", tr("Quality of Life Improvements"), tr("Miscellaneous visual focused features to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/quality_of_life.png"}, - {"BigMap", tr("Larger Map Display"), tr("A larger size of the map in the onroad UI for easier navigation readings."), ""}, - {"MapStyle", tr("Map Style"), tr("Custom map styles for the map used during navigation."), ""}, - {"StandbyMode", tr("Screen Standby Mode"), tr("The screen is turned off after it times out when driving, but it automatically wakes up if engagement state changes or important alerts occur."), ""}, - {"DriverCamera", tr("Show Driver Camera When In Reverse"), tr("The driver camera feed is displayed when the vehicle is in reverse."), ""}, - {"StoppedTimer", tr("Stopped Timer"), tr("A timer on the onroad UI to indicate how long the vehicle has been stopped."), ""} + {"AdvancedCustomUI", tr("Advanced UI Controls"), tr("Advanced features to fine tune your personalized UI."), "../frogpilot/assets/toggle_icons/icon_advanced_device.png"}, + {"HideSpeed", tr("Hide Current Speed"), tr("Hides the current speed."), ""}, + {"HideLeadMarker", tr("Hide Lead Marker"), tr("Hides the marker for the vehicle ahead."), ""}, + {"HideMapIcon", tr("Hide Map Icon"), tr("Hides the map icon."), ""}, + {"HideMaxSpeed", tr("Hide Max Speed"), tr("Hides the max speed."), ""}, + {"HideAlerts", tr("Hide Non-Critical Alerts"), tr("Hides non-critical alerts."), ""}, + {"WheelSpeed", tr("Use Wheel Speed"), tr("Uses the wheel speed instead of the cluster speed. This is purely a visual change and doesn't impact how openpilot drives."), ""}, + + {"DeveloperUI", tr("Developer Metrics"), tr("Show detailed information about openpilot's internal operations."), "../assets/offroad/icon_shell.png"}, + {"BorderMetrics", tr("Border Metrics"), tr("Displays performance metrics around the edge of the screen while driving."), ""}, + {"FPSCounter", tr("FPS Display"), tr("Displays the 'Frames Per Second' (FPS) at the bottom of the screen while driving."), ""}, + {"LateralMetrics", tr("Lateral Metrics"), tr("Displays metrics related to steering control at the top of the screen while driving."), ""}, + {"LongitudinalMetrics", tr("Longitudinal Metrics"), tr("Displays metrics related to acceleration, speed, and desired following distance at the top of the screen while driving."), ""}, + {"NumericalTemp", tr("Numerical Temperature Gauge"), tr("Shows exact temperature readings instead of status labels like 'GOOD', 'OK', or 'HIGH' in the sidebar."), ""}, + {"SidebarMetrics", tr("Sidebar"), tr("Displays system information like CPU, GPU, RAM usage, IP address, and storage space in the sidebar."), ""}, + {"UseSI", tr("Use International System of Units"), tr("Displays measurements using the 'International System of Units' (SI)."), ""}, + + {"ModelUI", tr("Model UI"), tr("Customize the model visualizations on the screen."), "../frogpilot/assets/toggle_icons/icon_vtc.png"}, + {"DynamicPathWidth", tr("Dynamic Path Width"), tr("Automatically adjusts the width of the driving path display based on the current engagement state:\n\nFully engaged = 100%\nAlways On Lateral Active = 75%\nFully disengaged = 50%"), ""}, + {"LaneLinesWidth", tr("Lane Lines Width"), tr("Controls the thickness the lane lines appear on the display.\n\nDefault matches the MUTCD standard of 4 inches."), ""}, + {"PathEdgeWidth", tr("Path Edges Width"), tr("Controls the width of the edges of the driving path to represent different modes and statuses.\n\nDefault is 20% of the total path width.\n\nColor Guide:\n- Blue: Navigation\n- Light Blue: 'Always On Lateral'\n- Green: Default\n- Orange: 'Experimental Mode'\n- Red: 'Traffic Mode'\n- Yellow: 'Conditional Experimental Mode' Overridden"), ""}, + {"PathWidth", tr("Path Width"), tr("Controls how wide the driving path appears on your screen.\n\nDefault (6.1 feet / 1.9 meters) matches the width of a 2019 Lexus ES 350."), ""}, + {"RoadEdgesWidth", tr("Road Edges Width"), tr("Controls how thick the road edges appear on the display.\n\nDefault matches half of the MUTCD standard lane line width of 4 inches."), ""}, + {"ShowStoppingPoint", tr("Stopping Point"), tr("Displays an image on the screen where openpilot is detecting a potential red light/stop sign."), ""}, + {"UnlimitedLength", tr("'Unlimited' Road UI"), tr("Extends the display of the path, lane lines, and road edges as far as the model can see."), ""}, + + {"NavigationUI", tr("Navigation Widgets"), tr("Wwidgets focused around navigation."), "../frogpilot/assets/toggle_icons/icon_map.png"}, + {"BigMap", tr("Larger Map Display"), tr("Increases the size of the map for easier navigation readings."), ""}, + {"MapStyle", tr("Map Style"), tr("Swaps out the stock map style for community created ones."), ""}, + {"RoadNameUI", tr("Road Name"), tr("Displays the current road name at the bottom of the screen using data from 'OpenStreetMap'."), ""}, + {"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("Displays the speed limit offset separately in the onroad UI when using 'Speed Limit Controller'."), ""}, + {"UseVienna", tr("Use Vienna-Style Speed Signs"), tr("Forces Vienna-style (EU) speed limit signs instead of MUTCD (US)."), ""}, + + {"CustomUI", tr("Onroad Screen Widgets"), tr("Custom FrogPilot widgets used in the onroad user interface."), "../assets/offroad/icon_road.png"}, + {"AccelerationPath", tr("Acceleration Path"), tr("Projects a path based on openpilot's current desired acceleration or deceleration."), ""}, + {"AdjacentPath", tr("Adjacent Lanes"), tr("Projects paths for the adjascent lanes."), ""}, + {"BlindSpotPath", tr("Blind Spot Path"), tr("Projects a red path when vehicles are detected in the blind spot for the respective lane."), ""}, + {"Compass", tr("Compass"), tr("Displays a compass to show the current driving direction."), ""}, + {"PedalsOnUI", tr("Gas / Brake Pedal Indicators"), tr("Displays pedal indicators to indicate when either of the pedals are currently being used."), ""}, + {"RotatingWheel", tr("Rotating Steering Wheel"), tr("Rotates the steering wheel in the onroad UI rotates along with your steering wheel movements."), ""} }; for (const auto &[param, title, desc, icon] : visualToggles) { AbstractControl *visualToggle; - if (param == "CustomUI") { + if (param == "QOLVisuals") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + std::set modifiedAccessibilityKeys = accessibilityKeys; + + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { + modifiedAccessibilityKeys.erase("OnroadDistanceButton"); + } + + if (customizationLevel == 0) { + modifiedAccessibilityKeys.erase("CameraView"); + modifiedAccessibilityKeys.erase("DriverCamera"); + modifiedAccessibilityKeys.erase("StandbyMode"); + modifiedAccessibilityKeys.erase("StoppedTimer"); + } else if (customizationLevel != 2) { + modifiedAccessibilityKeys.erase("CameraView"); + modifiedAccessibilityKeys.erase("StandbyMode"); + } + + showToggles(modifiedAccessibilityKeys); + }); + visualToggle = qolToggle; + } else if (param == "CameraView") { + std::vector cameraOptions{tr("Auto"), tr("Driver"), tr("Standard"), tr("Wide")}; + ButtonParamControl *preferredCamera = new ButtonParamControl(param, title, desc, icon, cameraOptions); + visualToggle = preferredCamera; + + } else if (param == "AdvancedCustomUI") { + FrogPilotParamManageControl *advancedCustomUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(advancedCustomUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + std::set modifiedAdvancedCustomOnroadUIKeys = advancedCustomOnroadUIKeys; + + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { + modifiedAdvancedCustomOnroadUIKeys.erase("HideLeadMarker"); + } + + showToggles(modifiedAdvancedCustomOnroadUIKeys); + }); + visualToggle = advancedCustomUIToggle; + + } else if (param == "DeveloperUI") { + FrogPilotParamManageControl *developerUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(developerUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + borderMetricsBtn->setVisibleButton(0, hasBSM); + lateralMetricsBtn->setVisibleButton(1, hasAutoTune); + longitudinalMetricsBtn->setVisibleButton(0, hasRadar); + + std::set modifiedDeveloperUIKeys = developerUIKeys; + + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { + modifiedDeveloperUIKeys.erase("LongitudinalMetrics"); + } + + showToggles(modifiedDeveloperUIKeys); + }); + visualToggle = developerUIToggle; + } else if (param == "BorderMetrics") { + std::vector borderToggles{"BlindSpotMetrics", "ShowSteering", "SignalMetrics"}; + std::vector borderToggleNames{tr("Blind Spot"), tr("Steering Torque"), tr("Turn Signal")}; + borderMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, borderToggles, borderToggleNames); + visualToggle = borderMetricsBtn; + } else if (param == "LateralMetrics") { + std::vector lateralToggles{"AdjacentPathMetrics", "TuningInfo"}; + std::vector lateralToggleNames{tr("Adjacent Path Metrics"), tr("Auto Tune")}; + lateralMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, lateralToggles, lateralToggleNames); + visualToggle = lateralMetricsBtn; + } else if (param == "LongitudinalMetrics") { + std::vector longitudinalToggles{"AdjacentLeadsUI", "LeadInfo", "JerkInfo"}; + std::vector longitudinalToggleNames{tr("Adjacent Leads"), tr("Lead Info"), tr("Jerk Values")}; + longitudinalMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, longitudinalToggles, longitudinalToggleNames); + visualToggle = longitudinalMetricsBtn; + } else if (param == "NumericalTemp") { + std::vector temperatureToggles{"Fahrenheit"}; + std::vector temperatureToggleNames{tr("Fahrenheit")}; + visualToggle = new FrogPilotButtonToggleControl(param, title, desc, temperatureToggles, temperatureToggleNames); + } else if (param == "SidebarMetrics") { + std::vector sidebarMetricsToggles{"ShowCPU", "ShowGPU", "ShowIP", "ShowMemoryUsage", "ShowStorageLeft", "ShowStorageUsed"}; + std::vector sidebarMetricsToggleNames{tr("CPU"), tr("GPU"), tr("IP"), tr("RAM"), tr("SSD Left"), tr("SSD Used")}; + FrogPilotButtonToggleControl *sidebarMetricsToggle = new FrogPilotButtonToggleControl(param, title, desc, sidebarMetricsToggles, sidebarMetricsToggleNames, false, 150); + QObject::connect(sidebarMetricsToggle, &FrogPilotButtonToggleControl::buttonClicked, [sidebarMetricsToggle, this](int index) { + if (index == 0) { + params.putBool("ShowGPU", false); + } else if (index == 1) { + params.putBool("ShowCPU", false); + } else if (index == 3) { + params.putBool("ShowStorageLeft", false); + params.putBool("ShowStorageUsed", false); + } else if (index == 4) { + params.putBool("ShowMemoryUsage", false); + params.putBool("ShowStorageUsed", false); + } else if (index == 5) { + params.putBool("ShowMemoryUsage", false); + params.putBool("ShowStorageLeft", false); + } + sidebarMetricsToggle->refresh(); + }); + visualToggle = sidebarMetricsToggle; + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + std::set modifiedModelUIKeys = modelUIKeys; + + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { + modifiedModelUIKeys.erase("ShowStoppingPoint"); + } + + showToggles(modifiedModelUIKeys); + }); + visualToggle = modelUIToggle; + } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { + visualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, tr(" inches")); + } else if (param == "PathEdgeWidth") { + visualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, tr("%")); + } else if (param == "PathWidth") { + visualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet"), std::map(), 0.1); + } else if (param == "ShowStoppingPoint") { + std::vector stoppingPointToggles{"ShowStoppingPointMetrics"}; + std::vector stoppingPointToggleNames{tr("Show Distance")}; + visualToggle = new FrogPilotButtonToggleControl(param, title, desc, stoppingPointToggles, stoppingPointToggleNames); + + } else if (param == "NavigationUI") { FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - customPathsBtn->setVisibleButton(0, hasBSM); + std::set modifiedNavigationUIKeys = navigationUIKeys; + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal || !params.getBool("SpeedLimitController")) { + modifiedNavigationUIKeys.erase("ShowSLCOffset"); + } + + if (customizationLevel != 2) { + modifiedNavigationUIKeys.erase("MapStyle"); + modifiedNavigationUIKeys.erase("RoadNameUI"); + modifiedNavigationUIKeys.erase("ShowSLCOffset"); + modifiedNavigationUIKeys.erase("UseVienna"); + } + + showToggles(modifiedNavigationUIKeys); + }); + visualToggle = customUIToggle; + } else if (param == "BigMap") { + std::vector mapToggles{"FullMap"}; + std::vector mapToggleNames{tr("Full Map")}; + visualToggle = new FrogPilotButtonToggleControl(param, title, desc, mapToggles, mapToggleNames); + } else if (param == "MapStyle") { + QMap styleMap { + {0, tr("Stock openpilot")}, + {1, tr("Mapbox Streets")}, + {2, tr("Mapbox Outdoors")}, + {3, tr("Mapbox Light")}, + {4, tr("Mapbox Dark")}, + {5, tr("Mapbox Satellite")}, + {6, tr("Mapbox Satellite Streets")}, + {7, tr("Mapbox Navigation Day")}, + {8, tr("Mapbox Navigation Night")}, + {9, tr("Mapbox Traffic Night")}, + {10, tr("mike854's (Satellite hybrid)")} + }; + + ButtonControl *mapStyleButton = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(mapStyleButton, &ButtonControl::clicked, [this, mapStyleButton, styleMap]() { + QString selection = MultiOptionDialog::getSelection(tr("Select a map style"), styleMap.values(), "", this); + if (!selection.isEmpty()) { + int selectedStyle = styleMap.key(selection); + params.putInt("MapStyle", selectedStyle); + mapStyleButton->setValue(selection); + updateFrogPilotToggles(); + } + }); + int currentStyle = params.getInt("MapStyle"); + mapStyleButton->setValue(styleMap[currentStyle]); + + visualToggle = mapStyleButton; + + } else if (param == "CustomUI") { + FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { std::set modifiedCustomOnroadUIKeys = customOnroadUIKeys; + if (!hasBSM) { + modifiedCustomOnroadUIKeys.erase("BlindSpotPath"); + } + + if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) { + modifiedCustomOnroadUIKeys.erase("AccelerationPath"); + modifiedCustomOnroadUIKeys.erase("PedalsOnUI"); + } + + if (customizationLevel != 2) { + modifiedCustomOnroadUIKeys.erase("AdjacentPath"); + } + showToggles(modifiedCustomOnroadUIKeys); }); visualToggle = customUIToggle; - } else if (param == "CustomPaths") { - std::vector pathToggles{"AccelerationPath", "AdjacentPath", "BlindSpotPath"}; - std::vector pathToggleNames{tr("Acceleration"), tr("Adjacent"), tr("Blind Spot")}; - customPathsBtn = new FrogPilotButtonToggleControl(param, title, desc, pathToggles, pathToggleNames); - visualToggle = customPathsBtn; } else if (param == "PedalsOnUI") { std::vector pedalsToggles{"DynamicPedalsOnUI", "StaticPedalsOnUI"}; std::vector pedalsToggleNames{tr("Dynamic"), tr("Static")}; @@ -49,49 +262,6 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : }); visualToggle = pedalsToggle; - } else if (param == "QOLVisuals") { - FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - showToggles(qolKeys); - }); - visualToggle = qolToggle; - } else if (param == "BigMap") { - std::vector mapToggles{"FullMap"}; - std::vector mapToggleNames{tr("Full Map")}; - visualToggle = new FrogPilotButtonToggleControl(param, title, desc, mapToggles, mapToggleNames); - } else if (param == "MapStyle") { - QMap styleMap = { - {0, tr("Stock openpilot")}, - {1, tr("Mapbox Streets")}, - {2, tr("Mapbox Outdoors")}, - {3, tr("Mapbox Light")}, - {4, tr("Mapbox Dark")}, - {5, tr("Mapbox Satellite")}, - {6, tr("Mapbox Satellite Streets")}, - {7, tr("Mapbox Navigation Day")}, - {8, tr("Mapbox Navigation Night")}, - {9, tr("Mapbox Traffic Night")}, - {10, tr("mike854's (Satellite hybrid)")}, - }; - - QStringList styles = styleMap.values(); - ButtonControl *mapStyleButton = new ButtonControl(title, tr("SELECT"), desc); - QObject::connect(mapStyleButton, &ButtonControl::clicked, [=]() { - QStringList styles = styleMap.values(); - QString selection = MultiOptionDialog::getSelection(tr("Select a map style"), styles, "", this); - if (!selection.isEmpty()) { - int selectedStyle = styleMap.key(selection); - params.putIntNonBlocking("MapStyle", selectedStyle); - mapStyleButton->setValue(selection); - updateFrogPilotToggles(); - } - }); - - int currentStyle = params.getInt("MapStyle"); - mapStyleButton->setValue(styleMap[currentStyle]); - - visualToggle = mapStyleButton; - } else { visualToggle = new ParamControl(param, title, desc, icon); } @@ -112,14 +282,67 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideToggles); QObject::connect(parent, &FrogPilotSettingsWindow::updateCarToggles, this, &FrogPilotVisualsPanel::updateCarToggles); + QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric); +} + +void FrogPilotVisualsPanel::showEvent(QShowEvent *event) { + customizationLevel = parent->customizationLevel; + + toggles["AdvancedCustomUI"]->setVisible(customizationLevel == 2); + toggles["CustomUI"]->setVisible(customizationLevel != 0); + toggles["DeveloperUI"]->setVisible(customizationLevel == 2); + toggles["ModelUI"]->setVisible(customizationLevel == 2); + toggles["NavigationUI"]->setVisible(customizationLevel != 0); + toggles["QOLVisuals"]->setVisible(customizationLevel != 0 || !disableOpenpilotLongitudinal && hasOpenpilotLongitudinal); } void FrogPilotVisualsPanel::updateCarToggles() { + disableOpenpilotLongitudinal = parent->disableOpenpilotLongitudinal; + hasAutoTune = parent->hasAutoTune; hasBSM = parent->hasBSM; + hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; + hasRadar = parent->hasRadar; hideToggles(); } +void FrogPilotVisualsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double smallDistanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; + double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + + params.putFloatNonBlocking("LaneLinesWidth", params.getFloat("LaneLinesWidth") * smallDistanceConversion); + params.putFloatNonBlocking("RoadEdgesWidth", params.getFloat("RoadEdgesWidth") * smallDistanceConversion); + + params.putFloatNonBlocking("PathWidth", params.getFloat("PathWidth") * distanceConversion); + } + + FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); + FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); + + if (isMetric) { + laneLinesWidthToggle->setDescription(tr("Adjust how thick the lane lines appear on the display.\n\nDefault matches the Vienna standard of 10 centimeters.")); + roadEdgesWidthToggle->setDescription(tr("Adjust how thick the road edges appear on the display.\n\nDefault matches half of the Vienna standard of 10 centimeters.")); + + laneLinesWidthToggle->updateControl(0, 60, tr(" centimeters")); + roadEdgesWidthToggle->updateControl(0, 60, tr(" centimeters")); + + pathWidthToggle->updateControl(0, 3, tr(" meters")); + } else { + laneLinesWidthToggle->setDescription(tr("Adjust how thick the lane lines appear on the display.\n\nDefault matches the MUTCD standard of 4 inches.")); + roadEdgesWidthToggle->setDescription(tr("Adjust how thick the road edges appear on the display.\n\nDefault matches half of the MUTCD standard of 4 inches.")); + + laneLinesWidthToggle->updateControl(0, 24, tr(" inches")); + roadEdgesWidthToggle->updateControl(0, 24, tr(" inches")); + + pathWidthToggle->updateControl(0, 10, tr(" feet")); + } +} + void FrogPilotVisualsPanel::showToggles(const std::set &keys) { setUpdatesEnabled(false); @@ -135,12 +358,23 @@ void FrogPilotVisualsPanel::hideToggles() { setUpdatesEnabled(false); for (auto &[key, toggle] : toggles) { - bool subToggles = customOnroadUIKeys.find(key) != customOnroadUIKeys.end() || - qolKeys.find(key) != qolKeys.end(); + bool subToggles = accessibilityKeys.find(key) != accessibilityKeys.end() || + advancedCustomOnroadUIKeys.find(key) != advancedCustomOnroadUIKeys.end() || + customOnroadUIKeys.find(key) != customOnroadUIKeys.end() || + developerUIKeys.find(key) != developerUIKeys.end() || + modelUIKeys.find(key) != modelUIKeys.end() || + navigationUIKeys.find(key) != navigationUIKeys.end(); toggle->setVisible(!subToggles); } + toggles["AdvancedCustomUI"]->setVisible(customizationLevel == 2); + toggles["CustomUI"]->setVisible(customizationLevel != 0); + toggles["DeveloperUI"]->setVisible(customizationLevel == 2); + toggles["ModelUI"]->setVisible(customizationLevel == 2); + toggles["NavigationUI"]->setVisible(customizationLevel != 0); + toggles["QOLVisuals"]->setVisible(customizationLevel != 0 || !disableOpenpilotLongitudinal && hasOpenpilotLongitudinal); + setUpdatesEnabled(true); update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h index 0a4dd5a5..ea88ee6c 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h @@ -15,26 +15,59 @@ signals: private: void hideToggles(); + void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); void updateCarToggles(); + void updateMetric(); - std::set customOnroadUIKeys = { - "Compass", "CustomPaths", "DynamicPathWidth", - "PedalsOnUI", "RoadNameUI", "RotatingWheel" - }; - - std::set qolKeys = { - "BigMap", "DriverCamera", "MapStyle", + std::set accessibilityKeys = { + "CameraView", "DriverCamera", "OnroadDistanceButton", "StandbyMode", "StoppedTimer" }; - FrogPilotSettingsWindow *parent; + std::set advancedCustomOnroadUIKeys = { + "HideAlerts", "HideLeadMarker", "HideMapIcon", + "HideMaxSpeed", "HideSpeed", "WheelSpeed" + }; - FrogPilotButtonToggleControl *customPathsBtn; + std::set customOnroadUIKeys = { + "AccelerationPath", "AdjacentPath", "BlindSpotPath", + "Compass", "PedalsOnUI", "RotatingWheel" + }; + + std::set developerUIKeys = { + "BorderMetrics", "FPSCounter", "LateralMetrics", + "LongitudinalMetrics", "NumericalTemp", + "SidebarMetrics", "UseSI" + }; + + std::set modelUIKeys = { + "DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", + "PathWidth", "RoadEdgesWidth", "ShowStoppingPoint", + "UnlimitedLength" + }; + + std::set navigationUIKeys = { + "BigMap", "MapStyle", "RoadNameUI", + "ShowSLCOffset", "UseVienna" + }; + + FrogPilotButtonToggleControl *borderMetricsBtn; + FrogPilotButtonToggleControl *lateralMetricsBtn; + FrogPilotButtonToggleControl *longitudinalMetricsBtn; + + FrogPilotSettingsWindow *parent; Params params; + bool disableOpenpilotLongitudinal; + bool hasAutoTune; bool hasBSM; + bool hasOpenpilotLongitudinal; + bool hasRadar; + bool isMetric = params.getBool("IsMetric"); + + int customizationLevel; std::map toggles; }; diff --git a/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc index 07586a88..bcae7692 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc @@ -61,13 +61,6 @@ void DriveStats::addStatsLayouts(const QString &title, StatsLabels &labels, bool main_layout->addStretch(1); } -void DriveStats::updateFrogPilotStats(const QJsonObject &obj, StatsLabels &labels) { - labels.routes->setText(QString::number(paramsTracking.getInt("FrogPilotDrives"))); - labels.distance->setText(QString::number(int(paramsTracking.getFloat("FrogPilotKilometers") * (metric ? 1 : KM_TO_MILE)))); - labels.distance_unit->setText(getDistanceUnit()); - labels.hours->setText(QString::number(int(paramsTracking.getFloat("FrogPilotMinutes") / 60))); -} - void DriveStats::updateStatsForLabel(const QJsonObject &obj, StatsLabels &labels) { labels.routes->setText(QString::number((int)obj["routes"].toDouble())); labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1)))); @@ -75,12 +68,22 @@ void DriveStats::updateStatsForLabel(const QJsonObject &obj, StatsLabels &labels labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); } +void DriveStats::updateFrogPilotStats(const QJsonObject &obj, StatsLabels &labels) { + labels.routes->setText(QString::number(paramsTracking.getInt("FrogPilotDrives"))); + labels.distance->setText(QString::number(int(paramsTracking.getFloat("FrogPilotKilometers") * (metric ? 1 : KM_TO_MILE)))); + labels.distance_unit->setText(getDistanceUnit()); + labels.hours->setText(QString::number(int(paramsTracking.getFloat("FrogPilotMinutes") / 60))); +} + void DriveStats::updateStats() { QJsonObject json = stats.object(); updateFrogPilotStats(json["frogpilot"].toObject(), frogPilot); updateStatsForLabel(json["all"].toObject(), all); updateStatsForLabel(json["week"].toObject(), week); + + int all_time_minutes = (int)(json["all"].toObject()["minutes"].toDouble()); + params.put("openpilotMinutes", QString::number(all_time_minutes).toStdString()); } void DriveStats::parseResponse(const QString &response, bool success) { diff --git a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc index c135a393..242f8cea 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc +++ b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc @@ -6,26 +6,7 @@ void updateFrogPilotToggles() { static Params paramsMemory{"/dev/shm/params"}; - static std::atomic isUpdating(false); - static std::thread resetThread; - - bool expected = false; - if (!isUpdating.compare_exchange_strong(expected, true)) { - return; - } - - if (resetThread.joinable()) { - resetThread.join(); - } - paramsMemory.putBool("FrogPilotTogglesUpdated", true); - - resetThread = std::thread([&]() { - util::sleep_for(1000); - paramsMemory.putBool("FrogPilotTogglesUpdated", false); - - isUpdating.store(false); - }); } QColor loadThemeColors(const QString &colorKey, bool clearCache) { diff --git a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h index d456abbe..86178cbd 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h +++ b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h @@ -197,7 +197,7 @@ public: for (int i = 0; i < buttons.size(); ++i) { QAbstractButton *button = buttons[i]; if (button) { - button->setVisible(state); + button->setEnabled(state); button->setChecked(params.getBool(buttonParams[i].toStdString())); } } @@ -280,6 +280,8 @@ class FrogPilotParamValueControl : public AbstractControl { Q_OBJECT public: + QLabel *valueLabel; + FrogPilotParamValueControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const float minValue, const float maxValue, const QString &label = "", const std::map &valueLabels = {}, const float interval = 1.0f, const bool compactSize = false, const bool instantUpdate = false) @@ -379,7 +381,7 @@ private: } void updateValueDisplay() { - int intValue = static_cast(value); + int intValue = static_cast(value / interval); if (valueLabels.count(intValue)) { valueLabel->setText(valueLabels.at(intValue)); } else { @@ -411,8 +413,6 @@ private: Params params; - QLabel *valueLabel; - QPushButton decrementButton; QPushButton incrementButton; @@ -442,12 +442,11 @@ public: const float minValue, const float maxValue, const QString &label = "", const std::map &valueLabels = {}, const float interval = 1.0f, const std::vector &buttonParams = {}, const std::vector &buttonLabels = {}, - const bool checkable = true, const int minimumButtonWidth = 225) + const bool leftButton = false, const bool checkable = true, const int minimumButtonWidth = 225) : FrogPilotParamValueControl(param, title, desc, icon, minValue, maxValue, label, valueLabels, interval, true), buttonParams(buttonParams), buttonGroup(new QButtonGroup(this)), checkable(checkable) { - buttonGroup->setExclusive(false); for (int i = 0; i < buttonLabels.size(); ++i) { @@ -456,7 +455,11 @@ public: button->setStyleSheet(buttonStyle); button->setMinimumWidth(minimumButtonWidth); - hlayout->addWidget(button); + if (leftButton) { + hlayout->insertWidget(hlayout->indexOf(valueLabel) - 1, button); + } else { + hlayout->addWidget(button); + } buttonGroup->addButton(button, i); } diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 363f1859..268634e5 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -20,7 +20,7 @@ from openpilot.common.realtime import set_realtime_priority from openpilot.common.transformations.orientation import rot_from_euler, euler_from_rot from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles MIN_SPEED_FILTER = 15 * CV.MPH_TO_MS MAX_VEL_ANGLE_STD = np.radians(0.25) @@ -61,19 +61,13 @@ def moving_avg_with_linear_decay(prev_mean: np.ndarray, new_val: np.ndarray, idx class Calibrator: def __init__(self, param_put: bool = False): - # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - - self.update_toggles = False - self.param_put = param_put self.not_car = False # Read saved calibration self.params = Params() - self.calibration_key = frogpilot_toggles.part_model_param + "CalibrationParams" + self.calibration_key = get_frogpilot_toggles(True).part_model_param + "CalibrationParams" calibration_params = self.params.get(self.calibration_key) rpy_init = RPY_INIT wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT @@ -175,13 +169,6 @@ class Calibrator: if self.param_put and write_this_cycle: self.params.put_nonblocking(self.calibration_key, self.get_msg(True).to_bytes()) - # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False - def handle_v_ego(self, v_ego: float) -> None: self.v_ego = v_ego diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index e457096b..29a5eff2 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -11,7 +11,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles HISTORY = 5 # secs POINTS_PER_BUCKET = 1500 @@ -52,13 +52,7 @@ class TorqueBuckets(PointBuckets): class TorqueEstimator(ParameterEstimator): - def __init__(self, CP, decimated=False): - # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - - self.update_toggles = False - + def __init__(self, CP, torque_cache, decimated=False): self.hist_len = int(HISTORY / DT_MDL) self.lag = CP.steerActuatorDelay + .2 # from controlsd if decimated: @@ -101,8 +95,6 @@ class TorqueEstimator(ParameterEstimator): # try to restore cached params params = Params() params_cache = params.get("CarParamsPrevRoute") - self.torque_key = frogpilot_toggles.part_model_param + "LiveTorqueParameters" - torque_cache = params.get(self.torque_key) if params_cache is not None and torque_cache is not None: try: with log.Event.from_bytes(torque_cache) as log_evt: @@ -165,13 +157,6 @@ class TorqueEstimator(ParameterEstimator): self.filtered_params[param].update(value) self.filtered_params[param].update_alpha(self.decay) - # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False - def handle_log(self, t, which, msg): if which == "carControl": self.raw_points["carControl_t"].append(t + self.lag) @@ -239,16 +224,12 @@ def main(demo=False): sm = messaging.SubMaster(['carControl', 'carOutput', 'carState', 'liveLocationKalman'], poll='liveLocationKalman') params = Params() - with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP: - estimator = TorqueEstimator(CP) - - # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - - torque_key = frogpilot_toggles.part_model_param + "LiveTorqueParameters" + torque_key = get_frogpilot_toggles(True).part_model_param + "LiveTorqueParameters" torque_cache = params.get(torque_key) + with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP: + estimator = TorqueEstimator(CP, torque_cache) + while True: sm.update() if sm.all_checks(): diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 86cea2e0..ea242e3f 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -26,7 +26,7 @@ from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext from openpilot.selfdrive.frogpilot.frogpilot_functions import MODELS_PATH -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles PROCESS_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') @@ -134,12 +134,6 @@ class ModelState: def main(demo=False): - # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() - - update_toggles = False - cloudlog.warning("modeld init") sentry.set_tag("daemon", PROCESS_NAME) @@ -150,6 +144,10 @@ def main(demo=False): cloudlog.warning("setting up CL context") cl_context = CLContext() cloudlog.warning("CL context ready; loading model") + + # FrogPilot variables + frogpilot_toggles = get_frogpilot_toggles(True) + model = ModelState(cl_context, frogpilot_toggles) cloudlog.warning("models loaded, modeld starting") @@ -311,11 +309,8 @@ def main(demo=False): last_vipc_frame_id = meta_main.frame_id # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - update_toggles = True - elif update_toggles: - FrogPilotVariables.update_frogpilot_params() - update_toggles = False + if sm['frogpilotPlan'].togglesUpdated: + frogpilot_toggles = get_frogpilot_toggles() if __name__ == "__main__": try: diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index 40f25b1a..1387f823 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -18,7 +18,7 @@ from openpilot.selfdrive.navd.helpers import (Coordinate, coordinate_from_param, parse_banner_instructions) from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles, has_prime REROUTE_DISTANCE = 25 MANEUVER_TRANSITION_THRESHOLD = 10 @@ -57,7 +57,7 @@ class RouteEngine: if "MAPBOX_TOKEN" in os.environ: self.mapbox_token = os.environ["MAPBOX_TOKEN"] self.mapbox_host = "https://api.mapbox.com" - elif not FrogPilotVariables.has_prime: + elif not has_prime(): self.mapbox_token = self.params.get("MapboxSecretKey", encoding='utf8') self.mapbox_host = "https://api.mapbox.com" else: @@ -65,15 +65,13 @@ class RouteEngine: self.mapbox_host = os.getenv('MAPS_HOST', 'https://maps.comma.ai') # FrogPilot variables - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + self.frogpilot_toggles = get_frogpilot_toggles(True) self.stop_coord = [] self.stop_signal = [] self.approaching_intersection = False self.approaching_turn = False - self.update_toggles = False self.nav_speed_limit = 0 @@ -96,11 +94,8 @@ class RouteEngine: cloudlog.exception("navd.failed_to_compute") # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() - self.update_toggles = False + if self.sm['frogpilotPlan'].togglesUpdated: + self.frogpilot_toggles = get_frogpilot_toggles() def update_location(self): location = self.sm['liveLocationKalman'] @@ -467,7 +462,7 @@ class RouteEngine: def main(): pm = messaging.PubMaster(['navInstruction', 'navRoute', 'frogpilotNavigation']) - sm = messaging.SubMaster(['carState', 'liveLocationKalman', 'managerState']) + sm = messaging.SubMaster(['carState', 'liveLocationKalman', 'managerState', 'frogpilotPlan']) rk = Ratekeeper(1.0) route_engine = RouteEngine(sm, pm) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 2d64a829..aa9587dc 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -46,12 +46,12 @@ frogpilot_src = ["../frogpilot/navigation/ui/maps_settings.cc", "../frogpilot/na "../frogpilot/screenrecorder/omx_encoder.cc", "../frogpilot/screenrecorder/screenrecorder.cc", "../frogpilot/navigation/ui/navigation_functions.cc", "../frogpilot/ui/qt/widgets/drive_stats.cc", "../frogpilot/ui/qt/widgets/frogpilot_controls.cc", "../frogpilot/ui/qt/widgets/model_reviewer.cc", - "../frogpilot/ui/qt/offroad/advanced_driving_settings.cc", "../frogpilot/ui/qt/offroad/advanced_visual_settings.cc", "../frogpilot/ui/qt/offroad/data_settings.cc", "../frogpilot/ui/qt/offroad/device_settings.cc", "../frogpilot/ui/qt/offroad/frogpilot_settings.cc", "../frogpilot/ui/qt/offroad/longitudinal_settings.cc", - "../frogpilot/ui/qt/offroad/lateral_settings.cc", "../frogpilot/ui/qt/offroad/sounds_settings.cc", - "../frogpilot/ui/qt/offroad/theme_settings.cc", "../frogpilot/ui/qt/offroad/utilities.cc", - "../frogpilot/ui/qt/offroad/vehicle_settings.cc", "../frogpilot/ui/qt/offroad/visual_settings.cc"] + "../frogpilot/ui/qt/offroad/lateral_settings.cc", "../frogpilot/ui/qt/offroad/model_settings.cc", + "../frogpilot/ui/qt/offroad/sounds_settings.cc", "../frogpilot/ui/qt/offroad/theme_settings.cc", + "../frogpilot/ui/qt/offroad/utilities.cc", "../frogpilot/ui/qt/offroad/vehicle_settings.cc", + "../frogpilot/ui/qt/offroad/visual_settings.cc"] qt_src += frogpilot_src diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 43a59ecd..e8f39cca 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -249,7 +249,10 @@ void OffroadHome::hideEvent(QHideEvent *event) { } void OffroadHome::refresh() { - QString model = QString::fromStdString(params.get("ModelName")); + QString model = QString::fromStdString(params.get("ModelName")).remove(QRegularExpression("[🗺️👀📡]")).trimmed(); + if (params.getBool("CustomizationLevelConfirmed") && params.getInt("CustomizationLevel") != 2) { + model = QString::fromStdString(params.get("DefaultModelName")); + } if (model.contains("(Default)")) { model = model.remove("(Default)").trimmed(); diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index f0fd395a..74a0cdd8 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -363,7 +363,7 @@ void DevicePanel::showEvent(QShowEvent *event) { ListWidget::showEvent(event); // Frogpilot variables - resetCalibBtn->setVisible(!params.getBool("ModelManagement")); + resetCalibBtn->setVisible(params.getInt("CustomizationLevel") != 2); } void SettingsWindow::hideEvent(QHideEvent *event) { @@ -377,7 +377,6 @@ void SettingsWindow::hideEvent(QHideEvent *event) { panelOpen = false; parentToggleOpen = false; subParentToggleOpen = false; - subSubParentToggleOpen = false; } void SettingsWindow::showEvent(QShowEvent *event) { @@ -422,9 +421,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { } else if (mapSelectionOpen) { closeMapSelection(); mapSelectionOpen = false; - } else if (subSubParentToggleOpen) { - closeSubSubParentToggle(); - subSubParentToggleOpen = false; } else if (subParentToggleOpen) { closeSubParentToggle(); subParentToggleOpen = false; @@ -451,12 +447,12 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { QObject::connect(toggles, &TogglesPanel::updateMetric, this, &SettingsWindow::updateMetric); FrogPilotSettingsWindow *frogpilotSettingsWindow = new FrogPilotSettingsWindow(this); + QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::closeMapBoxInstructions, [this]() {mapboxInstructionsOpen=false;}); QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openMapBoxInstructions, [this]() {mapboxInstructionsOpen=true;}); QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openMapSelection, [this]() {mapSelectionOpen=true;}); QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openPanel, [this]() {panelOpen=true;}); QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openParentToggle, [this]() {parentToggleOpen=true;}); QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openSubParentToggle, [this]() {subParentToggleOpen=true;}); - QObject::connect(frogpilotSettingsWindow, &FrogPilotSettingsWindow::openSubSubParentToggle, [this]() {subSubParentToggleOpen=true;}); QList> panels = { {tr("Device"), device}, @@ -497,6 +493,44 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { panel_widget->addWidget(panel_frame); QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() { + if (w->widget() == frogpilotSettingsWindow) { + bool customizationLevelConfirmed = params.getBool("CustomizationLevelConfirmed"); + + if (!customizationLevelConfirmed) { + int frogpilotHours = paramsTracking.getInt("FrogPilotMinutes") / 60; + int openpilotHours = params.getInt("openpilotMinutes") / 60; + + if (frogpilotHours < 1 && openpilotHours < 100) { + if (FrogPilotConfirmationDialog::toggleAlert(tr("Welcome to FrogPilot! Since you're new to FrogPilot, the 'Basic' toggle preset has been applied, but you can change this at any time via the 'Customization Level' button!"), tr("Sounds good!"), this)) { + params.putBoolNonBlocking("CustomizationLevelConfirmed", true); + params.putIntNonBlocking("CustomizationLevel", 0); + } + } else if (frogpilotHours < 50 && openpilotHours < 100) { + if (FrogPilotConfirmationDialog::toggleAlert(tr("Since you're fairly new to FrogPilot, the 'Basic' toggle preset has been applied, but you can change this at any time via the 'Customization Level' button!"), tr("Sounds good!"), this)) { + params.putBoolNonBlocking("CustomizationLevelConfirmed", true); + params.putIntNonBlocking("CustomizationLevel", 0); + } + } else if (frogpilotHours < 100) { + if (openpilotHours >= 100 && frogpilotHours < 100) { + if (FrogPilotConfirmationDialog::toggleAlert(tr("Since you're experienced with openpilot, the 'Standard' toggle preset has been applied, but you can change this at any time via the 'Customization Level' button!"), tr("Sounds good!"), this)) { + params.putBoolNonBlocking("CustomizationLevelConfirmed", true); + params.putIntNonBlocking("CustomizationLevel", 1); + } + } else { + if (FrogPilotConfirmationDialog::toggleAlert(tr("Since you're experienced with FrogPilot, the 'Standard' toggle preset has been applied, but you can change this at any time via the 'Customization Level' button!"), tr("Sounds good!"), this)) { + params.putBoolNonBlocking("CustomizationLevelConfirmed", true); + params.putIntNonBlocking("CustomizationLevel", 1); + } + } + } else if (frogpilotHours >= 100) { + if (FrogPilotConfirmationDialog::toggleAlert(tr("Since you're very experienced with FrogPilot, the 'Advanced' toggle preset has been applied, but you can change this at any time via the 'Customization Level' button!"), tr("Sounds good!"), this)) { + params.putBoolNonBlocking("CustomizationLevelConfirmed", true); + params.putIntNonBlocking("CustomizationLevel", 2); + } + } + } + } + if (mapboxInstructionsOpen) { closeMapBoxInstructions(); mapboxInstructionsOpen = false; diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index 6a3ef27d..5b93ab01 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -40,7 +40,6 @@ signals: void closePanel(); void closeParentToggle(); void closeSubParentToggle(); - void closeSubSubParentToggle(); void updateMetric(); private: @@ -50,12 +49,14 @@ private: QStackedWidget *panel_widget; // FrogPilot variables + Params params; + Params paramsTracking{"/persist/tracking"}; + bool mapboxInstructionsOpen; bool mapSelectionOpen; bool panelOpen; bool parentToggleOpen; bool subParentToggleOpen; - bool subSubParentToggleOpen; }; class DevicePanel : public ListWidget { diff --git a/selfdrive/ui/qt/onroad/alerts.cc b/selfdrive/ui/qt/onroad/alerts.cc index 355c7175..8e2a2c84 100644 --- a/selfdrive/ui/qt/onroad/alerts.cc +++ b/selfdrive/ui/qt/onroad/alerts.cc @@ -17,8 +17,8 @@ void OnroadAlerts::updateState(const UIState &s) { hide_alerts = scene.hide_alerts; road_name_ui = scene.road_name_ui; - show_aol_status_bar = scene.show_aol_status_bar; - show_cem_status_bar = scene.show_cem_status_bar; + show_aol_status_bar = scene.aol_status_bar; + show_cem_status_bar = scene.cem_status_bar; } void OnroadAlerts::clear() { diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index fe965a76..5ef225b8 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -65,7 +65,7 @@ void AnnotatedCameraWidget::updateState(int alert_height, const UIState &s) { // Handle older routes where vEgoCluster is not set v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; - float v_ego = v_ego_cluster_seen && !s.scene.wheel_speed ? car_state.getVEgoCluster() : car_state.getVEgo(); + float v_ego = v_ego_cluster_seen && !s.scene.use_wheel_speed ? car_state.getVEgoCluster() : car_state.getVEgo(); speed = cs_alive ? std::max(0.0, v_ego) : 0.0; speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; @@ -77,7 +77,7 @@ void AnnotatedCameraWidget::updateState(int alert_height, const UIState &s) { } has_us_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::MUTCD) || (speedLimitController && !useViennaSLCSign); - has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA) && !(speedLimitController && !useViennaSLCSign) || (speedLimitController && useViennaSLCSign); + has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA) || (speedLimitController && useViennaSLCSign); is_metric = s.scene.is_metric; speedUnit = s.scene.is_metric ? tr("km/h") : tr("mph"); hideBottomIcons = (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE || turnSignalAnimation && (turnSignalLeft || turnSignalRight) && (signalStyle == "traditional" || signalStyle == "traditional_gif") || bigMapOpen); @@ -147,8 +147,6 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { ), 10)); } else if (trafficModeActive) { p.setPen(QPen(redColor(), 10)); - } else if (reverseCruise) { - p.setPen(QPen(blueColor(), 6)); } else { p.setPen(QPen(whiteColor(75), 6)); } @@ -333,11 +331,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f // road edges for (int i = 0; i < std::size(scene.road_edge_vertices); ++i) { - if (useStockColors) { - painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); - } else { - painter.setBrush(scene.road_edges_color); - } + painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp(1.0 - scene.road_edge_stds[i], 0.0, 1.0))); painter.drawPolygon(scene.road_edge_vertices[i]); } @@ -367,14 +361,11 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f // If acceleration is between -0.25 and 0.25, resort to the theme color if (std::abs(acceleration[i]) < 0.25 && !useStockColors) { QColor color = scene.path_color; - - bg.setColorAt(0.0, color); - - color.setAlphaF(0.5); - bg.setColorAt(0.5, color); - - color.setAlphaF(0.1); - bg.setColorAt(1.0, color); + bg.setColorAt(0.0f, color); + color.setAlphaF(0.5f); + bg.setColorAt(0.5f, color); + color.setAlphaF(0.1f); + bg.setColorAt(1.0f, color); } else { // speed up: 120, slow down: 0 float path_hue = fmax(fmin(60 + acceleration[i] * 35, 120), 0); @@ -402,15 +393,13 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f if (scene.show_stopping_point && scene.red_light && speed > 1 && !(conditionalStatus == 1 || conditionalStatus == 3 || conditionalStatus == 5)) { QPointF last_point = scene.track_vertices.last(); - QPointF adjusted_point = last_point - QPointF(stopSignImg.width() / 2, stopSignImg.height()); painter.drawPixmap(adjusted_point, stopSignImg); if (scene.show_stopping_point_metrics) { - QString text = QString::number(modelLength * distanceConversion) + leadDistanceUnit; QFont font = InterFont(35, QFont::DemiBold); - QFontMetrics fm(font); - int text_width = fm.horizontalAdvance(text); + QString text = QString::number(modelLength * distanceConversion) + leadDistanceUnit; + int text_width = QFontMetrics(font).horizontalAdvance(text); QPointF text_position = last_point - QPointF(text_width / 2, stopSignImg.height() + 35); painter.save(); @@ -425,9 +414,9 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f if (scene.blind_spot_path) { QLinearGradient bs(0, height(), 0, 0); - bs.setColorAt(0.0, QColor::fromHslF(0 / 360., 0.75, 0.50, 0.6)); - bs.setColorAt(0.5, QColor::fromHslF(0 / 360., 0.75, 0.50, 0.4)); - bs.setColorAt(1.0, QColor::fromHslF(0 / 360., 0.75, 0.50, 0.2)); + bs.setColorAt(0.0f, QColor::fromHslF(0 / 360.0f, 0.75f, 0.5f, 0.6f)); + bs.setColorAt(0.5f, QColor::fromHslF(0 / 360.0f, 0.75f, 0.5f, 0.4f)); + bs.setColorAt(1.0f, QColor::fromHslF(0 / 360.0f, 0.75f, 0.5f, 0.2f)); painter.setBrush(bs); if (blindSpotLeft) { @@ -439,67 +428,68 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f } // Paint adjacent lane paths - if ((scene.adjacent_path || scene.adjacent_path_metrics) && v_ego > scene.minimum_lane_change_speed) { - const float minLaneWidth = laneDetectionWidth * 0.5f; - const float maxLaneWidth = laneDetectionWidth * 1.5f; + if ((scene.adjacent_path || scene.adjacent_path_metrics) && v_ego >= scene.minimum_lane_change_speed) { + QLinearGradient ap(0, height(), 0, 0); - auto paintLane = [&](const QPolygonF &lane, float laneWidth, bool blindspot) { - QLinearGradient gradient(0, height(), 0, 0); + std::function setAdjacentPathColors = [&](float hue) { + ap.setColorAt(0.0f, QColor::fromHslF(hue / 360.0f, 0.75f, 0.5f, 0.6f)); + ap.setColorAt(0.5f, QColor::fromHslF(hue / 360.0f, 0.75f, 0.5f, 0.4f)); + ap.setColorAt(1.0f, QColor::fromHslF(hue / 360.0f, 0.75f, 0.5f, 0.2f)); + }; - bool redPath = laneWidth < minLaneWidth || laneWidth > maxLaneWidth || blindspot; - float hue = redPath ? 0.0f : 120.0f * (laneWidth - minLaneWidth) / (maxLaneWidth - minLaneWidth); - float hueF = hue / 360.0f; + std::function drawAdjacentLane = [&](const QPolygonF &lane, float laneWidth, bool isBlindSpot) { + if (isBlindSpot) { + setAdjacentPathColors(0.0f); + } else { + float hue = 120.0f * (1 - fmin(fabs(laneWidth - laneDetectionWidth) / (laneDetectionWidth / 2), 1)); + setAdjacentPathColors(hue); + } - gradient.setColorAt(0.0, QColor::fromHslF(hueF, 0.75f, 0.50f, 0.6f)); - gradient.setColorAt(0.5, QColor::fromHslF(hueF, 0.75f, 0.50f, 0.4f)); - gradient.setColorAt(1.0, QColor::fromHslF(hueF, 0.75f, 0.50f, 0.2f)); - - painter.setBrush(gradient); + painter.setBrush(ap); painter.drawPolygon(lane); if (scene.adjacent_path_metrics) { painter.setFont(InterFont(30, QFont::DemiBold)); painter.setPen(Qt::white); - QRectF boundingRect = lane.boundingRect(); - QString text = blindspot ? tr("Vehicle in blind spot") : QString::number(laneWidth * distanceConversion, 'f', 2) + leadDistanceUnit; - painter.drawText(boundingRect, Qt::AlignCenter, text); - + QString text = isBlindSpot ? tr("Vehicle in blind spot") : QString::number(laneWidth * distanceConversion, 'f', 2) + leadDistanceUnit; + painter.drawText(lane.boundingRect(), Qt::AlignCenter, text); painter.setPen(Qt::NoPen); } }; - paintLane(scene.track_adjacent_vertices[4], scene.lane_width_left, blindSpotLeft); - paintLane(scene.track_adjacent_vertices[5], scene.lane_width_right, blindSpotRight); + drawAdjacentLane(scene.track_adjacent_vertices[4], scene.lane_width_left, blindSpotLeft); + drawAdjacentLane(scene.track_adjacent_vertices[5], scene.lane_width_right, blindSpotRight); } // Paint path edges QLinearGradient pe(0, height(), 0, 0); - auto setGradientColors = [&](const QColor &baseColor) { - pe.setColorAt(0.0, baseColor); + + std::function setPathEdgeColors = [&](QLinearGradient &gradient, const QColor &baseColor) { + gradient.setColorAt(0.0f, baseColor); QColor color = baseColor; - color.setAlphaF(0.5); - pe.setColorAt(0.5, color); - color.setAlphaF(0.1); - pe.setColorAt(1.0, color); + color.setAlphaF(0.5f); + gradient.setColorAt(0.5f, color); + color.setAlphaF(0.1f); + gradient.setColorAt(1.0f, color); }; if (alwaysOnLateralActive) { - setGradientColors(bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE]); + setPathEdgeColors(pe, bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE]); } else if (conditionalStatus == 1 || conditionalStatus == 3 || conditionalStatus == 5) { - setGradientColors(bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]); + setPathEdgeColors(pe, bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]); } else if (experimentalMode) { - setGradientColors(bg_colors[STATUS_EXPERIMENTAL_MODE_ACTIVE]); + setPathEdgeColors(pe, bg_colors[STATUS_EXPERIMENTAL_MODE_ACTIVE]); } else if (trafficModeActive) { - setGradientColors(bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]); + setPathEdgeColors(pe, bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]); } else if (scene.navigate_on_openpilot) { - setGradientColors(bg_colors[STATUS_NAVIGATION_ACTIVE]); + setPathEdgeColors(pe, bg_colors[STATUS_NAVIGATION_ACTIVE]); } else if (!useStockColors) { - setGradientColors(scene.path_edges_color); + setPathEdgeColors(pe, scene.path_edges_color); } else { - pe.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 1.0)); - pe.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.00, 0.68, 0.5)); - pe.setColorAt(1.0, QColor::fromHslF(112 / 360., 1.00, 0.68, 0.1)); + pe.setColorAt(0.0f, QColor::fromHslF(148 / 360.0f, 0.94f, 0.51f, 1.0f)); + pe.setColorAt(0.5f, QColor::fromHslF(112 / 360.0f, 1.00f, 0.68f, 0.5f)); + pe.setColorAt(1.0f, QColor::fromHslF(112 / 360.0f, 1.00f, 0.68f, 0.1f)); } QPainterPath path; @@ -559,12 +549,12 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) painter.restore(); } -void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, float v_ego, const QColor lead_marker_color) { +void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, float v_ego, const QColor &lead_marker_color, bool adjacent) { painter.save(); - const float speedBuff = useStockColors ? 10. : 25.; // Make the center of the chevron appear sooner if a theme is active - const float leadBuff = useStockColors ? 40. : 100.; // Make the center of the chevron appear sooner if a theme is active - const float d_rel = lead_data.getDRel(); + const float speedBuff = useStockColors || adjacent ? 10. : 25.; // Make the center of the chevron appear sooner if a theme is active + const float leadBuff = useStockColors || adjacent ? 40. : 100.; // Make the center of the chevron appear sooner if a theme is active + const float d_rel = lead_data.getDRel() + (adjacent ? fabs(lead_data.getYRel()) : 0); const float v_rel = lead_data.getVRel(); float fillAlpha = 0; @@ -576,7 +566,7 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState fillAlpha = (int)(fmin(fillAlpha, 255)); } - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; + float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), adjacent ? 5.0f : 15.0f, adjacent ? 20.0f : 30.0f) * 2.35; float x = std::clamp((float)vd.x(), 0.f, width() - sz / 2); float y = std::fmin(height() - sz * .6, (float)vd.y()); @@ -602,21 +592,38 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.setPen(Qt::white); painter.setFont(InterFont(35, QFont::Bold)); - QString text = QString("%1 %2 | %3 %4 | %5 %6") - .arg(qRound(d_rel * distanceConversion)) - .arg(leadDistanceUnit) - .arg(qRound(lead_speed * speedConversion)) - .arg(leadSpeedUnit) - .arg(QString::number(d_rel / std::max(v_ego, 1.0f), 'f', 1)) - .arg("s"); + QString text; + if (adjacent) { + text = QString("%1 %2 | %3 %4") + .arg(qRound(d_rel * distanceConversion)) + .arg(leadDistanceUnit) + .arg(qRound(lead_speed * speedConversion)) + .arg(leadSpeedUnit); + } else { + text = QString("%1 %2 | %3 %4 | %5 %6") + .arg(qRound(d_rel * distanceConversion)) + .arg(leadDistanceUnit) + .arg(qRound(lead_speed * speedConversion)) + .arg(leadSpeedUnit) + .arg(QString::number(d_rel / std::max(v_ego, 1.0f), 'f', 1)) + .arg("s"); + } QFontMetrics metrics(painter.font()); int middle_x = (chevron[2].x() + chevron[0].x()) / 2; + int textHeight = metrics.height(); int textWidth = metrics.horizontalAdvance(text); int text_x = middle_x - textWidth / 2; - int text_y = chevron[0].y() + metrics.height() + 5; + int text_y = chevron[0].y() + textHeight + 5; - painter.drawText(text_x, text_y, text); + if (!adjacent) { + lead_x = x + text_x + textWidth; + lead_y = y + text_y + textHeight; + } + + if (!adjacent || fabs((x + text_x + textWidth) - lead_x) >= textWidth || fabs((y + text_y + textHeight) - lead_y) >= textHeight) { + painter.drawText(text_x, text_y, text); + } } painter.restore(); @@ -691,11 +698,29 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { update_leads(s, radar_state, model.getPosition()); auto lead_one = radar_state.getLeadOne(); auto lead_two = radar_state.getLeadTwo(); - if (lead_one.getStatus()) { - drawLead(painter, lead_one, s->scene.lead_vertices[0], v_ego, s->scene.lead_marker_color); + auto lead_left = radar_state.getLeadLeft(); + auto lead_right = radar_state.getLeadRight(); + auto lead_left_far = radar_state.getLeadLeftFar(); + auto lead_right_far = radar_state.getLeadRightFar(); + if (lead_left.getStatus()) { + drawLead(painter, lead_left, s->scene.lead_vertices[2], v_ego, blueColor(), true); + } + if (lead_right.getStatus()) { + drawLead(painter, lead_right, s->scene.lead_vertices[3], v_ego, redColor(), true); + } + if (lead_left_far.getStatus()) { + drawLead(painter, lead_left_far, s->scene.lead_vertices[4], v_ego, greenColor(), true); + } + if (lead_right_far.getStatus()) { + drawLead(painter, lead_right_far, s->scene.lead_vertices[5], v_ego, whiteColor(), true); } if (lead_two.getStatus()) { drawLead(painter, lead_two, s->scene.lead_vertices[1], v_ego, s->scene.lead_marker_color); + } else if (lead_one.getStatus()) { + drawLead(painter, lead_one, s->scene.lead_vertices[0], v_ego, s->scene.lead_marker_color); + } else { + lead_x = 0; + lead_y = 0; } } } @@ -846,7 +871,7 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS alertHeight = alert_height; alwaysOnLateralActive = scene.always_on_lateral_active; - showAlwaysOnLateralStatusBar = scene.show_aol_status_bar; + showAlwaysOnLateralStatusBar = scene.aol_status_bar; blindSpotLeft = scene.blind_spot_left; blindSpotRight = scene.blind_spot_right; @@ -861,10 +886,10 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS bottom_layout->setAlignment(compass_img, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight)); } - conditionalSpeed = scene.conditional_speed; - conditionalSpeedLead = scene.conditional_speed_lead; + conditionalSpeed = scene.conditional_limit; + conditionalSpeedLead = scene.conditional_limit_lead; conditionalStatus = scene.conditional_status; - showConditionalExperimentalStatusBar = scene.show_cem_status_bar; + showConditionalExperimentalStatusBar = scene.cem_status_bar; cruiseAdjustment = scene.disable_curve_speed_smoothing || !is_cruise_set ? fmax(setSpeed - scene.adjusted_cruise, 0) : fmax(0.25 * (setSpeed - scene.adjusted_cruise) + 0.75 * cruiseAdjustment - 1, 0); vtscControllingCurve = scene.vtsc_controlling_curve; @@ -882,7 +907,7 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS laneDetectionWidth = scene.lane_detection_width; - leadInfo = scene.lead_info; + leadInfo = scene.lead_metrics; obstacleDistance = scene.obstacle_distance; obstacleDistanceStock = scene.obstacle_distance_stock; @@ -910,8 +935,6 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS pedal_icons->updateState(scene); } - reverseCruise = scene.reverse_cruise; - roadNameUI = scene.road_name_ui; bool enableScreenRecorder = scene.screen_recorder && !mapOpen; @@ -921,12 +944,12 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS } speedLimitController = scene.speed_limit_controller; - showSLCOffset = speedLimitController && scene.show_slc_offset; + showSLCOffset = speedLimitController && scene.show_speed_limit_offset; slcOverridden = speedLimitController && scene.speed_limit_overridden; slcSpeedLimitOffset = scene.speed_limit_offset * (is_metric ? MS_TO_KPH : MS_TO_MPH); speedLimitChanged = speedLimitController && scene.speed_limit_changed; unconfirmedSpeedLimit = speedLimitController ? scene.unconfirmed_speed_limit : 0; - useViennaSLCSign = scene.use_vienna_slc_sign; + useViennaSLCSign = scene.speed_limit_vienna; bool stoppedTimer = scene.stopped_timer && scene.standstill && scene.started_timer / UI_FREQ >= 10 && !mapOpen; if (stoppedTimer) { @@ -944,7 +967,7 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS turnSignalLeft = scene.turn_signal_left; turnSignalRight = scene.turn_signal_right; - useSI = scene.use_si; + useSI = scene.use_si_metrics; useStockColors = scene.use_stock_colors; } diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index ed7abc88..19d7212b 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -90,15 +90,14 @@ private: bool wide_cam_requested = false; // FrogPilot widgets - void initializeFrogPilotWidgets(); - void paintFrogPilotWidgets(QPainter &painter); - void updateFrogPilotVariables(int alert_height, const UIScene &scene); - void updateSignals(); - void drawLeadInfo(QPainter &p); void drawSLCConfirmation(QPainter &p); void drawStatusBar(QPainter &p); void drawTurnSignals(QPainter &p); + void initializeFrogPilotWidgets(); + void paintFrogPilotWidgets(QPainter &painter); + void updateFrogPilotVariables(int alert_height, const UIScene &scene); + void updateSignals(); // FrogPilot variables Params paramsMemory{"/dev/shm/params"}; @@ -122,7 +121,6 @@ private: bool leadInfo; bool mapOpen; bool onroadDistanceButton; - bool reverseCruise; bool roadNameUI; bool showAlwaysOnLateralStatusBar; bool showConditionalExperimentalStatusBar; @@ -145,6 +143,8 @@ private: float cruiseAdjustment; float distanceConversion; float laneDetectionWidth; + float lead_x; + float lead_y; float slcSpeedLimitOffset; float speedConversion; float unconfirmedSpeedLimit; @@ -191,7 +191,7 @@ protected: void showEvent(QShowEvent *event) override; void updateFrameMat() override; void drawLaneLines(QPainter &painter, const UIState *s, float v_ego); - void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, float v_ego, const QColor lead_marker_color); + void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, float v_ego, const QColor &lead_marker_color, bool adjacent = false); void drawHud(QPainter &p); void drawDriverState(QPainter &painter, const UIState *s); void paintEvent(QPaintEvent *event) override; diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index 73a95455..969d5e54 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -56,7 +56,7 @@ void ExperimentalButton::changeMode() { } } -void ExperimentalButton::updateState(const UIState &s, bool lead_info) { +void ExperimentalButton::updateState(const UIState &s, bool lead_metrics) { const auto cs = (*s.sm)["controlsState"].getControlsState(); bool eng = cs.getEngageable() || cs.getEnabled() || always_on_lateral_active; if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { @@ -77,7 +77,7 @@ void ExperimentalButton::updateState(const UIState &s, bool lead_info) { rotating_wheel = scene.rotating_wheel; traffic_mode_active = scene.traffic_mode_active; use_stock_wheel = scene.use_stock_wheel; - y_offset = lead_info ? 10 : 0; + y_offset = lead_metrics ? 10 : 0; if (rotating_wheel && steering_angle_deg != scene.steering_angle_deg) { steering_angle_deg = scene.steering_angle_deg; diff --git a/selfdrive/ui/qt/onroad/buttons.h b/selfdrive/ui/qt/onroad/buttons.h index bfe143b6..ec08db2b 100644 --- a/selfdrive/ui/qt/onroad/buttons.h +++ b/selfdrive/ui/qt/onroad/buttons.h @@ -14,7 +14,7 @@ class ExperimentalButton : public QPushButton { public: explicit ExperimentalButton(QWidget *parent = 0); - void updateState(const UIState &s, bool lead_info); + void updateState(const UIState &s, bool lead_metrics); // FrogPilot widgets ~ExperimentalButton(); diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc index 3634f99b..6a9aced2 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/qt/onroad/onroad_home.cc @@ -95,10 +95,10 @@ void OnroadWindow::updateState(const UIState &s) { liveValid = scene.live_valid; showBlindspot = scene.show_blind_spot && (blindSpotLeft || blindSpotRight); showFPS = scene.show_fps; - showJerk = scene.show_jerk; - showSignal = scene.show_signal && (turnSignalLeft || turnSignalRight); - showSteering = scene.show_steering; - showTuning = scene.show_tuning; + showJerk = scene.jerk_metrics; + showSignal = scene.signal_metrics && (turnSignalLeft || turnSignalRight); + showSteering = scene.steering_metrics; + showTuning = scene.lateral_tuning_metrics; speedJerk = scene.speed_jerk; speedJerkDifference = scene.speed_jerk_difference; steer = scene.steer; @@ -127,9 +127,6 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { QRect leftRect(0, 0, size.width() / 2, size.height()); QRect rightRect(size.width() / 2, 0, size.width() / 2, size.height()); - QRect hideSpeedRect(rect().center().x() - 175, 50, 350, 350); - QRect speedLimitRect(7, 250, 225, 225); - if (scene.speed_limit_changed && (leftRect.contains(pos) || rightRect.contains(pos))) { bool slcConfirmed = leftRect.contains(pos) ? !scene.right_hand_drive : scene.right_hand_drive; paramsMemory.putBoolNonBlocking("SLCConfirmed", slcConfirmed); @@ -137,19 +134,7 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { return; } - if (hideSpeedRect.contains(pos) && scene.hide_speed_ui) { - scene.hide_speed = !scene.hide_speed; - params.putBoolNonBlocking("HideSpeed", scene.hide_speed); - return; - } - - if (speedLimitRect.contains(pos) && scene.show_slc_offset_ui) { - scene.show_slc_offset = !scene.show_slc_offset; - params.putBoolNonBlocking("ShowSLCOffset", scene.show_slc_offset); - return; - } - - if (scene.experimental_mode_via_screen && pos != timeoutPoint) { + if (scene.experimental_mode_via_tap && pos != timeoutPoint) { if (clickTimer.isActive()) { clickTimer.stop(); @@ -427,9 +412,8 @@ void OnroadWindow::paintEvent(QPaintEvent *event) { avgFPS = totalFPS / fpsQueue.size(); } - QString fpsDisplayString = QString("FPS: %1 (%2) | Min: %3 | Max: %4 | Avg: %5") + QString fpsDisplayString = QString("FPS: %1 | Min: %3 | Max: %4 | Avg: %5") .arg(qRound(fps)) - .arg(paramsMemory.getInt("CameraFPS")) .arg(qRound(minFPS)) .arg(qRound(maxFPS)) .arg(qRound(avgFPS)); diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index abadeaca..a0de00fb 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -114,8 +114,8 @@ void Sidebar::mousePressEvent(QMouseEvent *event) { isCPU = (showChip == 1); isGPU = (showChip == 2); - scene.is_CPU = isCPU; - scene.is_GPU = isGPU; + scene.cpu_metrics = isCPU; + scene.gpu_metrics = isGPU; params.putBoolNonBlocking("ShowCPU", isCPU); params.putBoolNonBlocking("ShowGPU", isGPU); @@ -129,9 +129,9 @@ void Sidebar::mousePressEvent(QMouseEvent *event) { isStorageLeft = (showMemory == 2); isStorageUsed = (showMemory == 3); - scene.is_memory = isMemoryUsage; - scene.is_storage_left = isStorageLeft; - scene.is_storage_used = isStorageUsed; + scene.memory_metrics = isMemoryUsage; + scene.storage_left_metrics = isStorageLeft; + scene.storage_used_metrics = isStorageUsed; params.putBoolNonBlocking("ShowMemoryUsage", isMemoryUsage); params.putBoolNonBlocking("ShowStorageLeft", isStorageLeft); @@ -239,15 +239,15 @@ void Sidebar::updateState(const UIState &s) { // FrogPilot variables const UIScene &scene = s.scene; - isCPU = scene.is_CPU; + isCPU = scene.cpu_metrics; isFahrenheit = scene.fahrenheit; - isGPU = scene.is_GPU; - isIP = scene.is_IP; - isMemoryUsage = scene.is_memory; + isGPU = scene.gpu_metrics; + isIP = scene.ip_metrics; + isMemoryUsage = scene.memory_metrics; isNumericalTemp = scene.numerical_temp; isRandomEvents = scene.random_events; - isStorageLeft = scene.is_storage_left; - isStorageUsed = scene.is_storage_used; + isStorageLeft = scene.storage_left_metrics; + isStorageUsed = scene.storage_used_metrics; isSidebarMetrics = scene.sidebar_metrics; bool useStockColors = scene.use_stock_colors; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index a69442e2..1f916ad0 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -214,7 +214,7 @@ ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString #confirm_btn:pressed { background-color: #3049F4; } )"); QVBoxLayout *main_layout = new QVBoxLayout(container); - main_layout->setContentsMargins(32, rich ? 32 : 120, 32, 32); + main_layout->setContentsMargins(32, 32, 32, 32); QLabel *prompt = new QLabel(prompt_text, this); prompt->setWordWrap(true); diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 75e23837..99d3eb91 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -15,7 +15,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.system import micd from openpilot.selfdrive.frogpilot.frogpilot_functions import ACTIVE_THEME_PATH, RANDOM_EVENTS_PATH -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles SAMPLE_RATE = 48000 SAMPLE_BUFFER = 4096 # (approx 100ms) @@ -55,6 +55,7 @@ sound_list: dict[int, tuple[str, int | None, float]] = { AudibleAlert.nessie: ("nessie.wav", 1, MAX_VOLUME), AudibleAlert.noice: ("noice.wav", 1, MAX_VOLUME), AudibleAlert.promptRepeat: ("prompt_repeat.wav", None, MAX_VOLUME), + AudibleAlert.thisIsFine: ("this_is_fine.wav", None, MAX_VOLUME), AudibleAlert.uwu: ("uwu.wav", 1, MAX_VOLUME), } @@ -79,8 +80,9 @@ class Soundd: self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) # FrogPilot variables - self.frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + self.frogpilot_toggles = get_frogpilot_toggles(True) + + self.auto_volume = 0 self.previous_sound_pack = None @@ -97,11 +99,10 @@ class Soundd: AudibleAlert.mail: MAX_VOLUME, AudibleAlert.nessie: MAX_VOLUME, AudibleAlert.noice: MAX_VOLUME, + AudibleAlert.thisIsFine: MAX_VOLUME, AudibleAlert.uwu: MAX_VOLUME, } - self.update_toggles = False - self.update_frogpilot_sounds() def load_sounds(self): @@ -186,7 +187,7 @@ class Soundd: # sounddevice must be imported after forking processes import sounddevice as sd - sm = messaging.SubMaster(['controlsState', 'microphone']) + sm = messaging.SubMaster(['controlsState', 'microphone', 'frogpilotPlan']) with self.get_stream(sd) as stream: rk = Ratekeeper(20) @@ -197,6 +198,8 @@ class Soundd: if sm.updated['microphone'] and self.current_alert == AudibleAlert.none: # only update volume filter when not playing alert if self.frogpilot_toggles.alert_volume_control: + self.spl_filter_weighted.update(sm["microphone"].soundPressureWeightedDb) + self.auto_volume = self.calculate_volume(float(self.spl_filter_weighted.x)) self.current_volume = 0.0 else: self.spl_filter_weighted.update(sm["microphone"].soundPressureWeightedDb) @@ -204,6 +207,8 @@ class Soundd: elif self.frogpilot_toggles.alert_volume_control and self.current_alert in self.volume_map: self.current_volume = self.volume_map[self.current_alert] / 100.0 + if self.current_volume == 1.01: + self.current_volume = self.auto_volume elif self.current_alert in self.random_events_map: self.current_volume = self.random_events_map[self.current_alert] @@ -215,12 +220,9 @@ class Soundd: assert stream.active # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - self.update_toggles = True - elif self.update_toggles: - FrogPilotVariables.update_frogpilot_params() + if sm['frogpilotPlan'].togglesUpdated: + self.frogpilot_toggles = get_frogpilot_toggles() self.update_frogpilot_sounds() - self.update_toggles = False def update_frogpilot_sounds(self): self.volume_map = { diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index d8a21994..2dda847f 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -45,12 +45,16 @@ int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_h } void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line) { - cereal::RadarState::LeadData::Reader (cereal::RadarState::Reader::*get_lead_data[2])() const = { + cereal::RadarState::LeadData::Reader (cereal::RadarState::Reader::*get_lead_data[6])() const = { &cereal::RadarState::Reader::getLeadOne, &cereal::RadarState::Reader::getLeadTwo, + &cereal::RadarState::Reader::getLeadLeft, + &cereal::RadarState::Reader::getLeadRight, + &cereal::RadarState::Reader::getLeadLeftFar, + &cereal::RadarState::Reader::getLeadRightFar }; - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 6; ++i) { auto lead_data = (radar_state.*get_lead_data[i])(); if (lead_data.getStatus()) { float z = line.getZ()[get_path_length_idx(line, lead_data.getDRel())]; @@ -129,7 +133,7 @@ void update_model(UIState *s, auto lead_count = model.getLeadsV3().size(); if (lead_count > 0) { auto lead_one = model.getLeadsV3()[0]; - scene.has_lead = lead_one.getProb() > scene.lead_detection_threshold; + scene.has_lead = lead_one.getProb() > scene.lead_detection_probability; if (scene.has_lead) { const float lead_d = lead_one.getX()[0] * 2.; @@ -140,7 +144,7 @@ void update_model(UIState *s, } } else { auto lead_one = (*s->sm)["radarState"].getRadarState().getLeadOne(); - scene.has_lead = lead_one.getModelProb() > scene.lead_detection_threshold; + scene.has_lead = lead_one.getModelProb() > scene.lead_detection_probability; if (scene.has_lead) { const float lead_d = lead_one.getDRel() * 2.; @@ -148,7 +152,7 @@ void update_model(UIState *s, } } max_idx = get_path_length_idx(plan_position, max_distance); - update_line_data(s, plan_position, scene.model_ui ? path_width * (1 - scene.path_edge_width / 100.0f) : 0.9, 1.22, &scene.track_vertices, max_idx, false); + update_line_data(s, plan_position, scene.model_ui ? path_width * (1 - (scene.path_edge_width / 100.0f)) : 0.9, 1.22, &scene.track_vertices, max_idx, false); // Update path edges update_line_data(s, plan_position, scene.model_ui ? path_width : 0, 1.22, &scene.track_edge_vertices, max_idx, false); @@ -196,6 +200,7 @@ static void update_sockets(UIState *s) { } static void update_state(UIState *s) { + Params params = Params(); SubMaster &sm = *(s->sm); UIScene &scene = s->scene; @@ -297,6 +302,10 @@ static void update_state(UIState *s) { scene.stopped_equivalence = frogpilotPlan.getStoppedEquivalenceFactor(); scene.unconfirmed_speed_limit = frogpilotPlan.getUnconfirmedSlcSpeedLimit(); scene.vtsc_controlling_curve = frogpilotPlan.getVtscControllingCurve(); + if (frogpilotPlan.getTogglesUpdated()) { + scene.frogpilot_toggles = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotToggles")).toUtf8()).object(); + ui_update_params(uiState()); + } } if (sm.updated("liveLocationKalman")) { auto liveLocationKalman = sm["liveLocationKalman"].getLiveLocationKalman(); @@ -332,142 +341,94 @@ void ui_update_params(UIState *s) { s->scene.is_metric = params.getBool("IsMetric"); s->scene.map_on_left = params.getBool("NavSettingLeftSide"); - ui_update_frogpilot_params(s, params); + ui_update_frogpilot_params(s); } -void ui_update_frogpilot_params(UIState *s, Params ¶ms) { +void ui_update_frogpilot_params(UIState *s) { UIScene &scene = s->scene; - std::string carParams = params.get("CarParamsPersistent"); - if (!carParams.empty()) { - AlignedBuffer aligned_buf; - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(carParams.data(), carParams.size())); - cereal::CarParams::Reader CP = cmsg.getRoot(); - scene.longitudinal_control = hasLongitudinalControl(CP); - } - - float distance_conversion = scene.is_metric ? 1.0f : FOOT_TO_METER; - float small_distance_conversion = scene.is_metric ? 1.0f : INCH_TO_CM; - float speed_conversion = scene.is_metric ? 1 / MS_TO_KPH : 1 / MS_TO_MPH; - - bool advanced_custom_onroad_ui = params.getBool("AdvancedCustomUI"); - scene.camera_view = advanced_custom_onroad_ui ? params.getInt("CameraView") : 0; - scene.hide_lead_marker = advanced_custom_onroad_ui && params.getBool("HideLeadMarker"); - scene.hide_speed = advanced_custom_onroad_ui && params.getBool("HideSpeed"); - scene.hide_speed_ui = scene.hide_speed && params.getBool("HideSpeedUI"); - bool hide_ui_elements = advanced_custom_onroad_ui && params.getBool("HideUIElements"); - scene.hide_alerts = hide_ui_elements && params.getBool("HideAlerts"); - scene.hide_map_icon = hide_ui_elements && params.getBool("HideMapIcon"); - scene.hide_max_speed = hide_ui_elements && params.getBool("HideMaxSpeed"); - scene.show_stopping_point = advanced_custom_onroad_ui && params.getBool("ShowStoppingPoint"); - scene.show_stopping_point_metrics = scene.show_stopping_point && params.getBool("ShowStoppingPointMetrics"); - scene.wheel_speed = advanced_custom_onroad_ui && params.getBool("WheelSpeed"); - - bool always_on_lateral = params.getBool("AlwaysOnLateral"); - scene.show_aol_status_bar = always_on_lateral && !params.getBool("HideAOLStatusBar"); - - bool personalize_openpilot = params.getBool("PersonalizeOpenpilot"); + scene.acceleration_path = static_cast(scene.frogpilot_toggles.value("acceleration_path").toBool()); + scene.adjacent_path = static_cast(scene.frogpilot_toggles.value("adjacent_paths").toBool()); + scene.adjacent_path_metrics = static_cast(scene.frogpilot_toggles.value("adjacent_path_metrics").toBool()); + scene.aol_status_bar = static_cast(scene.frogpilot_toggles.value("always_on_lateral_status_bar").toBool()); + scene.big_map = static_cast(scene.frogpilot_toggles.value("big_map").toBool()); + scene.blind_spot_path = static_cast(scene.frogpilot_toggles.value("blind_spot_path").toBool()); + scene.camera_view = scene.frogpilot_toggles.value("camera_view").toDouble(); + scene.cem_status_bar = static_cast(scene.frogpilot_toggles.value("conditional_status_bar").toBool()); + scene.compass = static_cast(scene.frogpilot_toggles.value("compass").toBool()); + scene.conditional_experimental = static_cast(scene.frogpilot_toggles.value("conditional_experimental_mode").toBool()); + scene.conditional_limit = scene.frogpilot_toggles.value("conditional_limit").toDouble(); + scene.conditional_limit_lead = scene.frogpilot_toggles.value("conditional_limit_lead").toDouble(); + scene.cpu_metrics = static_cast(scene.frogpilot_toggles.value("cpu_metrics").toBool()); + scene.disable_curve_speed_smoothing = static_cast(scene.frogpilot_toggles.value("disable_curve_speed_smoothing").toBool()); + scene.driver_camera_in_reverse = static_cast(scene.frogpilot_toggles.value("driver_camera_in_reverse").toBool()); + scene.dynamic_path_width = static_cast(scene.frogpilot_toggles.value("dynamic_path_width").toBool()); + scene.dynamic_pedals_on_ui = static_cast(scene.frogpilot_toggles.value("dynamic_pedals_on_ui").toBool()); + scene.experimental_mode_via_tap = static_cast(scene.frogpilot_toggles.value("experimental_mode_via_tap").toBool()); + scene.fahrenheit = static_cast(scene.frogpilot_toggles.value("fahrenheit").toBool()); + scene.full_map = static_cast(scene.frogpilot_toggles.value("full_map").toBool()); + scene.gpu_metrics = static_cast(scene.frogpilot_toggles.value("gpu_metrics").toBool()); + scene.hide_alerts = static_cast(scene.frogpilot_toggles.value("hide_alerts").toBool()); + scene.hide_lead_marker = static_cast(scene.frogpilot_toggles.value("hide_lead_marker").toBool()); + scene.hide_map_icon = static_cast(scene.frogpilot_toggles.value("hide_map_icon").toBool()); + scene.hide_max_speed = static_cast(scene.frogpilot_toggles.value("hide_max_speed").toBool()); + scene.hide_speed = static_cast(scene.frogpilot_toggles.value("hide_speed").toBool()); + scene.ip_metrics = static_cast(scene.frogpilot_toggles.value("ip_metrics").toBool()); + scene.jerk_metrics = static_cast(scene.frogpilot_toggles.value("jerk_metrics").toBool()); + scene.lateral_tuning_metrics = static_cast(scene.has_auto_tune && scene.frogpilot_toggles.value("lateral_tuning_metrics").toBool()); + scene.lane_detection_width = scene.frogpilot_toggles.value("lane_detection_width").toDouble(); + scene.lane_line_width = scene.frogpilot_toggles.value("lane_line_width").toDouble(); scene.lane_lines_color = loadThemeColors("LaneLines"); + scene.lead_detection_probability = scene.frogpilot_toggles.value("lead_detection_probability").toDouble(); scene.lead_marker_color = loadThemeColors("LeadMarker"); + scene.lead_metrics = static_cast(scene.frogpilot_toggles.value("lead_metrics").toBool()); + scene.map_style = scene.frogpilot_toggles.value("map_style").toDouble(); + scene.memory_metrics = static_cast(scene.frogpilot_toggles.value("memory_metrics").toBool()); + scene.minimum_lane_change_speed = scene.frogpilot_toggles.value("minimum_lane_change_speed").toDouble(); + scene.model_randomizer = static_cast(scene.frogpilot_toggles.value("model_randomizer").toBool()); + scene.model_ui = static_cast(scene.frogpilot_toggles.value("model_ui").toBool()); + scene.numerical_temp = static_cast(scene.frogpilot_toggles.value("numerical_temp").toBool()); + scene.onroad_distance_button = static_cast(scene.frogpilot_toggles.value("onroad_distance_button").toBool()); scene.path_color = loadThemeColors("Path"); + scene.path_edge_width = scene.frogpilot_toggles.value("path_edge_width").toDouble(); scene.path_edges_color = loadThemeColors("PathEdge"); - scene.road_edges_color = loadThemeColors("RoadEdges"); + scene.path_width = scene.frogpilot_toggles.value("path_width").toDouble(); + scene.pedals_on_ui = static_cast(scene.frogpilot_toggles.value("pedals_on_ui").toBool()); + scene.radarless_model = static_cast(scene.frogpilot_toggles.value("radarless_model").toBool()); + scene.random_events = static_cast(scene.frogpilot_toggles.value("random_events").toBool()); + scene.road_edge_width = scene.frogpilot_toggles.value("road_edge_width").toDouble(); + scene.road_name_ui = static_cast(scene.frogpilot_toggles.value("road_name_ui").toBool()); + scene.rotating_wheel = static_cast(scene.frogpilot_toggles.value("rotating_wheel").toBool()); + scene.screen_brightness = scene.frogpilot_toggles.value("screen_brightness").toDouble(); + scene.screen_brightness_onroad = scene.frogpilot_toggles.value("screen_brightness_onroad").toDouble(); + scene.screen_recorder = static_cast(scene.frogpilot_toggles.value("screen_recorder").toBool()); + scene.screen_timeout = scene.frogpilot_toggles.value("screen_timeout").toDouble(); + scene.screen_timeout_onroad = scene.frogpilot_toggles.value("screen_timeout_onroad").toDouble(); + scene.show_blind_spot = static_cast(scene.frogpilot_toggles.value("blind_spot_metrics").toBool()); + scene.show_fps = static_cast(scene.frogpilot_toggles.value("show_fps").toBool()); + scene.show_speed_limit_offset = static_cast(scene.frogpilot_toggles.value("show_speed_limit_offset").toBool()); + scene.show_stopping_point = static_cast(scene.frogpilot_toggles.value("show_stopping_point").toBool()); + scene.show_stopping_point_metrics = static_cast(scene.frogpilot_toggles.value("show_stopping_point_metrics").toBool()); scene.sidebar_color1 = loadThemeColors("Sidebar1"); scene.sidebar_color2 = loadThemeColors("Sidebar2"); scene.sidebar_color3 = loadThemeColors("Sidebar3"); - scene.use_stock_colors = !personalize_openpilot || params.getBool("UseStockColors"); - scene.use_stock_wheel = !personalize_openpilot || QString::fromStdString(params.get("WheelIcon")) == "stock"; + scene.sidebar_metrics = static_cast(scene.frogpilot_toggles.value("sidebar_metrics").toBool()); + scene.signal_metrics = static_cast(scene.frogpilot_toggles.value("signal_metrics").toBool()); + scene.speed_limit_controller = static_cast(scene.frogpilot_toggles.value("speed_limit_controller").toBool()); + scene.speed_limit_vienna = static_cast(scene.frogpilot_toggles.value("speed_limit_vienna").toBool()); + scene.standby_mode = static_cast(scene.frogpilot_toggles.value("standby_mode").toBool()); + scene.static_pedals_on_ui = static_cast(scene.frogpilot_toggles.value("static_pedals_on_ui").toBool()); + scene.steering_metrics = static_cast(scene.frogpilot_toggles.value("steering_metrics").toBool()); + scene.stopped_timer = static_cast(scene.frogpilot_toggles.value("stopped_timer").toBool()); + scene.storage_left_metrics = static_cast(scene.frogpilot_toggles.value("storage_left_metrics").toBool()); + scene.storage_used_metrics = static_cast(scene.frogpilot_toggles.value("storage_used_metrics").toBool()); + scene.tethering_config = scene.frogpilot_toggles.value("tethering_config").toDouble(); + scene.unlimited_road_ui_length = static_cast(scene.frogpilot_toggles.value("unlimited_road_ui_length").toBool()); + scene.use_si_metrics = static_cast(scene.frogpilot_toggles.value("use_si_metrics").toBool()); + scene.use_stock_colors = static_cast(scene.frogpilot_toggles.value("color_scheme").toString() == "stock"); + scene.use_stock_wheel = static_cast(scene.frogpilot_toggles.value("wheel_image").toString() == "stock"); + scene.use_wheel_speed = static_cast(scene.frogpilot_toggles.value("use_wheel_speed").toBool()); - scene.conditional_experimental = scene.longitudinal_control && params.getBool("ConditionalExperimental"); - scene.conditional_speed = scene.conditional_experimental ? params.getInt("CESpeed") : 0; - scene.conditional_speed_lead = scene.conditional_experimental ? params.getInt("CESpeedLead") : 0; - scene.show_cem_status_bar = scene.conditional_experimental && !params.getBool("HideCEMStatusBar"); - - bool custom_onroad_ui = params.getBool("CustomUI"); - bool custom_paths = custom_onroad_ui && params.getBool("CustomPaths"); - scene.acceleration_path = custom_paths && params.getBool("AccelerationPath"); - scene.adjacent_path = custom_paths && params.getBool("AdjacentPath"); - scene.blind_spot_path = custom_paths && params.getBool("BlindSpotPath"); - scene.compass = custom_onroad_ui && params.getBool("Compass"); - scene.dynamic_path_width = custom_onroad_ui && params.getBool("DynamicPathWidth"); - scene.pedals_on_ui = custom_onroad_ui && params.getBool("PedalsOnUI"); - scene.dynamic_pedals_on_ui = scene.pedals_on_ui && params.getBool("DynamicPedalsOnUI"); - scene.static_pedals_on_ui = scene.pedals_on_ui && params.getBool("StaticPedalsOnUI"); - scene.road_name_ui = custom_onroad_ui && params.getBool("RoadNameUI"); - scene.rotating_wheel = custom_onroad_ui && params.getBool("RotatingWheel"); - - bool developer_ui = params.getBool("DeveloperUI"); - bool border_metrics = developer_ui && params.getBool("BorderMetrics"); - scene.show_blind_spot = border_metrics && params.getBool("BlindSpotMetrics"); - scene.show_fps = developer_ui && params.getBool("FPSCounter"); - scene.show_signal = border_metrics && params.getBool("SignalMetrics"); - scene.show_steering = border_metrics && params.getBool("ShowSteering"); - bool show_lateral = developer_ui && params.getBool("LateralMetrics"); - scene.adjacent_path_metrics = show_lateral && params.getBool("AdjacentPathMetrics"); - scene.show_tuning = show_lateral && scene.has_auto_tune && params.getBool("TuningInfo"); - bool show_longitudinal = scene.longitudinal_control && developer_ui && params.getBool("LongitudinalMetrics"); - scene.lead_info = show_longitudinal && params.getBool("LeadInfo"); - scene.show_jerk = show_longitudinal && params.getBool("JerkInfo"); - scene.numerical_temp = developer_ui && params.getBool("NumericalTemp"); - scene.fahrenheit = scene.numerical_temp && params.getBool("Fahrenheit"); - scene.sidebar_metrics = developer_ui && params.getBool("SidebarMetrics"); - scene.is_CPU = scene.sidebar_metrics && params.getBool("ShowCPU"); - scene.is_GPU = scene.sidebar_metrics && params.getBool("ShowGPU"); - scene.is_IP = scene.sidebar_metrics && params.getBool("ShowIP"); - scene.is_memory = scene.sidebar_metrics && params.getBool("ShowMemoryUsage"); - scene.is_storage_left = scene.sidebar_metrics && params.getBool("ShowStorageLeft"); - scene.is_storage_used = scene.sidebar_metrics && params.getBool("ShowStorageUsed"); - scene.use_si = developer_ui && params.getBool("UseSI"); - - scene.disable_curve_speed_smoothing = params.getBool("CurveSpeedControl") && params.getBool("DisableCurveSpeedSmoothing"); - - scene.experimental_mode_via_screen = scene.longitudinal_control && params.getBool("ExperimentalModeActivation") && params.getBool("ExperimentalModeViaTap"); - - bool lane_change_customizations = params.getBool("LaneChangeCustomizations"); - scene.lane_detection_width = lane_change_customizations ? params.getInt("LaneDetectionWidth") * distance_conversion / 10.0f : 2.75f; - scene.minimum_lane_change_speed = lane_change_customizations ? params.getInt("MinimumLaneChangeSpeed") * speed_conversion : 20 * (1 / MS_TO_MPH); - - bool advanced_longitudinal_tune = scene.longitudinal_control && params.getBool("AdvancedLongitudinalTune"); - scene.radarless_model = params.get("Model") == "radical-turtle"; - scene.lead_detection_threshold = advanced_longitudinal_tune && !scene.radarless_model ? params.getInt("LeadDetectionThreshold") / 100.0f : 0.5; - - bool model_manager = params.getBool("ModelManagement"); - scene.model_randomizer = model_manager && params.getBool("ModelRandomizer"); - - scene.model_ui = params.getBool("ModelUI"); - scene.lane_line_width = params.getInt("LaneLinesWidth") * small_distance_conversion / 200.0f; - scene.path_edge_width = params.getInt("PathEdgeWidth"); - scene.path_width = params.getFloat("PathWidth") * distance_conversion / 2.0f; - scene.road_edge_width = params.getInt("RoadEdgesWidth") * small_distance_conversion / 200.0f; - scene.unlimited_road_ui_length = scene.model_ui && params.getBool("UnlimitedLength"); - - bool quality_of_life_longitudinal = params.getBool("QOLLongitudinal"); - scene.onroad_distance_button = quality_of_life_longitudinal && params.getBool("OnroadDistanceButton"); - scene.reverse_cruise = quality_of_life_longitudinal && params.getBool("ReverseCruise"); - - bool quality_of_life_visuals = params.getBool("QOLVisuals"); - scene.big_map = quality_of_life_visuals && params.getBool("BigMap"); - scene.full_map = scene.big_map && params.getBool("FullMap"); - scene.driver_camera = quality_of_life_visuals && params.getBool("DriverCamera"); - scene.map_style = quality_of_life_visuals ? params.getInt("MapStyle") : 0; - scene.standby_mode = quality_of_life_visuals && params.getBool("StandbyMode"); - scene.stopped_timer = quality_of_life_visuals && params.getBool("StoppedTimer"); - - scene.random_events = params.getBool("RandomEvents"); - - bool screen_management = params.getBool("ScreenManagement"); - scene.screen_brightness = screen_management ? params.getInt("ScreenBrightness") : 101; - scene.screen_brightness_onroad = screen_management ? params.getInt("ScreenBrightnessOnroad") : 101; - scene.screen_recorder = screen_management && params.getBool("ScreenRecorder"); - scene.screen_timeout = screen_management ? params.getInt("ScreenTimeout") : 30; - scene.screen_timeout_onroad = screen_management ? params.getInt("ScreenTimeoutOnroad") : 10; - - scene.speed_limit_controller = scene.longitudinal_control && params.getBool("SpeedLimitController"); - scene.show_slc_offset = scene.speed_limit_controller && params.getBool("ShowSLCOffset"); - scene.show_slc_offset_ui = scene.speed_limit_controller && params.getBool("ShowSLCOffsetUI"); - scene.use_vienna_slc_sign = scene.speed_limit_controller && params.getBool("UseVienna"); - - scene.tethering_config = params.getInt("TetheringEnabled"); if (scene.tethering_config == 1) { WifiManager(s).setTetheringEnabled(true); } @@ -535,6 +496,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { // FrogPilot variables wifi = new WifiManager(this); + scene.frogpilot_toggles = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotToggles")).toUtf8()).object(); ui_update_params(this); } @@ -548,37 +510,21 @@ void UIState::update() { } emit uiUpdate(*this); - // Update FrogPilot parameters - static bool theme_updated = false; - static bool update_toggles = false; - - if (paramsMemory.getBool("FrogPilotTogglesUpdated")) { - update_toggles = true; - } else if (update_toggles) { - ui_update_params(this); - update_toggles = false; - } - + // Update FrogPilot variables if (paramsMemory.getBool("DriveRated")) { emit driveRated(); paramsMemory.remove("DriveRated"); } - if (theme_updated) { + if (paramsMemory.getBool("ThemeUpdated")) { loadThemeColors("", true); - ui_update_params(this); - - paramsMemory.remove("UpdateTheme"); - - theme_updated = false; - } else if (paramsMemory.getBool("UpdateTheme")) { - theme_updated = true; + paramsMemory.remove("ThemeUpdated"); } // FrogPilot variables that need to be constantly updated scene.conditional_status = scene.conditional_experimental && scene.enabled ? paramsMemory.getInt("CEStatus") : 0; - scene.driver_camera_timer = scene.driver_camera && scene.reverse ? scene.driver_camera_timer + 1 : 0; + scene.driver_camera_timer = scene.driver_camera_in_reverse && scene.reverse ? scene.driver_camera_timer + 1 : 0; scene.force_onroad = paramsMemory.getBool("ForceOnroad"); scene.started_timer = scene.started || started_prev ? scene.started_timer + 1 : 0; } diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 9e559692..9e1d55ca 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -104,7 +104,7 @@ typedef struct UIScene { QPolygonF road_edge_vertices[2]; // lead - QPointF lead_vertices[2]; + QPointF lead_vertices[6]; // DMoji state float driver_pose_vals[3]; @@ -122,27 +122,44 @@ typedef struct UIScene { uint64_t started_frame; // FrogPilot variables + QColor lane_lines_color; + QColor lead_marker_color; + QColor path_color; + QColor path_edges_color; + QColor sidebar_color1; + QColor sidebar_color2; + QColor sidebar_color3; + + QJsonObject frogpilot_toggles; + + QPolygonF track_adjacent_vertices[6]; + QPolygonF track_edge_vertices; + bool acceleration_path; bool adjacent_path; bool adjacent_path_metrics; bool always_on_lateral_active; + bool aol_status_bar; bool big_map; bool blind_spot_left; bool blind_spot_path; bool blind_spot_right; bool brake_lights_on; + bool cem_status_bar; bool compass; bool conditional_experimental; + bool cpu_metrics; bool disable_curve_speed_smoothing; - bool driver_camera; + bool driver_camera_in_reverse; bool dynamic_path_width; bool dynamic_pedals_on_ui; bool enabled; bool experimental_mode; - bool experimental_mode_via_screen; + bool experimental_mode_via_tap; bool fahrenheit; bool force_onroad; bool full_map; + bool gpu_metrics; bool has_auto_tune; bool has_lead; bool hide_alerts; @@ -150,16 +167,13 @@ typedef struct UIScene { bool hide_map_icon; bool hide_max_speed; bool hide_speed; - bool hide_speed_ui; - bool is_CPU; - bool is_GPU; - bool is_IP; - bool is_memory; - bool is_storage_left; - bool is_storage_used; - bool lead_info; + bool ip_metrics; + bool jerk_metrics; + bool lateral_tuning_metrics; + bool lead_metrics; bool live_valid; bool map_open; + bool memory_metrics; bool model_randomizer; bool model_ui; bool numerical_temp; @@ -171,44 +185,40 @@ typedef struct UIScene { bool random_events; bool red_light; bool reverse; - bool reverse_cruise; bool right_hand_drive; bool road_name_ui; bool rotating_wheel; bool screen_recorder; - bool show_aol_status_bar; bool show_blind_spot; - bool show_cem_status_bar; bool show_fps; - bool show_jerk; - bool show_signal; - bool show_slc_offset; - bool show_slc_offset_ui; - bool show_steering; + bool show_speed_limit_offset; bool show_stopping_point; bool show_stopping_point_metrics; - bool show_tuning; bool sidebar_metrics; + bool signal_metrics; bool speed_limit_changed; bool speed_limit_controller; bool speed_limit_overridden; + bool speed_limit_vienna; bool standby_mode; bool standstill; bool static_pedals_on_ui; + bool steering_metrics; bool stopped_timer; + bool storage_left_metrics; + bool storage_used_metrics; bool tethering_enabled; bool traffic_mode; bool traffic_mode_active; bool turn_signal_left; bool turn_signal_right; bool unlimited_road_ui_length; - bool use_si; + bool use_si_metrics; bool use_stock_colors; bool use_stock_wheel; - bool use_vienna_slc_sign; + bool use_wheel_speed; bool vtsc_controlling_curve; bool wake_up_screen; - bool wheel_speed; double fps; @@ -222,7 +232,7 @@ typedef struct UIScene { float lane_width_left; float lane_width_right; float lat_accel; - float lead_detection_threshold; + float lead_detection_probability; float path_edge_width; float path_width; float road_edge_width; @@ -236,8 +246,8 @@ typedef struct UIScene { int bearing_deg; int camera_view; - int conditional_speed; - int conditional_speed_lead; + int conditional_limit; + int conditional_limit_lead; int conditional_status; int desired_follow; int driver_camera_timer; @@ -255,18 +265,6 @@ typedef struct UIScene { int stopped_equivalence; int tethering_config; - QColor lane_lines_color; - QColor lead_marker_color; - QColor path_color; - QColor path_edges_color; - QColor road_edges_color; - QColor sidebar_color1; - QColor sidebar_color2; - QColor sidebar_color3; - - QPolygonF track_adjacent_vertices[6]; - QPolygonF track_edge_vertices; - } UIScene; class UIState : public QObject { @@ -368,4 +366,4 @@ void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert); // FrogPilot functions -void ui_update_frogpilot_params(UIState *s, Params ¶ms); +void ui_update_frogpilot_params(UIState *s); diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 67215aea..096e288c 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -958,12 +958,6 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { } void cameras_run(MultiCameraState *s) { - // FrogPilot variables - Params paramsMemory{"/dev/shm/params"}; - const std::chrono::seconds fpsUpdateInterval(1); - std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); - int frameCount = 0; - LOG("-- Starting threads"); std::vector threads; if (s->driver_cam.enabled) threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera)); @@ -1006,17 +1000,6 @@ void cameras_run(MultiCameraState *s) { // for debugging //do_exit = do_exit || event_data->u.frame_msg.frame_id > (30*20); - frameCount++; - - std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now(); - if (currentTime - startTime >= fpsUpdateInterval) { - auto duration = std::chrono::duration_cast(currentTime - startTime).count(); - double fps = frameCount / duration; - paramsMemory.putIntNonBlocking("CameraFPS", fps / 3); - frameCount = 0; - startTime = currentTime; - } - if (event_data->session_hdl == s->road_cam.session_handle) { s->road_cam.handle_camera_event(event_data); } else if (event_data->session_hdl == s->wide_road_cam.session_handle) { diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index cfde93ba..0bb9d332 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -25,7 +25,7 @@ from openpilot.system.hardware.power_monitoring import PowerMonitoring from openpilot.system.hardware.fan_controller import TiciFanController from openpilot.system.version import terms_version, training_version -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles ThermalStatus = log.DeviceState.ThermalStatus NetworkType = log.DeviceState.NetworkType @@ -166,7 +166,7 @@ def hw_state_thread(end_event, hw_queue): def hardware_thread(end_event, hw_queue) -> None: pm = messaging.PubMaster(['deviceState', 'frogpilotDeviceState']) - sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll="pandaStates") + sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates", "frogpilotPlan"], poll="pandaStates") count = 0 @@ -207,13 +207,10 @@ def hardware_thread(end_event, hw_queue) -> None: fan_controller = None # FrogPilot variables - frogpilot_toggles = FrogPilotVariables.toggles - FrogPilotVariables.update_frogpilot_params() + frogpilot_toggles = get_frogpilot_toggles(True) params_memory = Params("/dev/shm/params") - update_toggles = False - while not end_event.is_set(): sm.update(PANDA_STATES_TIMEOUT) @@ -470,11 +467,8 @@ def hardware_thread(end_event, hw_queue) -> None: should_start_prev = should_start # Update FrogPilot parameters - if FrogPilotVariables.toggles_updated: - update_toggles = True - elif update_toggles: - FrogPilotVariables.update_frogpilot_params(started_ts is not None) - update_toggles = False + if sm['frogpilotPlan'].togglesUpdated: + frogpilot_toggles = get_frogpilot_toggles() def main(): hw_queue = queue.Queue(maxsize=1) diff --git a/system/manager/manager.py b/system/manager/manager.py index 8fa51a8b..adcbe398 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -24,6 +24,7 @@ from openpilot.system.version import get_build_metadata, terms_version, training from openpilot.selfdrive.frogpilot.assets.model_manager import DEFAULT_MODEL, DEFAULT_MODEL_NAME from openpilot.selfdrive.frogpilot.frogpilot_functions import convert_params, frogpilot_boot_functions, setup_frogpilot, uninstall_frogpilot +from openpilot.selfdrive.frogpilot.frogpilot_variables import frogpilot_default_params, get_frogpilot_toggles def manager_init() -> None: @@ -32,9 +33,7 @@ def manager_init() -> None: build_metadata = get_build_metadata() params = Params() - setup_frogpilot(build_metadata, params) - params_storage = Params("/persist/params") params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) @@ -47,10 +46,13 @@ def manager_init() -> None: default_params: list[tuple[str, str | bytes]] = [ ("AlwaysOnDM", "0"), + ("CalibrationParams", ""), ("CarParamsPersistent", ""), ("CompletedTrainingVersion", "0"), ("DisengageOnAccelerator", "0"), ("ExperimentalLongitudinalEnabled", "0"), + ("ExperimentalMode", "0"), + ("ExperimentalModeConfirmed", "0"), ("GithubSshKeys", ""), ("GithubUsername", ""), ("GsmApn", ""), @@ -60,327 +62,14 @@ def manager_init() -> None: ("IsLdwEnabled", "0"), ("IsMetric", "0"), ("LanguageSetting", "main_en"), + ("LiveTorqueParameters", ""), ("NavSettingLeftSide", "0"), ("NavSettingTime24h", "0"), ("OpenpilotEnabledToggle", "1"), ("RecordFront", "0"), ("SshEnabled", "0"), ("TetheringEnabled", "0"), - ("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)), - - # Default FrogPilot parameters - ("AccelerationPath", "1"), - ("AccelerationProfile", "2"), - ("AdjacentPath", "0"), - ("AdjacentPathMetrics", "0"), - ("AdvancedCustomUI", "0"), - ("AdvancedLateralTune", "0"), - ("AdvancedLongitudinalTune", "1"), - ("AdvancedQOLDriving", "1"), - ("AggressiveFollow", "1.25"), - ("AggressiveJerkAcceleration", "50"), - ("AggressiveJerkDanger", "100"), - ("AggressiveJerkDeceleration", "50"), - ("AggressiveJerkSpeed", "50"), - ("AggressiveJerkSpeedDecrease", "50"), - ("AggressivePersonalityProfile", "1"), - ("AlertVolumeControl", "0"), - ("AlwaysOnLateral", "1"), - ("AlwaysOnLateralLKAS", "0"), - ("AlwaysOnLateralMain", "1"), - ("AMapKey1", ""), - ("AMapKey2", ""), - ("AutomaticallyUpdateModels", "0"), - ("AutomaticUpdates", "1"), - ("AvailableModels", ""), - ("AvailableModelsNames", ""), - ("BigMap", "0"), - ("BlacklistedModels", ""), - ("BlindSpotMetrics", "0"), - ("BlindSpotPath", "1"), - ("BorderMetrics", "1"), - ("CameraView", "2"), - ("CarMake", ""), - ("CarModel", ""), - ("CarModelName", ""), - ("CECurves", "1"), - ("CECurvesLead", "1"), - ("CELead", "1"), - ("CENavigation", "1"), - ("CENavigationIntersections", "1"), - ("CENavigationLead", "1"), - ("CENavigationTurns", "1"), - ("CertifiedHerbalistCalibrationParams", ""), - ("CertifiedHerbalistDrives", "0"), - ("CertifiedHerbalistLiveTorqueParameters", ""), - ("CertifiedHerbalistScore", "0"), - ("CEModelStopTime", "8"), - ("CESignalSpeed", "55"), - ("CESignalLaneDetection", "1"), - ("CESlowerLead", "1"), - ("CESpeed", "0"), - ("CESpeedLead", "0"), - ("CEStoppedLead", "1"), - ("ClusterOffset", "1.015"), - ("Compass", "0"), - ("ConditionalExperimental", "1"), - ("CrosstrekTorque", "1"), - ("CurveSensitivity", "100"), - ("CurveSpeedControl", "1"), - ("CustomAlerts", "1"), - ("CustomColors", "frog"), - ("CustomCruise", "1"), - ("CustomCruiseLong", "5"), - ("CustomDistanceIcons", "stock"), - ("CustomIcons", "frog-animated"), - ("CustomPaths", "1"), - ("CustomPersonalities", "0"), - ("CustomSignals", "frog"), - ("CustomSounds", "frog"), - ("CustomUI", "1"), - ("DecelerationProfile", "1"), - ("DeveloperUI", "0"), - ("DeviceManagement", "1"), - ("DeviceShutdown", "9"), - ("DisableCurveSpeedSmoothing", "0"), - ("DisableOnroadUploads", "0"), - ("DisableOpenpilotLongitudinal", "0"), - ("DisengageVolume", "100"), - ("DriverCamera", "0"), - ("DrivingPersonalities", "0"), - ("DuckAmigoCalibrationParams", ""), - ("DuckAmigoDrives", "0"), - ("DuckAmigoLiveTorqueParameters", ""), - ("DuckAmigoScore", "0"), - ("DynamicPathWidth", "0"), - ("DynamicPedalsOnUI", "1"), - ("EngageVolume", "100"), - ("ExperimentalGMTune", "0"), - ("ExperimentalModeActivation", "1"), - ("ExperimentalModels", ""), - ("ExperimentalModeViaDistance", "1"), - ("ExperimentalModeViaLKAS", "1"), - ("ExperimentalModeViaTap", "0"), - ("Fahrenheit", "0"), - ("ForceAutoTune", "1"), - ("ForceAutoTuneOff", "0"), - ("ForceFingerprint", "0"), - ("ForceMPHDashboard", "0"), - ("ForceStandstill", "0"), - ("ForceStops", "0"), - ("FPSCounter", "1"), - ("FrogsGoMoosTweak", "1"), - ("FullMap", "0"), - ("GameBoyCalibrationParams", ""), - ("GameBoyDrives", "0"), - ("GameBoyLiveTorqueParameters", ""), - ("GameBoyScore", "0"), - ("GasRegenCmd", "1"), - ("GMapKey", ""), - ("GoatScream", "0"), - ("GreenLightAlert", "0"), - ("HideAlerts", "0"), - ("HideAOLStatusBar", "0"), - ("HideCEMStatusBar", "0"), - ("HideLeadMarker", "0"), - ("HideMapIcon", "0"), - ("HideMaxSpeed", "0"), - ("HideSpeed", "0"), - ("HideSpeedUI", "0"), - ("HideUIElements", "0"), - ("HolidayThemes", "1"), - ("HumanAcceleration", "1"), - ("HumanFollowing", "1"), - ("IncreasedStoppedDistance", "3"), - ("IncreaseThermalLimits", "0"), - ("JerkInfo", "1"), - ("LaneChangeCustomizations", "1"), - ("LaneChangeTime", "0"), - ("LaneDetectionWidth", "6"), - ("LaneLinesWidth", "4"), - ("LateralMetrics", "1"), - ("LateralTune", "1"), - ("LeadDepartingAlert", "0"), - ("LeadDetectionThreshold", "35"), - ("LeadInfo", "1"), - ("LockDoors", "1"), - ("LongitudinalMetrics", "1"), - ("LongitudinalTune", "1"), - ("LongPitch", "1"), - ("LosAngelesCalibrationParams", ""), - ("LosAngelesDrives", "0"), - ("LosAngelesLiveTorqueParameters", ""), - ("LosAngelesScore", "0"), - ("LoudBlindspotAlert", "0"), - ("LowVoltageShutdown", str(VBATT_PAUSE_CHARGING)), - ("MapAcceleration", "0"), - ("MapDeceleration", "0"), - ("MapGears", "0"), - ("MapboxPublicKey", ""), - ("MapboxSecretKey", ""), - ("MapsSelected", ""), - ("MapStyle", "10"), - ("MaxDesiredAcceleration", "4.0"), - ("MinimumLaneChangeSpeed", str(LANE_CHANGE_SPEED_MIN / CV.MPH_TO_MS)), - ("Model", DEFAULT_MODEL), - ("ModelManagement", "0"), - ("ModelName", DEFAULT_MODEL_NAME), - ("ModelRandomizer", "0"), - ("ModelSelector", "0"), - ("ModelUI", "1"), - ("MTSCCurvatureCheck", "0"), - ("MTSCEnabled", "1"), - ("NavigationModels", ""), - ("NewLongAPI", "0"), - ("NewLongAPIGM", "1"), - ("NewToyotaTune", "0"), - ("NNFF", "1"), - ("NNFFLite", "1"), - ("NoLogging", "0"), - ("NorthDakotaCalibrationParams", ""), - ("NorthDakotaDrives", "0"), - ("NorthDakotaLiveTorqueParameters", ""), - ("NorthDakotaScore", "0"), - ("NotreDameCalibrationParams", ""), - ("NotreDameDrives", "0"), - ("NotreDameLiveTorqueParameters", ""), - ("NotreDameScore", "0"), - ("NoUploads", "0"), - ("NudgelessLaneChange", "1"), - ("NumericalTemp", "1"), - ("OfflineMode", "1"), - ("Offset1", "5"), - ("Offset2", "5"), - ("Offset3", "5"), - ("Offset4", "10"), - ("OneLaneChange", "1"), - ("OnroadDistanceButton", "0"), - ("PathEdgeWidth", "20"), - ("PathWidth", "6.1"), - ("PauseAOLOnBrake", "0"), - ("PauseLateralOnSignal", "0"), - ("PauseLateralSpeed", "0"), - ("PedalsOnUI", "1"), - ("PersonalizeOpenpilot", "1"), - ("PreferredSchedule", "0"), - ("PromptDistractedVolume", "100"), - ("PromptVolume", "100"), - ("QOLLateral", "1"), - ("QOLLongitudinal", "1"), - ("QOLVisuals", "1"), - ("RadarlessModels", ""), - ("RadicalTurtleCalibrationParams", ""), - ("RadicalTurtleDrives", "0"), - ("RadicalTurtleLiveTorqueParameters", ""), - ("RadicalTurtleScore", "0"), - ("RandomEvents", "0"), - ("RecertifiedHerbalistCalibrationParams", ""), - ("RecertifiedHerbalistDrives", "0"), - ("RecertifiedHerbalistLiveTorqueParameters", ""), - ("RecertifiedHerbalistScore", "0"), - ("RefuseVolume", "100"), - ("RelaxedFollow", "1.75"), - ("RelaxedJerkAcceleration", "100"), - ("RelaxedJerkDanger", "100"), - ("RelaxedJerkDeceleration", "100"), - ("RelaxedJerkSpeed", "100"), - ("RelaxedJerkSpeedDecrease", "100"), - ("RelaxedPersonalityProfile", "1"), - ("ResetFrogTheme", "0"), - ("ReverseCruise", "0"), - ("RoadEdgesWidth", "2"), - ("RoadNameUI", "1"), - ("RotatingWheel", "1"), - ("ScreenBrightness", "101"), - ("ScreenBrightnessOnroad", "101"), - ("ScreenManagement", "1"), - ("ScreenRecorder", "1"), - ("ScreenTimeout", "30"), - ("ScreenTimeoutOnroad", "30"), - ("SearchInput", "0"), - ("SecretGoodOpenpilotCalibrationParams", ""), - ("SecretGoodOpenpilotDrives", "0"), - ("SecretGoodOpenpilotLiveTorqueParameters", ""), - ("SecretGoodOpenpilotScore", "0"), - ("SetSpeedLimit", "0"), - ("SetSpeedOffset", "0"), - ("ShowCPU", "1"), - ("ShowGPU", "0"), - ("ShowIP", "0"), - ("ShowMemoryUsage", "1"), - ("ShowSLCOffset", "1"), - ("ShowSLCOffsetUI", "1"), - ("ShowSteering", "1"), - ("ShowStoppingPoint", "0"), - ("ShowStoppingPointMetrics", "0"), - ("ShowStorageLeft", "0"), - ("ShowStorageUsed", "0"), - ("Sidebar", "0"), - ("SidebarMetrics", "1"), - ("SignalMetrics", "0"), - ("SLCConfirmationHigher", "1"), - ("SLCConfirmationLower", "1"), - ("SLCFallback", "2"), - ("SLCLookaheadHigher", "5"), - ("SLCLookaheadLower", "5"), - ("SLCOverride", "1"), - ("SLCPriority1", "Dashboard"), - ("SLCPriority2", "Offline Maps"), - ("SLCPriority3", "Navigation"), - ("SNGHack", "1"), - ("SpeedLimitChangedAlert", "1"), - ("SpeedLimitController", "1"), - ("StartupMessageBottom", "so I do what I want 🐸"), - ("StartupMessageTop", "Hippity hoppity this is my property"), - ("StandardFollow", "1.45"), - ("StandardJerkAcceleration", "100"), - ("StandardJerkDanger", "100"), - ("StandardJerkDeceleration", "100"), - ("StandardJerkSpeed", "100"), - ("StandardJerkSpeedDecrease", "100"), - ("StandardPersonalityProfile", "1"), - ("StandbyMode", "0"), - ("StaticPedalsOnUI", "0"), - ("SteerFriction", "0.1"), - ("SteerFrictionStock", "0.1"), - ("SteerLatAccel", "2.5"), - ("SteerLatAccelStock", "2.5"), - ("SteerKP", "1"), - ("SteerKPStock", "1"), - ("SteerRatio", "15"), - ("SteerRatioStock", "15"), - ("StoppedTimer", "0"), - ("TacoTune", "0"), - ("TombRaiderCalibrationParams", ""), - ("TombRaiderDrives", "0"), - ("TombRaiderLiveTorqueParameters", ""), - ("TombRaiderScore", "0"), - ("ToyotaDoors", "0"), - ("TrafficFollow", "0.5"), - ("TrafficJerkAcceleration", "50"), - ("TrafficJerkDanger", "100"), - ("TrafficJerkDeceleration", "50"), - ("TrafficJerkSpeed", "50"), - ("TrafficJerkSpeedDecrease", "50"), - ("TrafficPersonalityProfile", "1"), - ("TuningInfo", "1"), - ("TurnAggressiveness", "100"), - ("TurnDesires", "0"), - ("UnlimitedLength", "1"), - ("UnlockDoors", "1"), - ("UseSI", "1"), - ("UseVienna", "0"), - ("VelocityModels", ""), - ("VisionTurnControl", "1"), - ("VoltSNG", "0"), - ("WarningImmediateVolume", "100"), - ("WarningSoftVolume", "100"), - ("WD40CalibrationParams", ""), - ("WD40Drives", "0"), - ("WD40LiveTorqueParameters", ""), - ("WD40Score", "0"), - ("WheelIcon", "frog"), - ("WheelSpeed", "0") + ("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)) ] if not PC: default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8'))) @@ -389,7 +78,7 @@ def manager_init() -> None: params.put_bool("RecordFront", True) # set unset params - for k, v in default_params: + for k, v in default_params + frogpilot_default_params: if params.get(k) is None or params.get_bool("DoToggleReset"): if params_storage.get(k) is None: params.put(k, v) @@ -476,16 +165,21 @@ def manager_thread() -> None: ignore.append("pandad") ignore += [x for x in os.getenv("BLOCK", "").split(",") if len(x) > 0] - sm = messaging.SubMaster(['deviceState', 'carParams'], poll='deviceState') + sm = messaging.SubMaster(['deviceState', 'carParams', 'frogpilotPlan'], poll='deviceState') pm = messaging.PubMaster(['managerState']) write_onroad_params(False, params) - ensure_running(managed_processes.values(), False, params=params, CP=sm['carParams'], not_run=ignore, secret_good_openpilot=False) + ensure_running(managed_processes.values(), False, params=params, CP=sm['carParams'], not_run=ignore, classic_model=False) started_prev = False # FrogPilot variables - secret_good_openpilot = params.get("Model", encoding='utf-8') == "secret-good-openpilot" + frogpilot_toggles = get_frogpilot_toggles(True) + classic_model = getattr(frogpilot_toggles, 'classic_model', False) + + error_log = os.path.join(sentry.CRASHES_DIR, 'error.txt') + if os.path.isfile(error_log): + os.remove(error_log) while True: sm.update(1000) @@ -495,12 +189,11 @@ def manager_thread() -> None: if started and not started_prev: params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) - error_log = os.path.join(sentry.CRASHES_DIR, 'error.txt') if os.path.isfile(error_log): os.remove(error_log) # FrogPilot variables - secret_good_openpilot = params.get("Model", encoding='utf-8') == "secret-good-openpilot" + classic_model = frogpilot_toggles.classic_model elif not started and started_prev: params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) @@ -512,7 +205,7 @@ def manager_thread() -> None: started_prev = started - ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore, secret_good_openpilot=secret_good_openpilot) + ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore, classic_model=classic_model) running = ' '.join("{}{}\u001b[0m".format("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name) for p in managed_processes.values() if p.proc) @@ -535,6 +228,9 @@ def manager_thread() -> None: if shutdown: break + # Update FrogPilot parameters + if sm['frogpilotPlan'].togglesUpdated: + frogpilot_toggles = get_frogpilot_toggles() def main() -> None: manager_init() diff --git a/system/manager/process.py b/system/manager/process.py index 7eef9adf..54ddd5b3 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -76,6 +76,9 @@ class ManagerProcess(ABC): watchdog_seen = False shutting_down = False + # FrogPilot variables + started_time = 0 + @abstractmethod def prepare(self) -> None: pass @@ -102,11 +105,14 @@ class ManagerProcess(ABC): dt = time.monotonic() - self.last_watchdog_time / 1e9 + self.started_time = self.started_time + 1 if started else 0 + if dt > self.watchdog_max_dt: if self.watchdog_seen and ENABLE_WATCHDOG: cloudlog.error(f"Watchdog timeout for {self.name} (exitcode {self.proc.exitcode}) restarting ({started=})") self.restart() - sentry.capture_tmux(self.name, params) + if self.started_time > 100: + sentry.capture_tmux(self.name, self.started_time, params) else: self.watchdog_seen = True @@ -239,7 +245,7 @@ class DaemonProcess(ManagerProcess): self.params = None @staticmethod - def should_run(started, params, CP, secret_good_openpilot): + def should_run(started, params, CP, classic_model): return True def prepare(self) -> None: @@ -275,13 +281,13 @@ class DaemonProcess(ManagerProcess): def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None, CP: car.CarParams=None, - not_run: list[str] | None=None, secret_good_openpilot=False) -> list[ManagerProcess]: + not_run: list[str] | None=None, classic_model=False) -> list[ManagerProcess]: if not_run is None: not_run = [] running = [] for p in procs: - if p.enabled and p.name not in not_run and p.should_run(started, params, CP, secret_good_openpilot): + if p.enabled and p.name not in not_run and p.should_run(started, params, CP, classic_model): running.append(p) else: p.stop(block=False) diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 9046c89e..10724a53 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -7,54 +7,54 @@ from openpilot.system.manager.process import PythonProcess, NativeProcess, Daemo WEBCAM = os.getenv("USE_WEBCAM") is not None -def driverview(started: bool, params: Params, CP: car.CarParams, secret_good_openpilot) -> bool: +def driverview(started: bool, params: Params, CP: car.CarParams, classic_model) -> bool: return started or params.get_bool("IsDriverViewEnabled") -def notcar(started: bool, params: Params, CP: car.CarParams, secret_good_openpilot) -> bool: +def notcar(started: bool, params: Params, CP: car.CarParams, classic_model) -> bool: return started and CP.notCar -def iscar(started: bool, params: Params, CP: car.CarParams, secret_good_openpilot) -> bool: +def iscar(started: bool, params: Params, CP: car.CarParams, classic_model) -> bool: return started and not CP.notCar -def logging(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def logging(started, params, CP: car.CarParams, classic_model) -> bool: run = (not CP.notCar) or not params.get_bool("DisableLogging") return started and run def ublox_available() -> bool: return os.path.exists('/dev/ttyHS0') and not os.path.exists('/persist/comma/use-quectel-gps') -def ublox(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def ublox(started, params, CP: car.CarParams, classic_model) -> bool: use_ublox = ublox_available() if use_ublox != params.get_bool("UbloxAvailable"): params.put_bool("UbloxAvailable", use_ublox) return started and use_ublox -def qcomgps(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def qcomgps(started, params, CP: car.CarParams, classic_model) -> bool: return started and not ublox_available() -def always_run(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def always_run(started, params, CP: car.CarParams, classic_model) -> bool: return True -def only_onroad(started: bool, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def only_onroad(started: bool, params, CP: car.CarParams, classic_model) -> bool: return started -def only_offroad(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def only_offroad(started, params, CP: car.CarParams, classic_model) -> bool: return not started # FrogPilot functions -def allow_logging(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def allow_logging(started, params, CP: car.CarParams, classic_model) -> bool: allow_logging = not (params.get_bool("DeviceManagement") and params.get_bool("NoLogging")) - return allow_logging and logging(started, params, CP, secret_good_openpilot) + return allow_logging and logging(started, params, CP, classic_model) -def allow_uploads(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: +def allow_uploads(started, params, CP: car.CarParams, classic_model) -> bool: allow_uploads = not (params.get_bool("DeviceManagement") and params.get_bool("NoUploads") and not params.get_bool("DisableOnroadUploads")) return allow_uploads -def run_classic_modeld(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: - return started and not secret_good_openpilot +def run_classic_modeld(started, params, CP: car.CarParams, classic_model) -> bool: + return started and classic_model -def run_new_modeld(started, params, CP: car.CarParams, secret_good_openpilot) -> bool: - return started and secret_good_openpilot +def run_new_modeld(started, params, CP: car.CarParams, classic_model) -> bool: + return started and not classic_model procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), diff --git a/system/sentry.py b/system/sentry.py index 082c7145..15a402a3 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -100,7 +100,7 @@ def capture_fingerprint(candidate, params, blocked=False): sentry_sdk.flush() -def capture_tmux(process, params) -> None: +def capture_tmux(process, started_time, params) -> None: updated = params.get("Updated", encoding='utf-8') result = subprocess.run(['tmux', 'capture-pane', '-p', '-S', '-50'], stdout=subprocess.PIPE) @@ -109,7 +109,7 @@ def capture_tmux(process, params) -> None: if lines: with sentry_sdk.configure_scope() as scope: scope.set_extra("tmux_log", "\n".join(lines)) - sentry_sdk.capture_message(f"{process} crashed - Last updated: {updated}", level='info') + sentry_sdk.capture_message(f"{process} crashed - Last updated: {updated} - Started time: {started_time}", level='info') sentry_sdk.flush() diff --git a/system/updated/updated.py b/system/updated/updated.py index 61504c29..9e4f8f5f 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -22,7 +22,7 @@ from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert from openpilot.system.hardware import AGNOS, HARDWARE from openpilot.system.version import get_build_metadata -from openpilot.selfdrive.frogpilot.frogpilot_variables import FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import get_frogpilot_toggles LOCK_FILE = os.getenv("UPDATER_LOCK_FILE", "/tmp/safe_staging_overlay.lock") STAGING_ROOT = os.getenv("UPDATER_STAGING_ROOT", "/data/safe_staging") @@ -327,7 +327,7 @@ class Updater: set_offroad_alert(alert, False) now = datetime.datetime.utcnow() - if FrogPilotVariables.toggles.offline_mode: + if get_frogpilot_toggles(True).offline_mode: last_update = now dt = now - last_update build_metadata = get_build_metadata()