diff --git a/MechJeb2/MechJebModuleGuidanceController.cs b/MechJeb2/MechJebModuleGuidanceController.cs index 5774ced5e..63abe53c2 100644 --- a/MechJeb2/MechJebModuleGuidanceController.cs +++ b/MechJeb2/MechJebModuleGuidanceController.cs @@ -129,7 +129,7 @@ private bool WillDoRCSButNotYet() bool hasRCS = Vessel.hasEnabledRCSModules() && VesselState.RCSThrustAvailable.Up > 0.1 * VesselState.RCSThrustAvailable.MaxMagnitude(); - return hasRCS && Status != PSGStatus.TERMINAL_RCS && Core.StageStats.VacStats.Count - 1 <= Solution.TerminalMJPhase(); + return hasRCS && Status != PSGStatus.TERMINAL_RCS && Vessel.currentStage == Solution.TerminalKSPStage(); } private void HandleTerminal() @@ -150,6 +150,21 @@ private void HandleTerminal() return; } + /* + * FIXME: consider liquid booster()s + unguided beehive cluster + * + * 1. we should enter terminal guidance on the top liquid booster and shut it down precisely and suspend the optimizer + * there because we CANNOT use the residuals because we're about to loose our degrees of freedom. but the optimizer should + * have burned this stage to completion. we also don't want to use TERMINAL_RCS here. + * 2. we should still enter terminal guidance on the top aerobee stage and precisely shut it down to actually hit the target as + * best as possible, and this burntime should have been tuned by the optimizer. we do want to use TERMINAL_RCS here. + * + * Right now we only support one OptimizeKSPStage() and really the SolutionBuilder needs to know to slap a PreciseShutdown flag + * onto the last liquid booster segment (even though the optimizer didn't optimize it) and likely could use the same flag for + * precise shutdown of engines before a coast. Although maybe there should be two different flags (for precise shutdown with + * and without RCS cleanup). + */ + // this handles termination of thrust for final stages of "fixed" burntime rockets (due to residuals Tgo may go less than zero so we // wait for natural termination of thrust). no support for RCS terminal trim. if (Solution.OptimizeKSPStage() < 0 && Vessel.currentStage <= Solution.TerminalKSPStage() && Solution.Tgo(VesselState.Time) <= 0 && @@ -169,26 +184,16 @@ private void HandleTerminal() Status = PSGStatus.BURNING; } - // We should either be in an non-upper stage optimized stage, or we should be within 10 seconds of the whole - // burntime in order to enter terminal guidance. - if (Vessel.currentStage != Solution.OptimizeKSPStage() && Solution.Tgo(VesselState.Time) > 10) + // we need to have an optimizable stage to run terminal guidance + if (Vessel.currentStage != Solution.OptimizeKSPStage()) return; - // The includeCoast: false flag here is to skip a coast which is in the past in the Solution when - // we are ending the coast and the optimizer hasn't run the solution, but CoastBefore is set so - // that both the coast and burn have the same KSPStage. So we want the index of the current burn - // and not the index of the first matching KSPStage in the Solution which is the coast. Might - // also consider modifying APIs like IndexForKSPStage to omit stages which are in the past -- but - // I have concerns about that with residuals where you may currently be in a burning stage which - // is in the "past" in the Solution but you're burning down residuals and you don't know when - // the stage will actually run out (assuming it isn't a burn before a coast or an optimized burntime - // so that we burn past the end of the stage and into whatever residuals are available). - int solutionIndex = Solution.IndexForKSPStage(Vessel.currentStage, Core.Guidance.IsCoasting()); - if (solutionIndex < 0) + // we need to be within 10 seconds of the end of the stage to run terminal guidance + if (Solution.TgoForKSPStage(VesselState.Time, Vessel.currentStage) > 10) return; - // Only enter terminal guidance within 10 seconds of the current stage - if (Solution.Tgo(VesselState.Time, solutionIndex) > 10) + // but if we're doing a coast, or going to do a coast we don't enter terminal guidance yet + if (Vessel.currentStage == Solution.CoastKSPStage() && Solution.WillCoast(VesselState.Time)) return; if (Status != PSGStatus.TERMINAL_RCS) diff --git a/MechJebLib/PSG/Solution.cs b/MechJebLib/PSG/Solution.cs index 39de53771..88e5b6dc7 100644 --- a/MechJebLib/PSG/Solution.cs +++ b/MechJebLib/PSG/Solution.cs @@ -239,6 +239,19 @@ public double Tgo(double t, int n) return TgoBar(tbar, n) * _timeScale; } + public double TgoForKSPStage(double t, int kspStage) + { + double tbar = (t - T0) / _timeScale; + double sum = 0; + for (int i = IndexForTbar(tbar); i < Phases.Count && Phases[i].KSPStage == kspStage; i++) + { + if (Phases[i].Coast) + continue; + sum += TgoBar(tbar, i) * _timeScale; + } + return sum; + } + public double TgoBar(double tbar, int n) { if (tbar > _tmin[n]) @@ -255,6 +268,7 @@ public bool Coast(double t) } // Specialized API to determine if we still have the coast in our future or not + // (or if we're in a coast right now) public bool WillCoast(double t) { double tbar = (t - T0) / _timeScale;