public override AutopilotStep OnFixedUpdate() { //if we don't want to deorbit but we're already on a reentry trajectory, we can't wait until the ideal point //in the orbit to deorbt; we already have deorbited. if (orbit.ApA < mainBody.RealMaxAtmosphereAltitude()) { core.thrust.targetThrottle = 0; return(doAfterExecution); } if (node == null) { //We aim for a trajectory that // a) has the same vertical speed as our current trajectory // b) has a horizontal speed that will give it a periapsis of -10% of the body's radius // c) has a heading that points toward where the target will be at the end of free-fall, accounting for planetary rotation Vector3d horizontalDV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, vesselState.time, 0.9 * mainBody.Radius); //Imagine we are going to deorbit now. Find the burn that would lower our periapsis to -10% of the planet's radius Orbit forwardDeorbitTrajectory = orbit.PerturbedOrbit(vesselState.time, horizontalDV); //Compute the orbit that would put us on double freefallTime = forwardDeorbitTrajectory.NextTimeOfRadius(vesselState.time, mainBody.Radius) - vesselState.time; //Find how long that orbit would take to impact the ground double planetRotationDuringFreefall = 360 * freefallTime / mainBody.rotationPeriod; //Find how many degrees the planet will rotate during that time Vector3d currentTargetRadialVector = mainBody.GetWorldSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0) - mainBody.position; //Find the current vector from the planet center to the target landing site Quaternion freefallPlanetRotation = Quaternion.AngleAxis((float)planetRotationDuringFreefall, mainBody.angularVelocity); //Construct a quaternion representing the rotation of the planet found above Vector3d freefallEndTargetRadialVector = freefallPlanetRotation * currentTargetRadialVector; //Use this quaternion to find what the vector from the planet center to the target will be when we hit the ground Vector3d freefallEndTargetPosition = mainBody.position + freefallEndTargetRadialVector; //Then find the actual position of the target at that time Vector3d freefallEndHorizontalToTarget = Vector3d.Exclude(freefallEndTargetRadialVector, freefallEndTargetPosition - vesselState.CoM).normalized; //Find a horizontal unit vector that points toward where the target will be when we hit the ground Vector3d currentHorizontalVelocity = Vector3d.Exclude(vesselState.up, vesselState.orbitalVelocity); //Find our current horizontal velocity double finalHorizontalSpeed = (currentHorizontalVelocity + horizontalDV).magnitude; //Find the desired horizontal speed after the deorbit burn Vector3d finalHorizontalVelocity = finalHorizontalSpeed * freefallEndHorizontalToTarget; //Combine the desired speed and direction to get the desired velocity after the deorbi burn //Compute the angle between the location of the target at the end of freefall and the normal to our orbit: Vector3d currentRadialVector = vesselState.CoM - mainBody.position; double targetAngleToOrbitNormal = Vector3d.Angle(orbit.SwappedOrbitNormal(), freefallEndTargetRadialVector); targetAngleToOrbitNormal = Math.Min(targetAngleToOrbitNormal, 180 - targetAngleToOrbitNormal); float targetAheadAngle = Vector3.SignedAngle(currentRadialVector, freefallEndTargetRadialVector, orbit.SwappedOrbitNormal()); //How far ahead the target is, in degrees if (targetAheadAngle < 60) { targetAheadAngle += 360; } float planeChangeAngle = Vector3.Angle(currentHorizontalVelocity, freefallEndHorizontalToTarget); //The plane change required to get onto the deorbit trajectory, in degrees vessel.RemoveAllManeuverNodes(); //If the target is basically almost normal to our orbit, it doesn't matter when we deorbit; might as well do it now //Otherwise, wait until the target is ahead if (targetAngleToOrbitNormal < 10 || (targetAheadAngle < 90 && planeChangeAngle < 90)) { vessel.PlaceManeuverNode(vessel.orbit, horizontalDV, vesselState.time); } else { double deorbitTime = vesselState.time + (targetAheadAngle - 90) * orbit.period / 360f; vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, deorbitTime, 0.9 * mainBody.Radius), deorbitTime); } } return(base.OnFixedUpdate()); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); if (!target.NormalTargetExists) { throw new OperationException("must select a target to match planes with."); } else if (o.referenceBody != target.TargetOrbit.referenceBody) { throw new OperationException("can only match planes with an object in the same sphere of influence."); } else if (timeSelector.timeReference == TimeReference.REL_ASCENDING) { if (!o.AscendingNodeExists(target.TargetOrbit)) { throw new OperationException("ascending node with target doesn't exist."); } } else { if (!o.DescendingNodeExists(target.TargetOrbit)) { throw new OperationException("descending node with target doesn't exist."); } } Vector3d dV = (timeSelector.timeReference == TimeReference.REL_ASCENDING) ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out UT): OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out UT); return(new ManeuverParameters(dV, UT)); }
public static void MPMatchplanes() { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vessel vessel = activejeb.vessel; Vessel target = activejeb.vessel.targetObject as Vessel; double time = Planetarium.GetUniversalTime(); Vector3d deltav; double gotime = 0; if (vessel.orbit.AscendingNodeExists(target.orbit)) { if (vessel.orbit.TimeOfAscendingNode(target.orbit, time) < vessel.orbit.TimeOfDescendingNode(target.orbit, time)) { deltav = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(vessel.orbit, target.orbit, time, out gotime); } else { deltav = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(vessel.orbit, target.orbit, time, out gotime); } } else { deltav = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(vessel.orbit, target.orbit, time, out gotime); } vessel.PlaceManeuverNode(vessel.orbit, deltav, gotime); } }
// find orbit round with min normalDiff to target, makes only sense if we are in inclined orbit bool minOrbit() { ManeuverNode plannedNode = vessel.patchedConicSolver.maneuverNodes[0]; if (Math.Abs(orbit.inclination) < 5) { return(true); } Debug.Log(String.Format("Current deorbit round at t={0:F0} has normalDiff={1:F1}", plannedNode.UT - Planetarium.GetUniversalTime(), targetInfo.normalDifference)); if (iteration == 0 || Math.Abs(targetInfo.normalDifference) < minDiff) { Debug.Log(String.Format("Found new optimum deorbit round at t={0:F0} for normalDiff={1:F1} ", plannedNode.UT - Planetarium.GetUniversalTime(), targetInfo.normalDifference)); minDiff = Math.Abs(targetInfo.normalDifference); minUT = plannedNode.UT; } iteration++; if (iteration > maxIterations) { plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, minUT, mainBody.Radius + core.landing.reentryTargetHeight), minUT); targetInfo.invalidateCalculation(); return(true); } // factor accounts for ground movement during orbit round double nextRound = plannedNode.UT + orbit.period * vessel.mainBody.rotationPeriod / (vessel.mainBody.rotationPeriod - orbit.period); plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, nextRound, mainBody.Radius + core.landing.reentryTargetHeight), nextRound); targetInfo.invalidateCalculation(); return(false); }
private void DoCircularize(int index, TextMenu.Item tmi) { double UT = 0.0; Vector3d dV = Vector3d.zero; Orbit o = vessel.orbit; switch (tmi.id) { case (int)MechJebModuleManeuverPlanner.TimeReference.APOAPSIS: UT = o.NextApoapsisTime(Planetarium.GetUniversalTime()); dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case (int)MechJebModuleManeuverPlanner.TimeReference.PERIAPSIS: UT = o.NextPeriapsisTime(Planetarium.GetUniversalTime()); dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case (int)MechJebModuleManeuverPlanner.TimeReference.X_FROM_NOW: UT = Planetarium.GetUniversalTime() + 15.0; dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; } if (UT > 0.0) { vessel.PlaceManeuverNode(o, dV, UT); } }
public static double RelativeVel() { Vessel target = mjvessel.targetObject as Vessel; Vector3d deltav = OrbitalManeuverCalculator.DeltaVToMatchVelocities(mjvessel.orbit, Planetarium.GetUniversalTime(), target.orbit); return(deltav.magnitude); }
/// <summary> /// Plot a Hohmann transfer to the current target. This is an instant /// fire-and-forget function, not a toggle switch /// </summary> /// <param name="state">unused</param> public void ButtonPlotHohmannTransfer(bool state) { if (!ButtonPlotHohmannTransferState()) { // Target is not one MechJeb can successfully plot. return; } MechJebCore activeJeb = vessel.GetMasterMechJeb(); Orbit o = vessel.orbit; Vector3d dV = Vector3d.zero; double UT = Planetarium.GetUniversalTime(); if (o.referenceBody == activeJeb.target.Orbit.referenceBody) { // Simple transfer. dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, activeJeb.target.Orbit, UT, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryTransferEjection(o, UT, activeJeb.target.Orbit, true, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(o, dV, UT); }
bool optimizeDeorbit() { //Debug.Log(String.Format("Autoland: currentImpactRadialVector={0} currentTargetRadialVector={1} differenceTarget={2}", targetInfo.currentImpactRadialVector, targetInfo.currentTargetRadialVector, targetInfo.differenceTarget)); //Debug.Log(String.Format("Autoland: orbitClosestToTarget={0} orbitNormal={1} targetForward={2} ", targetInfo.orbitClosestToTarget, orbit.SwappedOrbitNormal(), targetForward.ToString("F3"))); //Debug.Log(String.Format("Autoland: normalDiff={0:F1}, backwardDiff={1:F1}", targetInfo.normalDifference, targetInfo.backwardDifference)); if (Math.Abs(targetInfo.targetAheadAngle) < 0.5 && Math.Abs(targetInfo.backwardDifference) < deorbitprecision) { return(true); // execute plannedNode } else { //move Node ManeuverNode plannedNode = vessel.patchedConicSolver.maneuverNodes[0]; double deorbitTime = plannedNode.UT; double timedelta; if (Math.Abs(targetInfo.targetAheadAngle) < 0.5) // for small changes use tangential calculation, otherwise angluar { timedelta = targetInfo.backwardDifference / vesselState.speedSurfaceHorizontal; } else { timedelta = targetInfo.targetAheadAngle * orbit.period / 360f; } if (timedelta < 0) // asymetric to avoid jumping between two points without improvement. Observed with inclined trajectory. { deorbitTime -= timedelta; } else { deorbitTime -= 0.5 * timedelta; } if (deorbitTime < vesselState.time) { deorbitTime += orbit.period; } if (deorbitTime > vesselState.time + 1.5 * orbit.period) { deorbitTime -= orbit.period; } status = String.Format("Optimizing deorbit time based on trajectory prediction, shift by {0:F4} degree, {1:F0} m equals {2:F1} seconds", targetInfo.targetAheadAngle, targetInfo.backwardDifference, deorbitTime - plannedNode.UT); Debug.Log("Autoland: " + status); // deltaV needs to rotate plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, deorbitTime, mainBody.Radius + core.landing.reentryTargetHeight), deorbitTime); targetInfo.invalidateCalculation(); iteration++; } return(false); }
public static void MPInc(double time, double inc) { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vector3d deltav = OrbitalManeuverCalculator.DeltaVToChangeInclination(activejeb.vessel.orbit, time, inc); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public static void MPPea(double time, double pea) { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vector3d deltav = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(activejeb.vessel.orbit, time, pea); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public static void MPCirc(double time) { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vector3d deltav = OrbitalManeuverCalculator.DeltaVToCircularize(activejeb.vessel.orbit, time); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public static void MPFineTuneCa(double distance) { MechJebCore activejeb = GetJeb(); if (activejeb != null) { double burnt = 0; Vector3d deltav = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(mjvessel.orbit, Planetarium.GetUniversalTime(), mjvessel.targetObject.GetOrbit(), distance, out burnt); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, burnt); } }
public static void MPMatchVelocity(double time) { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vessel target = activejeb.vessel.targetObject as Vessel; Vector3d deltav = OrbitalManeuverCalculator.DeltaVToMatchVelocities(activejeb.vessel.orbit, time, target.orbit); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public static void MPPlanet() { MechJebCore activejeb = GetJeb(); if (activejeb != null) { CelestialBody target = activejeb.vessel.targetObject as CelestialBody; double time = 0; Vector3d deltav = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryLambertTransferEjection(activejeb.vessel.orbit, Planetarium.GetUniversalTime(), target.orbit, out time); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public static void MPHohmann() { MechJebCore activejeb = GetJeb(); if (activejeb != null) { Vessel target = activejeb.vessel.targetObject as Vessel; double time = 0; Vector3d deltav = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(activejeb.vessel.orbit, target.orbit, Planetarium.GetUniversalTime(), out time); activejeb.vessel.PlaceManeuverNode(activejeb.vessel.orbit, deltav, time); } }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); if (o.referenceBody.Radius + newApA < o.Radius(UT)) { string burnAltitude = MuUtils.ToSI(o.Radius(UT) - o.referenceBody.Radius) + "m"; throw new OperationException("new apoapsis cannot be lower than the altitude of the burn (" + burnAltitude + ")"); } return(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToChangeApoapsis(o, UT, newApA + o.referenceBody.Radius), UT)); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); if (2 * newSMA > o.Radius(UT) + o.referenceBody.sphereOfInfluence) { errorMessage = "Warning: new Semi-Major Axis is very large, and may result in a hyberbolic orbit"; } if (o.Radius(UT) > 2 * newSMA) { throw new OperationException("cannot make Semi-Major Axis less than twice the burn altitude plus the radius of " + o.referenceBody.theName + "(" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)"); } return(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(o, UT, newSMA), UT)); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); if (o.referenceBody.Radius + newPeA > o.Radius(UT)) { string burnAltitude = MuUtils.ToSI(o.Radius(UT) - o.referenceBody.Radius) + "m"; throw new OperationException("new periapsis cannot be higher than the altitude of the burn (" + burnAltitude + ")"); } else if (newPeA < -o.referenceBody.Radius) { throw new OperationException("new periapsis cannot be lower than minus the radius of " + o.referenceBody.displayName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)"); } return(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + o.referenceBody.Radius), UT)); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { if (!target.NormalTargetExists) { throw new OperationException("must select a target to intercept."); } if (o.referenceBody != target.TargetOrbit.referenceBody) { throw new OperationException("target must be in the same sphere of influence."); } double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); var dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(o, UT, target.TargetOrbit, UT + interceptInterval); return(new ManeuverParameters(dV, UT)); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); if (!target.NormalTargetExists) { throw new OperationException("must select a target to match planes with."); } else if (o.referenceBody != target.TargetOrbit.referenceBody) { throw new OperationException("can only match planes with an object in the same sphere of influence."); } var anExists = o.AscendingNodeExists(target.TargetOrbit); var dnExists = o.DescendingNodeExists(target.TargetOrbit); double anTime = 0; double dnTime = 0; var anDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out anTime) : Vector3d.zero; var dnDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out dnTime) : Vector3d.zero; Vector3d dV; if (timeSelector.timeReference == TimeReference.REL_ASCENDING) { if (!anExists) { throw new OperationException("ascending node with target doesn't exist."); } UT = anTime; dV = anDeltaV; } else if (timeSelector.timeReference == TimeReference.REL_DESCENDING) { if (!dnExists) { throw new OperationException("descending node with target doesn't exist."); } UT = dnTime; dV = dnDeltaV; } else if (timeSelector.timeReference == TimeReference.REL_NEAREST_AD) { if (!anExists && !dnExists) { throw new OperationException("neither ascending nor descending node with target exists."); } if (!dnExists || anTime <= dnTime) { UT = anTime; dV = anDeltaV; } else { UT = dnTime; dV = dnDeltaV; } } else if (timeSelector.timeReference == TimeReference.REL_HIGHEST_AD) { if (!anExists && !dnExists) { throw new OperationException("neither ascending nor descending node with target exists."); } if (!dnExists || anDeltaV.magnitude <= dnDeltaV.magnitude) { UT = anTime; dV = anDeltaV; } else { UT = dnTime; dV = dnDeltaV; } } else { throw new OperationException("wrong time reference."); } return(new ManeuverParameters(dV, UT)); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); return(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToCircularize(o, UT), UT)); }
// calculate deorbit node and if node is acceptable base class will excute it public override AutopilotStep OnFixedUpdate() { //if we don't want to deorbit but we're already on a reentry trajectory, we can't wait until the ideal point //in the orbit to deorbt; we already have deorbited. if (orbit.ApA < mainBody.RealMaxAtmosphereAltitude()) { core.thrust.targetThrottle = 0; return(doAfterExecution); } switch (phase) { case Phase.init: //core.attitude.attitudeTo(Quaternion.identity, AttitudeReference.SURFACE_HORIZONTAL, this); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, vesselState.time, mainBody.Radius + core.landing.reentryTargetHeight), vesselState.time); TrajectoriesConnector.API.SetTarget(core.target.targetLatitude, core.target.targetLongitude); status = "Calculating deorbit trajectory"; phase = Phase.deorbit; iteration = 0; break; case Phase.deorbit: targetInfo.update(); if (targetInfo.isValid && optimizeDeorbit()) { iteration = 30; phase = Phase.minOrbit; } else { if (iteration > maxIterations) { status = "Deorbit giving up in search for node, do manual deorbit"; core.landing.StopLanding(); return(null); } } break; case Phase.minOrbit: targetInfo.update(); if (targetInfo.isValid && minOrbit()) { phase = Phase.planeChange; } break; case Phase.planeChange: targetInfo.update(); if (targetInfo.isValid && optimizePlaneChange()) { phase = Phase.execute; } break; case Phase.execute: return(base.OnFixedUpdate()); } return(this); }
public override AutopilotStep OnFixedUpdate() { //if we don't want to deorbit but we're already on a reentry trajectory, we can't wait until the ideal point //in the orbit to deorbt; we already have deorbited. if (orbit.ApA < mainBody.RealMaxAtmosphereAltitude()) { core.thrust.targetThrottle = 0; return(new CourseCorrection(core)); } //We aim for a trajectory that // a) has the same vertical speed as our current trajectory // b) has a horizontal speed that will give it a periapsis of -10% of the body's radius // c) has a heading that points toward where the target will be at the end of free-fall, accounting for planetary rotation Vector3d horizontalDV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, vesselState.time, 0.9 * mainBody.Radius); //Imagine we are going to deorbit now. Find the burn that would lower our periapsis to -10% of the planet's radius Orbit forwardDeorbitTrajectory = orbit.PerturbedOrbit(vesselState.time, horizontalDV); //Compute the orbit that would put us on double freefallTime = forwardDeorbitTrajectory.NextTimeOfRadius(vesselState.time, mainBody.Radius) - vesselState.time; //Find how long that orbit would take to impact the ground double planetRotationDuringFreefall = 360 * freefallTime / mainBody.rotationPeriod; //Find how many degrees the planet will rotate during that time Vector3d currentTargetRadialVector = mainBody.GetWorldSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0) - mainBody.position; //Find the current vector from the planet center to the target landing site Quaternion freefallPlanetRotation = Quaternion.AngleAxis((float)planetRotationDuringFreefall, mainBody.angularVelocity); //Construct a quaternion representing the rotation of the planet found above Vector3d freefallEndTargetRadialVector = freefallPlanetRotation * currentTargetRadialVector; //Use this quaternion to find what the vector from the planet center to the target will be when we hit the ground Vector3d freefallEndTargetPosition = mainBody.position + freefallEndTargetRadialVector; //Then find the actual position of the target at that time Vector3d freefallEndHorizontalToTarget = Vector3d.Exclude(vesselState.up, freefallEndTargetPosition - vesselState.CoM).normalized; //Find a horizontal unit vector that points toward where the target will be when we hit the ground Vector3d currentHorizontalVelocity = Vector3d.Exclude(vesselState.up, vesselState.orbitalVelocity); //Find our current horizontal velocity double finalHorizontalSpeed = (currentHorizontalVelocity + horizontalDV).magnitude; //Find the desired horizontal speed after the deorbit burn Vector3d finalHorizontalVelocity = finalHorizontalSpeed * freefallEndHorizontalToTarget; //Combine the desired speed and direction to get the desired velocity after the deorbi burn //Compute the angle between the location of the target at the end of freefall and the normal to our orbit: Vector3d currentRadialVector = vesselState.CoM - mainBody.position; double targetAngleToOrbitNormal = Vector3d.Angle(orbit.SwappedOrbitNormal(), freefallEndTargetRadialVector); targetAngleToOrbitNormal = Math.Min(targetAngleToOrbitNormal, 180 - targetAngleToOrbitNormal); double targetAheadAngle = Vector3d.Angle(currentRadialVector, freefallEndTargetRadialVector); //How far ahead the target is, in degrees double planeChangeAngle = Vector3d.Angle(currentHorizontalVelocity, freefallEndHorizontalToTarget); //The plane change required to get onto the deorbit trajectory, in degrees //If the target is basically almost normal to our orbit, it doesn't matter when we deorbit; might as well do it now //Otherwise, wait until the target is ahead if (targetAngleToOrbitNormal < 10 || (targetAheadAngle < 90 && targetAheadAngle > 60 && planeChangeAngle < 90)) { deorbitBurnTriggered = true; } if (deorbitBurnTriggered) { if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } //get out of warp Vector3d deltaV = finalHorizontalVelocity - currentHorizontalVelocity; core.attitude.attitudeTo(deltaV.normalized, AttitudeReference.INERTIAL, core.landing); if (deltaV.magnitude < 2.0) { return(new CourseCorrection(core)); } status = "Doing high deorbit burn"; } else { core.attitude.attitudeTo(Vector3d.back, AttitudeReference.ORBIT, core.landing); if (core.node.autowarp) { core.warp.WarpRegularAtRate((float)(orbit.period / 10)); } status = "Moving to high deorbit burn point"; } return(this); }
public static double ClosestAppVel() { Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(mjvessel.orbit, Planetarium.GetUniversalTime(), mjvessel.targetObject.GetOrbit()); return(dV.magnitude); }