diff --git a/.github/update_date b/.github/update_date deleted file mode 100644 index c76e76d1f..000000000 --- a/.github/update_date +++ /dev/null @@ -1 +0,0 @@ -2025-04-26 diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 9b86b7ac8..2b8e73fa9 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -57,33 +57,34 @@ struct FrogPilotPlan @0x80ae746ee2596b11 { dangerJerk @2 :Float32; desiredFollowDistance @3 :Int64; experimentalMode @4 :Bool; - forcingStop @5 :Bool; - forcingStopLength @6 :Float32; - frogpilotEvents @7 :List(Car.CarEvent); - lateralCheck @8 :Bool; - laneWidthLeft @9 :Float32; - laneWidthRight @10 :Float32; - maxAcceleration @11 :Float32; - minAcceleration @12 :Float32; - mtscSpeed @13 :Float32; - redLight @14 :Bool; - roadCurvature @15 :Float32; - slcMapSpeedLimit @16 :Float32; - slcMapboxSpeedLimit @17 :Float32; - slcNextSpeedLimit @18 :Float32; - slcOverriddenSpeed @19 :Float32; - slcSpeedLimit @20 :Float32; - slcSpeedLimitOffset @21 :Float32; - slcSpeedLimitSource @22 :Text; - speedJerk @23 :Float32; - speedJerkStock @24 :Float32; - speedLimitChanged @25 :Bool; - tFollow @26 :Float32; - togglesUpdated @27 :Bool; - unconfirmedSlcSpeedLimit @28 :Float32; - vCruise @29 :Float32; - vtscControllingCurve @30 :Bool; - vtscSpeed @31 :Float32; + trackingLead @5 :Bool; + forcingStop @6 :Bool; + forcingStopLength @7 :Float32; + frogpilotEvents @8 :List(Car.CarEvent); + lateralCheck @9 :Bool; + laneWidthLeft @10 :Float32; + laneWidthRight @11 :Float32; + maxAcceleration @12 :Float32; + minAcceleration @13 :Float32; + mtscSpeed @14 :Float32; + redLight @15 :Bool; + roadCurvature @16 :Float32; + slcMapSpeedLimit @17 :Float32; + slcMapboxSpeedLimit @18 :Float32; + slcNextSpeedLimit @19 :Float32; + slcOverriddenSpeed @20 :Float32; + slcSpeedLimit @21 :Float32; + slcSpeedLimitOffset @22 :Float32; + slcSpeedLimitSource @23 :Text; + speedJerk @24 :Float32; + speedJerkStock @25 :Float32; + speedLimitChanged @26 :Bool; + tFollow @27 :Float32; + togglesUpdated @28 :Bool; + unconfirmedSlcSpeedLimit @29 :Float32; + vCruise @30 :Float32; + vtscControllingCurve @31 :Bool; + vtscSpeed @32 :Float32; } struct CustomReserved5 @0xa5cd762cd951a455 { diff --git a/cereal/log.capnp b/cereal/log.capnp index 01a6091b7..c06556e94 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -638,6 +638,7 @@ struct RadarState @0x9a185389d6fdd05f { modelProb @13 :Float32; radar @14 :Bool; radarTrackId @15 :Int32 = -1; + farLead @16 :Bool; aLeadDEPRECATED @5 :Float32; } diff --git a/common/params.cc b/common/params.cc index 7f1e7c651..3e541d5e1 100644 --- a/common/params.cc +++ b/common/params.cc @@ -284,6 +284,16 @@ std::unordered_map keys = { {"CustomUI", PERSISTENT}, {"DebugMode", CLEAR_ON_OFFROAD_TRANSITION}, {"DecelerationProfile", PERSISTENT}, + {"DeveloperMetrics", PERSISTENT}, + {"DeveloperSidebar", PERSISTENT}, + {"DeveloperSidebarMetric1", PERSISTENT}, + {"DeveloperSidebarMetric2", PERSISTENT}, + {"DeveloperSidebarMetric3", PERSISTENT}, + {"DeveloperSidebarMetric4", PERSISTENT}, + {"DeveloperSidebarMetric5", PERSISTENT}, + {"DeveloperSidebarMetric6", PERSISTENT}, + {"DeveloperSidebarMetric7", PERSISTENT}, + {"DeveloperWidgets", PERSISTENT}, {"DeveloperUI", PERSISTENT}, {"DeviceManagement", PERSISTENT}, {"DeviceShutdown", PERSISTENT}, @@ -344,7 +354,6 @@ std::unordered_map keys = { {"IncreasedStoppedDistance", PERSISTENT}, {"IncreaseThermalLimits", PERSISTENT}, {"IssueReported", CLEAR_ON_MANAGER_START}, - {"JerkInfo", PERSISTENT}, {"KonikDongleId", PERSISTENT}, {"KonikMinutes", PERSISTENT}, {"LaneChangeCustomizations", PERSISTENT}, @@ -527,7 +536,6 @@ std::unordered_map keys = { {"TrafficJerkSpeed", PERSISTENT}, {"TrafficJerkSpeedDecrease", PERSISTENT}, {"TrafficPersonalityProfile", PERSISTENT}, - {"TuningInfo", PERSISTENT}, {"TuningLevel", PERSISTENT}, {"TuningLevelConfirmed", PERSISTENT}, {"TurnAggressiveness", PERSISTENT}, diff --git a/frogpilot/assets/other_images/frogpilot_boot_logo.png b/frogpilot/assets/other_images/frogpilot_boot_logo.png index 2505b8cb5..8e96d7c2c 100644 Binary files a/frogpilot/assets/other_images/frogpilot_boot_logo.png and b/frogpilot/assets/other_images/frogpilot_boot_logo.png differ diff --git a/frogpilot/common/frogpilot_utilities.py b/frogpilot/common/frogpilot_utilities.py index c1d711a6c..da835781a 100644 --- a/frogpilot/common/frogpilot_utilities.py +++ b/frogpilot/common/frogpilot_utilities.py @@ -81,15 +81,18 @@ def calculate_lane_width(lane, current_lane, road_edge=None): current_y = np.asarray(current_lane.y) lane_y_interp = np.interp(current_x, np.asarray(lane.x), np.asarray(lane.y)) - distance_to_lane = np.mean(np.abs(current_y - lane_y_interp)) + if road_edge is None: return float(distance_to_lane) road_edge_y_interp = np.interp(current_x, np.asarray(road_edge.x), np.asarray(road_edge.y)) - distance_to_road_edge = np.mean(np.abs(current_y - road_edge_y_interp)) - return float(min(distance_to_lane, distance_to_road_edge)) + + if distance_to_road_edge < distance_to_lane: + return 0.0 + + return float(distance_to_lane) # Credit goes to Pfeiferj! def calculate_road_curvature(modelData, v_ego): diff --git a/frogpilot/common/frogpilot_variables.py b/frogpilot/common/frogpilot_variables.py index df99057a7..7e927298e 100644 --- a/frogpilot/common/frogpilot_variables.py +++ b/frogpilot/common/frogpilot_variables.py @@ -137,6 +137,16 @@ frogpilot_default_params: list[tuple[str, str | bytes, int]] = [ ("CustomSounds", "frog", 0), ("CustomUI", "1", 1), ("DecelerationProfile", "1", 2), + ("DeveloperMetrics", "1", 2), + ("DeveloperSidebar", "1", 2), + ("DeveloperSidebarMetric1", "1", 2), + ("DeveloperSidebarMetric2", "2", 2), + ("DeveloperSidebarMetric3", "3", 2), + ("DeveloperSidebarMetric4", "4", 2), + ("DeveloperSidebarMetric5", "5", 2), + ("DeveloperSidebarMetric6", "6", 2), + ("DeveloperSidebarMetric7", "7", 2), + ("DeveloperWidgets", "1", 2), ("DeveloperUI", "0", 2), ("DeviceManagement", "1", 1), ("DeviceShutdown", "9", 1), @@ -150,7 +160,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int]] = [ ("DynamicPedalsOnUI", "1", 2), ("EngageVolume", "101", 2), ("ExperimentalGMTune", "0", 2), - ("ExperimentalLongitudinalEnabled", "1", 0), + ("ExperimentalLongitudinalEnabled", "0", 0), ("ExperimentalMode", "0", 0), ("ExperimentalModeConfirmed", "0", 0), ("ExperimentalModels", "", 1), @@ -184,7 +194,6 @@ frogpilot_default_params: list[tuple[str, str | bytes, int]] = [ ("IncreaseThermalLimits", "0", 2), ("IsLdwEnabled", "0", 0), ("IsMetric", "0", 0), - ("JerkInfo", "0", 3), ("KonikDongleId", "", 3), ("KonikMinutes", "0", 0), ("LaneChangeCustomizations", "0", 0), @@ -345,7 +354,6 @@ frogpilot_default_params: list[tuple[str, str | bytes, int]] = [ ("TrafficJerkSpeed", "50", 3), ("TrafficJerkSpeedDecrease", "50", 3), ("TrafficPersonalityProfile", "1", 2), - ("TuningInfo", "0", 3), ("TuningLevel", "0", 0), ("TuningLevelConfirmed", "0", 0), ("TurnAggressiveness", "100", 2), @@ -366,8 +374,6 @@ frogpilot_default_params: list[tuple[str, str | bytes, int]] = [ ] misc_tuning_levels: list[tuple[str, str | bytes, int]] = [ - ("DeveloperMetrics", "", 2), - ("DeveloperWidgets", "", 2), ("SLCPriority", "", 2), ("WheelControls", "", 2) ] @@ -597,29 +603,37 @@ class FrogPilotVariables: toggle.rotating_wheel = custom_ui and (params.get_bool("RotatingWheel") if tuning_level >= level["RotatingWheel"] else default.get_bool("RotatingWheel")) toggle.developer_ui = params.get_bool("DeveloperUI") if tuning_level >= level["DeveloperUI"] else default.get_bool("DeveloperUI") - toggle.adjacent_lead_tracking = has_radar and ((params.get_bool("AdjacentLeadsUI") if tuning_level >= level["AdjacentLeadsUI"] else default.get_bool("AdjacentLeadsUI")) or toggle.debug_mode) - border_metrics = toggle.developer_ui and (params.get_bool("BorderMetrics") if tuning_level >= level["BorderMetrics"] else default.get_bool("BorderMetrics")) + developer_metrics = toggle.developer_ui and params.get_bool("DeveloperMetrics") if tuning_level >= level["DeveloperMetrics"] else default.get_bool("DeveloperMetrics") + border_metrics = developer_metrics and (params.get_bool("BorderMetrics") if tuning_level >= level["BorderMetrics"] else default.get_bool("BorderMetrics")) toggle.blind_spot_metrics = has_bsm and border_metrics and (params.get_bool("BlindSpotMetrics") if tuning_level >= level["BlindSpotMetrics"] else default.get_bool("BlindSpotMetrics")) or toggle.debug_mode toggle.signal_metrics = border_metrics and (params.get_bool("SignalMetrics") if tuning_level >= level["SignalMetrics"] else default.get_bool("SignalMetrics")) or toggle.debug_mode toggle.steering_metrics = border_metrics and (params.get_bool("ShowSteering") if tuning_level >= level["ShowSteering"] else default.get_bool("ShowSteering")) or toggle.debug_mode - toggle.show_fps = toggle.developer_ui and (params.get_bool("FPSCounter") if tuning_level >= level["FPSCounter"] else default.get_bool("FPSCounter")) or toggle.debug_mode - 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")) or toggle.debug_mode - toggle.lateral_tuning_metrics = (has_auto_tune or toggle.force_auto_tune) and lateral_metrics and (params.get_bool("TuningInfo") if tuning_level >= level["TuningInfo"] else default.get_bool("TuningInfo")) or toggle.debug_mode - longitudinal_metrics = openpilot_longitudinal and (toggle.developer_ui and (params.get_bool("LongitudinalMetrics") if tuning_level >= level["LongitudinalMetrics"] else default.get_bool("LongitudinalMetrics"))) - toggle.lead_metrics = longitudinal_metrics and (params.get_bool("LeadInfo") if tuning_level >= level["LeadInfo"] else default.get_bool("LeadInfo")) or toggle.debug_mode - toggle.jerk_metrics = longitudinal_metrics and (params.get_bool("JerkInfo") if tuning_level >= level["JerkInfo"] else default.get_bool("JerkInfo")) or toggle.debug_mode - toggle.numerical_temp = toggle.developer_ui and (params.get_bool("NumericalTemp") if tuning_level >= level["NumericalTemp"] else default.get_bool("NumericalTemp")) or toggle.debug_mode + toggle.show_fps = developer_metrics and (params.get_bool("FPSCounter") if tuning_level >= level["FPSCounter"] else default.get_bool("FPSCounter")) or toggle.debug_mode + toggle.adjacent_path_metrics = (developer_metrics and params.get_bool("AdjacentPathMetrics") if tuning_level >= level["AdjacentPathMetrics"] else default.get_bool("AdjacentPathMetrics")) or toggle.debug_mode + toggle.lead_metrics = (developer_metrics and params.get_bool("LeadInfo") if tuning_level >= level["LeadInfo"] else default.get_bool("LeadInfo")) or toggle.debug_mode + toggle.numerical_temp = developer_metrics and (params.get_bool("NumericalTemp") if tuning_level >= level["NumericalTemp"] else default.get_bool("NumericalTemp")) or toggle.debug_mode toggle.fahrenheit = toggle.numerical_temp and (params.get_bool("Fahrenheit") if tuning_level >= level["Fahrenheit"] else default.get_bool("Fahrenheit")) and not toggle.debug_mode - toggle.radar_tracks = has_radar and ((params.get_bool("RadarTracksUI") if tuning_level >= level["RadarTracksUI"] else default.get_bool("RadarTracksUI")) or toggle.debug_mode) - toggle.sidebar_metrics = toggle.developer_ui and (params.get_bool("SidebarMetrics") if tuning_level >= level["SidebarMetrics"] else default.get_bool("SidebarMetrics")) or toggle.debug_mode + toggle.sidebar_metrics = developer_metrics and (params.get_bool("SidebarMetrics") if tuning_level >= level["SidebarMetrics"] else default.get_bool("SidebarMetrics")) or toggle.debug_mode toggle.cpu_metrics = toggle.sidebar_metrics and (params.get_bool("ShowCPU") if tuning_level >= level["ShowCPU"] else default.get_bool("ShowCPU")) or toggle.debug_mode toggle.gpu_metrics = toggle.sidebar_metrics and (params.get_bool("ShowGPU") if tuning_level >= level["ShowGPU"] else default.get_bool("ShowGPU")) and not toggle.debug_mode toggle.ip_metrics = toggle.sidebar_metrics and (params.get_bool("ShowIP") if tuning_level >= level["ShowIP"] else default.get_bool("ShowIP")) toggle.memory_metrics = toggle.sidebar_metrics and (params.get_bool("ShowMemoryUsage") if tuning_level >= level["ShowMemoryUsage"] else default.get_bool("ShowMemoryUsage")) or toggle.debug_mode toggle.storage_left_metrics = toggle.sidebar_metrics and (params.get_bool("ShowStorageLeft") if tuning_level >= level["ShowStorageLeft"] else default.get_bool("ShowStorageLeft")) and not toggle.debug_mode toggle.storage_used_metrics = toggle.sidebar_metrics and (params.get_bool("ShowStorageUsed") if tuning_level >= level["ShowStorageUsed"] else default.get_bool("ShowStorageUsed")) and not toggle.debug_mode - toggle.use_si_metrics = toggle.developer_ui and (params.get_bool("UseSI") if tuning_level >= level["UseSI"] else default.get_bool("UseSI")) or toggle.debug_mode + toggle.use_si_metrics = developer_metrics and (params.get_bool("UseSI") if tuning_level >= level["UseSI"] else default.get_bool("UseSI")) or toggle.debug_mode + toggle.developer_sidebar = toggle.developer_ui and (params.get_bool("DeveloperSidebar") if tuning_level >= level["DeveloperSidebar"] else default.get_bool("DeveloperSidebar")) + toggle.developer_sidebar_metric1 = params.get_int("DeveloperSidebarMetric1") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric1"] else default.get_float("DeveloperSidebarMetric1") + toggle.developer_sidebar_metric2 = params.get_int("DeveloperSidebarMetric2") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric2"] else default.get_float("DeveloperSidebarMetric2") + toggle.developer_sidebar_metric3 = params.get_int("DeveloperSidebarMetric3") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric3"] else default.get_float("DeveloperSidebarMetric3") + toggle.developer_sidebar_metric4 = params.get_int("DeveloperSidebarMetric4") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric4"] else default.get_float("DeveloperSidebarMetric4") + toggle.developer_sidebar_metric5 = params.get_int("DeveloperSidebarMetric5") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric5"] else default.get_float("DeveloperSidebarMetric5") + toggle.developer_sidebar_metric6 = params.get_int("DeveloperSidebarMetric6") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric6"] else default.get_float("DeveloperSidebarMetric6") + toggle.developer_sidebar_metric7 = params.get_int("DeveloperSidebarMetric7") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric7"] else default.get_float("DeveloperSidebarMetric7") + developer_widgets = toggle.developer_ui and params.get_bool("DeveloperWidgets") if tuning_level >= level["DeveloperWidgets"] else default.get_bool("DeveloperWidgets") + toggle.adjacent_lead_tracking = has_radar and ((developer_widgets and params.get_bool("AdjacentLeadsUI") if tuning_level >= level["AdjacentLeadsUI"] else default.get_bool("AdjacentLeadsUI")) or toggle.debug_mode) + toggle.radar_tracks = has_radar and ((developer_widgets and params.get_bool("RadarTracksUI") if tuning_level >= level["RadarTracksUI"] else default.get_bool("RadarTracksUI")) or toggle.debug_mode) + toggle.show_stopping_point = openpilot_longitudinal and (developer_widgets and (params.get_bool("ShowStoppingPoint") if tuning_level >= level["ShowStoppingPoint"] else default.get_bool("ShowStoppingPoint")) or toggle.debug_mode) + toggle.show_stopping_point_metrics = toggle.show_stopping_point and (params.get_bool("ShowStoppingPointMetrics") if tuning_level >= level["ShowStoppingPointMetrics"] else default.get_bool("ShowStoppingPointMetrics") or toggle.debug_mode) device_management = params.get_bool("DeviceManagement") if tuning_level >= level["DeviceManagement"] else default.get_bool("DeviceManagement") device_shutdown_setting = params.get_int("DeviceShutdown") if device_management and tuning_level >= level["DeviceShutdown"] else default.get_int("DeviceShutdown") @@ -752,8 +766,6 @@ class FrogPilotVariables: toggle.path_edge_width = params.get_int("PathEdgeWidth") if toggle.model_ui and tuning_level >= level["PathEdgeWidth"] else default.get_int("PathEdgeWidth") toggle.path_width = params.get_float("PathWidth") * distance_conversion / 2 if toggle.model_ui and tuning_level >= level["PathWidth"] else default.get_float("PathWidth") * CV.FOOT_TO_METER / 2 toggle.road_edge_width = params.get_int("RoadEdgesWidth") * small_distance_conversion / 200 if toggle.model_ui and tuning_level >= level["RoadEdgesWidth"] else default.get_int("RoadEdgesWidth") * CV.INCH_TO_CM / 200 - toggle.show_stopping_point = openpilot_longitudinal and (toggle.model_ui and (params.get_bool("ShowStoppingPoint") if tuning_level >= level["ShowStoppingPoint"] else default.get_bool("ShowStoppingPoint")) or toggle.debug_mode) - toggle.show_stopping_point_metrics = toggle.show_stopping_point and (params.get_bool("ShowStoppingPointMetrics") if tuning_level >= level["ShowStoppingPointMetrics"] else default.get_bool("ShowStoppingPointMetrics") or toggle.debug_mode) toggle.unlimited_road_ui_length = toggle.model_ui and (params.get_bool("UnlimitedLength") if tuning_level >= level["UnlimitedLength"] else default.get_bool("UnlimitedLength")) toggle.navigation_ui = params.get_bool("NavigationUI") if tuning_level >= level["NavigationUI"] else default.get_bool("NavigationUI") diff --git a/frogpilot/controls/frogpilot_planner.py b/frogpilot/controls/frogpilot_planner.py index bfcdd10fc..e97a45f0c 100644 --- a/frogpilot/controls/frogpilot_planner.py +++ b/frogpilot/controls/frogpilot_planner.py @@ -173,6 +173,8 @@ class FrogPilotPlanner: frogpilotPlan.togglesUpdated = toggles_updated + frogpilotPlan.trackingLead = self.tracking_lead + frogpilotPlan.vCruise = self.v_cruise pm.send("frogpilotPlan", frogpilot_plan_send) diff --git a/frogpilot/controls/lib/frogpilot_vcruise.py b/frogpilot/controls/lib/frogpilot_vcruise.py index 98a0a5ba9..a0d685f8e 100644 --- a/frogpilot/controls/lib/frogpilot_vcruise.py +++ b/frogpilot/controls/lib/frogpilot_vcruise.py @@ -1,6 +1,4 @@ #!/usr/bin/env python3 -import numpy as np - from openpilot.common.realtime import DT_MDL from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE @@ -47,7 +45,7 @@ class FrogPilotVCruise: if not self.frogpilot_planner.frogpilot_following.following_lead and self.linear_braking_active: decel_rate = (v_ego - self.frogpilot_planner.lead_one.vLead)**2 / self.frogpilot_planner.lead_one.dRel - self.braking_target = float(np.clip(v_ego - (decel_rate * DT_MDL), self.frogpilot_planner.lead_one.vLead + CRUISING_SPEED, v_cruise)) + self.braking_target = max(v_ego - (decel_rate * DT_MDL), self.frogpilot_planner.lead_one.vLead + CRUISING_SPEED) else: self.braking_target = v_cruise else: @@ -65,7 +63,7 @@ class FrogPilotVCruise: self.mtsc_target = v_cruise else: mtsc_speed = ((TARGET_LAT_A * frogpilot_toggles.turn_aggressiveness) / (self.mtsc.get_map_curvature(gps_position, v_ego) * frogpilot_toggles.curve_sensitivity))**0.5 - self.mtsc_target = float(np.clip(mtsc_speed, CRUISING_SPEED, v_cruise)) + self.mtsc_target = max(CRUISING_SPEED, mtsc_speed) else: self.mtsc_target = v_cruise @@ -89,8 +87,8 @@ class FrogPilotVCruise: # Pfeiferj's Vision Turn Controller if v_ego > CRUISING_SPEED and sm["controlsState"].enabled and self.frogpilot_planner.road_curvature_detected and frogpilot_toggles.vision_turn_speed_controller: - self.vtsc_target = ((TARGET_LAT_A * frogpilot_toggles.turn_aggressiveness) / (abs(self.frogpilot_planner.road_curvature) * frogpilot_toggles.curve_sensitivity))**0.5 - self.vtsc_target = float(np.clip(self.vtsc_target, CRUISING_SPEED, v_cruise)) + vtsc_speed = ((TARGET_LAT_A * frogpilot_toggles.turn_aggressiveness) / (abs(self.frogpilot_planner.road_curvature) * frogpilot_toggles.curve_sensitivity))**0.5 + self.vtsc_target = max(CRUISING_SPEED, vtsc_speed) else: self.vtsc_target = v_cruise @@ -110,7 +108,7 @@ class FrogPilotVCruise: self.tracked_model_length = self.frogpilot_planner.model_length - targets = [self.braking_target, self.mtsc_target, self.vtsc_target] + targets = [self.braking_target, self.mtsc_target, self.vtsc_target, v_cruise] if frogpilot_toggles.speed_limit_controller: targets.append(max(self.slc.overridden_speed, self.slc_target + self.slc_offset)) diff --git a/frogpilot/controls/lib/speed_limit_controller.py b/frogpilot/controls/lib/speed_limit_controller.py index 4509eca39..63b03257a 100644 --- a/frogpilot/controls/lib/speed_limit_controller.py +++ b/frogpilot/controls/lib/speed_limit_controller.py @@ -300,7 +300,7 @@ class SpeedLimitController: if self.override_slc: if self.frogpilot_toggles.speed_limit_controller_override_manual: if sm["carState"].gasPressed: - self.overridden_speed = v_ego + self.overridden_speed = max(v_ego, self.overridden_speed) self.overridden_speed = float(np.clip(self.overridden_speed, self.target + self.offset, v_cruise)) elif self.frogpilot_toggles.speed_limit_controller_override_set_speed: self.overridden_speed = v_cruise diff --git a/frogpilot/system/fleetmanager/static/frog.png b/frogpilot/system/fleetmanager/static/frog.png index 5285f0be6..aab72c37a 100644 Binary files a/frogpilot/system/fleetmanager/static/frog.png and b/frogpilot/system/fleetmanager/static/frog.png differ diff --git a/frogpilot/system/verify_panda.py b/frogpilot/system/verify_panda.py deleted file mode 100644 index 450dfab8e..000000000 --- a/frogpilot/system/verify_panda.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 -from time import sleep - -from panda import Panda - -BODY_CAN_IDS = {0x750, 0x752, 0x660, 0x285} - -def hw_name(hw_type): - names = { - Panda.HW_TYPE_WHITE_PANDA: 'white', - Panda.HW_TYPE_GREY_PANDA: 'grey', - Panda.HW_TYPE_BLACK_PANDA: 'black', - Panda.HW_TYPE_UNO: 'uno', - Panda.HW_TYPE_DOS: 'dos', - Panda.HW_TYPE_RED_PANDA: 'red', - Panda.HW_TYPE_RED_PANDA_V2: 'red v2', - Panda.HW_TYPE_TRES: 'tres', - Panda.HW_TYPE_CUATRO: 'cuatro', - } - return names.get(hw_type, 'unknown') - -def expected_body_bus(hw_type, flipped): - if hw_type in Panda.H7_DEVICES: - return 1 if flipped else 0 - if hw_type in (Panda.HW_TYPE_UNO, Panda.HW_TYPE_DOS, Panda.HW_TYPE_BLACK_PANDA): - return 1 - return None - -def scan_can(panda, secs=1): - seen = set() - end = panda.get_microsecond_timer() + secs * 1_000_000 - while panda.get_microsecond_timer() < end: - for addr, _, _, bus in panda.can_recv(): - if addr in BODY_CAN_IDS: - seen.add(bus) - return sorted(seen) - -def main(): - serials = Panda.list() - print(f'Found {len(serials)} panda(serial): {serials}\n') - - for serial in serials: - with Panda(serial, claim=False) as panda: - hw_type = panda.get_type() - if isinstance(hw_type, bytearray): - hw_type = bytes(hw_type) - flipped = panda.health()['car_harness_status'] == Panda.HARNESS_STATUS_FLIPPED - body_bus = expected_body_bus(hw_type, flipped) - - print(f'Panda {serial[:8]}…') - print(f' hw: {hw_name(hw_type)}, mcu: {"H7" if hw_type in Panda.H7_DEVICES else "F4"}') - print(f' harness flipped: {flipped}') - print(f' expected Toyota body bus: {body_bus}') - print(' sniffing CAN for one second…') - buses = scan_can(panda) - print(f' body-CAN traffic seen on: {buses}\n') - -if __name__ == '__main__': - main() diff --git a/frogpilot/ui/frogpilot_ui.cc b/frogpilot/ui/frogpilot_ui.cc index 502b90d07..6a45044a0 100644 --- a/frogpilot/ui/frogpilot_ui.cc +++ b/frogpilot/ui/frogpilot_ui.cc @@ -56,7 +56,8 @@ void update_theme(FrogPilotUIState *fs) { FrogPilotUIState::FrogPilotUIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "carControl", "carState", "controlsState", "deviceState", "frogpilotCarState", "frogpilotDeviceState", - "frogpilotNavigation", "frogpilotPlan", "liveTracks", "navInstruction" + "frogpilotNavigation", "frogpilotPlan", "liveDelay", "liveParameters", "liveTorqueParameters", "liveTracks", + "navInstruction" }); wifi = new WifiManager(this); diff --git a/frogpilot/ui/qt/offroad/frogpilot_settings.cc b/frogpilot/ui/qt/offroad/frogpilot_settings.cc index 219a66e41..89b5c4eba 100644 --- a/frogpilot/ui/qt/offroad/frogpilot_settings.cc +++ b/frogpilot/ui/qt/offroad/frogpilot_settings.cc @@ -140,7 +140,7 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram "../../frogpilot/assets/toggle_icons/icon_customization.png", togglePresets, true); - int timeTo100FPHours = 100 - (paramsTracking.getInt("FrogPilotMinutes") / 60); + int timeTo100FPHours = 100 - (params_tracking.getInt("FrogPilotMinutes") / 60); int timeTo250OPHours = 250 - (params.getInt("KonikMinutes") / 60) - (params.getInt("openpilotMinutes") / 60); togglePreset->setEnabledButtons(3, timeTo100FPHours <= 0 || timeTo250OPHours <= 0); diff --git a/frogpilot/ui/qt/offroad/frogpilot_settings.h b/frogpilot/ui/qt/offroad/frogpilot_settings.h index 065d4d516..cff7bf236 100644 --- a/frogpilot/ui/qt/offroad/frogpilot_settings.h +++ b/frogpilot/ui/qt/offroad/frogpilot_settings.h @@ -66,7 +66,7 @@ private: Params params; Params params_memory{"/dev/shm/params"}; - Params paramsTracking{"/cache/tracking"}; + Params params_tracking{"/cache/tracking"}; QStackedLayout *mainLayout; diff --git a/frogpilot/ui/qt/offroad/lateral_settings.cc b/frogpilot/ui/qt/offroad/lateral_settings.cc index 5f9c2c0c3..c85ad2d8f 100644 --- a/frogpilot/ui/qt/offroad/lateral_settings.cc +++ b/frogpilot/ui/qt/offroad/lateral_settings.cc @@ -275,7 +275,7 @@ void FrogPilotLateralPanel::updateMetric(bool metric, bool bootRun) { } for (int i = 0; i <= 99; ++i) { - imperialSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr("mph"); + imperialSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr(" mph"); } for (int i = 0; i <= 50; ++i) { @@ -284,7 +284,7 @@ void FrogPilotLateralPanel::updateMetric(bool metric, bool bootRun) { } for (int i = 0; i <= 150; ++i) { - metricSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr("km/h"); + metricSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr(" km/h"); } labelsInitialized = true; diff --git a/frogpilot/ui/qt/offroad/longitudinal_settings.cc b/frogpilot/ui/qt/offroad/longitudinal_settings.cc index 96cdaf2b6..1f2e872e2 100644 --- a/frogpilot/ui/qt/offroad/longitudinal_settings.cc +++ b/frogpilot/ui/qt/offroad/longitudinal_settings.cc @@ -228,8 +228,8 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * }); longitudinalToggle = conditionalExperimentalToggle; } else if (param == "CESpeed") { - FrogPilotParamValueControl *CESpeed = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1, true, true); - FrogPilotParamValueControl *CESpeedLead = new FrogPilotParamValueControl("CESpeedLead", tr("With Lead"), tr("Switch to Experimental Mode when driving below this speed with a lead."), icon, 0, 99, tr("mph"), std::map(), 1, true, true); + FrogPilotParamValueControl *CESpeed = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map(), 1, true, true); + FrogPilotParamValueControl *CESpeedLead = new FrogPilotParamValueControl("CESpeedLead", tr("With Lead"), tr("Switch to Experimental Mode when driving below this speed with a lead."), icon, 0, 99, tr(" mph"), std::map(), 1, true, true); FrogPilotDualParamValueControl *conditionalSpeeds = new FrogPilotDualParamValueControl(CESpeed, CESpeedLead); longitudinalToggle = reinterpret_cast(conditionalSpeeds); } else if (param == "CECurves") { @@ -253,7 +253,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * } else if (param == "CESignalSpeed") { std::vector ceSignalToggles{"CESignalLaneDetection"}; std::vector ceSignalToggleNames{"Only For Detected Lanes"}; - longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr("mph"), std::map(), 1.0, true, ceSignalToggles, ceSignalToggleNames, true); + longitudinalToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map(), 1.0, true, ceSignalToggles, ceSignalToggleNames, true); } else if (param == "CurveSpeedControl") { FrogPilotManageControl *curveControlToggle = new FrogPilotManageControl(param, title, desc, icon); @@ -303,7 +303,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * } else if (param == "LeadDetectionThreshold") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, "%"); } else if (param == "MaxDesiredAcceleration") { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.1, 4.0, "m/s", std::map(), 0.1); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0.1, 4.0, tr(" m/s²"), std::map(), 0.1); } else if (param == "QOLLongitudinal") { FrogPilotManageControl *qolLongitudinalToggle = new FrogPilotManageControl(param, title, desc, icon); @@ -312,9 +312,9 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * }); longitudinalToggle = qolLongitudinalToggle; } else if (param == "CustomCruise") { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, tr("mph")); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, tr(" mph")); } else if (param == "CustomCruiseLong") { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, tr("mph")); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 99, tr(" mph")); } else if (param == "IncreasedStoppedDistance") { longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet")); } else if (param == "MapGears") { @@ -322,7 +322,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * std::vector mapGearsToggleNames{tr("Acceleration"), tr("Deceleration")}; longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, mapGearsToggles, mapGearsToggleNames); } else if (param == "SetSpeedOffset") { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr("mph")); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph")); } else if (param == "SpeedLimitController") { FrogPilotManageControl *speedLimitControllerToggle = new FrogPilotManageControl(param, title, desc, icon); @@ -405,7 +405,7 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow * }); longitudinalToggle = manageSLCOffsetsBtn; } else if (speedLimitControllerOffsetsKeys.find(param) != speedLimitControllerOffsetsKeys.end()) { - longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, -99, 99, tr("mph")); + longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, -99, 99, tr(" mph")); } else if (param == "SLCQOL") { ButtonControl *manageSLCQOLBtn = new ButtonControl(title, tr("MANAGE"), desc); QObject::connect(manageSLCQOLBtn, &ButtonControl::clicked, [this, longitudinalLayout, speedLimitControllerQOLPanel]() { @@ -732,7 +732,7 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) { } for (int i = 0; i <= 99; ++i) { - imperialSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr("mph"); + imperialSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr(" mph"); } for (int i = 0; i <= 3; ++i) { @@ -740,7 +740,7 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) { } for (int i = 0; i <= 150; ++i) { - metricSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr("km/h"); + metricSpeedLabels[i] = i == 0 ? tr("Off") : QString::number(i) + tr(" km/h"); } labelsInitialized = true; diff --git a/frogpilot/ui/qt/offroad/visual_settings.cc b/frogpilot/ui/qt/offroad/visual_settings.cc index 3fa00dc32..d97db7e31 100644 --- a/frogpilot/ui/qt/offroad/visual_settings.cc +++ b/frogpilot/ui/qt/offroad/visual_settings.cc @@ -13,6 +13,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget *advancedCustomList = new FrogPilotListWidget(this); FrogPilotListWidget *customUIList = new FrogPilotListWidget(this); FrogPilotListWidget *developerMetricList = new FrogPilotListWidget(this); + FrogPilotListWidget *developerSidebarList = new FrogPilotListWidget(this); FrogPilotListWidget *developerUIList = new FrogPilotListWidget(this); FrogPilotListWidget *developerWidgetList = new FrogPilotListWidget(this); FrogPilotListWidget *modelUIList = new FrogPilotListWidget(this); @@ -22,6 +23,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : ScrollView *advancedCustomPanel = new ScrollView(advancedCustomList, this); ScrollView *customUIPanel = new ScrollView(customUIList, this); ScrollView *developerMetricPanel = new ScrollView(developerMetricList, this); + ScrollView *developerSidebarPanel = new ScrollView(developerSidebarList, this); ScrollView *developerUIPanel = new ScrollView(developerUIList, this); ScrollView *developerWidgetPanel = new ScrollView(developerWidgetList, this); ScrollView *modelUIPanel = new ScrollView(modelUIList, this); @@ -31,6 +33,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : visualsLayout->addWidget(advancedCustomPanel); visualsLayout->addWidget(customUIPanel); visualsLayout->addWidget(developerMetricPanel); + visualsLayout->addWidget(developerSidebarPanel); visualsLayout->addWidget(developerUIPanel); visualsLayout->addWidget(developerWidgetPanel); visualsLayout->addWidget(modelUIPanel); @@ -48,14 +51,22 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : {"WheelSpeed", tr("Use Wheel Speed"), tr("Use the vehicle's wheel speed instead of the cluster speed. This is purely a visual change and doesn't impact how openpilot drives."), ""}, {"DeveloperUI", tr("Developer UI"), tr("Detailed information about openpilot's internal operations."), "../assets/offroad/icon_shell.png"}, + {"AdjacentPathMetrics", tr("Adjacent Path Metrics"), tr("Metrics displayed on top of the adjacent lanes measuring their current width."), ""}, {"DeveloperMetrics", tr("Developer Metrics"), tr("Performance data, sensor readings, and system metrics for debugging and optimizing openpilot."), ""}, {"BorderMetrics", tr("Border Metrics"), tr("Metrics displayed around the border of the driving screen.

Blind Spot: Turn the border red when a vehicle is detected in a blind spot
Steering Torque: Highlight the border green to red in accordance to the amount of steering torque being used
Turn Signal: Flash the border yellow when a turn signal is active"), ""}, + {"LeadInfo", tr("Lead Info"), tr("Metrics displayed under vehicle markers listing their distance and current speed."), ""}, {"FPSCounter", tr("FPS Display"), tr("Display the Frames Per Second (FPS) at the bottom of the driving screen."), ""}, - {"LateralMetrics", tr("Lateral Metrics"), tr("Metrics related to steering control.

Adjacent Path Metrics: Paint the adjacent lanes and their width measurements
Auto Tune: Display the Friction and Lateral Acceleration values from comma's auto tune at the top of the driving screen"), ""}, - {"LongitudinalMetrics", tr("Longitudinal Metrics"), tr("Metrics related to gas/brake control.

Lead Info: Display the lead vehicle's distance and speed on the lead marker
Jerk Values: Display the current longitudinal jerk values and any offsets from FrogPilot functions at the top of the driving screen"), ""}, {"NumericalTemp", tr("Numerical Temperature Gauge"), tr("Use numerical temperature readings instead of status labels in the sidebar."), ""}, {"SidebarMetrics", tr("Sidebar"), tr("Display system information (CPU, GPU, RAM usage, IP address, device storage) in the sidebar."), ""}, {"UseSI", tr("Use International System of Units"), tr("Display measurements using the International System of Units (SI) standard."), ""}, + {"DeveloperSidebar", tr("Developer Sidebar"), tr("Display debugging info and metrics in a dedicated sidebar on the right side of the screen."), ""}, + {"DeveloperSidebarMetric1", tr("Metric #1"), tr("Metric to display in the first metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric2", tr("Metric #2"), tr("Metric to display in the second metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric3", tr("Metric #3"), tr("Metric to display in the third metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric4", tr("Metric #4"), tr("Metric to display in the fourth metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric5", tr("Metric #5"), tr("Metric to display in the fifth metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric6", tr("Metric #6"), tr("Metric to display in the sixth metric in the \"Developer Sidebar\"."), ""}, + {"DeveloperSidebarMetric7", tr("Metric #7"), tr("Metric to display in the seventh metric in the \"Developer Sidebar\"."), ""}, {"DeveloperWidgets", tr("Developer Widgets"), tr("Overlays displaying debugging visuals, internal states, and model predictions on the driving screen."), ""}, {"AdjacentLeadsUI", tr("Adjacent Leads Tracking"), tr("Adjacent leads detected by the car's radar to the left and right of the current driving path."), ""}, {"ShowStoppingPoint", tr("Model Stopping Point"), tr("Display an image on the screen where openpilot is wanting to stop."), ""}, @@ -109,8 +120,8 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : }); visualToggle = developerUIToggle; } else if (param == "DeveloperMetrics") { - ButtonControl *developerMetricsToggle = new ButtonControl(title, tr("MANAGE"), desc); - QObject::connect(developerMetricsToggle, &ButtonControl::clicked, [this, visualsLayout, developerMetricPanel]() { + FrogPilotManageControl *developerMetricsToggle = new FrogPilotManageControl(param, title, desc, icon); + QObject::connect(developerMetricsToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerMetricPanel]() { openSubSubPanel(); visualsLayout->setCurrentWidget(developerMetricPanel); @@ -123,16 +134,6 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : std::vector borderToggleNames{tr("Blind Spot"), tr("Steering Torque"), tr("Turn Signal")}; borderMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, icon, borderToggles, borderToggleNames); visualToggle = borderMetricsBtn; - } else if (param == "LateralMetrics") { - std::vector lateralToggles{"AdjacentPathMetrics", "TuningInfo"}; - std::vector lateralToggleNames{tr("Adjacent Path Metrics"), tr("Auto Tune")}; - lateralMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, icon, lateralToggles, lateralToggleNames); - visualToggle = lateralMetricsBtn; - } else if (param == "LongitudinalMetrics") { - std::vector longitudinalToggles{"LeadInfo", "JerkInfo"}; - std::vector longitudinalToggleNames{tr("Lead Info"), tr("Jerk Values")}; - longitudinalMetricsBtn = new FrogPilotButtonToggleControl(param, title, desc, icon, longitudinalToggles, longitudinalToggleNames); - visualToggle = longitudinalMetricsBtn; } else if (param == "NumericalTemp") { std::vector temperatureToggles{"Fahrenheit"}; std::vector temperatureToggleNames{tr("Fahrenheit")}; @@ -159,9 +160,54 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : sidebarMetricsToggle->refresh(); }); visualToggle = sidebarMetricsToggle; + } else if (param == "DeveloperSidebar") { + FrogPilotManageControl *developerSidebarToggle = new FrogPilotManageControl(param, title, desc, icon); + QObject::connect(developerSidebarToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerSidebarPanel]() { + openSubSubPanel(); + + visualsLayout->setCurrentWidget(developerSidebarPanel); + + developerUIOpen = true; + }); + visualToggle = developerSidebarToggle; + } else if (developerSidebarKeys.find(param) != developerSidebarKeys.end()) { + QMap developerSidebarMetricOptions { + {0, tr("None")}, + {1, tr("Acceleration: Current")}, + {2, tr("Acceleration: Max")}, + {3, tr("Auto Tune: Actuator Delay")}, + {4, tr("Auto Tune: Friction")}, + {5, tr("Auto Tune: Lateral Acceleration")}, + {6, tr("Auto Tune: Steer Ratio")}, + {7, tr("Auto Tune: Stiffness Factor")}, + {8, tr("Engagement %: Lateral")}, + {9, tr("Engagement %: Longitudinal")}, + {10, tr("Lateral Control: Steering Angle")}, + {11, tr("Lateral Control: Torque % Used")}, + {12, tr("Longitudinal Control: Actuator Acceleration Output")}, + {13, tr("Longitudinal MPC Jerk: Acceleration")}, + {14, tr("Longitudinal MPC Jerk: Danger Zone")}, + {15, tr("Longitudinal MPC Jerk: Speed Control")}, + }; + + ButtonControl *metricToggle = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(metricToggle, &ButtonControl::clicked, [this, metricToggle, key = param, developerSidebarMetricOptions]() mutable { + QString current = developerSidebarMetricOptions.value(params.getInt(key.toStdString()), tr("None")); + QString selection = MultiOptionDialog::getSelection(tr("Select a metric to display"), developerSidebarMetricOptions.values(), current, this); + + if (!selection.isEmpty()) { + int selectedMetric = developerSidebarMetricOptions.key(selection); + + params.putInt(key.toStdString(), selectedMetric); + + metricToggle->setValue(selection); + } + }); + metricToggle->setValue(developerSidebarMetricOptions.value(params.getInt(param.toStdString()), tr("None"))); + visualToggle = metricToggle; } else if (param == "DeveloperWidgets") { - ButtonControl *developerWidgetsToggle = new ButtonControl(title, tr("MANAGE"), desc); - QObject::connect(developerWidgetsToggle, &ButtonControl::clicked, [this, visualsLayout, developerWidgetPanel]() { + FrogPilotManageControl *developerWidgetsToggle = new FrogPilotManageControl(param, title, desc, icon); + QObject::connect(developerWidgetsToggle, &FrogPilotManageControl::manageButtonClicked, [this, visualsLayout, developerWidgetPanel]() { openSubSubPanel(); visualsLayout->setCurrentWidget(developerWidgetPanel); @@ -274,6 +320,8 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) : customUIList->addItem(visualToggle); } else if (developerMetricKeys.find(param) != developerMetricKeys.end()) { developerMetricList->addItem(visualToggle); + } else if (developerSidebarKeys.find(param) != developerSidebarKeys.end()) { + developerSidebarList->addItem(visualToggle); } else if (developerUIKeys.find(param) != developerUIKeys.end()) { developerUIList->addItem(visualToggle); } else if (developerWidgetKeys.find(param) != developerWidgetKeys.end()) { @@ -413,7 +461,7 @@ void FrogPilotVisualsPanel::updateToggles() { setVisible &= hasOpenpilotLongitudinal; } - if (key == "LongitudinalMetrics") { + if (key == "LeadInfo") { setVisible &= hasOpenpilotLongitudinal; } @@ -461,8 +509,6 @@ void FrogPilotVisualsPanel::updateToggles() { } borderMetricsBtn->setVisibleButton(0, hasBSM); - lateralMetricsBtn->setVisibleButton(1, hasAutoTune); - longitudinalMetricsBtn->setVisibleButton(1, tuningLevel >= frogpilotToggleLevels["JerkInfo"].toDouble()); update(); } diff --git a/frogpilot/ui/qt/offroad/visual_settings.h b/frogpilot/ui/qt/offroad/visual_settings.h index a7387440f..649c963b2 100644 --- a/frogpilot/ui/qt/offroad/visual_settings.h +++ b/frogpilot/ui/qt/offroad/visual_settings.h @@ -33,8 +33,9 @@ private: std::set advancedCustomOnroadUIKeys = {"HideAlerts", "HideLeadMarker", "HideMapIcon", "HideMaxSpeed", "HideSpeed", "HideSpeedLimit", "WheelSpeed"}; std::set customOnroadUIKeys = {"AccelerationPath", "AdjacentPath", "BlindSpotPath", "Compass", "OnroadDistanceButton", "PedalsOnUI", "RotatingWheel"}; - std::set developerMetricKeys = {"BorderMetrics", "FPSCounter", "LateralMetrics", "LongitudinalMetrics", "NumericalTemp", "SidebarMetrics", "UseSI"}; - std::set developerUIKeys = {"DeveloperMetrics", "DeveloperWidgets"}; + std::set developerMetricKeys = {"AdjacentPathMetrics", "BorderMetrics", "FPSCounter", "LeadInfo", "NumericalTemp", "SidebarMetrics", "UseSI"}; + std::set developerSidebarKeys = {"DeveloperSidebarMetric1", "DeveloperSidebarMetric2", "DeveloperSidebarMetric3", "DeveloperSidebarMetric4", "DeveloperSidebarMetric5", "DeveloperSidebarMetric6", "DeveloperSidebarMetric7"}; + std::set developerUIKeys = {"DeveloperMetrics", "DeveloperSidebar", "DeveloperWidgets"}; std::set developerWidgetKeys = {"AdjacentLeadsUI", "RadarTracksUI", "ShowStoppingPoint"}; std::set modelUIKeys = {"DynamicPathWidth", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; std::set navigationUIKeys = {"BigMap", "MapStyle", "RoadNameUI", "ShowSpeedLimits", "UseVienna"}; @@ -43,8 +44,6 @@ private: std::set parentKeys; FrogPilotButtonToggleControl *borderMetricsBtn; - FrogPilotButtonToggleControl *lateralMetricsBtn; - FrogPilotButtonToggleControl *longitudinalMetricsBtn; FrogPilotSettingsWindow *parent; diff --git a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.cc b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.cc index 8df0b6130..5e676fdd4 100644 --- a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.cc +++ b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.cc @@ -40,17 +40,17 @@ void FrogPilotAnnotatedCameraWidget::showEvent(QShowEvent *event) { UIScene &scene = s.scene; if (scene.is_metric || frogpilot_toggles.value("use_si_metrics").toBool()) { - accelerationUnit = tr("m/s²"); - leadDistanceUnit = tr("meters"); - leadSpeedUnit = frogpilot_toggles.value("use_si_metrics").toBool() ? tr("m/s") : tr("km/h"); + accelerationUnit = tr(" m/s²"); + leadDistanceUnit = tr(" meters"); + leadSpeedUnit = frogpilot_toggles.value("use_si_metrics").toBool() ? tr(" m/s") : tr(" km/h"); distanceConversion = 1.0f; speedConversion = scene.is_metric ? MS_TO_KPH : MS_TO_MPH; speedConversionMetrics = frogpilot_toggles.value("use_si_metrics").toBool() ? 1.0f : MS_TO_KPH; } else { - accelerationUnit = tr("ft/s²"); - leadDistanceUnit = tr("feet"); - leadSpeedUnit = tr("mph"); + accelerationUnit = tr(" ft/s²"); + leadDistanceUnit = tr(" feet"); + leadSpeedUnit = tr(" mph"); distanceConversion = METER_TO_FOOT; speedConversion = MS_TO_MPH; @@ -132,9 +132,9 @@ void FrogPilotAnnotatedCameraWidget::updateState(const FrogPilotUIState &fs, con float speedLimitOffset = frogpilotPlan.getSlcSpeedLimitOffset() * speedConversion; - mtscSpeedStr = (frogpilotPlan.getMtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getMtscSpeed()))) + speedUnit : "–"; + mtscSpeedStr = (frogpilotPlan.getMtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getMtscSpeed() * speedConversion))) + speedUnit : "–"; speedLimitOffsetStr = (speedLimitOffset != 0) ? QString::number(speedLimitOffset, 'f', 0).prepend((speedLimitOffset > 0) ? "+" : "-") : "–"; - vtscSpeedStr = (frogpilotPlan.getVtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getVtscSpeed()))) + speedUnit : "–"; + vtscSpeedStr = (frogpilotPlan.getVtscSpeed() != 0) ? QString::number(std::nearbyint(fmin(speed, frogpilotPlan.getVtscSpeed() * speedConversion))) + speedUnit : "–"; if (frogpilot_scene.standstill && frogpilot_toggles.value("stopped_timer").toBool()) { if (!standstillTimer.isValid()) { @@ -226,7 +226,7 @@ void FrogPilotAnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p, UIState } } -void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const cereal::ModelDataV2::Reader &model, const UIScene &scene, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles) { +void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles) { std::function drawAdjacentPath = [this, &p, &frogpilot_toggles](bool isBlindSpot, float width, float requirement, const QPolygonF &polygon) { QLinearGradient gradient(0, height(), 0, 0); if (isBlindSpot && frogpilot_toggles.value("blind_spot_path").toBool()) { @@ -254,7 +254,7 @@ void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cerea p.drawText(polygon.boundingRect(), Qt::AlignCenter, text); }; - if (frogpilot_scene.lane_width_left != 0 && frogpilot_scene.track_adjacent_vertices[0][0].y() > scene.road_edge_vertices[0][0].y()) { + if (frogpilot_scene.lane_width_left >= frogpilot_toggles.value("lane_detection_width").toDouble()) { p.save(); drawAdjacentPath(carState.getLeftBlindspot(), frogpilot_scene.lane_width_left, frogpilot_toggles.value("lane_detection_width").toDouble(), frogpilot_scene.track_adjacent_vertices[0]); @@ -266,7 +266,7 @@ void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cerea p.restore(); } - if (frogpilot_scene.lane_width_right != 0 && frogpilot_scene.track_adjacent_vertices[1][0].y() < scene.road_edge_vertices[1][0].y()) { + if (frogpilot_scene.lane_width_right >= frogpilot_toggles.value("lane_detection_width").toDouble()) { p.save(); drawAdjacentPath(carState.getRightBlindspot(), frogpilot_scene.lane_width_right, frogpilot_toggles.value("lane_detection_width").toDouble(), frogpilot_scene.track_adjacent_vertices[1]); @@ -472,20 +472,25 @@ void FrogPilotAnnotatedCameraWidget::paintCurveSpeedControl(QPainter &p, const c p.setOpacity(1.0); - if ((setSpeed - frogpilotPlan.getMtscSpeed() > 1) && frogpilot_toggles.value("map_turn_speed_controller").toBool()) { + if (frogpilotPlan.getVCruise() == frogpilotPlan.getMtscSpeed() && frogpilot_toggles.value("map_turn_speed_controller").toBool()) { QRect mtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), frogpilotPlan.getVtscControllingCurve() ? 50 : 100)); drawCurveSpeedControl(mtscRect, mtscSpeedStr, true); - if ((setSpeed - frogpilotPlan.getVtscSpeed() > 1) && frogpilot_toggles.value("vision_turn_speed_controller").toBool()) { + if (frogpilot_toggles.value("vision_turn_speed_controller").toBool()) { QRect vtscRect(mtscRect.topLeft() + QPoint(0, mtscRect.height() + 20), QSize(mtscRect.width(), frogpilotPlan.getVtscControllingCurve() ? 100 : 50)); drawCurveSpeedControl(vtscRect, vtscSpeedStr, false); } p.drawPixmap(curveSpeedRect, scaledCurveSpeedIcon); - } else if ((setSpeed - frogpilotPlan.getVtscSpeed() > 1) && frogpilot_toggles.value("vision_turn_speed_controller").toBool()) { - QRect vtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), 150)); + } else if (frogpilotPlan.getVCruise() == frogpilotPlan.getVtscSpeed() && frogpilot_toggles.value("vision_turn_speed_controller").toBool()) { + QRect vtscRect(curveSpeedRect.topLeft() + QPoint(0, curveSpeedRect.height() + 10), QSize(curveSpeedRect.width(), frogpilotPlan.getVtscControllingCurve() ? 100 : 50)); drawCurveSpeedControl(vtscRect, vtscSpeedStr, false); + if (frogpilot_toggles.value("map_turn_speed_controller").toBool()) { + QRect mtscRect(vtscRect.topLeft() + QPoint(0, vtscRect.height() + 20), QSize(vtscRect.width(), frogpilotPlan.getVtscControllingCurve() ? 50 : 100)); + drawCurveSpeedControl(mtscRect, mtscSpeedStr, true); + } + p.drawPixmap(curveSpeedRect, scaledCurveSpeedIcon); } @@ -536,7 +541,7 @@ void FrogPilotAnnotatedCameraWidget::paintLeadMetrics(QPainter &p, bool adjacent .arg(qRound(leadSpeed * speedConversionMetrics)) .arg(leadSpeedUnit); } else { - text = QString("%1 %2 (%3) | %4 %5 | %6%7") + text = QString("%1 %2 (%3) | %4 %5 | %6 %7") .arg(qRound(leadDistance * distanceConversion)) .arg(leadDistanceUnit) .arg(QString("Desired: %1").arg(frogpilotPlan.getDesiredFollowDistance() * distanceConversion)) @@ -792,7 +797,7 @@ void FrogPilotAnnotatedCameraWidget::paintSpeedLimitSources(QPainter &p, const c QString speedText; if (speedLimitValue != 0) { - speedText = QString::number(std::nearbyint(speedLimitValue)) + " " + speedUnit; + speedText = QString::number(std::nearbyint(speedLimitValue)) + speedUnit; } else { speedText = "N/A"; } @@ -917,8 +922,7 @@ void FrogPilotAnnotatedCameraWidget::paintTurnSignals(QPainter &p, const cereal: signalXPosition = carState.getLeftBlinker() ? width() - ((animationFrameIndex + 1) * signalWidth) : animationFrameIndex * signalWidth; } - int signalYPosition = height() - signalHeight; - signalYPosition -= alertHeight; + int signalYPosition = height() - signalHeight - alertHeight; if (blindspotActive && !blindspotImages.empty()) { p.drawPixmap(carState.getLeftBlinker() ? width() - signalWidth : 0, signalYPosition, signalWidth, signalHeight, blindspotImages[carState.getLeftBlinker() ? 0 : 1]); diff --git a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h index 093c8839f..4a9a9b67e 100644 --- a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h +++ b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h @@ -11,7 +11,7 @@ class FrogPilotAnnotatedCameraWidget : public QWidget { public: explicit FrogPilotAnnotatedCameraWidget(QWidget *parent = 0); - void paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const cereal::ModelDataV2::Reader &model, const UIScene &scene, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles); + void paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles); void paintBlindSpotPath(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene); void paintFrogPilotWidgets(QPainter &p, UIState &s, FrogPilotUIState &fs, SubMaster &sm, SubMaster &fpsm, QJsonObject &frogpilot_toggles); void paintLeadMetrics(QPainter &p, bool adjacent, QPointF *chevron, const cereal::FrogPilotPlan::Reader &frogpilotPlan, const cereal::RadarState::LeadData::Reader &lead_data); @@ -32,7 +32,6 @@ public: int standstillDuration; float distanceConversion; - float setSpeed; float speed; float speedConversion; float speedConversionMetrics; diff --git a/frogpilot/ui/qt/onroad/frogpilot_onroad.cc b/frogpilot/ui/qt/onroad/frogpilot_onroad.cc index 4060ee191..1ba47244f 100644 --- a/frogpilot/ui/qt/onroad/frogpilot_onroad.cc +++ b/frogpilot/ui/qt/onroad/frogpilot_onroad.cc @@ -44,10 +44,6 @@ void FrogPilotOnroadWindow::paintEvent(QPaintEvent *event) { marginRegion += QRegion(rect.width() - UI_BORDER_SIZE, UI_BORDER_SIZE, UI_BORDER_SIZE, rect.height() - 2 * UI_BORDER_SIZE); p.setClipRegion(marginRegion); - if (showFPS) { - paintFPS(p, rect); - } - if (showSteering) { paintSteeringTorqueBorder(p, rect); } @@ -64,6 +60,10 @@ void FrogPilotOnroadWindow::paintEvent(QPaintEvent *event) { } else if (signalTimer->isActive()) { signalTimer->stop(); } + + if (showFPS) { + paintFPS(p, rect); + } } void FrogPilotOnroadWindow::paintFPS(QPainter &p, const QRect &rect) { diff --git a/frogpilot/ui/qt/widgets/developer_sidebar.cc b/frogpilot/ui/qt/widgets/developer_sidebar.cc new file mode 100644 index 000000000..ecebdc05b --- /dev/null +++ b/frogpilot/ui/qt/widgets/developer_sidebar.cc @@ -0,0 +1,154 @@ +#include "frogpilot/ui/qt/widgets/developer_sidebar.h" + +void DeveloperSidebar::drawMetric(QPainter &p, const QPair &label, QColor c, int y) { + const QRect rect = {12, y, 275, 126}; + + p.setPen(Qt::NoPen); + p.setBrush(QBrush(c)); + p.setClipRect(rect.x() + 4, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip); + p.drawRoundedRect(QRect(rect.x() + 4, rect.y() + 4, 100, 118), 18, 18); + p.setClipping(false); + + QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55)); + pen.setWidth(2); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawRoundedRect(rect, 20, 20); + + p.setPen(QColor(0xff, 0xff, 0xff)); + p.setFont(InterFont(35, QFont::DemiBold)); + p.drawText(rect.adjusted(22, 0, 0, 0), Qt::AlignCenter, label.first + "\n" + label.second); +} + +DeveloperSidebar::DeveloperSidebar(QWidget *parent) : QFrame(parent) { + setAttribute(Qt::WA_OpaquePaintEvent); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + setFixedWidth(300); + + QObject::connect(uiState(), &UIState::uiUpdate, this, &DeveloperSidebar::updateState); +} + +void DeveloperSidebar::showEvent(QShowEvent *event) { + update_theme(frogpilotUIState()); + + FrogPilotUIState &fs = *frogpilotUIState(); + FrogPilotUIScene &frogpilot_scene = fs.frogpilot_scene; + QJsonObject &frogpilot_toggles = fs.frogpilot_toggles; + + metricAssignments.clear(); + for (int i = 1; i <= 7; ++i) { + QString key = QString("developer_sidebar_metric%1").arg(i); + int metricId = frogpilot_toggles.value(key).toInt(); + metricAssignments.push_back(metricId); + } + + metricColor = frogpilot_scene.use_stock_colors ? QColor(255, 255, 255) : frogpilot_scene.sidebar_color1; +} + +void DeveloperSidebar::updateState(const UIState &s, const FrogPilotUIState &fs) { + if (!isVisible()) { + return; + } + + const FrogPilotUIScene &frogpilot_scene = fs.frogpilot_scene; + const SubMaster &fpsm = *(fs.sm); + + const cereal::CarControl::Reader &carControl = fpsm["carControl"].getCarControl(); + const cereal::CarState::Reader &carState = fpsm["carState"].getCarState(); + const cereal::FrogPilotPlan::Reader &frogpilotPlan = fpsm["frogpilotPlan"].getFrogpilotPlan(); + const cereal::LiveDelayData::Reader &liveDelay = fpsm["liveDelay"].getLiveDelay(); + const cereal::LiveParametersData::Reader &liveParameters = fpsm["liveParameters"].getLiveParameters(); + const cereal::LiveTorqueParametersData::Reader &liveTorqueParameters = fpsm["liveTorqueParameters"].getLiveTorqueParameters(); + + const bool is_metric = s.scene.is_metric; + const bool use_si = fs.frogpilot_toggles.value("use_si_metrics").toBool(); + + const QString accelerationUnit = (is_metric || use_si) ? tr(" m/s²") : tr(" ft/s²"); + const float accelerationConversion = (is_metric || use_si) ? 1.0f : METER_TO_FOOT; + + double acceleration = carState.getAEgo() * accelerationConversion; + static double maxAcceleration = 0.0; + maxAcceleration = std::max(maxAcceleration, acceleration); + + static double lateralEngagementTime = 0.0; + lateralEngagementTime += carControl.getLatActive() && !frogpilot_scene.reverse && !frogpilot_scene.standstill ? 1 : 0; + + static double longitudinalEngagementTime = 0.0; + longitudinalEngagementTime += carControl.getLongActive() && !frogpilot_scene.reverse && !frogpilot_scene.standstill ? 1 : 0; + + static double totalEngagementTime = 0.0; + totalEngagementTime += !(frogpilot_scene.reverse || frogpilot_scene.standstill) ? 1 : 0; + + accelerationStatus = ItemStatus(QPair(tr("ACCEL"), QString::number(acceleration, 'f', 2) + accelerationUnit), metricColor); + accelerationJerkStatus = ItemStatus(QPair(tr("ACCEL JERK"), QString::number(frogpilotPlan.getAccelerationJerk(), 'f', 2)), metricColor); + actuatorAccelerationStatus = ItemStatus(QPair(tr("ACT ACCEL"), QString::number(carControl.getActuators().getAccel() * accelerationConversion, 'f', 2) + accelerationUnit), metricColor); + dangerJerkStatus = ItemStatus(QPair(tr("DANGER JERK"), QString::number(frogpilotPlan.getDangerJerk(), 'f', 2)), metricColor); + delayStatus = ItemStatus(QPair(tr("STEER DELAY"), QString::number(liveDelay.getLateralDelay(), 'f', 5)), metricColor); + frictionStatus = ItemStatus(QPair(tr("FRICTION"), QString::number(liveTorqueParameters.getFrictionCoefficientFiltered(), 'f', 5)), metricColor); + latAccelStatus = ItemStatus(QPair(tr("LAT ACCEL"), QString::number(liveTorqueParameters.getLatAccelFactorFiltered(), 'f', 5)), metricColor); + lateralEngagementStatus = ItemStatus(QPair(tr("LATERAL %"), QString::number((lateralEngagementTime / totalEngagementTime) * 100.0f, 'f', 2) + "%"), metricColor); + longitudinalEngagementStatus = ItemStatus(QPair(tr("LONG %"), QString::number((longitudinalEngagementTime / totalEngagementTime) * 100.0f, 'f', 2) + "%"), metricColor); + maxAccelerationStatus = ItemStatus(QPair(tr("MAX ACCEL"), QString::number(maxAcceleration, 'f', 2) + accelerationUnit), metricColor); + speedJerkStatus = ItemStatus(QPair(tr("SPEED JERK"), QString::number(frogpilotPlan.getSpeedJerk(), 'f', 2)), metricColor); + steerAngleStatus = ItemStatus(QPair(tr("STEER ANGLE"), QString::number(fabs(carState.getSteeringAngleDeg()), 'f', 2)), metricColor); + steerRatioStatus = ItemStatus(QPair(tr("STEER RATIO"), QString::number(liveParameters.getSteerRatio(), 'f', 5)), metricColor); + stiffnessFactorStatus = ItemStatus(QPair(tr("STEER STIFF"), QString::number(liveParameters.getStiffnessFactor(), 'f', 5)), metricColor); + torqueStatus = ItemStatus(QPair(tr("TORQUE %"), QString::number(fabs(carControl.getActuators().getSteer() * 100.0f), 'f', 2)), metricColor); + + update(); +} + +void DeveloperSidebar::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.setPen(Qt::NoPen); + p.setRenderHint(QPainter::Antialiasing); + + p.fillRect(rect(), QColor(57, 57, 57)); + + QMap metricMap; + metricMap.insert(1, &accelerationStatus); + metricMap.insert(2, &maxAccelerationStatus); + metricMap.insert(3, &delayStatus); + metricMap.insert(4, &frictionStatus); + metricMap.insert(5, &latAccelStatus); + metricMap.insert(6, &steerRatioStatus); + metricMap.insert(7, &stiffnessFactorStatus); + metricMap.insert(8, &lateralEngagementStatus); + metricMap.insert(9, &longitudinalEngagementStatus); + metricMap.insert(10, &steerAngleStatus); + metricMap.insert(11, &torqueStatus); + metricMap.insert(12, &actuatorAccelerationStatus); + metricMap.insert(13, &accelerationJerkStatus); + metricMap.insert(14, &dangerJerkStatus); + metricMap.insert(15, &speedJerkStatus); + + int count = 0; + for (size_t i = 0; i < metricAssignments.size(); ++i) { + if (metricAssignments[i] > 0 && metricMap.contains(metricAssignments[i])) { + count++; + } + } + if (count == 0) { + return; + } + + int metricHeight = 126; + int spacing = (height() - (count * metricHeight)) / (count + 1); + int y = spacing; + + for (size_t i = 0; i < metricAssignments.size(); ++i) { + int metricId = metricAssignments[i]; + + if (metricId == 0) { + continue; + } + + if (!metricMap.contains(metricId)) { + continue; + } + + ItemStatus *status = metricMap[metricId]; + drawMetric(p, status->first, status->second, y); + y += metricHeight + spacing; + } +} diff --git a/frogpilot/ui/qt/widgets/developer_sidebar.h b/frogpilot/ui/qt/widgets/developer_sidebar.h new file mode 100644 index 000000000..745e2aa30 --- /dev/null +++ b/frogpilot/ui/qt/widgets/developer_sidebar.h @@ -0,0 +1,36 @@ +#pragma once + +#include "selfdrive/ui/qt/sidebar.h" + +class DeveloperSidebar : public QFrame { + Q_OBJECT + +public: + explicit DeveloperSidebar(QWidget* parent = 0); + +private: + void drawMetric(QPainter &p, const QPair &label, QColor c, int y); + void paintEvent(QPaintEvent *event) override; + void showEvent(QShowEvent *event); + void updateState(const UIState &s, const FrogPilotUIState &fs); + + std::vector metricAssignments; + + QColor metricColor; + + ItemStatus accelerationJerkStatus; + ItemStatus accelerationStatus; + ItemStatus actuatorAccelerationStatus; + ItemStatus dangerJerkStatus; + ItemStatus delayStatus; + ItemStatus frictionStatus; + ItemStatus latAccelStatus; + ItemStatus lateralEngagementStatus; + ItemStatus longitudinalEngagementStatus; + ItemStatus maxAccelerationStatus; + ItemStatus speedJerkStatus; + ItemStatus steerAngleStatus; + ItemStatus steerRatioStatus; + ItemStatus stiffnessFactorStatus; + ItemStatus torqueStatus; +}; diff --git a/frogpilot/ui/qt/widgets/frogpilot_controls.cc b/frogpilot/ui/qt/widgets/frogpilot_controls.cc index 4e60ab375..bad0785d6 100644 --- a/frogpilot/ui/qt/widgets/frogpilot_controls.cc +++ b/frogpilot/ui/qt/widgets/frogpilot_controls.cc @@ -22,24 +22,28 @@ bool useKonikServer() { } void loadImage(const QString &basePath, QPixmap &pixmap, QMovie *&movie, const QSize &size, QWidget *parent, Qt::AspectRatioMode aspectRatioMode) { - delete movie; - movie = nullptr; + if (movie) { + movie->stop(); + movie->deleteLater(); + movie = nullptr; + } QFileInfo gifFile(basePath + ".gif"); if (gifFile.exists()) { - movie = new QMovie(gifFile.filePath(), QByteArray(), parent); - if (movie->isValid()) { - movie->setCacheMode(QMovie::CacheAll); - movie->setScaledSize(size); + QMovie *newMovie = new QMovie(gifFile.filePath(), QByteArray(), parent); + if (newMovie->isValid()) { + newMovie->setCacheMode(QMovie::CacheAll); + newMovie->setScaledSize(size); - QObject::connect(movie, &QMovie::frameChanged, parent, [parent](int){parent->update();}); + QObject::connect(newMovie, &QMovie::frameChanged, parent, [parent](int) { parent->update(); }); - movie->start(); + newMovie->start(); + movie = newMovie; + + pixmap = QPixmap(); return; - } else { - delete movie; - movie = nullptr; } + newMovie->deleteLater(); } pixmap = loadPixmap(basePath + ".png", size, aspectRatioMode); diff --git a/frogpilot/ui/screenrecorder/omx_encoder.cc b/frogpilot/ui/screenrecorder/omx_encoder.cc index 20e713893..14fa44220 100644 --- a/frogpilot/ui/screenrecorder/omx_encoder.cc +++ b/frogpilot/ui/screenrecorder/omx_encoder.cc @@ -371,14 +371,13 @@ void OmxEncoder::handle_out_buf(OmxEncoder *encoder, OMX_BUFFERHEADERTYPE *out_b AVRational in_timebase = {1, 1000000}; AVPacket pkt; - av_new_packet(&pkt, out_buf->nFilledLen); - memcpy(pkt.data, buf_data, out_buf->nFilledLen); + av_init_packet(&pkt); pkt.data = buf_data; pkt.size = out_buf->nFilledLen; enum AVRounding rnd = static_cast(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); - pkt.pts = pkt.dts = av_rescale_q_rnd(out_buf->nTimeStamp, in_timebase, encoder->ofmt_ctx->streams[0]->time_base, rnd); - pkt.duration = av_rescale_q(50 * 1000, in_timebase, encoder->ofmt_ctx->streams[0]->time_base); + pkt.pts = pkt.dts = av_rescale_q_rnd(out_buf->nTimeStamp, in_timebase, encoder->out_stream->time_base, rnd); + pkt.duration = av_rescale_q(1, AVRational{1, encoder->fps}, encoder->out_stream->time_base); if (out_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME) { pkt.flags |= AV_PKT_FLAG_KEY; @@ -452,18 +451,35 @@ int OmxEncoder::encode_frame_rgba(const uint8_t *ptr, int in_width, int in_heigh } void OmxEncoder::encoder_open(const char* filename) { + if (!filename || strlen(filename) == 0) { + return; + } + + if (strlen(filename) + path.size() + 2 > sizeof(vid_path)) { + return; + } + struct stat st = {0}; if (stat(path.c_str(), &st) == -1) { - mkdir(path.c_str(), 0755); + if (mkdir(path.c_str(), 0755) == -1) { + return; + } } snprintf(vid_path, sizeof(vid_path), "%s/%s", path.c_str(), filename); - avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, vid_path); - assert(ofmt_ctx); + if (avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, vid_path) < 0 || !ofmt_ctx) { + return; + } out_stream = avformat_new_stream(ofmt_ctx, NULL); - assert(out_stream); + if (!out_stream) { + avformat_free_context(ofmt_ctx); + ofmt_ctx = nullptr; + return; + } + + out_stream->time_base = AVRational{1, fps}; out_stream->codecpar->codec_id = AV_CODEC_ID_H264; out_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; @@ -471,26 +487,36 @@ void OmxEncoder::encoder_open(const char* filename) { out_stream->codecpar->height = height; int err = avio_open(&ofmt_ctx->pb, vid_path, AVIO_FLAG_WRITE); - assert(err >= 0); + if (err < 0) { + avformat_free_context(ofmt_ctx); + ofmt_ctx = nullptr; + return; + } wrote_codec_config = false; - // create camera lock file snprintf(lock_path, sizeof(lock_path), "%s/%s.lock", path.c_str(), filename); int lock_fd = HANDLE_EINTR(open(lock_path, O_RDWR | O_CREAT, 0664)); - assert(lock_fd >= 0); + if (lock_fd < 0) { + avio_closep(&ofmt_ctx->pb); + avformat_free_context(ofmt_ctx); + ofmt_ctx = nullptr; + return; + } close(lock_fd); is_open = true; counter = 0; + + return; } void OmxEncoder::encoder_close() { - if (is_open) { - if (dirty) { - // drain output only if there could be frames in the encoder + if (!is_open) return; - OMX_BUFFERHEADERTYPE* in_buf = free_in.pop(); + if (dirty) { + OMX_BUFFERHEADERTYPE* in_buf = free_in.pop(); + if (in_buf) { in_buf->nFilledLen = 0; in_buf->nOffset = 0; in_buf->nFlags = OMX_BUFFERFLAG_EOS; @@ -500,6 +526,7 @@ void OmxEncoder::encoder_close() { while (true) { OMX_BUFFERHEADERTYPE *out_buf = done_out.pop(); + if (!out_buf) break; handle_out_buf(this, out_buf); @@ -507,17 +534,32 @@ void OmxEncoder::encoder_close() { break; } } - dirty = false; } + dirty = false; + } + if (out_stream) { + out_stream->nb_frames = counter; + out_stream->duration = counter; + } + + if (ofmt_ctx) { + ofmt_ctx->duration = av_rescale_q(counter, AVRational{1, fps}, out_stream->time_base); av_write_trailer(ofmt_ctx); avio_closep(&ofmt_ctx->pb); - if (out_stream && out_stream->codecpar && out_stream->codecpar->extradata) { - av_free(out_stream->codecpar->extradata); - out_stream->codecpar->extradata = nullptr; - } + avformat_free_context(ofmt_ctx); + ofmt_ctx = nullptr; + } + + if (out_stream && out_stream->codecpar && out_stream->codecpar->extradata) { + av_free(out_stream->codecpar->extradata); + out_stream->codecpar->extradata = nullptr; + } + + if (lock_path[0] != '\0') { unlink(lock_path); } + is_open = false; } diff --git a/launch_env.sh b/launch_env.sh index 81578aff0..c091538ff 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1 if [ -z "$AGNOS_VERSION" ]; then - export AGNOS_VERSION="10.1" + export AGNOS_VERSION="10.1.1" fi export STAGING_ROOT="/data/safe_staging" diff --git a/selfdrive/assets/img_spinner_comma.png b/selfdrive/assets/img_spinner_comma.png index 9f5e55877..659bf00c8 100644 Binary files a/selfdrive/assets/img_spinner_comma.png and b/selfdrive/assets/img_spinner_comma.png differ diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 90560bcd2..e1b0b83aa 100644 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -102,6 +102,7 @@ class Track: "modelProb": model_prob, "radar": True, "radarTrackId": self.identifier, + "farLead": False, } def potential_adjacent_lead(self, left: bool, standstill: bool, model_data: capnp._DynamicStructReader): @@ -180,6 +181,7 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa "status": True, "radar": False, "radarTrackId": -1, + "farLead": False, } @@ -213,6 +215,7 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn if len(far_lead_tracks) > 0: closest_track = min(far_lead_tracks, key=lambda c: c.dRel) lead_dict = closest_track.get_RadarState() + lead_dict['farLead'] = True lead_dict['vLead'] = lead_dict['vLeadK'] for track in tracks.values(): diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index e9a82c4c2..c02dcf396 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -54,10 +54,10 @@ frogpilot_src = ["../../frogpilot/ui/frogpilot_ui.cc", "../../frogpilot/ui/qt/of "../../frogpilot/ui/qt/offroad/theme_settings.cc", "../../frogpilot/ui/qt/offroad/utilities.cc", "../../frogpilot/ui/qt/offroad/vehicle_settings.cc", "../../frogpilot/ui/qt/offroad/visual_settings.cc", "../../frogpilot/ui/qt/offroad/wheel_settings.cc", "../../frogpilot/ui/qt/onroad/frogpilot_annotated_camera.cc", - "../../frogpilot/ui/qt/onroad/frogpilot_buttons.cc", "../../frogpilot/ui/qt/onroad/frogpilot_onroad.cc", - "../../frogpilot/ui/qt/widgets/drive_stats.cc", "../../frogpilot/ui/qt/widgets/model_reviewer.cc", - "../../frogpilot/ui/qt/widgets/navigation_functions.cc", "../../frogpilot/ui/screenrecorder/omx_encoder.cc", - "../../frogpilot/ui/screenrecorder/screenrecorder.cc"] + "../../frogpilot/ui/qt/onroad/frogpilot_buttons.cc", "../../frogpilot/ui/qt/onroad/frogpilot_onroad.cc", + "../../frogpilot/ui/qt/widgets/developer_sidebar.cc", "../../frogpilot/ui/qt/widgets/drive_stats.cc", + "../../frogpilot/ui/qt/widgets/model_reviewer.cc", "../../frogpilot/ui/qt/widgets/navigation_functions.cc", + "../../frogpilot/ui/screenrecorder/omx_encoder.cc", "../../frogpilot/ui/screenrecorder/screenrecorder.cc"] qt_src += frogpilot_src diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 446cfdfdb..252492442 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -50,6 +50,10 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState); QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition); QObject::connect(uiState(), &UIState::offroadTransition, sidebar, &Sidebar::offroadTransition); + + // FrogPilot variables + developer_sidebar = new DeveloperSidebar(this); + main_layout->addWidget(developer_sidebar); } void HomeWindow::showSidebar(bool show) { @@ -86,6 +90,9 @@ void HomeWindow::offroadTransition(bool offroad) { } else { slayout->setCurrentWidget(onroad); } + + // FrogPilot variables + developer_sidebar->setVisible(!offroad && frogpilotUIState()->frogpilot_toggles.value("developer_sidebar").toBool()); } void HomeWindow::showDriverView(bool show, bool started) { diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index deaeae5b3..d7e693579 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -16,6 +16,8 @@ #include "selfdrive/ui/qt/widgets/offroad_alerts.h" #include "selfdrive/ui/ui.h" +#include "frogpilot/ui/qt/widgets/developer_sidebar.h" + class OffroadHome : public QFrame { Q_OBJECT @@ -75,6 +77,8 @@ private: // FrogPilot variables Params params; + DeveloperSidebar *developer_sidebar; + private slots: void updateState(const UIState &s, const FrogPilotUIState &fs); }; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 070f343f4..852bc9f50 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -117,6 +117,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s, const FrogPilotUIState distance_btn->move(rightHandDM ? width() - UI_BORDER_SIZE - distance_btn->width() - (UI_BORDER_SIZE / 2) : UI_BORDER_SIZE, frogpilot_nvg->dmIconPosition.y() - distance_btn->height() / 2); distance_btn->updateState(s.scene, fs.frogpilot_scene); } + screen_recorder->setVisible(frogpilot_nvg->standstillDuration == 0 && !fs.frogpilot_scene.map_open && frogpilot_toggles.value("screen_recorder").toBool()); frogpilot_nvg->updateState(fs, frogpilot_toggles); } @@ -256,7 +257,6 @@ void AnnotatedCameraWidget::drawHud(QPainter &p, const cereal::FrogPilotPlan::Re frogpilot_nvg->mapButtonVisible = map_settings_btn->isVisible(); frogpilot_nvg->mutcdSpeedLimit = has_us_speed_limit; frogpilot_nvg->rightHandDM = rightHandDM; - frogpilot_nvg->setSpeed = setSpeed / (is_metric ? MS_TO_KPH : MS_TO_MPH); frogpilot_nvg->setSpeedRect = set_speed_rect; frogpilot_nvg->signMargin = sign_margin; frogpilot_nvg->speed = speed; @@ -386,7 +386,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s, c // paint path edges if (frogpilot_toggles.value("adjacent_path_metrics").toBool() || frogpilot_toggles.value("adjacent_paths").toBool()) { - frogpilot_nvg->paintAdjacentPaths(painter, sm["carState"].getCarState(), sm["modelV2"].getModelV2(), scene, frogpilot_scene, frogpilot_toggles); + frogpilot_nvg->paintAdjacentPaths(painter, sm["carState"].getCarState(), frogpilot_scene, frogpilot_toggles); } else if ((sm["carState"].getCarState().getLeftBlindspot() || sm["carState"].getCarState().getRightBlindspot()) && frogpilot_toggles.value("blind_spot_path").toBool()) { frogpilot_nvg->paintBlindSpotPath(painter, sm["carState"].getCarState(), frogpilot_scene); } @@ -405,9 +405,9 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s, int x = rightHandDM ? width() - offset : offset; if (distance_btn->isEnabled()) { if (rightHandDM) { - x -= distance_btn->width() + UI_BORDER_SIZE; + x -= UI_BORDER_SIZE + distance_btn->width() + UI_BORDER_SIZE; } else { - x += distance_btn->width() + UI_BORDER_SIZE; + x += UI_BORDER_SIZE + distance_btn->width() + UI_BORDER_SIZE; } } if (frogpilot_toggles.value("road_name_ui").toBool()) { @@ -452,17 +452,17 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState painter.save(); const float speedBuff = 10.; - const float leadBuff = 40.; + const float leadBuff = std::max((speed / frogpilot_nvg->speedConversion) * 10.0f, 40.0f); const float d_rel = lead_data.getDRel() + (adjacent ? fabs(lead_data.getYRel()) : 0); const float v_rel = lead_data.getVRel(); float fillAlpha = 0; - if (d_rel < leadBuff) { + if (frogpilotPlan.getTrackingLead() || adjacent) { fillAlpha = 255 * (1.0 - (d_rel / leadBuff)); if (v_rel < 0) { fillAlpha += 255 * (-1 * (v_rel / speedBuff)); } - fillAlpha = (int)(fmin(fillAlpha, 255)); + fillAlpha = std::clamp(fillAlpha, 0.f, 255.f); } float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; @@ -473,7 +473,11 @@ 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}}; - painter.setBrush(QColor(218, 202, 37, 255)); + if (lead_data.getFarLead()) { + painter.setBrush(QColor(0, 255, 255, 255)); + } else { + painter.setBrush(QColor(218, 202, 37, 255)); + } painter.drawPolygon(glow, std::size(glow)); // chevron @@ -567,6 +571,12 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { auto lead_two = radar_state.getLeadTwo(); auto lead_left = radar_state.getLeadLeft(); auto lead_right = radar_state.getLeadRight(); + if (lead_left.getStatus()) { + drawLead(painter, lead_left, frogpilotPlan, s->scene.lead_vertices[2], frogpilot_nvg->blueColor(), fs, true); + } + if (lead_right.getStatus()) { + drawLead(painter, lead_right, frogpilotPlan, s->scene.lead_vertices[3], frogpilot_nvg->purpleColor(), fs, true); + } if (lead_one.getStatus()) { drawLead(painter, lead_one, frogpilotPlan, s->scene.lead_vertices[0], fs->frogpilot_scene.lead_marker_color, fs); } else { @@ -575,12 +585,6 @@ void AnnotatedCameraWidget::paintEvent(QPaintEvent *event) { if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { drawLead(painter, lead_two, frogpilotPlan, s->scene.lead_vertices[1], fs->frogpilot_scene.lead_marker_color, fs); } - if (lead_left.getStatus()) { - drawLead(painter, lead_left, frogpilotPlan, s->scene.lead_vertices[2], frogpilot_nvg->blueColor(), fs, true); - } - if (lead_right.getStatus()) { - drawLead(painter, lead_right, frogpilotPlan, s->scene.lead_vertices[3], frogpilot_nvg->purpleColor(), fs, true); - } } } diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc index a53a79461..6fb2c1ecc 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/qt/onroad/onroad_home.cc @@ -127,8 +127,7 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { alerts->setVisible(true); nvg->setVisible(true); } - nvg->screen_recorder->setEnabled(!map->isVisible() && frogpilot_toggles.value("screen_recorder").toBool()); - nvg->screen_recorder->setVisible(nvg->screen_recorder->isEnabled()); + nvg->screen_recorder->setVisible(!map->isVisible() && frogpilot_toggles.value("screen_recorder").toBool()); } #endif // propagation event to parent(HomeWindow) diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 3d7434292..c81d75d88 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -134,10 +134,8 @@ void Sidebar::offroadTransition(bool offroad) { onroad = !offroad; // FrogPilot variables - if (!onroad) { - QTimer::singleShot(100, this, [this] { - updateTheme(); - }); + if (onroad) { + updateTheme(); } update(); diff --git a/system/fleetmanager/static/frog.png b/system/fleetmanager/static/frog.png deleted file mode 100644 index d7fcc8a87..000000000 --- a/system/fleetmanager/static/frog.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76a780657d874ef7d9464ae576c45392128a38bed4f963305be6ba2c12d04699 -size 108573 diff --git a/system/fleetmanager/templates/index.html b/system/fleetmanager/templates/index.html deleted file mode 100644 index 400df47e5..000000000 --- a/system/fleetmanager/templates/index.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "layout.html" %} - -{% block title %} - Home -{% endblock %} - -{% block main %} -
-

Fleet Manager

-
- View Dashcam Footage
-
View Screen Recordings
-
Access Error Logs
-
Navigation
-
Tools
-{% endblock %} diff --git a/system/hardware/tici/agnos.json b/system/hardware/tici/agnos.json index b1862bdef..1c0230572 100644 --- a/system/hardware/tici/agnos.json +++ b/system/hardware/tici/agnos.json @@ -1,13 +1,18 @@ [ { "name": "boot", - "url": "https://commadist.azureedge.net/agnosupdate/boot-5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f.img.xz", - "hash": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f", - "hash_raw": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f", + "url": "https://boot.frogpilot.download", + "hash": "b997aae3f1c93de82449ef7f23f30ff482b0978f3d0ac08219366f9ce362ad7a", + "hash_raw": "b997aae3f1c93de82449ef7f23f30ff482b0978f3d0ac08219366f9ce362ad7a", "size": 16029696, "sparse": false, "full_check": true, - "has_ab": true + "has_ab": true, + "alt": { + "hash": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f", + "url": "https://commadist.azureedge.net/agnosupdate/boot-5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f.img.xz", + "size": 16029696 + } }, { "name": "abl", @@ -61,17 +66,17 @@ }, { "name": "system", - "url": "https://commadist.azureedge.net/agnosupdate/system-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz", - "hash": "328e90c62068222dfd98f71dd3f6251fcb962f082b49c6be66ab2699f5db6f4f", - "hash_raw": "1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a", + "url": "https://system.frogpilot.download", + "hash": "be1c6bb9ee5e06779087b1b81e09b6df61d942566b0f8d4539c452179c661782", + "hash_raw": "a5f84e68d199466fda5c9aead760b90a4cd2d2ef9a418708b9794d95bb03ec5b", "size": 10737418240, "sparse": true, "full_check": false, "has_ab": true, "alt": { - "hash": "bc11d2148f29862ee1326aca2af1cf6bbf5fed831e3f8f6b8f7a0f110dfe8d26", - "url": "https://commadist.azureedge.net/agnosupdate/system-skip-chunks-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz", - "size": 4548070000 + "hash": "328e90c62068222dfd98f71dd3f6251fcb962f082b49c6be66ab2699f5db6f4f", + "url": "https://commadist.azureedge.net/agnosupdate/system-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz", + "size": 10737418240 } } -] \ No newline at end of file +]