public void ForceSimunlation() { try { simulationRunning = true; stopwatch.Start(); //starts a timer that times how long the simulation takes //Create two FuelFlowSimulations, one for vacuum and one for atmosphere List <Part> parts = (HighLogic.LoadedSceneIsEditor ? EditorLogic.fetch.ship.parts : vessel.parts); sims[0].Init(parts, dVLinearThrust); sims[1].Init(parts, dVLinearThrust); RunSimulation(sims); } catch (Exception e) { GravityTurner.Log("Exception in StageStats.ForceSimunlation(): {0}", e.ToString()); // Stop timing the simulation stopwatch.Stop(); millisecondsBetweenSimulations = 500; stopwatch.Reset(); // Start counting down the time to the next simulation stopwatch.Start(); simulationRunning = false; } }
protected void RunSimulation(object o) { try { CelestialBody simBody = HighLogic.LoadedSceneIsEditor ? editorBody : vessel.mainBody; double staticPressureKpa = (HighLogic.LoadedSceneIsEditor || !liveSLT ? (simBody.atmosphere ? simBody.GetPressure(0) : 0) : vessel.staticPressurekPa); double atmDensity = (HighLogic.LoadedSceneIsEditor || !liveSLT ? simBody.GetDensity(simBody.GetPressure(0), simBody.GetTemperature(0)) : vessel.atmDensity) / 1.225; double mach = HighLogic.LoadedSceneIsEditor ? 1 : vessel.mach; //Run the simulation FuelFlowSimulation[] sims = (FuelFlowSimulation[])o; FuelFlowSimulation.Stats[] newAtmoStats = sims[0].SimulateAllStages(1.0f, staticPressureKpa, atmDensity, mach); FuelFlowSimulation.Stats[] newVacStats = sims[1].SimulateAllStages(1.0f, 0.0, 0.0, mach); atmoStats = newAtmoStats; vacStats = newVacStats; } catch (Exception e) { GravityTurner.Log("Exception in StageStats.RunSimulation(): {0}", e.ToString()); } //see how long the simulation took stopwatch.Stop(); long millisecondsToCompletion = stopwatch.ElapsedMilliseconds; stopwatch.Reset(); //set the delay before the next simulation millisecondsBetweenSimulations = 2 * millisecondsToCompletion; //start the stopwatch that will count off this delay stopwatch.Start(); simulationRunning = false; }
public FlightMap(GravityTurner turner,int width=800,int height=400) { this.turner = turner; texture = new Texture2D(width, height); for (int x = 0; x < texture.width; x++) for (int y = 0; y < texture.height; y++) texture.SetPixel(x, y, Color.black); texture.Apply(); }
public static float MaxAngle(Vessel vessel, GravityTurner turner) { float angle = 100000 / (float)turner.vesselState.dynamicPressure; float vertical = 90 + vessel.Pitch(); angle = Mathf.Clamp(angle, 0, 35); if (angle > vertical) { return(vertical); } return(angle); }
public FlightMap(GravityTurner turner, int width = 800, int height = 400) { this.turner = turner; texture = new Texture2D(width, height); for (int x = 0; x < texture.width; x++) { for (int y = 0; y < texture.height; y++) { texture.SetPixel(x, y, Color.black); } } texture.Apply(); }
public void CircularizeAtAP() { double UT = Planetarium.GetUniversalTime(); UT += vessel.orbit.timeToAp; System.Type OrbitalManeuverCalculatorType = FindMechJebModule("MuMech.OrbitalManeuverCalculator"); MethodInfo CircularizeMethod = OrbitalManeuverCalculatorType.GetMethod("DeltaVToCircularize", BindingFlags.Public | BindingFlags.Static); Vector3d deltav = (Vector3d)CircularizeMethod.Invoke(null, new object[] { vessel.orbit, UT }); GravityTurner.Log(string.Format("Circularization burn {0:0.0} m/s", deltav.magnitude)); vessel.PlaceManeuverNode(vessel.orbit, deltav, UT); ExecuteNode(); }
///<summary> ///Get or create a new DBEntry based on angle, speed and destination height, so we don't have duplicates. ///</summary> DBEntry GetEntry() { DBEntry foundEntry = FindEntry(turner.StartSpeed, turner.TurnAngle, turner.DestinationHeight); if (foundEntry != null) { return(foundEntry); } GravityTurner.Log("Recording new launch record #{0}", DB.Count); DBEntry newentry = new DBEntry(); DB.Add(newentry); return(newentry); }
public static FlightMap Load(string filename, GravityTurner turner) { try { Texture2D texture = new Texture2D(800, 400); texture.LoadImage(System.IO.File.ReadAllBytes(filename)); FlightMap flightmap = new FlightMap(turner, texture.width, texture.height); flightmap.texture = texture; GravityTurner.Log("FlightMap loaded with {0:0.00} loss", args: flightmap.TotalLoss()); return(flightmap); } catch (Exception) { return(null); } }
public void Load() { try { root = ConfigNode.Load(GetFilename()); if (root != null) { ConfigNode.LoadObjectFromConfig(this, root); } DB.Sort(); } catch (Exception ex) { GravityTurner.Log("Vessel DB Load error {0}", ex.ToString()); } }
public static string GetBaseFilePath(Type t, string sub) { try { #if DEBUG return(System.IO.Directory.GetCurrentDirectory() + @"\GameData\GravityTurn\Plugins\PluginData\GravityTurn\" + sub); #else return(IOUtils.GetFilePathFor(t, sub)); #endif } catch (Exception ex) { GravityTurner.Log("Exception: {0}", ex.ToString()); return(System.IO.Directory.GetCurrentDirectory() + @"\GameData\GravityTurn\Plugins\PluginData\GravityTurn\" + sub); } }
///<summary> ///Just replay the best launch, no learning to be done. ///</summary> public bool BestSettings(out double TurnAngle, out double StartSpeed) { GravityTurner.DebugMessage = String.Format("LaunchDB entries: {0}", DB.Count); DB.Sort(); TurnAngle = 0; StartSpeed = 0; GravityTurner.Log("DB[0]: mh={0:0.00}, ok={1}", DB[0].MaxHeat, DB[0].LaunchSuccess); if (DB.Count < 1 || DB[0].MaxHeat >= 1 || !DB[0].LaunchSuccess) { return(false); } TurnAngle = DB[0].TurnAngle; StartSpeed = DB[0].StartSpeed; GravityTurner.Log("Best Guess: s={0:0.00}, a={1:0.00}", StartSpeed, TurnAngle); return(true); }
public float MaxHeat() { float max = 0; for (int x = 0; x < texture.width; x++) { for (int y = 0; y < texture.height; y++) { if (texture.GetPixel(x, y).r > max) { max = texture.GetPixel(x, y).r; } } } GravityTurner.Log("Previous max heat {0:0.000}", max); return(max); }
void Start() { instance = this; Log("Starting"); try { mucore.init(); vesselState = new VesselState(); attitude = new AttitudeController(this); stage = new StageController(this); attitude.OnStart(); stagestats = new StageStats(stage); stagestats.editorBody = getVessel.mainBody; stagestats.OnModuleEnabled(); stagestats.OnFixedUpdate(); stagestats.RequestUpdate(this); stagestats.OnFixedUpdate(); CreateButtonIcon(); LaunchName = new string(getVessel.vesselName.ToCharArray()); LaunchBody = getVessel.mainBody; launchdb = new LaunchDB(this); launchdb.Load(); mainWindow = new Window.MainWindow(this, 6378070); flightMapWindow = new Window.FlightMapWindow(this, 548302); statsWindow = new Window.StatsWindow(this, 6378070 + 4); double h = 80f; if (FlightGlobals.ActiveVessel.mainBody.atmosphere) { h = Math.Max(h, FlightGlobals.ActiveVessel.mainBody.atmosphereDepth + 10000f); DestinationHeight = new EditableValue(h, locked: true) / 1000; } delayUT = double.NaN; GameEvents.onShowUI.Add(ShowGUI); GameEvents.onHideUI.Add(HideGUI); LoadKeybind(); } catch (Exception ex) { Log(ex.ToString()); } }
public bool init() { if (Initialized) { return(true); } CoreType = FindMechJebModule("MuMech.MechJebCore"); if (CoreType == null) { GravityTurner.Log("MechJeb assembly not found"); return(false); } if (!GetCore()) { GravityTurner.Log("MechJeb core not found"); return(false); } GravityTurner.Log("Found MechJeb core"); Initialized = true; return(true); }
public bool Equals(GravityTurner turner) { return(StartSpeed == turner.StartSpeed && TurnAngle == turner.TurnAngle && MaxHeat == turner.MaxHeat && TotalLoss == turner.TotalLoss); }
public static FlightMap Load(string filename, GravityTurner turner) { try { Texture2D texture = new Texture2D(800, 400); texture.LoadImage(System.IO.File.ReadAllBytes(filename)); FlightMap flightmap = new FlightMap(turner, texture.width, texture.height); flightmap.texture = texture; GravityTurner.Log("FlightMap loaded with {0:0.00} loss", args:flightmap.TotalLoss()); return flightmap; } catch (Exception) { return null; } }
///<summary> ///Do the real work to analyze previous results and get recommended settings. ///</summary> public bool GuessSettings(out double TurnAngle, out double StartSpeed) { try { GravityTurner.Log("Guessing settings"); // sort by most aggressive DB.Sort(); if (GameSettings.MODIFIER_KEY.GetKey()) { TurnAngle = 10; StartSpeed = 100; GravityTurner.Log("Reset results"); return(false); } TurnAngle = 0; StartSpeed = 0; if (DB.Count == 0) { GravityTurner.Log("No previous result"); return(false); } if (DB.Count == 1) { GravityTurner.Log("Only one previous result"); if (DB[0].MaxHeat < 0.90) { float Adjust = Mathf.Clamp((float)DB[0].MaxHeat + (float)(1 - DB[0].MaxHeat) / 2, 0.8f, 0.95f); TurnAngle = DB[0].TurnAngle / Adjust; StartSpeed = DB[0].StartSpeed * Adjust; } else if (DB[0].MaxHeat > 0.95) { TurnAngle = DB[0].TurnAngle * 0.95; StartSpeed = DB[0].StartSpeed * 1.05; } else { TurnAngle = DB[0].TurnAngle; StartSpeed = DB[0].StartSpeed; } return(true); } // more than one result, now we can do real work // Simple linear progression 2nd best -> best -> next TurnAngle = DB[0].TurnAngle + DB[0].TurnAngle - DB[1].TurnAngle; StartSpeed = DB[0].StartSpeed + DB[0].StartSpeed - DB[1].StartSpeed; // check if this launch was already tried and failed DBEntry check = FindEntry(StartSpeed, TurnAngle, turner.DestinationHeight); if (check != null && !check.LaunchSuccess) { TurnAngle = (DB[0].TurnAngle + check.TurnAngle) / 2; StartSpeed = (DB[0].StartSpeed + check.StartSpeed) / 2; GravityTurner.Log("Found failed run, set between {0} and {1}", DB[0].ToString(), check.ToString() ); } // Check for overheated launches so we don't make that mistake again DBEntry hotrun = LeastCritical(); if (hotrun != null && TurnAngle / StartSpeed >= hotrun.TurnAngle / hotrun.StartSpeed * 0.99) // Close to a previous overheating run { TurnAngle = (DB[0].TurnAngle + hotrun.TurnAngle) / 2; StartSpeed = (DB[0].StartSpeed + hotrun.StartSpeed) / 2; GravityTurner.Log("Found hot run, set between {0} and {1}", DB[0].ToString(), hotrun.ToString() ); } // Need to check to see if we're past the point of max efficiency DBEntry toomuch = EfficiencyTippingPoint(); // If we're within 1% of a launch that was inefficient (or beyond)... if (toomuch != null && TurnAngle / StartSpeed >= toomuch.TurnAngle / toomuch.StartSpeed * 0.99) { // Go halfway between the best and too much TurnAngle = (DB[0].TurnAngle + toomuch.TurnAngle) / 2; StartSpeed = (DB[0].StartSpeed + toomuch.StartSpeed) / 2; } } catch (Exception ex) { GravityTurner.Log(ex.Message); TurnAngle = 0; StartSpeed = 0; return(false); } return(true); }
public StageController(GravityTurner turner) { this.turner = turner; }
public static float APThrottle(double timeToAP, GravityTurner turner) { Vessel vessel = GravityTurner.getVessel; if (vessel.speed < turner.StartSpeed) turner.Throttle.value = 1.0f; else { if (timeToAP > vessel.orbit.timeToPe) // We're falling timeToAP = 0; float diff = 0.1f * (float)Math.Abs(turner.HoldAPTime - timeToAP) * 0.5f; turner.TimeSpeed = (turner.PrevTime - timeToAP) / (Time.time - turner.lastTimeMeasured); if (Math.Abs(turner.TimeSpeed) < 0.02 && turner.PitchAdjustment == 0) turner.NeutralThrottle = (float)turner.Throttle.value; if (Math.Abs(timeToAP - turner.HoldAPTime) < 0.1) { if (turner.PitchAdjustment > 0) turner.PitchAdjustment.value -= 0.1f; else turner.Throttle.force(turner.NeutralThrottle); } else if (timeToAP < turner.HoldAPTime) { if (turner.Throttle.value >= 1 && (timeToAP < turner.PrevTime || (timeToAP - turner.HoldAPTime) / turner.TimeSpeed > 20)) { turner.NeutralThrottle = 1; turner.PitchAdjustment.value += 0.1f; } turner.Throttle.value += diff; if (0 < (timeToAP - turner.HoldAPTime) / turner.TimeSpeed && (timeToAP - turner.HoldAPTime) / turner.TimeSpeed < 20) // We will reach desired AP time in <20 second { turner.PitchAdjustment.value -= 0.1f; } } else if (timeToAP > turner.HoldAPTime) { if (turner.PitchAdjustment > 0) turner.PitchAdjustment.value -= 0.1f; else turner.Throttle.value -= diff; } } if (turner.PitchAdjustment < 0) turner.PitchAdjustment.value = 0; if (turner.PitchAdjustment > MaxAngle(vessel,turner)) turner.PitchAdjustment.value = MaxAngle(vessel,turner); // We don't want to do any pitch correction during the initial lift if (vessel.ProgradePitch(true) < -45) turner.PitchAdjustment.force(0); turner.PrevTime = vessel.orbit.timeToAp; turner.lastTimeMeasured = Time.time; if (turner.Throttle.value < turner.Sensitivity) turner.Throttle.force(turner.Sensitivity); if (turner.Throttle.value > 1) turner.Throttle.force(1); // Inrease the AP time if needed for SRB lifter stages if (vessel.HasActiveSRB() && vessel.orbit.timeToAp > turner.HoldAPTime && turner.TimeSpeed < 0) { double StopHeight = GravityTurner.getVessel.mainBody.atmosphereDepth; if (StopHeight <= 0) StopHeight = turner.DestinationHeight * 1000; turner.APTimeStart = (StopHeight * vessel.orbit.timeToAp - vessel.altitude * turner.APTimeFinish) / (StopHeight - vessel.altitude); turner.APTimeStart *= 0.99; // We want to be just a bit less than what we calculate, so we don't stay throttled up } return (float)turner.Throttle.value; }
public void CalculateSettings(Vessel vessel, bool UseBest = false) { float baseFactor = Mathf.Round((float)vessel.mainBody.GeeASL * 100.0f) / 10.0f; Log("Base turn speed factor {0:0.00}", baseFactor); // reset the settings to defaults if (GameSettings.MODIFIER_KEY.GetKey()) { launchdb.Clear(); TurnAngle = 10; StartSpeed = baseFactor * 10.0; DestinationHeight = (vessel.StableOrbitHeight() + 10000) / 1000; GravityTurner.Log("Reset results"); return; } Log("Min orbit height: {0}", vessel.StableOrbitHeight()); stagestats.ForceSimunlation(); double TWR = 0; for (int i = stagestats.atmoStats.Length - 1; i >= 0; i--) { double stagetwr = stagestats.atmoStats[i].StartTWR(vessel.mainBody.GeeASL); if (stagetwr > 0) { if (vessel.StageHasSolidEngine(i)) { TWR = (stagetwr + stagestats.atmoStats[i].MaxTWR(vessel.mainBody.GeeASL)) / 2.3; } else { TWR = stagetwr; } break; } } if (TWR > 1.2) { Log("First guess for TWR > 1.2 {0:0.00}", TWR); TWR -= 1.2; if (!TurnAngle.locked) { TurnAngle = Mathf.Clamp((float)(10 + TWR * 5), 10, 80); } if (!StartSpeed.locked) { StartSpeed = Mathf.Clamp((float)(baseFactor * 10 - TWR * baseFactor * 3), baseFactor, baseFactor * 10); if (StartSpeed < 10) { StartSpeed = 10; } } } double guessTurn, guessSpeed; if (UseBest && launchdb.BestSettings(out guessTurn, out guessSpeed)) { Log("UseBest && launchdb.BestSettings"); if (!StartSpeed.locked) { StartSpeed = guessSpeed; } if (!TurnAngle.locked) { TurnAngle = guessTurn; } } else if (launchdb.GuessSettings(out guessTurn, out guessSpeed)) { Log("GuessSettings"); if (!StartSpeed.locked) { StartSpeed = guessSpeed; } if (!TurnAngle.locked) { TurnAngle = guessTurn; } } if (!APTimeStart.locked) { APTimeStart = 50; } if (!APTimeFinish.locked) { APTimeFinish = 50; } if (!Sensitivity.locked) { Sensitivity = 0.3; } if (!DestinationHeight.locked) { DestinationHeight = vessel.StableOrbitHeight() + 10000; DestinationHeight /= 1000; } if (!Roll.locked) { Roll = 0; } if (!Inclination.locked) { Inclination = 0; } if (!PressureCutoff.locked) { PressureCutoff = 1200; } SaveParameters(); }
public static float MaxAngle(Vessel vessel, GravityTurner turner) { float angle = 100000 / (float)turner.vesselState.dynamicPressure; float vertical = 90 + vessel.Pitch(); angle = Mathf.Clamp(angle, 0, 35); if (angle > vertical) return vertical; return angle; }
public void Update() { if (!vessel.isActiveVessel) { return; } GravityTurner.DebugMessage += String.Format("StageController is active {0}, {1}\n", StageManager.CurrentStage, vessel.currentStage); //if autostage enabled, and if we are not waiting on the pad, and if there are stages left, //and if we are allowed to continue staging, and if we didn't just fire the previous stage if (!vessel.LiftedOff() || StageManager.CurrentStage <= 0 || StageManager.CurrentStage <= turner.autostageLimit || Math.Abs(vesselState.time - lastStageTime) < turner.autostagePostDelay) { return; } GravityTurner.DebugMessage += " Lifted off\n"; //only decouple fairings if the dynamic pressure and altitude conditions are respected if (!topFairingDeployed) { Part fairing = GetTopmostFairing(vessel); bool fairingReadyToDeploy = false; if (fairing == null) { GravityTurner.DebugMessage += " No top fairing\n"; } else { GravityTurner.DebugMessage += " Has top fairing\n"; fairingReadyToDeploy = (vesselState.dynamicPressure <turner.FairingPressure && Math.Abs(vesselState.dynamicPressure - vesselState.maxQ)> 0.1) && ((VesselState.isLoadedFAR && (vesselState.maxQ > vessel.mainBody.GetPressure(0) * 1000 / 5)) || (vesselState.maxQ > vessel.mainBody.atmospherePressureSeaLevel / 2)); if (fairingReadyToDeploy) { GravityTurner.DebugMessage += " Fairing ready to be deployed\n"; } } if (fairing != null && fairing.IsUnfiredDecoupler() && fairingReadyToDeploy) { topFairingDeployed = true; fairing.DeployFairing(); GravityTurner.Log("Top Fairing deployed."); GravityTurner.Log(" fairing pressure: {0:0.0}", turner.FairingPressure); GravityTurner.Log(" dynamic pressure: {0:0.0}", vesselState.dynamicPressure); GravityTurner.Log(" vessel maxQ: {0:0.0}", vesselState.maxQ); GravityTurner.DebugMessage += " Deploying top Fairing!!!\n"; return; } } //don't decouple active or idle engines or tanks List <int> burnedResources = FindBurnedResources(); if (InverseStageDecouplesActiveOrIdleEngineOrTank(StageManager.CurrentStage - 1, vessel, burnedResources)) { return; } GravityTurner.DebugMessage += " active/idle Engine\n"; //Don't fire a stage that will activate a parachute, unless that parachute gets decoupled: if (HasStayingChutes(StageManager.CurrentStage - 1, vessel)) { return; } GravityTurner.DebugMessage += " HasStayingChute\n"; //only fire decouplers to drop deactivated engines or tanks bool firesDecoupler = InverseStageFiresDecoupler(StageManager.CurrentStage - 1, vessel); if (firesDecoupler && !InverseStageDecouplesDeactivatedEngineOrTank(StageManager.CurrentStage - 1, vessel)) { return; } GravityTurner.DebugMessage += " deactivated Engine/Tank\n"; //When we find that we're allowed to stage, start a countdown (with a //length given by autostagePreDelay) and only stage once that countdown finishes, if (countingDown) { GravityTurner.DebugMessage += " Counting down\n"; if (Math.Abs(vesselState.time - stageCountdownStart) > turner.autostagePreDelay) { GravityTurner.DebugMessage += " Countdown finished\n"; if (firesDecoupler) { //if we decouple things, delay the next stage a bit to avoid exploding the debris lastStageTime = vesselState.time; } GravityTurner.DebugMessage += " ActivateNextStage\n"; GravityTurner.Log("Activate next stage."); StageManager.ActivateNextStage(); countingDown = false; GravityTurner.RestoreTimeWarp(); } } else { GravityTurner.DebugMessage += " Stage Countdown\n"; GravityTurner.StoreTimeWarp(); GravityTurner.StopSpeedup(); stageCountdownStart = vesselState.time; countingDown = true; } }
public LaunchDB(GravityTurner inTurner) { turner = inTurner; }
public AttitudeController(GravityTurner turner) { this.turner = turner; }
public static float APThrottle(double timeToAP, GravityTurner turner) { Vessel vessel = GravityTurner.getVessel; GravityTurner.DebugMessage += "-\n"; if (vessel.speed < turner.StartSpeed) { turner.Throttle.value = 1.0f; } else { if (timeToAP > vessel.orbit.timeToPe) // We're falling { timeToAP = 0; } float diff = 0.1f * (float)Math.Abs(turner.HoldAPTime - timeToAP) * 0.5f; turner.TimeSpeed = (turner.PrevTime - timeToAP) / (Time.time - turner.lastTimeMeasured); if (Math.Abs(turner.TimeSpeed) < 0.02 && turner.PitchAdjustment == 0) { turner.NeutralThrottle = (float)turner.Throttle.value; } if (Math.Abs(timeToAP - turner.HoldAPTime) < 0.1) { if (turner.PitchAdjustment > 0) { turner.PitchAdjustment.value -= 0.1f; } else { turner.Throttle.force(turner.NeutralThrottle); } } else if (timeToAP < turner.HoldAPTime) { if (turner.Throttle.value >= 1 && (timeToAP < turner.PrevTime || (timeToAP - turner.HoldAPTime) / turner.TimeSpeed > 20)) { turner.NeutralThrottle = 1; turner.PitchAdjustment.value += 0.1f; } turner.Throttle.value += diff; if (0 < (timeToAP - turner.HoldAPTime) / turner.TimeSpeed && (timeToAP - turner.HoldAPTime) / turner.TimeSpeed < 20) // We will reach desired AP time in <20 second { turner.PitchAdjustment.value -= 0.1f; } } else if (timeToAP > turner.HoldAPTime) { if (turner.PitchAdjustment > 0) { turner.PitchAdjustment.value -= 0.1f; } else { turner.Throttle.value -= diff; } } if (Math.Abs(maxAoA) < Math.Abs(turner.vesselState.AoA)) { maxAoA = turner.vesselState.AoA; } GravityTurner.DebugMessage += String.Format("max Angle of Attack: {0:0.00}\n", maxAoA); GravityTurner.DebugMessage += String.Format("cur Angle of Attack: {0:0.00}\n", turner.vesselState.AoA.value); GravityTurner.DebugMessage += String.Format("-\n"); } if (turner.PitchAdjustment < 0) { turner.PitchAdjustment.value = 0; } if (turner.PitchAdjustment > MaxAngle(vessel, turner)) { turner.PitchAdjustment.value = MaxAngle(vessel, turner); } // We don't want to do any pitch correction during the initial lift if (vessel.ProgradePitch(true) < -45) { turner.PitchAdjustment.force(0); } turner.PrevTime = vessel.orbit.timeToAp; turner.lastTimeMeasured = Time.time; if (turner.Throttle.value < turner.Sensitivity) { turner.Throttle.force(turner.Sensitivity); } if (turner.Throttle.value > 1) { turner.Throttle.force(1); } // calculate Yaw correction for inclination if (vessel.ProgradePitch(true) > -45 && Math.Abs(turner.Inclination) > 2 && turner.program != GravityTurner.AscentProgram.InLaunch) { float heading = (Mathf.Sign(turner.Inclination) * (float)turner.vesselState.orbitInclination.value - turner.Inclination); GravityTurner.DebugMessage += String.Format(" Heading: {0:0.00}\n", heading); heading *= 1.2f; if (Math.Abs(heading) < 0.3) { heading = 0; } else if (Mathf.Abs(turner.YawAdjustment) > 0.1) { heading = (turner.YawAdjustment * 7.0f + heading) / 8.0f; } if (Mathf.Abs(turner.YawAdjustment) > Mathf.Abs(heading) || turner.YawAdjustment == 0.0) { turner.YawAdjustment = heading; } GravityTurner.DebugMessage += String.Format(" YawCorrection: {0:0.00}\n", turner.YawAdjustment); } else { turner.YawAdjustment = 0; } // Inrease the AP time if needed for SRB lifter stages if (vessel.HasActiveSRB() && vessel.orbit.timeToAp > turner.HoldAPTime && turner.TimeSpeed < 0) { double StopHeight = GravityTurner.getVessel.mainBody.atmosphereDepth; if (StopHeight <= 0) { StopHeight = turner.DestinationHeight * 1000; } turner.APTimeStart = (StopHeight * vessel.orbit.timeToAp - vessel.altitude * turner.APTimeFinish) / (StopHeight - vessel.altitude); turner.APTimeStart *= 0.99; // We want to be just a bit less than what we calculate, so we don't stay throttled up } return((float)turner.Throttle.value); }
private void fly(FlightCtrlState s) { if (!Launching) { Kill(); return; } DebugMessage = ""; Vessel vessel = getVessel; if (program != AscentProgram.InCoasting && vessel.orbit.ApA > DestinationHeight * 1000 && vessel.altitude < vessel.StableOrbitHeight()) { CalculateLosses(getVessel); // save launch, ignoring losses due to coasting losses, but so we get results earlier launchdb.RecordLaunch(); launchdb.Save(); program = AscentProgram.InCoasting; DebugMessage += "In Coasting program\n"; Throttle.force(0); Log("minorbit {0}, {1}", vessel.mainBody.minOrbitalDistance, vessel.StableOrbitHeight()); // time warp to speed up things (if enabled) ApplySpeedup(2); } else if (vessel.orbit.ApA > DestinationHeight * 1000 && vessel.altitude > vessel.StableOrbitHeight()) { Log("minorbit {0}, {1}", vessel.mainBody.minOrbitalDistance, vessel.StableOrbitHeight()); program = AscentProgram.InCircularisation; StopSpeedup(); GravityTurner.Log("Saving launchDB"); launchdb.RecordLaunch(); launchdb.Save(); Kill(); DebugMessage += "In Circularisation program\n"; if (mucore.Initialized) { program = AscentProgram.InCircularisation; mucore.CircularizeAtAP(); } button.SetFalse(); } else { double minInsertionHeight = vessel.mainBody.atmosphere ? vessel.StableOrbitHeight() / 4 : Math.Max(DestinationHeight * 667, vessel.StableOrbitHeight() * 0.667); if (EnableStageManager && stage != null) { stage.Update(); } if (vessel.orbit.ApA < DestinationHeight * 1000) { s.mainThrottle = Calculations.APThrottle(vessel.orbit.timeToAp, this); } else { s.mainThrottle = 0; } if (program == AscentProgram.InInitialPitch && PitchSet) { if (vessel.ProgradePitch() + 90 >= TurnAngle - 0.1) { delayUT = double.NaN; // continue any previous timewarp RestoreTimeWarp(); ApplySpeedup(1); program = AscentProgram.InTurn; DebugMessage += "Turning now\n"; } } if (vessel.speed < StartSpeed) { DebugMessage += "In Launch program\n"; program = AscentProgram.InLaunch; if (vesselState.altitudeBottom > vesselState.vesselHeight) { attitude.attitudeTo(Quaternion.Euler(-90, LaunchHeading(vessel), 0) * RollRotation(), AttitudeReference.SURFACE_NORTH, this); } else { attitude.attitudeTo(Quaternion.Euler(-90, 0, vesselState.vesselHeading), AttitudeReference.SURFACE_NORTH, this); } } else if (program == AscentProgram.InLaunch || program == AscentProgram.InInitialPitch) { if (!PitchSet) { // remember and stop timewarp for pitching StoreTimeWarp(); StopSpeedup(); PitchSet = true; program = AscentProgram.InInitialPitch; delayUT = Planetarium.GetUniversalTime(); } DebugMessage += "In Pitch program\n"; double diffUT = Planetarium.GetUniversalTime() - delayUT; float newPitch = Mathf.Min((float)(((double)TurnAngle * diffUT) / 5.0d + 2.0d), TurnAngle); double pitch = (90d - vesselState.vesselPitch + vessel.ProgradePitch() + 90) / 2; attitude.attitudeTo(Quaternion.Euler(-90 + newPitch, LaunchHeading(vessel), 0) * RollRotation(), AttitudeReference.SURFACE_NORTH, this); DebugMessage += String.Format("TurnAngle: {0:0.00}\n", TurnAngle.value); DebugMessage += String.Format("Target pitch: {0:0.00}\n", newPitch); DebugMessage += String.Format("Current pitch: {0:0.00}\n", pitch); DebugMessage += String.Format("Prograde pitch: {0:0.00}\n", vessel.ProgradePitch() + 90); } else if (vesselState.dynamicPressure > vesselState.maxQ * 0.5 || vesselState.dynamicPressure > PressureCutoff || vessel.altitude < minInsertionHeight) { // Still ascending, or not yet below the cutoff pressure or below min insertion heigt DebugMessage += "In Turn program\n"; attitude.attitudeTo(Quaternion.Euler(vessel.ProgradePitch() - PitchAdjustment, LaunchHeading(vessel), 0) * RollRotation(), AttitudeReference.SURFACE_NORTH, this); } else { // did we reach the desired inclination? DebugMessage += String.Format("Insertion program\n"); Quaternion q = Quaternion.Euler(0 - PitchAdjustment, YawAdjustment, Roll); // smooth out change from surface to orbital prograde if (program != AscentProgram.InInsertion && program != AscentProgram.InCoasting) { // start timer if (Double.IsNaN(delayUT)) { // slow down timewarp delayUT = Planetarium.GetUniversalTime(); StoreTimeWarp(); StopSpeedup(); // switch NavBall UI FlightGlobals.SetSpeedMode(FlightGlobals.SpeedDisplayModes.Orbit); } double diffUT = Planetarium.GetUniversalTime() - delayUT; //attitude.attitudeTo(q, AttitudeReference.ORBIT, this); q.x = (attitude.lastAct.x * 8.0f + q.x) / 9.0f; if (diffUT > 10 || (attitude.lastAct.x > 0.02 && diffUT > 2.0)) { program = AscentProgram.InInsertion; delayUT = double.NaN; RestoreTimeWarp(); ApplySpeedup(2); } } attitude.attitudeTo(q, AttitudeReference.ORBIT, this); } attitude.enabled = true; attitude.Drive(s); CalculateLosses(getVessel); DebugMessage += "-"; } }