Ejemplo n.º 1
0
            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());
            }
Ejemplo n.º 2
0
        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));
        }
Ejemplo n.º 3
0
        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);
            }
        }
Ejemplo n.º 4
0
            // 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);
            }
Ejemplo n.º 5
0
        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);
            }
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 8
0
            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);
            }
Ejemplo n.º 9
0
        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);
            }
        }
Ejemplo n.º 10
0
        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);
            }
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 12
0
        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);
            }
        }
Ejemplo n.º 13
0
        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);
            }
        }
Ejemplo n.º 14
0
        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);
            }
        }
Ejemplo n.º 15
0
        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);
            }
        }
Ejemplo n.º 16
0
        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));
        }
Ejemplo n.º 17
0
        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));
        }
Ejemplo n.º 20
0
        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));
        }
Ejemplo n.º 22
0
            // 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);
            }
Ejemplo n.º 24
0
        public static double ClosestAppVel()
        {
            Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(mjvessel.orbit, Planetarium.GetUniversalTime(), mjvessel.targetObject.GetOrbit());

            return(dV.magnitude);
        }