diff --git a/common/params_keys.h b/common/params_keys.h index fb6985a7c..96cc18548 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -61,6 +61,8 @@ inline static std::unordered_map keys = { {"HardwareSerial", {PERSISTENT, STRING}}, {"HasAcceptedTerms", {PERSISTENT, STRING, "0"}}, {"HondaGasFactorParams", {PERSISTENT, FLOAT}}, + {"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}}, + {"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}}, {"HondaWindFactorParams", {PERSISTENT, FLOAT}}, {"InstallDate", {PERSISTENT, TIME}}, {"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}}, diff --git a/opendbc_repo/opendbc/car/gm/carcontroller.py b/opendbc_repo/opendbc/car/gm/carcontroller.py index b1bfb15f7..a29252434 100644 --- a/opendbc_repo/opendbc/car/gm/carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/carcontroller.py @@ -187,13 +187,19 @@ def get_testing_ground_1_brake_switch_bias(v_ego: float) -> int: return int(round(np.interp(v_ego, [0.0, 6.0, 15.0, 30.0], [40.0, 85.0, 130.0, 170.0]))) -def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool) -> float: +def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool, + lead_visible: bool = False, set_speed_error: float = 0.0) -> float: if not enabled or accel <= 0.0 or v_ego < 12.0: return accel low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.95, 0.88, 0.82, 0.76])) mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.98, 0.94, 0.89, 0.84])) + if lead_visible and set_speed_error > 0.0: + follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.08, 0.18, 0.35, 0.55])) + low_scale += (1.0 - low_scale) * follow_relief + mid_scale += (1.0 - mid_scale) * follow_relief + if accel <= 0.12: return accel * low_scale if accel <= 0.35: @@ -939,7 +945,13 @@ class CarController(CarControllerBase): getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and not self.CP.enableGasInterceptorDEPRECATED ): - accel_input = shape_truck_positive_accel(accel_input, CS.out.vEgo, True) + accel_input = shape_truck_positive_accel( + accel_input, + CS.out.vEgo, + True, + lead_visible=CC.hudControl.leadVisible, + set_speed_error=max(CC.hudControl.setSpeed - CS.out.vEgo, 0.0), + ) accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max)) torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2)) diff --git a/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py b/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py index 96d83d5c4..120f9b7d9 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py @@ -817,6 +817,21 @@ def test_shape_truck_positive_accel_is_inactive_when_disabled_or_low_speed(): assert shape_truck_positive_accel(0.12, 6.0, True) == 0.12 +def test_shape_truck_positive_accel_preserves_more_follow_authority_with_lead(): + base = shape_truck_positive_accel(0.28, 26.0, True) + relieved = shape_truck_positive_accel(0.28, 26.0, True, lead_visible=True, set_speed_error=6.0) + + assert relieved > base + assert relieved < 0.28 + + +def test_shape_truck_positive_accel_does_not_relax_without_speed_error(): + base = shape_truck_positive_accel(0.28, 26.0, True) + no_error = shape_truck_positive_accel(0.28, 26.0, True, lead_visible=True, set_speed_error=0.0) + + assert no_error == base + + def test_use_interceptor_sng_launch_requires_actual_near_stop(): CP = SimpleNamespace(vEgoStarting=0.25) diff --git a/opendbc_repo/opendbc/car/hyundai/carcontroller.py b/opendbc_repo/opendbc/car/hyundai/carcontroller.py index d146d002f..6fe5cdf05 100644 --- a/opendbc_repo/opendbc/car/hyundai/carcontroller.py +++ b/opendbc_repo/opendbc/car/hyundai/carcontroller.py @@ -69,6 +69,8 @@ DEFAULT_ANGLE_SMOOTHING_ALPHA_V = [0.2, 0.1, 0.0] EV9_HIGH_ANGLE_GAIN_BP = [70.0, 120.0, 220.0, 320.0] EV9_HIGH_ANGLE_GAIN_CAP_V = [0.85, 0.55, 0.30, 0.16] EV9_HIGH_ANGLE_GAIN_MIN = 0.004 +EV9_DRIVER_OVERRIDE_GAIN_BP = [125.0, 250.0, 375.0] +EV9_DRIVER_OVERRIDE_GAIN_CAP_V = [0.70, 0.12, 0.0] def egmp_dynamic_longitudinal_tuning(CP) -> bool: @@ -246,12 +248,20 @@ def compute_torque_reduction_gain(steering_torque, v_ego, lat_active, last_gain) return round(gain / 0.004) * 0.004 -def apply_ev9_high_angle_gain_cap(CP, gain: float, steering_angle_deg: float, lat_active: bool) -> float: +def apply_ev9_high_angle_gain_cap(CP, gain: float, steering_angle_deg: float, lat_active: bool, + steering_torque: float = 0.0, steering_pressed: bool = False) -> float: if CP.carFingerprint != CAR.KIA_EV9 or not CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING or not lat_active: return gain cap = float(np.interp(abs(steering_angle_deg), EV9_HIGH_ANGLE_GAIN_BP, EV9_HIGH_ANGLE_GAIN_CAP_V)) - return max(EV9_HIGH_ANGLE_GAIN_MIN, min(gain, cap)) + gain = max(EV9_HIGH_ANGLE_GAIN_MIN, min(gain, cap)) + + if steering_pressed or abs(steering_torque) >= EV9_DRIVER_OVERRIDE_GAIN_BP[0]: + driver_override_cap = float(np.interp(abs(steering_torque), EV9_DRIVER_OVERRIDE_GAIN_BP, + EV9_DRIVER_OVERRIDE_GAIN_CAP_V)) + gain = min(gain, driver_override_cap) + + return gain def process_hud_alert(enabled, fingerprint, hud_control): @@ -410,7 +420,8 @@ class CarController(CarControllerBase): CS.out.steeringAngleDeg, CC.latActive, self.params, self.BASELINE_VM) apply_torque = compute_torque_reduction_gain(CS.out.steeringTorque, v_ego_raw, CC.latActive, self.apply_torque_last) - apply_torque = apply_ev9_high_angle_gain_cap(self.CP, apply_torque, CS.out.steeringAngleDeg, CC.latActive) + apply_torque = apply_ev9_high_angle_gain_cap(self.CP, apply_torque, CS.out.steeringAngleDeg, CC.latActive, + CS.out.steeringTorque, CS.out.steeringPressed) apply_steer_req = CC.latActive and apply_torque != 0.0 torque_fault = False diff --git a/opendbc_repo/opendbc/car/hyundai/hyundaicanfd.py b/opendbc_repo/opendbc/car/hyundai/hyundaicanfd.py index db09fa590..ce2134c78 100644 --- a/opendbc_repo/opendbc/car/hyundai/hyundaicanfd.py +++ b/opendbc_repo/opendbc/car/hyundai/hyundaicanfd.py @@ -138,7 +138,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque, "LKA_RHLnWrnSta": 0, "LKA_HndsoffSnd": 0, "LKA_StrSnd": 0, - "LKA_SysIndReq": 2 if enabled else 1, + "LKA_SysIndReq": 2 if enabled or lat_active else 1, "StrTqReqVal": 0, "ActToiSta": 0, "ToiFltSta": 0, diff --git a/opendbc_repo/opendbc/car/hyundai/interface.py b/opendbc_repo/opendbc/car/hyundai/interface.py index 468d578d8..03a6022f0 100644 --- a/opendbc_repo/opendbc/car/hyundai/interface.py +++ b/opendbc_repo/opendbc/car/hyundai/interface.py @@ -148,6 +148,8 @@ class CarInterface(CarInterfaceBase): if ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING: ret.steerControlType = structs.CarParams.SteerControlType.angle ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_ANGLE_STEERING.value + if candidate == CAR.KIA_EV9: + ret.steerAtStandstill = True if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING: ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value diff --git a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py index 15cadf7ae..ba6b6dea8 100644 --- a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py +++ b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py @@ -297,7 +297,17 @@ class TestHyundaiFingerprint: assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 320.0, True) == pytest.approx(0.16) assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.0, 320.0, True) > 0.0 assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 320.0, False) == pytest.approx(0.70) + assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 30.0, True, 250.0, True) == pytest.approx(0.12) + assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 30.0, True, 400.0, True) == pytest.approx(0.0) assert apply_ev9_high_angle_gain_cap(sportage_cp, 0.70, 320.0, True) == pytest.approx(0.70) + assert apply_ev9_high_angle_gain_cap(sportage_cp, 0.70, 30.0, True, 400.0, True) == pytest.approx(0.70) + + def test_ev9_allows_lateral_at_standstill_without_changing_other_angle_platforms(self): + ev9_cp = CarInterface.get_params(CAR.KIA_EV9, gen_empty_fingerprint(), [], False, False, False, None) + sportage_cp = CarInterface.get_params(CAR.KIA_SPORTAGE_HEV_2026, gen_empty_fingerprint(), [], False, False, False, None) + + assert ev9_cp.steerAtStandstill + assert not sportage_cp.steerAtStandstill def test_ccnc_hda2_lka_layout_does_not_set_ccnc_safety_param(self): fingerprint = gen_empty_fingerprint() @@ -1848,7 +1858,7 @@ class TestHyundaiFingerprint: "DAMP_FACTOR": 0, } - msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, True, True, 0.44, -31.5, + msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, False, True, 0.44, -31.5, lkas_base_values=stock_lkas, lka_icon=2) lkas_msgs = [msg for msg in msgs if msg[0] == 0x110] assert len(lkas_msgs) == 1 diff --git a/opendbc_repo/opendbc/car/toyota/carcontroller.py b/opendbc_repo/opendbc/car/toyota/carcontroller.py index a2297e1a4..918672906 100644 --- a/opendbc_repo/opendbc/car/toyota/carcontroller.py +++ b/opendbc_repo/opendbc/car/toyota/carcontroller.py @@ -26,7 +26,7 @@ ACCEL_WINDDOWN_LIMIT = -4.0 * DT_CTRL * 3 # m/s^2 / frame ACCEL_PID_UNWIND = 0.03 * DT_CTRL * 3 # m/s^2 / frame PRIUS_INTEGRAL_MISMATCH_UNWIND = 8.0 PRIUS_POSITIVE_FEEDFORWARD_SCALE = 0.7 -PRIUS_CRUISE_FEEDFORWARD_SCALE = 0.85 +PRIUS_CRUISE_FEEDFORWARD_SCALE = 1.0 MAX_PITCH_COMPENSATION = 1.5 # m/s^2 TOYOTA_COAST_BRAKE_MIN_SPEED = 15.0 # m/s diff --git a/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py b/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py index 2b444a8f9..be3071ef8 100644 --- a/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py +++ b/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py @@ -306,7 +306,7 @@ class TestToyotaCarController: def test_prius_positive_feedforward_scale_restores_cruise_authority(self): assert get_prius_positive_feedforward_scale(20.0) > get_prius_positive_feedforward_scale(8.0) - assert abs(get_prius_positive_feedforward_scale(20.0) - 0.85) < 1e-6 + assert abs(get_prius_positive_feedforward_scale(20.0) - 1.0) < 1e-6 def test_sng_hack_clears_existing_standstill_latch(self): controller = self._make_controller(standstill_req=True, last_standstill=True) diff --git a/selfdrive/controls/lib/latcontrol_pid.py b/selfdrive/controls/lib/latcontrol_pid.py index 5605d72e2..56928f269 100644 --- a/selfdrive/controls/lib/latcontrol_pid.py +++ b/selfdrive/controls/lib/latcontrol_pid.py @@ -7,11 +7,28 @@ from openpilot.starpilot.common.testing_grounds import testing_ground from openpilot.selfdrive.controls.lib.latcontrol import LatControl from openpilot.common.pid import PIDController +HONDA_PID_GAIN_SCALE_MIN = 0.1 +HONDA_PID_GAIN_SCALE_MAX = 4.0 + def civic_bosch_modified_lateral_testing_ground_active() -> bool: return testing_ground.use("8", "B") +def get_honda_lateral_pid_gain_scale(value) -> float: + try: + scale = float(value) + except (TypeError, ValueError): + return 1.0 + if not math.isfinite(scale): + return 1.0 + return min(max(scale, HONDA_PID_GAIN_SCALE_MIN), HONDA_PID_GAIN_SCALE_MAX) + + +def scale_lateral_pid_gain_values(values, scale: float) -> list[float]: + return [float(value) * scale for value in values] + + def get_civic_bosch_modified_pid_output_scale(desired_angle_deg: float, desired_angle_delta_deg: float, v_ego: float) -> float: abs_angle = abs(desired_angle_deg) speed_weight = min(max((v_ego - 4.0) / 10.0, 0.0), 1.0) @@ -67,18 +84,41 @@ def get_civic_bosch_modified_pid_output_alpha(desired_angle_deg: float, desired_ class LatControlPID(LatControl): def __init__(self, CP, CI, dt): super().__init__(CP, CI, dt) - self.pid = PIDController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV), - (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV), + self.base_kp_bp = [float(value) for value in CP.lateralTuning.pid.kpBP] + self.base_kp_v = [float(value) for value in CP.lateralTuning.pid.kpV] + self.base_ki_bp = [float(value) for value in CP.lateralTuning.pid.kiBP] + self.base_ki_v = [float(value) for value in CP.lateralTuning.pid.kiV] + self.pid = PIDController((self.base_kp_bp, self.base_kp_v), + (self.base_ki_bp, self.base_ki_v), pos_limit=self.steer_max, neg_limit=-self.steer_max) self.ff_factor = CP.lateralTuning.pid.kf self.get_steer_feedforward = CI.get_steer_feedforward_function() + self.is_honda_pid_lateral = CP.brand == "honda" + self.honda_lateral_pid_kp_scale = 1.0 + self.honda_lateral_pid_ki_scale = 1.0 self.is_civic_bosch_modified = CP.carFingerprint == HONDA.HONDA_CIVIC_BOSCH and bool(CP.flags & HondaFlags.EPS_MODIFIED) self.prev_angle_steers_des_no_offset = 0.0 self.modified_civic_steering_pressed_filter_s = 0.0 self.modified_civic_steering_pressed_prev = False self.prev_output_torque = 0.0 + def update_honda_lateral_pid_gain_scale(self, starpilot_toggles): + if not self.is_honda_pid_lateral: + return + + kp_scale = get_honda_lateral_pid_gain_scale(getattr(starpilot_toggles, "honda_lateral_pid_kp_scale", 1.0)) + ki_scale = get_honda_lateral_pid_gain_scale(getattr(starpilot_toggles, "honda_lateral_pid_ki_scale", 1.0)) + if math.isclose(kp_scale, self.honda_lateral_pid_kp_scale) and math.isclose(ki_scale, self.honda_lateral_pid_ki_scale): + return + + self.honda_lateral_pid_kp_scale = kp_scale + self.honda_lateral_pid_ki_scale = ki_scale + self.pid._k_p = [self.base_kp_bp, scale_lateral_pid_gain_values(self.base_kp_v, kp_scale)] + self.pid._k_i = [self.base_ki_bp, scale_lateral_pid_gain_values(self.base_ki_v, ki_scale)] + def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, lat_delay, calibrated_pose, model_data, starpilot_toggles): + self.update_honda_lateral_pid_gain_scale(starpilot_toggles) + pid_log = log.ControlsState.LateralPIDState.new_message() pid_log.steeringAngleDeg = float(CS.steeringAngleDeg) pid_log.steeringRateDeg = float(CS.steeringRateDeg) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 9901f9c54..45a5928b6 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -45,6 +45,27 @@ def get_bolt_acc_pedal_friction_bias(output_accel, a_target, v_ego): return float(min(authority_gap * 0.30, max_bias) * speed_factor) +def get_bolt_acc_pedal_feedforward_gain(feedforward_gain, a_target, v_ego, pedal_regen_limit, last_output_accel): + effective_gain = feedforward_gain + if a_target >= 0.0: + return effective_gain + + restore = 0.0 + + if a_target < pedal_regen_limit: + friction_gap = pedal_regen_limit - a_target + restore = float(interp(friction_gap, [0.0, 0.25, 0.75], [0.0, 0.6, 1.0])) + + if v_ego > 5.0 and a_target < -1.10: + authority_gap = max(0.0, abs(a_target) - abs(min(last_output_accel, 0.0))) + target_restore = float(interp(abs(a_target), [1.1, 1.6, 2.2, 3.0], [0.0, 0.25, 0.55, 1.0])) + gap_restore = float(interp(authority_gap, [0.2, 0.6, 1.0, 1.6], [0.0, 0.25, 0.60, 1.0])) + speed_factor = float(interp(v_ego, [5.0, 8.0, 12.0, 18.0], [0.0, 0.35, 0.75, 1.0])) + restore = max(restore, max(target_restore, gap_restore) * speed_factor) + + return float(feedforward_gain + ((1.0 - feedforward_gain) * clip(restore, 0.0, 1.0))) + + def long_control_state_trans(CP, active, long_control_state, v_ego, should_stop, brake_pressed, cruise_standstill, starpilot_toggles, allow_stopping_release=True): @@ -346,12 +367,9 @@ class LongControl: return feedforward pedal_regen_limit = float(interp(v_ego, BOLT_ACC_PEDAL_REGEN_LIMIT_BP, BOLT_ACC_PEDAL_REGEN_LIMIT_V)) - if a_target >= pedal_regen_limit: - return feedforward - - friction_gap = pedal_regen_limit - a_target - gain_restore = float(interp(friction_gap, [0.0, 0.25, 0.75], [0.0, 0.6, 1.0])) - effective_gain = self.feedforward_gain + ((1.0 - self.feedforward_gain) * gain_restore) + effective_gain = get_bolt_acc_pedal_feedforward_gain( + self.feedforward_gain, a_target, v_ego, pedal_regen_limit, self.last_output_accel, + ) return a_target * effective_gain def update(self, active, CS, a_target, should_stop, accel_limits, starpilot_toggles): diff --git a/selfdrive/controls/tests/test_latcontrol.py b/selfdrive/controls/tests/test_latcontrol.py index 16a8e19ae..492e4cdc5 100644 --- a/selfdrive/controls/tests/test_latcontrol.py +++ b/selfdrive/controls/tests/test_latcontrol.py @@ -707,6 +707,24 @@ class TestLatControl: assert tapered_output == pytest.approx(base_output) + def test_honda_pid_gain_scales_update_live_from_opendbc_baseline(self): + controller, VM, CS, params, _ = self._build_pid_controller(HONDA.HONDA_ACCORD) + base_kp_v = list(controller.base_kp_v) + base_ki_v = list(controller.base_ki_v) + + starpilot_toggles = SimpleNamespace(honda_lateral_pid_kp_scale=1.5, honda_lateral_pid_ki_scale=0.75) + controller.update(True, CS, VM, params, False, 0.0025, False, 0.2, None, None, starpilot_toggles) + + assert controller.pid._k_p[1] == pytest.approx([value * 1.5 for value in base_kp_v]) + assert controller.pid._k_i[1] == pytest.approx([value * 0.75 for value in base_ki_v]) + + starpilot_toggles.honda_lateral_pid_kp_scale = 2.0 + starpilot_toggles.honda_lateral_pid_ki_scale = 1.25 + controller.update(True, CS, VM, params, False, 0.0025, False, 0.2, None, None, starpilot_toggles) + + assert controller.pid._k_p[1] == pytest.approx([value * 2.0 for value in base_kp_v]) + assert controller.pid._k_i[1] == pytest.approx([value * 1.25 for value in base_ki_v]) + def test_modified_civic_b_torque_path_uses_fixed_friction_threshold(self, monkeypatch): CarInterface = interfaces[HONDA.HONDA_CIVIC_BOSCH] CP = CarInterface.get_non_essential_params(HONDA.HONDA_CIVIC_BOSCH) diff --git a/selfdrive/controls/tests/test_longcontrol.py b/selfdrive/controls/tests/test_longcontrol.py index 30fdc7a5e..cd2dcccd1 100644 --- a/selfdrive/controls/tests/test_longcontrol.py +++ b/selfdrive/controls/tests/test_longcontrol.py @@ -5,7 +5,11 @@ import pytest import openpilot.selfdrive.controls.lib.longcontrol as longcontrol from opendbc.car.gm.values import CAR, GMFlags -from openpilot.selfdrive.controls.lib.longcontrol import LongControl, LongCtrlState, long_control_state_trans +from openpilot.selfdrive.controls.lib.longcontrol import ( + LongControl, + LongCtrlState, + long_control_state_trans, +) def make_toggles(**overrides): @@ -510,12 +514,30 @@ def test_bolt_acc_pedal_friction_feedforward_blends_back_in_for_small_friction_r pedal_regen_limit = float(longcontrol.interp(20.0, longcontrol.BOLT_ACC_PEDAL_REGEN_LIMIT_BP, longcontrol.BOLT_ACC_PEDAL_REGEN_LIMIT_V)) a_target = pedal_regen_limit - 0.10 - gain_restore = float(longcontrol.interp(0.10, [0.0, 0.25, 0.75], [0.0, 0.6, 1.0])) - expected = a_target * (0.20 + ((1.0 - 0.20) * gain_restore)) + expected_gain = longcontrol.get_bolt_acc_pedal_feedforward_gain(0.20, a_target, 20.0, pedal_regen_limit, 0.0) + expected = a_target * expected_gain assert lc._get_longitudinal_feedforward(a_target, 20.0) == pytest.approx(expected) +def test_bolt_acc_pedal_feedforward_gain_stays_base_for_mild_regen(): + gain = longcontrol.get_bolt_acc_pedal_feedforward_gain(0.2, -1.0, 10.0, -2.75, -0.4) + + assert gain == pytest.approx(0.2) + + +def test_bolt_acc_pedal_feedforward_gain_restores_for_authority_gap(): + gain = longcontrol.get_bolt_acc_pedal_feedforward_gain(0.2, -1.83, 12.38, -2.79, -0.70) + + assert gain > 0.55 + + +def test_bolt_acc_pedal_feedforward_gain_restores_near_friction_handoff(): + gain = longcontrol.get_bolt_acc_pedal_feedforward_gain(0.2, -2.63, 9.35, -2.69, -1.30) + + assert gain > 0.45 + + def test_bolt_cc_pedal_friction_feedforward_remains_fully_scaled_by_kf(): CP = make_longcontrol_cp( brand="gm", diff --git a/starpilot/common/starpilot_variables.py b/starpilot/common/starpilot_variables.py index 262c61a96..af2b9fcba 100644 --- a/starpilot/common/starpilot_variables.py +++ b/starpilot/common/starpilot_variables.py @@ -686,6 +686,9 @@ class StarPilotVariables: toggle.use_custom_latAccelFactor = bool(round(toggle.latAccelFactor, 2) != round(latAccelFactor, 2)) and is_torque_car and not toggle.force_auto_tune or toggle.force_auto_tune_off toggle.steerRatio = self.get_value("SteerRatio", cast=float, condition=advanced_lateral_tuning, default=steerRatio, min=steerRatio * 0.5, max=steerRatio * 1.5) toggle.use_custom_steerRatio = bool(round(toggle.steerRatio, 2) != round(steerRatio, 2)) and not toggle.force_auto_tune or toggle.force_auto_tune_off + honda_pid_lateral = toggle.car_make == "honda" and CP.lateralTuning.which() == "pid" and not is_angle_car + toggle.honda_lateral_pid_kp_scale = self.get_value("HondaLateralPidKpScale", cast=float, condition=honda_pid_lateral, default=1.0, min=0.1, max=4.0) + toggle.honda_lateral_pid_ki_scale = self.get_value("HondaLateralPidKiScale", cast=float, condition=honda_pid_lateral, default=1.0, min=0.1, max=4.0) advanced_longitudinal_tuning = toggle.openpilot_longitudinal and self.get_value("AdvancedLongitudinalTune") ev_vehicle = default_ev_tuning_enabled(CP) @@ -1357,6 +1360,8 @@ class StarPilotVariables: toggle.radar_tracks = False toggle.show_stopping_point = False toggle.show_stopping_point_metrics = False + toggle.honda_lateral_pid_kp_scale = 1.0 + toggle.honda_lateral_pid_ki_scale = 1.0 toggle.goat_scream_alert = False toggle.goat_scream_critical_alerts = False diff --git a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json index 54016ca65..4998138cb 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json +++ b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json @@ -3616,6 +3616,28 @@ "step": 0.01, "precision": 2 }, + { + "key": "HondaLateralPidKpScale", + "label": "Honda PID Kp Scale", + "description": "Scale the active Honda lateralTuning.pid.kpV values from openDBC. Applies live to Honda PID lateral only.", + "data_type": "float", + "ui_type": "numeric", + "min": 0.1, + "max": 4.0, + "step": 0.05, + "precision": 2 + }, + { + "key": "HondaLateralPidKiScale", + "label": "Honda PID Ki Scale", + "description": "Scale the active Honda lateralTuning.pid.kiV values from openDBC. Applies live to Honda PID lateral only.", + "data_type": "float", + "ui_type": "numeric", + "min": 0.1, + "max": 4.0, + "step": 0.05, + "precision": 2 + }, { "key": "AllowImpossibleAcceleration", "label": "Allow Impossible Acceleration",