November 2024 Update
|
@ -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
|
||||
------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -211,12 +211,11 @@ std::unordered_map<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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<std::string, uint32_t> 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},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"}]}
|
|
@ -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):
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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): [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -23,12 +23,6 @@
|
|||
"blue": 54,
|
||||
"alpha": 242
|
||||
},
|
||||
"RoadEdges": {
|
||||
"red": 23,
|
||||
"green": 134,
|
||||
"blue": 68,
|
||||
"alpha": 242
|
||||
},
|
||||
"Sidebar1": {
|
||||
"red": 23,
|
||||
"green": 134,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -23,12 +23,6 @@
|
|||
"blue": 255,
|
||||
"alpha": 255
|
||||
},
|
||||
"RoadEdges": {
|
||||
"red": 242,
|
||||
"green": 117,
|
||||
"blue": 3,
|
||||
"alpha": 255
|
||||
},
|
||||
"Sidebar1": {
|
||||
"red": 134,
|
||||
"green": 47,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 63 KiB |
|
@ -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'):
|
||||
|
|
Before Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 658 KiB |
|
@ -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)
|
||||
|
|
Before Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 9.1 KiB |
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||
std::vector<QString> 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] {
|
||||
|
|
|
@ -5,14 +5,14 @@ FrogPilotPrimelessPanel::FrogPilotPrimelessPanel(FrogPilotSettingsWindow *parent
|
|||
|
||||
std::vector<QString> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ public:
|
|||
explicit FrogPilotPrimelessPanel(FrogPilotSettingsWindow *parent);
|
||||
|
||||
signals:
|
||||
void closeMapBoxInstructions();
|
||||
void openMapBoxInstructions();
|
||||
|
||||
private:
|
||||
|
|
|
@ -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<std::tuple<QString, QString, QString, QString>> 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<QString> 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<QString> steerFrictionToggleNames{"Reset"};
|
||||
advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0.01, 0.25, QString(), std::map<int, QString>(), 0.01, {}, steerFrictionToggleNames, false);
|
||||
} else if (param == "SteerKP") {
|
||||
std::vector<QString> steerKPToggleNames{"Reset"};
|
||||
advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerKPStock * 0.50, steerKPStock * 1.50, QString(), std::map<int, QString>(), 0.01, {}, steerKPToggleNames, false);
|
||||
} else if (param == "SteerLatAccel") {
|
||||
std::vector<QString> steerLatAccelToggleNames{"Reset"};
|
||||
advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerLatAccelStock * 0.25, steerLatAccelStock * 1.25, QString(), std::map<int, QString>(), 0.01, {}, steerLatAccelToggleNames, false);
|
||||
} else if (param == "SteerRatio") {
|
||||
std::vector<QString> steerRatioToggleNames{"Reset"};
|
||||
advancedDrivingToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, QString(), std::map<int, QString>(), 0.01, {}, steerRatioToggleNames, false);
|
||||
|
||||
} else if (param == "AdvancedLongitudinalTune") {
|
||||
FrogPilotParamManageControl *advancedLongitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon);
|
||||
QObject::connect(advancedLongitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||
std::set<QString> 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<int, QString>(), 0.1);
|
||||
|
||||
} else if (param == "AdvancedQOLDriving") {
|
||||
FrogPilotParamManageControl *advancedQOLToggle = new FrogPilotParamManageControl(param, title, desc, icon);
|
||||
QObject::connect(advancedQOLToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||
std::set<QString> 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<int, QString>(), 0.01);
|
||||
} else {
|
||||
advancedDrivingToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 5, tr(" seconds"), std::map<int, QString>(), 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<AbstractControl*>(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<AbstractControl*>(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<QString, QString> 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<AbstractControl*>(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<QString, QString> 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<AbstractControl*>(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<AbstractControl*>(downloadAllModelsBtn);
|
||||
} else if (param == "SelectModel") {
|
||||
selectModelBtn = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(selectModelBtn, &ButtonControl::clicked, [this]() {
|
||||
QSet<QString> modelFilesBaseNames = QSet<QString>::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<AbstractControl*>(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<FrogPilotParamManageControl*>(advancedDrivingToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotParamManageControl::manageButtonClicked, this, &FrogPilotAdvancedDrivingPanel::openParentToggle);
|
||||
}
|
||||
|
||||
QObject::connect(advancedDrivingToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles["ModelManagement"]), &ToggleControl::toggleFlipped, [this](bool state) {
|
||||
modelManagement = state;
|
||||
});
|
||||
|
||||
QObject::connect(static_cast<ToggleControl*>(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<FrogPilotParamValueButtonControl*>(toggles["SteerFriction"]);
|
||||
QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerFriction", steerFrictionStock);
|
||||
steerFrictionToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerKPToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerKP"]);
|
||||
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerKP", steerKPStock);
|
||||
steerKPToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerLatAccelToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerLatAccel"]);
|
||||
QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerLatAccel", steerLatAccelStock);
|
||||
steerLatAccelToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerRatioToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerRatio"]);
|
||||
QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerRatio", steerRatioStock);
|
||||
steerRatioToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
FrogPilotParamValueControl *trafficFollowToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficFollow"]);
|
||||
FrogPilotParamValueControl *trafficAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *trafficDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *trafficDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkDanger"]);
|
||||
FrogPilotParamValueControl *trafficSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeed"]);
|
||||
FrogPilotParamValueControl *trafficSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *trafficResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["AggressiveFollow"]);
|
||||
FrogPilotParamValueControl *aggressiveAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *aggressiveDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *aggressiveDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkDanger"]);
|
||||
FrogPilotParamValueControl *aggressiveSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeed"]);
|
||||
FrogPilotParamValueControl *aggressiveSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *aggressiveResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["StandardFollow"]);
|
||||
FrogPilotParamValueControl *standardAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *standardDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *standardDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkDanger"]);
|
||||
FrogPilotParamValueControl *standardSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeed"]);
|
||||
FrogPilotParamValueControl *standardSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *standardResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["RelaxedFollow"]);
|
||||
FrogPilotParamValueControl *relaxedAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *relaxedDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *relaxedDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkDanger"]);
|
||||
FrogPilotParamValueControl *relaxedSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeed"]);
|
||||
FrogPilotParamValueControl *relaxedSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *relaxedResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(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<cereal::Event>().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<FrogPilotButtonsControl *>(sender())->setDescription(desc);
|
||||
}
|
||||
|
||||
void FrogPilotAdvancedDrivingPanel::updateModelLabels() {
|
||||
QVector<QPair<QString, int>> 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<QString, int> &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<QString> &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<QString> 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);
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#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<QString> &keys);
|
||||
|
||||
void startDownloadAllModels();
|
||||
void updateCalibrationDescription();
|
||||
void updateCarToggles();
|
||||
void updateMetric();
|
||||
void updateModelLabels();
|
||||
void updateState(const UIState &s);
|
||||
|
||||
std::set<QString> aggressivePersonalityKeys = {
|
||||
"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration",
|
||||
"AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease",
|
||||
"ResetAggressivePersonality"
|
||||
};
|
||||
|
||||
std::set<QString> customDrivingPersonalityKeys = {
|
||||
"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile",
|
||||
"TrafficPersonalityProfile"
|
||||
};
|
||||
|
||||
std::set<QString> lateralTuneKeys = {
|
||||
"ForceAutoTune", "ForceAutoTuneOff", "SteerFriction",
|
||||
"SteerLatAccel", "SteerKP", "SteerRatio", "TacoTune",
|
||||
"TurnDesires"
|
||||
};
|
||||
|
||||
std::set<QString> longitudinalTuneKeys = {
|
||||
"LeadDetectionThreshold", "MaxDesiredAcceleration"
|
||||
};
|
||||
|
||||
std::set<QString> modelManagementKeys = {
|
||||
"AutomaticallyUpdateModels", "DeleteModel", "DownloadModel",
|
||||
"DownloadAllModels", "ModelRandomizer", "ResetCalibrations",
|
||||
"SelectModel"
|
||||
};
|
||||
|
||||
std::set<QString> modelRandomizerKeys = {
|
||||
"ManageBlacklistedModels", "ResetScores", "ReviewScores"
|
||||
};
|
||||
|
||||
std::set<QString> qolKeys = {
|
||||
"ForceStandstill", "ForceStops", "SetSpeedOffset"
|
||||
};
|
||||
|
||||
std::set<QString> relaxedPersonalityKeys = {
|
||||
"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration",
|
||||
"RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease",
|
||||
"ResetRelaxedPersonality"
|
||||
};
|
||||
|
||||
std::set<QString> standardPersonalityKeys = {
|
||||
"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration",
|
||||
"StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease",
|
||||
"ResetStandardPersonality"
|
||||
};
|
||||
|
||||
std::set<QString> 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<LabelControl*> 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<QString, AbstractControl*> toggles;
|
||||
};
|
|
@ -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<std::tuple<QString, QString, QString, QString>> 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<QString> 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<QString> hideSpeedToggles{"HideSpeedUI"};
|
||||
std::vector<QString> hideSpeedToggleNames{tr("Control Via UI")};
|
||||
advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, hideSpeedToggles, hideSpeedToggleNames);
|
||||
} else if (param == "HideUIElements") {
|
||||
std::vector<QString> uiElementsToggles{"HideAlerts", "HideMapIcon", "HideMaxSpeed"};
|
||||
std::vector<QString> uiElementsToggleNames{tr("Alerts"), tr("Map Icon"), tr("Max Speed")};
|
||||
advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, uiElementsToggles, uiElementsToggleNames);
|
||||
} else if (param == "ShowStoppingPoint") {
|
||||
std::vector<QString> stoppingPointToggles{"ShowStoppingPointMetrics"};
|
||||
std::vector<QString> 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<QString> modifiedDeveloperUIKeys = developerUIKeys;
|
||||
|
||||
if (disableOpenpilotLongitudinal || !hasOpenpilotLongitudinal) {
|
||||
modifiedDeveloperUIKeys.erase("LongitudinalMetrics");
|
||||
}
|
||||
|
||||
showToggles(modifiedDeveloperUIKeys);
|
||||
});
|
||||
advancedVisualToggle = developerUIToggle;
|
||||
} else if (param == "BorderMetrics") {
|
||||
std::vector<QString> borderToggles{"BlindSpotMetrics", "ShowSteering", "SignalMetrics"};
|
||||
std::vector<QString> 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<QString> lateralToggles{"AdjacentPathMetrics", "TuningInfo"};
|
||||
std::vector<QString> lateralToggleNames{tr("Adjacent Path Metrics"), tr("Auto Tune")};
|
||||
lateralMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, lateralToggles, lateralToggleNames);
|
||||
advancedVisualToggle = lateralMetricsBtn;
|
||||
} else if (param == "LongitudinalMetrics") {
|
||||
std::vector<QString> longitudinalToggles{"LeadInfo", "JerkInfo"};
|
||||
std::vector<QString> longitudinalToggleNames{tr("Lead Info"), tr("Jerk Values")};
|
||||
longitudinalMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, longitudinalToggles, longitudinalToggleNames);
|
||||
advancedVisualToggle = longitudinalMetricsBtn;
|
||||
} else if (param == "NumericalTemp") {
|
||||
std::vector<QString> temperatureToggles{"Fahrenheit"};
|
||||
std::vector<QString> temperatureToggleNames{tr("Fahrenheit")};
|
||||
advancedVisualToggle = new FrogPilotButtonToggleControl(param, title, desc, temperatureToggles, temperatureToggleNames);
|
||||
} else if (param == "SidebarMetrics") {
|
||||
std::vector<QString> sidebarMetricsToggles{"ShowCPU", "ShowGPU", "ShowIP", "ShowMemoryUsage", "ShowStorageLeft", "ShowStorageUsed"};
|
||||
std::vector<QString> 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<QString> 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<int, QString>(), 0.1);
|
||||
|
||||
} else {
|
||||
advancedVisualToggle = new ParamControl(param, title, desc, icon);
|
||||
}
|
||||
|
||||
addItem(advancedVisualToggle);
|
||||
toggles[param] = advancedVisualToggle;
|
||||
|
||||
makeConnections(advancedVisualToggle);
|
||||
|
||||
if (FrogPilotParamManageControl *frogPilotManageToggle = qobject_cast<FrogPilotParamManageControl*>(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<FrogPilotParamValueControl*>(toggles["LaneLinesWidth"]);
|
||||
FrogPilotParamValueControl *pathWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["PathWidth"]);
|
||||
FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast<FrogPilotParamValueControl*>(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<QString> &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();
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#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<QString> &keys);
|
||||
void updateCarToggles();
|
||||
void updateMetric();
|
||||
|
||||
std::set<QString> advancedCustomOnroadUIKeys = {
|
||||
"CameraView", "HideLeadMarker", "HideSpeed",
|
||||
"HideUIElements", "ShowStoppingPoint", "WheelSpeed"
|
||||
};
|
||||
|
||||
std::set<QString> developerUIKeys = {
|
||||
"BorderMetrics", "FPSCounter", "LateralMetrics",
|
||||
"LongitudinalMetrics", "NumericalTemp",
|
||||
"SidebarMetrics", "UseSI"
|
||||
};
|
||||
|
||||
std::set<QString> 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<QString, AbstractControl*> toggles;
|
||||
};
|
|
@ -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([=] {
|
||||
|
|
|
@ -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<std::tuple<QString, QString, QString, QString>> 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<QString> 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<QString> modifiedScreenKeys = screenKeys;
|
||||
|
||||
showToggles(modifiedScreenKeys);
|
||||
});
|
||||
deviceToggle = screenToggle;
|
||||
} else if (param == "ScreenBrightness" || param == "ScreenBrightnessOnroad") {
|
||||
std::map<int, QString> 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();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ signals:
|
|||
|
||||
private:
|
||||
void hideToggles();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void showToggles(const std::set<QString> &keys);
|
||||
void updateState(const UIState &s);
|
||||
|
||||
|
@ -28,9 +29,13 @@ private:
|
|||
"ScreenTimeout", "ScreenTimeoutOnroad"
|
||||
};
|
||||
|
||||
FrogPilotSettingsWindow *parent;
|
||||
|
||||
Params params;
|
||||
|
||||
bool started;
|
||||
|
||||
int customizationLevel;
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
};
|
||||
|
|
|
@ -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<QString> 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<std::pair<QString, std::vector<QWidget*>>> 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<QString> 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<QString> 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<std::vector<QString>> 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<cereal::Event>();
|
||||
|
||||
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<QString> &button_labels, QString &icon, std::vector<QWidget*> &panels, bool isDrivingPanel, bool isNavigationPanel) {
|
||||
void FrogPilotSettingsWindow::addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector<QString> &button_labels, QString &icon, std::vector<QWidget*> &panels, QString ¤tPanel) {
|
||||
std::vector<QWidget*> 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);
|
||||
}
|
||||
|
|
|
@ -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<QString> &button_labels, QString &icon, std::vector<QWidget*> &panels, bool isDrivingPanel, bool isNavigationPanel);
|
||||
void addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector<QString> &button_labels, QString &icon, std::vector<QWidget*> &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;
|
||||
|
||||
|
|
|
@ -2,22 +2,32 @@
|
|||
|
||||
FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> 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<QString> 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<QString> steerFrictionToggleNames{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0.01, 0.25, QString(), std::map<int, QString>(), 0.01, {}, steerFrictionToggleNames, false, false);
|
||||
} else if (param == "SteerKP") {
|
||||
std::vector<QString> steerKPToggleNames{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerKPStock * 0.50, steerKPStock * 1.50, QString(), std::map<int, QString>(), 0.01, {}, steerKPToggleNames, false, false);
|
||||
} else if (param == "SteerLatAccel") {
|
||||
std::vector<QString> steerLatAccelToggleNames{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerLatAccelStock * 0.25, steerLatAccelStock * 1.25, QString(), std::map<int, QString>(), 0.01, {}, steerLatAccelToggleNames, false, false);
|
||||
} else if (param == "SteerRatio") {
|
||||
std::vector<QString> steerRatioToggleNames{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, QString(), std::map<int, QString>(), 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<QString> 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<QString> 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<int, QString>(), 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<QString> pauseLateralToggles{"PauseLateralOnSignal"};
|
||||
std::vector<QString> pauseLateralToggleNames{"Turn Signal Only"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map<int, QString>(), 1, pauseLateralToggles, pauseLateralToggleNames);
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map<int, QString>(), 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<int, QString> 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<int, QString>(), 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<FrogPilotParamValueButtonControl*>(toggles["SteerFriction"]);
|
||||
QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerFriction", steerFrictionStock);
|
||||
steerFrictionToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerKPToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerKP"]);
|
||||
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerKP", steerKPStock);
|
||||
steerKPToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerLatAccelToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerLatAccel"]);
|
||||
QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
params.putFloat("SteerLatAccel", steerLatAccelStock);
|
||||
steerLatAccelToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
});
|
||||
|
||||
steerRatioToggle = static_cast<FrogPilotParamValueButtonControl*>(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();
|
||||
}
|
||||
|
|
|
@ -15,30 +15,41 @@ signals:
|
|||
|
||||
private:
|
||||
void hideToggles();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void showToggles(const std::set<QString> &keys);
|
||||
void updateMetric();
|
||||
void updateCarToggles();
|
||||
void updateState(const UIState &s);
|
||||
|
||||
std::set<QString> advancedLateralTuneKeys = {
|
||||
"ForceAutoTune", "ForceAutoTuneOff", "SteerFriction",
|
||||
"SteerLatAccel", "SteerKP", "SteerRatio"
|
||||
};
|
||||
|
||||
std::set<QString> aolKeys = {
|
||||
"AlwaysOnLateralLKAS", "AlwaysOnLateralMain",
|
||||
"HideAOLStatusBar", "PauseAOLOnBrake"
|
||||
"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "HideAOLStatusBar",
|
||||
"PauseAOLOnBrake"
|
||||
};
|
||||
|
||||
std::set<QString> laneChangeKeys = {
|
||||
"LaneChangeTime", "LaneDetectionWidth",
|
||||
"MinimumLaneChangeSpeed", "NudgelessLaneChange",
|
||||
"OneLaneChange"
|
||||
"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed",
|
||||
"NudgelessLaneChange", "OneLaneChange"
|
||||
};
|
||||
|
||||
std::set<QString> lateralTuneKeys = {
|
||||
"NNFF", "NNFFLite"
|
||||
"NNFF", "NNFFLite", "TacoTune",
|
||||
"TurnDesires"
|
||||
};
|
||||
|
||||
std::set<QString> 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<QString, AbstractControl*> toggles;
|
||||
};
|
||||
|
|
|
@ -2,68 +2,169 @@
|
|||
|
||||
FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> 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<int, QString>(), 0.01);
|
||||
} else {
|
||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 5, tr(" seconds"), std::map<int, QString>(), 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<QString> 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<QString> navigationToggleNames{tr("Intersections"), tr("Turns"), tr("With Lead")};
|
||||
longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, navigationToggles, navigationToggleNames);
|
||||
} else if (param == "CEModelStopTime") {
|
||||
std::map<int, QString> 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<QString> ceSignalToggles{"CESignalLaneDetection"};
|
||||
std::vector<QString> ceSignalToggleNames{"Lane Detection"};
|
||||
longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map<int, QString>(), 1.0, ceSignalToggles, ceSignalToggleNames);
|
||||
std::vector<QString> ceSignalToggleNames{"Only For Detected Lanes"};
|
||||
longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map<int, QString>(), 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<QString> 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<QString> profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")};
|
||||
ButtonParamControl *profileSelection = new ButtonParamControl(param, title, desc, icon, profileOptions);
|
||||
longitudinalToggle = profileSelection;
|
||||
std::vector<QString> 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<QString> profileOptions{tr("Standard"), tr("Eco"), tr("Sport")};
|
||||
ButtonParamControl *profileSelection = new ButtonParamControl(param, title, desc, icon, profileOptions);
|
||||
longitudinalToggle = profileSelection;
|
||||
std::vector<QString> 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<int, QString>(), 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<QString> mapGearsToggles{"MapAcceleration", "MapDeceleration"};
|
||||
std::vector<QString> 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<QString> 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<QString> confirmationToggles{"SLCConfirmationLower", "SLCConfirmationHigher"};
|
||||
std::vector<QString> confirmationToggleNames{tr("Lower Limits"), tr("Higher Limits")};
|
||||
longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, confirmationToggles, confirmationToggleNames);
|
||||
} else if (param == "SLCFallback") {
|
||||
std::vector<QString> 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<QString> overrideOptions{tr("None"), tr("Gas Pedal Press"), tr("Cruise Set Speed")};
|
||||
std::vector<QString> 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<AbstractControl*>(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<AbstractControl*>(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<QString> slcOffsetToggles{"ShowSLCOffsetUI"};
|
||||
std::vector<QString> 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<FrogPilotParamValueControl*>(toggles["TrafficFollow"]);
|
||||
FrogPilotParamValueControl *trafficAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *trafficDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *trafficDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkDanger"]);
|
||||
FrogPilotParamValueControl *trafficSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeed"]);
|
||||
FrogPilotParamValueControl *trafficSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["TrafficJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *trafficResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["AggressiveFollow"]);
|
||||
FrogPilotParamValueControl *aggressiveAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *aggressiveDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *aggressiveDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkDanger"]);
|
||||
FrogPilotParamValueControl *aggressiveSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeed"]);
|
||||
FrogPilotParamValueControl *aggressiveSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["AggressiveJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *aggressiveResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["StandardFollow"]);
|
||||
FrogPilotParamValueControl *standardAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *standardDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *standardDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkDanger"]);
|
||||
FrogPilotParamValueControl *standardSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeed"]);
|
||||
FrogPilotParamValueControl *standardSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["StandardJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *standardResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotParamValueControl*>(toggles["RelaxedFollow"]);
|
||||
FrogPilotParamValueControl *relaxedAccelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkAcceleration"]);
|
||||
FrogPilotParamValueControl *relaxedDecelerationToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkDeceleration"]);
|
||||
FrogPilotParamValueControl *relaxedDangerToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkDanger"]);
|
||||
FrogPilotParamValueControl *relaxedSpeedToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeed"]);
|
||||
FrogPilotParamValueControl *relaxedSpeedDecreaseToggle = static_cast<FrogPilotParamValueControl*>(toggles["RelaxedJerkSpeedDecrease"]);
|
||||
FrogPilotButtonsControl *relaxedResetButton = static_cast<FrogPilotButtonsControl*>(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<FrogPilotDualParamControl*>(toggles["CESpeed"]);
|
||||
|
@ -422,6 +646,7 @@ void FrogPilotLongitudinalPanel::updateMetric() {
|
|||
FrogPilotParamValueControl *offset3Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset3"]);
|
||||
FrogPilotParamValueControl *offset4Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset4"]);
|
||||
FrogPilotParamValueControl *increasedStoppedDistanceToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistance"]);
|
||||
FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast<FrogPilotParamValueControl*>(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<QString> &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<QString> modifiedSpeedLimitControllerKeys = speedLimitControllerKeys;
|
||||
|
||||
if (customizationLevel == 0) {
|
||||
modifiedSpeedLimitControllerKeys.erase("SLCFallback");
|
||||
modifiedSpeedLimitControllerKeys.erase("SLCOverride");
|
||||
modifiedSpeedLimitControllerKeys.erase("SLCPriority");
|
||||
modifiedSpeedLimitControllerKeys.erase("SLCQOL");
|
||||
}
|
||||
|
||||
showToggles(modifiedSpeedLimitControllerKeys);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,40 +17,58 @@ signals:
|
|||
private:
|
||||
void hideSubToggles();
|
||||
void hideToggles();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void showToggles(const std::set<QString> &keys);
|
||||
void updateCarToggles();
|
||||
void updateMetric();
|
||||
|
||||
std::set<QString> aggressivePersonalityKeys = {
|
||||
"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration",
|
||||
"AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease",
|
||||
"ResetAggressivePersonality"
|
||||
};
|
||||
|
||||
std::set<QString> conditionalExperimentalKeys = {
|
||||
"CESpeed", "CESpeedLead", "CECurves", "CELead",
|
||||
"CEModelStopTime", "CENavigation", "CESignalSpeed",
|
||||
"HideCEMStatusBar"
|
||||
"CESpeed", "CESpeedLead", "CECurves",
|
||||
"CELead", "CEModelStopTime", "CENavigation",
|
||||
"CESignalSpeed", "HideCEMStatusBar"
|
||||
};
|
||||
|
||||
std::set<QString> curveSpeedKeys = {
|
||||
"CurveDetectionMethod", "CurveSensitivity",
|
||||
"DisableCurveSpeedSmoothing", "MTSCCurvatureCheck",
|
||||
"TurnAggressiveness"
|
||||
"CurveDetectionMethod", "CurveSensitivity", "DisableCurveSpeedSmoothing",
|
||||
"MTSCCurvatureCheck", "TurnAggressiveness"
|
||||
};
|
||||
|
||||
std::set<QString> customDrivingPersonalityKeys = {
|
||||
"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile",
|
||||
"TrafficPersonalityProfile"
|
||||
};
|
||||
|
||||
std::set<QString> experimentalModeActivationKeys = {
|
||||
"ExperimentalModeViaDistance", "ExperimentalModeViaLKAS",
|
||||
"ExperimentalModeViaTap"
|
||||
"ExperimentalModeViaDistance", "ExperimentalModeViaLKAS", "ExperimentalModeViaTap"
|
||||
};
|
||||
|
||||
std::set<QString> longitudinalTuneKeys = {
|
||||
"AccelerationProfile", "DecelerationProfile",
|
||||
"HumanAcceleration", "HumanFollowing", "IncreasedStoppedDistance"
|
||||
"AccelerationProfile", "DecelerationProfile", "HumanAcceleration",
|
||||
"HumanFollowing", "IncreasedStoppedDistance", "LeadDetectionThreshold",
|
||||
"MaxDesiredAcceleration"
|
||||
};
|
||||
|
||||
std::set<QString> qolKeys = {
|
||||
"CustomCruise", "CustomCruiseLong", "MapGears",
|
||||
"OnroadDistanceButton", "ReverseCruise"
|
||||
"CustomCruise", "CustomCruiseLong", "ForceStandstill",
|
||||
"ForceStops", "MapGears", "ReverseCruise",
|
||||
"SetSpeedOffset"
|
||||
};
|
||||
|
||||
std::set<QString> relaxedPersonalityKeys = {
|
||||
"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration",
|
||||
"RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease",
|
||||
"ResetRelaxedPersonality"
|
||||
};
|
||||
|
||||
std::set<QString> speedLimitControllerKeys = {
|
||||
"SLCConfirmation", "SLCOffsets", "SLCFallback", "SLCOverride",
|
||||
"SLCPriority", "SLCQOL", "SLCVisuals"
|
||||
"SLCConfirmation", "SLCOffsets", "SLCFallback",
|
||||
"SLCOverride", "SLCPriority", "SLCQOL"
|
||||
};
|
||||
|
||||
std::set<QString> speedLimitControllerOffsetsKeys = {
|
||||
|
@ -62,17 +80,26 @@ private:
|
|||
"SLCLookaheadLower"
|
||||
};
|
||||
|
||||
std::set<QString> speedLimitControllerVisualsKeys = {
|
||||
"ShowSLCOffset", "UseVienna"
|
||||
std::set<QString> standardPersonalityKeys = {
|
||||
"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration",
|
||||
"StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease",
|
||||
"ResetStandardPersonality"
|
||||
};
|
||||
|
||||
std::set<QString> 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<QString, AbstractControl*> toggles;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,527 @@
|
|||
#include "selfdrive/frogpilot/ui/qt/offroad/model_settings.h"
|
||||
|
||||
FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> 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<AbstractControl*>(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<AbstractControl*>(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<QString, QString> 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<AbstractControl*>(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<QString, QString> 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<AbstractControl*>(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<AbstractControl*>(downloadAllModelsBtn);
|
||||
} else if (param == "SelectModel") {
|
||||
selectModelBtn = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(selectModelBtn, &ButtonControl::clicked, [this]() {
|
||||
QSet<QString> modelFilesBaseNames = QSet<QString>::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<AbstractControl*>(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<FrogPilotParamManageControl*>(modelToggle)) {
|
||||
QObject::connect(frogPilotManageToggle, &FrogPilotParamManageControl::manageButtonClicked, this, &FrogPilotModelPanel::openParentToggle);
|
||||
}
|
||||
|
||||
QObject::connect(modelToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(static_cast<ToggleControl*>(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<cereal::Event>().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<FrogPilotButtonsControl *>(sender())->setDescription(desc);
|
||||
}
|
||||
|
||||
void FrogPilotModelPanel::updateModelLabels() {
|
||||
QVector<QPair<QString, int>> 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<QString, int> &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<QString> &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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#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<QString> &keys);
|
||||
void startDownloadAllModels();
|
||||
void updateCalibrationDescription();
|
||||
void updateModelLabels();
|
||||
void updateState(const UIState &s);
|
||||
|
||||
std::set<QString> 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<LabelControl*> 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<QString, AbstractControl*> toggles;
|
||||
};
|
|
@ -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<int, QString> 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();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ signals:
|
|||
|
||||
private:
|
||||
void hideToggles();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void showToggles(const std::set<QString> &keys);
|
||||
void updateCarToggles();
|
||||
|
||||
|
@ -36,5 +37,7 @@ private:
|
|||
bool hasBSM;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
|
||||
int customizationLevel;
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
};
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> 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<QString(QString)> 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();
|
||||
}
|
||||
|
|
|
@ -19,11 +19,10 @@ signals:
|
|||
private:
|
||||
void hideToggles();
|
||||
void showToggles(const std::set<QString> &keys);
|
||||
void updateCarToggles();
|
||||
void updateState(const UIState &s);
|
||||
|
||||
std::set<QString> 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<QString, AbstractControl*> toggles;
|
||||
};
|
||||
|
|
|
@ -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([=] {
|
||||
|
|
|
@ -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<std::tuple<QString, QString, QString, QString>> 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<QString> clusterOffsetToggleNames{"Reset"};
|
||||
vehicleToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map<int, QString>(), 0.001, {}, clusterOffsetToggleNames, false);
|
||||
vehicleToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map<int, QString>(), 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();
|
||||
}
|
||||
|
|