Exemplo n.º 1
0
 void update_landing_site_after_brake()
 {
     SetBrakeDeltaV(-LandingTrajectoryAutopilot
                    .CorrectedBrakeVelocity(VSL, BrakeEndPoint.vel, BrakeEndPoint.pos,
                                            BrakeEndPoint.DynamicPressure / 1000 / LandingTrajectoryAutopilot.C.MinDPressure,
                                            AtTargetUT - BrakeEndPoint.UT));
     BrakeStartPoint = Path.PointAtUT(Math.Max(BrakeEndPoint.UT - MatchVelocityAutopilot
                                               .BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration), StartUT));
     AfterBrakePath = new LandingPath(VSL,
                                      BrakeStartPoint.OrbitFromHere(),
                                      TargetAltitude,
                                      BrakeStartPoint.UT,
                                      (AtTargetUT - BrakeStartPoint.UT) / 20,
                                      VSL.Physics.M - ManeuverFuel,
                                      VSL.Engines.AvailableFuelMass - ManeuverFuel,
                                      BrakeDeltaV.magnitude);
     if (Path.Atmosphere)
     {
         update_overheat_info(AfterBrakePath, BrakeStartPoint.ShipTemperature);
     }
     BrakeDeltaV = BrakeDeltaV.normalized * AfterBrakePath.BrakeDeltaV;
     BrakeFuel   = (float)AfterBrakePath.FuelUsed;
     FullBrake   = (VSL.Engines.AvailableFuelMass
                    - ManeuverFuel - BrakeFuel
                    - VSL.Engines.MaxMassFlow * LandingTrajectoryAutopilot.C.LandingThrustTime > 0);
     AtTargetVel  = AfterBrakePath.LastPoint.vel;
     AtTargetPos  = AfterBrakePath.LastPoint.pos;
     AtTargetUT   = AfterBrakePath.LastPoint.UT;
     TransferTime = AtTargetUT - StartUT;
     update_landing_site(AfterBrakePath);
 }
Exemplo n.º 2
0
        protected void add_target_node()
        {
            var dV = trajectory.BrakeDeltaV;

            ManeuverAutopilot.AddNode(VSL, dV,
                                      trajectory.AtTargetUT
                                      - MatchVelocityAutopilot.BrakingNodeCorrection((float)dV.magnitude, VSL));
        }
        public void AddBrakeNode()
        {
            var dV = Trajectory.BrakeDeltaV;

            ManeuverAutopilot.AddNode(VSL, dV,
                                      Trajectory.AtTargetUT
                                      - MatchVelocityAutopilot.BrakingNodeCorrection((float)dV.magnitude, VSL));
        }
 void update(bool with_brake)
 {
     update_from_orbit(Orbit, StartUT);
     //correct for brake maneuver
     if (with_brake)
     {
         BrakeEndUT    = AtTargetUT - GLB.LTRJ.CorrectionOffset;
         BrakeStartUT  = BrakeEndUT - MatchVelocityAutopilot.BrakingOffset((float)AtTargetVel.magnitude, VSL, out BrakeDuration);
         brake_delta_v = -0.9 * Orbit.getOrbitalVelocityAtUT(BrakeEndUT);
         update_from_orbit(TrajectoryCalculator.NewOrbit(Orbit, BrakeDeltaV, BrakeEndUT), BrakeEndUT);
     }
     else
     {
         brake_delta_v = -(AtTargetVel + Vector3d.Cross(Body.zUpAngularVelocity, AtTargetPos));
         BrakeEndUT    = TrajectoryCalculator.FlyAboveUT(Orbit, Target.RelSurfPos(Body).xzy, StartUT);
         BrakeStartUT  = BrakeEndUT - MatchVelocityAutopilot.BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration);
     }
     //compute vessel coordinates at maneuver start
     if (VSL.LandedOrSplashed)
     {
         VslStartLat = Utils.ClampAngle(VSL.vessel.latitude);
         VslStartLon = Utils.ClampAngle(VSL.vessel.longitude);
     }
     else
     {
         var start_pos = (TrajectoryCalculator.BodyRotationAtdT(Body, -TimeToStart) * StartPos).xzy + Body.position;
         VslStartLat = Utils.ClampAngle(Body.GetLatitude(start_pos));
         VslStartLon = Utils.ClampAngle(Body.GetLongitude(start_pos));
     }
     //compute distance to target
     DistanceToTarget = Target.AngleTo(SurfacePoint) * Body.Radius;
     BrakeEndDeltaAlt = Orbit.getRelativePositionAtUT(BrakeEndUT).magnitude - Body.Radius - TargetAltitude;
     //compute distance in lat-lon coordinates
     DeltaLat = Utils.AngleDelta(SurfacePoint.Pos.Lat, Target.Pos.Lat) *
                Math.Sign(Utils.AngleDelta(Utils.ClampAngle(VslStartLat), SurfacePoint.Pos.Lat));
     DeltaLon = Utils.AngleDelta(SurfacePoint.Pos.Lon, Target.Pos.Lon) *
                Math.Sign(Utils.AngleDelta(Utils.ClampAngle(VslStartLon), SurfacePoint.Pos.Lon));
     //compute distance in radial coordinates
     DeltaFi = 90 - Vector3d.Angle(Orbit.GetOrbitNormal(),
                                   TrajectoryCalculator.BodyRotationAtdT(Body, TimeToSurface) *
                                   Body.GetRelSurfacePosition(Target.Pos.Lat, Target.Pos.Lon, TargetAltitude).xzy);
     DeltaR = Utils.RadDelta(SurfacePoint.AngleTo(VslStartLat, VslStartLon), Target.AngleTo(VslStartLat, VslStartLon)) * Mathf.Rad2Deg;
 }
        void update(bool with_brake)
        {
            update_from_orbit(Orbit, StartUT);
            LandingAngle = 90 - Vector3d.Angle(AtTargetPos, -AtTargetVel);
            //correct for brake maneuver
            if (with_brake)
            {
                //estimate time needed to rotate the ship downwards
                var rotation_time = VSL.Torque.NoEngines?
                                    VSL.Torque.NoEngines.MinRotationTime(90) :
                                    VSL.Torque.MaxPossible.RotationTime(90, 0.1f);
                //estimate amount fuel needed for the maneuver
                var vertical_vel = Vector3d.Project(AtTargetVel, AtTargetPos);
                SetBrakeEndUT(Math.Max(AtTargetUT - GLB.LTRJ.CorrectionOffset + rotation_time, StartUT));
                SetBrakeDeltaV(vertical_vel);
                if (BrakeFuel > 0)
                {
                    //calculate braking maneuver
                    var dV = (float)BrakeDeltaV.magnitude;
                    BrakeDuration  = VSL.Engines.AntigravTTB(dV);
                    BrakeDuration += rotation_time;
                    //find the appropriate point to perform the maneuver
                    var    brake_end_UT   = Math.Max(AtTargetUT - Mathf.Max(GLB.LTRJ.CorrectionOffset, BrakeDuration * 1.1f), StartUT);
                    var    vertical_speed = vertical_vel.magnitude;
                    double fly_over_error;
                    do
                    {
                        SetBrakeEndUT(brake_end_UT);
                        fly_over_error = BrakeEndDeltaAlt - GLB.LTRJ.FlyOverAlt;
                        brake_end_UT  -= Math.Abs(fly_over_error / vertical_speed);
                    } while(brake_end_UT > StartUT && fly_over_error < -1);
                    SetBrakeDeltaV(-0.9 * Orbit.getOrbitalVelocityAtUT(BrakeEndUT));
                    //calculate maneuver start time and update landing site
                    BrakeStartUT = Math.Max(BrakeEndUT - MatchVelocityAutopilot.BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration), StartUT);
                    update_from_orbit(TrajectoryCalculator.NewOrbit(Orbit, BrakeDeltaV, BrakeEndUT), BrakeEndUT);
                }
                else
                {
                    BrakeStartUT  = BrakeEndUT;
                    BrakeDuration = 0;
                }
            }
            else
            {
                SetBrakeEndUT(TrajectoryCalculator.FlyAboveUT(Orbit, Target.RelOrbPos(Body), StartUT));
                SetBrakeDeltaV(-(AtTargetVel + Vector3d.Cross(Body.zUpAngularVelocity, AtTargetPos)));
                if (BrakeFuel > 0)
                {
                    var offset = MatchVelocityAutopilot.BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration);
                    BrakeStartUT = Math.Max(BrakeEndUT - offset, StartUT);
                }
                else
                {
                    BrakeStartUT  = BrakeEndUT;
                    BrakeDuration = 0;
                }
            }
            BrakeOffset = (float)Utils.ClampL(BrakeEndUT - BrakeStartUT, 0);
            //compute vessel coordinates at maneuver start
            if (VSL.LandedOrSplashed)
            {
                VslStartLat = Utils.ClampAngle(VSL.vessel.latitude);
                VslStartLon = Utils.ClampAngle(VSL.vessel.longitude);
            }
            else
            {
                var start_pos = (TrajectoryCalculator.BodyRotationAtdT(Body, -TimeToStart) * StartPos).xzy + Body.position;
                VslStartLat = Utils.ClampAngle(Body.GetLatitude(start_pos));
                VslStartLon = Utils.ClampAngle(Body.GetLongitude(start_pos));
            }
            //compute distance to target
            DistanceToTarget   = Target.AngleTo(SurfacePoint) * Body.Radius;
            SurfacePoint.Name += string.Format("\n{0} from target", Utils.formatBigValue((float)DistanceToTarget, "m"));
            //compute distance in lat-lon coordinates
            DeltaLat = Utils.AngleDelta(SurfacePoint.Pos.Lat, Target.Pos.Lat) *
                       Math.Sign(Utils.AngleDelta(approach.Lat, SurfacePoint.Pos.Lat));
            DeltaLon = Utils.AngleDelta(SurfacePoint.Pos.Lon, Target.Pos.Lon) *
                       Math.Sign(Utils.AngleDelta(approach.Lon, SurfacePoint.Pos.Lon));
            //compute distance in radial coordinates
            DeltaFi = 90 - Vector3d.Angle(Orbit.GetOrbitNormal(),
                                          TrajectoryCalculator.BodyRotationAtdT(Body, TimeToTarget) *
                                          Body.GetRelSurfacePosition(Target.Pos.Lat, Target.Pos.Lon, TargetAltitude).xzy);
            DeltaR = Utils.RadDelta(SurfacePoint.AngleTo(VslStartLat, VslStartLon), Target.AngleTo(VslStartLat, VslStartLon)) * Mathf.Rad2Deg;
//            Utils.Log("{}", this);//debug
        }
Exemplo n.º 6
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            VSL.Engines.ActivateEngines();
            if (VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines)
            {
                landing_stage = LandingStage.HardLanding;
            }
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            double   terminal_velocity;
            Vector3d brake_pos, brake_vel, obt_vel;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB),
                                                LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP)
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                update_trajectory();
                nose_to_target();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    compute_terminal_velocity();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        brake_vel = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        //this is nice smoothing, but is dangerous on a low decending trajectory
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        if (VSL.Info.Countdown - VSL.Torque.MaxCurrent.TurnTime - VSL.vessel.dynamicPressurekPa > VSL.Info.TTB)
                        {
                            brake_vel = brake_vel.normalized * VSL.HorizontalSpeed.Absolute * Utils.ClampH(trajectory.DistanceToTarget / CFG.Target.DistanceTo(VSL.vessel), 1);
                        }
                        if (Executor.Execute(-brake_vel, (float)Utils.ClampL(LTRJ.BrakeEndSpeed * Body.GeeASL, GLB.THR.MinDeltaV)))
                        {
                            break;
                        }
                    }
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                correct_landing_site();
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, TRJ.ManeuverOffset);
                if (VSL.Info.Countdown <= 0)
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < LTRJ.HoverTimeThreshold))
                    {
                        Message(10, "Not enough fuel to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", "Emergency Landing...");
                set_destination_vector();
                update_trajectory();
                VSL.BrakesOn();
                CFG.BR.Off();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel to land properly.\nWill deceletate as much as possible before impact...");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    VSL.OnPlanetParams.ActivateParachutes();
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for safe speed to deploy parachutes.\n" +
                                   "Trying to decelerate using drag...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                    }
                    Status("red", "Crash is imminent.\nImpact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                THR.Throttle = 0;
                set_destination_vector();
                update_trajectory();
                setup_for_deceleration();
                compute_terminal_velocity();
                nose_to_target();
                if (Working)
                {
                    Status("white", "Final deceleration. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    ATC.SetThrustDirW(correction_direction());
                    if (VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = Mathf.Max(VSL.HorizontalSpeed.Absolute, -VSL.VerticalSpeed.Absolute);
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (VSL.vessel.srfSpeed > LTRJ.BrakeEndSpeed)
                    {
                        Working = THR.Throttle.Equals(1) || VSL.Info.Countdown < 10;
                        break;
                    }
                }
                else
                {
                    var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                    correct_attitude_with_thrusters(turn_time);
                    correct_landing_site();
                    VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time + LTRJ.FinalBrakeOffset;
                    if (VSL.Controls.InvAlignmentFactor > 0.5)
                    {
                        Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    else
                    {
                        Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    Working = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;
                    break;
                }
                THR.Throttle = 0;
                if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                {
                    approach();
                }
                else
                {
                    land();
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }
Exemplo n.º 7
0
        void update(bool with_brake, bool brake_at_fly_above)
        {
            reset();
            //update everything
            update_from_orbit();
            update_landing_steepness();
            ActualLandingAngle = 90 - Utils.Angle2(AtTargetPos, -AtTargetVel);
            var AerobrakeStartUT = Path.Atmosphere ? Path.AtmoStartUT : AtTargetUT - 1;

            //correct for brake maneuver
            if (with_brake)
            {
                //estimate time needed to rotate the ship downwards
                var rotation_time = VSL.Torque.NoEngines ?
                                    VSL.Torque.NoEngines.RotationTime2Phase(90) :
                                    VSL.Torque.MaxPossible.RotationTime2Phase(90, 0.1f);
                //estimate amount of fuel needed for the maneuver
                var vertical_vel = Vector3d.Project(AtTargetVel, AtTargetPos);
                SetBrakeEndUT(Math.Max(AtTargetUT - LandingTrajectoryAutopilot.C.CorrectionOffset + rotation_time, StartUT));
                SetBrakeDeltaV(vertical_vel);
                if (BrakeFuel > 0)
                {
                    //calculate braking maneuver
                    BrakeDuration = VSL.Engines.OnPlanetTTB(BrakeDeltaV,
                                                            Orbit.getRelativePositionAtUT(BrakeEndPoint.UT),
                                                            (float)(BrakeEndPointDeltaAlt + TargetAltitude));
                    BrakeDuration += rotation_time;
                    if (FullBrake)
                    {
                        if (brake_at_fly_above)
                        {
                            FlyAbovePoint = Path.FlyAbovePoint(Target.OrbPos(Body));
                            if (WillOverheat)
                            {
                                SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                            }
                            else
                            {
                                SetBrakeEndPoint(FlyAbovePoint);
                            }
                        }
                        else
                        {
                            //find appropriate point to perform the maneuver
                            var brake_end_UT = Math.Max(AtTargetUT - Mathf.Max(LandingTrajectoryAutopilot.C.CorrectionOffset, BrakeDuration * 1.1f), StartUT);
                            var fly_over_alt = TargetAltitude + LandingTrajectoryAutopilot.C.FlyOverAlt;
                            if (WillOverheat)
                            {
                                SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                            }
                            else if (Path.UT2Altitude(brake_end_UT) < fly_over_alt)
                            {
                                SetBrakeEndPoint(Path.PointAtAltitude(fly_over_alt));
                            }
                            else
                            {
                                SetBrakeEndUT(brake_end_UT);
                            }
                        }
                    }
                    else
                    {
                        SetBrakeEndUT(AerobrakeStartUT);
                    }
                    //update landing site
                    update_landing_site_after_brake();
                }
                else //no brake maneuver
                {
                    SetBrakeEndUT(AerobrakeStartUT);
                    BrakeStartPoint = BrakeEndPoint;
                    BrakeDuration   = 0;
                }
            }
            else
            {
                FlyAbovePoint = Path.FlyAbovePoint(Target.OrbPos(Body));
                if (WillOverheat)
                {
                    SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                }
                else
                {
                    SetBrakeEndPoint(FlyAbovePoint);
                }
                SetBrakeDeltaV(-AtTargetVel - Vector3d.Cross(Body.zUpAngularVelocity, AtTargetPos));
                if (BrakeFuel > 0)
                {
                    var offset = MatchVelocityAutopilot.BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration);
                    BrakeStartPoint = Path.PointAtUT(Math.Max(BrakeEndPoint.UT - offset, StartUT));
                }
                else
                {
                    SetBrakeEndUT(AerobrakeStartUT);
                    BrakeStartPoint = BrakeStartPoint;
                    BrakeDuration   = 0;
                }
            }
            BrakeOffset = (float)Utils.ClampL(BrakeEndPoint.UT - BrakeStartPoint.UT, 0);
            //compute vessel coordinates at maneuver start
            if (VSL.LandedOrSplashed)
            {
                VslStartLat = Utils.ClampAngle(VSL.vessel.latitude);
                VslStartLon = Utils.ClampAngle(VSL.vessel.longitude);
            }
            else
            {
                var start_pos = (TrajectoryCalculator.BodyRotationAtdT(Body, -TimeToStart) * StartPos).xzy + Body.position;
                VslStartLat = Utils.ClampAngle(Body.GetLatitude(start_pos));
                VslStartLon = Utils.ClampAngle(Body.GetLongitude(start_pos));
            }
            //compute distance to target
            DistanceToTarget   = Target.AngleTo(SurfacePoint) * Body.Radius;
            SurfacePoint.Name += string.Format("\n{0} from target", Utils.formatBigValue((float)DistanceToTarget, "m"));
            //compute distance in lat-lon coordinates
            DeltaLat = Utils.AngleDelta(SurfacePoint.Pos.Lat, Target.Pos.Lat) *
                       Math.Sign(Utils.AngleDelta(approach.Lat, SurfacePoint.Pos.Lat));
            DeltaLon = Utils.AngleDelta(SurfacePoint.Pos.Lon, Target.Pos.Lon) *
                       Math.Sign(Utils.AngleDelta(approach.Lon, SurfacePoint.Pos.Lon));
            //compute distance in radial coordinates
            DeltaFi = 90 - Utils.Angle2(Orbit.GetOrbitNormal(),
                                        TrajectoryCalculator.BodyRotationAtdT(Body, TimeToTarget) * Target.OrbPos(Body));
            DeltaR = Utils.RadDelta(SurfacePoint.AngleTo(VslStartLat, VslStartLon), Target.AngleTo(VslStartLat, VslStartLon)) * Mathf.Rad2Deg;
//            Utils.Log("{}", this);//debug
        }
Exemplo n.º 8
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                stop_aerobraking();
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            update_trajectory();
            VSL.Engines.ActivateEngines();
            NoEnginesTimer.RunIf(VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines);
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            Vector3d brake_pos, brake_vel, obt_vel;
            var      vessel_within_range   = CFG.Target.DistanceTo(VSL.vessel) < LTRJ.Dtol;
            var      vessel_after_target   = Vector3.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.VectorTo(VSL.vessel)) >= 0;
            var      target_within_range   = trajectory.DistanceToTarget < LTRJ.Dtol;
            var      landing_before_target = trajectory.DeltaR > 0;
            var      terminal_velocity     = compute_terminal_velocity();;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                var offset = MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB);
                offset             = Mathf.Lerp(VSL.Info.TTB, offset, Utils.Clamp(VSL.Engines.TMR - 0.1f, 0, 1));
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(offset, LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP ||
                    will_overheat(trajectory.GetAtmosphericCurve(5, VSL.Physics.UT + TRJ.ManeuverOffset)))
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                if (CorrectTarget && VSL.Info.Countdown < CorrectionOffset)
                {
                    scan_for_landing_site();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                CFG.BR.Off();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    if (CorrectTarget)
                    {
                        scan_for_landing_site();
                    }
                    do_aerobraking_if_requested();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        THR.Throttle = 0;
                        brake_vel    = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel    = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        var aerobraking = rel_dP > 0 && VSL.OnPlanetParams.ParachutesActive;
                        if (!vessel_after_target)
                        {
                            var overheating = rel_dP > 0 &&
                                              VSL.vessel.Parts.Any(p =>
                                                                   p.temperature / p.maxTemp > PhysicsGlobals.TemperatureGaugeThreshold ||
                                                                   p.skinTemperature / p.skinMaxTemp > PhysicsGlobals.TemperatureGaugeThreshold);
                            if (!overheating)
                            {
                                ATC.SetThrustDirW(brake_vel);
                                THR.Throttle = CFG.Target.DistanceTo(VSL.vessel) > trajectory.DistanceToTarget?
                                               (float)Utils.ClampH(trajectory.DistanceToTarget / LTRJ.Dtol / 2, 1) : 1;
                            }
                            else
                            {
                                THR.Throttle = 1;
                            }
                        }
                        if (THR.Throttle > 0 || aerobraking)
                        {
                            break;
                        }
                    }
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                nose_to_target();
                setup_for_deceleration();
                if (correct_landing_site())
                {
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, ManeuverOffset);
                if (VSL.Info.Countdown > 0)
                {
                    if (THR.Throttle.Equals(0))
                    {
                        warp_to_coundown();
                    }
                }
                else
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left         = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed       = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    var needed_hover_time = LandASAP? LTRJ.HoverTimeThreshold / 5 : LTRJ.HoverTimeThreshold;
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < needed_hover_time))
                    {
                        Message(10, "Not enough fuel for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
//						Log("Hard Landing. Trajectory:\n{}", trajectory);//debug
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
//					Log("Soft Landing. Trajectory:\n{}", trajectory);//debug
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", VSL.OnPlanetParams.ParachutesActive?
                       "Landing on parachutes..." : "Emergency Landing...");
                set_destination_vector();
                CFG.BR.Off();
                var not_too_hot = VSL.vessel.externalTemperature < VSL.Physics.MinMaxTemperature;
                if (not_too_hot)
                {
                    setup_for_deceleration();
                }

                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else if (VSL.Info.Countdown > 0.5f)
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel for powered landing.\nWill deceletate as much as possible before impact.");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    if (vessel_within_range || vessel_after_target ||
                        trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                    {
                        VSL.OnPlanetParams.ActivateParachutesASAP();
                    }
                    else
                    {
                        VSL.OnPlanetParams.ActivateParachutesBeforeUnsafe();
                    }
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        //don't push our luck when it's too hot outside
                        if (not_too_hot)
                        {
                            brake_with_drag();
                        }
                        else
                        {
                            CFG.AT.Off();
                            CFG.StabilizeFlight = false;
                            VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, false);
                        }
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for the right moment to deploy parachutes...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (Body.atmosphere)
                {
                    VSL.BrakesOn();
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere && not_too_hot)
                    {
                        brake_with_drag();
                    }
                    Status("red", "Crash is imminent.\nVertical impact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                CFG.BR.Off();
                THR.Throttle = 0;
                set_destination_vector();
                setup_for_deceleration();
                if (vessel_within_range || vessel_after_target ||
                    trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                {
                    do_aerobraking_if_requested(true);
                }
                var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                if (!Working)
                {
                    correct_landing_site();
                    correct_attitude_with_thrusters(turn_time);
                    VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    //VSL.Engines.OnPlanetTTB(VSL.vessel.srf_velocity, VSL.Physics.Up);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                    Working             = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;        //TODO: is this correct?
                    if (!Working)
                    {
                        if (VSL.Controls.InvAlignmentFactor > 0.5)
                        {
                            Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        else
                        {
                            Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        break;
                    }
                }
                if (Working)
                {
                    ATC.SetThrustDirW(correction_direction());
                    if (!VSL.Controls.HaveControlAuthority)
                    {
                        correct_attitude_with_thrusters(turn_time);
                        if (!VSL.Torque.HavePotentialControlAuthority)
                        {
                            landing_stage = LandingStage.HardLanding;
                        }
                        break;
                    }
                    if (vessel_within_range || VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = -VSL.VerticalSpeed.Absolute;
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (vessel_within_range && VSL.Altitude.Relative > GLB.LND.StopAtH * VSL.Geometry.D ||
                        VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                        Working             = THR.Throttle > 0.7 || VSL.Info.Countdown < 10;
                        Status("white", "Final deceleration. Landing site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        break;
                    }
                }
                THR.Throttle = 0;
                if (LandASAP)
                {
                    landing_stage = LandingStage.LandHere;
                }
                else
                {
                    stop_aerobraking();
                    if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                    {
                        approach();
                    }
                    else
                    {
                        land();
                    }
                }
                break;

            case LandingStage.LandHere:
                Status("lime", "Landing...");
                CFG.BR.Off();
                CFG.BlockThrottle        = true;
                CFG.AltitudeAboveTerrain = true;
                CFG.VF.On(VFlight.AltitudeControl);
                CFG.HF.OnIfNot(HFlight.Stop);
                if (CFG.DesiredAltitude >= 0 && !VSL.HorizontalSpeed.MoovingFast)
                {
                    CFG.DesiredAltitude = 0;
                }
                else
                {
                    CFG.DesiredAltitude = Utils.ClampL(VSL.Altitude.Relative / 2, VSL.Geometry.H * 2);
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }