diff --git a/README.md b/README.md index b1d76f46a883a6..2e3dccaf3aa1cc 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ FrogPilot is a fully open-sourced fork of openpilot, featuring clear and concise ------ FrogPilot was last updated on: -**December 21st, 2024** +**January 1st, 2025** Features ------ diff --git a/cereal/custom.capnp b/cereal/custom.capnp index b4bc8dab875fe7..1730181e1e4b28 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -63,26 +63,23 @@ struct FrogPilotPlan @0x80ae746ee2596b11 { minAcceleration @12 :Float32; mtscSpeed @13 :Float32; redLight @14 :Bool; - safeObstacleDistance @15 :Int64; - safeObstacleDistanceStock @16 :Int64; - slcMapSpeedLimit @17 :Float32; - slcOverridden @18 :Bool; - slcOverriddenSpeed @19 :Float32; - slcSpeedLimit @20 :Float32; - slcSpeedLimitOffset @21 :Float32; - slcSpeedLimitSource @22 :Text; - speedJerk @23 :Float32; - speedJerkStock @24 :Float32; - speedLimitChanged @25 :Bool; - stoppedEquivalenceFactor @26 :Int64; - tFollow @27 :Float32; - themeUpdated @28 :Bool; - togglesUpdated @29 :Bool; - unconfirmedSlcSpeedLimit @30 :Float32; - upcomingSLCSpeedLimit @31 :Float32; - vCruise @32 :Float32; - vtscControllingCurve @33 :Bool; - vtscSpeed @34 :Float32; + slcMapSpeedLimit @15 :Float32; + slcOverridden @16 :Bool; + slcOverriddenSpeed @17 :Float32; + slcSpeedLimit @18 :Float32; + slcSpeedLimitOffset @19 :Float32; + slcSpeedLimitSource @20 :Text; + speedJerk @21 :Float32; + speedJerkStock @22 :Float32; + speedLimitChanged @23 :Bool; + tFollow @24 :Float32; + themeUpdated @25 :Bool; + togglesUpdated @26 :Bool; + unconfirmedSlcSpeedLimit @27 :Float32; + upcomingSLCSpeedLimit @28 :Float32; + vCruise @29 :Float32; + vtscControllingCurve @30 :Bool; + vtscSpeed @31 :Float32; } struct CustomReserved5 @0xa5cd762cd951a455 { diff --git a/common/params.cc b/common/params.cc index 8149aa90fe5136..cb78bc0cb963fa 100644 --- a/common/params.cc +++ b/common/params.cc @@ -339,8 +339,6 @@ std::unordered_map keys = { {"GoatScream", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"GreenLightAlert", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HideAlerts", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, - {"HideAOLStatusBar", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"HideCEMStatusBar", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"HideCSCUI", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"HideLeadMarker", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"HideMapIcon", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, @@ -467,6 +465,7 @@ std::unordered_map keys = { {"SecretGoodOpenpilotScore", PERSISTENT | FROGPILOT_CONTROLS}, {"SetSpeedLimit", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SetSpeedOffset", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, + {"ShowCEMStatus", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowCPU", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowGPU", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, {"ShowIP", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, @@ -485,7 +484,6 @@ std::unordered_map keys = { {"SLCConfirmation", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmationHigher", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCConfirmationLower", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, - {"SLCConfirmed", PERSISTENT}, {"SLCLookaheadHigher", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCLookaheadLower", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SLCFallback", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, @@ -495,6 +493,7 @@ std::unordered_map keys = { {"SLCPriority3", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SNGHack", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VEHICLES}, {"SoundToDownload", PERSISTENT}, + {"SpeedLimitAccepted", PERSISTENT}, {"SpeedLimitChangedAlert", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SpeedLimitController", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_CONTROLS}, {"SpeedLimitSources", PERSISTENT | FROGPILOT_STORAGE | FROGPILOT_VISUALS}, diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 9aad54ee82ae35..8bedb3c6d4b133 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -100,7 +100,6 @@ def __init__(self, dbc_name, CP, VM): self.secoc_lka_message_counter = 0 self.secoc_lta_message_counter = 0 self.secoc_prev_reset_counter = 0 - self.secoc_mismatch_counter = 0 # FrogPilot variables self.stock_max_accel = self.params.ACCEL_MAX @@ -148,9 +147,8 @@ def update(self, CC, CS, now_nanos, frogpilot_toggles): self.secoc_prev_reset_counter = CS.secoc_synchronization['RESET_CNT'] expected_mac = build_sync_mac(self.secoc_key, int(CS.secoc_synchronization['TRIP_CNT']), int(CS.secoc_synchronization['RESET_CNT'])) - if int(CS.secoc_synchronization['AUTHENTICATOR']) != expected_mac and self.secoc_mismatch_counter < 100: + if int(CS.secoc_synchronization['AUTHENTICATOR']) != expected_mac: carlog.error("SecOC synchronization MAC mismatch, wrong key?") - self.secoc_mismatch_counter += 1 # *** steer torque *** new_steer = int(round(actuators.steer * self.params.STEER_MAX)) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 1cbff09a66b45d..99d6c3b963ee23 100644 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -52,6 +52,27 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP): return [a_target[0], min(a_target[1], a_x_allowed)] +def get_accel_from_plan_classic(CP, speeds, accels): + if len(speeds) == CONTROL_N: + v_target_now = interp(DT_MDL, CONTROL_N_T_IDX, speeds) + a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, accels) + + v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds) + if v_target != v_target_now: + a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now + else: + a_target = a_target_now + + v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds) + else: + v_target = 0.0 + v_target_1sec = 0.0 + a_target = 0.0 + should_stop = (v_target < CP.vEgoStopping and + v_target_1sec < CP.vEgoStopping) + return a_target, should_stop + + def get_accel_from_plan(speeds, accels, action_t=DT_MDL, vEgoStopping=0.05): if len(speeds) == CONTROL_N: v_now = speeds[0] @@ -273,7 +294,7 @@ def update(self, classic_model, radarless_model, sm, frogpilot_toggles): self.a_desired = float(interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory)) self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0 - def publish(self, sm, pm): + def publish(self, classic_model, sm, pm): plan_send = messaging.new_message('longitudinalPlan') plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState']) @@ -291,9 +312,12 @@ def publish(self, sm, pm): longitudinalPlan.longitudinalPlanSource = self.mpc.source longitudinalPlan.fcw = self.fcw - action_t = self.CP.longitudinalActuatorDelay + DT_MDL - a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels, - action_t=action_t, vEgoStopping=self.CP.vEgoStopping) + if classic_model: + a_target, should_stop = get_accel_from_plan_classic(self.CP, longitudinalPlan.speeds, longitudinalPlan.accels) + else: + action_t = self.CP.longitudinalActuatorDelay + DT_MDL + a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels, + action_t=action_t, vEgoStopping=self.CP.vEgoStopping) longitudinalPlan.aTarget = a_target longitudinalPlan.shouldStop = should_stop longitudinalPlan.allowBrake = True diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index c151c816076908..d3329dd44e7b49 100644 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -44,7 +44,7 @@ def plannerd_thread(): sm.update() if sm.updated['modelV2']: longitudinal_planner.update(classic_model, radarless_model, sm, frogpilot_toggles) - longitudinal_planner.publish(sm, pm) + longitudinal_planner.publish(classic_model, sm, pm) publish_ui_plan(sm, pm, longitudinal_planner) # Update FrogPilot parameters diff --git a/selfdrive/frogpilot/assets/other_images/chill_mode_icon.png b/selfdrive/frogpilot/assets/other_images/chill_mode_icon.png new file mode 100644 index 00000000000000..6c511cfbb95554 Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/chill_mode_icon.png differ diff --git a/selfdrive/frogpilot/assets/other_images/compass_inner.png b/selfdrive/frogpilot/assets/other_images/compass_inner.png deleted file mode 100644 index d6517758c05e51..00000000000000 Binary files a/selfdrive/frogpilot/assets/other_images/compass_inner.png and /dev/null differ diff --git a/selfdrive/frogpilot/assets/other_images/curve_icon.png b/selfdrive/frogpilot/assets/other_images/curve_icon.png new file mode 100644 index 00000000000000..594fc03228484b Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/curve_icon.png differ diff --git a/selfdrive/frogpilot/assets/other_images/lead_icon.png b/selfdrive/frogpilot/assets/other_images/lead_icon.png new file mode 100644 index 00000000000000..4d691275cafa86 Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/lead_icon.png differ diff --git a/selfdrive/frogpilot/assets/other_images/light_icon.png b/selfdrive/frogpilot/assets/other_images/light_icon.png new file mode 100644 index 00000000000000..85c1c5e24bc964 Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/light_icon.png differ diff --git a/selfdrive/frogpilot/assets/other_images/speed_icon.png b/selfdrive/frogpilot/assets/other_images/speed_icon.png new file mode 100644 index 00000000000000..8c022fb60143b8 Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/speed_icon.png differ diff --git a/selfdrive/frogpilot/assets/other_images/turn_icon.png b/selfdrive/frogpilot/assets/other_images/turn_icon.png new file mode 100644 index 00000000000000..6b1377976d836d Binary files /dev/null and b/selfdrive/frogpilot/assets/other_images/turn_icon.png differ diff --git a/selfdrive/frogpilot/assets/theme_manager.py b/selfdrive/frogpilot/assets/theme_manager.py index 939736502fcb2e..a5e4c055275ab2 100644 --- a/selfdrive/frogpilot/assets/theme_manager.py +++ b/selfdrive/frogpilot/assets/theme_manager.py @@ -349,23 +349,23 @@ def validate_themes(self, downloadable_colors, downloadable_distance_icons, down if theme_name in {"none", "stock"}: continue + if theme_name.replace('_', ' ').split('.')[0].title() not in downloadable_list: + print(f" {theme_name} for {theme_component} is outdated. Deleting...") + delete_file(theme_path) + continue + if theme_component == "steering_wheels": matching_files = list(THEME_SAVE_PATH.joinpath(theme_component).glob(f"{theme_name}.*")) if not matching_files: - continue - theme_path = matching_files[0] + print(f" {theme_name} for {theme_component} not found. Downloading...") + self.download_theme(theme_component, theme_name, theme_param) + update_frogpilot_toggles() else: theme_path = THEME_SAVE_PATH / "theme_packs" / theme_name / theme_component - - if theme_name.replace('_', ' ').split('.')[0].title() not in downloadable_list: - print(f"{theme_name} for {theme_component} is outdated. Deleting...") - delete_file(theme_path) - continue - - if not theme_path.exists(): - print(f"{theme_name} for {theme_component} not found. Downloading...") - self.download_theme(theme_component, theme_name, theme_param) - update_frogpilot_toggles() + if not theme_path.exists(): + print(f" {theme_name} for {theme_component} not found. Downloading...") + self.download_theme(theme_component, theme_name, theme_param) + update_frogpilot_toggles() for dir_path in THEME_SAVE_PATH.glob('**/*'): if dir_path.is_dir() and not any(dir_path.iterdir()): @@ -375,6 +375,8 @@ def validate_themes(self, downloadable_colors, downloadable_distance_icons, down print(f"Deleting temp file: {dir_path}") dir_path.unlink() + print("Theme validation complete.") + def update_themes(self, frogpilot_toggles, boot_run=False): if self.downloading_theme: return diff --git a/selfdrive/frogpilot/controls/frogpilot_planner.py b/selfdrive/frogpilot/controls/frogpilot_planner.py index b1837188765af4..05a3c8ac159c13 100644 --- a/selfdrive/frogpilot/controls/frogpilot_planner.py +++ b/selfdrive/frogpilot/controls/frogpilot_planner.py @@ -81,15 +81,13 @@ def update(self, carControl, carState, controlsState, frogpilotCarControl, frogp self.road_curvature = calculate_road_curvature(modelData, v_ego) if not carState.standstill else 1 - self.tracking_lead = self.set_lead_status(frogpilotCarState, v_ego, frogpilot_toggles) + self.tracking_lead = self.set_lead_status(carState, v_lead) self.v_cruise = self.frogpilot_vcruise.update(carControl, carState, controlsState, frogpilotCarControl, frogpilotCarState, frogpilotNavigation, v_cruise, v_ego, frogpilot_toggles) - def set_lead_status(self, frogpilotCarState, v_ego, frogpilot_toggles): - distance_offset = frogpilot_toggles.increased_stopped_distance if not frogpilotCarState.trafficModeActive else 0 - + def set_lead_status(self, carState, v_lead): following_lead = self.lead_one.status - following_lead &= 1 < self.lead_one.dRel < self.model_length + STOP_DISTANCE + distance_offset - following_lead &= v_ego > CRUISING_SPEED or self.tracking_lead + following_lead &= self.lead_one.dRel < self.model_length + STOP_DISTANCE + following_lead &= not carState.standstill or self.tracking_lead self.tracking_lead_mac.add_data(following_lead) return self.tracking_lead_mac.get_moving_average() >= THRESHOLD @@ -110,10 +108,7 @@ def publish(self, sm, pm, theme_updated, toggles_updated, frogpilot_toggles): frogpilotPlan.vtscControllingCurve = bool(self.frogpilot_vcruise.mtsc_target > self.frogpilot_vcruise.vtsc_target) frogpilotPlan.vtscSpeed = float(self.frogpilot_vcruise.vtsc_target) - frogpilotPlan.desiredFollowDistance = self.frogpilot_following.safe_obstacle_distance - self.frogpilot_following.stopped_equivalence_factor - frogpilotPlan.safeObstacleDistance = self.frogpilot_following.safe_obstacle_distance - frogpilotPlan.safeObstacleDistanceStock = self.frogpilot_following.safe_obstacle_distance_stock - frogpilotPlan.stoppedEquivalenceFactor = self.frogpilot_following.stopped_equivalence_factor + frogpilotPlan.desiredFollowDistance = self.frogpilot_following.desired_follow_distance frogpilotPlan.experimentalMode = self.cem.experimental_mode or self.frogpilot_vcruise.slc.experimental_mode @@ -136,7 +131,7 @@ def publish(self, sm, pm, theme_updated, toggles_updated, frogpilot_toggles): frogpilotPlan.slcOverridden = bool(self.frogpilot_vcruise.override_slc) frogpilotPlan.slcOverriddenSpeed = float(self.frogpilot_vcruise.overridden_speed) frogpilotPlan.slcSpeedLimit = self.frogpilot_vcruise.slc_target - frogpilotPlan.slcSpeedLimitOffset = self.frogpilot_vcruise.slc.offset + frogpilotPlan.slcSpeedLimitOffset = self.frogpilot_vcruise.slc_offset frogpilotPlan.slcSpeedLimitSource = self.frogpilot_vcruise.slc.source frogpilotPlan.speedLimitChanged = self.frogpilot_vcruise.speed_limit_changed frogpilotPlan.unconfirmedSlcSpeedLimit = self.frogpilot_vcruise.slc.desired_speed_limit diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_events.py b/selfdrive/frogpilot/controls/lib/frogpilot_events.py index 481c69f1396e54..a3ab9da52545b7 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_events.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_events.py @@ -61,7 +61,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState self.stopped_for_light = False if not self.holiday_theme_played and frogpilot_toggles.current_holiday_theme != "stock" and self.frame >= 10: - #self.events.add(EventName.holidayActive) + self.events.add(EventName.holidayActive) self.holiday_theme_played = True if frogpilot_toggles.lead_departing_alert and self.frogpilot_planner.tracking_lead and carState.standstill: @@ -177,7 +177,7 @@ def update(self, carState, controlsState, frogpilotCarControl, frogpilotCarState self.random_event_played = True self.always_on_lateral_active_previously = frogpilotCarControl.alwaysOnLateralActive - if frogpilot_toggles.speed_limit_changed_alert and self.frogpilot_planner.frogpilot_vcruise.speed_limit_changed: + if frogpilot_toggles.speed_limit_changed_alert and self.frogpilot_planner.frogpilot_vcruise.speed_limit_changed and self.frogpilot_planner.frogpilot_vcruise.speed_limit_timer < 1: self.events.add(EventName.speedLimitChanged) if 5 > self.frame > 4 and params.get("NNFFModelName", encoding='utf-8') is not None: diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_following.py b/selfdrive/frogpilot/controls/lib/frogpilot_following.py index 2c1f8d16dc77b6..fc302cc5b24978 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_following.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_following.py @@ -1,5 +1,5 @@ from openpilot.common.numpy_fast import clip, interp -from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, get_jerk_factor, get_safe_obstacle_distance, get_stopped_equivalence_factor, get_T_FOLLOW +from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, desired_follow_distance, get_jerk_factor, get_T_FOLLOW from openpilot.selfdrive.frogpilot.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED @@ -16,10 +16,8 @@ def __init__(self, FrogPilotPlanner): self.base_acceleration_jerk = 0 self.base_speed_jerk = 0 self.danger_jerk = 0 - self.safe_obstacle_distance = 0 - self.safe_obstacle_distance_stock = 0 + self.desired_follow_distance = 0 self.speed_jerk = 0 - self.stopped_equivalence_factor = 0 self.t_follow = 0 def update(self, aEgo, controlsState, frogpilotCarState, lead_distance, v_ego, v_lead, frogpilot_toggles): @@ -63,14 +61,10 @@ def update(self, aEgo, controlsState, frogpilotCarState, lead_distance, v_ego, v self.following_lead = self.frogpilot_planner.tracking_lead and lead_distance < (self.t_follow + 1) * v_ego if self.frogpilot_planner.tracking_lead: - self.safe_obstacle_distance = int(get_safe_obstacle_distance(v_ego, self.t_follow)) - self.safe_obstacle_distance_stock = self.safe_obstacle_distance - self.stopped_equivalence_factor = int(get_stopped_equivalence_factor(v_lead)) self.update_follow_values(lead_distance, v_ego, v_lead, frogpilot_toggles) + self.desired_follow_distance = int(desired_follow_distance(v_ego, v_lead, self.t_follow)) else: - self.safe_obstacle_distance = 0 - self.safe_obstacle_distance_stock = 0 - self.stopped_equivalence_factor = 0 + self.desired_follow_distance = 0 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 diff --git a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py index 93e13199a4c5a4..0c269089cba572 100644 --- a/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py +++ b/selfdrive/frogpilot/controls/lib/frogpilot_vcruise.py @@ -28,6 +28,7 @@ def __init__(self, FrogPilotPlanner): self.overridden_speed = 0 self.override_force_stop_timer = 0 self.previous_speed_limit = 0 + self.slc_offset = 0 self.slc_target = 0 self.speed_limit_timer = 0 self.tracked_model_length = 0 @@ -80,48 +81,45 @@ def update(self, carControl, carState, controlsState, frogpilotCarControl, frogp 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 = abs(self.previous_speed_limit - unconfirmed_slc_target) > 1 and self.previous_speed_limit != 0 and unconfirmed_slc_target > 1 - - speed_limit_accepted = self.speed_limit_changed and (frogpilotCarControl.accelPressed and carControl.longActive or params_memory.get_bool("SLCConfirmed")) - speed_limit_denied = self.speed_limit_changed and (frogpilotCarControl.decelPressed and carControl.longActive or self.speed_limit_timer >= 30) - - speed_limit_decreased = self.speed_limit_changed and (self.slc_target - unconfirmed_slc_target) > 1 - speed_limit_increased = self.speed_limit_changed and (unconfirmed_slc_target - self.slc_target) > 1 - - if speed_limit_accepted: - self.previous_speed_limit = unconfirmed_slc_target - self.slc_target = unconfirmed_slc_target - self.speed_limit_changed = False - params_memory.remove("SLCConfirmed") - elif speed_limit_denied: - self.previous_speed_limit = unconfirmed_slc_target - self.speed_limit_changed = False - elif speed_limit_decreased and not frogpilot_toggles.speed_limit_confirmation_lower: - self.previous_speed_limit = unconfirmed_slc_target - self.slc_target = unconfirmed_slc_target - self.speed_limit_changed = False - elif speed_limit_increased and not frogpilot_toggles.speed_limit_confirmation_higher: - self.previous_speed_limit = unconfirmed_slc_target - self.slc_target = unconfirmed_slc_target - self.speed_limit_changed = False - - if self.speed_limit_changed: - self.speed_limit_timer += DT_MDL + speed_limit_difference = unconfirmed_slc_target - self.previous_speed_limit + + if abs(speed_limit_difference) > 1: + speed_limit_accepted = frogpilotCarControl.accelPressed and carControl.longActive or params_memory.get_bool("SpeedLimitAccepted") + speed_limit_denied = frogpilotCarControl.decelPressed and carControl.longActive or self.speed_limit_timer >= 30 + + if speed_limit_accepted: + self.previous_speed_limit = unconfirmed_slc_target + self.slc_target = unconfirmed_slc_target + params_memory.remove("SpeedLimitAccepted") + elif speed_limit_denied: + self.previous_speed_limit = unconfirmed_slc_target + elif speed_limit_difference < 0 and not frogpilot_toggles.speed_limit_confirmation_lower: + self.previous_speed_limit = unconfirmed_slc_target + self.slc_target = unconfirmed_slc_target + elif speed_limit_difference > 0 and not frogpilot_toggles.speed_limit_confirmation_higher: + self.previous_speed_limit = unconfirmed_slc_target + self.slc_target = unconfirmed_slc_target + else: + self.speed_limit_timer += DT_MDL + + self.speed_limit_changed = unconfirmed_slc_target != self.previous_speed_limit else: + self.speed_limit_changed = False self.speed_limit_timer = 0 else: + self.previous_speed_limit = unconfirmed_slc_target self.slc_target = unconfirmed_slc_target if frogpilot_toggles.speed_limit_controller: - self.override_slc = self.overridden_speed > self.slc_target - self.override_slc |= carState.gasPressed and v_ego > self.slc_target + self.override_slc = self.overridden_speed > self.slc_target + self.slc_offset + self.override_slc |= carState.gasPressed and v_ego > self.slc_target + self.slc_offset self.override_slc &= controlsState.enabled if self.override_slc: if frogpilot_toggles.speed_limit_controller_override_manual: if carState.gasPressed: self.overridden_speed = v_ego_cluster - self.overridden_speed = clip(self.overridden_speed, self.slc_target, v_cruise) + self.overridden_speed = clip(self.overridden_speed, self.slc_target + self.slc_offset, v_cruise_cluster) elif frogpilot_toggles.speed_limit_controller_override_set_speed: self.overridden_speed = v_cruise_cluster else: @@ -129,7 +127,10 @@ def update(self, carControl, carState, controlsState, frogpilotCarControl, frogp else: self.override_slc = False self.overridden_speed = 0 + + self.slc_offset = self.slc.get_offset(self.slc_target, frogpilot_toggles) else: + self.slc_offset = 0 self.slc_target = 0 # Pfeiferj's Vision Turn Controller @@ -157,7 +158,7 @@ def update(self, carControl, carState, controlsState, frogpilotCarControl, frogp self.tracked_model_length = self.frogpilot_planner.model_length if frogpilot_toggles.speed_limit_controller: - targets = [self.mtsc_target, max(self.overridden_speed, self.slc_target) - v_ego_diff, self.vtsc_target] + targets = [self.mtsc_target, max(self.overridden_speed, self.slc_target + self.slc_offset) - v_ego_diff, self.vtsc_target] else: targets = [self.mtsc_target, self.vtsc_target] v_cruise = float(min([target if target > CRUISING_SPEED else v_cruise for target in targets])) diff --git a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py index b2532bafb902e0..8effad99c6bf34 100644 --- a/selfdrive/frogpilot/controls/lib/speed_limit_controller.py +++ b/selfdrive/frogpilot/controls/lib/speed_limit_controller.py @@ -10,7 +10,6 @@ def __init__(self): self.desired_speed_limit = 0 self.map_speed_limit = 0 - self.offset = 0 self.speed_limit = 0 self.upcoming_speed_limit = 0 @@ -22,7 +21,6 @@ def update(self, dashboard_speed_limit, enabled, navigation_speed_limit, v_cruis self.update_map_speed_limit(v_ego, frogpilot_toggles) max_speed_limit = v_cruise if enabled else 0 - self.offset = self.get_offset(frogpilot_toggles) self.speed_limit = self.get_speed_limit(dashboard_speed_limit, max_speed_limit, navigation_speed_limit, frogpilot_toggles) self.desired_speed_limit = self.get_desired_speed_limit() @@ -30,25 +28,27 @@ def update(self, dashboard_speed_limit, enabled, navigation_speed_limit, v_cruis def get_desired_speed_limit(self): if self.speed_limit > 1: - if self.previous_speed_limit != self.speed_limit: + if abs(self.speed_limit - self.previous_speed_limit) > 1: params.put_float_nonblocking("PreviousSpeedLimit", self.speed_limit) self.previous_speed_limit = self.speed_limit - return self.speed_limit + self.offset - return 0 + return self.speed_limit + else: + return 0 def update_map_speed_limit(self, v_ego, frogpilot_toggles): self.map_speed_limit = params_memory.get_float("MapSpeedLimit") next_map_speed_limit = json.loads(params_memory.get("NextMapSpeedLimit", "{}")) - next_lat = next_map_speed_limit.get("latitude", 0) - next_lon = next_map_speed_limit.get("longitude", 0) self.upcoming_speed_limit = next_map_speed_limit.get("speedlimit", 0) - position = json.loads(params_memory.get("LastGPSPosition", "{}")) - latitude = position.get("latitude", 0) - longitude = position.get("longitude", 0) - if self.upcoming_speed_limit > 1: + position = json.loads(params_memory.get("LastGPSPosition", "{}")) + latitude = position.get("latitude", 0) + longitude = position.get("longitude", 0) + + next_lat = next_map_speed_limit.get("latitude", 0) + next_lon = next_map_speed_limit.get("longitude", 0) + distance = calculate_distance_to_point(latitude * TO_RADIANS, longitude * TO_RADIANS, next_lat * TO_RADIANS, next_lon * TO_RADIANS) if self.previous_speed_limit < self.upcoming_speed_limit: @@ -59,12 +59,12 @@ def update_map_speed_limit(self, v_ego, frogpilot_toggles): if distance < max_distance: self.map_speed_limit = self.upcoming_speed_limit - def get_offset(self, frogpilot_toggles): - if self.speed_limit < 13.5: + def get_offset(self, speed_limit, frogpilot_toggles): + if speed_limit < 13.5: return frogpilot_toggles.speed_limit_offset1 - if self.speed_limit < 24: + if speed_limit < 24: return frogpilot_toggles.speed_limit_offset2 - if self.speed_limit < 29: + if speed_limit < 29: return frogpilot_toggles.speed_limit_offset3 return frogpilot_toggles.speed_limit_offset4 @@ -100,7 +100,6 @@ def get_speed_limit(self, dashboard_speed_limit, max_speed_limit, navigation_spe return self.previous_speed_limit if frogpilot_toggles.slc_fallback_set_speed: - self.offset = 0 return max_speed_limit return 0 diff --git a/selfdrive/frogpilot/frogpilot_functions.py b/selfdrive/frogpilot/frogpilot_functions.py index 610718588ec846..906a932568dcec 100644 --- a/selfdrive/frogpilot/frogpilot_functions.py +++ b/selfdrive/frogpilot/frogpilot_functions.py @@ -20,84 +20,73 @@ from openpilot.selfdrive.frogpilot.frogpilot_variables import MODELS_PATH, THEME_SAVE_PATH, FrogPilotVariables, get_frogpilot_toggles, params def backup_directory(backup, destination, success_message, fail_message, minimum_backup_size=0, compressed=False): - if not compressed: - if destination.exists(): - print("Backup already exists. Aborting") - return - - destination.mkdir(parents=True, exist_ok=False) - - run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", str(destination)], success_message, fail_message) - print(f"Backup successfully created at {destination}") - - else: + if compressed: destination_compressed = destination.with_suffix(".tar.gz") - in_progress_compressed = destination_compressed.with_suffix(".tar.gz_in_progress") - if destination_compressed.exists(): print("Backup already exists. Aborting") return in_progress_destination = destination.parent / (destination.name + "_in_progress") - in_progress_destination.mkdir(parents=True, exist_ok=False) - - run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", str(in_progress_destination)], "", fail_message) + run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", in_progress_destination], "", fail_message) + in_progress_compressed = destination_compressed.with_suffix(".tar.gz_in_progress") with tarfile.open(in_progress_compressed, "w:gz") as tar: tar.add(in_progress_destination, arcname=destination.name) - run_cmd(["sudo", "rm", "-rf", str(in_progress_destination)], success_message, fail_message) + run_cmd(["sudo", "rm", "-rf", in_progress_destination], success_message, fail_message) in_progress_compressed.rename(destination_compressed) - print(f"Backup successfully compressed to {destination_compressed}") compressed_backup_size = destination_compressed.stat().st_size if minimum_backup_size == 0 or compressed_backup_size < minimum_backup_size: params.put_int("MinimumBackupSize", compressed_backup_size) + else: + if destination.exists(): + print("Backup already exists. Aborting") + return + + run_cmd(["sudo", "rsync", "-avq", f"{backup}/.", destination], success_message, fail_message) def cleanup_backups(directory, limit, success_message, fail_message, compressed=False): directory.mkdir(parents=True, exist_ok=True) + backups = sorted(directory.glob("*_auto*"), key=lambda x: x.stat().st_mtime, reverse=True) for backup in backups[:]: if backup.name.endswith("_in_progress") or backup.name.endswith("_in_progress.tar.gz"): - run_cmd(["sudo", "rm", "-rf", str(backup)], "", fail_message) + run_cmd(["sudo", "rm", "-rf", backup], "", fail_message) backups.remove(backup) for oldest_backup in backups[limit:]: if oldest_backup.is_dir(): - run_cmd(["sudo", "rm", "-rf", str(oldest_backup)], success_message, fail_message) + run_cmd(["sudo", "rm", "-rf", oldest_backup], success_message, fail_message) else: - run_cmd(["sudo", "rm", str(oldest_backup)], success_message, fail_message) + run_cmd(["sudo", "rm", oldest_backup], success_message, fail_message) def backup_frogpilot(build_metadata): backup_path = Path("/data/backups") maximum_backups = 5 - minimum_backup_size = params.get_int("MinimumBackupSize") - - cleanup_backups(backup_path, maximum_backups, f"Successfully cleaned up old FrogPilot backups", f"Failed to cleanup old FrogPilot backups", True) + cleanup_backups(backup_path, maximum_backups, "Successfully cleaned up old FrogPilot backups", "Failed to cleanup old FrogPilot backups", True) _, _, free = shutil.disk_usage(backup_path) - required_free_space = minimum_backup_size * maximum_backups - - if free > required_free_space: - branch = build_metadata.channel - commit = build_metadata.openpilot.git_commit_date[12:-16] - backup_dir = backup_path / f"{branch}_{commit}_auto" - backup_directory(Path(BASEDIR), backup_dir, f"Successfully backed up FrogPilot to {backup_dir}", f"Failed to backup FrogPilot to {backup_dir}", minimum_backup_size, compressed=True) + minimum_backup_size = params.get_int("MinimumBackupSize") + if free > minimum_backup_size * maximum_backups: + directory = Path(BASEDIR) + destination_directory = backup_path / f"{build_metadata.channel}_{build_metadata.openpilot.git_commit_date[12:-16]}_auto" + backup_directory(directory, destination_directory, f"Successfully backed up FrogPilot to {destination_directory}", f"Failed to backup FrogPilot to {destination_directory}", minimum_backup_size, compressed=True) def backup_toggles(params_storage): for key in params.all_keys(): - if params.get_key_type(key) & ParamKeyType.FROGPILOT_STORAGE: + if params.get_key_type(key) & ParamKeyType.PERSISTENT: value = params.get(key) if value is not None: params_storage.put(key, value) backup_path = Path("/data/toggle_backups") maximum_backups = 10 + cleanup_backups(backup_path, maximum_backups, "Successfully cleaned up old toggle backups", "Failed to cleanup old toggle backups") - cleanup_backups(backup_path, maximum_backups, f"Successfully cleaned up old toggle backups", f"Failed to cleanup old toggle backups") - - backup_dir = backup_path / f"{datetime.datetime.now().strftime('%Y-%m-%d_%I-%M%p').lower()}_auto" - backup_directory(Path("/data/params/d"), backup_dir, f"Successfully backed up toggles to {backup_dir}", f"Failed to backup toggles to {backup_dir}") + directory = Path("/data/params/d") + destination_directory = backup_path / f"{datetime.datetime.now().strftime('%Y-%m-%d_%I-%M%p').lower()}_auto" + backup_directory(directory, destination_directory, f"Successfully backed up toggles to {destination_directory}", f"Failed to backup toggles to {destination_directory}") def convert_params(params_storage): print("Starting to convert params") @@ -163,7 +152,6 @@ def frogpilot_boot_functions(build_metadata, params_storage): source = Path(THEME_SAVE_PATH) / "distance_icons" destination = Path(THEME_SAVE_PATH) / "theme_packs" - if source.exists(): for item in source.iterdir(): if item.is_dir(): @@ -191,8 +179,7 @@ def backup_thread(): print("Waiting for system time to become valid...") time.sleep(1) - if params.get("UpdaterAvailableBranches") is None: - subprocess.run(["pkill", "-SIGUSR1", "-f", "system.updated.updated"], check=False) + subprocess.run(["pkill", "-SIGUSR1", "-f", "system.updated.updated"], check=False) backup_frogpilot(build_metadata) backup_toggles(params_storage) diff --git a/selfdrive/frogpilot/frogpilot_process.py b/selfdrive/frogpilot/frogpilot_process.py index c6a54b7ead7c18..0ce462b7693778 100644 --- a/selfdrive/frogpilot/frogpilot_process.py +++ b/selfdrive/frogpilot/frogpilot_process.py @@ -1,4 +1,5 @@ import datetime +import json import subprocess import threading import time @@ -20,13 +21,14 @@ 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 +from openpilot.selfdrive.frogpilot.navigation.mapd import ensure_mapd_is_running, update_mapd locks = { "backup_toggles": threading.Lock(), "download_all_models": threading.Lock(), "download_model": threading.Lock(), "download_theme": threading.Lock(), + "ensure_mapd_is_running": threading.Lock(), "update_checks": threading.Lock(), "update_mapd": threading.Lock(), "update_models": threading.Lock(), @@ -44,12 +46,14 @@ def run_thread_with_lock(name, target, args=()): def automatic_update_check(): subprocess.run(["pkill", "-SIGUSR1", "-f", "system.updated.updated"], check=False) - while params.get("UpdaterState", encoding="utf8") != "idle": - time.sleep(60) + time.sleep(60) if not params.get_bool("UpdaterFetchAvailable"): return + while params.get("UpdaterState", encoding="utf8") != "idle": + time.sleep(60) + subprocess.run(["pkill", "-SIGHUP", "-f", "system.updated.updated"], check=False) while not params.get_bool("UpdateAvailable"): time.sleep(60) @@ -60,6 +64,8 @@ def automatic_update_check(): HARDWARE.reboot() def check_assets(model_manager, theme_manager, frogpilot_toggles): + run_thread_with_lock("ensure_mapd_is_running", ensure_mapd_is_running) + if params_memory.get_bool("DownloadAllModels"): run_thread_with_lock("download_all_models", model_manager.download_all_models) @@ -81,11 +87,11 @@ 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(model_manager, now, theme_manager, frogpilot_toggles): +def update_checks(manually_updated, model_manager, now, theme_manager, frogpilot_toggles): if not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")): return - if frogpilot_toggles.automatic_updates and not params_memory.get_bool("ManualUpdateInitiated"): + if frogpilot_toggles.automatic_updates and not manually_updated: automatic_update_check() update_maps(now) @@ -94,9 +100,11 @@ def update_checks(model_manager, now, theme_manager, frogpilot_toggles): run_thread_with_lock("update_models", model_manager.update_models) run_thread_with_lock("update_themes", theme_manager.update_themes, (frogpilot_toggles,)) + time.sleep(1) + def update_maps(now): - maps_selected = params.get("MapsSelected", encoding='utf8') - if maps_selected is None: + maps_selected = json.loads(params.get("MapsSelected", encoding='utf8')) + if not (maps_selected.get("nations") or maps_selected.get("states")): return day = now.day @@ -115,7 +123,7 @@ def update_maps(now): return if params.get("OSMDownloadProgress", encoding='utf-8') is None: - params_memory.put("OSMDownloadLocations", maps_selected) + params_memory.put("OSMDownloadLocations", json.dumps(maps_selected)) params.put("LastMapsUpdate", todays_date) def frogpilot_thread(): @@ -204,13 +212,15 @@ def frogpilot_thread(): else: assets_checked = False - run_update_checks |= params_memory.get_bool("ManualUpdateInitiated") + manually_updated = params_memory.get_bool("ManualUpdateInitiated") + + run_update_checks |= manually_updated run_update_checks |= now.second == 0 and (now.minute % 60 == 0 or frogpilot_toggles.frogs_go_moo) run_update_checks &= time_validated if run_update_checks: theme_updated = theme_manager.update_active_theme(time_validated, frogpilot_toggles) - run_thread_with_lock("update_checks", update_checks, (model_manager, now, theme_manager, frogpilot_toggles)) + run_thread_with_lock("update_checks", update_checks, (manually_updated, model_manager, now, theme_manager, frogpilot_toggles)) run_update_checks = False elif not time_validated: diff --git a/selfdrive/frogpilot/frogpilot_variables.py b/selfdrive/frogpilot/frogpilot_variables.py index cf1bd460cab8ff..30958d2cb9cec5 100644 --- a/selfdrive/frogpilot/frogpilot_variables.py +++ b/selfdrive/frogpilot/frogpilot_variables.py @@ -148,8 +148,6 @@ def update_frogpilot_toggles(): ("GoatScream", "0", 2), ("GreenLightAlert", "0", 0), ("HideAlerts", "0", 2), - ("HideAOLStatusBar", "0", 2), - ("HideCEMStatusBar", "0", 2), ("HideCSCUI", "0", 2), ("HideLeadMarker", "0", 2), ("HideMapIcon", "0", 2), @@ -248,6 +246,7 @@ def update_frogpilot_toggles(): ("SearchInput", "0", 0), ("SetSpeedLimit", "0", 2), ("SetSpeedOffset", "0", 2), + ("ShowCEMStatus", "1", 3), ("ShowCPU", "1", 3), ("ShowGPU", "0", 3), ("ShowIP", "0", 3), @@ -323,8 +322,10 @@ def update_frogpilot_toggles(): ] misc_tuning_levels: list[tuple[str, str | bytes, int]] = [ + ("DeveloperMetrics", "", 3), + ("DeveloperWidgets", "", 3), ("SLCPriority", "", 2), - ("SLCQOL", "", 2), + ("SLCQOL", "", 0), ("StartupAlert", "", 0) ] @@ -423,7 +424,6 @@ def update(self, holiday_theme, started): toggle.always_on_lateral_lkas = toggle.always_on_lateral_set and car_make != "subaru" and (params.get_bool("AlwaysOnLateralLKAS") if tuning_level >= level["AlwaysOnLateralLKAS"] else default.get_bool("AlwaysOnLateralLKAS")) toggle.always_on_lateral_main = toggle.always_on_lateral_set and (params.get_bool("AlwaysOnLateralMain") if tuning_level >= level["AlwaysOnLateralMain"] else default.get_bool("AlwaysOnLateralMain")) toggle.always_on_lateral_pause_speed = params.get_int("PauseAOLOnBrake") if toggle.always_on_lateral_set and tuning_level >= level["PauseAOLOnBrake"] else default.get_int("PauseAOLOnBrake") - toggle.always_on_lateral_status_bar = toggle.always_on_lateral_set and not (params.get_bool("HideAOLStatusBar") if tuning_level >= level["HideAOLStatusBar"] else default.get_bool("HideAOLStatusBar")) toggle.automatic_updates = params.get_bool("AutomaticUpdates") if tuning_level >= level["AutomaticUpdates"] else default.get_bool("AutomaticUpdates") @@ -444,7 +444,6 @@ def update(self, holiday_theme, started): toggle.conditional_model_stop_time = params.get_int("CEModelStopTime") if toggle.conditional_experimental_mode and tuning_level >= level["CEModelStopTime"] else default.get_int("CEModelStopTime") toggle.conditional_signal = params.get_int("CESignalSpeed") if toggle.conditional_experimental_mode and tuning_level >= level["CESignalSpeed"] else default.get_int("CESignalSpeed") toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and (params.get_bool("CESignalLaneDetection") if tuning_level >= level["CESignalLaneDetection"] else default.get_bool("CESignalLaneDetection")) - toggle.conditional_status_bar = toggle.conditional_experimental_mode and not (params.get_bool("HideCEMStatusBar") if tuning_level >= level["HideCEMStatusBar"] else default.get_bool("HideCEMStatusBar")) if toggle.conditional_experimental_mode: params.put_bool("ExperimentalMode", True) @@ -510,6 +509,7 @@ def update(self, holiday_theme, started): toggle.blind_spot_metrics = has_bsm and border_metrics and (params.get_bool("BlindSpotMetrics") if tuning_level >= level["BlindSpotMetrics"] else default.get_bool("BlindSpotMetrics")) toggle.signal_metrics = border_metrics and (params.get_bool("SignalMetrics") if tuning_level >= level["SignalMetrics"] else default.get_bool("SignalMetrics")) toggle.steering_metrics = border_metrics and (params.get_bool("ShowSteering") if tuning_level >= level["ShowSteering"] else default.get_bool("ShowSteering")) + toggle.cem_status = toggle.developer_ui and (params.get_bool("ShowCEMStatus") if tuning_level >= level["ShowCEMStatus"] else default.get_bool("ShowCEMStatus")) toggle.show_fps = toggle.developer_ui and (params.get_bool("FPSCounter") if tuning_level >= level["FPSCounter"] else default.get_bool("FPSCounter")) lateral_metrics = toggle.developer_ui and (params.get_bool("LateralMetrics") if tuning_level >= level["LateralMetrics"] else default.get_bool("LateralMetrics")) toggle.adjacent_path_metrics = lateral_metrics and (params.get_bool("AdjacentPathMetrics") if tuning_level >= level["AdjacentPathMetrics"] else default.get_bool("AdjacentPathMetrics")) @@ -620,7 +620,6 @@ def update(self, holiday_theme, started): toggle.full_map = toggle.big_map and (params.get_bool("FullMap") if tuning_level >= level["FullMap"] else default.get_bool("FullMap")) toggle.map_style = params.get_int("MapStyle") if toggle.navigation_ui and tuning_level >= level["MapStyle"] else default.get_int("MapStyle") toggle.road_name_ui = toggle.navigation_ui and (params.get_bool("RoadNameUI") if tuning_level >= level["RoadNameUI"] else default.get_bool("RoadNameUI")) - toggle.show_speed_limit_offset = toggle.navigation_ui and (params.get_bool("ShowSLCOffset") if tuning_level >= level["ShowSLCOffset"] else default.get_bool("ShowSLCOffset")) toggle.show_speed_limits = toggle.navigation_ui and (params.get_bool("ShowSpeedLimits") if tuning_level >= level["ShowSpeedLimits"] else default.get_bool("ShowSpeedLimits")) toggle.speed_limit_vienna = toggle.navigation_ui and (params.get_bool("UseVienna") if tuning_level >= level["UseVienna"] else default.get_bool("UseVienna")) @@ -676,6 +675,7 @@ def update(self, holiday_theme, started): toggle.map_speed_lookahead_higher = params.get_int("SLCLookaheadHigher") if toggle.speed_limit_controller and tuning_level >= level["SLCLookaheadHigher"] else default.get_int("SLCLookaheadHigher") toggle.map_speed_lookahead_lower = params.get_int("SLCLookaheadLower") if toggle.speed_limit_controller and tuning_level >= level["SLCLookaheadLower"] else default.get_int("SLCLookaheadLower") toggle.set_speed_limit = toggle.speed_limit_controller and (params.get_bool("SetSpeedLimit") if tuning_level >= level["SetSpeedLimit"] else default.get_bool("SetSpeedLimit")) + toggle.show_speed_limit_offset = toggle.speed_limit_controller and (params.get_bool("ShowSLCOffset") if tuning_level >= level["ShowSLCOffset"] else default.get_bool("ShowSLCOffset")) slc_fallback_method = params.get_int("SLCFallback") if toggle.speed_limit_controller and tuning_level >= level["SLCFallback"] else default.get_int("SLCFallback") toggle.slc_fallback_experimental_mode = slc_fallback_method == 1 toggle.slc_fallback_previous_speed_limit = slc_fallback_method == 2 diff --git a/selfdrive/frogpilot/navigation/mapd.py b/selfdrive/frogpilot/navigation/mapd.py index 32618e4cd6dd1f..20e31319038cc4 100644 --- a/selfdrive/frogpilot/navigation/mapd.py +++ b/selfdrive/frogpilot/navigation/mapd.py @@ -1,13 +1,12 @@ -# PFEIFER - MAPD - Modified by FrogAi for FrogPilot to automatically update +# PFEIFER - MAPD - Modified by FrogAi for FrogPilot import json import stat import subprocess -import time import urllib.request from pathlib import Path -VERSION = 'v1' +VERSION = "v1" GITHUB_VERSION_URL = f"https://github.com/FrogAi/FrogPilot-Resources/raw/Versions/mapd_version_{VERSION}.json" GITLAB_VERSION_URL = f"https://gitlab.com/FrogAi/FrogPilot-Resources/-/raw/Versions/mapd_version_{VERSION}.json" @@ -69,7 +68,7 @@ def update_mapd(): if installed_version != latest_version: print("New mapd version available, stopping the mapd process for update") try: - subprocess.run(["pkill", "-f", str(MAPD_PATH)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.run(["pkill", "-f", MAPD_PATH], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except Exception as error: print(f"Error stopping mapd process: {error}") @@ -81,15 +80,7 @@ def update_mapd(): print("Mapd is up to date") def ensure_mapd_is_running(): - while True: - try: - subprocess.run([str(MAPD_PATH)], check=True) - except Exception as error: - print(f"Error running mapd process: {error}") - time.sleep(60) - -def main(): - ensure_mapd_is_running() - -if __name__ == "__main__": - main() + try: + subprocess.run([MAPD_PATH], check=True) + except Exception as error: + print(f"Error running mapd process: {error}") diff --git a/selfdrive/frogpilot/navigation/ui/maps_settings.cc b/selfdrive/frogpilot/navigation/ui/maps_settings.cc index c67301cce57d64..7b829fb9d093a4 100644 --- a/selfdrive/frogpilot/navigation/ui/maps_settings.cc +++ b/selfdrive/frogpilot/navigation/ui/maps_settings.cc @@ -1,7 +1,5 @@ #include -#include -#include #include #include "selfdrive/frogpilot/navigation/ui/maps_settings.h" @@ -49,12 +47,9 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi QObject::connect(removeMapsButton, &ButtonControl::clicked, [this] { if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to delete all of your downloaded maps?"), this)) { std::thread([this] { - lastMapsDownload->setText("Never"); mapsSize->setText("0 MB"); std::system("rm -rf /data/media/0/osm/offline"); - - params.remove("LastMapsUpdate"); }).detach(); } }); @@ -99,8 +94,12 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi QObject::connect(parent, &FrogPilotSettingsWindow::closeMapSelection, [this]() { displayMapButtons(false); + countriesOpen = false; - mapsSelected = QString::fromStdString(params.get("MapsSelected")); + + mapsSelected = params.get("MapsSelected"); + hasMapsSelected = !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("nations").toArray().isEmpty(); + hasMapsSelected |= !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("states").toArray().isEmpty(); }); QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotMapsPanel::updateState); @@ -108,11 +107,14 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi } void FrogPilotMapsPanel::showEvent(QShowEvent *event) { - mapsSelected = QString::fromStdString(params.get("MapsSelected")); + mapsSelected = params.get("MapsSelected"); + hasMapsSelected = !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("nations").toArray().isEmpty(); + hasMapsSelected |= !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("states").toArray().isEmpty(); } void FrogPilotMapsPanel::hideEvent(QHideEvent *event) { displayMapButtons(false); + countriesOpen = false; } @@ -125,12 +127,13 @@ void FrogPilotMapsPanel::updateState(const UIState &s) { updateDownloadStatusLabels(); } - downloadMapsButton->setEnabled(!mapsSelected.isEmpty() && s.scene.online); + downloadMapsButton->setEnabled(hasMapsSelected && s.scene.online); } void FrogPilotMapsPanel::cancelDownload() { if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to cancel the download?"), this)) { std::system("pkill mapd"); + resetDownloadState(); } } @@ -152,7 +155,7 @@ void FrogPilotMapsPanel::downloadMaps() { int retryCount = 0; while (!isMapdRunning() && retryCount < 3) { retryCount++; - std::this_thread::sleep_for(std::chrono::seconds(1)); + util::sleep_for(1000); } if (retryCount >= 3) { @@ -160,7 +163,7 @@ void FrogPilotMapsPanel::downloadMaps() { return; } - params_memory.put("OSMDownloadLocations", params.get("MapsSelected")); + params_memory.put("OSMDownloadLocations", mapsSelected); downloadActive = true; @@ -168,14 +171,13 @@ void FrogPilotMapsPanel::downloadMaps() { } void FrogPilotMapsPanel::updateDownloadStatusLabels() { - static const std::regex fileStatuses(R"("total_files":(\d+),.*"downloaded_files":(\d+))"); + static std::regex fileStatuses(R"("total_files":(\d+),.*"downloaded_files":(\d+))"); static int previousDownloadedFiles = 0; static qint64 lastUpdatedTime = QDateTime::currentMSecsSinceEpoch(); static qint64 lastRemainingTime = 0; std::string osmDownloadProgress = params.get("OSMDownloadProgress"); std::smatch match; - if (!std::regex_search(osmDownloadProgress, match, fileStatuses)) { resetDownloadLabels(); return; @@ -244,7 +246,7 @@ void FrogPilotMapsPanel::handleDownloadError() { update(); - std::this_thread::sleep_for(std::chrono::seconds(3)); + util::sleep_for(3000); downloadStatus->setText(""); @@ -258,7 +260,7 @@ void FrogPilotMapsPanel::handleDownloadError() { void FrogPilotMapsPanel::finalizeDownload() { QString formattedDate = formatCurrentDate(); - params.putNonBlocking("LastMapsUpdate", formattedDate.toStdString()); + params.put("LastMapsUpdate", formattedDate.toStdString()); params.remove("OSMDownloadProgress"); mapsSize->setText(calculateDirectorySize(mapsFolderPath)); @@ -343,5 +345,6 @@ void FrogPilotMapsPanel::displayMapButtons(bool visible) { westLabel->setVisible(visible && !countriesOpen); setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/navigation/ui/maps_settings.h b/selfdrive/frogpilot/navigation/ui/maps_settings.h index ce0b524946745f..6556b51a0853a7 100644 --- a/selfdrive/frogpilot/navigation/ui/maps_settings.h +++ b/selfdrive/frogpilot/navigation/ui/maps_settings.h @@ -67,11 +67,13 @@ class FrogPilotMapsPanel : public FrogPilotListWidget { Params params; Params params_memory{"/dev/shm/params"}; + QString mapsFolderPath = "/data/media/0/osm/offline"; + bool countriesOpen; bool downloadActive; + bool hasMapsSelected; qint64 startTime; - QString mapsFolderPath = "/data/media/0/osm/offline"; - QString mapsSelected; + std::string mapsSelected; }; diff --git a/selfdrive/frogpilot/navigation/ui/navigation_functions.cc b/selfdrive/frogpilot/navigation/ui/navigation_functions.cc index 9d2802ff00f52b..b3ee544d5d69a4 100644 --- a/selfdrive/frogpilot/navigation/ui/navigation_functions.cc +++ b/selfdrive/frogpilot/navigation/ui/navigation_functions.cc @@ -1,86 +1,60 @@ -#include #include #include #include "selfdrive/frogpilot/navigation/ui/navigation_functions.h" -MapSelectionControl::MapSelectionControl(const QMap &map, bool isCountry, QWidget *parent) - : QWidget(parent), buttonGroup(new QButtonGroup(this)), gridLayout(new QGridLayout(this)), mapData(map), isCountry(isCountry) { - +MapSelectionControl::MapSelectionControl(const QMap &map, bool isCountry) + : buttonGroup(new QButtonGroup(this)), gridLayout(new QGridLayout(this)), mapData(map), isCountry(isCountry), selectionType(isCountry ? "nations" : "states") { buttonGroup->setExclusive(false); - const QList keys = mapData.keys(); + QList keys = mapData.keys(); for (int i = 0; i < keys.size(); ++i) { QPushButton *button = new QPushButton(mapData[keys[i]], this); + button->setCheckable(true); button->setStyleSheet(buttonStyle); button->setMinimumWidth(225); + gridLayout->addWidget(button, i / 3, i % 3); buttonGroup->addButton(button, i); + connect(button, &QPushButton::toggled, this, &MapSelectionControl::updateSelectedMaps); } + buttons = buttonGroup->buttons(); + + mapSelections = QJsonDocument::fromJson(QByteArray::fromStdString(params.get("MapsSelected"))).object()[selectionType].toArray(); + loadSelectedMaps(); } void MapSelectionControl::loadSelectedMaps() { - QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(params.get("MapsSelected"))); - if (!doc.isObject()) { - return; - } - - QJsonArray selectedArray = doc.object().value(isCountry ? "nations" : "states").toArray(); - QList buttons = buttonGroup->buttons(); - - for (int i = 0; i < selectedArray.size(); ++i) { - QString buttonLabel = mapData.value(selectedArray[i].toString()); - if (!buttonLabel.isEmpty()) { - for (int j = 0; j < buttons.size(); ++j) { - if (buttons[j]->text() == buttonLabel) { - buttons[j]->setChecked(true); - break; - } + for (int i = 0; i < mapSelections.size(); ++i) { + QString selectedKey = mapSelections[i].toString(); + for (int j = 0; j < buttons.size(); ++j) { + QAbstractButton *button = buttons[j]; + if (button->text() == mapData.value(selectedKey)) { + button->setChecked(true); + break; } } } } void MapSelectionControl::updateSelectedMaps() { - QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(params.get("MapsSelected"))); - QJsonObject selectionJson = doc.isObject() ? doc.object() : QJsonObject(); - - QString selectionType = isCountry ? "nations" : "states"; - QJsonArray existingSelections = selectionJson.value(selectionType).toArray(); - - QList buttons = buttonGroup->buttons(); - for (int i = 0; i < buttons.size(); ++i) { - QAbstractButton *button = buttons[i]; - QString code = mapData.key(button->text()); - - if (code.isEmpty()) { - continue; - } - - bool alreadySelected = false; - for (int j = 0; j < existingSelections.size(); ++j) { - if (existingSelections[j].toString() == code) { - alreadySelected = true; - break; - } - } - - if (button->isChecked() && !alreadySelected) { - existingSelections.append(code); - } else if (!button->isChecked() && alreadySelected) { - for (int j = 0; j < existingSelections.size(); ++j) { - if (existingSelections[j].toString() == code) { - existingSelections.removeAt(j); - break; + for (QAbstractButton *button : buttons) { + QString key = mapData.key(button->text()); + if (button->isChecked() && !mapSelections.contains(key)) { + mapSelections.append(key); + } else if (!button->isChecked()) { + for (int i = 0; i < mapSelections.size(); ++i) { + if (mapSelections[i].toString() == key) { + mapSelections.removeAt(i); + --i; } } } } - selectionJson[selectionType] = existingSelections; - params.put("MapsSelected", QString::fromUtf8(QJsonDocument(selectionJson).toJson(QJsonDocument::Compact)).toStdString()); + params.put("MapsSelected", QString::fromUtf8(QJsonDocument(QJsonObject{{selectionType, mapSelections}}).toJson(QJsonDocument::Compact)).toStdString()); } diff --git a/selfdrive/frogpilot/navigation/ui/navigation_functions.h b/selfdrive/frogpilot/navigation/ui/navigation_functions.h index 29ef0dc0ac1625..ce9cf1a781c04b 100644 --- a/selfdrive/frogpilot/navigation/ui/navigation_functions.h +++ b/selfdrive/frogpilot/navigation/ui/navigation_functions.h @@ -1,9 +1,9 @@ #pragma once #include -#include #include +#include #include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h" @@ -126,15 +126,15 @@ inline QMap southAmericaMap = { {"VE", "Venezuela"} }; -namespace fs = std::filesystem; - inline bool isMapdRunning() { return std::system("pgrep mapd > /dev/null 2>&1") == 0; } +namespace fs = std::filesystem; + inline QString calculateDirectorySize(const QString &directoryPath) { - constexpr uintmax_t oneGB = 1024 * 1024 * 1024; constexpr uintmax_t oneMB = 1024 * 1024; + constexpr uintmax_t oneGB = 1024 * 1024 * 1024; uintmax_t totalSize = 0; fs::path path(directoryPath.toStdString()); @@ -159,9 +159,9 @@ inline QString calculateDirectorySize(const QString &directoryPath) { inline QString formatCurrentDate() { QDate currentDate = QDate::currentDate(); - QString suffix; int day = currentDate.day(); + QString suffix; if (day % 10 == 1 && day != 11) { suffix = "st"; } else if (day % 10 == 2 && day != 12) { @@ -197,7 +197,7 @@ class MapSelectionControl : public QWidget { Q_OBJECT public: - MapSelectionControl(const QMap &map, bool isCountry = false, QWidget *parent = nullptr); + MapSelectionControl(const QMap &map, bool isCountry = false); private: void loadSelectedMaps(); @@ -209,7 +209,13 @@ class MapSelectionControl : public QWidget { QGridLayout *gridLayout; + QJsonArray mapSelections; + + QList buttons; + QMap mapData; + QString selectionType; + bool isCountry; }; diff --git a/selfdrive/frogpilot/navigation/ui/primeless_settings.cc b/selfdrive/frogpilot/navigation/ui/primeless_settings.cc index 5218500e67eed4..6e28dd1393c595 100644 --- a/selfdrive/frogpilot/navigation/ui/primeless_settings.cc +++ b/selfdrive/frogpilot/navigation/ui/primeless_settings.cc @@ -65,7 +65,7 @@ void FrogPilotPrimelessPanel::createMapboxKeyControl(ButtonControl *&control, co key = prefix + key; } if (key.length() >= 80) { - params.putNonBlocking(paramKey, key.toStdString()); + params.put(paramKey, key.toStdString()); } else { FrogPilotConfirmationDialog::toggleAlert(tr("Inputted key is invalid or too short!"), tr("Okay"), this); } @@ -105,12 +105,12 @@ void FrogPilotPrimelessPanel::displayMapboxInstructions(bool visible) { setupButton->setVisible(!visible); setUpdatesEnabled(true); + update(); } void FrogPilotPrimelessPanel::updateStep() { QString currentStep; - if (setupCompleted) { currentStep = "../frogpilot/navigation/navigation_training/setup_completed.png"; } else if (mapboxPublicKeySet && mapboxSecretKeySet) { @@ -123,7 +123,7 @@ void FrogPilotPrimelessPanel::updateStep() { QPixmap pixmap; pixmap.load(currentStep); - imageLabel->setPixmap(pixmap.scaledToWidth(1500, Qt::SmoothTransformation)); + update(); } diff --git a/selfdrive/frogpilot/screenrecorder/screenrecorder.cc b/selfdrive/frogpilot/screenrecorder/screenrecorder.cc index 8692ede6352eec..c427c899ad0a91 100644 --- a/selfdrive/frogpilot/screenrecorder/screenrecorder.cc +++ b/selfdrive/frogpilot/screenrecorder/screenrecorder.cc @@ -18,12 +18,8 @@ ScreenRecorder::ScreenRecorder(QWidget *parent) : QPushButton(parent) { setFixedSize(btn_size, btn_size); 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; - } + encoder = std::make_unique("/data/media/screen_recordings", screenWidth, screenHeight, UI_FREQ, 8 * 1024 * 1024); + encoderReady = true; }); encoderInitThread.detach(); @@ -58,14 +54,8 @@ void ScreenRecorder::startRecording() { } QString filename = QDateTime::currentDateTime().toString("MMMM_dd_yyyy-hh:mmAP") + ".mp4"; - try { - openEncoder(filename.toStdString()); - encodingThread = std::thread(&ScreenRecorder::encodingThreadFunction, this); - } catch (const std::exception &e) { - std::cerr << "Error starting encoder: " << e.what() << std::endl; - recording = false; - } - + openEncoder(filename.toStdString()); + encodingThread = std::thread(&ScreenRecorder::encodingThreadFunction, this); startedTime = currentMilliseconds(); } @@ -80,12 +70,7 @@ void ScreenRecorder::stopRecording() { encodingThread.join(); } - try { - closeEncoder(); - } catch (const std::exception &e) { - std::cerr << "Error stopping encoder: " << e.what() << std::endl; - } - + closeEncoder(); imageQueue.clear(); rgbScaleBuffer = std::make_unique(screenWidth * screenHeight * 4); } @@ -159,17 +144,14 @@ void ScreenRecorder::paintEvent(QPaintEvent *event) { if (recording) { painter.setPen(QPen(redColor(), 6)); painter.setBrush(redColor(166)); - painter.setFont(InterFont(25, QFont::Bold)); } else { painter.setPen(QPen(redColor(), 6)); painter.setBrush(blackColor(166)); - painter.setFont(InterFont(25, QFont::DemiBold)); } int centeringOffset = 10; - QRect buttonRect(centeringOffset, btn_size / 3, btn_size - centeringOffset * 2, btn_size / 3); painter.drawRoundedRect(buttonRect, 24, 24); diff --git a/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc index f7d7a532b3cadf..cdecb8e334c0b1 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/device_settings.cc @@ -120,6 +120,7 @@ void FrogPilotDevicePanel::showToggles(const std::set &keys) { } setUpdatesEnabled(true); + update(); } @@ -133,5 +134,6 @@ void FrogPilotDevicePanel::hideToggles() { } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc index 106a45068a3656..d2091b0abeae6c 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.cc @@ -105,6 +105,7 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram FrogPilotVisualsPanel *frogpilotVisualsPanel = new FrogPilotVisualsPanel(this); QObject::connect(frogpilotVisualsPanel, &FrogPilotVisualsPanel::openParentToggle, this, &FrogPilotSettingsWindow::openParentToggle); + QObject::connect(frogpilotVisualsPanel, &FrogPilotVisualsPanel::openSubParentToggle, this, &FrogPilotSettingsWindow::openSubParentToggle); std::vector>> panels = { {tr("Alerts and Sounds"), {frogpilotSoundsPanel}}, @@ -188,11 +189,11 @@ void FrogPilotSettingsWindow::updateVariables() { cereal::CarParams::SafetyModel safetyModel = CP.getSafetyConfigs()[0].getSafetyModel(); std::string carFingerprint = CP.getCarFingerprint(); - std::string carModel = CP.getCarName(); + std::string carMake = CP.getCarName(); - hasAutoTune = (carModel == "hyundai" || carModel == "toyota") && CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE; + hasAutoTune = (carMake == "hyundai" || carMake == "toyota") && CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE; hasBSM = CP.getEnableBsm(); - hasDashSpeedLimits = carModel == "hyundai" || carModel == "toyota"; + hasDashSpeedLimits = carMake == "hyundai" || carMake == "toyota"; hasExperimentalOpenpilotLongitudinal = CP.getExperimentalLongitudinalAvailable(); hasNNFFLog = checkNNFFLogFileExists(carFingerprint); hasOpenpilotLongitudinal = hasLongitudinalControl(CP); @@ -200,12 +201,13 @@ void FrogPilotSettingsWindow::updateVariables() { hasRadar = !CP.getRadarUnavailable(); hasSNG = CP.getMinEnableSpeed() <= 0; isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV"; - isGM = carModel == "gm"; - isHKGCanFd = carModel == "hyundai" && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD; + isGM = carMake == "gm"; + isHKG = carMake == "hyundai"; + isHKGCanFd = isHKG && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD; isImpreza = carFingerprint == "SUBARU_IMPREZA"; isPIDCar = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::PID; - isSubaru = carModel == "subaru"; - isToyota = carModel == "toyota"; + isSubaru = carMake == "subaru"; + isToyota = carMake == "toyota"; isVolt = carFingerprint == "CHEVROLET_VOLT"; forcingAutoTune = params.getBool("AdvancedLateralTune") && params.getBool("ForceAutoTune"); steerFrictionStock = CP.getLateralTuning().getTorque().getFriction(); diff --git a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h index e25be6554076a6..d6c7e6486c3bef 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/frogpilot_settings.h @@ -24,6 +24,7 @@ class FrogPilotSettingsWindow : public QFrame { bool hasSNG = false; bool isBolt = false; bool isGM = true; + bool isHKG = true; bool isHKGCanFd = true; bool isImpreza = true; bool isPIDCar = false; diff --git a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc index 2fa30b0e2ce7fb..d42b43353d71b6 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.cc @@ -14,7 +14,6 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : {"AlwaysOnLateralLKAS", tr("Control with LKAS Button"), tr("Controls the current state of 'Always on Lateral' with the 'LKAS' button."), ""}, {"AlwaysOnLateralMain", tr("Enable with Cruise Control"), tr("Activates 'Always on Lateral' whenever 'Cruise Control' is active bypassing the requirement to enable openpilot first."), ""}, {"PauseAOLOnBrake", tr("Pause on Brake Below"), tr("Pauses 'Always on Lateral' when the brake pedal is pressed below the set speed."), ""}, - {"HideAOLStatusBar", tr("Hide the Status Bar"), tr("Hides status bar for 'Always On Lateral'."), ""}, {"LaneChangeCustomizations", tr("Lane Change Settings"), tr("How openpilot handles lane changes."), "../frogpilot/assets/toggle_icons/icon_lane.png"}, {"NudgelessLaneChange", tr("Automatic Lane Changes"), tr("Conducts lane changes without needing to touch the steering wheel upon turn signal activation."), ""}, @@ -157,7 +156,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : QObject::connect(static_cast(toggles["AlwaysOnLateralLKAS"]), &ToggleControl::toggleFlipped, [this](bool state) { if (state && params.getBool("ExperimentalModeViaLKAS")) { - params.putBoolNonBlocking("ExperimentalModeViaLKAS", false); + params.putBool("ExperimentalModeViaLKAS", false); } }); @@ -166,11 +165,18 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : modifiedAdvancedLateralTuneKeys.erase("ForceAutoTuneOff"); - if (!hasAutoTune && state) { + if (state) { modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); modifiedAdvancedLateralTuneKeys.erase("SteerKP"); modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); modifiedAdvancedLateralTuneKeys.erase("SteerRatio"); + } else if (isPIDCar) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerKP"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); + } else if (!liveValid || hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF")) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); } showToggles(modifiedAdvancedLateralTuneKeys); @@ -181,11 +187,14 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : modifiedAdvancedLateralTuneKeys.erase("ForceAutoTune"); - if (hasAutoTune && !state) { + if (!state) { modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); modifiedAdvancedLateralTuneKeys.erase("SteerKP"); modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); modifiedAdvancedLateralTuneKeys.erase("SteerRatio"); + } else if (!liveValid || hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF")) { + modifiedAdvancedLateralTuneKeys.erase("SteerFriction"); + modifiedAdvancedLateralTuneKeys.erase("SteerLatAccel"); } showToggles(modifiedAdvancedLateralTuneKeys); @@ -206,7 +215,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) : std::set rebootKeys = {"AlwaysOnLateral", "NNFF", "NNFFLite"}; for (const QString &key : rebootKeys) { - QObject::connect(static_cast(toggles[key.toStdString().c_str()]), &ToggleControl::toggleFlipped, [this, key](bool state) { + QObject::connect(static_cast(toggles[key]), &ToggleControl::toggleFlipped, [this, key](bool state) { if (started) { if (key == "AlwaysOnLateral" && state) { if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) { @@ -325,9 +334,8 @@ void FrogPilotLateralPanel::showToggles(const std::set &keys) { toggle->setVisible(keys.find(key) != keys.end() && tuningLevel >= frogpilotToggleLevels[key].toDouble()); } - static_cast(toggles["AlwaysOnLateral"])->setVisibleButton(tuningLevel >= 1); - setUpdatesEnabled(true); + update(); } @@ -344,8 +352,13 @@ void FrogPilotLateralPanel::hideToggles() { toggle->setVisible(!subToggles && tuningLevel >= frogpilotToggleLevels[key].toDouble()); } - static_cast(toggles["AlwaysOnLateral"])->setVisibleButton(tuningLevel >= 1); + std::set toggleKeys = {"AlwaysOnLateral"}; + for (const QString &key : toggleKeys) { + FrogPilotParamManageControl *control = static_cast(toggles[key]); + control->setVisibleButton(tuningLevel > frogpilotToggleLevels[key].toDouble()); + } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h index 72fefb0762bc65..0d8c6cfd73683e 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/lateral_settings.h @@ -49,7 +49,7 @@ class FrogPilotLateralPanel : public FrogPilotListWidget { std::map toggles; std::set advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "SteerFriction", "SteerLatAccel", "SteerKP", "SteerRatio"}; - std::set aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "HideAOLStatusBar", "PauseAOLOnBrake"}; + std::set aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "PauseAOLOnBrake"}; std::set laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"}; std::set lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"}; std::set qolKeys = {"PauseLateralSpeed"}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc index f332f1c4817d39..1c54dc93270376 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.cc @@ -9,7 +9,6 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * {"CENavigation", tr("Navigation Data"), tr("Triggers 'Experimental Mode' based on navigation data, such as upcoming intersections or turns."), ""}, {"CEModelStopTime", tr("openpilot Wants to Stop In"), tr("Triggers 'Experimental Mode' when openpilot wants to stop such as for a stop sign or red light."), ""}, {"CESignalSpeed", tr("Turn Signal Below"), tr("Triggers 'Experimental Mode' when using turn signals below the set speed."), ""}, - {"HideCEMStatusBar", tr("Hide the Status Bar"), tr("Hides status bar for 'Conditional Experimental Mode'."), ""}, {"CurveSpeedControl", tr("Curve Speed Control"), tr("Automatically slow down for curves detected ahead or through the downloaded maps."), "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, {"CurveDetectionMethod", tr("Curve Detection Method"), tr("Uses data from either the downloaded maps or the model to determine where curves are."), ""}, @@ -80,10 +79,10 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * {"ReverseCruise", tr("Reverse Cruise Increase"), tr("Reverses the long press cruise increase feature to increase the max speed by 5 mph instead of 1 on short presses."), ""}, {"SpeedLimitController", tr("Speed Limit Controller"), tr("Automatically adjust your max speed to match the speed limit using downloaded 'Open Street Maps' data, 'Navigate on openpilot', or your car's dashboard (Toyota/Lexus/HKG only)."), "../assets/offroad/icon_speed_limit.png"}, - {"SLCConfirmation", tr("Confirm New Speed Limits"), tr("Enables manual confirmations before using a new speed limit."), ""}, {"SLCFallback", tr("Fallback Method"), tr("Controls what happens when no speed limit data is available."), ""}, {"SLCOverride", tr("Override Method"), tr("Controls how the current speed limit is overriden.\n\n"), ""}, {"SLCQOL", tr("Quality of Life Improvements"), tr("Miscellaneous 'Speed Limit Controller' focused features to improve your overall openpilot experience."), ""}, + {"SLCConfirmation", tr("Confirm New Speed Limits"), tr("Enables manual confirmations before using a new speed limit."), ""}, {"ForceMPHDashboard", tr("Force MPH Readings from Dashboard"), tr("Forces speed limit readings from the dashboard to MPH if it normally displays them in KPH."), ""}, {"SLCLookaheadHigher", tr("Prepare for Higher Speed Limits"), tr("Sets a lookahead value to prepare for upcoming higher speed limits when using downloaded map data."), ""}, {"SLCLookaheadLower", tr("Prepare for Lower Speed Limits"), tr("Sets a lookahead value to prepare for upcoming lower speed limits when using downloaded map data."), ""}, @@ -94,6 +93,8 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * {"Offset2", tr("Speed Limit Offset (35-54 mph)"), tr("Sets the speed limit offset for speeds between 35 and 54 mph."), ""}, {"Offset3", tr("Speed Limit Offset (55-64 mph)"), tr("Sets the speed limit offset for speeds between 55 and 64 mph."), ""}, {"Offset4", tr("Speed Limit Offset (65-99 mph)"), tr("Sets the speed limit offset for speeds between 65 and 99 mph."), ""}, + {"SLCVisuals", tr("Visuals"), tr("Visual 'Speed Limit Controller' features to improve your overall openpilot experience."), ""}, + {"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("Displays the speed limit offset separately in the onroad UI when using 'Speed Limit Controller'."), ""}, {"SpeedLimitSources", tr("Show Speed Limit Sources"), tr("Displays the speed limit sources in the onroad UI when using 'Speed Limit Controller'."), ""}, }; @@ -318,10 +319,6 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * showToggles(speedLimitControllerKeys); }); longitudinalToggle = speedLimitControllerToggle; - } else if (param == "SLCConfirmation") { - std::vector confirmationToggles{"SLCConfirmationLower", "SLCConfirmationHigher"}; - std::vector confirmationToggleNames{tr("Lower Limits"), tr("Higher Limits")}; - longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, confirmationToggles, confirmationToggleNames); } else if (param == "SLCFallback") { std::vector fallbackOptions{tr("Set Speed"), tr("Experimental Mode"), tr("Previous Limit")}; ButtonParamControl *fallbackSelection = new ButtonParamControl(param, title, desc, icon, fallbackOptions); @@ -394,6 +391,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * ButtonControl *manageSLCQOLBtn = new ButtonControl(title, tr("MANAGE"), desc); QObject::connect(manageSLCQOLBtn, &ButtonControl::clicked, [this]() { openSubParentToggle(); + std::set modifiedSpeedLimitControllerQOLKeys = speedLimitControllerQOLKeys; if (hasPCMCruise) { @@ -407,10 +405,21 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * showToggles(modifiedSpeedLimitControllerQOLKeys); }); longitudinalToggle = manageSLCQOLBtn; + } else if (param == "SLCConfirmation") { + std::vector confirmationToggles{"SLCConfirmationLower", "SLCConfirmationHigher"}; + std::vector confirmationToggleNames{tr("Lower Limits"), tr("Higher Limits")}; + longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, confirmationToggles, confirmationToggleNames); } else if (param == "SLCLookaheadHigher" || param == "SLCLookaheadLower") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 30, tr(" seconds")); } else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, -99, 99, tr("mph")); + } else if (param == "SLCVisuals") { + ButtonControl *manageSLCVisualsBtn = new ButtonControl(title, tr("MANAGE"), desc); + QObject::connect(manageSLCVisualsBtn, &ButtonControl::clicked, [this]() { + openSubParentToggle(); + showToggles(speedLimitControllerVisualKeys); + }); + longitudinalToggle = manageSLCVisualsBtn; } else { longitudinalToggle = new ParamControl(param, title, desc, icon); @@ -430,7 +439,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * QObject::connect(static_cast(toggles["ExperimentalModeViaLKAS"]), &ToggleControl::toggleFlipped, [this](bool state) { if (state && params.getBool("AlwaysOnLateralLKAS")) { - params.putBoolNonBlocking("AlwaysOnLateralLKAS", false); + params.putBool("AlwaysOnLateralLKAS", false); } }); @@ -637,9 +646,8 @@ void FrogPilotLongitudinalPanel::showToggles(const std::set &keys) { toggle->setVisible(keys.find(key) != keys.end() && tuningLevel >= frogpilotToggleLevels[key].toDouble()); } - static_cast(toggles["ConditionalExperimental"])->setVisibleButton(tuningLevel >= 1); - setUpdatesEnabled(true); + update(); } @@ -661,15 +669,21 @@ void FrogPilotLongitudinalPanel::hideToggles() { speedLimitControllerKeys.find(key) != speedLimitControllerKeys.end() || speedLimitControllerOffsetsKeys.find(key) != speedLimitControllerOffsetsKeys.end() || speedLimitControllerQOLKeys.find(key) != speedLimitControllerQOLKeys.end() || + speedLimitControllerVisualKeys.find(key) != speedLimitControllerVisualKeys.end() || standardPersonalityKeys.find(key) != standardPersonalityKeys.end() || trafficPersonalityKeys.find(key) != trafficPersonalityKeys.end(); toggle->setVisible(!subToggles && tuningLevel >= frogpilotToggleLevels[key].toDouble()); } - static_cast(toggles["ConditionalExperimental"])->setVisibleButton(tuningLevel >= 1); + std::set toggleKeys = {"ConditionalExperimental", "CurveSpeedControl"}; + for (const QString &key : toggleKeys) { + FrogPilotParamManageControl *control = static_cast(toggles[key]); + control->setVisibleButton(tuningLevel > frogpilotToggleLevels[key].toDouble()); + } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h index dc4955a881de69..410f966d27b4d3 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/longitudinal_settings.h @@ -45,16 +45,17 @@ class FrogPilotLongitudinalPanel : public FrogPilotListWidget { std::map toggles; std::set aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"}; - std::set conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "HideCEMStatusBar"}; + std::set conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed"}; std::set curveSpeedKeys = {"CurveDetectionMethod", "CurveSensitivity", "HideCSCUI", "MTSCCurvatureCheck", "TurnAggressiveness"}; std::set customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"}; std::set experimentalModeActivationKeys = {"ExperimentalModeViaDistance", "ExperimentalModeViaLKAS", "ExperimentalModeViaTap"}; std::set longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "MaxDesiredAcceleration", "TacoTune"}; std::set qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStandstill", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset"}; std::set relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"}; - std::set speedLimitControllerKeys = {"SLCConfirmation", "SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SpeedLimitSources"}; + std::set speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"}; std::set speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4"}; - std::set speedLimitControllerQOLKeys = {"ForceMPHDashboard", "SetSpeedLimit", "SLCLookaheadHigher", "SLCLookaheadLower"}; + std::set speedLimitControllerQOLKeys = {"ForceMPHDashboard", "SetSpeedLimit", "SLCConfirmation", "SLCLookaheadHigher", "SLCLookaheadLower"}; + std::set speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"}; std::set standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"}; std::set trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"}; }; diff --git a/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc index 0579331250194b..42d554ba07d20d 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/model_settings.cc @@ -161,6 +161,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog params_memory.put("ModelDownloadProgress", "Downloading..."); downloadModelBtn->setValue("Downloading..."); + + downloadModelBtn->setVisibleButton(1, false); } } } else if (id == 1) { @@ -175,6 +177,8 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog params_memory.put("ModelDownloadProgress", "Downloading..."); downloadModelBtn->setValue("Downloading..."); + + downloadModelBtn->setVisibleButton(0, false); } } }); @@ -339,7 +343,7 @@ void FrogPilotModelPanel::updateModelLabels() { int drives = modelData.value("Drives").toInt(0); int score = modelData.value("Score").toInt(0); - QString drivesDisplay = drives == 1 ? QString("%1 Drive") : drives > 0 ? QString("%1 Drives").arg(drives) : "N/A"; + QString drivesDisplay = drives == 1 ? QString("%1 Drive").arg(drives) : drives > 0 ? QString("%1 Drives").arg(drives) : "N/A"; QString scoreDisplay = score > 0 ? QString("Score: %1%").arg(score) : "N/A"; QString labelTitle = QStringLiteral("%1").arg(processModelName(modelName)); @@ -363,6 +367,7 @@ void FrogPilotModelPanel::showToggles(const std::set &keys) { } setUpdatesEnabled(true); + update(); } @@ -382,6 +387,7 @@ void FrogPilotModelPanel::hideToggles() { } setUpdatesEnabled(true); + update(); } @@ -399,5 +405,6 @@ void FrogPilotModelPanel::hideSubToggles() { } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc index 55c0674029b7a7..161e9517426bb4 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/sounds_settings.cc @@ -141,6 +141,7 @@ void FrogPilotSoundsPanel::showToggles(const std::set &keys) { } setUpdatesEnabled(true); + update(); } @@ -155,5 +156,6 @@ void FrogPilotSoundsPanel::hideToggles() { } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc index a54405366409ec..1a41f743af6d90 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/theme_settings.cc @@ -598,6 +598,7 @@ void FrogPilotThemesPanel::showToggles(const std::set &keys) { } setUpdatesEnabled(true); + update(); } @@ -611,5 +612,6 @@ void FrogPilotThemesPanel::hideToggles() { } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc index 8de6225ff27cf6..6f8abd3cd851ae 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc @@ -1,17 +1,17 @@ -#include #include #include #include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h" -QStringList getCarNames(const QString &carMake, QMap &carModels) { - static const QMap makeMap = { +QStringList getCarModels(const QString &carMake) { + static QMap makeMap = { {"acura", "honda"}, {"audi", "volkswagen"}, {"buick", "gm"}, {"cadillac", "gm"}, {"chevrolet", "gm"}, {"chrysler", "chrysler"}, + {"cupra", "volkswagen"}, {"dodge", "chrysler"}, {"ford", "ford"}, {"genesis", "hyundai"}, @@ -35,11 +35,9 @@ QStringList getCarNames(const QString &carMake, QMap &carModel {"volkswagen", "volkswagen"} }; - QString targetFolder = makeMap.value(carMake.toLower(), carMake); - QFile file(QString("../car/%1/values.py").arg(targetFolder)); QStringList names; - QSet uniqueNames; + QFile file(QString("../car/%1/values.py").arg(makeMap.value(carMake, carMake))); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return names; } @@ -47,29 +45,24 @@ QStringList getCarNames(const QString &carMake, QMap &carModel QString fileContent = QTextStream(&file).readAll(); file.close(); - fileContent.remove(QRegularExpression("#[^\n]*")); - fileContent.remove(QRegularExpression("footnotes=\\[[^\\]]*\\],\\s*")); + static QRegularExpression carClassRegex(R"(class CAR\(.*\):\n(\s+.*(\n|$))*)"); + QRegularExpressionMatch match = carClassRegex.match(fileContent); + fileContent = match.captured(0).trimmed(); - QRegularExpression carModelRegex(R"((\w+)\s*=\s*\w+\s*\(\s*\[([\s\S]*?)\]\s*,)"); - QRegularExpression carDocsRegex("CarDocs\\(\\s*\"([^\"]+)\"[^)]*\\)"); + fileContent.remove(QRegularExpression("#[^\n]*")); + fileContent.remove(QRegularExpression("footnotes\\s*=\\s*\\[.*?\\]")); + static QRegularExpression carModelRegex(R"((\w+)\s*=\s*\w+\s*\(\s*\[([\s\S]*?)\]\s*,)"); QRegularExpressionMatchIterator carModelIt = carModelRegex.globalMatch(fileContent); + while (carModelIt.hasNext()) { - QRegularExpressionMatch carModelMatch = carModelIt.next(); - QString platform = carModelMatch.captured(1); - QString platformSection = carModelMatch.captured(2); + static QRegularExpression carDocsRegex("CarDocs\\(\\s*\"([^\"]+)\"[^)]*\\)"); + QRegularExpressionMatchIterator carDocsIt = carDocsRegex.globalMatch(carModelIt.next().captured(2)); - QRegularExpressionMatchIterator carDocsIt = carDocsRegex.globalMatch(platformSection); while (carDocsIt.hasNext()) { QString carName = carDocsIt.next().captured(1); - - if (carName.contains(QRegularExpression("^[A-Za-z0-9 Å .()-]+$")) && carName.count(" ") >= 1) { - QStringList nameParts = carName.split(" "); - if (nameParts.contains(carMake, Qt::CaseInsensitive) && !uniqueNames.contains(carName)) { - uniqueNames.insert(carName); - names << carName; - carModels[carName] = platform; - } + if (carName.contains(carMake, Qt::CaseInsensitive)) { + names << carName; } } } @@ -80,16 +73,18 @@ QStringList getCarNames(const QString &carMake, QMap &carModel FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) { QStringList makes = { - "Acura", "Audi", "Buick", "Cadillac", "Chevrolet", "Chrysler", "Dodge", "Ford", "Genesis", - "GMC", "Holden", "Honda", "Hyundai", "Jeep", "Kia", "Lexus", "Lincoln", "MAN", "Mazda", - "Nissan", "Ram", "SEAT", "Å koda", "Subaru", "Tesla", "Toyota", "Volkswagen" + tr("Acura"), tr("Audi"), tr("Buick"), tr("Cadillac"), tr("Chevrolet"), tr("Chrysler"), + tr("CUPRA"), tr("Dodge"), tr("Ford"), tr("Genesis"), tr("GMC"), tr("Holden"), tr("Honda"), + tr("Hyundai"), tr("Jeep"), tr("Kia"), tr("Lexus"), tr("Lincoln"), tr("MAN"), tr("Mazda"), + tr("Nissan"), tr("Ram"), tr("SEAT"), tr("Å koda"), tr("Subaru"), tr("Tesla"), tr("Toyota"), + tr("Volkswagen") }; selectMakeButton = new ButtonControl(tr("Select Make"), tr("SELECT")); QObject::connect(selectMakeButton, &ButtonControl::clicked, [this, makes]() { QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, "", this); if (!newMakeSelection.isEmpty()) { carMake = newMakeSelection; - params.putNonBlocking("CarMake", carMake.toStdString()); + params.put("CarMake", carMake.toStdString()); selectMakeButton->setValue(newMakeSelection); setModels(); } @@ -98,12 +93,12 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) selectModelButton = new ButtonControl(tr("Select Model"), tr("SELECT")); QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() { - QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, "", this); + QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), carModels, "", this); if (!newModelSelection.isEmpty()) { carModel = newModelSelection; - QString modelIdentifier = carModels.value(newModelSelection); - params.putNonBlocking("CarModel", modelIdentifier.toStdString()); - params.putNonBlocking("CarModelName", newModelSelection.toStdString()); + QString modelIdentifier = newModelSelection; + params.put("CarModel", modelIdentifier.toStdString()); + params.put("CarModelName", newModelSelection.toStdString()); selectModelButton->setValue(newModelSelection); } }); @@ -118,7 +113,9 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) QObject::connect(disableOpenpilotLong, &ToggleControl::toggleFlipped, [this, parent](bool state) { if (state) { if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely disable openpilot longitudinal control?"), this)) { - params.putBool("DisableOpenpilotLongitudinal", state); + disableOpenpilotLongitudinal = true; + params.putBool("DisableOpenpilotLongitudinal", true); + if (started) { if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) { Hardware::reboot(); @@ -128,27 +125,27 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) disableOpenpilotLong->refresh(); } } else { - params.putBool("DisableOpenpilotLongitudinal", state); + disableOpenpilotLongitudinal = false; + params.putBool("DisableOpenpilotLongitudinal", false); } - disableOpenpilotLongitudinal = state; parent->updateVariables(); }); addItem(disableOpenpilotLong); std::vector> vehicleToggles { - {"VoltSNG", tr("2017 Volt Stop and Go Hack"), tr("Forces stop and go for the 2017 Chevy Volt."), ""}, - {"ExperimentalGMTune", tr("Experimental GM Tune"), tr("Enables FrogsGoMoo's experimental GM tune that is based on nothing but guesswork. Use at your own risk!"), ""}, - {"LongPitch", tr("Uphill/Downhill Smoothing"), tr("Smoothens the gas and brake response when driving on slopes."), ""}, - {"NewLongAPIGM", tr("Use comma's New Longitudinal API"), tr("Enables comma's new control system that has shown great improvement with acceleration and braking, but has a few issues on some GM vehicles."), ""}, + {"VoltSNG", tr("2017 Volt Stop and Go Hack"), tr("Force stop and go for the 2017 Chevy Volt."), ""}, + {"LongPitch", tr("Downhill/Uphill Smoothing"), tr("Smoothen the gas and brake response when driving downhill or uphill."), ""}, + {"ExperimentalGMTune", tr("Experimental GM Longitudinal Tune"), tr("Enable FrogsGoMoo's experimental GM longitudinal tune that is based on nothing but guesswork. Use at your own risk!"), ""}, + {"NewLongAPIGM", tr("Use comma's New Longitudinal API"), tr("Enable comma's new control system that has shown great improvement with acceleration and braking, but has issues on some GM vehicles."), ""}, - {"NewLongAPI", tr("Use comma's New Longitudinal API"), tr("Enables comma's new control system that has shown great improvement with acceleration and braking, but has a few issues on Hyundai/Kia/Genesis."), ""}, + {"NewLongAPI", tr("Use comma's New Longitudinal API"), tr("Enable comma's new control system that has shown great improvement with acceleration and braking, but has issues on some Hyundai/Kia/Genesis vehicles."), ""}, - {"CrosstrekTorque", tr("Subaru Crosstrek Torque Increase"), tr("Increases the maximum allowed torque for the Subaru Crosstrek."), ""}, + {"CrosstrekTorque", tr("Subaru Crosstrek Torque Increase"), tr("Increase the maximum allowed torque for the 'Subaru Crosstrek'."), ""}, - {"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("Automatically locks the doors when in drive and unlocks when in park."), ""}, - {"ClusterOffset", tr("Cluster Speed Offset"), tr("Sets the cluster offset openpilot uses to try and match the speed displayed on the dash."), ""}, - {"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("Enables FrogsGoMoo's personal tweaks to the Toyota tune focused around his 2019 Lexus ES 350 to take off a bit quicker and stop a bit smoother."), ""}, - {"SNGHack", tr("Stop and Go Hack"), tr("Forces stop and go for vehicles without stock stop and go functionality."), ""}, + {"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("Automatically lock the doors when in drive and unlock when in park."), ""}, + {"ClusterOffset", tr("Cluster Speed Offset"), tr("Set the cluster offset openpilot uses to try and match the speed displayed on the dash."), ""}, + {"FrogsGoMoosTweak", tr("FrogsGoMoo's Personal Tweaks"), tr("FrogsGoMoo's personal tweaks to the Toyota/Lexus tune that allows the vehicle to take off and stop a bit smoother."), ""}, + {"SNGHack", tr("Stop and Go Hack"), tr("Force stop and go for vehicles without stop and go functionality."), ""}, }; for (const auto &[param, title, desc, icon] : vehicleToggles) { @@ -160,13 +157,17 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) vehicleToggle = new FrogPilotButtonToggleControl(param, title, desc, lockToggles, lockToggleNames); } else if (param == "ClusterOffset") { std::vector clusterOffsetButton{"Reset"}; - vehicleToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map(), 0.001, {}, clusterOffsetButton, false, false); + FrogPilotParamValueButtonControl *clusterOffsetToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 1.000, 1.050, "x", std::map(), 0.001, {}, clusterOffsetButton, false, false); + QObject::connect(clusterOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [=]() { + params.putFloat("ClusterOffset", params_default.getFloat("ClusterOffset")); + clusterOffsetToggle->refresh(); + }); + vehicleToggle = clusterOffsetToggle; } else { vehicleToggle = new ParamControl(param, title, desc, icon); } - vehicleToggle->setVisible(false); addItem(vehicleToggle); toggles[param] = vehicleToggle; @@ -175,12 +176,6 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent) }); } - FrogPilotParamValueButtonControl *clusterOffsetToggle = static_cast(toggles["ClusterOffset"]); - QObject::connect(clusterOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [=]() { - params.putFloat("ClusterOffset", params_default.getFloat("ClusterOffset")); - clusterOffsetToggle->refresh(); - }); - std::set rebootKeys = {"CrosstrekTorque", "ExperimentalGMTune", "FrogsGoMoosTweak", "NewLongAPI", "NewLongAPIGM"}; for (const QString &key : rebootKeys) { QObject::connect(static_cast(toggles[key]), &ToggleControl::toggleFlipped, [this]() { @@ -219,7 +214,11 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) { hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal; hasSNG = parent->hasSNG; isBolt = parent->isBolt; + isGM = parent->isGM; + isHKG = parent->isHKG; isImpreza = parent->isImpreza; + isSubaru = parent->isSubaru; + isToyota = parent->isToyota; isVolt = parent->isVolt; tuningLevel = parent->tuningLevel; @@ -235,58 +234,55 @@ void FrogPilotVehiclesPanel::updateState(const UIState &s) { } void FrogPilotVehiclesPanel::setModels() { - models = getCarNames(carMake.toLower(), carModels); + carModels = getCarModels(carMake.toLower()); updateToggles(); } void FrogPilotVehiclesPanel::updateToggles() { setUpdatesEnabled(false); - disableOpenpilotLong->setVisible(hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && tuningLevel >= frogpilotToggleLevels["DisableOpenpilotLongitudinal"].toDouble()); - disableOpenpilotLong->setVisible(disableOpenpilotLong->isVisible() || disableOpenpilotLongitudinal); + disableOpenpilotLong->setVisible(hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && tuningLevel >= frogpilotToggleLevels["DisableOpenpilotLongitudinal"].toDouble() || disableOpenpilotLongitudinal); forceFingerprint ->setVisible(tuningLevel >= frogpilotToggleLevels["ForceFingerprint"].toDouble() || isBolt); selectMakeButton->setValue(carMake); selectModelButton->setValue(carModel); selectModelButton->setVisible(!carMake.isEmpty()); - bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; - bool hyundai = carMake == "Genesis" || carMake == "Hyundai" || carMake == "Kia"; - bool subaru = carMake == "Subaru"; - bool toyota = carMake == "Lexus" || carMake == "Toyota"; - for (auto &[key, toggle] : toggles) { bool setVisible = false; - if (gm && gmKeys.find(key) != gmKeys.end()) { + if (isGM && gmKeys.find(key) != gmKeys.end()) { + setVisible = true; + + if (longitudinalKeys.find(key) != longitudinalKeys.end()) { + setVisible &= hasOpenpilotLongitudinal; + } if (voltKeys.find(key) != voltKeys.end()) { - setVisible = isVolt && hasOpenpilotLongitudinal; - } else if (longitudinalKeys.find(key) != longitudinalKeys.end()) { - setVisible = hasOpenpilotLongitudinal; - } else { - setVisible = true; + setVisible &= isVolt; } - } else if (hyundai && hyundaiKeys.find(key) != hyundaiKeys.end()) { + } else if (isHKG && hyundaiKeys.find(key) != hyundaiKeys.end()) { + setVisible = true; + if (longitudinalKeys.find(key) != longitudinalKeys.end()) { - setVisible = hasOpenpilotLongitudinal; - } else { - setVisible = true; + setVisible &= hasOpenpilotLongitudinal; } - } else if (subaru && subaruKeys.find(key) != subaruKeys.end()) { + } else if (isSubaru && subaruKeys.find(key) != subaruKeys.end()) { + setVisible = true; + if (imprezaKeys.find(key) != imprezaKeys.end()) { - setVisible = isImpreza; - } else if (longitudinalKeys.find(key) != longitudinalKeys.end()) { - setVisible = hasOpenpilotLongitudinal; - } else { - setVisible = true; + setVisible &= isImpreza; + } + if (longitudinalKeys.find(key) != longitudinalKeys.end()) { + setVisible &= hasOpenpilotLongitudinal; + } + } else if (isToyota && toyotaKeys.find(key) != toyotaKeys.end()) { + setVisible = true; + + if (longitudinalKeys.find(key) != longitudinalKeys.end()) { + setVisible &= hasOpenpilotLongitudinal; } - } else if (toyota && toyotaKeys.find(key) != toyotaKeys.end()) { if (sngKeys.find(key) != sngKeys.end()) { - setVisible = !hasSNG && hasOpenpilotLongitudinal; - } else if (longitudinalKeys.find(key) != longitudinalKeys.end()) { - setVisible = hasOpenpilotLongitudinal; - } else { - setVisible = true; + setVisible &= !hasSNG; } } @@ -294,5 +290,6 @@ void FrogPilotVehiclesPanel::updateToggles() { } setUpdatesEnabled(true); + update(); } diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h index 989a0481d2f6a9..fea584c7463576 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h @@ -23,12 +23,10 @@ class FrogPilotVehiclesPanel : public FrogPilotListWidget { QJsonObject frogpilotToggleLevels; - QMap carModels; - QString carMake; QString carModel; - QStringList models; + QStringList carModels; ParamControl *forceFingerprint; @@ -42,7 +40,11 @@ class FrogPilotVehiclesPanel : public FrogPilotListWidget { bool hasOpenpilotLongitudinal; bool hasSNG; bool isBolt; + bool isGM; + bool isHKG; bool isImpreza; + bool isSubaru; + bool isToyota; bool isVolt; bool started; diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc index cee6c74d8bf7ac..c8c59f7775207d 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc @@ -18,7 +18,8 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : {"HideSpeedLimit", tr("Hide Speed Limits"), tr("Hides the speed limits."), ""}, {"WheelSpeed", tr("Use Wheel Speed"), tr("Uses the wheel speed instead of the cluster speed. This is purely a visual change and doesn't impact how openpilot drives."), ""}, - {"DeveloperUI", tr("Developer Metrics"), tr("Show detailed information about openpilot's internal operations."), "../assets/offroad/icon_shell.png"}, + {"DeveloperUI", tr("Developer UI"), tr("Show detailed information about openpilot's internal operations."), "../assets/offroad/icon_shell.png"}, + {"DeveloperMetrics", tr("Developer Metrics"), tr("Show detailed information about openpilot's internal operations."), ""}, {"BorderMetrics", tr("Border Metrics"), tr("Displays performance metrics around the edge of the screen while driving."), ""}, {"FPSCounter", tr("FPS Display"), tr("Displays the 'Frames Per Second' (FPS) at the bottom of the screen while driving."), ""}, {"LateralMetrics", tr("Lateral Metrics"), tr("Displays metrics related to steering control at the top of the screen while driving."), ""}, @@ -26,6 +27,9 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : {"NumericalTemp", tr("Numerical Temperature Gauge"), tr("Shows exact temperature readings instead of status labels like 'GOOD', 'OK', or 'HIGH' in the sidebar."), ""}, {"SidebarMetrics", tr("Sidebar"), tr("Displays system information like CPU, GPU, RAM usage, IP address, and storage space in the sidebar."), ""}, {"UseSI", tr("Use International System of Units"), tr("Displays measurements using the 'International System of Units' (SI)."), ""}, + {"DeveloperWidgets", tr("Developer Widgets"), tr("Show detailed information about openpilot's internal operations."), ""}, + {"ShowCEMStatus", tr("'Conditional Experimental Mode' Status"), tr("Show 'Conditional Experimental Mode''s current status in the onroad UI."), ""}, + {"ShowStoppingPoint", tr("Model Stopping Point"), tr("Displays an image on the screen where openpilot is wanting to stop."), ""}, {"ModelUI", tr("Model UI"), tr("Customize the model visualizations on the screen."), "../frogpilot/assets/toggle_icons/icon_vtc.png"}, {"DynamicPathWidth", tr("Dynamic Path Width"), tr("Automatically adjusts the width of the driving path display based on the current engagement state:\n\nFully engaged = 100%\nAlways On Lateral Active = 75%\nFully disengaged = 50%"), ""}, @@ -33,14 +37,12 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : {"PathEdgeWidth", tr("Path Edges Width"), tr("Controls the width of the edges of the driving path to represent different modes and statuses.\n\nDefault is 20% of the total path width.\n\nColor Guide:\n- Blue: Navigation\n- Light Blue: 'Always On Lateral'\n- Green: Default\n- Orange: 'Experimental Mode'\n- Red: 'Traffic Mode'\n- Yellow: 'Conditional Experimental Mode' Overridden"), ""}, {"PathWidth", tr("Path Width"), tr("Controls how wide the driving path appears on your screen.\n\nDefault (6.1 feet / 1.9 meters) matches the width of a 2019 Lexus ES 350."), ""}, {"RoadEdgesWidth", tr("Road Edges Width"), tr("Controls how thick the road edges appear on the display.\n\nDefault matches half of the MUTCD standard lane line width of 4 inches."), ""}, - {"ShowStoppingPoint", tr("Stopping Point"), tr("Displays an image on the screen where openpilot is detecting a potential red light/stop sign."), ""}, {"UnlimitedLength", tr("'Unlimited' Road UI"), tr("Extends the display of the path, lane lines, and road edges as far as the model can see."), ""}, {"NavigationUI", tr("Navigation Widgets"), tr("Wwidgets focused around navigation."), "../frogpilot/assets/toggle_icons/icon_map.png"}, {"BigMap", tr("Larger Map Display"), tr("Increases the size of the map for easier navigation readings."), ""}, {"MapStyle", tr("Map Style"), tr("Swaps out the stock map style for community created ones."), ""}, {"RoadNameUI", tr("Road Name"), tr("Displays the current road name at the bottom of the screen using data from 'OpenStreetMap'."), ""}, - {"ShowSLCOffset", tr("Show Speed Limit Offset"), tr("Displays the speed limit offset separately in the onroad UI when using 'Speed Limit Controller'."), ""}, {"ShowSpeedLimits", tr("Show Speed Limits"), tr("Displays the currently detected speed limit in the top left corner of the onroad UI. Uses data from your car's dashboard (if supported) and data from 'OpenStreetMaps'."), ""}, {"UseVienna", tr("Use Vienna-Style Speed Signs"), tr("Forces Vienna-style (EU) speed limit signs instead of MUTCD (US)."), ""}, @@ -89,19 +91,29 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : } else if (param == "DeveloperUI") { FrogPilotParamManageControl *developerUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(developerUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + showToggles(developerUIKeys); + }); + visualToggle = developerUIToggle; + } else if (param == "DeveloperMetrics") { + ButtonControl *developerMetricsToggle = new ButtonControl(title, tr("MANAGE"), desc); + QObject::connect(developerMetricsToggle, &ButtonControl::clicked, [this]() { + developerUIOpen = true; + + openSubParentToggle(); + borderMetricsBtn->setVisibleButton(0, hasBSM); lateralMetricsBtn->setVisibleButton(1, hasAutoTune); longitudinalMetricsBtn->setVisibleButton(0, hasRadar); - std::set modifiedDeveloperUIKeys = developerUIKeys; + std::set modifiedDeveloperMetricKeys = developerMetricKeys; if (!hasOpenpilotLongitudinal) { - modifiedDeveloperUIKeys.erase("LongitudinalMetrics"); + modifiedDeveloperMetricKeys.erase("LongitudinalMetrics"); } - showToggles(modifiedDeveloperUIKeys); + showToggles(modifiedDeveloperMetricKeys); }); - visualToggle = developerUIToggle; + visualToggle = developerMetricsToggle; } else if (param == "BorderMetrics") { std::vector borderToggles{"BlindSpotMetrics", "ShowSteering", "SignalMetrics"}; std::vector borderToggleNames{tr("Blind Spot"), tr("Steering Torque"), tr("Turn Signal")}; @@ -143,17 +155,31 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : sidebarMetricsToggle->refresh(); }); visualToggle = sidebarMetricsToggle; + } else if (param == "DeveloperWidgets") { + ButtonControl *developerWidgetsToggle = new ButtonControl(title, tr("MANAGE"), desc); + QObject::connect(developerWidgetsToggle, &ButtonControl::clicked, [this]() { + developerUIOpen = true; - } else if (param == "ModelUI") { - FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); - QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { - std::set modifiedModelUIKeys = modelUIKeys; + openSubParentToggle(); + + std::set modifiedDeveloperWidgetKeys = developerWidgetKeys; if (!hasOpenpilotLongitudinal) { - modifiedModelUIKeys.erase("ShowStoppingPoint"); + modifiedDeveloperWidgetKeys.erase("ShowStoppingPoint"); } - showToggles(modifiedModelUIKeys); + showToggles(modifiedDeveloperWidgetKeys); + }); + visualToggle = developerWidgetsToggle; + } else if (param == "ShowStoppingPoint") { + std::vector stoppingPointToggles{"ShowStoppingPointMetrics"}; + std::vector stoppingPointToggleNames{tr("Show Distance")}; + visualToggle = new FrogPilotButtonToggleControl(param, title, desc, stoppingPointToggles, stoppingPointToggleNames); + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { + showToggles(modelUIKeys); }); visualToggle = modelUIToggle; } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { @@ -162,19 +188,13 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : visualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, tr("%")); } else if (param == "PathWidth") { visualToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet"), std::map(), 0.1); - } else if (param == "ShowStoppingPoint") { - std::vector stoppingPointToggles{"ShowStoppingPointMetrics"}; - std::vector stoppingPointToggleNames{tr("Show Distance")}; - visualToggle = new FrogPilotButtonToggleControl(param, title, desc, stoppingPointToggles, stoppingPointToggleNames); } else if (param == "NavigationUI") { FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon); QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, [this]() { std::set modifiedNavigationUIKeys = navigationUIKeys; - if (!hasOpenpilotLongitudinal || !params.getBool("SpeedLimitController")) { - modifiedNavigationUIKeys.erase("ShowSLCOffset"); - } else if (params.getBool("SpeedLimitController")) { + if (params.getBool("SpeedLimitController")) { modifiedNavigationUIKeys.erase("ShowSpeedLimits"); } @@ -261,6 +281,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : } QObject::connect(parent, &FrogPilotSettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideToggles); + QObject::connect(parent, &FrogPilotSettingsWindow::closeSubParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles); QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric); } @@ -320,6 +341,7 @@ void FrogPilotVisualsPanel::showToggles(const std::set &keys) { } setUpdatesEnabled(true); + update(); } @@ -330,7 +352,9 @@ void FrogPilotVisualsPanel::hideToggles() { bool subToggles = accessibilityKeys.find(key) != accessibilityKeys.end() || advancedCustomOnroadUIKeys.find(key) != advancedCustomOnroadUIKeys.end() || customOnroadUIKeys.find(key) != customOnroadUIKeys.end() || + developerMetricKeys.find(key) != developerMetricKeys.end() || developerUIKeys.find(key) != developerUIKeys.end() || + developerWidgetKeys.find(key) != developerWidgetKeys.end() || modelUIKeys.find(key) != modelUIKeys.end() || navigationUIKeys.find(key) != navigationUIKeys.end(); @@ -340,5 +364,13 @@ void FrogPilotVisualsPanel::hideToggles() { toggles["QOLVisuals"]->setVisible(toggles["QOLVisuals"]->isVisible() || hasOpenpilotLongitudinal); setUpdatesEnabled(true); + update(); } + +void FrogPilotVisualsPanel::hideSubToggles() { + if (developerUIOpen) { + developerUIOpen = false; + showToggles(developerUIKeys); + } +} diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h index 74da95396af91b..74106171bc2877 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h @@ -12,8 +12,10 @@ class FrogPilotVisualsPanel : public FrogPilotListWidget { signals: void openParentToggle(); + void openSubParentToggle(); private: + void hideSubToggles(); void hideToggles(); void showEvent(QShowEvent *event) override; void showToggles(const std::set &keys); @@ -29,6 +31,7 @@ class FrogPilotVisualsPanel : public FrogPilotListWidget { QJsonObject frogpilotToggleLevels; + bool developerUIOpen; bool hasAutoTune; bool hasBSM; bool hasOpenpilotLongitudinal; @@ -42,7 +45,9 @@ class FrogPilotVisualsPanel : public FrogPilotListWidget { std::set accessibilityKeys = {"CameraView", "DriverCamera", "OnroadDistanceButton", "StandbyMode", "StoppedTimer"}; std::set advancedCustomOnroadUIKeys = {"HideAlerts", "HideLeadMarker", "HideMapIcon", "HideMaxSpeed", "HideSpeed", "HideSpeedLimit", "WheelSpeed"}; std::set customOnroadUIKeys = {"AccelerationPath", "AdjacentPath", "BlindSpotPath", "Compass", "PedalsOnUI", "RotatingWheel"}; - std::set developerUIKeys = {"BorderMetrics", "FPSCounter", "LateralMetrics", "LongitudinalMetrics", "NumericalTemp", "SidebarMetrics", "UseSI"}; - std::set modelUIKeys = {"DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "ShowStoppingPoint", "UnlimitedLength"}; - std::set navigationUIKeys = {"BigMap", "MapStyle", "RoadNameUI", "ShowSLCOffset", "ShowSpeedLimits", "UseVienna"}; + std::set developerMetricKeys = {"BorderMetrics", "FPSCounter", "LateralMetrics", "LongitudinalMetrics", "NumericalTemp", "SidebarMetrics", "UseSI"}; + std::set developerUIKeys = {"DeveloperMetrics", "DeveloperWidgets"}; + std::set developerWidgetKeys = {"ShowCEMStatus", "ShowStoppingPoint"}; + std::set modelUIKeys = {"DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; + std::set navigationUIKeys = {"BigMap", "MapStyle", "RoadNameUI", "ShowSpeedLimits", "UseVienna"}; }; diff --git a/selfdrive/ui/qt/onroad/alerts.cc b/selfdrive/ui/qt/onroad/alerts.cc index 8e2a2c8464b9ac..8be4e9bf07fd00 100644 --- a/selfdrive/ui/qt/onroad/alerts.cc +++ b/selfdrive/ui/qt/onroad/alerts.cc @@ -17,8 +17,6 @@ void OnroadAlerts::updateState(const UIState &s) { hide_alerts = scene.hide_alerts; road_name_ui = scene.road_name_ui; - show_aol_status_bar = scene.aol_status_bar; - show_cem_status_bar = scene.cem_status_bar; } void OnroadAlerts::clear() { @@ -82,7 +80,7 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { int margin = 40; int radius = 30; - int offset = road_name_ui || show_aol_status_bar || show_cem_status_bar ? 25 : 0; + int offset = road_name_ui ? 25 : 0; alert_height = h - margin + offset; if (alert.size == cereal::ControlsState::AlertSize::FULL) { margin = 0; diff --git a/selfdrive/ui/qt/onroad/alerts.h b/selfdrive/ui/qt/onroad/alerts.h index 0ee444355b4a1b..56b300b7a61453 100644 --- a/selfdrive/ui/qt/onroad/alerts.h +++ b/selfdrive/ui/qt/onroad/alerts.h @@ -46,6 +46,4 @@ class OnroadAlerts : public QWidget { // FrogPilot variables bool hide_alerts; bool road_name_ui; - bool show_aol_status_bar; - bool show_cem_status_bar; }; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 8e81b9f3bdc2b6..f2c6124f321089 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -76,7 +76,6 @@ void AnnotatedCameraWidget::updateState(int alert_height, const UIState &s) { speedLimit = nav_alive ? nav_instruction.getSpeedLimit() : 0.0; } speedLimit *= (s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH); - speedLimit -= (showSLCOffset && !slcOverridden ? slcSpeedLimitOffset : 0); has_us_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::MUTCD) || !useViennaSLCSign && !hideSpeedLimit; has_eu_speed_limit = (nav_alive && speed_limit_sign == cereal::NavInstruction::SpeedLimitSign::VIENNA) || useViennaSLCSign && !hideSpeedLimit; @@ -88,7 +87,7 @@ void AnnotatedCameraWidget::updateState(int alert_height, const UIState &s) { status = s.status; // update engageability/experimental mode button - experimental_btn->updateState(s, leadInfo); + experimental_btn->updateState(s); // update DM icon auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); @@ -99,8 +98,8 @@ void AnnotatedCameraWidget::updateState(int alert_height, const UIState &s) { // hide map settings button for alerts and flip for right hand DM if (map_settings_btn->isEnabled()) { - map_settings_btn->setVisible(!hideBottomIcons && compass && !hideMapIcon); - main_layout->setAlignment(map_settings_btn, (rightHandDM && !compass || !rightHandDM && compass ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); + map_settings_btn->setVisible(!hideBottomIcons && !hideMapIcon); + main_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); } // Update FrogPilot widgets @@ -213,12 +212,11 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { QPixmap scaledCurveSpeedIcon = (leftCurve ? curveSpeedLeftIcon : curveSpeedRightIcon).scaled(curveSpeedRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); p.setOpacity(1.0); - p.setRenderHint(QPainter::Antialiasing); p.drawPixmap(curveSpeedRect, scaledCurveSpeedIcon); if (mtscEnabled) { QRect mtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), vtscControllingCurve ? 50 : 100)); - drawCurveSpeedControl(mtscRect, mtscSpeedStr, true); + drawCurveSpeedControl(mtscRect, mtscSpeedStr, true); if (vtscEnabled) { QRect vtscRect(mtscRect.topLeft() + QPoint(0, mtscRect.height() + 20), QSize(mtscRect.width(), vtscControllingCurve ? 100 : 50)); @@ -331,6 +329,8 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { QRect iconRect(rect.x() + 20, rect.y() + (rect.height() - img_size / 4) / 2, img_size / 4, img_size / 4); + QPixmap scaledIcon = icon.scaled(iconRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + QString speedText; if (speedLimitValue > 1) { speedText = QString::number(std::nearbyint(speedLimitValue)) + " " + speedUnit; @@ -343,8 +343,7 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { p.setOpacity(1.0); p.drawRoundedRect(rect, 24, 24); - p.setRenderHint(QPainter::Antialiasing); - p.drawPixmap(iconRect, icon); + p.drawPixmap(iconRect, scaledIcon); p.setPen(QPen(whiteColor(), 6)); QRect textRect(iconRect.right() + 10, rect.y(), rect.width() - iconRect.width() - 30, rect.height()); @@ -631,7 +630,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, f gradient.setColorAt(1.0f, color); }; - if (alwaysOnLateralActive) { + if (scene.always_on_lateral_active) { setPathEdgeColors(pe, bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE]); } else if (conditionalStatus == 1 || conditionalStatus == 3 || conditionalStatus == 5) { setPathEdgeColors(pe, bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]); @@ -672,10 +671,11 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) } else if (onroadDistanceButton) { x += 250; } - offset += statusBarHeight / 2; int y = height() - offset; + dmIconPosition.setX(x); + dmIconPosition.setY(y); float opacity = dmActive ? 0.65 : 0.2; - drawIcon(painter, QPoint(x, y), dm_img, blackColor(70), opacity); + drawIcon(painter, dmIconPosition, dm_img, blackColor(70), opacity); // face QPointF face_kpts_draw[std::size(default_face_kpts_3d)]; @@ -710,7 +710,7 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.save(); const float speedBuff = 10.; - const float leadBuff = 40.; + const float leadBuff = adjacent ? 100. : 40.; const float d_rel = lead_data.getDRel() + (adjacent ? fabs(lead_data.getYRel()) : 0); const float v_rel = lead_data.getVRel(); @@ -723,7 +723,7 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState fillAlpha = (int)(fmin(fillAlpha, 255)); } - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), adjacent ? 5.0f : 15.0f, adjacent ? 20.0f : 30.0f) * 2.35; + float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), adjacent ? 10.0f : 15.0f, adjacent ? 20.0f : 30.0f) * 2.35; float x = std::clamp((float)vd.x(), 0.f, width() - sz / 2); float y = std::fmin(height() - sz * .6, (float)vd.y()); @@ -731,16 +731,12 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState float g_yo = sz / 10; QPointF glow[] = {{x + (sz * 1.35) + g_xo, y + sz + g_yo}, {x, y - g_yo}, {x - (sz * 1.35) - g_xo, y + sz + g_yo}}; - if (!adjacent) { - painter.setBrush(QColor(218, 202, 37, 255)); - } else { - painter.setBrush(QColor(lead_marker_color.red(), lead_marker_color.green(), lead_marker_color.blue(), 255)); - } + painter.setBrush(QColor(218, 202, 37, 255)); painter.drawPolygon(glow, std::size(glow)); // chevron QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}}; - if (adjacent || useStockColors) { + if (!adjacent && useStockColors) { painter.setBrush(redColor(fillAlpha)); } else { painter.setBrush(QColor(lead_marker_color.red(), lead_marker_color.green(), lead_marker_color.blue(), fillAlpha)); @@ -761,12 +757,13 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState .arg(qRound(lead_speed * speedConversionMetrics)) .arg(leadSpeedUnit); } else { - text = QString("%1 %2 | %3 %4 | %5 %6") + text = QString("%1 %2 (%3) | %4 %5 | %6 %7") .arg(qRound(d_rel * distanceConversion)) .arg(leadDistanceUnit) + .arg(QString("Desired: %1").arg(desiredFollow * distanceConversion)) .arg(qRound(lead_speed * speedConversionMetrics)) .arg(leadSpeedUnit) - .arg(QString::number(d_rel / std::max(v_ego, 1.0f), 'f', 1)) + .arg(QString::number(std::max(d_rel / std::max(v_ego, 1.0f), 1.0f), 'f', 2)) .arg("s"); } @@ -782,7 +779,7 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState lead_y = y + text_y + textHeight; } - if (!adjacent || fabs((x + text_x + textWidth) - lead_x) >= textWidth || fabs((y + text_y + textHeight) - lead_y) >= textHeight) { + if (!adjacent || fabs((x + text_x + textWidth) - lead_x) >= textWidth * 1.25 || fabs((y + text_y + textHeight) - lead_y) >= textHeight * 2) { painter.drawText(text_x, text_y, text); } } @@ -797,6 +794,7 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { UIState *s = uiState(); SubMaster &sm = *(s->sm); QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); const double start_draw_t = millis_since_boot(); const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); const float v_ego = sm["carState"].getCarState().getVEgo(); @@ -847,7 +845,6 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { painter.endNativePainting(); } - painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); if (s->scene.world_objects_visible) { @@ -871,13 +868,13 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { drawLead(painter, lead_left, s->scene.lead_vertices[3], v_ego, blueColor(), true); } if (lead_right.getStatus()) { - drawLead(painter, lead_right, s->scene.lead_vertices[4], v_ego, orangeColor(), true); + drawLead(painter, lead_right, s->scene.lead_vertices[4], v_ego, purpleColor(), true); } if (lead_left_far.getStatus()) { - drawLead(painter, lead_left_far, s->scene.lead_vertices[5], v_ego, purpleColor(), true); + drawLead(painter, lead_left_far, s->scene.lead_vertices[5], v_ego, orangeColor(), true); } if (lead_right_far.getStatus()) { - drawLead(painter, lead_right_far, s->scene.lead_vertices[6], v_ego, yellowColor(), true); + drawLead(painter, lead_right_far, s->scene.lead_vertices[6], v_ego, redColor(), true); } if (lead_two.getStatus()) { drawLead(painter, lead_two, s->scene.lead_vertices[1], v_ego, s->scene.lead_marker_color); @@ -990,29 +987,23 @@ void AnnotatedCameraWidget::updateSignals() { } void AnnotatedCameraWidget::initializeFrogPilotWidgets() { - bottom_layout = new QHBoxLayout(); - distance_btn = new DistanceButton(this); - bottom_layout->addWidget(distance_btn); - - QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); - bottom_layout->addItem(spacer); - - compass_img = new Compass(this); - bottom_layout->addWidget(compass_img); - - map_settings_btn_bottom = new MapSettingsButton(this); - bottom_layout->addWidget(map_settings_btn_bottom); - - main_layout->addLayout(bottom_layout); - - curveSpeedLeftIcon = loadPixmap("../frogpilot/assets/other_images/curve_speed_left.png", QSize(img_size, img_size)); - curveSpeedRightIcon = loadPixmap("../frogpilot/assets/other_images/curve_speed_right.png", QSize(img_size, img_size)); - dashboardIcon = loadPixmap("../frogpilot/assets/other_images/dashboard_icon.png", QSize(img_size / 2, img_size / 2)); - mapDataIcon = loadPixmap("../frogpilot/assets/other_images/offline_maps_icon.png", QSize(img_size / 2, img_size / 2)); - navigationIcon = loadPixmap("../frogpilot/assets/other_images/navigation_icon.png", QSize(img_size / 2, img_size / 2)); - stopSignImg = loadPixmap("../frogpilot/assets/other_images/stop_sign.png", QSize(img_size, img_size)); - upcomingMapsIcon = loadPixmap("../frogpilot/assets/other_images/upcoming_maps_icon.png", QSize(img_size / 2, img_size / 2)); + main_layout->addWidget(distance_btn, 0, Qt::AlignBottom | Qt::AlignLeft); + + chillModeIcon = loadPixmap("../frogpilot/assets/other_images/chill_mode_icon.png", {img_size / 2, img_size / 2}); + curveIcon = loadPixmap("../frogpilot/assets/other_images/curve_icon.png", {img_size / 2, img_size / 2}); + curveSpeedLeftIcon = loadPixmap("../frogpilot/assets/other_images/curve_speed_left.png", {img_size, img_size}); + curveSpeedRightIcon = loadPixmap("../frogpilot/assets/other_images/curve_speed_right.png", {img_size, img_size}); + dashboardIcon = loadPixmap("../frogpilot/assets/other_images/dashboard_icon.png", {img_size / 2, img_size / 2}); + experimentalModeIcon = loadPixmap("../assets/img_experimental.svg", {img_size / 2, img_size / 2}); + leadIcon = loadPixmap("../frogpilot/assets/other_images/lead_icon.png", {img_size / 2, img_size / 2}); + lightIcon = loadPixmap("../frogpilot/assets/other_images/light_icon.png", {img_size / 2, img_size / 2}); + mapDataIcon = loadPixmap("../frogpilot/assets/other_images/offline_maps_icon.png", {img_size / 2, img_size / 2}); + navigationIcon = loadPixmap("../frogpilot/assets/other_images/navigation_icon.png", {img_size / 2, img_size / 2}); + speedIcon = loadPixmap("../frogpilot/assets/other_images/speed_icon.png", {img_size / 2, img_size / 2}); + stopSignImg = loadPixmap("../frogpilot/assets/other_images/stop_sign.png", {img_size, img_size}); + turnIcon = loadPixmap("../frogpilot/assets/other_images/turn_icon.png", {img_size / 2, img_size / 2}); + upcomingMapsIcon = loadPixmap("../frogpilot/assets/other_images/upcoming_maps_icon.png", {img_size / 2, img_size / 2}); animationTimer = new QTimer(this); QObject::connect(animationTimer, &QTimer::timeout, [this] { @@ -1047,31 +1038,17 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS alertHeight = alert_height; - alwaysOnLateralActive = scene.always_on_lateral_active; - showAlwaysOnLateralStatusBar = scene.aol_status_bar; - blindSpotLeft = scene.blind_spot_left; blindSpotRight = scene.blind_spot_right; cameraView = scene.camera_view; - compass = scene.compass; - bool enableCompass = compass && !hideBottomIcons; - compass_img->setVisible(enableCompass); - if (enableCompass) { - compass_img->updateState(scene); - bottom_layout->setAlignment(compass_img, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight)); - } - - conditionalSpeed = scene.conditional_limit; - conditionalSpeedLead = scene.conditional_limit_lead; + cemStatus = scene.cem_status; conditionalStatus = scene.conditional_status; - showConditionalExperimentalStatusBar = scene.cem_status_bar; - currentAcceleration = scene.acceleration; + compass = scene.compass; desiredFollow = scene.desired_follow; - stoppedEquivalence = scene.stopped_equivalence; experimentalMode = scene.experimental_mode; @@ -1084,18 +1061,11 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS laneDetectionWidth = scene.lane_detection_width; leadInfo = scene.lead_metrics; - obstacleDistance = scene.obstacle_distance; - obstacleDistanceStock = scene.obstacle_distance_stock; leftCurve = scene.left_curve; mapOpen = scene.map_open; bigMapOpen = mapOpen && scene.big_map; - map_settings_btn_bottom->setEnabled(map_settings_btn->isEnabled()); - if (map_settings_btn_bottom->isEnabled()) { - map_settings_btn_bottom->setVisible(!hideBottomIcons && !compass && !hideMapIcon); - bottom_layout->setAlignment(map_settings_btn_bottom, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); - } modelLength = scene.model_length; @@ -1107,7 +1077,6 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS distance_btn->setVisible(enableDistanceButton); if (enableDistanceButton) { distance_btn->updateState(scene); - bottom_layout->setAlignment(distance_btn, (rightHandDM ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignBottom); } bool enablePedalIcons = scene.pedals_on_ui && !bigMapOpen; @@ -1164,14 +1133,12 @@ void AnnotatedCameraWidget::updateFrogPilotVariables(int alert_height, const UIS } void AnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &painter) { - if ((showAlwaysOnLateralStatusBar || showConditionalExperimentalStatusBar || roadNameUI) && !bigMapOpen) { - drawStatusBar(painter); - } else { - statusBarHeight = 0; + if (cemStatus && !mapOpen && !hideBottomIcons) { + drawCEMStatus(painter); } - if (leadInfo && !bigMapOpen) { - drawLeadInfo(painter); + if (roadNameUI && !bigMapOpen) { + drawRoadName(painter); } if (turnSignalAnimation && (turnSignalLeft || turnSignalRight) && !bigMapOpen && ((!mapOpen && standstillDuration == 0) || signalStyle != "static")) { @@ -1184,175 +1151,46 @@ void AnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &painter) { } } -Compass::Compass(QWidget *parent) : QWidget(parent) { - setFixedSize(btn_size * 1.5, btn_size * 1.5); - - compassSize = btn_size; - circleOffset = compassSize / 2; - degreeLabelOffset = circleOffset + 25; - innerCompass = compassSize / 2; - - x = (btn_size * 1.5) / 2 + 20; - y = (btn_size * 1.5) / 2; - - compassInnerImg = loadPixmap("../frogpilot/assets/other_images/compass_inner.png", QSize(compassSize / 1.75, compassSize / 1.75)); - initializeStaticElements(); -} - -void Compass::initializeStaticElements() { - staticElements = QPixmap(size()); - staticElements.fill(Qt::transparent); - QPainter p(&staticElements); - - p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); - p.setPen(QPen(Qt::white, 2)); - p.setBrush(QColor(0, 0, 0, 100)); - - const int xOffset = x - circleOffset; - const int yOffset = y - circleOffset; - - p.drawEllipse(xOffset, yOffset, compassSize, compassSize); - p.setBrush(Qt::NoBrush); - const int innerOffset = innerCompass + 5; - p.drawEllipse(x - innerOffset, y - innerOffset, innerOffset * 2, innerOffset * 2); - p.drawEllipse(x - degreeLabelOffset, y - degreeLabelOffset, degreeLabelOffset * 2, degreeLabelOffset * 2); - - QPainterPath outerCircle, innerCircle; - outerCircle.addEllipse(x - degreeLabelOffset, y - degreeLabelOffset, degreeLabelOffset * 2, degreeLabelOffset * 2); - innerCircle.addEllipse(xOffset, yOffset, compassSize, compassSize); - p.fillPath(outerCircle.subtracted(innerCircle), Qt::black); -} - -void Compass::updateState(const UIScene &scene) { - if (bearingDeg != scene.bearing_deg) { - bearingDeg = (scene.bearing_deg + 360) % 360; - update(); - } -} - -void Compass::paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); - p.drawPixmap(0, 0, staticElements); - p.translate(x, y); - p.rotate(bearingDeg); - p.drawPixmap(-compassInnerImg.width() / 2, -compassInnerImg.height() / 2, compassInnerImg); - p.resetTransform(); - - QFont font = InterFont(10, QFont::Normal); - const int halfCompassSize = compassSize / 2; - for (int i = 0; i < 360; i += 15) { - bool isBold = abs(i - bearingDeg) <= 7; - font.setWeight(isBold ? QFont::Bold : QFont::Normal); - p.setFont(font); - p.setPen(QPen(Qt::white, i % 90 == 0 ? 2 : 1)); - - p.save(); - p.translate(x, y); - p.rotate(i); - int lineLength = i % 90 == 0 ? 12 : 8; - p.drawLine(0, -(halfCompassSize - lineLength), 0, -halfCompassSize); - p.translate(0, -(halfCompassSize + 12)); - p.rotate(-i); - p.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(i)); - p.restore(); - } - - p.setFont(InterFont(20, QFont::Bold)); - const std::map, int, QColor>> directionInfo = { - {"N", {{292.5, 67.5}, Qt::AlignTop | Qt::AlignHCenter, Qt::white}}, - {"E", {{22.5, 157.5}, Qt::AlignRight | Qt::AlignVCenter, Qt::white}}, - {"S", {{112.5, 247.5}, Qt::AlignBottom | Qt::AlignHCenter, Qt::white}}, - {"W", {{202.5, 337.5}, Qt::AlignLeft | Qt::AlignVCenter, Qt::white}} - }; - const int directionOffset = 20; - - for (const auto &[direction, params] : directionInfo) { - const auto &[range, alignmentFlag, color] = params; - const auto &[minRange, maxRange] = range; - - bool isInRange = (minRange > maxRange) ? (bearingDeg >= minRange || bearingDeg <= maxRange) : (bearingDeg >= minRange && bearingDeg <= maxRange); - - QRect textRect(x - innerCompass + directionOffset, y - innerCompass + directionOffset, innerCompass * 2 - 2 * directionOffset, innerCompass * 2 - 2 * directionOffset); - - p.setOpacity(isInRange ? 1.0 : 0.2); - p.setPen(QPen(color)); - p.drawText(textRect, alignmentFlag, direction); - } -} - -void AnnotatedCameraWidget::drawLeadInfo(QPainter &p) { - static QElapsedTimer timer; - - static bool isFiveSecondsPassed = false; - - static double maxAcceleration = 0.0; - constexpr int maxAccelDuration = 5000; - - double acceleration = std::round(currentAcceleration * 100) / 100; - - auto resetTimer = [&]() { - timer.start(); - isFiveSecondsPassed = false; - }; - - if (acceleration > maxAcceleration && (status == STATUS_ENGAGED || status == STATUS_TRAFFIC_MODE_ACTIVE)) { - maxAcceleration = acceleration; - resetTimer(); - } else { - isFiveSecondsPassed = timer.hasExpired(maxAccelDuration); - } - - auto createText = [&](const QString &title, double data) { - return title + QString::number(std::round(data * distanceConversion)) + " " + leadDistanceUnit; - }; - - QString accelText = QString(tr("Accel: %1%2")) - .arg(acceleration * accelerationConversion, 0, 'f', 2) - .arg(accelerationUnit); - - QString maxAccSuffix; - if (!mapOpen) { - maxAccSuffix = QString(tr(" - Max: %1%2")) - .arg(maxAcceleration * accelerationConversion, 0, 'f', 2) - .arg(accelerationUnit); +void AnnotatedCameraWidget::drawCEMStatus(QPainter &p) { + if (dmIconPosition == QPoint(0, 0)) { + return; } - QString obstacleText = createText(mapOpen ? tr(" | Obstacle: ") : tr(" | Obstacle Factor: "), obstacleDistance); - QString stopText = createText(mapOpen ? tr(" - Stop: ") : tr(" - Stop Factor: "), stoppedEquivalence); - QString followText = " = " + createText(mapOpen ? tr("Follow: ") : tr("Follow Distance: "), desiredFollow); - - auto createDiffText = [&](double data, double stockData) { - double difference = std::round((data - stockData) * distanceConversion); - return difference > 1 ? QString(" (%1%2)").arg(difference > 0 ? "+" : "").arg(difference) : QString(); - }; - p.save(); + p.setOpacity(1.0); - QRect insightsRect(rect().left() - 1, rect().top() - 60, rect().width() + 2, 100); - p.setBrush(QColor(0, 0, 0, 150)); - p.drawRoundedRect(insightsRect, 30, 30); - p.setFont(InterFont(28, QFont::Bold)); - p.setRenderHint(QPainter::TextAntialiasing); - - QRect adjustedRect(insightsRect.adjusted(0, 27, 0, 27)); - int textBaseLine = adjustedRect.y() + (adjustedRect.height() + p.fontMetrics().height()) / 2 - p.fontMetrics().descent(); - - QStringList texts = {accelText, maxAccSuffix, obstacleText, createDiffText(obstacleDistance, obstacleDistanceStock), stopText, followText}; - QList colors = {Qt::white, isFiveSecondsPassed ? Qt::white : redColor(), Qt::white, (obstacleDistance - obstacleDistanceStock) > 0 ? Qt::green : Qt::red, Qt::white, Qt::white}; - - int totalTextWidth = 0; - for (const auto &text : texts) { - totalTextWidth += p.fontMetrics().horizontalAdvance(text); + QRect cemWidget(dmIconPosition.x() + (rightHandDM ? -img_size : img_size), dmIconPosition.y() - img_size / 2, img_size, img_size); + if (conditionalStatus == 1 || conditionalStatus == 3 || conditionalStatus == 5) { + p.setPen(QPen(QColor(bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]), 10)); + } else if (experimentalMode) { + p.setPen(QPen(QColor(bg_colors[STATUS_EXPERIMENTAL_MODE_ACTIVE]), 10)); + } else { + p.setPen(QPen(blackColor(), 10)); } - - int textStartPos = adjustedRect.x() + (adjustedRect.width() - totalTextWidth) / 2; - - for (int i = 0; i < texts.size(); ++i) { - p.setPen(colors[i]); - p.drawText(textStartPos, textBaseLine, texts[i]); - textStartPos += p.fontMetrics().horizontalAdvance(texts[i]); + p.setBrush(blackColor(166)); + p.drawRoundedRect(cemWidget, 24, 24); + + QSize iconSize(cemWidget.size().width() - 10, cemWidget.size().height() - 10); + QPixmap iconToDraw; + if (conditionalStatus == 1 || conditionalStatus == 3 || conditionalStatus == 5) { + iconToDraw = chillModeIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 2 || conditionalStatus == 4 || conditionalStatus == 6) { + iconToDraw = experimentalModeIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 7 || conditionalStatus == 8) { + iconToDraw = speedIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 9 || conditionalStatus == 11) { + iconToDraw = turnIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 10 || conditionalStatus == 15 || conditionalStatus == 16) { + iconToDraw = lightIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 12) { + iconToDraw = curveIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (conditionalStatus == 13 || conditionalStatus == 14) { + iconToDraw = leadIcon.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else { + p.restore(); + return; } + p.drawPixmap(QRect(cemWidget.center() - QPoint(iconToDraw.width() / 2, iconToDraw.height() / 2), iconToDraw.size()), iconToDraw); p.restore(); } @@ -1360,8 +1198,8 @@ void AnnotatedCameraWidget::drawLeadInfo(QPainter &p) { PedalIcons::PedalIcons(QWidget *parent) : QWidget(parent) { setFixedSize(btn_size, btn_size); - brake_pedal_img = loadPixmap("../frogpilot/assets/other_images/brake_pedal.png", QSize(img_size, img_size)); - gas_pedal_img = loadPixmap("../frogpilot/assets/other_images/gas_pedal.png", QSize(img_size, img_size)); + brake_pedal_img = loadPixmap("../frogpilot/assets/other_images/brake_pedal.png", {img_size, img_size}); + gas_pedal_img = loadPixmap("../frogpilot/assets/other_images/gas_pedal.png", {img_size, img_size}); } void PedalIcons::updateState(const UIScene &scene) { @@ -1407,114 +1245,32 @@ void PedalIcons::paintEvent(QPaintEvent *event) { p.drawPixmap(gasX, (height() - img_size) / 2, gas_pedal_img); } -void AnnotatedCameraWidget::drawStatusBar(QPainter &p) { - p.save(); - - static QElapsedTimer timer; - static QString lastShownStatus; - - static bool displayStatusText = false; - - constexpr qreal fadeDuration = 1500.0; - constexpr qreal textDuration = 5000.0; - - static qreal roadNameOpacity = 0.0; - static qreal statusTextOpacity = 0.0; - - QString newStatus; - - int offset = 50; - QRect statusBarRect(rect().left() - 1, rect().bottom() - offset, rect().width() + 2, 100); - statusBarHeight = statusBarRect.height() - offset; - p.setBrush(QColor(0, 0, 0, 150)); - p.setOpacity(1.0); - p.drawRoundedRect(statusBarRect, 30, 30); - - int modelStopTime = std::nearbyint(modelLength / (speed / (is_metric ? MS_TO_KPH : MS_TO_MPH))); - - std::map conditionalStatusMap = { - {0, tr("Conditional Experimental Mode ready")}, - {1, tr("Conditional Experimental overridden")}, - {2, tr("Experimental Mode manually activated")}, - {3, tr("Conditional Experimental overridden")}, - {4, tr("Experimental Mode manually activated")}, - {5, tr("Conditional Experimental overridden")}, - {6, tr("Experimental Mode manually activated")}, - {7, tr("Experimental Mode activated for %1").arg(mapOpen ? tr("low speed") : tr("speed being less than %1 %2").arg(conditionalSpeedLead).arg(speedUnit))}, - {8, tr("Experimental Mode activated for %1").arg(mapOpen ? tr("low speed") : tr("speed being less than %1 %2").arg(conditionalSpeed).arg(speedUnit))}, - {9, tr("Experimental Mode activated for turn") + (mapOpen ? " signal" : tr(" / lane change"))}, - {10, tr("Experimental Mode activated for intersection")}, - {11, tr("Experimental Mode activated for upcoming turn")}, - {12, tr("Experimental Mode activated for curve")}, - {13, tr("Experimental Mode activated for stopped lead")}, - {14, tr("Experimental Mode activated for slower lead")}, - {15, tr("Experimental Mode activated %1").arg(mapOpen || modelStopTime < 1 || speed < 1 ? tr("to stop") : QString("for the model wanting to stop in %1 seconds").arg(modelStopTime))}, - {16, tr("Experimental Mode forced on %1").arg(mapOpen || modelStopTime < 1 || speed < 1 ? tr("to stop") : QString("for the model wanting to stop in %1 seconds").arg(modelStopTime))}, - {17, tr("Experimental Mode activated due to no speed limit")}, - }; - - if (alwaysOnLateralActive && showAlwaysOnLateralStatusBar) { - newStatus = tr("Always On Lateral active") + (mapOpen ? "" : tr(". Press the \"Cruise Control\" button to disable")); - } else if (showConditionalExperimentalStatusBar) { - newStatus = conditionalStatusMap.at(conditionalStatus); - } - - static const std::map suffixMap = { - {1, tr(". Long press the \"distance\" button to revert")}, - {2, tr(". Long press the \"distance\" button to revert")}, - {3, tr(". Click the \"LKAS\" button to revert")}, - {4, tr(". Click the \"LKAS\" button to revert")}, - {5, tr(". Double tap the screen to revert")}, - {6, tr(". Double tap the screen to revert")}, - }; - - if (!alwaysOnLateralActive && !mapOpen && !newStatus.isEmpty()) { - if (suffixMap.find(conditionalStatus) != suffixMap.end()) { - newStatus += suffixMap.at(conditionalStatus); - } +void AnnotatedCameraWidget::drawRoadName(QPainter &p) { + QString roadName = QString::fromStdString(params_memory.get("RoadName")); + if (roadName.isEmpty()) { + return; } - QString roadName = QString::fromStdString(paramsMemory.get("RoadName")); - roadName = (!roadNameUI || roadName.isEmpty() || roadName == "null") ? "" : roadName; - - if (newStatus != lastShownStatus || roadName.isEmpty()) { - lastShownStatus = newStatus; - displayStatusText = true; - timer.restart(); - } else if (displayStatusText && timer.hasExpired(textDuration + fadeDuration)) { - displayStatusText = false; - } + QFont font = InterFont(40, QFont::DemiBold); + int textWidth = QFontMetrics(font).horizontalAdvance(roadName); - if (displayStatusText) { - statusTextOpacity = qBound(0.0, 1.0 - (timer.elapsed() - textDuration) / fadeDuration, 1.0); - roadNameOpacity = 1.0 - statusTextOpacity; - } else { - roadNameOpacity = qBound(0.0, timer.elapsed() / fadeDuration, 1.0); - statusTextOpacity = 0.0; - } + p.save(); - p.setFont(InterFont(40, QFont::Bold)); - p.setOpacity(statusTextOpacity); - p.setPen(Qt::white); - p.setRenderHint(QPainter::TextAntialiasing); + QRect roadNameRect((width() - textWidth * 1.25) / 2, rect().bottom() - 55 + 1, textWidth * 1.25, 50); - QRect textRect(p.fontMetrics().boundingRect(statusBarRect, Qt::AlignCenter | Qt::TextWordWrap, newStatus)); - textRect.moveBottom(statusBarRect.bottom() - offset); - p.drawText(textRect, Qt::AlignCenter | Qt::TextWordWrap, newStatus); + p.setBrush(blackColor(166)); + p.setOpacity(1.0); + p.setPen(QPen(blackColor(), 10)); + p.drawRoundedRect(roadNameRect, 24, 24); - if (!roadName.isEmpty()) { - p.setOpacity(roadNameOpacity); - textRect = p.fontMetrics().boundingRect(statusBarRect, Qt::AlignCenter | Qt::TextWordWrap, roadName); - textRect.moveBottom(statusBarRect.bottom() - offset); - p.drawText(textRect, Qt::AlignCenter | Qt::TextWordWrap, roadName); - } + p.setFont(font); + p.setPen(QPen(Qt::white, 6)); + p.drawText(roadNameRect, Qt::AlignCenter, roadName); p.restore(); } void AnnotatedCameraWidget::drawTurnSignals(QPainter &p) { - p.setRenderHint(QPainter::Antialiasing); - bool blindspotActive = turnSignalLeft ? blindSpotLeft : blindSpotRight; if (signalStyle == "static") { @@ -1530,7 +1286,7 @@ void AnnotatedCameraWidget::drawTurnSignals(QPainter &p) { int signalXPosition = turnSignalLeft ? width() - ((animationFrameIndex + 1) * signalWidth) : animationFrameIndex * signalWidth; int signalYPosition = height() - signalHeight; - signalYPosition -= fmax(alertHeight, statusBarHeight); + signalYPosition -= alertHeight; if (blindspotActive && !blindspotImages.empty()) { p.drawPixmap(turnSignalLeft ? width() - signalWidth : 0, signalYPosition, signalWidth, signalHeight, blindspotImages[turnSignalLeft ? 0 : 1]); @@ -1541,7 +1297,7 @@ void AnnotatedCameraWidget::drawTurnSignals(QPainter &p) { int signalXPosition = turnSignalLeft ? width() - (animationFrameIndex * signalMovement) + signalWidth : (animationFrameIndex * signalMovement) - signalWidth; int signalYPosition = height() - signalHeight; - signalYPosition -= fmax(alertHeight, statusBarHeight); + signalYPosition -= alertHeight; if (blindspotActive && !blindspotImages.empty()) { p.drawPixmap(turnSignalLeft ? width() - signalWidth : 0, signalYPosition, signalWidth, signalHeight, blindspotImages[turnSignalLeft ? 0 : 1]); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index 7ba29548ea6135..d070caf051e2d2 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -8,29 +8,6 @@ #include "selfdrive/frogpilot/screenrecorder/screenrecorder.h" -class Compass : public QWidget { - Q_OBJECT - -public: - explicit Compass(QWidget *parent = 0); - void updateState(const UIScene &scene); - -private: - void initializeStaticElements(); - void paintEvent(QPaintEvent *event) override; - - int bearingDeg; - int circleOffset; - int compassSize; - int degreeLabelOffset; - int innerCompass; - int x; - int y; - - QPixmap compassInnerImg; - QPixmap staticElements; -}; - class PedalIcons : public QWidget { Q_OBJECT @@ -64,10 +41,12 @@ class AnnotatedCameraWidget : public CameraWidget { MapSettingsButton *map_settings_btn; // FrogPilot variables - MapSettingsButton *map_settings_btn_bottom; - QRect newSpeedLimitRect; + QString accelerationUnit; + + float accelerationConversion; + private: void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255, bool overridePen = false); @@ -94,8 +73,8 @@ class AnnotatedCameraWidget : public CameraWidget { bool wide_cam_requested = false; // FrogPilot widgets - void drawLeadInfo(QPainter &p); - void drawStatusBar(QPainter &p); + void drawCEMStatus(QPainter &p); + void drawRoadName(QPainter &p); void drawTurnSignals(QPainter &p); void initializeFrogPilotWidgets(); void paintFrogPilotWidgets(QPainter &painter); @@ -103,24 +82,29 @@ class AnnotatedCameraWidget : public CameraWidget { void updateSignals(); // FrogPilot variables - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; - Compass *compass_img; DistanceButton *distance_btn; PedalIcons *pedal_icons; ScreenRecorder *screenRecorder; - QHBoxLayout *bottom_layout; - + QPixmap chillModeIcon; + QPixmap curveIcon; QPixmap curveSpeedLeftIcon; QPixmap curveSpeedRightIcon; QPixmap dashboardIcon; + QPixmap experimentalModeIcon; + QPixmap leadIcon; + QPixmap lightIcon; QPixmap mapDataIcon; QPixmap navigationIcon; + QPixmap speedIcon; QPixmap stopSignImg; + QPixmap turnIcon; QPixmap upcomingMapsIcon; - QString accelerationUnit; + QPoint dmIconPosition; + QString leadDistanceUnit; QString leadSpeedUnit; QString signalStyle; @@ -130,10 +114,10 @@ class AnnotatedCameraWidget : public CameraWidget { QVector blindspotImages; QVector signalImages; - bool alwaysOnLateralActive; bool bigMapOpen; bool blindSpotLeft; bool blindSpotRight; + bool cemStatus; bool compass; bool experimentalMode; bool hideCSCUI; @@ -147,8 +131,6 @@ class AnnotatedCameraWidget : public CameraWidget { bool mtscEnabled; bool onroadDistanceButton; bool roadNameUI; - bool showAlwaysOnLateralStatusBar; - bool showConditionalExperimentalStatusBar; bool showSLCOffset; bool slcOverridden; bool speedLimitChanged; @@ -163,9 +145,6 @@ class AnnotatedCameraWidget : public CameraWidget { bool vtscControllingCurve; bool vtscEnabled; - double currentAcceleration; - - float accelerationConversion; float dashboardSpeedLimit; float distanceConversion; float laneDetectionWidth; @@ -184,20 +163,14 @@ class AnnotatedCameraWidget : public CameraWidget { int alertHeight; int animationFrameIndex; int cameraView; - int conditionalSpeed; - int conditionalSpeedLead; int conditionalStatus; int desiredFollow; int modelLength; - int obstacleDistance; - int obstacleDistanceStock; int signalAnimationLength; int signalHeight; int signalMovement; int signalWidth; int standstillDuration; - int statusBarHeight; - int stoppedEquivalence; int totalFrames; std::string speedLimitSource; diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index e524a0dbc9a088..c1d5d8e48d22cf 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -57,7 +57,7 @@ void ExperimentalButton::changeMode() { } } -void ExperimentalButton::updateState(const UIState &s, bool lead_metrics) { +void ExperimentalButton::updateState(const UIState &s) { const auto cs = (*s.sm)["controlsState"].getControlsState(); bool eng = cs.getEngageable() || cs.getEnabled() || always_on_lateral_active; if ((cs.getExperimentalMode() != experimental_mode) || (eng != engageable)) { @@ -78,7 +78,6 @@ void ExperimentalButton::updateState(const UIState &s, bool lead_metrics) { rotating_wheel = scene.rotating_wheel; traffic_mode_active = scene.traffic_mode_active; use_stock_wheel = scene.use_stock_wheel; - y_offset = lead_metrics ? 10 : 0; if (rotating_wheel && steering_angle_deg != scene.steering_angle_deg) { steering_angle_deg = scene.steering_angle_deg; @@ -142,7 +141,7 @@ void ExperimentalButton::updateIcon() { 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); + gif_label->move((btn_size - img_size) / 2, (btn_size - img_size) / 2); gif_label->show(); gif->start(); @@ -150,7 +149,7 @@ void ExperimentalButton::updateIcon() { use_gif = true; image_empty = false; } else if (QFile::exists(wheel_png_path)) { - img = loadPixmap(wheel_png_path, QSize(img_size, img_size)); + img = loadPixmap(wheel_png_path, {img_size, img_size}); image_empty = false; use_gif = false; @@ -172,7 +171,7 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) { img = experimental_mode ? experimental_img : engage_img; } updateBackgroundColor(); - drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || !engageable) ? 0.6 : 1.0, steering_angle_deg); + drawIcon(p, QPoint(btn_size / 2, btn_size / 2), img, background_color, (isDown() || !engageable) ? 0.6 : 1.0, steering_angle_deg); } // MapSettingsButton diff --git a/selfdrive/ui/qt/onroad/buttons.h b/selfdrive/ui/qt/onroad/buttons.h index ec08db2b9f12ea..225a04cbbadd13 100644 --- a/selfdrive/ui/qt/onroad/buttons.h +++ b/selfdrive/ui/qt/onroad/buttons.h @@ -14,7 +14,7 @@ class ExperimentalButton : public QPushButton { public: explicit ExperimentalButton(QWidget *parent = 0); - void updateState(const UIState &s, bool lead_metrics); + void updateState(const UIState &s); // FrogPilot widgets ~ExperimentalButton(); @@ -60,7 +60,6 @@ class ExperimentalButton : public QPushButton { int conditional_status; int steering_angle_deg; - int y_offset; }; diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc index 5614bfc0e7f44d..4eb0b4861ceb2d 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/qt/onroad/onroad_home.cc @@ -53,8 +53,8 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { // FrogPilot variables QObject::connect(&clickTimer, &QTimer::timeout, [this]() { clickTimer.stop(); - QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, timeoutPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - QApplication::postEvent(this, event); + QMouseEvent event(QEvent::MouseButtonPress, timeoutPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QApplication::sendEvent(this, &event); }); } @@ -84,13 +84,13 @@ void OnroadWindow::updateState(const UIState &s) { // FrogPilot variables const UIScene &scene = s.scene; + acceleration = scene.acceleration; accelerationJerk = scene.acceleration_jerk; accelerationJerkDifference = scene.acceleration_jerk_difference; blindSpotLeft = scene.blind_spot_left; blindSpotRight = scene.blind_spot_right; fps = scene.fps; friction = scene.friction; - hasLead = scene.has_lead; latAccel = scene.lat_accel; liveValid = scene.live_valid; showBlindspot = scene.show_blind_spot && (blindSpotLeft || blindSpotRight); @@ -106,7 +106,7 @@ void OnroadWindow::updateState(const UIState &s) { turnSignalLeft = scene.turn_signal_left; turnSignalRight = scene.turn_signal_right; - if (showBlindspot || showFPS || (showJerk && hasLead) || showSignal || showSteering || showTuning) { + if (showBlindspot || showFPS || showJerk || showSignal || showSteering || showTuning) { shouldUpdate = true; } @@ -119,12 +119,10 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { // FrogPilot variables UIState *s = uiState(); UIScene &scene = s->scene; - - // FrogPilot clickable widgets QPoint pos = e->pos(); if (scene.speed_limit_changed && nvg->newSpeedLimitRect.contains(pos)) { - paramsMemory.putBool("SLCConfirmed", true); + params_memory.putBool("SpeedLimitAccepted", true); return; } @@ -133,8 +131,8 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { clickTimer.stop(); if (scene.conditional_experimental) { - int override_value = (scene.conditional_status >= 1 && scene.conditional_status <= 6) ? 0 : (scene.conditional_status >= 7 ? 5 : 6); - paramsMemory.putInt("CEStatus", override_value); + int override_value = scene.conditional_status != 0 && scene.conditional_status <= 6 ? 0 : scene.conditional_status >= 7 ? 5 : 6; + params_memory.putInt("CEStatus", override_value); } else { params.putBoolNonBlocking("ExperimentalMode", !params.getBool("ExperimentalMode")); } @@ -168,7 +166,6 @@ void OnroadWindow::createMapWidget() { map = m; QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested); QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); - QObject::connect(nvg->map_settings_btn_bottom, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings); nvg->map_settings_btn->setEnabled(true); m->setFixedWidth(topWidget(this)->width() / 2 - UI_BORDER_SIZE); @@ -248,88 +245,53 @@ void OnroadWindow::paintEvent(QPaintEvent *event) { } } - if (showBlindspot) { - QColor blindspotColorLeft = bgColor; - QColor blindspotColorRight = bgColor; - - if (blindSpotLeft) { - blindspotColorLeft = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; - } - - if (blindSpotRight) { - blindspotColorRight = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; - } - - int xLeft = rect.x(); - int xRight = rect.x() + rect.width() / 2; - QRect blindspotRectLeft(xLeft, rect.y(), rect.width() / 2, rect.height()); - QRect blindspotRectRight(xRight, rect.y(), rect.width() / 2, rect.height()); - - p.fillRect(blindspotRectLeft, blindspotColorLeft); - p.fillRect(blindspotRectRight, blindspotColorRight); - } - - if (showSignal) { - static int signalFramesLeft = 0; - static int signalFramesRight = 0; - - bool blindSpotActive = (blindSpotLeft && turnSignalLeft) || (blindSpotRight && turnSignalRight); - bool turnSignalActive = (turnSignalLeft && signalFramesLeft > 0) || (turnSignalRight && signalFramesRight > 0); - - QColor signalBorderColorLeft = bg; - QColor signalBorderColorRight = bg; - - if (blindSpotLeft) { - signalBorderColorLeft = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; - } - - if (blindSpotRight) { - signalBorderColorRight = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; - } - - if (sm.frame % 20 == 0 || blindSpotActive || turnSignalActive) { - QColor activeColor = bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]; - - if (turnSignalLeft) { - signalFramesLeft = sm.frame % 10 == 0 && blindSpotActive ? 5 : sm.frame % 20 == 0 ? 10 : signalFramesLeft - 1; - if (signalFramesLeft > 0) { - signalBorderColorLeft = activeColor; - } - } - - if (turnSignalRight) { - signalFramesRight = sm.frame % 10 == 0 && blindSpotActive ? 5 : sm.frame % 20 == 0 ? 10 : signalFramesRight - 1; - if (signalFramesRight > 0) { - signalBorderColorRight = activeColor; + if (showBlindspot || showSignal) { + static bool leftFlickerActive = false; + static bool rightFlickerActive = false; + + std::function getBorderColor = [&](bool blindSpot, bool turnSignal, bool &flickerActive) -> QColor { + if (showSignal && turnSignal) { + if (blindSpot) { + if (sm.frame % (UI_FREQ / 5) == 0) { + flickerActive = !flickerActive; + } + return flickerActive ? bg_colors[STATUS_TRAFFIC_MODE_ACTIVE] : bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]; + } else if (sm.frame % (UI_FREQ / 2) == 0) { + flickerActive = !flickerActive; } + return flickerActive ? bg_colors[STATUS_CONDITIONAL_OVERRIDDEN] : bg; + } else if (showBlindspot && blindSpot) { + return bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; + } else { + return bg; } - } + }; - int xLeft = rect.x(); - int xRight = rect.x() + rect.width() / 2; - QRect signalRectLeft(xLeft, rect.y(), rect.width() / 2, rect.height()); - QRect signalRectRight(xRight, rect.y(), rect.width() / 2, rect.height()); - - if (turnSignalLeft) { - p.fillRect(signalRectLeft, signalBorderColorLeft); - } + QColor borderColorLeft = getBorderColor(blindSpotLeft, turnSignalLeft, leftFlickerActive); + QColor borderColorRight = getBorderColor(blindSpotRight, turnSignalRight, rightFlickerActive); - if (turnSignalRight) { - p.fillRect(signalRectRight, signalBorderColorRight); - } + p.fillRect(rect.x(), rect.y(), rect.width() / 2, rect.height(), borderColorLeft); + p.fillRect(rect.x() + rect.width() / 2, rect.y(), rect.width() / 2, rect.height(), borderColorRight); } QString logicsDisplayString; if (showJerk) { - logicsDisplayString += QString("Acceleration Jerk: %1 | ").arg(accelerationJerk, 0, 'f', 3); - logicsDisplayString += QString("Speed Jerk: %1").arg(speedJerk, 0, 'f', 3); + if (bg == bg_colors[STATUS_ENGAGED] || bg == bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]) { + maxAcceleration = std::max(maxAcceleration, acceleration); + } + maxAccelTimer = maxAcceleration == acceleration && maxAcceleration != 0 ? UI_FREQ * 5 : maxAccelTimer - 1; + + logicsDisplayString += QString("Acceleration: %1 %2 - ").arg(acceleration, 0, 'f', 2).arg(nvg->accelerationUnit); + logicsDisplayString += QString("Max: %1 %2 | ").arg(maxAcceleration, 0, 'f', 2).arg(nvg->accelerationUnit); + logicsDisplayString += QString("Acceleration Jerk: %1 | ").arg(accelerationJerk, 0, 'f', 2); + logicsDisplayString += QString("Speed Jerk: %1").arg(speedJerk, 0, 'f', 2); } if (showTuning) { if (!logicsDisplayString.isEmpty()) { logicsDisplayString += " | "; } - logicsDisplayString += QString("Friction: %1 | ").arg(liveValid ? QString::number(friction, 'f', 3) : "Calculating..."); - logicsDisplayString += QString("Lateral Acceleration: %1").arg(liveValid ? QString::number(latAccel, 'f', 3) : "Calculating..."); + logicsDisplayString += QString("Friction: %1 | ").arg(liveValid ? QString::number(friction, 'f', 2) : "Calculating..."); + logicsDisplayString += QString("Lateral Acceleration: %1").arg(liveValid ? QString::number(latAccel, 'f', 2) : "Calculating..."); } if (!logicsDisplayString.isEmpty()) { p.save(); @@ -339,28 +301,38 @@ void OnroadWindow::paintEvent(QPaintEvent *event) { QFontMetrics fontMetrics(p.font()); - int x = (rect.width() - fontMetrics.horizontalAdvance(logicsDisplayString)) / 2; + int x = (rect.width() - fontMetrics.horizontalAdvance(logicsDisplayString)) / 2 - UI_BORDER_SIZE; int y = rect.top() + (fontMetrics.height() / 1.5); QStringList parts = logicsDisplayString.split("|"); for (QString part : parts) { - if (part.contains("Acceleration Jerk") && accelerationJerkDifference != 0) { - QString baseText = QString("Acceleration Jerk: %1").arg(accelerationJerk, 0, 'f', 3); - p.setPen(Qt::white); + if (part.contains("Max:") && maxAccelTimer > 0) { + QString baseText = QString("Acceleration: %1 %2 - ").arg(acceleration, 0, 'f', 2).arg(nvg->accelerationUnit); + p.setPen(whiteColor()); + p.drawText(x, y, baseText); + x += fontMetrics.horizontalAdvance(baseText); + + QString maxText = QString("Max: %1 %2 | ").arg(maxAcceleration, 0, 'f', 2).arg(nvg->accelerationUnit); + p.setPen(redColor()); + p.drawText(x, y, maxText); + x += fontMetrics.horizontalAdvance(maxText); + } else if (part.contains("Acceleration Jerk") && accelerationJerkDifference != 0) { + QString baseText = QString("Acceleration Jerk: %1").arg(accelerationJerk, 0, 'f', 2); + p.setPen(whiteColor()); p.drawText(x, y, baseText); x += fontMetrics.horizontalAdvance(baseText); - QString diffText = QString(" (%1) | ").arg(accelerationJerkDifference, 0, 'f', 3); + QString diffText = QString(" (%1) | ").arg(accelerationJerkDifference, 0, 'f', 2); p.setPen(redColor()); p.drawText(x, y, diffText); x += fontMetrics.horizontalAdvance(diffText); } else if (part.contains("Speed Jerk") && speedJerkDifference != 0) { - QString baseText = QString("Speed Jerk: %1").arg(speedJerk, 0, 'f', 3); - p.setPen(Qt::white); + QString baseText = QString("Speed Jerk: %1").arg(speedJerk, 0, 'f', 2); + p.setPen(whiteColor()); p.drawText(x, y, baseText); x += fontMetrics.horizontalAdvance(baseText); - QString diffText = QString(" (%1)").arg(speedJerkDifference, 0, 'f', 3); + QString diffText = QString(" (%1)").arg(speedJerkDifference, 0, 'f', 2); if (showTuning) { diffText += " | "; } @@ -368,16 +340,16 @@ void OnroadWindow::paintEvent(QPaintEvent *event) { p.drawText(x, y, diffText); x += fontMetrics.horizontalAdvance(diffText); } else if (part.contains("Speed Jerk") && !showTuning) { - p.setPen(Qt::white); + p.setPen(whiteColor()); p.drawText(x, y, part); x += fontMetrics.horizontalAdvance(part); } else if (part.contains("Lateral Acceleration")) { - p.setPen(Qt::white); + p.setPen(whiteColor()); p.drawText(x, y, part); x += fontMetrics.horizontalAdvance(part); } else { part += " | "; - p.setPen(Qt::white); + p.setPen(whiteColor()); p.drawText(x, y, part); x += fontMetrics.horizontalAdvance(part); } @@ -419,7 +391,7 @@ void OnroadWindow::paintEvent(QPaintEvent *event) { p.setFont(InterFont(28, QFont::DemiBold)); p.setRenderHint(QPainter::TextAntialiasing); - p.setPen(Qt::white); + p.setPen(whiteColor()); int textWidth = p.fontMetrics().horizontalAdvance(fpsDisplayString); int xPos = (rect.width() - textWidth) / 2; diff --git a/selfdrive/ui/qt/onroad/onroad_home.h b/selfdrive/ui/qt/onroad/onroad_home.h index 9d4a2a256b978a..35efdd00c43ed2 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.h +++ b/selfdrive/ui/qt/onroad/onroad_home.h @@ -27,7 +27,6 @@ class OnroadWindow : public QWidget { // FrogPilot variables bool blindSpotLeft; bool blindSpotRight; - bool hasLead; bool liveValid; bool showBlindspot; bool showFPS; @@ -38,15 +37,18 @@ class OnroadWindow : public QWidget { bool turnSignalLeft; bool turnSignalRight; + float acceleration; float accelerationJerk; float accelerationJerkDifference; float fps; float friction; float latAccel; + float maxAcceleration; float speedJerk; float speedJerkDifference; float steer; + int maxAccelTimer; int steeringAngleDeg; QPoint timeoutPoint = QPoint(420, 69); @@ -54,9 +56,10 @@ class OnroadWindow : public QWidget { QTimer clickTimer; inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } + inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } Params params; - Params paramsMemory{"/dev/shm/params"}; + Params params_memory{"/dev/shm/params"}; private slots: void offroadTransition(bool offroad); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 349b257dfaded1..3bedabeab34687 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -140,20 +140,16 @@ void update_model(UIState *s, auto lead_count = model.getLeadsV3().size(); if (lead_count > 0) { auto lead_one = model.getLeadsV3()[0]; - scene.has_lead = lead_one.getProb() > scene.lead_detection_probability; - if (scene.has_lead) { + if (lead_one.getProb() > scene.lead_detection_probability) { const float lead_d = lead_one.getX()[0] * 2.; max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); } - } else { - scene.has_lead = false; } } else { auto lead_one = (*s->sm)["radarState"].getRadarState().getLeadOne(); - scene.has_lead = lead_one.getModelProb() > scene.lead_detection_probability; - if (scene.has_lead) { + if (lead_one.getModelProb() > scene.lead_detection_probability) { const float lead_d = lead_one.getDRel() * 2.; max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); } @@ -299,8 +295,6 @@ static void update_state(UIState *s) { scene.lane_width_left = frogpilotPlan.getLaneWidthLeft(); scene.lane_width_right = frogpilotPlan.getLaneWidthRight(); scene.mtsc_speed = frogpilotPlan.getMtscSpeed(); - scene.obstacle_distance = frogpilotPlan.getSafeObstacleDistance(); - scene.obstacle_distance_stock = frogpilotPlan.getSafeObstacleDistanceStock(); scene.red_light = frogpilotPlan.getRedLight(); scene.speed_jerk = frogpilotPlan.getSpeedJerk(); scene.speed_jerk_difference = frogpilotPlan.getSpeedJerkStock() - scene.speed_jerk; @@ -311,7 +305,6 @@ static void update_state(UIState *s) { scene.speed_limit_overridden = frogpilotPlan.getSlcOverridden(); scene.speed_limit_overridden_speed = frogpilotPlan.getSlcOverriddenSpeed(); scene.speed_limit_source = frogpilotPlan.getSlcSpeedLimitSource().cStr(); - scene.stopped_equivalence = frogpilotPlan.getStoppedEquivalenceFactor(); scene.unconfirmed_speed_limit = frogpilotPlan.getUnconfirmedSlcSpeedLimit(); scene.upcoming_speed_limit = frogpilotPlan.getUpcomingSLCSpeedLimit(); scene.vtsc_controlling_curve = frogpilotPlan.getVtscControllingCurve(); @@ -368,15 +361,12 @@ void ui_update_frogpilot_params(UIState *s) { scene.adjacent_path = scene.frogpilot_toggles.value("adjacent_paths").toBool(); scene.adjacent_path_metrics = scene.frogpilot_toggles.value("adjacent_path_metrics").toBool(); scene.always_on_lateral = scene.frogpilot_toggles.value("always_on_lateral").toBool(); - scene.aol_status_bar = scene.frogpilot_toggles.value("always_on_lateral_status_bar").toBool(); scene.big_map = scene.frogpilot_toggles.value("big_map").toBool(); scene.blind_spot_path = scene.frogpilot_toggles.value("blind_spot_path").toBool(); scene.camera_view = scene.frogpilot_toggles.value("camera_view").toDouble(); - scene.cem_status_bar = scene.frogpilot_toggles.value("conditional_status_bar").toBool(); + scene.cem_status = scene.frogpilot_toggles.value("cem_status").toBool(); scene.compass = scene.frogpilot_toggles.value("compass").toBool(); scene.conditional_experimental = scene.frogpilot_toggles.value("conditional_experimental_mode").toBool(); - scene.conditional_limit = scene.frogpilot_toggles.value("conditional_limit").toDouble(); - scene.conditional_limit_lead = scene.frogpilot_toggles.value("conditional_limit_lead").toDouble(); scene.cpu_metrics = scene.frogpilot_toggles.value("cpu_metrics").toBool(); scene.driver_camera_in_reverse = scene.frogpilot_toggles.value("driver_camera_in_reverse").toBool(); scene.dynamic_path_width = scene.frogpilot_toggles.value("dynamic_path_width").toBool(); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index cbfeb3ccc42676..1a0b8ab5106638 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -143,13 +143,12 @@ typedef struct UIScene { bool adjacent_path_metrics; bool always_on_lateral; bool always_on_lateral_active; - bool aol_status_bar; bool big_map; bool blind_spot_left; bool blind_spot_path; bool blind_spot_right; bool brake_lights_on; - bool cem_status_bar; + bool cem_status; bool compass; bool conditional_experimental; bool cpu_metrics; @@ -164,7 +163,6 @@ typedef struct UIScene { bool frogs_go_moo; bool full_map; bool gpu_metrics; - bool has_lead; bool hide_alerts; bool hide_csc_ui; bool hide_lead_marker; @@ -264,23 +262,18 @@ typedef struct UIScene { int bearing_deg; int camera_view; - int conditional_limit; - int conditional_limit_lead; int conditional_status; int desired_follow; int driver_camera_timer; int map_style; int minimum_lane_change_speed; int model_length; - int obstacle_distance; - int obstacle_distance_stock; int screen_brightness = -1; int screen_brightness_onroad = -1; int screen_timeout; int screen_timeout_onroad; int started_timer; int steering_angle_deg; - int stopped_equivalence; int tethering_config; std::string speed_limit_source; diff --git a/system/manager/process.py b/system/manager/process.py index 4d845e936f93d0..a1cde729530d14 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -76,9 +76,6 @@ class ManagerProcess(ABC): watchdog_seen = False shutting_down = False - # FrogPilot variables - started_time = 0 - @abstractmethod def prepare(self) -> None: pass @@ -105,14 +102,10 @@ def check_watchdog(self, started: bool, params: Params) -> None: dt = time.monotonic() - self.last_watchdog_time / 1e9 - self.started_time = self.started_time + 1 if started else 0 - if dt > self.watchdog_max_dt: if self.watchdog_seen and ENABLE_WATCHDOG: cloudlog.error(f"Watchdog timeout for {self.name} (exitcode {self.proc.exitcode}) restarting ({started=})") self.restart() - if self.started_time > 100 and self.name == "ui": - sentry.capture_tmux(self.started_time, params) else: self.watchdog_seen = True diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 7c53d30d7f07b3..40bd3000898063 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -106,7 +106,6 @@ def run_new_modeld(started, params, CP: car.CarParams, classic_model, frogpilot_ NativeProcess("classic_modeld", "selfdrive/classic_modeld", ["./classic_modeld"], run_classic_modeld), PythonProcess("fleet_manager", "selfdrive.frogpilot.fleetmanager.fleet_manager", always_run), PythonProcess("frogpilot_process", "selfdrive.frogpilot.frogpilot_process", always_run), - PythonProcess("mapd", "selfdrive.frogpilot.navigation.mapd", always_run), ] managed_processes = {p.name: p for p in procs} diff --git a/system/sentry.py b/system/sentry.py index 19c3dc74e9a24b..100211814e6948 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -71,7 +71,10 @@ def capture_fingerprint(candidate, params, blocked=False): if key_type == ParamKeyType.FROGPILOT_TRACKING: value = params_tracking.get_int(key) else: - value = params.get(key).decode('utf-8') if isinstance(params.get(key), bytes) else params.get(key) or "0" + if isinstance(params.get(key), bytes): + value = params.get(key).decode('utf-8') + else: + value = params.get(key) or "0" if isinstance(value, str) and "." in value: value = value.rstrip("0").rstrip(".") @@ -87,26 +90,15 @@ def capture_fingerprint(candidate, params, blocked=False): for label, key_values in matched_params.items(): scope.set_context(label, key_values) + scope.fingerprint = [params.get("DongleId", encoding='utf-8'), candidate] + if blocked: 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("FingerprintLogged", True) - - sentry_sdk.flush() - -def capture_tmux(started_time, params) -> None: - updated = params.get("Updated", encoding='utf-8') - - result = subprocess.run(['tmux', 'capture-pane', '-p', '-S', '-100'], stdout=subprocess.PIPE) - lines = result.stdout.decode('utf-8').splitlines() - - if lines: - with sentry_sdk.configure_scope() as scope: - scope.set_extra("tmux_log", "\n".join(lines)) - sentry_sdk.capture_message(f"UI Debugging Log - Last updated: {updated} - Started time: {started_time}", level='info') - sentry_sdk.flush() + params.put_bool("FingerprintLogged", True) + sentry_sdk.flush() def set_tag(key: str, value: str) -> None: