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); }
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 }
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); }
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 }
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); }