public override List <ManeuverParameters> MakeNodesImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = timeSelector.ComputeManeuverTime(o, universalTime, target); List <ManeuverParameters> NodeList = new List <ManeuverParameters>(); NodeList.Add(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToCircularize(o, UT), UT)); return(NodeList); }
void DriveCircularizationBurn(FlightCtrlState s) { if (!vessel.patchedConicsUnlocked()) { this.users.Clear(); return; } if (placedCircularizeNode) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>(); if (recorder != null) { launchPhaseAngle = recorder.phaseAngleFromMark; } //finished circularize this.users.Clear(); return; } } else { //place circularization node vessel.RemoveAllManeuverNodes(); double UT = orbit.NextApoapsisTime(vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); placedCircularizeNode = true; core.node.ExecuteOneNode(this); } if (core.node.burnTriggered) { status = "Circularizing"; } else { status = "Coasting to circularization burn"; } }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.target.Distance > 1000; //don't warp when close to target, because warping introduces small perturbations //If we get within the target distance and then next maneuver node is still //far in the future, delete it and we will create a new one to match velocities immediately. //This can often happen because the target vessel's orbit shifts slightly when it is unpacked. if (core.target.Distance < desiredDistance && vessel.patchedConicSolver.maneuverNodes.Count > 0 && vessel.patchedConicSolver.maneuverNodes[0].UT > vesselState.time + 1) { vessel.RemoveAllManeuverNodes(); } if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { //If we have plotted a maneuver, execute it. if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < desiredDistance * 1.05 + 2 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = "Successful rendezvous"; } else if (core.target.Distance < desiredDistance * 1.05 + 2) { //We are within the target distance: match velocities double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Within " + desiredDistance.ToString() + "m: matching velocities."; } else if (core.target.Distance < vesselState.radius / 25) { if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < desiredDistance && orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = orbit.Separation(core.target.Orbit, UT); double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.Orbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning to match velocities at closest approach."; } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; double interceptUT = UT + closingTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 0); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Close to target: plotting intercept"; } } else if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < core.target.Orbit.semiMajorAxis / 25) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = (orbit.SwappedAbsolutePositionAtUT(UT) - core.target.Orbit.SwappedAbsolutePositionAtUT(UT)).magnitude; double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.Orbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = "On intercept course. Planning to match velocities at closest approach."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05 && orbit.SynodicPeriod(core.target.Orbit) < 5 * orbit.period) { //We're not on an intercept course, but we have a circular orbit in the right plane. //Also we are phasing quickly enough that it won't be too long until an intercept window //Plot a Hohmann transfer intercept. double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning Hohmann transfer for intercept."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05) { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double lowPhasingRadius = core.target.Orbit.semiMajorAxis / 1.16; double highPhasingRadius = core.target.Orbit.semiMajorAxis * 1.16; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.RealMaxAtmosphereAltitude() + 3000 && orbit.semiMajorAxis < core.target.orbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = "Increasing phasing rate by establishing new phasing orbit at " + MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0) + "m"; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.Orbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.Orbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Circularizing."; } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.Orbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.Orbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.Orbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Matching planes."; } }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label("Select a target to rendezvous with."); base.WindowGUI(windowID); return; } if (core.target.Orbit.referenceBody != orbit.referenceBody) { GUILayout.Label("Rendezvous target must be in the same sphere of influence."); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); //Information readouts: GuiUtils.SimpleLabel("Rendezvous target", core.target.Name); double leadTime = 30; GuiUtils.SimpleLabel("Target orbit", MuUtils.ToSI(core.target.Orbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.Orbit.ApA, 3) + "m"); GuiUtils.SimpleLabel("Current orbit", MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); GuiUtils.SimpleLabel("Relative inclination", orbit.RelativeInclination(core.target.Orbit).ToString("F2") + "º"); double closestApproachTime = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); GuiUtils.SimpleLabel("Time until closest approach", GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); GuiUtils.SimpleLabel("Separation at closest approach", MuUtils.ToSI(orbit.Separation(core.target.Orbit, closestApproachTime), 0) + "m"); //Maneuver planning buttons: if (GUILayout.Button("Align Planes")) { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.Orbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Establish new orbit at")) { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } phasingOrbitAltitude.text = GUILayout.TextField(phasingOrbitAltitude.text, GUILayout.Width(70)); GUILayout.Label("km", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Intercept with Hohmann transfer")) { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button("Match velocities at closest approach")) { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button("Get closer")) { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
public List <ManeuverParameters> OptimizeEjection(double UT_transfer, Orbit initial_orbit, Orbit target, CelestialBody target_body, double UT_arrival, double earliest_UT, double target_PeR, bool includeCaptureBurn) { int N = 0; List <ManeuverParameters> NodeList = new List <ManeuverParameters>(); while (true) { const double DIFFSTEP = 1e-6; const double EPSX = 1e-9; const int MAXITS = 100; alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[3]; double[] scale = new double[3]; Vector3d exitDV, captureDV; CalcLambertDVs(UT_transfer, UT_arrival - UT_transfer, out exitDV, out captureDV); Orbit source = initial_orbit.referenceBody.orbit; // helicentric orbit of the source planet // helicentric transfer orbit Orbit transfer_orbit = new Orbit(); transfer_orbit.UpdateFromStateVectors(source.getRelativePositionAtUT(UT_transfer), source.getOrbitalVelocityAtUT(UT_transfer) + exitDV, source.referenceBody, UT_transfer); double UT_SOI_exit; OrbitalManeuverCalculator.SOI_intercept(transfer_orbit, initial_orbit.referenceBody, UT_transfer, UT_arrival, out UT_SOI_exit); // convert from heliocentric to body centered velocity Vector3d Vsoi = transfer_orbit.getOrbitalVelocityAtUT(UT_SOI_exit) - initial_orbit.referenceBody.orbit.getOrbitalVelocityAtUT(UT_SOI_exit); // find the magnitude of Vinf from energy double Vsoi_mag = Vsoi.magnitude; double E_h = Vsoi_mag * Vsoi_mag / 2 - initial_orbit.referenceBody.gravParameter / initial_orbit.referenceBody.sphereOfInfluence; double Vinf_mag = Math.Sqrt(2 * E_h); // scale Vsoi by the Vinf magnitude (this is now the Vinf target that will yield Vsoi at the SOI interface, but in the Vsoi direction) Vector3d Vinf = Vsoi / Vsoi.magnitude * Vinf_mag; // using Vsoi seems to work slightly better here than the Vinf from the heliocentric computation at UT_Transfer //ManeuverParameters maneuver = ComputeEjectionManeuver(Vsoi, initial_orbit, UT_transfer, true); ManeuverParameters maneuver = ComputeEjectionManeuver(Vinf, initial_orbit, UT_transfer, true); // // common setup for the optimization problems // x[0] = maneuver.dV.x; x[1] = maneuver.dV.y; x[2] = maneuver.dV.z; UT_transfer = maneuver.UT; scale[0] = scale[1] = scale[2] = 1000.0f; // // initial patched conic shooting to precisely hit the target // const int ZEROMISSCONS = 3; double[] fi = new double[ZEROMISSCONS]; zeroMissObjectiveFunction(x, fi, null, initial_orbit, target_body, UT_transfer, UT_arrival); Debug.Log("zero miss phase before optimization = " + new Vector3d(fi[0], fi[1], fi[2]).magnitude + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); alglib.minlmcreatev(3, ZEROMISSCONS, x, DIFFSTEP, out state); alglib.minlmsetcond(state, EPSX, MAXITS); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, (x, fi, obj) => zeroMissObjectiveFunction(x, fi, obj, initial_orbit, target_body, UT_transfer, UT_arrival), null, null); alglib.minlmresults(state, out x, out rep); zeroMissObjectiveFunction(x, fi, null, initial_orbit, target_body, UT_transfer, UT_arrival); Debug.Log("zero miss phase after optimization = " + new Vector3d(fi[0], fi[1], fi[2]).magnitude + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); // // Fine tuning of the periapsis // bool failed = false; if (target_PeR > 0) { const int PERIAPSISCONS = 1; double[] fi2 = new double[PERIAPSISCONS]; periapsisObjectiveFunction(x, fi2, null, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed); Debug.Log("periapsis phase before optimization = " + fi2[0] + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); alglib.minlmcreatev(3, PERIAPSISCONS, x, DIFFSTEP, out state); alglib.minlmsetcond(state, EPSX, MAXITS); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, (x, fi, obj) => periapsisObjectiveFunction(x, fi, obj, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed), null, null); alglib.minlmresults(state, out x, out rep); periapsisObjectiveFunction(x, fi2, null, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed); Debug.Log("periapsis phase after optimization = " + fi2[0] + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); } maneuver.dV.x = x[0]; maneuver.dV.y = x[1]; maneuver.dV.z = x[2]; // // exit conditions and error handling // // try again if we failed to intersect the target orbit if (failed) { Debug.Log("Failed to intersect target orbit"); } // try again in one orbit if the maneuver node is in the past else if (maneuver.UT < earliest_UT || failed) { Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - maneuver.UT) + " s too early, trying again in " + initial_orbit.period + " s"); UT_transfer += initial_orbit.period; } else { Debug.Log("from optimizer DV = " + maneuver.dV + " t = " + maneuver.UT + " original arrival = " + UT_arrival); NodeList.Add(maneuver); break; } if (N++ > 10) { throw new OperationException("Ejection Optimization failed; try manual selection"); } } if (NodeList.Count > 0 && target_PeR > 0 && includeCaptureBurn) { // calculate the incoming orbit Orbit incoming_orbit; OrbitalManeuverCalculator.PatchedConicInterceptBody(initial_orbit, target_body, NodeList[0].dV, NodeList[0].UT, UT_arrival, out incoming_orbit); double burnUT = incoming_orbit.NextPeriapsisTime(incoming_orbit.StartUT); NodeList.Add(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToCircularize(incoming_orbit, burnUT), burnUT)); } return(NodeList); }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label("Select a target to rendezvous with."); base.WindowGUI(windowID); return; } if (core.target.Orbit.referenceBody != orbit.referenceBody) { GUILayout.Label("Rendezvous target must be in the same sphere of influence."); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); step = (Step)GuiUtils.ArrowSelector((int)step, numSteps, stepStrings[(int)step]); double leadTime = 30; switch (step) { case Step.AlignPlanes: GUILayout.Label("First, bring your relative inclination to zero by aligning your orbital plane with the target's orbital plane:"); GUILayout.Label("Relative inclination: " + orbit.RelativeInclination(core.target.Orbit).ToString("F2") + "º"); if (GUILayout.Button("Align Planes")) { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.Orbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); } break; case Step.PhasingOrbit: double phasingOrbitRadius = 0.9 * core.target.Orbit.PeR; if (phasingOrbitRadius < orbit.referenceBody.Radius + orbit.referenceBody.RealMaxAtmosphereAltitude()) { phasingOrbitRadius = 1.1 * core.target.Orbit.ApR; } double phasingOrbitAltitude = phasingOrbitRadius - mainBody.Radius; GUILayout.Label("Next, establish a circular phasing orbit close to the target orbit."); GUILayout.Label("Target orbit: " + MuUtils.ToSI(core.target.Orbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.Orbit.ApA, 3) + "m"); GUILayout.Label("Suggested phasing orbit: " + MuUtils.ToSI(phasingOrbitAltitude, 3) + "m x " + MuUtils.ToSI(phasingOrbitAltitude, 3) + "m"); GUILayout.Label("Current orbit: " + MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); if (GUILayout.Button("Establish Phasing Orbit")) { if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } break; case Step.Transfer: GUILayout.Label("Once in the phasing orbit, transfer to the target orbit at just the right time to intercept the target:"); if (GUILayout.Button("Intercept with Hohmann transfer")) { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); } double closestApproachTime = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); GUILayout.Label("Once on a transfer trajectory, match velocities at closest approach:"); GUILayout.Label("Time until closest approach: " + GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); GUILayout.Label("Separation at closest approach: " + MuUtils.ToSI(orbit.Separation(core.target.Orbit, closestApproachTime), 0) + "m"); if (GUILayout.Button("Match velocities at closest approach")) { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); } break; case Step.GetCloser: GUILayout.Label("If you aren't close enough after matching velocities, thrust gently toward the target:"); if (GUILayout.Button("Get closer")) { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.Label("Then match velocities again at closest approach"); break; } GUILayout.EndVertical(); MechJebModuleRendezvousAutopilot autopilot = core.GetComputerModule <MechJebModuleRendezvousAutopilot>(); if (autopilot != null) { bool active = GUILayout.Toggle(autopilot.enabled, "Autopilot enable"); if (autopilot.enabled != active) { if (active) { autopilot.users.Add(this); } else { autopilot.users.Remove(this); } } if (autopilot.enabled) { GUILayout.Label("Status: " + autopilot.status); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label1"));//"Select a target to rendezvous with." base.WindowGUI(windowID); return; } if (core.target.TargetOrbit.referenceBody != orbit.referenceBody) { GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label2"));//"Rendezvous target must be in the same sphere of influence." base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); //Information readouts: GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label3"), core.target.Name);//"Rendezvous target" const double leadTime = 30; GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label4"), MuUtils.ToSI(core.target.TargetOrbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.TargetOrbit.ApA, 3) + "m"); //"Target orbit" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label5"), MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); //"Current orbit" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label6"), orbit.RelativeInclination(core.target.TargetOrbit).ToString("F2") + "º"); //"Relative inclination" double closestApproachTime = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label7"), GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); //"Time until closest approach" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label8"), MuUtils.ToSI(orbit.Separation(core.target.TargetOrbit, closestApproachTime), 0) + "m"); //"Separation at closest approach" //Maneuver planning buttons: if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button1")))//"Align Planes" { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button2")))//"Establish new orbit at" { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } phasingOrbitAltitude.text = GUILayout.TextField(phasingOrbitAltitude.text, GUILayout.Width(70)); GUILayout.Label("km", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button3")))//"Intercept with Hohmann transfer" { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button4")))//"Match velocities at closest approach" { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button5")))//"Get closer" { double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, 100, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Any() && !core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button6")))//"Execute next node" { core.node.ExecuteOneNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button7")))//"Execute all nodes" { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button8")))//"Abort node execution" { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_RZplan_checkbox"), GUILayout.ExpandWidth(true)); //"Auto-warp" GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label9"), GUILayout.ExpandWidth(false)); //"Tolerance:" core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { core.node.tolerance.val += 0.1; } if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { core.node.tolerance.val -= core.node.tolerance.val > 0.1 ? 0.1 : 0.0; } if (GUILayout.Button("R", GUILayout.ExpandWidth(false))) { core.node.tolerance.val = 0.1; } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
void MakeNodeForOperation(Orbit o, double UT) { Vector3d dV = Vector3d.zero; double bodyRadius = o.referenceBody.Radius; switch (operation) { case Operation.CIRCULARIZE: dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case Operation.ELLIPTICIZE: dV = OrbitalManeuverCalculator.DeltaVToEllipticize(o, UT, newPeA + bodyRadius, newApA + bodyRadius); break; case Operation.PERIAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + bodyRadius); break; case Operation.APOAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(o, UT, newApA + bodyRadius); break; case Operation.INCLINATION: dV = OrbitalManeuverCalculator.DeltaVToChangeInclination(o, UT, newInc); break; case Operation.PLANE: if (timeReference == TimeReference.REL_ASCENDING) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, core.target.Orbit, UT, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, core.target.Orbit, UT, out UT); } break; case Operation.TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, core.target.Orbit, UT, out UT); break; case Operation.MOON_RETURN: dV = OrbitalManeuverCalculator.DeltaVAndTimeForMoonReturnEjection(o, UT, o.referenceBody.referenceBody.Radius + moonReturnAltitude, out UT); break; case Operation.COURSE_CORRECTION: CelestialBody targetBody = core.target.Target as CelestialBody; if (targetBody != null) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.Orbit, targetBody, targetBody.Radius + courseCorrectFinalPeA, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.Orbit, out UT); } break; case Operation.INTERPLANETARY_TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryTransferEjection(o, UT, core.target.Orbit, true, out UT); break; case Operation.LAMBERT: dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(o, UT, core.target.Orbit, UT + interceptInterval); break; case Operation.KILL_RELVEL: dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(o, UT, core.target.Orbit); break; } vessel.PlaceManeuverNode(o, dV, UT); }
void MakeNodeForOperation(Orbit o, double UT, Operation op, double newPeA, double newApA, double newInc, double courseCorrectFinalPeA, double moonReturnAltitude, double interceptInterval) { Vector3d dV = Vector3d.zero; double bodyRadius = o.referenceBody.Radius; // print(newPeA + " - " + this.newPeA + "\n" + // newApA + " - " + this.newApA + "\n" + // newInc + " - " + this.newInc + "\n" + // courseCorrectFinalPeA + " - " + this.courseCorrectFinalPeA + "\n" + // moonReturnAltitude + " - " + this.moonReturnAltitude + "\n" + // interceptInterval + " - " + this.interceptInterval); switch (op) { case Operation.CIRCULARIZE: dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case Operation.ELLIPTICIZE: dV = OrbitalManeuverCalculator.DeltaVToEllipticize(o, UT, newPeA + bodyRadius, newApA + bodyRadius); break; case Operation.PERIAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + bodyRadius); break; case Operation.APOAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(o, UT, newApA + bodyRadius); break; case Operation.INCLINATION: dV = OrbitalManeuverCalculator.DeltaVToChangeInclination(o, UT, newInc); break; case Operation.PLANE: if (timeReference == TimeReference.REL_ASCENDING) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, core.target.TargetOrbit, UT, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, core.target.TargetOrbit, UT, out UT); } break; case Operation.TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, core.target.TargetOrbit, UT, out UT); break; case Operation.MOON_RETURN: dV = OrbitalManeuverCalculator.DeltaVAndTimeForMoonReturnEjection(o, UT, o.referenceBody.referenceBody.Radius + moonReturnAltitude, out UT); break; case Operation.COURSE_CORRECTION: CelestialBody targetBody = core.target.Target as CelestialBody; if (targetBody != null) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.TargetOrbit, targetBody, targetBody.Radius + courseCorrectFinalPeA, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.TargetOrbit, interceptDistance, out UT); } break; case Operation.INTERPLANETARY_TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryTransferEjection(o, UT, core.target.TargetOrbit, true, out UT); break; case Operation.LAMBERT: dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(o, UT, core.target.TargetOrbit, UT + interceptInterval); break; case Operation.KILL_RELVEL: dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(o, UT, core.target.TargetOrbit); break; case Operation.RESONANT_ORBIT: dV = OrbitalManeuverCalculator.DeltaVToResonantOrbit(o, UT, (double)resonanceNumerator.val / resonanceDenominator.val); break; case Operation.SEMI_MAJOR: dV = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(o, UT, newSMA); break; case Operation.LAN: dV = OrbitalManeuverCalculator.DeltaVToShiftLAN(o, UT, core.target.targetLongitude); break; } vessel.PlaceManeuverNode(o, dV, UT); }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.target.Distance > 1000; //don't warp when close to target, because warping introduces small perturbations if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < 100 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = "Successful rendezvous"; } else if (core.target.Distance < 100) { double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Within 100m: matching velocities."; } else if (core.target.Distance < vesselState.radius / 50) { if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < 100 && orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning to match velocities at closest approach."; } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; double interceptUT = UT + closingTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Close to target: plotting intercept over " + closingTime.ToString("F0") + "s"; } } else if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < core.target.Orbit.semiMajorAxis / 50) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "On intercept course. Planning to match velocities at closest approach."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05 && orbit.SynodicPeriod(core.target.Orbit) < 5 * orbit.period) { //We're not on an intercept course, but we have a circular orbit in the right plane. //Also we are phasing quickly enough that it won't be too long until an intercept window //Plot a Hohmann transfer intercept. double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning Hohmann transfer for intercept."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05) { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double lowPhasingRadius = core.target.Orbit.semiMajorAxis / 1.16; double highPhasingRadius = core.target.Orbit.semiMajorAxis * 1.16; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.RealMaxAtmosphereAltitude() + 3000 && orbit.semiMajorAxis < core.target.orbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = "Increasing phasing rate by establishing new phasing orbit at " + MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0) + "m"; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.Orbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.Orbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Circularizing."; } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.Orbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.Orbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.Orbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Matching planes."; } }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.node.autowarp && core.target.Distance > 1000; //If we get within the target distance and then next maneuver node is still //far in the future, delete it and we will create a new one to match velocities immediately. //This can often happen because the target vessel's orbit shifts slightly when it is unpacked. if (core.target.Distance < desiredDistance && vessel.patchedConicSolver.maneuverNodes.Count > 0 && vessel.patchedConicSolver.maneuverNodes[0].UT > vesselState.time + 1) { vessel.RemoveAllManeuverNodes(); } if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { //If we have plotted a maneuver, execute it. if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < desiredDistance * 1.05 + 2 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = Localizer.Format("#MechJeb_RZauto_statu1");//"Successful rendezvous" } else if (core.target.Distance < desiredDistance * 1.05 + 2) { //We are within the target distance: match velocities double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu2", desiredDistance.ToString());//"Within " + + "m: matching velocities." } else if (core.target.Distance < vesselState.radius / 25) { if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < desiredDistance && orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = orbit.Separation(core.target.TargetOrbit, UT); double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu3");//"Planning to match velocities at closest approach." } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, closingTime); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu4");//"Close to target: plotting intercept" } } else if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < core.target.TargetOrbit.semiMajorAxis / 25) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = (orbit.SwappedAbsolutePositionAtUT(UT) - core.target.TargetOrbit.SwappedAbsolutePositionAtUT(UT)).magnitude; double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu5");//"On intercept course. Planning to match velocities at closest approach." } else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05 && orbit.eccentricity < 0.05) { //We're not on an intercept course, but we have a circular orbit in the right plane. double hohmannUT; Vector3d hohmannDV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out hohmannUT); double numPhasingOrbits = (hohmannUT - vesselState.time) / orbit.period; double actualMaxPhasingOrbits = Math.Max(maxPhasingOrbits, 5); // ignore input values that are unreasonably small if (numPhasingOrbits < actualMaxPhasingOrbits) { //It won't be too long until the intercept window. Plot a Hohmann transfer intercept. vessel.PlaceManeuverNode(orbit, hohmannDV, hohmannUT); status = Localizer.Format("#MechJeb_RZauto_statu6", numPhasingOrbits.ToString("F2"));//"Planning Hohmann transfer for intercept after " + + " phasing orbits." } else { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double axisRatio = Math.Pow(1 + 1.25 / actualMaxPhasingOrbits, 2.0 / 3.0); double lowPhasingRadius = core.target.TargetOrbit.semiMajorAxis / axisRatio; double highPhasingRadius = core.target.TargetOrbit.semiMajorAxis * axisRatio; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.Radius + mainBody.RealMaxAtmosphereAltitude() + 3000) && (orbit.semiMajorAxis < core.target.TargetOrbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = Localizer.Format("#MechJeb_RZauto_statu7", numPhasingOrbits.ToString("F1"), maxPhasingOrbits.text, MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0));//"Next intercept window would be <<1>> orbits away, which is more than the maximum of <<2>> phasing orbits. Increasing phasing rate by establishing new phasing orbit at <<3>>m } } else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.TargetOrbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.TargetOrbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu8");//"Circularizing." } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.TargetOrbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.TargetOrbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu9");//"Matching planes." } }
override public void activateAction() { base.activateAction(); Vessel vessel = this.scriptModule.vessel; VesselState vesselState = this.scriptModule.vesselState; Orbit orbit = this.scriptModule.orbit; CelestialBody mainBody = this.scriptModule.mainBody; const double leadTime = 30; double closestApproachTime = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); if (actionType == 0) //Align planes { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(this.scriptModule.orbit, dV, UT); } else if (actionType == 1) //Establish new orbit { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } else if (actionType == 2) //Intercept with Hohmann transfer { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } else if (actionType == 3) //Match velocities at closest approach { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } else if (actionType == 4) //Get closer { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, interceptUT, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } this.endAction(); }