diff --git a/common/params_keys.h b/common/params_keys.h index 4bb275e69..1aa462b71 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -317,7 +317,7 @@ inline static std::unordered_map keys = { {"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}}, {"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}}, {"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, - {"GalaxyMobileDefault", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_ADVANCED}}, + {"GalaxyMobileDefault", {PERSISTENT | DONT_LOG, BOOL, "1", "1", 0, SETTINGS_SIMPLE}}, {"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}}, {"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}}, @@ -609,6 +609,7 @@ inline static std::unordered_map keys = { {"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, {"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, {"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, + {"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"RivianAngleControl", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"RivianAngleSaturated", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}}, {"RivianToiRecoveryFailed", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}}, diff --git a/selfdrive/car/cruise.py b/selfdrive/car/cruise.py index 36a3c151b..42c7f2562 100644 --- a/selfdrive/car/cruise.py +++ b/selfdrive/car/cruise.py @@ -72,11 +72,7 @@ class VCruiseHelper: return short_interval, long_interval def _uses_software_cruise(self) -> bool: - # Some cars, including Toyota TSS2, keep pcmCruise enabled while - # openpilot owns longitudinal control. In that case the software cruise - # target must be used so custom short/hold intervals are honored. - return bool(self.gm_cc_only or self.redneck_non_pcm or not self.CP.pcmCruise or - getattr(self.CP, "openpilotLongitudinalControl", False)) + return bool(self.gm_cc_only or self.redneck_non_pcm or not self.CP.pcmCruise) @property def v_cruise_initialized(self): @@ -229,12 +225,6 @@ class VCruiseHelper: self.v_cruise_kph = float(np.clip(initialized_speed_limit_kph, V_CRUISE_MIN, V_CRUISE_MAX)) elif self.redneck_non_pcm and CS.cruiseState.speedCluster > 0: self.v_cruise_kph = float(np.clip(CS.cruiseState.speedCluster * CV.MS_TO_KPH, V_CRUISE_MIN, V_CRUISE_MAX)) - elif self.CP.pcmCruise and CS.cruiseState.speed > 0: - # Keep PCM/dash set speed as the starting target when software cruise - # takes over, while allowing subsequent button presses to use custom - # intervals. This preserves Toyota's stock engage behavior. - pcm_speed_kph = CS.cruiseState.speed * CV.MS_TO_KPH - self.v_cruise_kph = float(np.clip(pcm_speed_kph, V_CRUISE_MIN, V_CRUISE_MAX)) else: self.v_cruise_kph = int(round(np.clip(CS.vEgo * CV.MS_TO_KPH, engage_floor_kph, V_CRUISE_MAX))) diff --git a/selfdrive/car/tests/test_cruise_speed.py b/selfdrive/car/tests/test_cruise_speed.py index fc4f7f90e..60158281d 100644 --- a/selfdrive/car/tests/test_cruise_speed.py +++ b/selfdrive/car/tests/test_cruise_speed.py @@ -498,95 +498,34 @@ class TestVCruiseHelper: assert self.v_cruise_helper.v_cruise_kph == pytest.approx(initial_v_cruise_kph + IMPERIAL_INCREMENT) - def test_pcm_cruise_uses_pcm_speed(self): - CP = car.CarParams(pcmCruise=True, openpilotLongitudinalControl=False) + @pytest.mark.parametrize("openpilot_longitudinal", [False, True]) + def test_pcm_cruise_always_tracks_pcm_speed(self, openpilot_longitudinal): + CP = car.CarParams(pcmCruise=True, openpilotLongitudinalControl=openpilot_longitudinal) helper = VCruiseHelper(CP) toggles = SimpleNamespace(cruise_increase=5, cruise_increase_long=1, set_speed_limit=False) - pcm_speed_kph = 72.0 - pcm_cluster_speed_kph = 71.0 helper.initialize_v_cruise(car.CarState(vEgo=40 * CV.KPH_TO_MS), False, False, toggles) assert not helper.v_cruise_initialized - cs = car.CarState( - cruiseState={ - "available": True, - "speed": pcm_speed_kph * CV.KPH_TO_MS, - "speedCluster": pcm_cluster_speed_kph * CV.KPH_TO_MS, - }, + samples = ( + (72.0, 71.0, None), + (25.0, 25.0, {"type": ButtonType.decelCruise, "pressed": True}), + (65.0, 65.0, {"type": ButtonType.decelCruise, "pressed": False}), + (90.0, 90.0, {"type": ButtonType.accelCruise, "pressed": True}), + (5.0, 5.0, {"type": ButtonType.accelCruise, "pressed": False}), ) - - helper.update_v_cruise(cs, True, True, False, toggles) - assert helper.v_cruise_kph == pytest.approx(pcm_speed_kph) - assert helper.v_cruise_cluster_kph == pytest.approx(pcm_cluster_speed_kph) - - next_pcm_speed_kph = 74.0 - next_cs = car.CarState( - cruiseState={ - "available": True, - "speed": next_pcm_speed_kph * CV.KPH_TO_MS, - "speedCluster": next_pcm_speed_kph * CV.KPH_TO_MS, - }, - buttonEvents=[{"type": ButtonType.accelCruise, "pressed": False}], - ) - helper.update_v_cruise(next_cs, True, True, False, toggles) - assert helper.v_cruise_kph == pytest.approx(next_pcm_speed_kph) - - def test_openpilot_longitudinal_pcm_cruise_uses_custom_intervals(self): - CP = car.CarParams(pcmCruise=True, openpilotLongitudinalControl=True) - helper = VCruiseHelper(CP) - toggles = SimpleNamespace(cruise_increase=5, cruise_increase_long=1, set_speed_limit=False) - initial_speed_kph = 40.0 - - helper.initialize_v_cruise(car.CarState(vEgo=initial_speed_kph * CV.KPH_TO_MS), False, False, toggles) - assert helper.v_cruise_kph == pytest.approx(initial_speed_kph) - - press_cs = car.CarState( - cruiseState={"available": True}, - buttonEvents=[{"type": ButtonType.accelCruise, "pressed": True}], - ) - helper.update_v_cruise(press_cs, True, True, False, toggles) - - release_cs = car.CarState( - cruiseState={"available": True}, - buttonEvents=[{"type": ButtonType.accelCruise, "pressed": False}], - ) - helper.update_v_cruise(release_cs, True, True, False, toggles) - assert helper.v_cruise_kph == pytest.approx(initial_speed_kph + 5) - - helper.update_v_cruise(press_cs, True, True, False, toggles) - for _ in range(50): - helper.update_v_cruise(car.CarState(cruiseState={"available": True}), True, True, False, toggles) - - assert helper.v_cruise_kph == pytest.approx(initial_speed_kph + 5 + 1) - - def test_openpilot_longitudinal_pcm_cruise_starts_from_pcm_set_speed(self): - CP = car.CarParams(pcmCruise=True, openpilotLongitudinalControl=True) - helper = VCruiseHelper(CP) - toggles = SimpleNamespace(cruise_increase=5, cruise_increase_long=1, set_speed_limit=False) - pcm_speed_kph = 72.0 - - helper.initialize_v_cruise( - car.CarState( - vEgo=40 * CV.KPH_TO_MS, - cruiseState={"available": True, "speed": pcm_speed_kph * CV.KPH_TO_MS}, - ), - False, - False, - toggles, - ) - assert helper.v_cruise_kph == pytest.approx(pcm_speed_kph) - - helper.update_v_cruise( - car.CarState( - cruiseState={"available": True, "speed": 74 * CV.KPH_TO_MS}, - ), - True, - True, - False, - toggles, - ) - assert helper.v_cruise_kph == pytest.approx(pcm_speed_kph) + for pcm_speed_kph, pcm_cluster_speed_kph, button_event in samples: + cs = car.CarState( + cruiseState={ + "available": True, + "speed": pcm_speed_kph * CV.KPH_TO_MS, + "speedCluster": pcm_cluster_speed_kph * CV.KPH_TO_MS, + }, + buttonEvents=[] if button_event is None else [button_event], + ) + helper.update_v_cruise(cs, True, True, False, toggles) + assert helper.v_cruise_kph == pytest.approx(pcm_speed_kph) + assert helper.v_cruise_cluster_kph == pytest.approx(pcm_cluster_speed_kph) class TestVCruiseHelperRedneck: diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 7688e8cd0..32156cef7 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -639,6 +639,9 @@ class LatControlTorque(LatControl): output_torque *= tucson_4th_gen_center_taper elif genesis_g70_active: output_torque *= genesis_g70_center_output_taper + output_torque *= get_genesis_g70_high_speed_transition_scale( + setpoint, desired_lateral_jerk, CS.vEgo, + ) output_torque *= get_genesis_g70_curve_unwind_output_scale(setpoint, desired_lateral_jerk, CS.vEgo) output_torque *= get_genesis_g70_high_speed_error_scale( setpoint, measurement, desired_lateral_jerk, CS.vEgo, diff --git a/selfdrive/controls/lib/latcontrol_vehicle_tunes.py b/selfdrive/controls/lib/latcontrol_vehicle_tunes.py index e128ce128..f8235b767 100644 --- a/selfdrive/controls/lib/latcontrol_vehicle_tunes.py +++ b/selfdrive/controls/lib/latcontrol_vehicle_tunes.py @@ -289,6 +289,13 @@ GENESIS_G70_CENTER_OUTPUT_TAPER_LAT = 0.30 GENESIS_G70_CENTER_OUTPUT_TAPER_LAT_WIDTH = 0.10 GENESIS_G70_CENTER_OUTPUT_TAPER_SPEED = 18.0 GENESIS_G70_CENTER_OUTPUT_TAPER_SPEED_WIDTH = 3.0 +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_MAX = 0.18 +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_SPEED = 45.0 * CV.MPH_TO_MS +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_SPEED_WIDTH = 8.0 * CV.MPH_TO_MS +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_LAT = 0.45 +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_LAT_WIDTH = 0.15 +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_JERK = 0.35 +GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_JERK_WIDTH = 0.15 GENESIS_G70_LOW_SPEED_CENTER_TAPER_MAX = 0.06 GENESIS_G70_LOW_SPEED_CENTER_TAPER_LAT = 0.14 GENESIS_G70_LOW_SPEED_CENTER_TAPER_LAT_WIDTH = 0.05 @@ -3246,6 +3253,18 @@ def get_genesis_g70_center_output_scale(desired_lateral_accel: float, v_ego: flo return 1.0 - reduction +def get_genesis_g70_high_speed_transition_scale(desired_lateral_accel: float, + desired_lateral_jerk: float, v_ego: float) -> float: + speed_weight = _sigmoid((v_ego - GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_SPEED) / + GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_SPEED_WIDTH) + center_weight = _sigmoid((GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_LAT - abs(desired_lateral_accel)) / + GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_LAT_WIDTH) + jerk_weight = _sigmoid((abs(desired_lateral_jerk) - GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_JERK) / + GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_JERK_WIDTH) + reduction = (GENESIS_G70_HIGH_SPEED_TRANSITION_DAMPING_MAX * speed_weight * center_weight * jerk_weight) + return 1.0 - reduction + + def get_genesis_g70_low_speed_angle_damping(desired_angle_deg: float, actual_angle_deg: float, current_output_torque: float, v_ego: float) -> float: angle_error = desired_angle_deg - actual_angle_deg diff --git a/selfdrive/controls/tests/test_latcontrol.py b/selfdrive/controls/tests/test_latcontrol.py index 737e2a1b8..22c67822c 100644 --- a/selfdrive/controls/tests/test_latcontrol.py +++ b/selfdrive/controls/tests/test_latcontrol.py @@ -54,6 +54,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_vehicle_tunes import ( get_rav4_tss2_pid_output, get_subaru_impreza_pid_output_scale, get_genesis_gv70_low_speed_center_overshoot_scale, + get_genesis_g70_high_speed_transition_scale, normalize_flm_overrides, set_flm_runtime_overrides, ) @@ -960,6 +961,12 @@ class TestLatControl: assert get_genesis_g70_low_speed_output_limit(0.0, 2.0) < 0.30 assert get_genesis_g70_low_speed_angle_damping(0.0, -20.0, 0.0, 2.0) < 0.0 assert get_genesis_g70_low_speed_angle_damping(0.0, 20.0, 0.0, 2.0) > 0.0 + assert get_genesis_g70_high_speed_transition_scale(0.0, 0.8, 65.0 * 0.44704) < \ + get_genesis_g70_high_speed_transition_scale(0.0, 0.1, 65.0 * 0.44704) + assert get_genesis_g70_high_speed_transition_scale(1.0, 0.8, 65.0 * 0.44704) > \ + get_genesis_g70_high_speed_transition_scale(0.0, 0.8, 65.0 * 0.44704) + assert get_genesis_g70_high_speed_transition_scale(0.0, 0.8, 20.0 * 0.44704) > \ + get_genesis_g70_high_speed_transition_scale(0.0, 0.8, 65.0 * 0.44704) assert 0.90 < get_genesis_g70_curve_unwind_output_scale(0.7, -0.5, 25.0) < 1.0 assert get_genesis_g70_curve_unwind_output_scale(0.7, 0.5, 25.0) == 1.0 assert get_genesis_g70_angle_output_scale(55.0, 1.0) > get_genesis_g70_angle_output_scale(85.0, 1.0) diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index 2e817bef2..313260c0d 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -32,6 +32,7 @@ class DeveloperLayout(Widget): def __init__(self): super().__init__() self._params = Params() + self._params.put_bool("LongitudinalManeuverMode", False) # Build items and keep references for callbacks/state updates self._adb_toggle = toggle_item( @@ -59,13 +60,6 @@ class DeveloperLayout(Widget): enabled=ui_state.is_offroad, ) - self._long_maneuver_toggle = toggle_item( - lambda: tr("Longitudinal Maneuver Mode"), - description="", - initial_state=self._params.get_bool("LongitudinalManeuverMode"), - callback=self._on_long_maneuver_mode, - ) - self._alpha_long_toggle = toggle_item( lambda: tr("openpilot Longitudinal Control (Alpha)"), description=lambda: tr(DESCRIPTIONS["alpha_longitudinal"]), @@ -87,7 +81,6 @@ class DeveloperLayout(Widget): self._ssh_toggle, self._ssh_keys, self._joystick_toggle, - self._long_maneuver_toggle, self._alpha_long_toggle, self._ui_debug_toggle, ], line_separator=True, spacing=0) @@ -114,13 +107,7 @@ class DeveloperLayout(Widget): else: self._alpha_long_toggle.set_visible(True) - long_man_enabled = ui_state.has_longitudinal_control and ui_state.is_offroad() - self._long_maneuver_toggle.action_item.set_enabled(long_man_enabled) - if not long_man_enabled: - self._long_maneuver_toggle.action_item.set_state(False) - self._params.put_bool("LongitudinalManeuverMode", False) else: - self._long_maneuver_toggle.action_item.set_enabled(False) self._alpha_long_toggle.set_visible(False) # TODO: make a param control list item so we don't need to manage internal state as much here @@ -129,7 +116,6 @@ class DeveloperLayout(Widget): ("AdbEnabled", self._adb_toggle), ("SshEnabled", self._ssh_toggle), ("JoystickDebugMode", self._joystick_toggle), - ("LongitudinalManeuverMode", self._long_maneuver_toggle), ("AlphaLongitudinalEnabled", self._alpha_long_toggle), ("ShowDebugInfo", self._ui_debug_toggle), ): @@ -149,12 +135,6 @@ class DeveloperLayout(Widget): def _on_joystick_debug_mode(self, state: bool): self._params.put_bool("JoystickDebugMode", state) self._params.put_bool("LongitudinalManeuverMode", False) - self._long_maneuver_toggle.action_item.set_state(False) - - def _on_long_maneuver_mode(self, state: bool): - self._params.put_bool("LongitudinalManeuverMode", state) - self._params.put_bool("JoystickDebugMode", False) - self._joystick_toggle.action_item.set_state(False) def _on_alpha_long_enabled(self, state: bool): if state: diff --git a/selfdrive/ui/layouts/settings/starpilot/longitudinal.py b/selfdrive/ui/layouts/settings/starpilot/longitudinal.py index b37124b5b..6567d33b0 100644 --- a/selfdrive/ui/layouts/settings/starpilot/longitudinal.py +++ b/selfdrive/ui/layouts/settings/starpilot/longitudinal.py @@ -731,7 +731,7 @@ class StarPilotLongitudinalLayout(_SettingsPage): unit=self._speed_unit(), value_type="float", current_value=max(1, self._params.get_float("CustomCruise"))), - visible=lambda: self._params.get_bool("QOLLongitudinal")), + visible=lambda: self._params.get_bool("QOLLongitudinal") and not starpilot_state.car_state.isToyota), SettingRow("CustomCruiseLong", "value", tr_noop("Cruise Long"), subtitle="", get_value=lambda: f"{max(1, self._params.get_float('CustomCruiseLong')):g}{self._speed_unit()}", @@ -739,7 +739,12 @@ class StarPilotLongitudinalLayout(_SettingsPage): unit=self._speed_unit(), value_type="float", current_value=max(1, self._params.get_float("CustomCruiseLong"))), - visible=lambda: self._params.get_bool("QOLLongitudinal")), + visible=lambda: self._params.get_bool("QOLLongitudinal") and not starpilot_state.car_state.isToyota), + SettingRow("ReverseCruise", "toggle", tr_noop("Reverse Cruise Increase"), + subtitle=tr_noop("Swap Toyota/Lexus cruise increments: short press changes the dash set speed by 5; hold changes it by 1."), + get_state=lambda: self._params.get_bool("ReverseCruise"), + set_state=lambda s: self._params.put_bool("ReverseCruise", s), + visible=lambda: self._params.get_bool("QOLLongitudinal") and starpilot_state.car_state.isToyota), SettingRow("ForceStops", "toggle", tr_noop("Force Stops"), subtitle="", get_state=lambda: self._params.get_bool("ForceStops"), diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index caaf157e1..2266b215e 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -12,6 +12,7 @@ class DeveloperLayoutMici(NavScroller): def __init__(self): super().__init__() self._ssh_fetcher = SshKeyFetcher(ui_state.params) + ui_state.params.put_bool("LongitudinalManeuverMode", False) def github_username_callback(username: str): if username: @@ -45,7 +46,6 @@ class DeveloperLayoutMici(NavScroller): self._ssh_keys_btn = BigButton("SSH keys", "Not set" if not github_username else github_username, icon=txt_ssh) self._ssh_keys_btn.set_click_callback(ssh_keys_callback) - # adb, ssh, ssh keys, debug mode, joystick debug mode, longitudinal maneuver mode, ip address # ******** Main Scroller ******** self._adb_toggle = BigCircleParamControl(gui_app.texture("icons_mici/adb_short.png", 82, 82), "AdbEnabled", icon_offset=(0, 12)) self._ssh_toggle = BigCircleParamControl(gui_app.texture("icons_mici/ssh_short.png", 82, 82), "SshEnabled", icon_offset=(0, 12)) @@ -53,9 +53,6 @@ class DeveloperLayoutMici(NavScroller): self._joystick_toggle = BigToggle("joystick debug mode", initial_state=ui_state.params.get_bool("JoystickDebugMode"), toggle_callback=self._on_joystick_debug_mode) - self._long_maneuver_toggle = BigToggle("longitudinal maneuver mode", - initial_state=ui_state.params.get_bool("LongitudinalManeuverMode"), - toggle_callback=self._on_long_maneuver_mode) self._alpha_long_toggle = BigToggle("alpha longitudinal", initial_state=ui_state.params.get_bool("AlphaLongitudinalEnabled"), toggle_callback=self._on_alpha_long_enabled) @@ -69,7 +66,6 @@ class DeveloperLayoutMici(NavScroller): self._ssh_keys_btn, self._disable_wide_road_toggle, self._joystick_toggle, - self._long_maneuver_toggle, self._alpha_long_toggle, self._debug_mode_toggle, ]) @@ -80,7 +76,6 @@ class DeveloperLayoutMici(NavScroller): ("SshEnabled", self._ssh_toggle), ("DisableWideRoad", self._disable_wide_road_toggle), ("JoystickDebugMode", self._joystick_toggle), - ("LongitudinalManeuverMode", self._long_maneuver_toggle), ("AlphaLongitudinalEnabled", self._alpha_long_toggle), ("ShowDebugInfo", self._debug_mode_toggle), ) @@ -89,7 +84,7 @@ class DeveloperLayoutMici(NavScroller): self._disable_wide_road_toggle, self._joystick_toggle, ) - engaged_blocked_toggles = (self._long_maneuver_toggle, self._alpha_long_toggle) + engaged_blocked_toggles = (self._alpha_long_toggle,) # Disable toggles that require offroad for item in onroad_blocked_toggles: @@ -129,13 +124,7 @@ class DeveloperLayoutMici(NavScroller): else: self._alpha_long_toggle.set_visible(True) - long_man_enabled = ui_state.has_longitudinal_control and ui_state.is_offroad() - self._long_maneuver_toggle.set_enabled(long_man_enabled) - if not long_man_enabled: - self._long_maneuver_toggle.set_checked(False) - ui_state.params.put_bool("LongitudinalManeuverMode", False) else: - self._long_maneuver_toggle.set_enabled(False) self._alpha_long_toggle.set_visible(False) # Refresh toggles from params to mirror external changes @@ -145,16 +134,8 @@ class DeveloperLayoutMici(NavScroller): def _on_joystick_debug_mode(self, state: bool): ui_state.params.put_bool("JoystickDebugMode", state) ui_state.params.put_bool("LongitudinalManeuverMode", False) - self._long_maneuver_toggle.set_checked(False) ui_state.params.put_bool("LateralManeuverMode", False) - def _on_long_maneuver_mode(self, state: bool): - ui_state.params.put_bool("LongitudinalManeuverMode", state) - ui_state.params.put_bool("JoystickDebugMode", False) - self._joystick_toggle.set_checked(False) - ui_state.params.put_bool("LateralManeuverMode", False) - restart_needed_callback(state) - def _on_alpha_long_enabled(self, state: bool): # TODO: show confirmation dialog before enabling ui_state.params.put_bool("AlphaLongitudinalEnabled", state) diff --git a/starpilot/common/assets/device_settings_layout.json b/starpilot/common/assets/device_settings_layout.json index 61f0a0a9e..ac2ae2150 100644 --- a/starpilot/common/assets/device_settings_layout.json +++ b/starpilot/common/assets/device_settings_layout.json @@ -1704,6 +1704,10 @@ "precision": 0, "unit_type": "vehicle_speed", "metric_max": 150.0, + "excluded_vehicle_makes": [ + "Lexus", + "Toyota" + ], "parent_key": "QOLLongitudinal", "settings_tier": "simple" }, @@ -1719,6 +1723,24 @@ "precision": 0, "unit_type": "vehicle_speed", "metric_max": 150.0, + "excluded_vehicle_makes": [ + "Lexus", + "Toyota" + ], + "parent_key": "QOLLongitudinal", + "settings_tier": "simple" + }, + { + "key": "ReverseCruise", + "label": "Reverse Cruise Increase", + "description": "Reverse Toyota/Lexus cruise-button behavior so a short press changes the dashboard set speed by 5 and a hold changes it by 1.", + "picker_description": "Swaps Toyota/Lexus short-press and hold cruise increments.", + "data_type": "bool", + "ui_type": "toggle", + "vehicle_makes": [ + "Lexus", + "Toyota" + ], "parent_key": "QOLLongitudinal", "settings_tier": "simple" }, @@ -4829,12 +4851,12 @@ }, { "key": "GalaxyMobileDefault", - "label": "Try the Big Dipper Web UI", - "description": "Open the Big Dipper at the top-level Galaxy link instead of the classic Galaxy. The classic UI remains available at /classic and Big Dipper at /mobile regardless of this toggle.", - "picker_description": "Serve the Big Dipper as the default landing page.", + "label": "Use Galaxy (new) by Default", + "description": "Open Galaxy (new) at the top-level Galaxy link. Turn this off to use Galaxy (old) instead. Galaxy (old) remains available at /classic and Galaxy (new) at /mobile.", + "picker_description": "Serve Galaxy (new) as the default landing page.", "data_type": "bool", "ui_type": "toggle", - "settings_tier": "advanced" + "settings_tier": "simple" }, { "key": "AlphaLongitudinalEnabled", diff --git a/starpilot/common/starpilot_variables.py b/starpilot/common/starpilot_variables.py index a3bfeb924..767aaf9d5 100644 --- a/starpilot/common/starpilot_variables.py +++ b/starpilot/common/starpilot_variables.py @@ -390,6 +390,16 @@ def speed_limit_controller_available(openpilot_longitudinal: bool, redneck_cruis return openpilot_longitudinal or redneck_cruise +def software_cruise_intervals_available(quality_of_life: bool, car_make: str, pcm_cruise: bool, + openpilot_longitudinal: bool, pcm_cruise_speed: bool) -> bool: + return bool(quality_of_life and not (car_make == "toyota" and pcm_cruise) and + (openpilot_longitudinal or not pcm_cruise_speed)) + + +def reverse_cruise_available(quality_of_life: bool, car_make: str, pcm_cruise: bool) -> bool: + return bool(quality_of_life and car_make == "toyota" and pcm_cruise) + + def migrate_cancel_button_controls(params: Params | None = None) -> bool: params = params or Params(return_defaults=True) if params.get_bool(CANCEL_BUTTON_MIGRATION_KEY) or not params.get_bool("RemapCancelToDistance"): @@ -1345,10 +1355,17 @@ class StarPilotVariables: toggle.pause_lateral_below_signal = self.get_value("PauseLateralOnSignal", condition=toggle.pause_lateral_below_speed != 0) toggle.pause_lateral_signal_delay = self.get_value("LateralResumeDelay", cast=float, condition=toggle.pause_lateral_below_signal, default=0.0, min=0.0, max=5.0) - quality_of_life_longitudinal = toggle.openpilot_longitudinal and self.get_value("QOLLongitudinal") - quality_of_life_cruise = self.get_value("QOLLongitudinal") and (toggle.openpilot_longitudinal or not FPCP.pcmCruiseSpeed) + quality_of_life = self.get_value("QOLLongitudinal") + quality_of_life_longitudinal = toggle.openpilot_longitudinal and quality_of_life + quality_of_life_cruise = software_cruise_intervals_available( + quality_of_life, toggle.car_make, pcm_cruise, toggle.openpilot_longitudinal, FPCP.pcmCruiseSpeed, + ) toggle.cruise_increase = self.get_value("CustomCruise", cast=float, condition=quality_of_life_cruise, default=1.0) toggle.cruise_increase_long = self.get_value("CustomCruiseLong", cast=float, condition=quality_of_life_cruise, default=5.0) + toggle.reverse_cruise_increase = self.get_value( + "ReverseCruise", + condition=reverse_cruise_available(quality_of_life, toggle.car_make, pcm_cruise), + ) toggle.force_stops = self.get_value("ForceStops", condition=quality_of_life_longitudinal) toggle.force_stop_distance_offset = self.get_value("ForceStopDistanceOffset", cast=int, condition=(quality_of_life_longitudinal and toggle.force_stops)) toggle.force_standstill = self.get_value("ForceStandstill", condition=quality_of_life_longitudinal) diff --git a/starpilot/common/tests/test_starpilot_variables.py b/starpilot/common/tests/test_starpilot_variables.py index 9a7d65b1a..3241de5d0 100644 --- a/starpilot/common/tests/test_starpilot_variables.py +++ b/starpilot/common/tests/test_starpilot_variables.py @@ -328,4 +328,14 @@ def test_set_speed_limit_unavailable_on_stock_pcm_without_helper(): def test_speed_limit_controller_available_on_openpilot_longitudinal_or_redneck(): assert spv.speed_limit_controller_available(openpilot_longitudinal=True, redneck_cruise=False) is True assert spv.speed_limit_controller_available(openpilot_longitudinal=False, redneck_cruise=True) is True + + +def test_toyota_pcm_cruise_uses_hardware_reverse_instead_of_software_intervals(): + assert spv.software_cruise_intervals_available(True, "toyota", True, True, True) is False + assert spv.reverse_cruise_available(True, "toyota", True) is True + + +def test_non_toyota_software_cruise_keeps_custom_intervals(): + assert spv.software_cruise_intervals_available(True, "hyundai", False, True, True) is True + assert spv.reverse_cruise_available(True, "hyundai", False) is False assert spv.speed_limit_controller_available(openpilot_longitudinal=False, redneck_cruise=False) is False diff --git a/starpilot/system/the_galaxy/assets/components/router.js b/starpilot/system/the_galaxy/assets/components/router.js index 390beed0c..bfcc56fed 100644 --- a/starpilot/system/the_galaxy/assets/components/router.js +++ b/starpilot/system/the_galaxy/assets/components/router.js @@ -10,7 +10,6 @@ import { VehicleFeatures } from "/assets/components/tools/vehicle_features.js" import { TSKManager } from "/assets/components/tools/tsk_manager.js" import { GalaxyPairing } from "/assets/components/tools/galaxy.js" import { Home } from "/assets/components/home/home.js" -import { LongitudinalManeuvers } from "/assets/components/tools/longitudinal_maneuvers.js" import { MapsManager } from "/assets/components/tools/maps.js" import { NavDestination } from "/assets/components/navigation/navigation_destination.js?v=nav-search-context-2" import { NavKeys } from "/assets/components/navigation/navigation_keys.js?v=app-keys-session-1" @@ -91,7 +90,6 @@ function Root() { createRoute("model_laboratory", "/model_laboratory", ModelLaboratory), createRoute("tuning", "/tuning", Tuning), createRoute("lateral_maneuvers", "/lateral_maneuvers", Tuning), - createRoute("longitudinal_maneuvers", "/longitudinal_maneuvers", LongitudinalManeuvers), createRoute("maps", "/manage_maps", MapsManager), createRoute("plots", "/plots", LivePlots), createRoute("thememaker", "/theme_maker", ThemeMaker), diff --git a/starpilot/system/the_galaxy/assets/components/sidebar.js b/starpilot/system/the_galaxy/assets/components/sidebar.js index 53b53b105..1a5cb77c6 100644 --- a/starpilot/system/the_galaxy/assets/components/sidebar.js +++ b/starpilot/system/the_galaxy/assets/components/sidebar.js @@ -18,7 +18,6 @@ const MENU_ITEMS = { { name: "Sentry Mode", link: "/sentry", icon: "bi-shield-exclamation" }, { name: "Controllers", link: "/wheel-controls", icon: "bi-controller" }, { name: "Lateral Tuning", link: "/tuning", icon: "bi-sign-turn-right" }, - { name: "Long Maneuvers", link: "/longitudinal_maneuvers", icon: "bi-signpost-split" }, { name: "Maps", link: "/manage_maps", icon: "bi-map" }, { name: "Navigation", link: "/set_navigation_destination", icon: "bi-geo-alt-fill" }, { name: "App Keys", link: "/manage_navigation_keys", icon: "bi-key-fill" }, diff --git a/starpilot/system/the_galaxy/assets/components/tools/device_settings.js b/starpilot/system/the_galaxy/assets/components/tools/device_settings.js index 75deefe81..064caa3e7 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/device_settings.js +++ b/starpilot/system/the_galaxy/assets/components/tools/device_settings.js @@ -1,5 +1,5 @@ import { html, reactive } from "/assets/vendor/arrow-core.js" -import { formatNumericParamValue, resolveVehicleUnitParam, vehicleSpeedUnit } from "/assets/mobile/js/params.js" +import { formatNumericParamValue, resolveVehicleUnitParam } from "/assets/mobile/js/params.js" const endpointOptionsCache = {} const endpointOptionsInflight = {} @@ -102,9 +102,11 @@ function normalizeVehicleMake(value) { function isVehicleSettingVisible(section, param) { const allowedMakes = param.vehicle_makes || (section.name === "Vehicle" ? VEHICLE_SETTING_MAKES[param.key] : null) - if (!allowedMakes) return true const selectedMake = normalizeVehicleMake(state.values.CarMake) - return allowedMakes.some(make => normalizeVehicleMake(make) === selectedMake) + if (allowedMakes && !allowedMakes.some(make => normalizeVehicleMake(make) === selectedMake)) return false + + const excludedMakes = param.excluded_vehicle_makes || [] + return !excludedMakes.some(make => normalizeVehicleMake(make) === selectedMake) } function matchesSettingValueCondition(param) { @@ -1818,11 +1820,6 @@ export function DeviceSettings({ params }) {

Toggles

-
- - Vehicle-unit speed settings use ${() => vehicleSpeedUnit(state.values)} and follow the comma's Use Metric System toggle. Each control shows its adjustment step. -
-
- + @@ -26,7 +26,7 @@ } - Big Dipper + Galaxy diff --git a/starpilot/system/the_galaxy/assets/mobile/js/app.js b/starpilot/system/the_galaxy/assets/mobile/js/app.js index 7976f4c7f..bbda847e3 100644 --- a/starpilot/system/the_galaxy/assets/mobile/js/app.js +++ b/starpilot/system/the_galaxy/assets/mobile/js/app.js @@ -8,12 +8,12 @@ import { Logs } from "./views/Logs.js" import { Tuning } from "./views/Tuning.js" import { Navigation } from "./views/Navigation.js" import { Vehicle } from "./views/Vehicle.js" +import { Bluetooth } from "./views/Bluetooth.js" import { SystemTools } from "./views/SystemTools.js" import { ToolEmbed } from "./views/ToolEmbed.js" import { Doors } from "./views/Doors.js" import { Galaxy } from "./views/Galaxy.js" import { Tsk } from "./views/Tsk.js" -import { Sentry } from "./views/Sentry.js" import { ModelManager } from "./views/ModelManager.js" import { Plots } from "./views/Plots.js" import { TestingGround } from "./views/TestingGround.js" @@ -43,12 +43,13 @@ const VIEWS = { "/tuning": Tuning, "/navigation": Navigation, "/vehicle": Vehicle, + "/bluetooth": Bluetooth, "/system": SystemTools, "/embed": ToolEmbed, "/manage_doors": Doors, "/galaxy": Galaxy, "/manage_tsk": Tsk, - "/sentry": Sentry, + "/sentry": Cameras, "/manage_models": ModelManager, "/plots": Plots, "/testing_ground": TestingGround, diff --git a/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js b/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js index 630d30a3f..8b08d3858 100644 --- a/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js +++ b/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js @@ -7,12 +7,12 @@ const NAV = { { name: "Recordings", link: "/recordings", icon: "bi-camera-reels" }, ], tools: [ + { name: "Bluetooth", link: "/bluetooth", icon: "bi-bluetooth" }, { name: "Cameras & Monitoring", link: "/cameras", icon: "bi-camera-video" }, { name: "Galaxy", link: "/galaxy", icon: "bi-globe2" }, { name: "Logs & Diagnostics", link: "/logs", icon: "bi-exclamation-triangle" }, { name: "Model Manager", link: "/manage_models", icon: "bi-cpu" }, { name: "Navigation & Maps", link: "/navigation", icon: "bi-map" }, - { name: "Sentry Mode", link: "/sentry", icon: "bi-shield-exclamation" }, { name: "System Tools", link: "/system", icon: "bi-arrow-repeat" }, { name: "Model Laboratory", link: "/model_laboratory", icon: "bi-bezier2" }, { name: "Plots", link: "/plots", icon: "bi-graph-up-arrow" }, @@ -102,7 +102,7 @@ export const AppShell = { - Big Dipper + Galaxy
@@ -128,8 +128,8 @@ export const AppShell = {