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."; } }
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." } }