diff --git a/common/params.cc b/common/params.cc index 6d64a1d120ccfa..7d7b7a915cf1dc 100644 --- a/common/params.cc +++ b/common/params.cc @@ -332,7 +332,7 @@ std::unordered_map keys = { {"FrogPilotDrives", PERSISTENT | FROGPILOT_TRACKING}, {"FrogPilotKilometers", PERSISTENT | FROGPILOT_TRACKING}, {"FrogPilotMinutes", PERSISTENT | FROGPILOT_TRACKING}, - {"FrogPilotToggles", PERSISTENT}, + {"FrogPilotToggles", CLEAR_ON_MANAGER_START}, {"FrogPilotTogglesUpdated", PERSISTENT}, {"FrogsGoMoosTweak", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"FullMap", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, @@ -488,7 +488,6 @@ std::unordered_map keys = { {"SLCConfirmationHigher", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmationLower", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmed", PERSISTENT}, - {"SLCConfirmedPressed", PERSISTENT}, {"SLCLookaheadHigher", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCLookaheadLower", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCFallback", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, diff --git a/panda/board/safety/safety_toyota.h b/panda/board/safety/safety_toyota.h index 208d0e08980efb..36b236ceabcfdd 100644 --- a/panda/board/safety/safety_toyota.h +++ b/panda/board/safety/safety_toyota.h @@ -49,10 +49,18 @@ const int TOYOTA_GAS_INTERCEPTOR_THRSLD = 805; #define TOYOTA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks // Stock longitudinal -#define TOYOTA_COMMON_TX_MSGS \ - {0x2E4, 0, 5}, {0x191, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, /* LKAS + LTA + ACC & PCM cancel cmds */ \ +#define TOYOTA_BASE_TX_MSGS \ + {0x191, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, /* LKAS + LTA + ACC & PCM cancel cmds */ \ {0x750, 0, 8}, /* white list 0x750 for Enhanced Diagnostic Request */ \ +#define TOYOTA_COMMON_TX_MSGS \ + TOYOTA_BASE_TX_MSGS \ + {0x2E4, 0, 5}, \ + +#define TOYOTA_COMMON_SECOC_TX_MSGS \ + TOYOTA_BASE_TX_MSGS \ + {0x2E4, 0, 8}, {0x131, 0, 8}, \ + #define TOYOTA_COMMON_LONG_TX_MSGS \ TOYOTA_COMMON_TX_MSGS \ {0x283, 0, 7}, {0x2E6, 0, 8}, {0x2E7, 0, 8}, {0x33E, 0, 7}, {0x344, 0, 8}, {0x365, 0, 7}, {0x366, 0, 7}, {0x4CB, 0, 8}, /* DSU bus 0 */ \ @@ -66,7 +74,7 @@ const CanMsg TOYOTA_TX_MSGS[] = { }; const CanMsg TOYOTA_SECOC_TX_MSGS[] = { - TOYOTA_COMMON_TX_MSGS + TOYOTA_COMMON_SECOC_TX_MSGS }; const CanMsg TOYOTA_LONG_TX_MSGS[] = { @@ -81,9 +89,11 @@ const CanMsg TOYOTA_INTERCEPTOR_TX_MSGS[] = { #define TOYOTA_COMMON_RX_CHECKS(lta) \ {.msg = {{ 0xaa, 0, 8, .check_checksum = false, .frequency = 83U}, { 0 }, { 0 }}}, \ {.msg = {{0x260, 0, 8, .check_checksum = true, .quality_flag = (lta), .frequency = 50U}, { 0 }, { 0 }}}, \ - {.msg = {{0x1D2, 0, 8, .check_checksum = true, .frequency = 33U}, { 0 }, { 0 }}}, \ - {.msg = {{0x224, 0, 8, .check_checksum = false, .frequency = 40U}, \ - {0x226, 0, 8, .check_checksum = false, .frequency = 40U}, { 0 }}}, \ + {.msg = {{0x1D2, 0, 8, .check_checksum = true, .frequency = 33U}, \ + {0x176, 0, 8, .check_checksum = true, .frequency = 32U}, { 0 }}}, \ + {.msg = {{0x101, 0, 8, .check_checksum = false, .frequency = 50U}, \ + {0x224, 0, 8, .check_checksum = false, .frequency = 40U}, \ + {0x226, 0, 8, .check_checksum = false, .frequency = 40U}}}, \ RxCheck toyota_lka_rx_checks[] = { TOYOTA_COMMON_RX_CHECKS(false) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 8ab60d786ecbed..4871ff5a426171 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -295,7 +295,7 @@ def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_ eps_firmware = str(next((fw.fwVersion for fw in car_fw if fw.ecu == "eps"), "")) model = get_nn_model_path(candidate, eps_firmware) if model is not None: - params.put_nonblocking("NNFFModelName", candidate.replace("_", " ")) + params.put("NNFFModelName", candidate.replace("_", " ")) # Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload if not ret.notCar: diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 4c56efaed430b9..cb6519e7e92ef0 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -68,6 +68,7 @@ def __init__(self, dbc_name, CP, VM): def update(self, CC, CS, now_nanos, frogpilot_toggles): actuators = CC.actuators + stopping = actuators.longControlState == LongCtrlState.stopping hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel lat_active = CC.latActive and abs(CS.out.steeringTorque) < MAX_USER_TORQUE @@ -142,44 +143,6 @@ def update(self, CC, CS, now_nanos, frogpilot_toggles): else: 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 - if self.CP.flags & ToyotaFlags.RAISED_ACCEL_LIMIT and CC.longActive and not CS.out.cruiseState.standstill: - # calculate amount of acceleration PCM should apply to reach target, given pitch - 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 - pcm_accel_compensation = 0.0 - if actuators.longControlState != LongCtrlState.stopping: - pcm_accel_compensation = 2.0 * (CS.pcm_accel_net - net_acceleration_request) - - # prevent compensation windup - pcm_accel_compensation = clip(pcm_accel_compensation, actuators.accel - self.params.ACCEL_MAX, - actuators.accel - self.params.ACCEL_MIN) - - self.pcm_accel_compensation = rate_limit(pcm_accel_compensation, self.pcm_accel_compensation, -0.01, 0.01) - pcm_accel_cmd = actuators.accel - self.pcm_accel_compensation - - # Along with rate limiting positive jerk below, this greatly improves gas response time - # Consider the net acceleration request that the PCM should be applying (pitch included) - if net_acceleration_request < 0.1: - self.permit_braking = True - elif net_acceleration_request > 0.2: - self.permit_braking = False - else: - self.pcm_accel_compensation = 0.0 - pcm_accel_cmd = actuators.accel - 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_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_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): self.standstill_req = True @@ -192,31 +155,70 @@ def update(self, CC, CS, now_nanos, frogpilot_toggles): # handle UI messages fcw_alert = hud_control.visualAlert == VisualAlert.fcw steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) + lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged + + if self.CP.openpilotLongitudinalControl: + if self.frame % 3 == 0: + # Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup + if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl: + desired_distance = 4 - hud_control.leadDistanceBars + if CS.out.cruiseState.enabled and CS.pcm_follow_distance != desired_distance: + self.distance_button = not self.distance_button + else: + self.distance_button = 0 + + # For cars where we allow a higher max acceleration of 2.0 m/s^2, compensate for PCM request overshoot and imprecise braking + if self.CP.flags & ToyotaFlags.RAISED_ACCEL_LIMIT and CC.longActive and not CS.out.cruiseState.standstill: + # calculate amount of acceleration PCM should apply to reach target, given pitch + 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 + pcm_accel_compensation = 0.0 + if not stopping: + pcm_accel_compensation = 2.0 * (CS.pcm_accel_net - net_acceleration_request) + + # prevent compensation windup + pcm_accel_compensation = clip(pcm_accel_compensation, actuators.accel - self.params.ACCEL_MAX, + actuators.accel - self.params.ACCEL_MIN) + + self.pcm_accel_compensation = rate_limit(pcm_accel_compensation, self.pcm_accel_compensation, -0.01, 0.01) + pcm_accel_cmd = actuators.accel - self.pcm_accel_compensation + + # Along with rate limiting positive jerk below, this greatly improves gas response time + # Consider the net acceleration request that the PCM should be applying (pitch included) + if net_acceleration_request < 0.1 or stopping: + self.permit_braking = True + elif net_acceleration_request > 0.2: + self.permit_braking = False + else: + self.pcm_accel_compensation = 0.0 + pcm_accel_cmd = actuators.accel + self.permit_braking = True - # we can spam can to cancel the system even if we are using lat only control - if (self.frame % 3 == 0 and self.CP.openpilotLongitudinalControl) or pcm_cancel_cmd: - lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged - - # Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup - if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl: - desired_distance = 4 - hud_control.leadDistanceBars - if CS.out.cruiseState.enabled and CS.pcm_follow_distance != desired_distance: - self.distance_button = not self.distance_button + if frogpilot_toggles.sport_plus: + 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: - self.distance_button = 0 + pcm_accel_cmd = clip(pcm_accel_cmd, self.params.ACCEL_MIN, min(frogpilot_toggles.max_desired_acceleration, self.params.ACCEL_MAX)) - # Lexus IS uses a different cancellation message - if pcm_cancel_cmd and self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: - can_sends.append(toyotacan.create_acc_cancel_command(self.packer)) - elif self.CP.openpilotLongitudinalControl: # internal PCM gas command can get stuck unwinding from negative accel so we apply a generous rate limit pcm_accel_cmd = min(pcm_accel_cmd, self.accel + ACCEL_WINDUP_LIMIT) if CC.longActive else 0.0 can_sends.append(toyotacan.create_accel_command(self.packer, pcm_accel_cmd, pcm_cancel_cmd, self.permit_braking, self.standstill_req, lead, CS.acc_type, fcw_alert, self.distance_button, self.reverse_cruise_active)) self.accel = pcm_accel_cmd - else: - can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, True, False, lead, CS.acc_type, False, self.distance_button, self.reverse_cruise_active)) + + else: + # we can spam can to cancel the system even if we are using lat only control + if pcm_cancel_cmd: + if self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: + can_sends.append(toyotacan.create_acc_cancel_command(self.packer)) + else: + can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, True, False, lead, CS.acc_type, False, self.distance_button, self.reverse_cruise_active)) if self.frame % 2 == 0 and self.CP.enableGasInterceptor and self.CP.openpilotLongitudinalControl: # send exactly zero if gas cmd is zero. Interceptor will send the max between read value and gas cmd. diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 55a8dedbb4f42a..50bfd5620c0143 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -9,7 +9,7 @@ from opendbc.can.parser import CANParser from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ - TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR + TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR, SECOC_CAR SteerControlType = car.CarParams.SteerControlType @@ -80,7 +80,7 @@ def update(self, cp, cp_cam, CC, frogpilot_toggles): # Describes the acceleration request from the PCM if on flat ground, may be higher or lower if pitched # CLUTCH->ACCEL_NET is only accurate for gas, PCM_CRUISE->ACCEL_NET is only accurate for brake # These signals only have meaning when ACC is active - if self.CP.flags & ToyotaFlags.RAISED_ACCEL_LIMIT: + if "CLUTCH" in cp.vl: self.pcm_accel_net = max(cp.vl["CLUTCH"]["ACCEL_NET"], 0.0) # Sometimes ACC_BRAKING can be 1 while showing we're applying gas already @@ -279,7 +279,7 @@ def get_can_parser(CP): ("STEER_TORQUE_SENSOR", 50), ] - if CP.flags & ToyotaFlags.RAISED_ACCEL_LIMIT: + if CP.carFingerprint in (TSS2_CAR - SECOC_CAR - {CAR.LEXUS_NX_TSS2, CAR.TOYOTA_ALPHARD_TSS2, CAR.LEXUS_IS_TSS2}): messages.append(("CLUTCH", 15)) if CP.carFingerprint != CAR.TOYOTA_MIRAI: diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index fd3887efab3f49..5d633fc952aa00 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -33,10 +33,17 @@ def create_lta_steer_command(packer, steer_control_type, steer_angle, steer_req, return packer.make_can_msg("STEERING_LTA", 0, values) +def create_lta_steer_command_2(packer, frame): + values = { + "COUNTER": frame + 128, + } + return packer.make_can_msg("STEERING_LTA_2", 0, values) + + def create_accel_command(packer, accel, pcm_cancel, permit_braking, standstill_req, lead, acc_type, fcw_alert, distance, reverse_cruise_active): # TODO: find the exact canceling bit that does not create a chime values = { - "ACCEL_CMD": accel, # compensated accel command + "ACCEL_CMD": accel, "ACC_TYPE": acc_type, "DISTANCE": distance, "MINI_CAR": lead, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index e46a7bb828b37d..f182040008f498 100644 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -15,7 +15,7 @@ from openpilot.common.git import get_short_branch from openpilot.common.numpy_fast import clip from openpilot.common.params import Params -from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL, DT_MDL from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event @@ -579,7 +579,7 @@ def state_control(self, CS): torque_params = self.sm['liveTorqueParameters'] friction = self.frogpilot_toggles.steer_friction if self.frogpilot_toggles.use_custom_steer_friction else torque_params.frictionCoefficientFiltered lat_accel_factor = self.frogpilot_toggles.steer_lat_accel_factor if self.frogpilot_toggles.use_custom_lat_accel_factor else torque_params.latAccelFactorFiltered - if self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.frogpilot_toggles.force_auto_tune) and not self.frogpilot_toggles.force_auto_tune_off: + if self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.frogpilot_toggles.force_auto_tune): self.LaC.update_live_torque_params(lat_accel_factor, torque_params.latAccelOffsetFiltered, friction) @@ -744,7 +744,7 @@ def update_frogpilot_variables(self, CS): self.experimental_mode = not self.experimental_mode self.params.put_bool_nonblocking("ExperimentalMode", self.experimental_mode) - if self.sm.frame % 10 == 0 or self.resume_pressed: + if self.sm.frame * DT_CTRL % DT_MDL == 0 or self.resume_pressed: self.resume_previously_pressed = self.resume_pressed FPCC = custom.FrogPilotCarControl.new_message() diff --git a/selfdrive/frogpilot/assets/model_manager.py b/selfdrive/frogpilot/assets/model_manager.py index d7fa1162422bc5..999d35f167bd10 100644 --- a/selfdrive/frogpilot/assets/model_manager.py +++ b/selfdrive/frogpilot/assets/model_manager.py @@ -127,27 +127,29 @@ def update_model_params(self, model_info, repo_url): for model in model_info: available_models.append(model['id']) - params.put_nonblocking("AvailableModels", ','.join(available_models)) - params.put_nonblocking("AvailableModelsNames", ','.join([model['name'] for model in model_info])) - params.put_nonblocking("ClassicModels", ','.join([model['id'] for model in model_info if model.get("classic_model", False)])) - params.put_nonblocking("ExperimentalModels", ','.join([model['id'] for model in model_info if model.get("experimental", False)])) - params.put_nonblocking("NavigationModels", ','.join([model['id'] for model in model_info if "πŸ—ΊοΈ" in model['name']])) - params.put_nonblocking("RadarlessModels", ','.join([model['id'] for model in model_info if "πŸ“‘" not in model['name']])) + params.put("AvailableModels", ','.join(available_models)) + params.put("AvailableModelsNames", ','.join([model['name'] for model in model_info])) + params.put("ClassicModels", ','.join([model['id'] for model in model_info if model.get("classic_model", False)])) + params.put("ExperimentalModels", ','.join([model['id'] for model in model_info if model.get("experimental", False)])) + params.put("NavigationModels", ','.join([model['id'] for model in model_info if "πŸ—ΊοΈ" in model['name']])) + params.put("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, repo_url) - params.put_bool_nonblocking("ModelsDownloaded", models_downloaded) + params.put_bool("ModelsDownloaded", models_downloaded) def are_all_models_downloaded(self, available_models, repo_url): + model_sizes = self.fetch_all_model_sizes(repo_url) + if not model_sizes: + return + available_models = set(available_models) - {DEFAULT_MODEL, DEFAULT_CLASSIC_MODEL} - automatically_update_models = params.get_bool("AutomaticallyUpdateModels") all_models_downloaded = True + automatically_update_models = params.get_bool("AutomaticallyUpdateModels") - 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") expected_size = model_sizes.get(model) @@ -179,7 +181,7 @@ def validate_models(self): current_model_name = params.get("ModelName", encoding='utf-8') if "(Default)" in current_model_name and current_model_name != DEFAULT_CLASSIC_MODEL_NAME: - params.put_nonblocking("ModelName", current_model_name.replace(" (Default)", "")) + params.put("ModelName", current_model_name.replace(" (Default)", "")) available_models = params.get("AvailableModels", encoding='utf-8') if not available_models: @@ -194,8 +196,8 @@ def validate_models(self): model_name = model_file.replace(".thneed", "") if model_name not in available_models.split(','): if model_name == current_model: - params.put_nonblocking("Model", DEFAULT_CLASSIC_MODEL) - params.put_nonblocking("ModelName", DEFAULT_CLASSIC_MODEL_NAME) + params.put("Model", DEFAULT_CLASSIC_MODEL) + params.put("ModelName", DEFAULT_CLASSIC_MODEL_NAME) delete_file(os.path.join(MODELS_PATH, model_file)) print(f"Deleted model file: {model_file} - Reason: Model is not in the list of available models") @@ -253,4 +255,4 @@ def download_all_models(self): params_memory.put(self.download_progress_param, "All models downloaded!") params_memory.remove("DownloadAllModels") - params.put_bool_nonblocking("ModelsDownloaded", True) + params.put_bool("ModelsDownloaded", True) diff --git a/selfdrive/frogpilot/assets/theme_manager.py b/selfdrive/frogpilot/assets/theme_manager.py index 2d25eacfa086ca..e3ad1ec752e1b3 100644 --- a/selfdrive/frogpilot/assets/theme_manager.py +++ b/selfdrive/frogpilot/assets/theme_manager.py @@ -23,7 +23,7 @@ def update_theme_asset(asset_type, theme, holiday_theme): save_location = os.path.join(ACTIVE_THEME_PATH, asset_type) - if holiday_theme: + if holiday_theme is not None: asset_location = os.path.join(HOLIDAY_THEME_PATH, holiday_theme, asset_type) elif asset_type == "distance_icons": asset_location = os.path.join(THEME_SAVE_PATH, "distance_icons", theme) @@ -51,11 +51,14 @@ def update_theme_asset(asset_type, theme, holiday_theme): os.makedirs(os.path.dirname(save_location), exist_ok=True) + if os.path.islink(save_location): + os.unlink(save_location) + if os.path.exists(save_location): - if os.path.islink(save_location): - os.unlink(save_location) - elif os.path.isdir(save_location): + if os.path.isdir(save_location): shutil.rmtree(save_location) + else: + os.remove(save_location) os.symlink(asset_location, save_location, target_is_directory=True) print(f"Linked {save_location} to {asset_location}") @@ -63,7 +66,7 @@ def update_theme_asset(asset_type, theme, holiday_theme): def update_wheel_image(image, holiday_theme=None, random_event=True): wheel_save_location = os.path.join(ACTIVE_THEME_PATH, "steering_wheel") - if holiday_theme: + if holiday_theme is not None: wheel_location = os.path.join(HOLIDAY_THEME_PATH, holiday_theme, "steering_wheel") elif random_event: wheel_location = os.path.join(RANDOM_EVENTS_PATH, "icons") @@ -426,6 +429,8 @@ def update_themes(self, frogpilot_toggles, boot_run=False): self.validate_themes(frogpilot_toggles) assets = self.fetch_assets(repo_url) + if not assets["themes"] and not assets["distance_icons"] and not assets["wheels"]: + return downloadable_colors = [] downloadable_icons = [] diff --git a/selfdrive/frogpilot/controls/frogpilot_planner.py b/selfdrive/frogpilot/controls/frogpilot_planner.py index dde238a451b926..4c75f096f17e06 100644 --- a/selfdrive/frogpilot/controls/frogpilot_planner.py +++ b/selfdrive/frogpilot/controls/frogpilot_planner.py @@ -15,7 +15,9 @@ from openpilot.selfdrive.frogpilot.frogpilot_variables import CRUISING_SPEED, MODEL_LENGTH, NON_DRIVING_GEARS, PLANNER_TIME, THRESHOLD class FrogPilotPlanner: - def __init__(self): + def __init__(self, error_log): + self.error_log = error_log + self.cem = ConditionalExperimentalMode(self) self.frogpilot_acceleration = FrogPilotAcceleration(self) self.frogpilot_events = FrogPilotEvents(self) diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_events.py b/selfdrive/frogpilot/controls/lib/frogpilot_events.py index 5838aed82dc4ad..ce0d33531e03d2 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_events.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_events.py @@ -1,8 +1,6 @@ import os import random -import openpilot.system.sentry as sentry - from openpilot.common.conversions import Conversions as CV from openpilot.common.realtime import DT_MDL from openpilot.selfdrive.controls.controlsd import Desire @@ -11,11 +9,14 @@ from openpilot.selfdrive.frogpilot.assets.theme_manager import update_wheel_image from openpilot.selfdrive.frogpilot.frogpilot_variables import CRUISING_SPEED, params, params_memory +RANDOM_EVENTS_CHANCE = 0.01 * DT_MDL + class FrogPilotEvents: def __init__(self, FrogPilotPlanner): - self.events = Events() self.frogpilot_planner = FrogPilotPlanner + self.events = Events() + self.accel30_played = False self.accel35_played = False self.accel40_played = False @@ -76,7 +77,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState 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 not self.openpilot_crashed_played and os.path.isfile(self.frogpilot_planner.error_log): if frogpilot_toggles.random_events: self.events.add(EventName.openpilotCrashedRandomEvent) else: @@ -135,7 +136,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState if not self.this_is_fine_played: event_choices.append("thisIsFineSteerSaturated") - if self.frame % 100 == 0 and event_choices: + if random.random() < RANDOM_EVENTS_CHANCE and event_choices: event_choice = random.choice(event_choices) if event_choice == "firefoxSteerSaturated": self.events.add(EventName.firefoxSteerSaturated) @@ -161,17 +162,17 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState if not self.fcw_played and frogpilotCarControl.fcwEventTriggered: event_choices = ["toBeContinued", "yourFrogTriedToKillMe"] - event_choice = random.choice(event_choices) - if random.random() < 0.1: + if random.random() < RANDOM_EVENTS_CHANCE: + event_choice = random.choice(event_choices) if event_choice == "toBeContinued": self.events.add(EventName.toBeContinued) elif event_choice == "yourFrogTriedToKillMe": self.events.add(EventName.yourFrogTriedToKillMe) - self.fcw_played = True - self.random_event_played = True + self.fcw_played = True + self.random_event_played = True if not self.youveGotMail_played and frogpilotCarControl.alwaysOnLateralActive and not self.always_on_lateral_active_previously: - if random.random() < 0.01 and not carState.standstill: + if random.random() < RANDOM_EVENTS_CHANCE and not carState.standstill: self.events.add(EventName.youveGotMail) self.youveGotMail_played = True self.random_event_played = True @@ -180,7 +181,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState 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 params.get("NNFFModelName", encoding='utf-8') is not None: + if 5 > self.frame > 4 and params.get("NNFFModelName", encoding='utf-8') is not None: self.events.add(EventName.torqueNNLoad) if frogpilotCarState.trafficModeActive != self.previous_traffic_mode: @@ -195,4 +196,4 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState elif modelData.meta.turnDirection == Desire.turnRight: self.events.add(EventName.turningRight) - self.frame = round(self.frame + DT_MDL, 2) + self.frame += DT_MDL diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_following.py b/selfdrive/frogpilot/controls/lib/frogpilot_following.py index a29c4577700dbf..600b17947a5dbd 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_following.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_following.py @@ -76,17 +76,17 @@ 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(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 + standstill_offset = max((v_lead - v_ego) * (STOP_DISTANCE - v_ego), 1) + acceleration_offset = clip((v_lead - v_ego) * standstill_offset - COMFORT_BRAKE, 1, distance_factor) + self.acceleration_jerk /= standstill_offset + self.speed_jerk /= standstill_offset self.t_follow /= acceleration_offset # 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 > CRUISING_SPEED: distance_factor = max(lead_distance - (v_lead * self.t_follow), 1) - 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) + far_lead_offset = max(lead_distance - (v_ego * self.t_follow) - STOP_DISTANCE + (v_lead - CITY_SPEED_LIMIT), 1) + braking_offset = clip((v_ego - v_lead) * far_lead_offset - COMFORT_BRAKE, 1, distance_factor) if frogpilot_toggles.human_following: self.t_follow /= braking_offset self.slower_lead = braking_offset - far_lead_offset > 1 diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py index fc4a918abf28b0..2feff92b263215 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py @@ -52,6 +52,8 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState elif self.override_force_stop_timer > 0: self.override_force_stop_timer -= DT_MDL + v_cruise_cluster = max(controlsState.vCruiseCluster * CV.KPH_TO_MS, v_cruise) + v_ego_cluster = max(carState.vEgoCluster, v_ego) v_ego_diff = v_ego_cluster - v_ego @@ -77,21 +79,13 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState unconfirmed_slc_target = self.slc.desired_speed_limit if (frogpilot_toggles.speed_limit_changed_alert or frogpilot_toggles.speed_limit_confirmation) 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 + self.speed_limit_changed |= unconfirmed_slc_target != self.previous_speed_limit and abs(self.slc_target - 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 - accepted_via_ui = params_memory.get_bool("SLCConfirmedPressed") and params_memory.get_bool("SLCConfirmed") - denied_via_ui = params_memory.get_bool("SLCConfirmedPressed") and not params_memory.get_bool("SLCConfirmed") - - speed_limit_accepted = frogpilotCarControl.resumePressed and controlsState.enabled or accepted_via_ui - speed_limit_denied = any(be.type == ButtonType.decelCruise for be in carState.buttonEvents) and controlsState.enabled or denied_via_ui or self.speed_limit_timer >= 30 - - if speed_limit_accepted or speed_limit_denied: - self.previous_speed_limit = unconfirmed_slc_target - params_memory.put_bool("SLCConfirmed", False) - params_memory.put_bool("SLCConfirmedPressed", False) + speed_limit_accepted = frogpilotCarControl.resumePressed and controlsState.enabled or params_memory.get_bool("SLCConfirmed") + speed_limit_denied = any(be.type == ButtonType.decelCruise for be in carState.buttonEvents) and controlsState.enabled or self.speed_limit_timer >= 30 if speed_limit_decreased: speed_limit_confirmed = not frogpilot_toggles.speed_limit_confirmation_lower or speed_limit_accepted @@ -100,15 +94,18 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState else: speed_limit_confirmed = False + if speed_limit_confirmed: + self.slc_target = unconfirmed_slc_target + + if speed_limit_denied or self.slc_target == unconfirmed_slc_target: + self.speed_limit_changed = False + if self.speed_limit_changed: self.speed_limit_timer += DT_MDL else: self.speed_limit_timer = 0 - if speed_limit_confirmed: - self.slc_target = unconfirmed_slc_target - elif self.slc_target == unconfirmed_slc_target: - self.speed_limit_changed = False + self.previous_speed_limit = unconfirmed_slc_target else: self.slc_target = unconfirmed_slc_target @@ -122,7 +119,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState self.overridden_speed = v_ego_cluster self.overridden_speed = clip(self.overridden_speed, self.slc_target, v_cruise) elif frogpilot_toggles.speed_limit_controller_override_set_speed: - self.overridden_speed = v_cruise + self.overridden_speed = v_cruise_cluster else: self.overridden_speed = 0 else: diff --git a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py index 9315ad9f3f776b..33298bcef2713f 100644 --- a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py +++ b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py @@ -85,8 +85,12 @@ def get_speed_limit(self, dashboard_speed_limit, max_speed_limit, navigation_spe self.source = min(filtered_limits, key=filtered_limits.get) return filtered_limits[self.source] - for priority in [frogpilot_toggles.speed_limit_priority1, frogpilot_toggles.speed_limit_priority2, frogpilot_toggles.speed_limit_priority3]: - if priority in filtered_limits: + for priority in [ + frogpilot_toggles.speed_limit_priority1, + frogpilot_toggles.speed_limit_priority2, + frogpilot_toggles.speed_limit_priority3 + ]: + if priority is not None and priority in filtered_limits: self.source = priority return filtered_limits[priority] diff --git a/selfdrive/frogpilot/frogpilot_functions.py b/selfdrive/frogpilot/frogpilot_functions.py index a02bf219aa2cf1..3fa7a24abe98ae 100644 --- a/selfdrive/frogpilot/frogpilot_functions.py +++ b/selfdrive/frogpilot/frogpilot_functions.py @@ -13,10 +13,10 @@ from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.frogpilot.frogpilot_utilities import copy_if_exists, run_cmd -from openpilot.selfdrive.frogpilot.frogpilot_variables import ACTIVE_THEME_PATH, MODELS_PATH, THEME_SAVE_PATH, FrogPilotVariables +from openpilot.selfdrive.frogpilot.frogpilot_variables import ACTIVE_THEME_PATH, MODELS_PATH, THEME_SAVE_PATH, FrogPilotVariables, params -def backup_directory(backup, destination, success_message, fail_message, minimum_backup_size=0, params=None, compressed=False): +def backup_directory(backup, destination, success_message, fail_message, minimum_backup_size=0, compressed=False): if not compressed: if os.path.exists(destination): print("Backup already exists. Aborting") @@ -53,29 +53,31 @@ def backup_directory(backup, destination, success_message, fail_message, minimum params.put_int("MinimumBackupSize", compressed_backup_size) -def cleanup_backups(directory, limit, minimum_backup_size=0, compressed=False): +def cleanup_backups(directory, limit, 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"): - 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 backup.endswith("_in_progress") or backup.endswith("_in_progress.tar.gz"): + if os.path.isdir(backup): + shutil.rmtree(backup) + elif os.path.isfile(backup): + os.remove(backup) + backups.remove(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 oldest_backup in backups[limit:]: + if os.path.isdir(oldest_backup): + shutil.rmtree(oldest_backup) + elif os.path.isfile(oldest_backup): + os.remove(oldest_backup) - for old_backup in backups[limit - 1:]: - 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): +def backup_frogpilot(build_metadata): backup_path = os.path.join("/data", "backups") maximum_backups = 5 minimum_backup_size = params.get_int("MinimumBackupSize") - cleanup_backups(backup_path, maximum_backups, minimum_backup_size, compressed=True) + cleanup_backups(backup_path, maximum_backups) _, _, free = shutil.disk_usage(backup_path) required_free_space = minimum_backup_size * maximum_backups @@ -84,10 +86,10 @@ def backup_frogpilot(build_metadata, params): branch = build_metadata.channel commit = build_metadata.openpilot.git_commit_date[12:-16] 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) + backup_directory(BASEDIR, backup_dir, f"Successfully backed up FrogPilot to {backup_dir}.", f"Failed to backup FrogPilot to {backup_dir}.", minimum_backup_size, True) -def backup_toggles(params, params_storage): +def backup_toggles(params_storage): for key in params.all_keys(): if params.get_key_type(key) & ParamKeyType.FROGPILOT_STORAGE: value = params.get(key) @@ -103,7 +105,7 @@ def backup_toggles(params, params_storage): 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 convert_params(params, params_storage): +def convert_params(params_storage): print("Starting to convert params") required_type = str @@ -159,7 +161,7 @@ def decrease_param(key): print("Param conversion completed") -def frogpilot_boot_functions(build_metadata, params, params_storage): +def frogpilot_boot_functions(build_metadata, params_storage): old_screenrecordings = os.path.join("/data", "media", "0", "videos") new_screenrecordings = os.path.join("/data", "media", "screen_recordings") @@ -171,15 +173,14 @@ def frogpilot_boot_functions(build_metadata, params, params_storage): print("Waiting for system time to become valid...") time.sleep(1) - backup_frogpilot(build_metadata, params) - backup_toggles(params, params_storage) + backup_frogpilot(build_metadata) + backup_toggles(params_storage) -def setup_frogpilot(build_metadata, params): +def setup_frogpilot(build_metadata): FrogPilotVariables().update(started=False) - remount_persist = ["sudo", "mount", "-o", "remount,rw", "/persist"] - run_cmd(remount_persist, "Successfully remounted /persist as read-write.", "Failed to remount /persist.") + run_cmd(["sudo", "mount", "-o", "remount,rw", "/persist"], "Successfully remounted /persist as read-write.", "Failed to remount /persist.") os.makedirs("/persist/params", exist_ok=True) os.makedirs(MODELS_PATH, exist_ok=True) @@ -227,8 +228,7 @@ def setup_frogpilot(build_metadata, params): if not os.path.exists(frog_steering_wheel_destination): copy_if_exists(frog_steering_wheel_source, frog_steering_wheel_destination, single_file_name="frog.png") - remount_root = ["sudo", "mount", "-o", "remount,rw", "/"] - run_cmd(remount_root, "File system remounted as read-write.", "Failed to remount file system.") + run_cmd(["sudo", "mount", "-o", "remount,rw", "/"], "File system remounted as read-write.", "Failed to remount file system.") boot_logo_location = "/usr/comma/bg.jpg" boot_logo_save_location = os.path.join(BASEDIR, "selfdrive", "frogpilot", "assets", "other_images", "original_bg.jpg") @@ -246,7 +246,6 @@ 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") - copy_cmd = ["sudo", "cp", boot_logo_restore_location, boot_logo_location] - run_cmd(copy_cmd, "Successfully restored the original boot logo.", "Failed to restore the original boot logo.") + run_cmd(["sudo", "cp", boot_logo_restore_location, boot_logo_location], "Successfully restored the original boot logo.", "Failed to restore the original boot logo.") HARDWARE.uninstall() diff --git a/selfdrive/frogpilot/frogpilot_process.py b/selfdrive/frogpilot/frogpilot_process.py index 570183b14f3e22..79728f407ae869 100644 --- a/selfdrive/frogpilot/frogpilot_process.py +++ b/selfdrive/frogpilot/frogpilot_process.py @@ -18,6 +18,7 @@ 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, params, params_memory +from openpilot.selfdrive.frogpilot.navigation.mapd import update_mapd locks = { "backup_toggles": threading.Lock(), @@ -26,13 +27,13 @@ "download_theme": threading.Lock(), "update_active_theme": threading.Lock(), "update_checks": threading.Lock(), + "update_mapd": 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]: @@ -40,27 +41,22 @@ def run_thread_with_lock(name, target, args=()): thread.start() running_threads[name] = thread +def automatic_update_check(): + os.system("pkill -SIGUSR1 -f system.updated.updated") + while params.get("UpdaterState", encoding="utf8") != "idle": + time.sleep(60) + + if not params.get_bool("UpdaterFetchAvailable"): + return -def automatic_update_check(frogs_go_moo, started): - update_available = params.get_bool("UpdaterFetchAvailable") - update_ready = params.get_bool("UpdateAvailable") - update_state_idle = params.get("UpdaterState", encoding='utf8') == "idle" + os.system("pkill -SIGHUP -f system.updated.updated") + while not params.get_bool("UpdateAvailable"): + time.sleep(60) - if update_ready and not started: - if not frogs_go_moo: - os.system("pkill -SIGUSR1 -f system.updated.updated") - time.sleep(30) - if params.get_bool("UpdaterFetchAvailable"): - os.system("pkill -SIGHUP -f system.updated.updated") - time.sleep(300) - HARDWARE.reboot() - elif update_available: - os.system("pkill -SIGUSR1 -f system.updated.updated") - time.sleep(30) - os.system("pkill -SIGHUP -f system.updated.updated") - elif update_state_idle: - os.system("pkill -SIGUSR1 -f system.updated.updated") + while params.get_bool("IsOnroad"): + time.sleep(60) + HARDWARE.reboot() def check_assets(model_manager, theme_manager, frogpilot_toggles): if params_memory.get_bool("DownloadAllModels"): @@ -84,19 +80,19 @@ def check_assets(model_manager, theme_manager, frogpilot_toggles): if asset_to_download is not None: run_thread_with_lock("download_theme", theme_manager.download_theme, (asset_type, asset_to_download, param)) - -def update_checks(automatic_updates, frogs_go_moo, model_manager, now, screen_off, started, theme_manager, time_validated): +def update_checks(model_manager, now, theme_manager, time_validated, frogpilot_toggles): if not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")): return - if automatic_updates and (screen_off or frogs_go_moo): - automatic_update_check(frogs_go_moo, started) + if frogpilot_toggles.automatic_updates: + automatic_update_check() if time_validated: update_maps(now) + run_thread_with_lock("update_mapd", update_mapd()) run_thread_with_lock("update_models", model_manager.update_models) - + run_thread_with_lock("update_themes", theme_manager.update_themes(frogpilot_toggles)) def update_maps(now): maps_selected = params.get("MapsSelected", encoding='utf8') @@ -120,15 +116,18 @@ def update_maps(now): if params.get("OSMDownloadProgress", encoding='utf-8') is None: params_memory.put("OSMDownloadLocations", maps_selected) - params.put_nonblocking("LastMapsUpdate", todays_date) - + params.put("LastMapsUpdate", todays_date) def frogpilot_thread(): config_realtime_process(5, Priority.CTRL_LOW) + error_log = os.path.join(sentry.CRASHES_DIR, 'error.txt') + if os.path.isfile(error_log): + os.remove(error_log) + params_storage = Params("/persist/params") - frogpilot_planner = FrogPilotPlanner() + frogpilot_planner = FrogPilotPlanner(error_log) frogpilot_tracking = FrogPilotTracking() frogpilot_variables = FrogPilotVariables() model_manager = ModelManager() @@ -145,35 +144,34 @@ def frogpilot_thread(): toggles_last_updated = datetime.datetime.now() - error_log = os.path.join(sentry.CRASHES_DIR, 'error.txt') - if os.path.isfile(error_log): - os.remove(error_log) - pm = messaging.PubMaster(['frogpilotPlan']) sm = messaging.SubMaster(['carState', 'controlsState', 'deviceState', 'modelV2', 'radarState', 'frogpilotCarControl', 'frogpilotCarState', 'frogpilotNavigation'], poll='modelV2', ignore_avg_freq=['radarState']) + run_thread_with_lock("update_active_theme", theme_manager.update_active_theme, (frogpilot_toggles,)) + while True: sm.update() now = datetime.datetime.now() - deviceState = sm['deviceState'] - screen_off = deviceState.screenBrightnessPercent == 0 - started = deviceState.started + + started = sm['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)) + run_thread_with_lock("backup_toggles", backup_toggles, (params_storage,)) run_thread_with_lock("update_active_theme", theme_manager.update_active_theme, (frogpilot_toggles,)) toggles_last_updated = now toggles_updated = (now - toggles_last_updated).total_seconds() <= 1 if not started and started_previously: - frogpilot_planner = FrogPilotPlanner() + frogpilot_planner = FrogPilotPlanner(error_log) frogpilot_tracking = FrogPilotTracking() + + run_update_checks = True elif started and not started_previously: radarless_model = frogpilot_toggles.radarless_model @@ -193,21 +191,19 @@ def frogpilot_thread(): started_previously = started - check_assets(model_manager, theme_manager, frogpilot_toggles) + if now.second % 2 == 0: + check_assets(model_manager, theme_manager, frogpilot_toggles) + + run_update_checks |= params_memory.get_bool("ManualUpdateInitiated") + run_update_checks |= now.second == 0 and (now.minute % 60 == 0 or frogpilot_toggles.frogs_go_moo) - if params_memory.get_bool("ManualUpdateInitiated"): - run_thread_with_lock("update_checks", update_checks, (False, frogpilot_toggles.frogs_go_moo, model_manager, now, screen_off, started, theme_manager, time_validated)) - run_thread_with_lock("update_themes", theme_manager.update_themes(frogpilot_toggles)) - elif now.second == 0: - run_update_checks = not screen_off and not started or now.minute % 15 == 0 or frogpilot_toggles.frogs_go_moo - elif run_update_checks: - run_thread_with_lock("update_checks", update_checks, (frogpilot_toggles.automatic_updates, frogpilot_toggles.frogs_go_moo, model_manager, now, screen_off, started, theme_manager, time_validated)) + if run_update_checks: + run_thread_with_lock("update_checks", update_checks, (model_manager, now, theme_manager, time_validated, frogpilot_toggles)) if time_validated: theme_manager.update_holiday() run_update_checks = False - elif not time_validated: time_validated = system_time_valid() if not time_validated: @@ -219,6 +215,5 @@ def frogpilot_thread(): def main(): frogpilot_thread() - if __name__ == "__main__": main() diff --git a/selfdrive/frogpilot/frogpilot_variables.py b/selfdrive/frogpilot/frogpilot_variables.py index a41ba95513e0cd..4f237be5b571b5 100644 --- a/selfdrive/frogpilot/frogpilot_variables.py +++ b/selfdrive/frogpilot/frogpilot_variables.py @@ -35,8 +35,8 @@ RANDOM_EVENTS_PATH = os.path.join(BASEDIR, "selfdrive", "frogpilot", "assets", "random_events") THEME_SAVE_PATH = os.path.join("/data", "themes") -DEFAULT_MODEL = "alabama" -DEFAULT_MODEL_NAME = "Alabama" +DEFAULT_MODEL = "frankenweenie" +DEFAULT_MODEL_NAME = "Frankenweenie" DEFAULT_CLASSIC_MODEL = "north-dakota" DEFAULT_CLASSIC_MODEL_NAME = "North Dakota (Default)" @@ -157,7 +157,6 @@ def update_frogpilot_toggles(): ("ForceStandstill", 0), ("ForceStops", 0), ("FPSCounter", 1), - ("FrogPilotToggles", ""), ("FrogsGoMoosTweak", 1), ("FullMap", 0), ("GasRegenCmd", 1), @@ -297,9 +296,9 @@ def update_frogpilot_toggles(): ("SLCLookaheadHigher", 5), ("SLCLookaheadLower", 5), ("SLCOverride", 1), - ("SLCPriority1", "Dashboard"), - ("SLCPriority2", "Navigation"), - ("SLCPriority3", "Map Data"), + ("SLCPriority1", "Navigation"), + ("SLCPriority2", "Map Data"), + ("SLCPriority3", "Dashboard"), ("SNGHack", 1), ("SpeedLimitChangedAlert", 1), ("SpeedLimitController", 1), @@ -315,14 +314,14 @@ def update_frogpilot_toggles(): ("StandardPersonalityProfile", 1), ("StandbyMode", 0), ("StaticPedalsOnUI", 0), - ("SteerFriction", 0.1), - ("SteerFrictionStock", 0.1), - ("SteerLatAccel", 2.5), - ("SteerLatAccelStock", 2.5), - ("SteerKP", 1), - ("SteerKPStock", 1), - ("SteerRatio", 15), - ("SteerRatioStock", 15), + ("SteerFriction", 0), + ("SteerFrictionStock", 0), + ("SteerKP", 0), + ("SteerKPStock", 0), + ("SteerLatAccel", 0), + ("SteerLatAccelStock", 0), + ("SteerRatio", 0), + ("SteerRatioStock", 0), ("StoppedTimer", 0), ("TacoTune", 0), ("ToyotaDoors", 1), @@ -368,14 +367,14 @@ def update(self, started): if msg_bytes: with car.CarParams.from_bytes(msg_bytes) as CP: - always_on_lateral_set = key == "CarParams" and CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL + always_on_lateral_set = CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL car_make = CP.carName car_model = CP.carFingerprint has_auto_tune = (car_model == "hyundai" or car_model == "toyota") and CP.lateralTuning.which == "torque" has_bsm = CP.enableBsm has_radar = not CP.radarUnavailable is_pid_car = CP.lateralTuning.which == "pid" - max_acceleration_enabled = key == "CarParams" and CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX + max_acceleration_enabled = CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX openpilot_longitudinal = CP.openpilotLongitudinalControl pcm_cruise = CP.pcmCruise else: @@ -407,20 +406,20 @@ def update(self, started): toggle.use_wheel_speed = toggle.advanced_custom_onroad_ui and params.get_bool("WheelSpeed") toggle.advanced_lateral_tuning = params.get_bool("AdvancedLateralTune") + toggle.force_auto_tune = toggle.advanced_lateral_tuning and not has_auto_tune and not is_pid_car and params.get_bool("ForceAutoTune") + toggle.force_auto_tune_off = toggle.advanced_lateral_tuning and has_auto_tune and not is_pid_car and params.get_bool("ForceAutoTuneOff") stock_steer_friction = params.get_float("SteerFrictionStock") toggle.steer_friction = params.get_float("SteerFriction") if toggle.advanced_lateral_tuning else stock_steer_friction - toggle.use_custom_steer_friction = toggle.steer_friction != stock_steer_friction and not is_pid_car + toggle.use_custom_steer_friction = toggle.steer_friction != stock_steer_friction and not is_pid_car and not toggle.force_auto_tune or toggle.force_auto_tune_off stock_steer_kp = params.get_float("SteerKPStock") toggle.steer_kp = params.get_float("SteerKP") if toggle.advanced_lateral_tuning else stock_steer_kp toggle.use_custom_kp = toggle.steer_kp != stock_steer_kp and not is_pid_car stock_steer_lat_accel_factor = params.get_float("SteerLatAccelStock") toggle.steer_lat_accel_factor = params.get_float("SteerLatAccel") if toggle.advanced_lateral_tuning else stock_steer_lat_accel_factor - toggle.use_custom_lat_accel_factor = toggle.steer_lat_accel_factor != stock_steer_lat_accel_factor and not is_pid_car + toggle.use_custom_lat_accel_factor = toggle.steer_lat_accel_factor != stock_steer_lat_accel_factor and not is_pid_car and not toggle.force_auto_tune or toggle.force_auto_tune_off stock_steer_ratio = params.get_float("SteerRatioStock") toggle.steer_ratio = params.get_float("SteerRatio") if toggle.advanced_lateral_tuning else stock_steer_ratio - toggle.use_custom_steer_ratio = toggle.steer_ratio != stock_steer_ratio - toggle.force_auto_tune = toggle.advanced_lateral_tuning and not has_auto_tune and not is_pid_car and params.get_bool("ForceAutoTune") - toggle.force_auto_tune_off = toggle.advanced_lateral_tuning and has_auto_tune and not is_pid_car and params.get_bool("ForceAutoTuneOff") + toggle.use_custom_steer_ratio = toggle.steer_ratio != stock_steer_ratio and not toggle.force_auto_tune or toggle.force_auto_tune_off toggle.alert_volume_control = params.get_bool("AlertVolumeControl") toggle.disengage_volume = params.get_int("DisengageVolume") if toggle.alert_volume_control else 101 @@ -562,7 +561,7 @@ def update(self, started): toggle.frogsgomoo_tweak = openpilot_longitudinal and car_make == "toyota" and params.get_bool("FrogsGoMoosTweak") toggle.holiday_themes = params.get_bool("HolidayThemes") - toggle.current_holiday_theme = params.get("CurrentHolidayTheme", encoding='utf-8') if params.get_bool("HolidayThemes") else None + toggle.current_holiday_theme = params.get("CurrentHolidayTheme", encoding='utf-8') if toggle.holiday_themes else None toggle.lane_change_customizations = params.get_bool("LaneChangeCustomizations") toggle.lane_change_delay = params.get_float("LaneChangeTime") if toggle.lane_change_customizations else 0 @@ -661,7 +660,7 @@ def update(self, started): toggle.quality_of_life_visuals = params.get_bool("QOLVisuals") toggle.camera_view = params.get_int("CameraView") if toggle.quality_of_life_visuals else 0 toggle.driver_camera_in_reverse = toggle.quality_of_life_visuals and params.get_bool("DriverCamera") - toggle.onroad_distance_button = toggle.quality_of_life_visuals and params.get_bool("OnroadDistanceButton") + toggle.onroad_distance_button = openpilot_longitudinal and toggle.quality_of_life_visuals and params.get_bool("OnroadDistanceButton") toggle.standby_mode = toggle.quality_of_life_visuals and params.get_bool("StandbyMode") toggle.stopped_timer = toggle.quality_of_life_visuals and params.get_bool("StoppedTimer") @@ -704,8 +703,8 @@ def update(self, started): toggle.speed_limit_priority_lowest = toggle.speed_limit_priority1 == "Lowest" toggle.speed_limit_sources = toggle.speed_limit_controller and params.get_bool("SpeedLimitSources") - toggle.startup_alert_top = params.get("StartupMessageTop", encoding='utf-8') or "" - toggle.startup_alert_bottom = params.get("StartupMessageBottom", encoding='utf-8') or "" + toggle.startup_alert_top = params.get("StartupMessageTop", encoding='utf-8') or str(self.default_frogpilot_toggles.StartupMessageTop) + toggle.startup_alert_bottom = params.get("StartupMessageBottom", encoding='utf-8') or str(self.default_frogpilot_toggles.StartupMessageTop) toggle.tethering_config = params.get_int("TetheringEnabled") diff --git a/selfdrive/frogpilot/navigation/mapd.py b/selfdrive/frogpilot/navigation/mapd.py index 4bb08eb147b871..d37cef1277c531 100644 --- a/selfdrive/frogpilot/navigation/mapd.py +++ b/selfdrive/frogpilot/navigation/mapd.py @@ -3,13 +3,8 @@ import os import stat import subprocess -import time import urllib.request -from openpilot.common.realtime import Ratekeeper - -from openpilot.selfdrive.frogpilot.frogpilot_utilities import is_url_pingable - VERSION = 'v1' GITHUB_VERSION_URL = f"https://github.com/FrogAi/FrogPilot-Resources/raw/Versions/mapd_version_{VERSION}.json" @@ -18,16 +13,6 @@ MAPD_PATH = '/data/media/0/osm/mapd' VERSION_PATH = '/data/media/0/osm/mapd_version' -def get_latest_version(): - for url in [GITHUB_VERSION_URL, GITLAB_VERSION_URL]: - try: - with urllib.request.urlopen(url, timeout=5) as response: - return json.loads(response.read().decode('utf-8'))['version'] - except Exception as e: - print(f"Error fetching version from {url}: {e}") - print("Failed to get the latest version from both sources.") - return None - def download(current_version): urls = [ f"https://github.com/pfeiferj/openpilot-mapd/releases/download/{current_version}/mapd", @@ -45,49 +30,64 @@ def download(current_version): with open(VERSION_PATH, 'w') as version_file: version_file.write(current_version) - print(f"Successfully downloaded mapd from {url}") return True except Exception as e: - print(f"Failed to download from {url}: {e}") + print(f"Failed to download mapd from {url}: {e}") - print(f"Failed to download mapd for version {current_version} from both sources.") + print(f"Failed to download mapd for version {current_version}") return False -def ensure_mapd_is_running(): - while True: - if os.path.exists(MAPD_PATH): - try: - subprocess.run([MAPD_PATH], check=True) - except Exception as e: - print(f"Error running mapd process: {e}") - else: - print(f"Error: {MAPD_PATH} does not exist.") - time.sleep(1) +def get_installed_version(): + try: + with open(VERSION_PATH, 'r') as version_file: + return version_file.read().strip() + except FileNotFoundError: + return None + except Exception as e: + print(f"Error reading installed version: {e}") + return None -def mapd_thread(): - rk = Ratekeeper(0.05) +def get_latest_version(): + for url in [GITHUB_VERSION_URL, GITLAB_VERSION_URL]: + try: + with urllib.request.urlopen(url, timeout=5) as response: + return json.loads(response.read().decode('utf-8'))['version'] + except Exception as e: + print(f"Error fetching mapd version from {url}: {e}") + print("Failed to get the latest mapd version") + return None - while True: +def update_mapd(): + installed_version = get_installed_version() + latest_version = get_latest_version() + + if latest_version is None: + print("Could not get the latest mapd version") + return + + if installed_version != latest_version: + print("New version available, stopping mapd for update...") try: - if is_url_pingable("https://github.com"): - current_version = get_latest_version() - if current_version: - if not os.path.exists(MAPD_PATH) or not os.path.exists(VERSION_PATH) or open(VERSION_PATH).read() != current_version: - if download(current_version): - continue - ensure_mapd_is_running() + subprocess.run(["pkill", "-f", MAPD_PATH], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except Exception as e: - print(f"Exception in mapd_thread: {e}") - time.sleep(1) + print(f"Error stopping mapd process: {e}") + if download(latest_version): + print(f"Updated mapd to version {latest_version}") + else: + print("Failed to update mapd") + else: + print("Mapd is up to date") - rk.keep_time() +def ensure_mapd_is_running(): + while True: + try: + subprocess.run([MAPD_PATH], check=True) + except Exception as e: + print(f"Error running mapd process: {e}") def main(): - try: - mapd_thread() - except Exception as e: - print(f"Unhandled exception in main: {e}") + ensure_mapd_is_running() if __name__ == "__main__": main() diff --git a/selfdrive/frogpilot/navigation/ui/maps_settings.cc b/selfdrive/frogpilot/navigation/ui/maps_settings.cc index 7bc573c1f42832..7f5c53d209faa5 100644 --- a/selfdrive/frogpilot/navigation/ui/maps_settings.cc +++ b/selfdrive/frogpilot/navigation/ui/maps_settings.cc @@ -162,7 +162,7 @@ void FrogPilotMapsPanel::downloadMaps() { return; } - paramsMemory.put("OSMDownloadLocations", params.get("MapsSelected")); + params_memory.put("OSMDownloadLocations", params.get("MapsSelected")); downloadActive = true; diff --git a/selfdrive/frogpilot/navigation/ui/maps_settings.h b/selfdrive/frogpilot/navigation/ui/maps_settings.h index 2373c1ed198fcc..ce0b524946745f 100644 --- a/selfdrive/frogpilot/navigation/ui/maps_settings.h +++ b/selfdrive/frogpilot/navigation/ui/maps_settings.h @@ -65,7 +65,7 @@ class FrogPilotMapsPanel : public FrogPilotListWidget { MapSelectionControl *westMaps; Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; bool countriesOpen; bool downloadActive; diff --git a/selfdrive/frogpilot/screenrecorder/omx_encoder.cc b/selfdrive/frogpilot/screenrecorder/omx_encoder.cc index 0700cd7cf0defb..69e3f5c6ec874a 100644 --- a/selfdrive/frogpilot/screenrecorder/omx_encoder.cc +++ b/selfdrive/frogpilot/screenrecorder/omx_encoder.cc @@ -209,10 +209,18 @@ OmxEncoder::OmxEncoder(const char* path, int width, int height, int fps, int bit this->height = height; this->fps = fps; + OMX_ERRORTYPE err = OMX_Init(); + if (err != OMX_ErrorNone) { + LOGE("OMX_Init failed: %x", err); + return; + } + OMX_STRING component = (OMX_STRING)("OMX.qcom.video.encoder.avc"); - int err = OMX_GetHandle(&handle, component, this, &omx_callbacks); + err = OMX_GetHandle(&handle, component, this, &omx_callbacks); if (err != OMX_ErrorNone) { - LOGE("error getting codec: %x", err); + LOGE("Error getting codec: %x", err); + OMX_Deinit(); + return; } // setup input port @@ -543,6 +551,11 @@ OmxEncoder::~OmxEncoder() { OMX_CHECK(OMX_FreeHandle(handle)); + OMX_ERRORTYPE err = OMX_Deinit(); + if (err != OMX_ErrorNone) { + LOGE("OMX_Deinit failed: %x", err); + } + OMX_BUFFERHEADERTYPE *out_buf; while (free_in.try_pop(out_buf)); while (done_out.try_pop(out_buf)); diff --git a/selfdrive/frogpilot/screenrecorder/screenrecorder.cc b/selfdrive/frogpilot/screenrecorder/screenrecorder.cc index 906063bfc57f71..be6307d7a1cc0a 100644 --- a/selfdrive/frogpilot/screenrecorder/screenrecorder.cc +++ b/selfdrive/frogpilot/screenrecorder/screenrecorder.cc @@ -5,30 +5,48 @@ #include "selfdrive/frogpilot/screenrecorder/screenrecorder.h" namespace { - inline long long milliseconds() { + long long currentMilliseconds() { return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } + + uint64_t nanosSinceBoot() { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + } } -ScreenRecorder::ScreenRecorder(QWidget *parent) : QPushButton(parent), recording(false) { +ScreenRecorder::ScreenRecorder(QWidget *parent) : QPushButton(parent) { setFixedSize(btn_size, btn_size); - encoder = std::make_unique("/data/media/screen_recordings", screenWidth, screenHeight, UI_FREQ, 8 * 1024 * 1024); + std::thread encoderInitThread([this]() { + try { + encoder = std::make_unique("/data/media/screen_recordings", screenWidth, screenHeight, UI_FREQ, 8 * 1024 * 1024); + encoderReady = true; + } catch (const std::exception &e) { + std::cerr << "Error initializing OmxEncoder: " << e.what() << std::endl; + } + }); + encoderInitThread.detach(); + rgbScaleBuffer = std::make_unique(screenWidth * screenHeight * 4); QObject::connect(this, &QPushButton::clicked, this, &ScreenRecorder::toggleRecording); } ScreenRecorder::~ScreenRecorder() { - stop(); + stopRecording(); } void ScreenRecorder::toggleRecording() { - recording ? stop() : start(); + if (recording) { + stopRecording(); + } else { + startRecording(); + } } -void ScreenRecorder::start() { - if (recording) { +void ScreenRecorder::startRecording() { + if (recording || !encoderReady) { + std::cerr << "Recording already in progress or encoder not ready." << std::endl; return; } @@ -48,10 +66,10 @@ void ScreenRecorder::start() { recording = false; } - started_time = milliseconds(); + startedTime = currentMilliseconds(); } -void ScreenRecorder::stop() { +void ScreenRecorder::stopRecording() { if (!recording) { return; } @@ -69,7 +87,7 @@ void ScreenRecorder::stop() { } imageQueue.clear(); - rgbScaleBuffer.reset(new uint8_t[screenWidth * screenHeight * 4]); + rgbScaleBuffer = std::make_unique(screenWidth * screenHeight * 4); } void ScreenRecorder::openEncoder(const std::string &filename) { @@ -85,20 +103,29 @@ void ScreenRecorder::closeEncoder() { } void ScreenRecorder::encodingThreadFunction() { - uint64_t start_time = nanos_since_boot(); + uint64_t startTime = nanosSinceBoot(); while (recording) { - if (!encoder) { - break; - } - - QImage popImage; - if (imageQueue.pop_wait_for(popImage, std::chrono::milliseconds(10))) { - QImage image = popImage.convertToFormat(QImage::Format_RGBA8888); - libyuv::ARGBScale(image.bits(), image.width() * 4, image.width(), image.height(), - rgbScaleBuffer.get(), screenWidth * 4, screenWidth, screenHeight, - libyuv::kFilterBilinear); - encoder->encode_frame_rgba(rgbScaleBuffer.get(), screenWidth, screenHeight, nanos_since_boot() - start_time); + QImage image; + if (imageQueue.pop_wait_for(image, std::chrono::milliseconds(10))) { + QImage convertedImage = image.convertToFormat(QImage::Format_RGBA8888); + libyuv::ARGBScale( + convertedImage.bits(), + convertedImage.width() * 4, + convertedImage.width(), + convertedImage.height(), + rgbScaleBuffer.get(), + screenWidth * 4, + screenWidth, + screenHeight, + libyuv::kFilterBilinear + ); + encoder->encode_frame_rgba( + rgbScaleBuffer.get(), + screenWidth, + screenHeight, + nanosSinceBoot() - startTime + ); } } } @@ -109,13 +136,14 @@ void ScreenRecorder::updateScreen(double fps, bool started) { } if (!started) { - stop(); + stopRecording(); return; } - if (milliseconds() - started_time > 1000 * 60 * 3) { - stop(); - start(); + static long long recordingDurationLimit = 1000 * 60 * 3; + if (currentMilliseconds() - startedTime > recordingDurationLimit) { + stopRecording(); + startRecording(); return; } @@ -157,7 +185,7 @@ void ScreenRecorder::paintEvent(QPaintEvent *event) { painter.setPen(QPen(whiteColor(), 6)); painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, tr("RECORD")); - if (recording && ((milliseconds() - started_time) / 1000) % 2 == 0) { + if (recording && ((currentMilliseconds() - startedTime) / 1000) % 2 == 0) { painter.setPen(Qt::NoPen); painter.drawEllipse(QPoint(buttonRect.right() - btn_size / 10 - centeringOffset, buttonRect.center().y()), btn_size / 10, btn_size / 10); } diff --git a/selfdrive/frogpilot/screenrecorder/screenrecorder.h b/selfdrive/frogpilot/screenrecorder/screenrecorder.h index a3f4d536e0608a..4747d6269c5759 100644 --- a/selfdrive/frogpilot/screenrecorder/screenrecorder.h +++ b/selfdrive/frogpilot/screenrecorder/screenrecorder.h @@ -9,39 +9,43 @@ class ScreenRecorder : public QPushButton { Q_OBJECT public: - explicit ScreenRecorder(QWidget *parent = 0); + explicit ScreenRecorder(QWidget *parent = nullptr); ~ScreenRecorder() override; void updateScreen(double fps, bool started); +protected: + void paintEvent(QPaintEvent *event) override; + +private slots: + void toggleRecording(); + private: void closeEncoder(); void encodingThreadFunction(); void openEncoder(const std::string &filename); - void paintEvent(QPaintEvent *event) override; - void start(); - void stop(); - void toggleRecording(); + void startRecording(); + void stopRecording(); BlockingQueue imageQueue{UI_FREQ}; - BlockingQueue encodeQueue{UI_FREQ}; inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } - QWidget *rootWidget; - - bool recording; + QWidget *rootWidget = nullptr; int screenHeight = 1080; int screenWidth = 2160; - long long started_time; + long long startedTime = 0; - std::thread encodingThread; + std::atomic encoderReady{false}; + std::atomic recording{false}; std::unique_ptr encoder; std::unique_ptr rgbScaleBuffer; + + std::thread encodingThread; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc index 211fdc20ca89c5..bfe56bdd7f9e74 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc @@ -136,12 +136,12 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotSettingsWindow::closeParentToggle); QObject::connect(parent, &SettingsWindow::closeSubParentToggle, this, &FrogPilotSettingsWindow::closeSubParentToggle); QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotSettingsWindow::updateMetric); - QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotSettingsWindow::updateCarVariables); closeParentToggle(); } void FrogPilotSettingsWindow::showEvent(QShowEvent *event) { + updateCarVariables(); updatePanelVisibility(); } @@ -175,12 +175,8 @@ void FrogPilotSettingsWindow::updatePanelVisibility() { } void FrogPilotSettingsWindow::updateCarVariables() { - std::thread([this] { - std::string carParams = params.get("CarParamsPersistent"); - if (carParams.empty()) { - carParams = params.get("CarParams", true); - } - + std::string carParams = params.get("CarParamsPersistent"); + if (!carParams.empty()) { AlignedBuffer aligned_buf; capnp::FlatArrayMessageReader cmsg(aligned_buf.align(carParams.data(), carParams.size())); cereal::CarParams::Reader CP = cmsg.getRoot(); @@ -219,31 +215,31 @@ void FrogPilotSettingsWindow::updateCarVariables() { float currentRatioStock = params.getFloat("SteerRatioStock"); if (currentFrictionStock != steerFrictionStock && steerFrictionStock != 0) { - if (params.getFloat("SteerFriction") == currentFrictionStock) { - params.putFloatNonBlocking("SteerFriction", steerFrictionStock); + if (params.getFloat("SteerFriction") == currentFrictionStock || currentFrictionStock == 0) { + params.putFloat("SteerFriction", steerFrictionStock); } - params.putFloatNonBlocking("SteerFrictionStock", steerFrictionStock); + params.putFloat("SteerFrictionStock", steerFrictionStock); } if (currentKPStock != steerKPStock && currentKPStock != 0) { - if (params.getFloat("SteerKP") == currentKPStock) { - params.putFloatNonBlocking("SteerKP", steerKPStock); + if (params.getFloat("SteerKP") == currentKPStock || currentKPStock == 0) { + params.putFloat("SteerKP", steerKPStock); } - params.putFloatNonBlocking("SteerKPStock", steerKPStock); + params.putFloat("SteerKPStock", steerKPStock); } if (currentLatAccelStock != steerLatAccelStock && steerLatAccelStock != 0) { - if (params.getFloat("SteerLatAccel") == steerLatAccelStock) { - params.putFloatNonBlocking("SteerLatAccel", steerLatAccelStock); + if (params.getFloat("SteerLatAccel") == steerLatAccelStock || steerLatAccelStock == 0) { + params.putFloat("SteerLatAccel", steerLatAccelStock); } - params.putFloatNonBlocking("SteerLatAccelStock", steerLatAccelStock); + params.putFloat("SteerLatAccelStock", steerLatAccelStock); } if (currentRatioStock != steerRatioStock && steerRatioStock != 0) { - if (params.getFloat("SteerRatio") == steerRatioStock) { - params.putFloatNonBlocking("SteerRatio", steerRatioStock); + if (params.getFloat("SteerRatio") == steerRatioStock || steerRatioStock == 0) { + params.putFloat("SteerRatio", steerRatioStock); } - params.putFloatNonBlocking("SteerRatioStock", steerRatioStock); + params.putFloat("SteerRatioStock", steerRatioStock); } uiState()->scene.has_auto_tune = hasAutoTune || forcingAutoTune; @@ -265,7 +261,7 @@ void FrogPilotSettingsWindow::updateCarVariables() { } emit updateCarToggles(); - }).detach(); + } } void FrogPilotSettingsWindow::addPanelControl(FrogPilotListWidget *list, QString &title, QString &desc, std::vector &button_labels, QString &icon, std::vector &panels, QString ¤tPanel) { diff --git a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc index dcaa426e298993..0e5b5d6e08d33e 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc @@ -40,23 +40,27 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : QObject::connect(advancedLateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { std::set modifiedAdvancedLateralTuneKeys = advancedLateralTuneKeys; - bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF"); - if (usingNNFF) { + bool forcingAutoTune = params.getBool("ForceAutoTune"); + bool forcingAutoTuneOff = params.getBool("ForceAutoTuneOff"); + if (!hasAutoTune && forcingAutoTune || hasAutoTune && !forcingAutoTuneOff) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + modifiedAdvancedLateralTuneKeys.erase("SteerRatio"); + } + + if (hasAutoTune) { modifiedAdvancedLateralTuneKeys.erase("ForceAutoTune"); + } else if (isPIDCar) { modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); } 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"); - } + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); } + bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF"); if (!liveValid || usingNNFF) { modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); @@ -175,6 +179,36 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : } }); + QObject::connect(static_cast(toggles["ForceAutoTune"]), &ToggleControl::toggleFlipped, [this](bool state) { + std::set modifiedAdvancedLateralTuneKeys = advancedLateralTuneKeys; + + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); + + if (!hasAutoTune && state) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + modifiedAdvancedLateralTuneKeys.erase("SteerRatio"); + } + + showToggles(modifiedAdvancedLateralTuneKeys); + }); + + QObject::connect(static_cast(toggles["ForceAutoTuneOff"]), &ToggleControl::toggleFlipped, [this](bool state) { + std::set modifiedAdvancedLateralTuneKeys = advancedLateralTuneKeys; + + modifiedAdvancedLateralTuneKeys.erase("ForceAutoTune"); + + if (hasAutoTune && !state) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + modifiedAdvancedLateralTuneKeys.erase("SteerRatio"); + } + + showToggles(modifiedAdvancedLateralTuneKeys); + }); + QObject::connect(static_cast(toggles["NNFF"]), &ToggleControl::toggleFlipped, [this](bool state) { std::set modifiedLateralTuneKeys = lateralTuneKeys; diff --git a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc index c4220fdb7d8e23..00844447a94a5c 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc @@ -372,43 +372,35 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * longitudinalToggle = overrideSelection; } else if (param == "SLCPriority") { ButtonControl *slcPriorityButton = new ButtonControl(title, tr("SELECT"), desc); - QStringList primaryPriorities = {tr("None"), tr("Dashboard"), tr("Map Data"), tr("Navigation"), tr("Highest"), tr("Lowest")}; - QStringList secondaryTertiaryPriorities = {tr("None"), tr("Dashboard"), tr("Map Data"), tr("Navigation")}; + QStringList primaryPriorities = {tr("Dashboard"), tr("Map Data"), tr("Navigation"), tr("Highest"), tr("Lowest")}; + QStringList otherPriorities = {tr("None"), tr("Dashboard"), tr("Map Data"), tr("Navigation")}; QStringList priorityPrompts = {tr("Select your primary priority"), tr("Select your secondary priority"), tr("Select your tertiary priority")}; QObject::connect(slcPriorityButton, &ButtonControl::clicked, [=]() { QStringList selectedPriorities; for (int i = 1; i <= 3; ++i) { - QStringList currentPriorities = (i == 1) ? primaryPriorities : secondaryTertiaryPriorities; - QStringList prioritiesToDisplay = currentPriorities; - - for (QString selectedPriority : qAsConst(selectedPriorities)) { - prioritiesToDisplay.removeAll(selectedPriority); - } + QStringList availablePriorities = (i == 1) ? primaryPriorities : otherPriorities; + availablePriorities = availablePriorities.toSet().subtract(selectedPriorities.toSet()).toList(); if (!hasDashSpeedLimits) { - prioritiesToDisplay.removeAll(tr("Dashboard")); + availablePriorities.removeAll(tr("Dashboard")); } - - if (prioritiesToDisplay.size() == 1 && prioritiesToDisplay.contains(tr("None"))) { + if (availablePriorities.size() == 1 && availablePriorities.contains(tr("None"))) { break; } - QString priorityKey = QString("SLCPriority%1").arg(i); - QString selection = MultiOptionDialog::getSelection(priorityPrompts[i - 1], prioritiesToDisplay, "", this); - + QString selection = MultiOptionDialog::getSelection(priorityPrompts[i - 1], availablePriorities, "", this); if (selection.isEmpty()) { break; } - params.putNonBlocking(priorityKey.toStdString(), selection.toStdString()); + params.put(QString("SLCPriority%1").arg(i).toStdString(), selection.toStdString()); selectedPriorities.append(selection); if (selection == tr("None")) { for (int j = i + 1; j <= 3; ++j) { - QString priorityKeyNext = QString("SLCPriority%1").arg(j); - params.putNonBlocking(priorityKeyNext.toStdString(), "None"); + params.put(QString("SLCPriority%1").arg(j).toStdString(), tr("None").toStdString()); } break; } @@ -426,10 +418,8 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * QStringList initialPriorities; for (int i = 1; i <= 3; ++i) { - QString priorityKey = QString("SLCPriority%1").arg(i); - QString priority = QString::fromStdString(params.get(priorityKey.toStdString())); - - if (!priority.isEmpty() && primaryPriorities.contains(priority) && priority != tr("None")) { + QString priority = QString::fromStdString(params.get(QString("SLCPriority%1").arg(i).toStdString())); + if (!priority.isEmpty() && priority != tr("None") && primaryPriorities.contains(priority)) { initialPriorities.append(priority); } } diff --git a/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc index cf23ec66d0ac3a..d229c1d209f73d 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc @@ -144,8 +144,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog 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); + params_memory.remove("ModelToDownload"); + params_memory.putBool("CancelModelDownload", true); cancellingDownload = true; } else { QMap labelToModelMap; @@ -163,8 +163,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog QString modelToDownload = MultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableModels, "", this); if (!modelToDownload.isEmpty()) { modelDownloading = true; - paramsMemory.put("ModelToDownload", labelToModelMap.value(modelToDownload).toStdString()); - paramsMemory.put("ModelDownloadProgress", "0%"); + params_memory.put("ModelToDownload", labelToModelMap.value(modelToDownload).toStdString()); + params_memory.put("ModelDownloadProgress", "0%"); downloadModelBtn->setValue(tr("Downloading %1...").arg(modelToDownload.remove(QRegularExpression("[πŸ—ΊοΈπŸ‘€πŸ“‘]")).trimmed())); @@ -172,7 +172,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog progressTimer->setInterval(100); QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { - QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); + QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress")); bool downloadComplete = progress.contains(QRegularExpression("downloaded", QRegularExpression::CaseInsensitiveOption)); bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); @@ -199,8 +199,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog downloadModelBtn->setValue(progress); - paramsMemory.remove("CancelModelDownload"); - paramsMemory.remove("ModelDownloadProgress"); + params_memory.remove("CancelModelDownload"); + params_memory.remove("ModelDownloadProgress"); progressTimer->stop(); progressTimer->deleteLater(); @@ -229,8 +229,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog 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); + params_memory.remove("DownloadAllModels"); + params_memory.putBool("CancelModelDownload", true); cancellingDownload = true; } else { startDownloadAllModels(); @@ -340,7 +340,7 @@ void FrogPilotModelPanel::startDownloadAllModels() { allModelsDownloading = true; modelDownloading = true; - paramsMemory.putBool("DownloadAllModels", true); + params_memory.putBool("DownloadAllModels", true); downloadAllModelsBtn->setValue(tr("Downloading models...")); @@ -348,7 +348,7 @@ void FrogPilotModelPanel::startDownloadAllModels() { progressTimer->setInterval(100); QObject::connect(progressTimer, &QTimer::timeout, this, [=]() { - QString progress = QString::fromStdString(paramsMemory.get("ModelDownloadProgress")); + QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress")); bool downloadComplete = progress.contains(QRegularExpression("All models downloaded!", QRegularExpression::CaseInsensitiveOption)); bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption)); @@ -364,8 +364,8 @@ void FrogPilotModelPanel::startDownloadAllModels() { downloadAllModelsBtn->setValue(progress); - paramsMemory.remove("CancelModelDownload"); - paramsMemory.remove("ModelDownloadProgress"); + params_memory.remove("CancelModelDownload"); + params_memory.remove("ModelDownloadProgress"); progressTimer->stop(); progressTimer->deleteLater(); @@ -374,7 +374,7 @@ void FrogPilotModelPanel::startDownloadAllModels() { cancellingDownload = false; modelDownloading = false; - paramsMemory.remove("DownloadAllModels"); + params_memory.remove("DownloadAllModels"); downloadAllModelsBtn->setValue(""); }); diff --git a/selfdrive/frogpilot/ui/qt/offroad/model_settings.h b/selfdrive/frogpilot/ui/qt/offroad/model_settings.h index cc3229e6c7d048..379c192c82acef 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/model_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/model_settings.h @@ -33,7 +33,7 @@ class FrogPilotModelPanel : public FrogPilotListWidget { ButtonControl *selectModelBtn; Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; Params paramsStorage{"/persist/params"}; QDir modelDir{"/data/models/"}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc index 6fe782ed9a80d1..08dddee948508e 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc @@ -113,11 +113,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (colorDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; colorDownloading = false; themeDownloading = false; @@ -128,9 +128,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!colorSchemeToDownload.isEmpty()) { QString convertedColorScheme = formatColorNameForStorage(colorSchemeToDownload); - paramsMemory.put("ColorToDownload", convertedColorScheme.toStdString()); + params_memory.put("ColorToDownload", convertedColorScheme.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); colorDownloading = true; themeDownloading = true; @@ -241,11 +241,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (distanceIconDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; distanceIconDownloading = false; themeDownloading = false; @@ -256,9 +256,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!iconPackToDownload.isEmpty()) { QString convertedIconPack = formatIconNameForStorage(iconPackToDownload); - paramsMemory.put("DistanceIconToDownload", convertedIconPack.toStdString()); + params_memory.put("DistanceIconToDownload", convertedIconPack.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); distanceIconDownloading = true; themeDownloading = true; @@ -370,11 +370,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (iconDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; iconDownloading = false; themeDownloading = false; @@ -385,9 +385,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!iconPackToDownload.isEmpty()) { QString convertedIconPack = formatIconNameForStorage(iconPackToDownload); - paramsMemory.put("IconToDownload", convertedIconPack.toStdString()); + params_memory.put("IconToDownload", convertedIconPack.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); iconDownloading = true; themeDownloading = true; @@ -465,12 +465,12 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr availableSignals << formatSignalName(dirInfo.fileName()); } } - availableSignals.append("Stock"); + availableSignals.append("None"); std::sort(availableSignals.begin(), availableSignals.end()); if (id == 0) { QStringList customSignalsList = availableSignals; - customSignalsList.removeAll("Stock"); + customSignalsList.removeAll("None"); customSignalsList.removeAll(currentSignal); QString signalPackToDelete = MultiOptionDialog::getSelection(tr("Select a signal pack to delete"), customSignalsList, "", this); @@ -499,11 +499,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (signalDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; signalDownloading = false; themeDownloading = false; @@ -514,9 +514,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!signalPackToDownload.isEmpty()) { QString convertedSignalPack = formatSignalNameForStorage(signalPackToDownload); - paramsMemory.put("SignalToDownload", convertedSignalPack.toStdString()); + params_memory.put("SignalToDownload", convertedSignalPack.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); signalDownloading = true; themeDownloading = true; @@ -628,11 +628,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (soundDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; soundDownloading = false; themeDownloading = false; @@ -643,9 +643,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!soundSchemeToDownload.isEmpty()) { QString convertedSoundScheme = formatSoundNameForStorage(soundSchemeToDownload); - paramsMemory.put("SoundToDownload", convertedSoundScheme.toStdString()); + params_memory.put("SoundToDownload", convertedSoundScheme.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); soundDownloading = true; themeDownloading = true; @@ -757,11 +757,11 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } } else if (id == 1) { if (wheelDownloading) { - paramsMemory.putBool("CancelThemeDownload", true); + params_memory.putBool("CancelThemeDownload", true); cancellingDownload = true; QTimer::singleShot(2000, [=]() { - paramsMemory.putBool("CancelThemeDownload", false); + params_memory.putBool("CancelThemeDownload", false); cancellingDownload = false; wheelDownloading = false; themeDownloading = false; @@ -772,9 +772,9 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr if (!wheelToDownload.isEmpty()) { QString convertedImage = formatWheelNameForStorage(wheelToDownload); - paramsMemory.put("WheelToDownload", convertedImage.toStdString()); + params_memory.put("WheelToDownload", convertedImage.toStdString()); downloadStatusLabel->setText("Downloading..."); - paramsMemory.put("ThemeDownloadProgress", "Downloading..."); + params_memory.put("ThemeDownloadProgress", "Downloading..."); themeDownloading = true; wheelDownloading = true; @@ -831,10 +831,10 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr } else if (id == 2) { 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()); + params.put("StartupMessageTop", newTop.toStdString()); 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()); + params.put("StartupMessageBottom", newBottom.toStdString()); } } } else if (id == 3) { @@ -891,7 +891,7 @@ void FrogPilotThemesPanel::updateState(const UIState &s) { if (personalizeOpenpilotOpen) { if (themeDownloading) { - QString progress = QString::fromStdString(paramsMemory.get("ThemeDownloadProgress")); + QString progress = QString::fromStdString(params_memory.get("ThemeDownloadProgress")); bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|Failed|offline", QRegularExpression::CaseInsensitiveOption)); if (progress != "Downloading...") { @@ -904,7 +904,7 @@ void FrogPilotThemesPanel::updateState(const UIState &s) { downloadStatusLabel->setText("Idle"); } }); - paramsMemory.remove("ThemeDownloadProgress"); + params_memory.remove("ThemeDownloadProgress"); colorDownloading = false; distanceIconDownloading = false; iconDownloading = false; diff --git a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h index 9ddfe7b6aa3914..65fae972542461 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.h @@ -35,7 +35,7 @@ class FrogPilotThemesPanel : public FrogPilotListWidget { LabelControl *downloadStatusLabel; Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; bool cancellingDownload; bool colorDownloading; diff --git a/selfdrive/frogpilot/ui/qt/offroad/utilities.cc b/selfdrive/frogpilot/ui/qt/offroad/utilities.cc index eb6a5c10868922..3e837dcd6a3d85 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/utilities.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/utilities.cc @@ -29,14 +29,14 @@ UtilitiesPanel::UtilitiesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListW 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); - paramsMemory.putBool("ForceOnroad", false); + params_memory.putBool("ForceOffroad", true); + params_memory.putBool("ForceOnroad", false); } else if (id == 1) { - paramsMemory.putBool("ForceOffroad", false); - paramsMemory.putBool("ForceOnroad", true); + params_memory.putBool("ForceOffroad", false); + params_memory.putBool("ForceOnroad", true); } else if (id == 2) { - paramsMemory.putBool("ForceOffroad", false); - paramsMemory.putBool("ForceOnroad", false); + params_memory.putBool("ForceOffroad", false); + params_memory.putBool("ForceOnroad", false); } forceStartedBtn->setCheckedButton(id); }); diff --git a/selfdrive/frogpilot/ui/qt/offroad/utilities.h b/selfdrive/frogpilot/ui/qt/offroad/utilities.h index 93f5481c9b1e85..4be541371c7685 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/utilities.h +++ b/selfdrive/frogpilot/ui/qt/offroad/utilities.h @@ -12,5 +12,5 @@ class UtilitiesPanel : public FrogPilotListWidget { FrogPilotButtonsControl *forceStartedBtn; Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; }; diff --git a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc index e44bce01e52dd0..bc82cbda65c918 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc +++ b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.cc @@ -5,8 +5,8 @@ #include "selfdrive/ui/ui.h" void updateFrogPilotToggles() { - static Params paramsMemory{"/dev/shm/params"}; - paramsMemory.putBool("FrogPilotTogglesUpdated", true); + static Params params_memory{"/dev/shm/params"}; + params_memory.putBool("FrogPilotTogglesUpdated", true); } QColor loadThemeColors(const QString &colorKey, bool clearCache) { diff --git a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h index b4c78b959b91fb..7b689387e3e15b 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h +++ b/selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h @@ -343,7 +343,7 @@ private slots: void onButtonReleased() { if (instantUpdate) { - params.putFloatNonBlocking(key, value); + params.putFloat(key, value); } float lastValue = value; diff --git a/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.cc b/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.cc index 5bc2d310c55300..cc34f895e822e2 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.cc +++ b/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.cc @@ -110,7 +110,7 @@ QPushButton *ModelReview::createButton(const QString &text, const QString &type, } void ModelReview::showEvent(QShowEvent *event) { - currentModel = QString::fromStdString(paramsMemory.get("CurrentModelName")); + currentModel = QString::fromStdString(params_memory.get("CurrentModelName")); currentModelFiltered = processModelName(currentModel); mainLayout->setCurrentIndex(modelRated ? 1 : 0); diff --git a/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.h b/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.h index 4f5af5c0164dc2..f3593d2c00da94 100644 --- a/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.h +++ b/selfdrive/frogpilot/ui/qt/widgets/model_reviewer.h @@ -43,7 +43,7 @@ private slots: QPushButton *blacklistButton; Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; QString currentModel; QString currentModelFiltered; diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 415f736cdc2e40..03e0176ca93aa4 100644 Binary files a/selfdrive/modeld/models/supercombo.onnx and b/selfdrive/modeld/models/supercombo.onnx differ diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index e2ea3ac5a04624..efb7925be2ff5e 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -125,5 +125,5 @@ class SoftwarePanel : public ListWidget { ParamWatcher *fs_watch; // FrogPilot variables - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; }; diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 081e2ea5e3cd1d..45b8463bca8f23 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -44,7 +44,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { } else { std::system("pkill -SIGHUP -f system.updated.updated"); } - paramsMemory.putBool("ManualUpdateInitiated", true); + params_memory.putBool("ManualUpdateInitiated", true); }); addItem(downloadBtn); @@ -143,10 +143,10 @@ void SoftwarePanel::updateLabels() { } // updater only runs offroad or when parked - bool parked = scene.parked; + bool parked = scene.parked || scene.frogs_go_moo; - onroadLbl->setVisible(is_onroad && !parked && !scene.frogs_go_moo); - downloadBtn->setVisible(!is_onroad || parked || scene.frogs_go_moo); + onroadLbl->setVisible(is_onroad && !parked); + downloadBtn->setVisible(!is_onroad || parked); // download update QString updater_state = QString::fromStdString(params.get("UpdaterState")); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 8a817bc47a5dca..0e6f728940b018 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -560,7 +560,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f if (scene.show_stopping_point_metrics) { QFont font = InterFont(35, QFont::DemiBold); - QString text = QString::number(modelLength * distanceConversion) + leadDistanceUnit; + QString text = QString::number(std::nearbyint(modelLength * distanceConversion)) + leadDistanceUnit; int text_width = QFontMetrics(font).horizontalAdvance(text); QPointF text_position = last_point - QPointF(text_width / 2, stopSignImg.height() + 35); diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index 2f0722ccb58747..e524a0dbc9a088 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -39,6 +39,7 @@ ExperimentalButton::~ExperimentalButton() { if (gif != nullptr) { gif->stop(); delete gif; + gif = nullptr; gif_label->hide(); } } @@ -126,12 +127,19 @@ void ExperimentalButton::updateIcon() { if (gif != nullptr) { gif->stop(); delete gif; + gif = nullptr; gif_label->hide(); } if (QFile::exists(wheel_gif_path)) { gif = new QMovie(wheel_gif_path); + if (!gif->isValid()) { + delete gif; + gif = nullptr; + return; + } + gif_label->setMovie(gif); gif_label->resize(img_size, img_size); gif_label->move((btn_size - img_size) / 2, (btn_size - img_size) / 2 + y_offset); diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc index 0749dd2cc708d0..d4deac8fc3557d 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/qt/onroad/onroad_home.cc @@ -125,7 +125,6 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { if (scene.speed_limit_changed && nvg->newSpeedLimitRect.contains(pos)) { paramsMemory.putBool("SLCConfirmed", true); - paramsMemory.putBool("SLCConfirmedPressed", true); return; } diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index abb864eb3676a4..bd2a843f6598ab 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -63,24 +63,28 @@ void Sidebar::updateIcon(QLabel *&label, QMovie *&gif, const QString &gifPath, c gif->stop(); delete gif; gif = nullptr; - label->hide(); + if (label) { + label->hide(); + } } if (QFile::exists(selectedGifPath)) { gif = new QMovie(selectedGifPath); - if (!gif->fileName().isEmpty()) { + if (gif->isValid()) { gif->setScaledSize(btnRect.size()); - label->setGeometry(btnRect); - label->setMovie(gif); - label->show(); + if (label) { + label->setGeometry(btnRect); + label->setMovie(gif); + label->show(); + } gif->start(); - isGif = true; } else { delete gif; + gif = nullptr; isGif = false; } } else { diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 6e52e9139d1a1c..c3dca7840f9852 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -490,7 +490,7 @@ void UIState::updateStatus() { } scene.started |= scene.force_onroad; - scene.started &= !paramsMemory.getBool("ForceOffroad"); + scene.started &= !params_memory.getBool("ForceOffroad"); // Handle onroad/offroad transition if (scene.started != started_prev || sm->frame == 1) { @@ -548,9 +548,9 @@ void UIState::update() { emit uiUpdate(*this); // FrogPilot variables - scene.conditional_status = scene.conditional_experimental && scene.enabled ? paramsMemory.getInt("CEStatus") : 0; + scene.conditional_status = scene.conditional_experimental && scene.enabled ? params_memory.getInt("CEStatus") : 0; scene.driver_camera_timer = scene.driver_camera_in_reverse && scene.reverse ? scene.driver_camera_timer + 1 : 0; - scene.force_onroad = paramsMemory.getBool("ForceOnroad"); + scene.force_onroad = params_memory.getBool("ForceOnroad"); scene.started_timer = scene.started || started_prev ? scene.started_timer + 1 : 0; if (scene.keep_screen_on) { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 9cccb54f61d090..aa5ef314813736 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -332,7 +332,7 @@ private slots: PrimeType prime_type = PrimeType::UNKNOWN; // FrogPilot variables - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; }; UIState *uiState(); diff --git a/system/manager/manager.py b/system/manager/manager.py index 29dcb0efe072f3..53eb6a6aed8503 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -29,16 +29,17 @@ def manager_init() -> None: build_metadata = get_build_metadata() params = Params() - setup_frogpilot(build_metadata, params) - params_storage = Params("/persist/params") params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) if build_metadata.release_channel: params.clear_all(ParamKeyType.DEVELOPMENT_ONLY) - convert_params(params, params_storage) - threading.Thread(target=frogpilot_boot_functions, args=(build_metadata, params, params_storage,)).start() + # FrogPilot variables + setup_frogpilot(build_metadata) + params_storage = Params("/persist/params") + convert_params(params_storage) + threading.Thread(target=frogpilot_boot_functions, args=(build_metadata, params_storage,)).start() default_params: list[tuple[str, str | bytes]] = [ ("AlwaysOnDM", "0"), diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 39d418c33e61f9..115b951e7556a7 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -72,7 +72,7 @@ def run_new_modeld(started, params, CP: car.CarParams, classic_model, frogpilot_ NativeProcess("mapsd", "selfdrive/navd", ["./mapsd"], only_onroad), PythonProcess("navmodeld", "selfdrive.modeld.navmodeld", only_onroad), NativeProcess("sensord", "system/sensord", ["./sensord"], only_onroad, enabled=not PC), - NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(30 if not PC else None)), + NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)), PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"], only_onroad), NativeProcess("pandad", "selfdrive/pandad", ["./pandad"], always_run, enabled=False), diff --git a/system/sentry.py b/system/sentry.py index 35bf570e6f1612..7a2dd7e4e971ed 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -96,7 +96,7 @@ def capture_fingerprint(candidate, params, blocked=False): sentry_sdk.capture_message("Blocked user from using the development branch", level='error') else: sentry_sdk.capture_message(f"Fingerprinted {candidate}", level='info') - params.put_bool_nonblocking("FingerprintLogged", True) + params.put_bool("FingerprintLogged", True) sentry_sdk.flush() diff --git a/system/updated/updated.py b/system/updated/updated.py index 180a4a54e08ec6..40fd8b898e8f0a 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -411,7 +411,7 @@ def fetch_update(self) -> None: cloudlog.info("finalize success!") # Format "Updated" to Phoenix time zone - self.params.put_nonblocking("Updated", datetime.datetime.now().astimezone(ZoneInfo('America/Phoenix')).strftime("%B %d, %Y - %I:%M%p").encode('utf8')) + self.params.put("Updated", datetime.datetime.now().astimezone(ZoneInfo('America/Phoenix')).strftime("%B %d, %Y - %I:%M%p").encode('utf8')) def main() -> None: params = Params() @@ -468,7 +468,7 @@ def main() -> None: # Format "InstallDate" to Phoenix time zone if not install_date_set: - params.put_nonblocking("InstallDate", datetime.datetime.now().astimezone(ZoneInfo('America/Phoenix')).strftime("%B %d, %Y - %I:%M%p").encode('utf8')) + params.put("InstallDate", datetime.datetime.now().astimezone(ZoneInfo('America/Phoenix')).strftime("%B %d, %Y - %I:%M%p").encode('utf8')) install_date_set = True if not (frogpilot_toggles.automatic_updates or params_memory.get_bool("ManualUpdateInitiated")):