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()); }
// 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); }
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 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 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.theName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)"); } return(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + o.referenceBody.Radius), UT)); }
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); }
// 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); }