protected override void correct_steering() { if (BRC != null && BRC.IsActive) { steering = Vector3.ProjectOnPlane(steering, VSL.LocalDir(VSL.Engines.CurrentDefThrustDir)); } }
// ThrottleControl THR; // // OscillationDetector3D OD = new OscillationDetector3D(3, 30, 100, 200, 1); // Timer test_timer = new Timer(1); // static readonly Vector3[] axes = {Vector3.up, Vector3.right}; // Vector3 needed_thrust; // int direction = 1, axis = 0; // float throttle = 0.1f, dThrottle = 0.1f; // float curAAf = 0.1f, dAAf = 0.05f; // enum TestStage {START, TESTING, KILL_ROT, NEXT_AAf, NEXT_THROTTLE, NEXT_AXIS, DONE}; // TestStage stage = TestStage.START; // // void tune_steering_test(Vector3 AAf) // { // VSL.Controls.GimbalLimit = 0;//VSL.OnPlanetParams.TWRf*100; // //tune PID parameters // var angularV = VSL.vessel.angularVelocity; // var angularM = Vector3.Scale(angularV, VSL.Physics.MoI); // var slow = VSL.Engines.Slow? // (Vector3.one+Vector3.Scale(VSL.Torque.EnginesResponseTime, // VSL.Torque.Engines.SpecificTorque)*ATCB.SlowTorqueF) // .ClampComponentsH(ATCB.MaxSlowF) : Vector3.one; // var slowi = slow.Inverse(); // var iErr = (Vector3.one-angle_error); // var PIf = AAf.ScaleChain(iErr.ClampComponentsL(1/ATCB.MaxEf)*ATCB.MaxEf, slowi); //// var AA_clamped = AA.ClampComponentsH(ATCB.MaxAA); // steering_pid.P = Vector3.Scale(ATCB.PID.P, PIf); // steering_pid.I = Vector3.Scale(ATCB.PID.I, PIf); // steering_pid.D = ATCB.PID.D.ScaleChain((iErr //// + (Vector3.one-AA_clamped/ATCB.MaxAA) // + angularM.AbsComponents()*ATCB.AngularMf // ).ClampComponentsH(1), // // AAf, slow,slow).ClampComponentsL(0); // //add inertia to handle constantly changing needed direction // var inertia = angularM.Sign() // .ScaleChain(iErr, // angularM, angularM, // Vector3.Scale(VSL.Torque.MaxCurrent.Torque, VSL.Physics.MoI).Inverse(0)) // .ClampComponents(-Mathf.PI, Mathf.PI) // /Mathf.Lerp(ATCB.InertiaFactor, 1, VSL.Physics.MoI.magnitude*ATCB.MoIFactor); // steering += inertia; // //update PID // steering_pid.Update(steering, angularV); // steering = Vector3.Scale(steering_pid.Action, slowi); // //postprocessing by derived classes // correct_steering(); // } // // // protected override void OnAutopilotUpdate(FlightCtrlState s) // { // if(!(CFG.Enabled && stage != TestStage.DONE && VSL.refT != null && VSL.orbit != null)) return; // if(VSL.AutopilotDisabled) { reset(); return; } // lthrust = VSL.LocalDir(VSL.Engines.CurrentDefThrustDir).normalized; // if(VSL.IsActiveVessel) // TCAGui.DebugMessage = Utils.Format("stage: {}, axis: {}\ntimer: {}\ncur AAf {}, throttle {}\n", // stage, axis, test_timer, curAAf, throttle); // switch(stage) // { // case TestStage.START: // CheatOptions.InfinitePropellant = true; // CheatOptions.InfiniteElectricity = true; // CheatOptions.IgnoreMaxTemperature = true; // VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.RCS, true); // Debug.ClearDeveloperConsole(); // needed_thrust = VSL.WorldDir(Quaternion.AngleAxis(120*direction, axes[axis])*lthrust); // OD.Reset(); // test_timer.Reset(); // direction = -direction; // stage = TestStage.TESTING; // break; // case TestStage.KILL_ROT: // THR.Throttle = 0; // CFG.AT.Off(); // VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, true); // if(VSL.vessel.angularVelocity.sqrMagnitude > 1e-4) break; // VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, false); // stage = TestStage.START; // break; // case TestStage.TESTING: // CFG.AT.OnIfNot(Attitude.Custom); // THR.Throttle = throttle; // needed_lthrust = VSL.LocalDir(needed_thrust); // compute_steering(lthrust, needed_lthrust); // tune_steering_test(Vector3.one*curAAf); // VSL.Controls.AddSteering(steering); // //detect oscillations // OD.Update(steering, TimeWarp.fixedDeltaTime); // if(VSL.IsActiveVessel) // TCAGui.DebugMessage += // string.Format("pid: {0}\nsteering: {1}%\ngimbal limit: {2}\nOD: {3}", // steering_pid, steering_pid.Action*100, VSL.Controls.GimbalLimit, OD.Value); // // if(OD.Value.x > 0.1 || // OD.Value.y > 0.1 || // OD.Value.z > 0.1) // stage = TestStage.NEXT_THROTTLE; // else if(VSL.Controls.AttitudeError < 1) // stage = TestStage.NEXT_AAf; // break; // case TestStage.NEXT_AAf: // curAAf += dAAf; // stage = curAAf > 5+dAAf/2 ? TestStage.NEXT_THROTTLE : TestStage.KILL_ROT; // break; // case TestStage.NEXT_THROTTLE: // CSV(axes[axis] == Vector3.up? 0 : 1, throttle, AA, OD.Value, steering_pid.D, curAAf-dAAf); // curAAf = 0.1f; // throttle += dThrottle; // if(throttle > 1 && throttle < 1+dThrottle/2) // throttle = 1; // stage = throttle > 1 ? TestStage.NEXT_AXIS : TestStage.KILL_ROT; // break; // case TestStage.NEXT_AXIS: // throttle = 0.1f; // axis += 1; // stage = axis < axes.Length ? TestStage.KILL_ROT : TestStage.DONE; // break; // } // } public void DrawDebugLines() { if (!CFG.AT || VSL == null || VSL.vessel == null || VSL.refT == null) { return; } // Utils.GLVec(VSL.refT.position, VSL.OnPlanetParams.Heading.normalized*2500, Color.white); Utils.GLVec(VSL.refT.position, VSL.WorldDir(lthrust.normalized) * 20, Color.yellow); Utils.GLVec(VSL.refT.position, VSL.WorldDir(needed_lthrust.normalized) * 20, Color.red); Utils.GLVec(VSL.refT.position, VSL.WorldDir(VSL.vessel.angularVelocity * 20), Color.cyan); Utils.GLVec(VSL.refT.position, VSL.WorldDir(new Vector3(pid_pitch.atPID.Action * rotation_axis.x, pid_roll.atPID.Action * rotation_axis.y, pid_yaw.atPID.Action * rotation_axis.z) * 20), Color.green); // Utils.GLVec(VSL.refT.position, VSL.WorldDir(steering*20), Color.cyan); // Utils.GLVec(VSL.refT.position, VSL.WorldDir(steering_pid.Action*20), Color.magenta); // Utils.GLVec(VSL.refT.position, VSL.refT.right*2, Color.red); // Utils.GLVec(VSL.refT.position, VSL.refT.forward*2, Color.blue); // Utils.GLVec(VSL.refT.position, VSL.refT.up*2, Color.green); // if(VSL.Target != null) // Utils.GLDrawPoint(VSL.Target.GetTransform().position, Color.red, 5); // // VSL.Engines.All.ForEach(e => // { // Utils.GLVec(e.wThrustPos, e.wThrustDir*2, Color.red); // Utils.GLVec(e.wThrustPos, e.defThrustDir*2, Color.yellow); // }); }
public void ControlCallback(Multiplexer.Command cmd) { translation_pid.Reset(); switch (cmd) { case Multiplexer.Command.Resume: RegisterTo <SASBlocker>(); NeedRadarWhenMooving(); break; case Multiplexer.Command.On: VSL.UpdateOnPlanetStats(); if (CFG.HF[HFlight.Stop]) { VSL.HorizontalSpeed.SetNeeded(Vector3d.zero); CFG.Nav.Off(); //any kind of navigation conflicts with the Stop program; obviously. } else if (CFG.HF[HFlight.NoseOnCourse]) { CFG.BR.OnIfNot(BearingMode.Auto); } CFG.AT.OnIfNot(Attitude.Custom); goto case Multiplexer.Command.Resume; case Multiplexer.Command.Off: UnregisterFrom <SASBlocker>(); UnregisterFrom <Radar>(); CFG.AT.OffIfOn(Attitude.Custom); CFG.BR.OffIfOn(BearingMode.Auto); EnableManualTranslation(false); break; } }
public void ActivateEnginesAndRun(Callback action) { if (NoActiveEngines) { if (CFG.AutoStage) { if (HaveNextStageEngines) { VSL.ActivateNextStageImmidiate(); VSL.TCA.StartCoroutine(CallbackUtil.WaitUntil(() => !NoActiveEngines, action)); } else { Utils.Message("No engines left to activate"); } } else { Utils.Message("Automatic staging is disabled"); } } else { action(); } }
public void CruiseControlCallback(Multiplexer.Command cmd) { UpdateTimer.Reset(); switch (cmd) { case Multiplexer.Command.Resume: RegisterTo <SASBlocker>(); NeedCPSWhenMooving(); break; case Multiplexer.Command.On: VSL.UpdateOnPlanetStats(); var nV = VSL.HorizontalSpeed.Absolute; if (nV > PointNavigator.C.MaxSpeed) { nV = PointNavigator.C.MaxSpeed; } var nVdir = nV > C.MaxIdleSpeed? (Vector3)VSL.HorizontalSpeed.Vector.normalized : VSL.OnPlanetParams.Fwd; CFG.BR.OnIfNot(BearingMode.User); BRC.UpdateBearing((float)VSL.Physics.Bearing(nVdir)); VSL.HorizontalSpeed.SetNeeded(nVdir * nV); CFG.MaxNavSpeed = needed_velocity = nV; goto case Multiplexer.Command.Resume; case Multiplexer.Command.Off: VSL.HorizontalSpeed.SetNeeded(Vector3d.zero); UnregisterFrom <SASBlocker>(); ReleaseCPS(); CFG.BR.OffIfOn(BearingMode.User); break; } }
public override void Init() { base.Init(); Dtol = LTRJ.Dtol; CorrectionTimer.Period = LTRJ.CorrectionTimer; StageTimer.action = () => { VSL.ActivateNextStage(); Message("Have to drop ballast to decelerate..."); }; dP_up_timer.action = () => { dP_threshold = Utils.ClampL(dP_threshold * 0.9, LTRJ.MinDPressure); last_dP = VSL.vessel.dynamicPressurekPa; }; dP_down_timer.action = () => { dP_threshold = Utils.ClampH(dP_threshold * 1.1, LTRJ.MaxDPressure); last_dP = VSL.vessel.dynamicPressurekPa; }; NoEnginesTimer.action = () => { landing_stage = LandingStage.HardLanding; }; sim = new AtmoSim(VSL); Executor = new ManeuverExecutor(TCA); scanner = new PQS_Scanner(VSL); scanner.MaxUnevennes = GLB.LND.MaxUnevenness / 3; dP_threshold = LTRJ.MaxDPressure; last_Err = 0; last_dP = 0; Working = false; }
public void Add(EngineWrapper e) { Engines.Add(e); MaxThrust = MaxThrust + VSL.LocalDir(e.defThrustDir) * e.engine.maxThrust; MaxMassFlow = MaxMassFlow + e.engine.maxFuelFlow; Dir = MaxThrust.normalized; }
public EngineCluster BestForManeuver(Vector3 dV) { var dVm = dV.magnitude; var loc_dV = -VSL.LocalDir(dV); var min_score = float.MaxValue; EngineCluster best = null; for (int j = 0, clustersCount = clusters.Count; j < clustersCount; j++) { var c = clusters[j]; var score = VSL.Torque.NoEngines.RotationTime2Phase(Utils.Angle2(loc_dV, c.Dir), 1); var thrust = c.MaxThrust.magnitude; var ttb = VSL.Engines.TTB(dVm, thrust, (float)c.MaxMassFlow, 1); if (VSL.Info.Countdown > 0 && score + ttb / 2 > VSL.Info.Countdown) { continue; } if (ttb < ManeuverAutopilot.C.ClosestCluster) { ttb = 0; } score += ttb; var fuel = VSL.Engines.FuelNeeded(dVm, (float)(thrust / c.MaxMassFlow)); if (fuel / VSL.Physics.M > ManeuverAutopilot.C.EfficientCluster) { score += fuel * ManeuverAutopilot.C.EfficiencyWeight; } if (score < min_score) { min_score = score; best = c; } } return(best ?? Closest(loc_dV)); }
public void OnPostAutopilotUpdate(FlightCtrlState s) { if (!Valid || !CFG.Enabled) { return; } //handle engines VSL.PostUpdateState(s); VSL.Engines.Tune(); if (VSL.Engines.NumActive > 0) { //:preset manual limits for translation if needed if (VSL.Controls.ManualTranslationSwitch.On) { ENG.PresetLimitsForTranslation(VSL.Engines.Active.Manual, VSL.Controls.ManualTranslation); if (CFG.VSCIsActive) { ENG.LimitInDirection(VSL.Engines.Active.Manual, VSL.Physics.UpL); } } //:optimize limits for steering ENG.PresetLimitsForTranslation(VSL.Engines.Active.Maneuver, VSL.Controls.Translation); ENG.Steer(); } RCS.Steer(); VSL.Engines.SetControls(); VSL.FinalUpdate(); }
void start_to(WayPoint wp) { VSL.UpdateOnPlanetStats(); wp.Update(VSL); if (CFG.Nav[Navigation.GoToTarget] && wp.CloseEnough(VSL)) { CFG.Nav.Off(); return; } if (VSL.LandedOrSplashed) { CFG.AltitudeAboveTerrain = true; CFG.VF.OnIfNot(VFlight.AltitudeControl); CFG.DesiredAltitude = PN.TakeoffAltitude + VSL.Geometry.H; } else if (CFG.VTOLAssistON) { VSL.GearOn(false); } reset_formation(); SetTarget(wp); DistancePID.Reset(); LateralPID.Reset(); CFG.HF.OnIfNot(HFlight.NoseOnCourse); RegisterTo <Radar>(); }
public void TargetUI() { if (SelectingTarget) { SelectingTarget &= !GUILayout.Button("Cancel", Styles.close_button, GUILayout.ExpandWidth(true)); } else if (CFG.Target != null) { if (VSL.TargetUsers.Count > 0) { GUILayout.Label(new GUIContent("Del Target", "Target point is in use"), Styles.grey_button, GUILayout.ExpandWidth(true)); } else if (GUILayout.Button(new GUIContent("Del Target", "Remove target point"), Styles.danger_button, GUILayout.ExpandWidth(true))) { VSL.SetTarget(null); } } else if (GUILayout.Button(new GUIContent("Set Surface Target", "Select target point on the surface"), Styles.active_button, GUILayout.ExpandWidth(true))) { select_single = true; SelectingTarget = true; CFG.GUIVisible = true; CFG.ShowPath = true; MapView.EnterMapView(); } }
public void OnPostAutopilotUpdate(FlightCtrlState s) { if (!Valid || !CFG.Enabled) { return; } //handle engines VSL.PostUpdateState(s); VSL.Engines.Tune(); if (VSL.Engines.NumActive > 0) { //:preset manual limits for translation if needed var translation = VSL.Controls.EnginesTranslation; if (VSL.Controls.HasTranslation) { translation += VSL.Controls.Translation; } if (!translation.IsZero()) { EngineOptimizer.PresetLimitsForTranslation(VSL.Engines.Active.Maneuver, translation.normalized); if (CFG.VSCIsActive && !VSL.Controls.HasTranslation) { EngineOptimizer.LimitInDirection(VSL.Engines.Active.Maneuver, VSL.Physics.UpL); } } ENG.Steer(); } RCS.Steer(); VSL.Engines.SetControls(); VSL.FinalUpdate(); }
public bool ActivateInactiveEngines() { if (CFG.AutoStage && NoActiveEngines && HaveNextStageEngines) { VSL.ActivateNextStage(); return(true); } return(false); }
public void OnReloadGlobals() { AllModules.ForEach(m => m.Reset()); VSL.Reset(); VSL.Init(); AllModules.ForEach(m => m.Init()); VSL.ConnectAutopilotOutput(); }
public void FixedUpdate() { if (VSL == null) { return; } //initialize systems VSL.UpdateState(); State = TCAState.Disabled; if (!CFG.Enabled) { return; } State = TCAState.Enabled; if (!VSL.Info.ElectricChargeAvailible) { return; } SetState(TCAState.HaveEC); ClearFrameState(); //update VSL VSL.UpdatePhysics(); if (VSL.Engines.Check()) { SetState(TCAState.HaveActiveEngines); } Actions["onActionUpdate"].actionGroup = VSL.Engines.ActionGroups; VSL.UpdateCommons(); VSL.UpdateOnPlanetStats(); //update modules ModulePipeline.ForEach(m => m.OnFixedUpdate()); //handle engines VSL.Engines.Tune(); if (VSL.Engines.NumActive > 0) { //:preset manual limits for translation if needed if (VSL.Controls.ManualTranslationSwitch.On) { ENG.PresetLimitsForTranslation(VSL.Engines.Manual, VSL.Controls.ManualTranslation); if (CFG.VSCIsActive) { ENG.LimitInDirection(VSL.Engines.Manual, VSL.Physics.UpL); } } //:balance-only engines if (VSL.Engines.Balanced.Count > 0) { VSL.Torque.UpdateImbalance(VSL.Engines.Manual, VSL.Engines.UnBalanced); ENG.OptimizeLimitsForTorque(VSL.Engines.Balanced, Vector3.zero); } VSL.Torque.UpdateImbalance(VSL.Engines.Manual, VSL.Engines.UnBalanced, VSL.Engines.Balanced); //:optimize limits for steering ENG.PresetLimitsForTranslation(VSL.Engines.Maneuver, VSL.Controls.Translation); ENG.Steer(); } RCS.Steer(); VSL.Engines.SetControls(); }
IEnumerator <YieldInstruction> activeProfileUpdate() { ProfileSyncAllowed = false; yield return(new WaitForSeconds(0.5f)); VSL.UpdateParts(); CFG.ActiveProfile.Update(VSL.Engines.All, true); ProfileSyncAllowed = true; }
public ToOrbitExecutor(ModuleTCA tca) : base(tca) { InitModuleFields(); Executor = new ManeuverExecutor(tca); GearAction.action = () => VSL.GearOn(false); ErrorThreshold.Lower = 2 * GLB.ORB.Dtol; ErrorThreshold.Upper = 4 * GLB.ORB.Dtol; GravityTurnStart = 0; }
public void UpdateAeroForces() { var lift = Vector3.zero; var drag = Vector3.zero; var torque = Vector3.zero; if (VSL.vessel.dynamicPressurekPa > 0) { for (int i = 0, VSLvesselPartsCount = VSL.vessel.Parts.Count; i < VSLvesselPartsCount; i++) { var p = VSL.vessel.Parts[i]; var r = p.Rigidbody.worldCenterOfMass - VSL.Physics.wCoM; var d = -p.dragVectorDir * p.dragScalar; torque += Vector3.Cross(r, d); drag += d; if (!p.hasLiftModule) { var lift_mod = p.transform.rotation * (p.bodyLiftScalar * p.DragCubes.LiftForce); torque += Vector3.Cross(r, lift_mod); lift += lift_mod; } var lift_srf = p.Modules.GetModules <ModuleLiftingSurface>(); if (lift_srf.Count > 0) { var srf_lift = Vector3.zero; var srf_drag = Vector3.zero; lift_srf.ForEach(m => { srf_lift += m.liftForce; srf_drag += m.dragForce; }); torque += Vector3.Cross(r, srf_lift + srf_drag); lift += srf_lift; drag += srf_drag; } } } Lift = lift; Drag = drag; AeroForce = Lift + Drag; var relAeroForce = AeroForce / (float)Utils.ClampL(VSL.vessel.dynamicPressurekPa, 1); if (relAeroForce.sqrMagnitude > MaxAeroForceL.sqrMagnitude) { MaxAeroForceL = VSL.LocalDir(relAeroForce); } vLift = Vector3.Dot(AeroForce, VSL.Physics.Up); AeroTorque = torque; AeroTorqueL = VSL.LocalDir(VSL.OnPlanetParams.AeroTorque); var aeroTorqueL = AeroTorqueL.AbsComponents(); AeroTorqueRatio = Vector3.Scale( aeroTorqueL, (VSL.Torque.NoEngines.Torque + VSL.Torque.EnginesFinal.Torque).Inverse()) .MaxComponentF(); MaxAeroTorqueRatio = Vector3.Scale( aeroTorqueL, VSL.Torque.MaxCurrent.Torque.Inverse()) .MaxComponentF(); }
public virtual void AttachTCA(ModuleTCA tca) { if (TCA == null) { TCA = tca; InitModuleFields(); GearAction.action = () => VSL.GearOn(false); TimeToApA.Value = Mathf.Max(TimeToApA, VSL.Torque.MaxCurrent.TurnTime); } }
public void ToggleTCA(KSPActionParam param = null) { CFG.Enabled = !CFG.Enabled; if (CFG.Enabled) { CFG.ActiveProfile.Update(VSL.Engines.All, true); } AllModules.ForEach(m => m.OnEnableTCA(CFG.Enabled)); VSL.OnEnableTCA(CFG.Enabled); }
public bool Execute(Vector3d dV, float MinDeltaV = 0.1f, ManeuverCondition condition = null) { THR.Throttle = 0; dVrem.Value = dV.magnitude; //end if below the minimum dV if (dVrem < MinDeltaV) { return(false); } VSL.Engines.ActivateEngines(); //test: flameouted engines are automatically excluded from Active, //so this should work without this check; but this needs to be tested //in-game anyway with: MAN, REN, DEO // if(VSL.Engines.MaxThrustM.Equals(0)) // return VSL.Engines.HaveNextStageEngines; //orient along the burning vector if (dVrem && VSL.Controls.RCSAvailableInDirection(-dV)) { CFG.AT.OnIfNot(Attitude.KillRotation); } else { CFG.AT.OnIfNot(Attitude.Custom); ATC.SetThrustDirW(-dV); VSL.Engines.RequestClusterActivationForManeuver(-dV); } //check the condition if (condition != null && !condition((float)dVrem)) { return(true); } if (VSL.Controls.TranslationAvailable) { if (dVrem || VSL.Controls.AttitudeError > GLB.ATCB.AttitudeErrorThreshold) { TRA.AddDeltaV(-VSL.LocalDir(dV)); } if (dVrem && CFG.AT[Attitude.KillRotation]) { var errorF = Utils.ClampL(Vector3.Dot(VSL.Engines.Thrust.normalized, -dV.normalized), 0); THR.DeltaV = (float)dVrem * errorF * errorF; } else { THR.DeltaV = (float)dVrem; } } else { THR.DeltaV = (float)dVrem; } // Log("\ndVrem: {}\nAttitudeError {}, DeltaV: {}, Throttle {}, RCS {}", // dVrem, VSL.Controls.AttitudeError, THR.DeltaV, THR.Throttle, VSL.Controls.RCSAvailableInDirection(-dV));//debug return(true); }
void stop_aerobraking() { if (UseBrakes) { VSL.BrakesOn(false); } if (UseChutes && VSL.OnPlanetParams.ParachutesActive) { VSL.OnPlanetParams.CutActiveParachutes(); } }
public void DrawDebugLines() { if (VSL == null || VSL.vessel == null || VSL.refT == null || !CFG.HF) { return; } Utils.GLVec(VSL.refT.position, VSL.HorizontalSpeed.NeededVector, Color.yellow); Utils.GLVec(VSL.refT.position, VSL.WorldDir(manual_thrust), Color.magenta); Utils.GLVec(VSL.refT.position + VSL.Physics.Up * VSL.Geometry.H, VSL.HorizontalSpeed.Vector, Color.red); Utils.GLVec(VSL.refT.position + VSL.Physics.Up * VSL.Geometry.H * 1.1, CourseCorrection, Color.green); }
void reset() { if (VSL != null) { VSL.Reset(); AllModules.ForEach(m => m.Reset()); CFG.ClearCallbacks(); } DeleteModules(); VSL = null; }
void ClearFrameState() { VSL.ClearFrameState(); AllModules.ForEach(m => m.ClearFrameState()); #if DEBUG if (VSL.IsActiveVessel) { TCAGui.ClearDebugMessage(); } #endif }
public void Add(params EngineWrapper[] engines) { for (int i = 0, len = engines.Length; i < len; i++) { var e = engines[i]; Engines.Add(e); MaxThrust = MaxThrust + VSL.LocalDir(e.defThrustDir) * e.engine.maxThrust; MaxMassFlow = MaxMassFlow + e.engine.maxFuelFlow; } Dir = MaxThrust.normalized; }
public bool Execute(Vector3d dV, float MinDeltaV = 0.1f, ManeuverCondition condition = null) { THR.Throttle = 0; dVrem.Value = dV.magnitude; //end if below the minimum dV if (dVrem < MinDeltaV) { return(false); } VSL.Engines.ActivateEngines(); if (VSL.Engines.MaxThrustM.Equals(0)) { return(true); } //orient along the burning vector if (dVrem && VSL.Controls.RCSAvailableInDirection(-dV)) { CFG.AT.OnIfNot(Attitude.KillRotation); } else { CFG.AT.OnIfNot(Attitude.Custom); ATC.SetThrustDirW(-dV); } //check the condition if (condition != null && !condition((float)dVrem)) { return(true); } if (VSL.Controls.TranslationAvailable) { if (dVrem || VSL.Controls.AttitudeError > GLB.ATCB.AttitudeErrorThreshold) { TRA.AddDeltaV(-VSL.LocalDir(dV)); } if (dVrem && CFG.AT[Attitude.KillRotation]) { var errorF = Utils.ClampL(Vector3.Dot(VSL.Engines.Thrust.normalized, -dV.normalized), 0); THR.DeltaV = (float)dVrem * errorF * errorF; } else { THR.DeltaV = (float)dVrem; } } else { THR.DeltaV = (float)dVrem; } // Log("\ndVrem: {}\nAttitudeError {}, DeltaV: {}, Throttle {}, RCS {}", // dVrem, VSL.Controls.AttitudeError, THR.DeltaV, THR.Throttle, VSL.Controls.RCSAvailableInDirection(-dV));//debug return(true); }
protected override void DrawContent() { #if DEBUG ATC.DrawDebugLines(); Utils.GLVec(VSL.refT.position, VSL.WorldDir(VSL.OnPlanetParams.MaxAeroForceL) * 10, Color.magenta); #endif if (GUILayout.Button(new GUIContent("T-SAS", "Push to toggle attitude controls"), CFG.AT && !VSL.AutopilotDisabled? Styles.cyan : Styles.white, GUILayout.ExpandWidth(false))) { cues.Toggle(); } }
protected override void OnAutopilotUpdate(FlightCtrlState s) { //need to check all the prerequisites, because the callback is called asynchroniously if (!(CFG.Enabled && IsActive && VSL.refT != null)) { DirectionOverride = Vector3d.zero; return; } //allow user to intervene if (VSL.HasUserInput) { if (!s.yaw.Equals(0)) { UpdateBearing(Bearing.Value + s.yaw * BRC.YawFactor * CFG.ControlSensitivity); if (CFG.HF[HFlight.CruiseControl] && !VSL.HorizontalSpeed.NeededVector.IsZero()) { VSL.HorizontalSpeed.SetNeeded(ForwardDirection * CFG.MaxNavSpeed); } draw_forward_direction = BRC.DrawForwardDirection; VSL.HasUserInput = !(s.pitch.Equals(0) && s.roll.Equals(0)); VSL.AutopilotDisabled = VSL.HasUserInput; DirectionLineTimer.Reset(); bearing_pid.Reset(); s.yaw = 0; } } if (VSL.AutopilotDisabled) { DirectionOverride = Vector3d.zero; return; } //turn ship's nose in the direction of needed velocity var axis = up_axis; var laxis = VSL.LocalDir(axis); var cDir = H(VSL.OnPlanetParams.Fwd); var nDir = DirectionOverride.IsZero()? H(ForwardDirection) : H(DirectionOverride); var angle = Vector3.Angle(cDir, nDir) * Mathf.Sign(Vector3.Dot(Vector3.Cross(nDir, cDir), axis)); var eff = Mathf.Abs(Vector3.Dot(VSL.Engines.CurrentMaxThrustDir.normalized, VSL.Physics.Up)); var ADf = (float)VSL.vessel.staticPressurekPa / VSL.Torque.MaxCurrent.AngularDragResistanceAroundAxis(laxis) * BRC.ADf + 1; AAf = Utils.Clamp(1 / VSL.Torque.MaxCurrent.AngularAccelerationAroundAxis(laxis) / ADf, BRC.MinAAf, BRC.MaxAAf); bearing_pid.P = BRC.DirectionPID.P; bearing_pid.D = BRC.DirectionPID.D * AAf; bearing_pid.Update(angle * eff, Vector3.Dot(VSL.vessel.angularVelocity, laxis) * Mathf.Rad2Deg); steering = rotation2steering(world2local_rotation(Quaternion.AngleAxis(bearing_pid.Action, axis))); VSL.Controls.AddSteering(steering); // if(VSL.IsActiveVessel) // TCAGui.DebugMessage = // Utils.Format("angle {}deg, action {}deg, action*eff {}deg\n" + // "AAf {}, ADf {}, result {}", // angle, bearing_pid.Action, bearing_pid.Action*eff, // 1/VSL.Torque.MaxCurrent.AngularAccelerationAroundAxis(laxis), ADf, AAf);//debug DirectionOverride = Vector3d.zero; }
protected virtual void CreateTarget(System.Random RND) { Coordinates c = null; while (c == null || c.OnWater) { c = Coordinates.SurfacePoint(RND.NextDouble() * latSpread - latSpread / 2, RND.NextDouble() * 360, VSL.Body); c.SetAlt2Surface(VSL.Body); } VSL.SetTarget(MOD, new WayPoint(c)); }