diff --git a/AtmosphereAutopilot/Modules/CruiseController.cs b/AtmosphereAutopilot/Modules/CruiseController.cs index 4d992f0..c71d717 100644 --- a/AtmosphereAutopilot/Modules/CruiseController.cs +++ b/AtmosphereAutopilot/Modules/CruiseController.cs @@ -38,7 +38,13 @@ public sealed class CruiseController : StateController { internal CruiseController(Vessel v) : base(v, "Cruise Flight controller", 88437226) - { } + { + flc_controller.KP = 0.6; + flc_controller.KI = 0.03; + flc_controller.KD = 0.2; + flc_controller.IntegralClamp = double.PositiveInfinity; + flc_controller.AccumulatorClamp = double.PositiveInfinity; + } FlightModel imodel; DirectorController dir_c; @@ -229,14 +235,24 @@ public enum HeightMode [VesselSerializable("desired_vertspeed_field")] public DelayedFieldFloat desired_vertspeed = new DelayedFieldFloat(0.0f, "G4"); - [GlobalSerializable("preudo_flc")] - [VesselSerializable("preudo_flc")] - [AutoGuiAttr("pseudo-FLC", true)] - public bool pseudo_flc = true; + [GlobalSerializable("pseudo_flc")] + [VesselSerializable("pseudo_flc")] + [AutoGuiAttr("pseudo_flc", true)] + public bool pseudo_flc = false; + + PIDController flc_controller = new PIDController(); + + [VesselSerializable("flc_pid_Kp")] + [AutoGuiAttr("flc_pid_Kp", true, "G4")] + public double flc_pid_Kp { get { return flc_controller.KP; } set { flc_controller.KP = value; } } - [VesselSerializable("flc_margin")] - [AutoGuiAttr("flc_margin", true, "G4")] - public double flc_margin = 20.0; + [VesselSerializable("flc_pid_Ki")] + [AutoGuiAttr("flc_pid_Ki", true, "G4")] + public double flc_pid_Ki { get { return flc_controller.KI; } set { flc_controller.KI = value; } } + + [VesselSerializable("flc_pid_Kd")] + [AutoGuiAttr("flc_pid_Kd", true, "G4")] + public double flc_pid_Kd { get { return flc_controller.KD; } set { flc_controller.KD = value; } } [VesselSerializable("strength_mult")] [AutoGuiAttr("strength_mult", true, "G5")] @@ -278,6 +294,10 @@ Vector3d account_for_height(Vector3d desired_direction) Vector3d proportional_acc = Vector3d.zero; double cur_vert_speed = Vector3d.Dot(imodel.surface_v, planet2vesNorm); + + // speed control portion for ascent\descent + double effective_max_climb_angle = max_climb_angle; + if (Math.Abs(height_error) < height_relax_frame) { relax_transition_k = Common.Clamp(2.0 * (height_relax_frame - Math.Abs(height_error)), 0.0, 1.0); @@ -286,6 +306,30 @@ Vector3d account_for_height(Vector3d desired_direction) // exponential descent if (cur_vert_speed * height_error > 0.0) proportional_acc = -planet2vesNorm * height_relax_Kp * cur_vert_speed; + flc_controller.clear(); + } + else if (pseudo_flc) + { + // refactored flc using pid loop + double flc_pid_control = flc_controller.Control(imodel.surface_v_magnitude, thrust_c.setpoint.mps(), TimeWarp.fixedDeltaTime); + if (height_error >= 0.0) + { + effective_max_climb_angle = Common.Clamp(-flc_pid_control, 0.1, max_climb_angle); + if (thrust_c.spd_control_enabled) + thrust_c.ForceThrottle(1.0f); + } + else + { + effective_max_climb_angle = Common.Clamp(-flc_pid_control, -max_climb_angle, -0.1); + if (thrust_c.spd_control_enabled) + thrust_c.ForceThrottle(0.0f); + } + + } + else + { + effective_max_climb_angle *= Math.Max(0.0, Math.Min(1.0, vessel.srfSpeed / thrust_c.setpoint.mps())); + flc_controller.clear(); } // let's assume parabolic ascent\descend @@ -304,32 +348,6 @@ Vector3d account_for_height(Vector3d desired_direction) parabolic_acc = -planet2vesNorm * 0.5 * cur_vert_speed * cur_vert_speed / height_error; } - // speed control portion for ascend - double effective_max_climb_angle = max_climb_angle; - if (thrust_c.spd_control_enabled && (height_error >= 0.0)) - { - if (pseudo_flc) - { - filtered_drag = Common.simple_filter(thrust_c.drag_estimate, filtered_drag, 5.0); - if (thrust_c.estimated_max_thrust > filtered_drag) - { - double sin = Vector3d.Dot(-planet2vesNorm, imodel.gravity_acc + imodel.noninert_acc) / (thrust_c.estimated_max_thrust - filtered_drag); - if (sin < 0.0 || sin >= 1.0) - effective_max_climb_angle = Math.Min(Math.Asin(sin), max_climb_angle); - } - else - effective_max_climb_angle = 1.0; - - double spd_diff = (imodel.surface_v_magnitude - thrust_c.setpoint.mps()); - if (spd_diff < -flc_margin) - effective_max_climb_angle *= 0.0; - else if (spd_diff < 0.0) - effective_max_climb_angle *= (spd_diff + flc_margin) / flc_margin; - } - else - effective_max_climb_angle *= Math.Max(0.0, Math.Min(1.0, vessel.srfSpeed / thrust_c.setpoint.mps())); - } - double max_vert_speed = vessel.horizontalSrfSpeed * Math.Tan(effective_max_climb_angle * dgr2rad); bool apply_acc = Math.Abs(des_vert_speed) < max_vert_speed; des_vert_speed = Common.Clamp(des_vert_speed, max_vert_speed); diff --git a/AtmosphereAutopilot/Modules/ProgradeThrustController.cs b/AtmosphereAutopilot/Modules/ProgradeThrustController.cs index 947c6ee..fe14e4b 100644 --- a/AtmosphereAutopilot/Modules/ProgradeThrustController.cs +++ b/AtmosphereAutopilot/Modules/ProgradeThrustController.cs @@ -176,6 +176,22 @@ protected override void OnDeactivate() private bool was_breaking_previously = true; + private bool is_throttle_forced = false; + private float forced_throttle = 0.0f; + + /// + /// Allow other module to force throttle output in the next frame + /// + /// Desired throttle for this frame + /// Achievable throttle regarding the desired throttle + public float ForceThrottle(float throttle) + { + is_throttle_forced = true; + forced_throttle = Common.Clampf(throttle, 0.0f, 1.0f); + // Currently throttle output is always the same to the desired input + return throttle; + } + /// /// Main control function /// @@ -183,6 +199,19 @@ protected override void OnDeactivate() /// Prograde surface speed setpoint public override float ApplyControl(FlightCtrlState cntrl, float target_value) { + if (is_throttle_forced) + { + if (use_breaks && was_breaking_previously) + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); + was_breaking_previously = false; + } + + is_throttle_forced = false; + cntrl.mainThrottle = forced_throttle; + return cntrl.mainThrottle; + } + current_v = imodel.surface_v_magnitude; desired_v = target_value;