Exemple #1
0
 public override void OnModuleEnabled()
 {
     if (!MuUtils.PhysicsRunning())
     {
         core.warp.MinimumWarp();
     }
 }
Exemple #2
0
 public override void OnModuleEnabled()
 {
     vessel.RemoveAllManeuverNodes();
     if (!MuUtils.PhysicsRunning())
     {
         core.warp.MinimumWarp();
     }
 }
Exemple #3
0
 public void Reset()
 {
     // lambda and lambdaDot are deliberately not cleared here
     //Debug.Log("call stack: + " + Environment.StackTrace);
     if (p != null)
     {
         p.KillThread();
         p = null;
     }
     status              = PVGStatus.INITIALIZING;
     last_stage_time     = 0.0;
     last_optimizer_time = 0.0;
     last_success_time   = 0.0;
     autowarp            = false;
     if (!MuUtils.PhysicsRunning())
     {
         core.warp.MinimumWarp();
     }
 }
Exemple #4
0
        void FixedUpdatePlaneChange()
        {
            Vector3d targetRadialVector  = mainBody.GetRelSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0);
            Vector3d currentRadialVector = vesselState.CoM - mainBody.position;
            double   angleToTarget       = Vector3d.Angle(targetRadialVector, currentRadialVector);
            bool     approaching         = Vector3d.Dot(targetRadialVector - currentRadialVector, vesselState.velocityVesselOrbit) > 0;

            if (!planeChangeTriggered && approaching && (angleToTarget > 80) && (angleToTarget < 90))
            {
                if (!MuUtils.PhysicsRunning())
                {
                    core.warp.MinimumWarp(true);
                }
                planeChangeTriggered = true;
            }

            if (planeChangeTriggered)
            {
                Vector3d horizontalToTarget = ComputePlaneChange();
                Vector3d finalVelocity      = Quaternion.FromToRotation(vesselState.horizontalOrbit, horizontalToTarget) * vesselState.velocityVesselOrbit;

                Vector3d deltaV = finalVelocity - vesselState.velocityVesselOrbit;
                //burn normal+ or normal- to avoid dropping the Pe:
                Vector3d burnDir = Vector3d.Exclude(vesselState.up, Vector3d.Exclude(vesselState.velocityVesselOrbit, deltaV));
                planeChangeDVLeft = Math.PI / 180 * Vector3d.Angle(finalVelocity, vesselState.velocityVesselOrbit) * vesselState.speedOrbitHorizontal;
                core.attitude.attitudeTo(burnDir, AttitudeReference.INERTIAL, this);
                if (planeChangeDVLeft < 0.1F)
                {
                    landStep = LandStep.LOW_DEORBIT_BURN;
                }

                status = "Executing low orbit plane change of about " + planeChangeDVLeft.ToString("F0") + " m/s";
            }
            else
            {
                if (core.node.autowarp)
                {
                    core.warp.WarpRegularAtRate((float)(orbit.period / 6));
                }
                status = "Moving to low orbit plane change burn point";
            }
        }
        public override void OnFixedUpdate()
        {
            if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any())
            {
                Abort();
                return;
            }

            //check if we've finished a node:
            ManeuverNode node   = vessel.patchedConicSolver.maneuverNodes.First();
            double       dVLeft = node.GetBurnVector(orbit).magnitude;

            if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5)
            {
                burnTriggered = false;

                node.RemoveSelf();

                if (mode == Mode.ONE_NODE)
                {
                    Abort();
                    return;
                }
                else if (mode == Mode.ALL_NODES)
                {
                    if (!vessel.patchedConicSolver.maneuverNodes.Any())
                    {
                        Abort();
                        return;
                    }
                    else
                    {
                        node = vessel.patchedConicSolver.maneuverNodes.First();
                    }
                }
            }

            //aim along the node
            core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this);

            double halfBurnTime;
            double burnTime = BurnTime(dVLeft, out halfBurnTime);

            double timeToNode = node.UT - vesselState.time;

            if (timeToNode < halfBurnTime)
            {
                burnTriggered = true;
                if (!MuUtils.PhysicsRunning())
                {
                    core.warp.MinimumWarp();
                }
            }

            //autowarp, but only if we're already aligned with the node
            if (autowarp && !burnTriggered)
            {
                if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning()))
                {
                    core.warp.WarpToUT(node.UT - halfBurnTime - leadTime);
                }
                else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600)
                {
                    //realign
                    core.warp.MinimumWarp();
                }
            }

            core.thrust.targetThrottle = 0;

            if (burnTriggered)
            {
                if (alignedForBurn)
                {
                    if (core.attitude.attitudeAngleFromTarget() < 90)
                    {
                        double timeConstant = (dVLeft > 10 || vesselState.minThrustAccel > 0.25 * vesselState.maxThrustAccel ? 0.5 : 2);
                        core.thrust.ThrustForDV(dVLeft + tolerance, timeConstant);
                    }
                    else
                    {
                        alignedForBurn = false;
                    }
                }
                else
                {
                    if (core.attitude.attitudeAngleFromTarget() < 2)
                    {
                        alignedForBurn = true;
                    }
                }
            }
        }
Exemple #6
0
        void FixedUpdateDecelerationBurn()
        {
            if (vesselState.altitudeASL < DecelerationEndAltitude() + 5)
            {
                if (UseAtmosphereToBrake())
                {
                    landStep = LandStep.FINAL_DESCENT;
                }
                else
                {
                    landStep = LandStep.KILLING_HORIZONTAL_VELOCITY;
                }
                core.warp.MinimumWarp();
                return;
            }

            double decelerationStartTime = (prediction.trajectory.Any() ? prediction.trajectory.First().UT : vesselState.time);

            if (decelerationStartTime - vesselState.time > 5)
            {
                core.thrust.targetThrottle = 0;

                status = "Warping to start of braking burn.";

                //warp to deceleration start
                Vector3d decelerationStartAttitude = -orbit.SwappedOrbitalVelocityAtUT(decelerationStartTime);
                decelerationStartAttitude += mainBody.getRFrmVel(orbit.SwappedAbsolutePositionAtUT(decelerationStartTime));
                decelerationStartAttitude  = decelerationStartAttitude.normalized;
                core.attitude.attitudeTo(decelerationStartAttitude, AttitudeReference.INERTIAL, this);
                bool warpReady = core.attitude.attitudeAngleFromTarget() < 5;

                if (warpReady && core.node.autowarp)
                {
                    core.warp.WarpToUT(decelerationStartTime - 5);
                }
                else if (!MuUtils.PhysicsRunning())
                {
                    core.warp.MinimumWarp();
                }
                return;
            }

            Vector3d desiredThrustVector = -vesselState.velocityVesselSurfaceUnit;

            Vector3d courseCorrection = ComputeCourseCorrection(false);
            double   correctionAngle  = courseCorrection.magnitude / (2.0 * vesselState.limitedMaxThrustAccel);

            correctionAngle     = Math.Min(0.1, correctionAngle);
            desiredThrustVector = (desiredThrustVector + correctionAngle * courseCorrection.normalized).normalized;

            if (Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.up) > 0 ||
                Vector3d.Dot(vesselState.forward, desiredThrustVector) < 0.75)
            {
                core.thrust.targetThrottle = 0;
                status = "Braking";
            }
            else
            {
                double controlledSpeed             = vesselState.speedSurface * Math.Sign(Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.up)); //positive if we are ascending, negative if descending
                double desiredSpeed                = -MaxAllowedSpeed();
                double desiredSpeedAfterDt         = -MaxAllowedSpeedAfterDt(vesselState.deltaT);
                double minAccel                    = -vesselState.localg * Math.Abs(Vector3d.Dot(vesselState.velocityVesselSurfaceUnit, vesselState.up));
                double maxAccel                    = vesselState.maxThrustAccel * Vector3d.Dot(vesselState.forward, -vesselState.velocityVesselSurfaceUnit) - vesselState.localg * Math.Abs(Vector3d.Dot(vesselState.velocityVesselSurfaceUnit, vesselState.up));
                double speedCorrectionTimeConstant = 0.3;
                double speedError                  = desiredSpeed - controlledSpeed;
                double desiredAccel                = speedError / speedCorrectionTimeConstant + (desiredSpeedAfterDt - desiredSpeed) / vesselState.deltaT;
                if (maxAccel - minAccel > 0)
                {
                    core.thrust.targetThrottle = Mathf.Clamp((float)((desiredAccel - minAccel) / (maxAccel - minAccel)), 0.0F, 1.0F);
                }
                else
                {
                    core.thrust.targetThrottle = 0;
                }
                status = "Braking: target speed = " + Math.Abs(desiredSpeed).ToString("F1") + " m/s";
            }

            core.attitude.attitudeTo(desiredThrustVector, AttitudeReference.INERTIAL, this);
        }
Exemple #7
0
        void FixedUpdateDeorbitBurn()
        {
            //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 (part.vessel.orbit.ApA < part.vessel.mainBody.RealMaxAtmosphereAltitude())
            {
                landStep = LandStep.COURSE_CORRECTIONS;
                core.thrust.targetThrottle = 0;
                return;
            }

            //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.GetRelSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0);        //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.velocityVesselOrbit);                                 //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 - part.vessel.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(true);                            //get out of warp
                }
                Vector3d deltaV = finalHorizontalVelocity - currentHorizontalVelocity;
                core.attitude.attitudeTo(deltaV.normalized, AttitudeReference.INERTIAL, this);

                if (deltaV.magnitude < 2.0)
                {
                    landStep = LandStep.COURSE_CORRECTIONS;
                }

                status = "Doing high deorbit burn";
            }
            else
            {
                core.attitude.attitudeTo(Vector3d.back, AttitudeReference.ORBIT, this);
                if (core.node.autowarp)
                {
                    core.warp.WarpRegularAtRate((float)(orbit.period / 10));
                }

                status = "Moving to high deorbit burn point";
            }
        }
Exemple #8
0
        void FixedUpdateLowDeorbitBurn()
        {
            //Decide when we will start the deorbit burn:
            double stoppingDistance  = Math.Pow(vesselState.speedSurfaceHorizontal, 2) / (2 * vesselState.limitedMaxThrustAccel);
            double triggerDistance   = lowDeorbitBurnTriggerFactor * stoppingDistance;
            double heightAboveTarget = vesselState.altitudeASL - DecelerationEndAltitude();

            if (triggerDistance < heightAboveTarget)
            {
                triggerDistance = heightAboveTarget;
            }

            //See if it's time to start the deorbit burn:
            double rangeToTarget = Vector3d.Exclude(vesselState.up, core.target.GetPositionTargetPosition() - vesselState.CoM).magnitude;

            if (!deorbitBurnTriggered && rangeToTarget < triggerDistance)
            {
                if (!MuUtils.PhysicsRunning())
                {
                    core.warp.MinimumWarp(true);
                }
                deorbitBurnTriggered = true;
            }

            if (deorbitBurnTriggered)
            {
                status = "Executing low deorbit burn";
            }
            else
            {
                status = "Moving to low deorbit burn point";
            }

            //Warp toward deorbit burn if it hasn't been triggerd yet:
            if (!deorbitBurnTriggered && core.node.autowarp && rangeToTarget > 2 * triggerDistance)
            {
                core.warp.WarpRegularAtRate((float)(orbit.period / 6));
            }
            if (rangeToTarget < triggerDistance && !MuUtils.PhysicsRunning())
            {
                core.warp.MinimumWarp();
            }

            //By default, thrust straight back at max throttle
            Vector3d thrustDirection = -vesselState.velocityVesselSurfaceUnit;

            lowDeorbitBurnMaxThrottle = 1;

            //If we are burning, we watch the predicted landing site and switch to the braking
            //burn when the predicted landing site crosses the target. We also use the predictions
            //to steer the predicted landing site toward the target
            if (deorbitBurnTriggered && PredictionReady)
            {
                //angle slightly left or right to fix any cross-range error in the predicted landing site:
                Vector3d horizontalToLandingSite = Vector3d.Exclude(vesselState.up, LandingSite - vesselState.CoM).normalized;
                Vector3d horizontalToTarget      = Vector3d.Exclude(vesselState.up, core.target.GetPositionTargetPosition() - vesselState.CoM).normalized;
                double   angleGain       = 4;
                Vector3d angleCorrection = angleGain * (horizontalToTarget - horizontalToLandingSite);
                if (angleCorrection.magnitude > 0.1)
                {
                    angleCorrection *= 0.1 / angleCorrection.magnitude;
                }
                thrustDirection = (thrustDirection + angleCorrection).normalized;

                double rangeToLandingSite = Vector3d.Exclude(vesselState.up, LandingSite - vesselState.CoM).magnitude;
                double maxAllowedSpeed    = MaxAllowedSpeed();

                if (!lowDeorbitEndConditionSet && Vector3d.Distance(LandingSite, vesselState.CoM) < mainBody.Radius + vesselState.altitudeASL)
                {
                    lowDeorbitEndOnLandingSiteNearer = rangeToLandingSite > rangeToTarget;
                    lowDeorbitEndConditionSet        = true;
                }

                lowDeorbitBurnMaxThrottle = 1;

                if (orbit.PeA < 0)
                {
                    if (rangeToLandingSite > rangeToTarget)
                    {
                        if (lowDeorbitEndConditionSet && !lowDeorbitEndOnLandingSiteNearer)
                        {
                            landStep = LandStep.DECELERATING;
                            core.thrust.targetThrottle = 0;
                        }

                        double maxAllowedSpeedAfterDt = MaxAllowedSpeedAfterDt(vesselState.deltaT);
                        double speedAfterDt           = vesselState.speedSurface + vesselState.deltaT * Vector3d.Dot(vesselState.gravityForce, vesselState.velocityVesselSurfaceUnit);
                        double throttleToMaintainLandingSite;
                        if (vesselState.speedSurface < maxAllowedSpeed)
                        {
                            throttleToMaintainLandingSite = 0;
                        }
                        else
                        {
                            throttleToMaintainLandingSite = (speedAfterDt - maxAllowedSpeedAfterDt) / (vesselState.deltaT * vesselState.maxThrustAccel);
                        }

                        lowDeorbitBurnMaxThrottle = throttleToMaintainLandingSite + 1 * (rangeToLandingSite / rangeToTarget - 1) + 0.2;
                    }
                    else
                    {
                        if (lowDeorbitEndConditionSet && lowDeorbitEndOnLandingSiteNearer)
                        {
                            landStep = LandStep.DECELERATING;
                            core.thrust.targetThrottle = 0;
                        }
                        else
                        {
                            lowDeorbitBurnMaxThrottle = 0;
                            status = "Deorbit burn complete: waiting for the right moment to start braking";
                        }
                    }
                }
            }

            core.attitude.attitudeTo(thrustDirection, AttitudeReference.INERTIAL, this);
        }
Exemple #9
0
        public override void OnFixedUpdate()
        {
            if (!vessel.patchedConicSolver.maneuverNodes.Any())
            {
                Abort();
                return;
            }

            //check if we've finished a node:
            ManeuverNode node   = vessel.patchedConicSolver.maneuverNodes.First();
            double       dVLeft = node.GetBurnVector(orbit).magnitude;

            if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5)
            {
                burnTriggered = false;

                vessel.patchedConicSolver.RemoveManeuverNode(node);

                if (mode == Mode.ONE_NODE)
                {
                    Abort();
                    return;
                }
                else if (mode == Mode.ALL_NODES)
                {
                    if (!vessel.patchedConicSolver.maneuverNodes.Any())
                    {
                        Abort();
                        return;
                    }
                    else
                    {
                        node = vessel.patchedConicSolver.maneuverNodes.First();
                    }
                }
            }

            //aim along the node
            core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this);

            double burnTime = BurnTime(dVLeft);

            double timeToNode = node.UT - vesselState.time;

            if (timeToNode < burnTime * leadFraction)
            {
                burnTriggered = true;
                if (!MuUtils.PhysicsRunning())
                {
                    core.warp.MinimumWarp();
                }
            }

            //autowarp, but only if we're already aligned with the node
            if (autowarp && !burnTriggered)
            {
                if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning()))
                {
                    core.warp.WarpToUT(node.UT - burnTime * leadFraction - leadTime);
                }
                else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600)
                {
                    //realign
                    core.warp.MinimumWarp();
                }
            }

            core.thrust.targetThrottle = 0;

            if (burnTriggered)
            {
                if (alignedForBurn)
                {
                    if (core.attitude.attitudeAngleFromTarget() < 90)
                    {
                        double timeConstant        = (dVLeft > 10 ? 0.5 : 2);
                        double desiredAcceleration = dVLeft / timeConstant;
                        desiredAcceleration = Math.Max(tolerance, desiredAcceleration);

                        core.thrust.targetThrottle = Mathf.Clamp01((float)(desiredAcceleration / vesselState.maxThrustAccel));
                    }
                    else
                    {
                        alignedForBurn = false;
                    }
                }
                else
                {
                    if (core.attitude.attitudeAngleFromTarget() < 2)
                    {
                        alignedForBurn = true;
                    }
                }
            }
        }