adaptive_pid:
  ros__parameters:
    # Control loop
    control_rate: 100.0           # Hz
    balance_setpoint_rad: 0.0     # target tilt (rad); 0 = upright

    # PID gains per weight class
    # Tune: heavier loads need more proportional gain to overcome inertia
    kp_empty: 15.0
    ki_empty:  0.5
    kd_empty:  1.5

    kp_light: 18.0
    ki_light:  0.6
    kd_light:  2.0

    kp_heavy: 22.0
    ki_heavy:  0.8
    kd_heavy:  2.5

    # Safety bounds — ALL gains are hard-clamped to these regardless of source
    kp_min:  5.0
    kp_max: 40.0
    ki_min:  0.0
    ki_max:  5.0
    kd_min:  0.0
    kd_max: 10.0
    output_min: -50.0             # balance effort clamp
    output_max:  50.0
    i_clamp:    10.0              # anti-windup integrator clamp

    # Weight classification thresholds (kg)
    weight_empty_max_kg: 0.5      # ≤ 0.5 kg  → empty
    weight_light_max_kg: 2.0      # ≤ 2.0 kg  → light; > 2.0 → heavy

    # Weight estimation from motor current
    idle_current_a:           0.5    # motor current at rest with no payload (A)
    current_per_kg_a:         0.3    # current increase per kg payload (A/kg)
    weight_window_s:          3.0    # rolling-average window (s)
    weight_change_threshold_kg: 0.3  # triggers gain reschedule when exceeded
    steady_tilt_threshold_rad: 0.05  # max tilt to accept current sample

    # Gain blending
    gain_blend_alpha: 0.05   # convergence rate per tick (0=no change, 1=instant)
                             # at 100 Hz: ~0.4 s to 50 % of target, ~0.9 s to 90 %

    # Instability detection
    instability_tilt_threshold_rad: 0.4   # |tilt| exceeds this → suspect
    instability_oscillation_count:   6    # sign reversals in window → unstable
    instability_window_size:        100   # samples (~1 s at 100 Hz)

    # IMU watchdog
    imu_timeout_s: 0.5   # zero effort if IMU goes silent

    # Dynamic reconfigure / manual override
    # Set override_enabled=true + override_kp/ki/kd to bypass scheduling
    override_enabled: false
    override_kp: 15.0
    override_ki:  0.5
    override_kd:  1.5

    # Calibration routine (rock-and-settle)
    calibration_amplitude_rad: 0.05   # rocking amplitude
    calibration_frequency_hz:  0.5    # rocking frequency
    calibration_cycles:        3      # number of rock cycles (duration = cycles/freq)
    calibration_settle_s:      2.0    # settling window after rocking
