void DriveCircularizationBurn(FlightCtrlState s) { if (!vessel.patchedConicsUnlocked() || skipCircularization) { this.users.Clear(); return; } DriveDeployableComponents(s); if (placedCircularizeNode) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>(); if (recorder != null) { launchPhaseAngle = recorder.phaseAngleFromMark; } if (recorder != null) { launchLANDifference = vesselState.orbitLAN - recorder.markLAN; } //finished circularize this.users.Clear(); return; } } else { //place circularization node vessel.RemoveAllManeuverNodes(); double UT = orbit.NextApoapsisTime(vesselState.time); //During the circularization burn, try to correct any inclination errors because it's better to combine the two burns. // For example, if you're about to do a 1500 m/s circularization burn, if you combine a 200 m/s inclination correction // into it, you actually only spend 1513 m/s to execute combined manuver. Mechjeb should also do correction burns before // this if possible, and this can't correct all errors... but it's better then nothing. // (A better version of this should try to match inclination & LAN if target is specified) // FIXME? this inclination correction is unlikely to be at tha AN/DN and will throw the LAN off with anything other than high // TWR launches from equatorial launch sites -- should probably be made optional (or clip it if the correction is too large). Vector3d inclinationCorrection = OrbitalManeuverCalculator.DeltaVToChangeInclination(orbit, UT, Math.Abs(desiredInclination)); Vector3d smaCorrection = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit.PerturbedOrbit(UT, inclinationCorrection), UT, desiredOrbitAltitude + mainBody.Radius); Vector3d dV = inclinationCorrection + smaCorrection; vessel.PlaceManeuverNode(orbit, dV, UT); placedCircularizeNode = true; core.node.ExecuteOneNode(this); } if (core.node.burnTriggered) { status = Localizer.Format("#MechJeb_Ascent_status7"); //"Circularizing" } else { status = Localizer.Format("#MechJeb_Ascent_status8"); //"Coasting to circularization burn" } }
public override void OnStart(PartModule.StartState state) { autopilot = core.GetComputerModule <MechJebModuleAscentAutopilot>(); if (autopilot != null) { desiredInclination = autopilot.desiredInclination; } }
public override void OnStart(PartModule.StartState state) { if (autopilot != null) { desiredInclination = autopilot.desiredInclination; // FIXME: remove this indirection } navBall = core.GetComputerModule <MechJebModuleAscentNavBall>(); }
public override void OnStart(PartModule.StartState state) { autopilot = core.GetComputerModule<MechJebModuleAscentAutopilot>(); if (autopilot != null) { autopilot.users.Add(this); desiredInclination = autopilot.desiredInclination; } }
public override void OnStart(PartModule.StartState state) { autopilot = core.GetComputerModule<MechJebModuleAscentAutopilot>(); if (autopilot != null) { desiredInclination = autopilot.desiredInclination; } navBall = core.GetComputerModule<MechJebModuleAscentNavBall>(); }
void DriveCircularizationBurn(FlightCtrlState s) { if (!vessel.patchedConicsUnlocked() || skipCircularization) { this.users.Clear(); return; } if (placedCircularizeNode) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>(); if (recorder != null) { launchPhaseAngle = recorder.phaseAngleFromMark; } if (recorder != null) { launchLANDifference = vesselState.orbitLAN - recorder.markLAN; } //finished circularize this.users.Clear(); return; } } else { //place circularization node vessel.RemoveAllManeuverNodes(); double UT = orbit.NextApoapsisTime(vesselState.time); //During the circularization burn, try to correct any inclination errors because it's better to combine the two burns. // For example, if you're about to do a 1500 m/s circularization burn, if you combine a 200 m/s inclination correction // into it, you actually only spend 1513 m/s to execute combined manuver. Mechjeb should also do correction burns before // this if possible, and this can't correct all errors... but it's better then nothing. // (A better version of this should try to match inclination & LAN if target is specified) Vector3d inclinationCorrection = OrbitalManeuverCalculator.DeltaVToChangeInclination(orbit, UT, desiredInclination); Vector3d smaCorrection = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit.PerturbedOrbit(UT, inclinationCorrection), UT, desiredOrbitAltitude + mainBody.Radius); Vector3d dV = inclinationCorrection + smaCorrection; vessel.PlaceManeuverNode(orbit, dV, UT); placedCircularizeNode = true; core.node.ExecuteOneNode(this); } if (core.node.burnTriggered) { status = "Circularizing"; } else { status = "Coasting to circularization burn"; } }
public override void OnStart(PartModule.StartState state) { Tf = new EditableDouble(core.attitude.Tf); TfMin = new EditableDouble(core.attitude.TfMin); TfMax = new EditableDouble(core.attitude.TfMax); kpFactor = new EditableDouble(core.attitude.kpFactor); kiFactor = new EditableDouble(core.attitude.kiFactor); kdFactor = new EditableDouble(core.attitude.kdFactor); base.OnStart(state); }
public override void OnStart(PartModule.StartState state) { Kp = new EditableDouble(core.attitude.Kp); Ki = new EditableDouble(core.attitude.Ki); Kd = new EditableDouble(core.attitude.Kd); Tf = new EditableDouble(core.attitude.Tf); Ki_limit = new EditableDouble(core.attitude.Ki_limit); factor = new EditableDouble(core.attitude.drive_factor); base.OnStart(state); }
public void setPIDParameters() { if (Tf < 2 * TimeWarp.fixedDeltaTime) { Tf = 2 * TimeWarp.fixedDeltaTime; } pid.Kd = 0.53 / Tf; pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf); pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf); }
public EditableAngle(double angle) { angle = MuUtils.ClampDegrees180(angle); negative = (angle < 0); angle = Math.Abs(angle); degrees = (int)angle; angle -= degrees; minutes = (int)(60 * angle); angle -= minutes / 60; seconds = Math.Round(3600 * angle); }
public override void OnStart(PartModule.StartState state) { TfX = new EditableDouble(core.attitude.TfV.x); TfY = new EditableDouble(core.attitude.TfV.y); TfZ = new EditableDouble(core.attitude.TfV.z); TfMin = new EditableDouble(core.attitude.TfMin); TfMax = new EditableDouble(core.attitude.TfMax); kpFactor = new EditableDouble(core.attitude.kpFactor); kiFactor = new EditableDouble(core.attitude.kiFactor); kdFactor = new EditableDouble(core.attitude.kdFactor); deadband = new EditableDouble(core.attitude.deadband); base.OnStart(state); }
override public void readModuleConfiguration() { deployGear = module_autopilot.deployGears; deployChutes = module_autopilot.deployChutes; limitChutesStage = module_autopilot.limitChutesStage; touchdownSpeed = module_autopilot.touchdownSpeed; if (core.target.PositionTargetExists) { landTarget = true; targetLattitude = core.target.targetLatitude; targetLongitude = core.target.targetLongitude; } }
void DriveCircularizationBurn(FlightCtrlState s) { if (!vessel.patchedConicsUnlocked() || skipCircularization) { this.users.Clear(); return; } if (placedCircularizeNode) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>(); if (recorder != null) { launchPhaseAngle = recorder.phaseAngleFromMark; } if (recorder != null) { launchLANDifference = vesselState.orbitLAN - recorder.markLAN; } //finished circularize this.users.Clear(); return; } } else { //place circularization node vessel.RemoveAllManeuverNodes(); double UT = orbit.NextApoapsisTime(vesselState.time); //Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); Vector3d dV = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit, UT, desiredOrbitAltitude + mainBody.Radius); vessel.PlaceManeuverNode(orbit, dV, UT); placedCircularizeNode = true; core.node.ExecuteOneNode(this); } if (core.node.burnTriggered) { status = "Circularizing"; } else { status = "Coasting to circularization burn"; } }
override public void activateAction() { base.activateAction(); this.smartAss.mode = Target2Mode[(int)target]; this.smartAss.target = target; this.smartAss.srfHdg = this.srfHdg; this.smartAss.srfPit = this.srfPit; this.smartAss.srfRol = this.srfRol; this.smartAss.srfVelYaw = this.srfVelYaw; this.smartAss.srfVelPit = this.srfVelPit; this.smartAss.srfVelRol = this.srfVelRol; this.smartAss.rol = this.rol; this.smartAss.advReference = this.advReference; this.smartAss.advDirection = this.advDirection; this.smartAss.forceRol = this.forceRol; this.smartAss.forcePitch = this.forcePitch; this.smartAss.forceYaw = this.forceYaw; this.smartAss.Engage(); }
public void setPIDParameters() { if (rcsManualPID) { pid.Kd = Kd; pid.Kp = Kp; pid.Ki = Ki; } else { Tf = Math.Max(Tf, 0.02); pid.Kd = 0.53 / Tf; pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf); pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf); Kd.val = pid.Kd; Kp.val = pid.Kp; Ki.val = pid.Ki; } }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label("No maneuver nodes to edit."); RelativityModeSelectUI(); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) node = vessel.patchedConicSolver.maneuverNodes[0]; int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) gizmo.OnGizmoUpdated -= GizmoUpdateHandler; gizmo = node.attachedGizmo; if (gizmo != null) gizmo.OnGizmoUpdated += GizmoUpdateHandler; } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Prograde:", prograde, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { prograde -= progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { prograde += progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { radialPlus -= radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { radialPlus += radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { normalPlus -= normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { normalPlus += normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Set delta to:", GUILayout.ExpandWidth(true)); if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true))) progradeDelta = radialPlusDelta = normalPlusDelta = 0.01; if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true))) progradeDelta = radialPlusDelta = normalPlusDelta = 0.1; if (GUILayout.Button("1", GUILayout.ExpandWidth(true))) progradeDelta = radialPlusDelta = normalPlusDelta = 1; if (GUILayout.Button("10", GUILayout.ExpandWidth(true))) progradeDelta = radialPlusDelta = normalPlusDelta = 10; if (GUILayout.Button("100", GUILayout.ExpandWidth(true))) progradeDelta = radialPlusDelta = normalPlusDelta = 100; GUILayout.EndHorizontal(); if (GUILayout.Button("Update")) node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); GUILayout.BeginHorizontal(); GUILayout.Label("Shift time", GUILayout.ExpandWidth(true)); if (GUILayout.Button("-o", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT - node.patch.period); } if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT - timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset); } if (GUILayout.Button("+o", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT + node.patch.period); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Snap node to", GUILayout.ExpandWidth(true))) { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(UT - o.period / 2); //period is who-knows-what for e > 1, but this should still work break; case Snap.APOAPSIS: if (o.eccentricity < 1) UT = o.NextApoapsisTime(UT - o.period / 2); break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.TargetOrbit)) UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2); } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.TargetOrbit)) UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2); } break; } node.OnGizmoUpdated(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); RelativityModeSelectUI(); if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled) { if (GUILayout.Button("Execute next node")) { core.node.ExecuteOneNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button("Execute all nodes")) { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button("Abort node execution")) { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp", GUILayout.ExpandWidth(true)); GUILayout.Label("Tolerance:", GUILayout.ExpandWidth(false)); core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; //btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; btGreen = new GUIStyle(btNormal); btGreen.normal.textColor = Color.green; btGreen.fixedWidth = 35; btWhite = new GUIStyle(btNormal); btWhite.normal.textColor = Color.white; btWhite.fixedWidth = 35; btAuto = new GUIStyle(btNormal); btAuto.padding = new RectOffset(8, 8, 8, 8); btAuto.normal.textColor = Color.red; btAuto.onActive = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal; } if (autopilot.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button1"), btActive)) //Disengage autopilot { autopilot.users.Remove(this); } } else if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0) { if (core.attitude.users.Contains(this)) { core.attitude.users.Remove(this); // so we don't suddenly turn on when the other autopilot finishes } GUILayout.Button("Auto", btAuto, GUILayout.ExpandWidth(true)); } else { if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button2"))) //Engage autopilot { autopilot.users.Add(this); } } GUILayout.BeginHorizontal(); bool AltitudeHold = autopilot.AltitudeHoldEnabled; autopilot.AltitudeHoldEnabled = GUILayout.Toggle(autopilot.AltitudeHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label1"), GUILayout.Width(140)); //Altitude Hold if (AltitudeHold != autopilot.AltitudeHoldEnabled) { if (autopilot.AltitudeHoldEnabled) { autopilot.EnableAltitudeHold(); } else { autopilot.DisableAltitudeHold(); } } bool change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { AltitudeTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } AltitudeTargettmp.text = GUILayout.TextField(AltitudeTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { AltitudeTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } if (AltitudeTargettmp < 0) { AltitudeTargettmp = 0; } GUILayout.Label("m", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset1"), autopilot.AltitudeTarget == AltitudeTargettmp ? btWhite : btGreen)) //Set { autopilot.AltitudeTarget = AltitudeTargettmp; } GUILayout.EndHorizontal(); if (!autopilot.AltitudeHoldEnabled) { bool _VertSpeedHoldEnabled = autopilot.VertSpeedHoldEnabled; GUILayout.BeginHorizontal(); autopilot.VertSpeedHoldEnabled = GUILayout.Toggle(autopilot.VertSpeedHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label2"), GUILayout.Width(140)); //Vertical Speed Hold if (_VertSpeedHoldEnabled != autopilot.VertSpeedHoldEnabled) { if (autopilot.VertSpeedHoldEnabled) { autopilot.EnableVertSpeedHold(); } else { autopilot.DisableVertSpeedHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedTargettmp = Math.Max(0, VertSpeedTargettmp); GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset2"), autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen)) { autopilot.VertSpeedTarget = VertSpeedTargettmp; } GUILayout.EndHorizontal(); } else { GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_VS"), GUILayout.Width(140));//" V/S ±" change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedTargettmp = Math.Max(0, VertSpeedTargettmp); GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset6"), autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen)) { autopilot.VertSpeedTarget = VertSpeedTargettmp; } GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); bool _HeadingHoldEnabled = autopilot.HeadingHoldEnabled; autopilot.HeadingHoldEnabled = GUILayout.Toggle(autopilot.HeadingHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label4"), GUILayout.Width(140)); //"Heading Hold" if (_HeadingHoldEnabled != autopilot.HeadingHoldEnabled) { if (autopilot.HeadingHoldEnabled) { autopilot.EnableHeadingHold(); } else { autopilot.DisableHeadingHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { HeadingTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } HeadingTargettmp.text = GUILayout.TextField(HeadingTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { HeadingTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } HeadingTargettmp = MuUtils.ClampDegrees360(HeadingTargettmp); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset4"), autopilot.HeadingTarget == HeadingTargettmp ? btWhite : btGreen)) { autopilot.HeadingTarget = HeadingTargettmp; } GUILayout.EndHorizontal(); if (!autopilot.HeadingHoldEnabled) { GUILayout.BeginHorizontal(); autopilot.RollHoldEnabled = GUILayout.Toggle(autopilot.RollHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label5"), GUILayout.Width(140)); //"Roll Hold" change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { RollTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollTargettmp.text = GUILayout.TextField(RollTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { RollTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollTargettmp = MuUtils.Clamp(RollTargettmp, -90, 90); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset5"), autopilot.RollTarget == RollTargettmp ? btWhite : btGreen)) { autopilot.RollTarget = RollTargettmp; } GUILayout.EndHorizontal(); } else { GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label6"), GUILayout.Width(140)); //" Roll Limit ±" change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { RollMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollMaxtmp.text = GUILayout.TextField(RollMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { RollMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollMaxtmp = MuUtils.Clamp(RollMaxtmp, -60, 60); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset6"), autopilot.BankAngle == RollMaxtmp ? btWhite : btGreen)) { autopilot.BankAngle = RollMaxtmp; } GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); bool _AutoThrustCtrl = autopilot.SpeedHoldEnabled; autopilot.SpeedHoldEnabled = GUILayout.Toggle(autopilot.SpeedHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label7"), GUILayout.Width(140)); //Speed Hold if (autopilot.SpeedHoldEnabled != _AutoThrustCtrl) { if (autopilot.SpeedHoldEnabled) { autopilot.EnableSpeedHold(); } else { autopilot.DisableSpeedHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { SpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } SpeedTargettmp.text = GUILayout.TextField(SpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { SpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } if (SpeedTargettmp < 0) { SpeedTargettmp = 0; } GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset7"), autopilot.SpeedTarget == SpeedTargettmp ? btWhite : btGreen)) //Set { autopilot.SpeedTarget = SpeedTargettmp; } GUILayout.EndHorizontal(); if (!showpid) { if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button3"), GUILayout.Width(40))) //"PID" { showpid = true; } } else { if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button4"), GUILayout.Width(140))) //Hide PID { showpid = false; } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label8"), GUILayout.ExpandWidth(true)); //Accceleration GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.AccKp.text = GUILayout.TextField(autopilot.AccKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.AccKi.text = GUILayout.TextField(autopilot.AccKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.AccKd.text = GUILayout.TextField(autopilot.AccKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.SpeedHoldEnabled) { GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error1", autopilot.a_err.ToString("F2"), autopilot.RealAccelerationTarget.ToString("F2"), autopilot.cur_acc.ToString("F2")), GUILayout.ExpandWidth(false)); //"error:"<<1>>" Target:"<<2>> " Cur:"<<3>> } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Pitch"), GUILayout.ExpandWidth(true));//"VertSpeed" GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.PitKp.text = GUILayout.TextField(autopilot.PitKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.PitKi.text = GUILayout.TextField(autopilot.PitKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.PitKd.text = GUILayout.TextField(autopilot.PitKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.VertSpeedHoldEnabled) { GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.pitch_err.ToString("F2"), autopilot.RealPitchTarget.ToString("F2"), vesselState.currentPitch.ToString("F2"), autopilot.pitch_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:" } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label10"), GUILayout.ExpandWidth(true)); //Roll GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.RolKp.text = GUILayout.TextField(autopilot.RolKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.RolKi.text = GUILayout.TextField(autopilot.RolKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.RolKd.text = GUILayout.TextField(autopilot.RolKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.RollHoldEnabled) { GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.roll_err.ToString("F2"), autopilot.RealRollTarget.ToString("F2"), (-vesselState.currentRoll).ToString("F2"), autopilot.roll_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:" } GUILayout.BeginHorizontal(); GUILayout.Label("Yaw", GUILayout.ExpandWidth(true)); GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.YawKp.text = GUILayout.TextField(autopilot.YawKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.YawKi.text = GUILayout.TextField(autopilot.YawKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.YawKd.text = GUILayout.TextField(autopilot.YawKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.HeadingHoldEnabled) { GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.yaw_err.ToString("F2"), autopilot.RealYawTarget.ToString("F2"), autopilot.curr_yaw.ToString("F2"), autopilot.yaw_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:" } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Limits"), GUILayout.ExpandWidth(false)); //Yaw Control Limit GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_PitchDownLimit"), GUILayout.ExpandWidth(false)); autopilot.PitchDownLimit.text = GUILayout.TextField(autopilot.PitchDownLimit.text, GUILayout.Width(40)); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_PitchUpLimit"), GUILayout.ExpandWidth(false)); autopilot.PitchUpLimit.text = GUILayout.TextField(autopilot.PitchUpLimit.text, GUILayout.Width(40)); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_YawLimit"), GUILayout.ExpandWidth(false)); autopilot.YawLimit.text = GUILayout.TextField(autopilot.YawLimit.text, GUILayout.Width(40)); GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_RollLimit"), GUILayout.ExpandWidth(false)); autopilot.RollLimit.text = GUILayout.TextField(autopilot.RollLimit.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; } GUILayout.BeginVertical(); if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button1")))//Disengage autopilot { autopilot.users.Remove(this); } } else { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button2")))//Engage autopilot { autopilot.users.Add(this); } } if (ascentPathIdx == ascentType.PVG) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button3")))//Reset Guidance (DO NOT PRESS) { core.guidance.Reset(); } GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button4"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //"TARG" { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button5"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button6"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button7"), autopilot.showStatus ? btActive : btNormal, GUILayout.ExpandWidth(true))) //STATUS { autopilot.showStatus = !autopilot.showStatus; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.GRAVITYTURN) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.BREATHING_GT) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.CLASSIC) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button11"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button12"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } if (autopilot.showTargeting) { if (ascentPathIdx == ascentType.PVG) { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label1"), autopilot.desiredOrbitAltitude, "km"); //Target Periapsis GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label2"), pvgascent.desiredApoapsis, "km"); //Target Apoapsis: if (pvgascent.desiredApoapsis >= 0 && pvgascent.desiredApoapsis < autopilot.desiredOrbitAltitude) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label3"), s);//Ap < Pe: circularizing orbit } if (pvgascent.desiredApoapsis < 0) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = XKCDColors.Orange; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label4"), s);//Hyperbolic target orbit (neg Ap) } } else { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label5"), autopilot.desiredOrbitAltitude, "km");//Orbit altitude } GUIStyle si = new GUIStyle(GUI.skin.label); if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange; } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label6"), si, GUILayout.ExpandWidth(true));//Orbit inc. desiredInclination.text = GUILayout.TextField(desiredInclination.text, GUILayout.ExpandWidth(true), GUILayout.Width(100)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button13")))//Current { desiredInclination.val = vesselState.latitude; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label7", Math.Abs(vesselState.latitude) - Math.Abs(desiredInclination)), si);//inc {0:F1}º below current latitude } GUILayout.EndHorizontal(); autopilot.desiredInclination = desiredInclination; } if (autopilot.showGuidanceSettings) { if (ascentPathIdx == ascentType.GRAVITYTURN) { GUILayout.BeginVertical(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), gtascent.turnStartAltitude, "km"); //Turn start altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), gtascent.turnStartVelocity, "m/s"); //Turn start velocity: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), gtascent.turnStartPitch, "deg"); //Turn start pitch: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label11"), gtascent.intermediateAltitude, "km"); //Intermediate altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label12"), gtascent.holdAPTime, "s"); //Hold AP Time: GUILayout.EndVertical(); } else if (ascentPathIdx == ascentType.BREATHING_GT) { GUILayout.BeginVertical(); //GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), bgtascent.turnStartAltitude, "km");//Turn start altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), bgtascent.turnStartVelocity, "m/s"); //Turn start velocity: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), bgtascent.turnStartPitch, "deg"); //Turn start pitch: GuiUtils.SimpleTextBox(Localizer.Format("speed for breathing mode:"), bgtascent.startBreathingSpeed, "m/s"); //speed for breathing mode: GuiUtils.SimpleTextBox(Localizer.Format("TWR to throttle other:"), bgtascent.minTWRthrottle, "s"); //TWR to throttle other: GUILayout.EndVertical(); } else if (ascentPathIdx == ascentType.PVG) { GUILayout.BeginVertical(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label13"), pvgascent.pitchStartVelocity, "m/s"); //Booster Pitch start: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label14"), pvgascent.pitchRate, "°/s"); //Booster Pitch rate: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label15"), core.guidance.pvgInterval, "s"); //Guidance Interval: if (core.guidance.pvgInterval < 1 || core.guidance.pvgInterval > 30) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label16"), s); //Guidance intervals are limited to between 1s and 30s } GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label17"), autopilot.limitQa, "Pa-rad"); //Qα limit if (autopilot.limitQa < 100 || autopilot.limitQa > 4000) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; if (autopilot.limitQa < 100) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label18"), s);//Qα limit cannot be set to lower than 100 Pa-rad } else if (autopilot.limitQa > 10000) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label19"), s);//Qα limit cannot be set to higher than 10000 Pa-rad } else { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label20"), s);//Qα limit is recommended to be 1000 to 4000 Pa-rad } } pvgascent.omitCoast = GUILayout.Toggle(pvgascent.omitCoast, Localizer.Format("#MechJeb_Ascent_checkbox1"));//Omit Coast GUILayout.EndVertical(); } } autopilot.limitQaEnabled = (ascentPathIdx == ascentType.PVG); // this is mandatory for PVG if (autopilot.showSettings) { ToggleAscentNavballGuidanceInfoItem(); if (ascentPathIdx != ascentType.PVG) { core.thrust.LimitToPreventOverheatsInfoItem(); //core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); core.thrust.LimitElectricInfoItem(); } else { core.thrust.LimitToPreventOverheatsInfoItem(); //core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); //core.thrust.LimitAccelerationInfoItem(); //core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); //core.thrust.LimitElectricInfoItem(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label21")); //FIXME: g-limiter is down for maintenance core.thrust.limitAcceleration = false; core.thrust.limitThrottle = false; core.thrust.limitToTerminalVelocity = false; core.thrust.electricThrottle = false; } GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, Localizer.Format("#MechJeb_Ascent_checkbox2"));//Force Roll if (autopilot.forceRoll) { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label22"), autopilot.verticalRoll, "º", 30f); //climb GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label23"), autopilot.turnRoll, "º", 30f); //turn } GUILayout.EndHorizontal(); if (ascentPathIdx != ascentType.PVG) { GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) { s.onHover.textColor = s.onNormal.textColor = Color.green; } autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, Localizer.Format("#MechJeb_Ascent_checkbox3"), s, GUILayout.ExpandWidth(true));//Limit AoA to autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) { sl.normal.textColor = sl.hover.textColor = Color.green; } GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label24"), autopilot.aoALimitFadeoutPressure, "Pa", 50, sl);//Dynamic Pressure Fadeout } GUILayout.EndHorizontal(); autopilot.limitQaEnabled = false; // this is only for PVG } if (ascentPathIdx == ascentType.CLASSIC) { // corrective steering only applies to Classic GUILayout.BeginHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, Localizer.Format("#MechJeb_Ascent_checkbox4"), GUILayout.ExpandWidth(false));//Corrective steering if (autopilot.correctiveSteering) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label25"), GUILayout.ExpandWidth(false));//Gain autopilot.correctiveSteeringGain.text = GUILayout.TextField(autopilot.correctiveSteeringGain.text, GUILayout.Width(40)); } GUILayout.EndHorizontal(); } autopilot.autostage = GUILayout.Toggle(autopilot.autostage, Localizer.Format("#MechJeb_Ascent_checkbox5"));//Autostage if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, Localizer.Format("#MechJeb_Ascent_checkbox6"));//Auto-deploy solar panels autopilot.autoDeployAntennas = GUILayout.Toggle(autopilot.autoDeployAntennas, Localizer.Format("#MechJeb_Ascent_checkbox7"));//Auto-deploy antennas GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_Ascent_checkbox8"));//Auto-warp if (ascentPathIdx != ascentType.PVG) { autopilot.skipCircularization = GUILayout.Toggle(autopilot.skipCircularization, Localizer.Format("#MechJeb_Ascent_checkbox9"));//Skip Circularization } else { // skipCircularization is always true for Optimizer autopilot.skipCircularization = true; } GUILayout.EndHorizontal(); } if (autopilot.showStatus) { if (ascentPathIdx == ascentType.PVG) { if (core.guidance.solution != null) { for (int i = core.guidance.solution.num_segments; i > 0; i--) { GUILayout.Label(String.Format("{0}: {1}", i, core.guidance.solution.ArcString(vesselState.time, i - 1))); } } GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("vgo: {0:F1}", core.guidance.vgo), GUILayout.Width(100)); GUILayout.Label(String.Format("heading: {0:F1}", core.guidance.heading), GUILayout.Width(100)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("tgo: {0:F3}", core.guidance.tgo), GUILayout.Width(100)); GUILayout.Label(String.Format("pitch: {0:F1}", core.guidance.pitch), GUILayout.Width(100)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle si = new GUIStyle(GUI.skin.label); if (core.guidance.isStable()) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Green; } else if (core.guidance.isInitializing() || core.guidance.status == PVGStatus.FINISHED) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange; } else { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Red; } GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label26") + core.guidance.status, si);//Guidance Status: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label27") + core.guidance.successful_converges, GUILayout.Width(100)); //converges: GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label28") + core.guidance.last_lm_status, GUILayout.Width(100)); //status: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("n: " + core.guidance.last_lm_iteration_count + "(" + core.guidance.max_lm_iteration_count + ")", GUILayout.Width(100)); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label29") + GuiUtils.TimeToDHMS(core.guidance.staleness));//staleness: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("znorm: {0:G5}", core.guidance.last_znorm)); GUILayout.EndHorizontal(); if (core.guidance.last_failure_cause != null) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.red; GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label30") + core.guidance.last_failure_cause, s);//LAST FAILURE: GUILayout.EndHorizontal(); } if (vessel.situation != Vessel.Situations.LANDED && vessel.situation != Vessel.Situations.PRELAUNCH && vessel.situation != Vessel.Situations.SPLASHED) { double m0 = atmoStats[vessel.currentStage].startMass; double thrust = atmoStats[vessel.currentStage].startThrust; if (Math.Abs(vesselState.mass - m0) / m0 > 0.01) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.BeginHorizontal(); GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label31") + "{0:F1}%", (vesselState.mass - m0) / m0 * 100.0), s);//MASS IS OFF BY GUILayout.EndHorizontal(); } if (Math.Abs(vesselState.thrustCurrent - thrust) / thrust > 0.01) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.BeginHorizontal(); GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label32") + "{0:F1}%", (vesselState.thrustCurrent - thrust) / thrust * 100.0), s);//THRUST IS OFF BY GUILayout.EndHorizontal(); } } } } if (vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label33"), GUILayout.ExpandWidth(true)); //Launch countdown: autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { // disable plane/rendezvous/interplanetary for now if (ascentPathIdx != ascentType.PVG) { GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button14"), GUILayout.ExpandWidth(false))) //Launch to rendezvous: { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button15"), GUILayout.ExpandWidth(false))) //Launch into plane of target { launchingToPlane = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPlane(autopilot.launchLANDifference, mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchLANDifference.text = GUILayout.TextField( autopilot.launchLANDifference.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button16"))) //Launch at interplanetary window { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt( Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label34")); //Select a target for a timed launch. } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = Localizer.Format("#MechJeb_Ascent_msg1"); //Launching at interplanetary window } else if (launchingToPlane) { desiredInclination = MuUtils.Clamp(core.target.TargetOrbit.inclination, Math.Abs(vesselState.latitude), 180 - Math.Abs(vesselState.latitude)); desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = Localizer.Format("#MechJeb_Ascent_msg2"); //Launching to target plane } else if (launchingToRendezvous) { message = "#MechJeb_Ascent_msg3"; //Launching to rendezvous } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button17")))//Abort { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } } if (autopilot.enabled) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label35") + autopilot.status);//Autopilot status: } if (core.DeactivateControl) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.red; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label36"), s);//CONTROL DISABLED (AVIONICS) } } if (!vessel.patchedConicsUnlocked() && ascentPathIdx != ascentType.PVG) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label37"));//"Warning: MechJeb is unable to circularize without an upgraded Tracking Station." } GUILayout.BeginHorizontal(); autopilot.ascentPathIdxPublic = (ascentType)GuiUtils.ComboBox.Box((int)autopilot.ascentPathIdxPublic, autopilot.ascentPathList, this); GUILayout.EndHorizontal(); if (autopilot.ascentMenu != null) { autopilot.ascentMenu.enabled = GUILayout.Toggle(autopilot.ascentMenu.enabled, Localizer.Format("#MechJeb_Ascent_checkbox10")); //Edit ascent path } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUIStyle sty = new GUIStyle(GUI.skin.button); sty.normal.textColor = sty.focused.textColor = Color.white; sty.hover.textColor = sty.active.textColor = Color.yellow; sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = Color.green; sty.padding = new RectOffset(8, 8, 8, 8); GUILayout.BeginVertical(); if ((core.thrust.users.Count > 1) && !core.thrust.users.Contains(this)) { if (!autoMode) { windowPos = new Rect(windowPos.x, windowPos.y, 10, 10); autoMode = true; } sty.normal.textColor = Color.red; sty.onActive = sty.onFocused = sty.onHover = sty.onNormal = sty.active = sty.focused = sty.hover = sty.normal; GUILayout.Button(Localizer.Format("#MechJeb_Trans_auto"), sty, GUILayout.ExpandWidth(true)); } else { if (autoMode) { windowPos = new Rect(windowPos.x, windowPos.y, 10, 10); autoMode = false; } MechJebModuleThrustController.TMode newMode = (MechJebModuleThrustController.TMode)GUILayout.SelectionGrid((int)core.thrust.tmode, trans_texts, 2, sty); SetMode(newMode); float val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 -- would be better if it actually worked... core.thrust.trans_kill_h = GUILayout.Toggle(core.thrust.trans_kill_h, Localizer.Format("#MechJeb_Trans_kill_h"), GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Trans_spd"), trans_spd, "", 37); bool change = false; if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { trans_spd -= val; change = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { trans_spd = 0; change = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { trans_spd += val; change = true; } GUILayout.EndHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_Trans_spd_act") + ":", sty, GUILayout.ExpandWidth(true)) || change) { core.thrust.trans_spd_act = (float)trans_spd.val; GUIUtility.keyboardControl = 0; } } if (core.thrust.tmode != MechJebModuleThrustController.TMode.OFF) { GUILayout.Label(Localizer.Format("#MechJeb_Trans_current_spd") + MuMech.MuUtils.ToSI(core.thrust.trans_spd_act) + "m/s", GUILayout.ExpandWidth(true)); } GUILayout.FlexibleSpace(); GUIStyle tsty = new GUIStyle(GUI.skin.label); tsty.alignment = TextAnchor.UpperCenter; GUILayout.Label("Automation", tsty, GUILayout.ExpandWidth(true)); sty.normal.textColor = sty.focused.textColor = sty.hover.textColor = sty.active.textColor = sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = (abort != AbortStage.OFF) ? Color.red : Color.green; if (GUILayout.Button((abort != AbortStage.OFF) ? Localizer.Format("#MechJeb_Trans_NOPANIC") : Localizer.Format("#MechJeb_Trans_PANIC"), sty, GUILayout.ExpandWidth(true))) { PanicSwitch(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset(); } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this); } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.limitToPreventOverheats = GUILayout.Toggle(core.thrust.limitToPreventOverheats, "Prevent overheats"); core.thrust.limitToTerminalVelocity = GUILayout.Toggle(core.thrust.limitToTerminalVelocity, "Limit to terminal velocity"); GUILayout.BeginHorizontal(); core.thrust.limitAcceleration = GUILayout.Toggle(core.thrust.limitAcceleration, "Limit acceleration to", GUILayout.ExpandWidth(false)); core.thrust.maxAcceleration.text = GUILayout.TextField(core.thrust.maxAcceleration.text, GUILayout.ExpandWidth(true)); GUILayout.Label("m/s²", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); core.staging.AutostageInfoItem(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (!launchingToPlane && !launchingToRendezvous) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; } } else { launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToPlane || launchingToRendezvous) { double tMinus; if (launchingToPlane) tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.Orbit); else tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.Orbit); double launchTime = vesselState.time + tMinus; core.warp.WarpToUT(launchTime); if (launchingToPlane) { desiredInclination = core.target.Orbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.Orbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); } if (autopilot.enabled) core.warp.WarpToUT(launchTime); GUILayout.Label("Launching to " + (launchingToPlane ? "target plane" : "rendezvous") + ": T-" + MuUtils.ToSI(tMinus, 0) + "s"); if (tMinus < 3 * vesselState.deltaT) { if (autopilot.enabled) Staging.ActivateNextStage(); launchingToPlane = launchingToRendezvous = false; } if (GUILayout.Button("Abort")) launchingToPlane = launchingToRendezvous = false; } if (autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } } MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>(); if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto tunning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); } else { // pid.Kd = kpFactor / Tf; // pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf); // pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf); GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); } core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); core.rcs.rcsThrottle = GUILayout.Toggle(core.rcs.rcsThrottle, " RCS throttle when 0k thrust"); GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = new Vector3d( vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle, vesselState.torqueAvailable.y, vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle ); GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.Tf != Tf) { core.attitude.Tf = Tf; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) { core.target.Unset(); } } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll"); if (autopilot.forceRoll) { GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f); GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) { s.onHover.textColor = s.onNormal.textColor = Color.green; } autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true)); autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) { sl.normal.textColor = sl.hover.textColor = Color.green; } GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl); } GUILayout.EndHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels"); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = "Launching at interplanetary window"; } else if (launchingToPlane) { desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { message = "Launching to rendezvous"; } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button("Abort")) { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } if (!vessel.patchedConicsUnlocked()) { GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station."); } MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>(); if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); if (GUILayout.Button("Reset")) { core.attitude.ResetConfig(); OnStart(PartModule.StartState.None); } core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GUILayout.BeginHorizontal(); GUILayout.Label("Tf (s)", GUILayout.ExpandWidth(true)); GUILayout.Label("P", GUILayout.ExpandWidth(false)); TfX.text = GUILayout.TextField(TfX.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.Label("Y", GUILayout.ExpandWidth(false)); TfY.text = GUILayout.TextField(TfY.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.Label("R", GUILayout.ExpandWidth(false)); TfZ.text = GUILayout.TextField(TfZ.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.EndHorizontal(); TfX = Math.Max(0.01, TfX); TfY = Math.Max(0.01, TfY); TfZ = Math.Max(0.01, TfZ); } else { GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.TfV), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); } GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); showInfos = GUILayout.Toggle(showInfos, "Show Numbers"); if (showInfos) { GUILayout.BeginHorizontal(); GUILayout.Label("Kp", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kp), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Ki", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Ki), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kd), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Error", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.error * Mathf.Rad2Deg), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Axis Control ", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.AxisState, "F0"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Torque", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + core.attitude.torque.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("torqueReactionSpeed", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vesselState.torqueReactionSpeed.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.torqueReactionSpeed), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Inertia", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + core.attitude.inertia.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, core.attitude.torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("MOI / torque", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + ratio.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(ratio), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("MOI", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vesselState.MoI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.MoI), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("MOI stock", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vessel.MOI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.MOI), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Angular Velocity", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vessel.angularVelocity.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.angularVelocity), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock"); MechJebModuleDebugArrows arrows = core.GetComputerModule<MechJebModuleDebugArrows>(); GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50); arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object"); GUILayout.BeginHorizontal(); arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false)); arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM"); arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)"); arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)"); arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)"); arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)"); arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)"); //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)"); arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)"); arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)"); GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.TfV.x != TfX || core.attitude.TfV.y != TfY || core.attitude.TfV.z != TfZ) { core.attitude.TfV.x = TfX; core.attitude.TfV.y = TfY; core.attitude.TfV.z = TfZ; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; //btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; btGreen = new GUIStyle(btNormal); btGreen.normal.textColor = Color.green; btGreen.fixedWidth = 35; btWhite = new GUIStyle(btNormal); btWhite.normal.textColor = Color.white; btWhite.fixedWidth = 35; btAuto = new GUIStyle(btNormal); btAuto.padding = new RectOffset(8, 8, 8, 8); btAuto.normal.textColor = Color.red; btAuto.onActive = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal; } if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot", btActive)) { autopilot.users.Remove(this); } } else if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0) { if (core.attitude.users.Contains(this)) { core.attitude.users.Remove(this); // so we don't suddenly turn on when the other autopilot finishes } GUILayout.Button("Auto", btAuto, GUILayout.ExpandWidth(true)); } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } GUILayout.BeginHorizontal(); bool AltitudeHold = autopilot.AltitudeHoldEnabled; autopilot.AltitudeHoldEnabled = GUILayout.Toggle(autopilot.AltitudeHoldEnabled, "Altitude Hold", GUILayout.Width(140)); if (AltitudeHold != autopilot.AltitudeHoldEnabled) { if (autopilot.AltitudeHoldEnabled) { autopilot.EnableAltitudeHold(); } else { autopilot.DisableAltitudeHold(); } } bool change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { AltitudeTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } AltitudeTargettmp.text = GUILayout.TextField(AltitudeTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { AltitudeTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } if (AltitudeTargettmp < 0) { AltitudeTargettmp = 0; } GUILayout.Label("m", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.AltitudeTarget == AltitudeTargettmp ? btWhite : btGreen)) { autopilot.AltitudeTarget = AltitudeTargettmp; } GUILayout.EndHorizontal(); if (!autopilot.AltitudeHoldEnabled) { bool _VertSpeedHoldEnabled = autopilot.VertSpeedHoldEnabled; GUILayout.BeginHorizontal(); autopilot.VertSpeedHoldEnabled = GUILayout.Toggle(autopilot.VertSpeedHoldEnabled, "Vertical Speed Hold", GUILayout.Width(140)); if (_VertSpeedHoldEnabled != autopilot.VertSpeedHoldEnabled) { if (autopilot.VertSpeedHoldEnabled) { autopilot.EnableVertSpeedHold(); } else { autopilot.DisableVertSpeedHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen)) { autopilot.VertSpeedTarget = VertSpeedTargettmp; } GUILayout.EndHorizontal(); } else { GUILayout.BeginHorizontal(); GUILayout.Label(" Vertical Speed Limit", GUILayout.Width(140)); change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { VertSpeedMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } VertSpeedMaxtmp.text = GUILayout.TextField(VertSpeedMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { VertSpeedMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } if (VertSpeedMaxtmp < 0) { VertSpeedMaxtmp = 0; } GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.VertSpeedMax == VertSpeedMaxtmp ? btWhite : btGreen)) { autopilot.VertSpeedMax = VertSpeedMaxtmp; } GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); bool _HeadingHoldEnabled = autopilot.HeadingHoldEnabled; autopilot.HeadingHoldEnabled = GUILayout.Toggle(autopilot.HeadingHoldEnabled, "Heading Hold", GUILayout.Width(140)); if (_HeadingHoldEnabled != autopilot.HeadingHoldEnabled) { if (autopilot.HeadingHoldEnabled) { autopilot.EnableHeadingHold(); } else { autopilot.DisableHeadingHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { HeadingTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } HeadingTargettmp.text = GUILayout.TextField(HeadingTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { HeadingTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } HeadingTargettmp = MuUtils.ClampDegrees360(HeadingTargettmp); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.HeadingTarget == HeadingTargettmp ? btWhite : btGreen)) { autopilot.HeadingTarget = HeadingTargettmp; } GUILayout.EndHorizontal(); if (!autopilot.HeadingHoldEnabled) { GUILayout.BeginHorizontal(); autopilot.RollHoldEnabled = GUILayout.Toggle(autopilot.RollHoldEnabled, "Roll Hold", GUILayout.Width(140)); change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { RollTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollTargettmp.text = GUILayout.TextField(RollTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { RollTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollTargettmp = MuUtils.Clamp(RollTargettmp, -90, 90); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.RollTarget == RollTargettmp ? btWhite : btGreen)) { autopilot.RollTarget = RollTargettmp; } GUILayout.EndHorizontal(); } else { GUILayout.BeginHorizontal(); GUILayout.Label(" Roll Limit ±", GUILayout.Width(140)); change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { RollMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollMaxtmp.text = GUILayout.TextField(RollMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { RollMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } RollMaxtmp = MuUtils.Clamp(RollMaxtmp, -60, 60); GUILayout.Label("°", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.RollMax == RollMaxtmp ? btWhite : btGreen)) { autopilot.RollMax = RollMaxtmp; } GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); bool _AutoThrustCtrl = autopilot.SpeedHoldEnabled; autopilot.SpeedHoldEnabled = GUILayout.Toggle(autopilot.SpeedHoldEnabled, "Speed Hold", GUILayout.Width(140)); if (autopilot.SpeedHoldEnabled != _AutoThrustCtrl) { if (autopilot.SpeedHoldEnabled) { autopilot.EnableSpeedHold(); } else { autopilot.DisableSpeedHold(); } } change = false; if (GUILayout.Button("-", GUILayout.Width(18))) { SpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } SpeedTargettmp.text = GUILayout.TextField(SpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60)); if (GUILayout.Button("+", GUILayout.Width(18))) { SpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true; } if (SpeedTargettmp < 0) { SpeedTargettmp = 0; } GUILayout.Label("m/s", GUILayout.ExpandWidth(true)); if (change || GUILayout.Button("Set", autopilot.SpeedTarget == SpeedTargettmp ? btWhite : btGreen)) { autopilot.SpeedTarget = SpeedTargettmp; } GUILayout.EndHorizontal(); if (!showpid) { if (GUILayout.Button("PID", GUILayout.Width(40))) { showpid = true; } } else { if (GUILayout.Button("Hide PID", GUILayout.Width(140))) { showpid = false; } GUILayout.BeginHorizontal(); GUILayout.Label("Accceleration", GUILayout.ExpandWidth(true)); GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.AccKp.text = GUILayout.TextField(autopilot.AccKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.AccKi.text = GUILayout.TextField(autopilot.AccKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.AccKd.text = GUILayout.TextField(autopilot.AccKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.SpeedHoldEnabled) { GUILayout.Label("error:" + autopilot.a_err.ToString("F2") + " Target:" + autopilot.RealAccelerationTarget.ToString("F2") + " Cur:" + autopilot.cur_acc.ToString("F2"), GUILayout.ExpandWidth(false)); } GUILayout.BeginHorizontal(); GUILayout.Label("VertSpeed", GUILayout.ExpandWidth(true)); GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.VerKp.text = GUILayout.TextField(autopilot.VerKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.VerKi.text = GUILayout.TextField(autopilot.VerKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.VerKd.text = GUILayout.TextField(autopilot.VerKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); if (autopilot.VertSpeedHoldEnabled) { GUILayout.Label("error:" + autopilot.v_err.ToString("F2") + " Target:" + autopilot.RealVertSpeedTarget.ToString("F2") + " Cur:" + vesselState.speedVertical.ToString("F2"), GUILayout.ExpandWidth(false)); } GUILayout.BeginHorizontal(); GUILayout.Label("Roll", GUILayout.ExpandWidth(true)); GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.RolKp.text = GUILayout.TextField(autopilot.RolKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.RolKi.text = GUILayout.TextField(autopilot.RolKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.RolKd.text = GUILayout.TextField(autopilot.RolKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Yaw", GUILayout.ExpandWidth(true)); GUILayout.Label("Kp", GUILayout.ExpandWidth(false)); autopilot.YawKp.text = GUILayout.TextField(autopilot.YawKp.text, GUILayout.Width(40)); GUILayout.Label("i", GUILayout.ExpandWidth(false)); autopilot.YawKi.text = GUILayout.TextField(autopilot.YawKi.text, GUILayout.Width(40)); GUILayout.Label("d", GUILayout.ExpandWidth(false)); autopilot.YawKd.text = GUILayout.TextField(autopilot.YawKd.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Yaw Control Limit", GUILayout.ExpandWidth(false)); autopilot.YawLimit.text = GUILayout.TextField(autopilot.YawLimit.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); } base.WindowGUI(windowID); }
public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to { // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now? if (orbit.referenceBody != lastBody) { WaypointIndex = -1; Waypoints.Clear(); } MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null); var brake = vessel.ActionGroups[KSPActionGroup.Brakes]; // keep brakes locked if they are curSpeed = Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward); CalculateTraction(); speedIntAcc = speedPID.intAccum; if (wp != null && wp.Body == orbit.referenceBody) { if (ControlHeading) { heading.val = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1); } if (ControlSpeed) { var nextWP = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null)); var distance = Vector3.Distance(vessel.CoM, wp.Position); if (wp.Target != null) { distance += (float)(wp.Target.srfSpeed * curSpeed) / 2; } //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed); // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed : (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) : (distance - wp.Radius > 50 ? turnSpeed.val : 1))); minSpeed = (wp.Quicksave ? 1 : minSpeed); // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last) var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3); var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed); // reduce speed when turning a lot // if (LimitAcceleration) { newSpeed = curSpeed + Mathf.Clamp((float)(newSpeed - curSpeed), -1.5f, 0.5f); } // newSpeed = tgtSpeed + Mathf.Clamp((float)(newSpeed - tgtSpeed), -Time.deltaTime * 8f, Time.deltaTime * 2f); var radius = Math.Max(wp.Radius, 10); if (distance < radius) { if (WaypointIndex + 1 >= Waypoints.Count) // last waypoint { newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min(); // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons if (LoopWaypoints) { WaypointIndex = 0; } else { newSpeed = 0; // tgtSpeed.force(newSpeed); if (curSpeed < brakeSpeedLimit) { if (wp.Quicksave) { //if (s.mainThrottle > 0) { s.mainThrottle = 0; } if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex = -1; ControlHeading = ControlSpeed = false; QuickSaveLoad.QuickSave(); } } else { WaypointIndex = -1; ControlHeading = ControlSpeed = false; } } // else { // Debug.Log("Is this even getting called?"); // WaypointIndex++; // } } } else { if (wp.Quicksave) { //if (s.mainThrottle > 0) { s.mainThrottle = 0; } newSpeed = 0; // tgtSpeed.force(newSpeed); if (curSpeed < brakeSpeedLimit) { if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex++; QuickSaveLoad.QuickSave(); } } } else { WaypointIndex++; } } } brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit); // ^ brake if needed to prevent rolling, hopefully tgtSpeed = (newSpeed >= 0 ? newSpeed : 0); } } if (ControlHeading) { headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1); double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y; headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading); if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel) { float spd = Mathf.Min((float)speed, (float)turnSpeed); // if a slower speed than the turnspeed is used also be more careful with the steering float limit = (Mathf.Abs((float)curSpeed) <= turnSpeed ? 1 : Mathf.Clamp((float)(spd / Mathf.Abs((float)curSpeed)), 0.35f, 1f)); double act = headingPID.Compute(headingErr); s.wheelSteer = Mathf.Clamp((float)act, -limit, limit); } } // Brake if there is no controler (Pilot eject from seat) if (BrakeOnEject && vessel.GetReferenceTransformPart() == null) { s.wheelThrottle = 0; // vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); brake = true; } else if (ControlSpeed) { speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5); speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward); if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel) { float act = (float)speedPID.Compute(speedErr); s.wheelThrottle = (!LimitAcceleration ? Mathf.Clamp(act, -1, 1) : // I think I'm using these ( ? : ) a bit too much (traction == 0 ? 0 : (act < 0 ? Mathf.Clamp(act, -1f, 1f) : (lastThrottle + Mathf.Clamp(act - lastThrottle, -0.01f, 0.01f)) * (traction < tractionLimit ? -1 : 1)))); // (lastThrottle + Mathf.Clamp(act, -0.01f, 0.01f))); // Debug.Log(s.wheelThrottle + Mathf.Clamp(act, -0.01f, 0.01f)); if (curSpeed < 0 & s.wheelThrottle < 0) { s.wheelThrottle = 0; } // don't go backwards if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0) { s.wheelThrottle = Mathf.Clamp(act, -1f, 1f); } // if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) == 0) { // StabilityControl && traction > 50 && //// vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); // brake = true; // foreach (Part p in wheels) { // if (p.GetModule<ModuleWheels.ModuleWheelDamage>().stressPercent >= 0.01) { // #TODO needs adaptive braking // brake = false; // break; // } // } // } //// else if (!StabilityControl || traction <= 50 || speedErr > -0.2 || Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { //// vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel)); //// } lastThrottle = Mathf.Clamp(s.wheelThrottle, -1, 1); } } if (StabilityControl) { if (!core.attitude.users.Contains(this)) { core.attitude.users.Add(this); // line.enabled = true; } // float scale = Vector3.Distance(FlightCamera.fetch.mainCamera.transform.position, vessel.CoM) / 900f; // line.SetPosition(0, vessel.CoM); // line.SetPosition(1, vessel.CoM + hit.normal * 5); // line.SetWidth(0, scale + 0.1f); var fSpeed = (float)curSpeed; // if (Mathf.Abs(fSpeed) >= turnSpeed * 0.75) { Vector3 fwd = (Vector3)(traction > 0 ? // V when the speed is low go for the vessels forward, else with a bit of velocity // ((Mathf.Abs(fSpeed) <= turnSpeed ? vesselState.forward : vesselState.surfaceVelocity / 4) - vessel.transform.right * s.wheelSteer) * Mathf.Sign(fSpeed) : // // ^ and then add the steering vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering vesselState.surfaceVelocity); // in the air so follow velocity Vector3.OrthoNormalize(ref norm, ref fwd); var quat = Quaternion.LookRotation(fwd, norm); // if (traction > 0 || speed <= turnSpeed) { // var u = new Vector3(0, 1, 0); // // var q = FlightGlobals.ship_rotation; // var q_s = quat; // // var q_u = new Quaternion(u.x, u.y, u.z, 0); // var a = Quaternion.Dot(q, q_s * q_u); // var q_qs = Quaternion.Dot(q, q_s); // var b = (a == 0) ? Math.Sign(q_qs) : (q_qs / a); // var g = b / Mathf.Sqrt((b * b) + 1); // var gu = Mathf.Sqrt(1 - (g * g)) * u; // var q_d = new Quaternion() { w = g, x = gu.x, y = gu.y, z = gu.z }; // var n = q_s * q_d; // // quat = n; // } if (vesselState.torqueAvailable.sqrMagnitude > 0) core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this); // } } if (BrakeOnEnergyDepletion) { var batteries = vessel.Parts.FindAll(p => p.Resources.Contains("ElectricCharge") && p.Resources["ElectricCharge"].flowState); var energyLeft = batteries.Sum(p => p.Resources["ElectricCharge"].amount) / batteries.Sum(p => p.Resources["ElectricCharge"].maxAmount); var openSolars = vessel.mainBody.atmosphere && // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState != ModuleDeployableSolarPanel.panelStates.BROKEN && p.panelState != ModuleDeployableSolarPanel.panelStates.RETRACTED).Count > 0; if (openSolars && energyLeft > 0.99) { vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).ForEach(p => p.Retract()); } if (energyLeft < 0.05 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { s.wheelThrottle = 0; } // save remaining energy by not using it for acceleration if (openSolars || energyLeft < 0.03) { tgtSpeed = 0; } if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars)) { brake = true; } if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight && vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).Count > 0) { waitingForDaylight = true; } } // brake = brake && (s.wheelThrottle == 0); // release brake if the user or AP want to drive if (s.wheelThrottle != 0 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { brake = false; // the AP or user want to drive into the direction of momentum so release the brake } if (vessel.isActiveVessel) { if (GameSettings.BRAKES.GetKeyUp()) { brake = false; // release the brakes if the user lets go of them } if (GameSettings.BRAKES.GetKey()) { brake = true; // brake if the user brakes and we aren't about to flip } } tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100); vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && curSpeed > brakeSpeedLimit ? traction >= tractionLimit : true)); // ^ brake but hopefully prevent flipping over, assuming the user set up the limit right if (brake && curSpeed < 0.1) { s.wheelThrottle = 0; } }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); } else { // pid.Kd = kpFactor / Tf; // pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf); // pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf); GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); } core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); showInfos = GUILayout.Toggle(showInfos, "Show Numbers"); if (showInfos) { GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label( core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = vesselState.torqueAvailable + vesselState.torqueFromEngine * vessel.ctrlState.mainThrottle; GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock"); MechJebModuleDebugArrows arrows = core.GetComputerModule <MechJebModuleDebugArrows>(); GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50); arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object"); GUILayout.BeginHorizontal(); arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false)); arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM"); arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)"); arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)"); arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)"); arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)"); arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)"); //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)"); arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)"); arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)"); GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.Tf != Tf) { core.attitude.Tf = Tf; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = new Vector3d( vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle, vesselState.torqueAvailable.y, vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle ); GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if ((core.attitude.Tf != Tf)) { core.attitude.Tf = Tf; double Kd = 0.53 / Tf; double Kp = Kd / (3 * Math.Sqrt(2) * Tf); double Ki = Kp / (12 * Math.Sqrt(2) * Tf); core.attitude.pid = new PIDControllerV2(Kp, Ki, Kd, 1, -1); } base.WindowGUI(windowID); }
public override void OnStart(PartModule.StartState state) { Tf = new EditableDouble(core.attitude.Tf); base.OnStart(state); }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label("No maneuver nodes to edit."); GUI.DragWindow(); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) node = vessel.patchedConicSolver.maneuverNodes[0]; int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = -node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) gizmo.OnGizmoUpdated -= GizmoUpdateHandler; gizmo = node.attachedGizmo; if (gizmo != null) gizmo.OnGizmoUpdated += GizmoUpdateHandler; } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Prograde:", prograde, "m/s", 60); if (GUILayout.Button("Add", GUILayout.ExpandWidth(false))) { prograde += progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60); if (GUILayout.Button("Add", GUILayout.ExpandWidth(false))) { radialPlus += radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60); if (GUILayout.Button("Add", GUILayout.ExpandWidth(false))) { normalPlus += normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Update")) node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); GUILayout.BeginHorizontal(); if (GUILayout.Button("Shift time by", GUILayout.ExpandWidth(true))) { node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Snap node to", GUILayout.ExpandWidth(true))) { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(UT - o.period / 2); //period is who-knows-what for e > 1, but this should still work break; case Snap.APOAPSIS: if (o.eccentricity < 1) UT = o.NextApoapsisTime(UT - o.period / 2); break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.Orbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.Orbit)) UT = o.TimeOfAscendingNode(core.target.Orbit, UT - o.period / 2); } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.Orbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.Orbit)) UT = o.TimeOfDescendingNode(core.target.Orbit, UT - o.period / 2); } break; } node.OnGizmoUpdated(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; btAuto = new GUIStyle(btNormal); btAuto.normal.textColor = Color.red; btAuto.onActive = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal; } // If any other module use the attitude controler then let them do it if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0) { if (autoDisableSmartASS) { target = Target.OFF; if (core.attitude.users.Contains(this)) core.attitude.users.Remove(this); // so we don't suddenly turn on when the other autopilot finishes } GUILayout.Button("AUTO", btAuto, GUILayout.ExpandWidth(true)); } else { GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); TargetButton(Target.OFF); TargetButton(Target.KILLROT); if (vessel.patchedConicsUnlocked()) { TargetButton(Target.NODE); } else { GUILayout.Button("-", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); } GUILayout.EndHorizontal(); GUILayout.Label("Mode:"); GUILayout.BeginHorizontal(); ModeButton(Mode.ORBITAL); ModeButton(Mode.SURFACE); ModeButton(Mode.TARGET); ModeButton(Mode.ADVANCED); GUILayout.EndHorizontal(); switch (mode) { case Mode.ORBITAL: GUILayout.BeginHorizontal(); TargetButton(Target.PROGRADE); TargetButton(Target.NORMAL_PLUS); TargetButton(Target.RADIAL_PLUS); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.RETROGRADE); TargetButton(Target.NORMAL_MINUS); TargetButton(Target.RADIAL_MINUS); GUILayout.EndHorizontal(); ForceRoll(); break; case Mode.SURFACE: double val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 GUILayout.BeginHorizontal(); TargetButton(Target.SURFACE_PROGRADE); TargetButton(Target.SURFACE_RETROGRADE); TargetButtonNoEngage(Target.SURFACE); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.HORIZONTAL_PLUS); TargetButton(Target.HORIZONTAL_MINUS); TargetButton(Target.VERTICAL_PLUS); GUILayout.EndHorizontal(); if (target == Target.SURFACE) { bool changed = false; GUILayout.BeginHorizontal(); forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("HDG", srfHdg, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfHdg -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfHdg += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfHdg = 0; changed = true; } if (GUILayout.Button("90", GUILayout.Width(35))) { srfHdg = 90; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("PIT", srfPit, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfPit -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfPit += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfPit = 0; changed = true; } if (GUILayout.Button("90", GUILayout.Width(35))) { srfPit = 90; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("ROL", srfRol, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfRol -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfRol += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfRol = 0; changed = true; } if (GUILayout.Button("180", GUILayout.Width(35))) { srfRol = 180; changed = true; } GUILayout.EndHorizontal(); if (GUILayout.Button("EXECUTE")) { Engage(); } if (changed) { Engage(false); } core.attitude.AxisControl(forcePitch, forceYaw, forceRol); } else if (target == Target.SURFACE_PROGRADE || target == Target.SURFACE_RETROGRADE) { bool changed = false; GUILayout.BeginHorizontal(); forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("ROL", srfVelRol, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelRol -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelRol += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelRol = -vesselState.vesselRoll.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelRol = 0; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("PIT", srfVelPit, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelPit -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelPit += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelPit = vesselState.AoA.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelPit = 0; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("YAW", srfVelYaw, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelYaw -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelYaw += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelYaw = -vesselState.AoS.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelYaw = 0; changed = true; } GUILayout.EndHorizontal(); if (GUILayout.Button("EXECUTE")) { Engage(); } if (changed) { Engage(false); } core.attitude.AxisControl(forcePitch, forceYaw, forceRol); } break; case Mode.TARGET: if (core.target.NormalTargetExists) { GUILayout.BeginHorizontal(); TargetButton(Target.TARGET_PLUS); TargetButton(Target.RELATIVE_PLUS); TargetButton(Target.PARALLEL_PLUS); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.TARGET_MINUS); TargetButton(Target.RELATIVE_MINUS); TargetButton(Target.PARALLEL_MINUS); GUILayout.EndHorizontal(); ForceRoll(); } else { GUILayout.Label("Please select a target"); } break; case Mode.ADVANCED: GUILayout.Label("Reference:"); advReference = (AttitudeReference)GuiUtils.ComboBox.Box((int)advReference, ReferenceTexts, this); GUILayout.Label("Direction:"); advDirection = (Vector6.Direction)GuiUtils.ComboBox.Box((int)advDirection, directionTexts, directionTexts); ForceRoll(); if (GUILayout.Button("EXECUTE", btNormal, GUILayout.ExpandWidth(true))) { target = Target.ADVANCED; Engage(); } break; case Mode.AUTO: break; } GUILayout.EndVertical(); } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label("No maneuver nodes to edit."); RelativityModeSelectUI(); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) { node = vessel.patchedConicSolver.maneuverNodes[0]; } int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) { gizmo.OnGizmoUpdated -= GizmoUpdateHandler; } gizmo = node.attachedGizmo; if (gizmo != null) { gizmo.OnGizmoUpdated += GizmoUpdateHandler; } } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Prograde:", prograde, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { prograde -= progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { prograde += progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { radialPlus -= radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { radialPlus += radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { normalPlus -= normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { normalPlus += normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Set delta to:", GUILayout.ExpandWidth(true)); if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.01; } if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.1; } if (GUILayout.Button("1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 1; } if (GUILayout.Button("10", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 10; } if (GUILayout.Button("100", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 100; } GUILayout.EndHorizontal(); if (GUILayout.Button("Update")) { node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.BeginHorizontal(); GUILayout.Label("Shift time", GUILayout.ExpandWidth(true)); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT - timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Snap node to", GUILayout.ExpandWidth(true))) { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(UT - o.period / 2); //period is who-knows-what for e > 1, but this should still work break; case Snap.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT - o.period / 2); } break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); } break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); } break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; } node.OnGizmoUpdated(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); RelativityModeSelectUI(); if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled) { if (GUILayout.Button("Execute next node")) { core.node.ExecuteOneNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button("Execute all nodes")) { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button("Abort node execution")) { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp", GUILayout.ExpandWidth(true)); GUILayout.Label("Tolerance:", GUILayout.ExpandWidth(false)); core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; btAuto = new GUIStyle(btNormal); btAuto.normal.textColor = Color.red; btAuto.onActive = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal; } // If any other module use the attitude controler then let them do it if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0) { if (autoDisableSmartASS) { target = Target.OFF; if (core.attitude.users.Contains(this)) { core.attitude.users.Remove(this); // so we don't suddenly turn on when the other autopilot finishes } } GUILayout.Button("AUTO", btAuto, GUILayout.ExpandWidth(true)); } else { GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); TargetButton(Target.OFF); TargetButton(Target.KILLROT); if (vessel.patchedConicsUnlocked()) { TargetButton(Target.NODE); } else { GUILayout.Button("-", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); } GUILayout.EndHorizontal(); GUILayout.Label("Mode:"); GUILayout.BeginHorizontal(); ModeButton(Mode.ORBITAL); ModeButton(Mode.SURFACE); ModeButton(Mode.TARGET); ModeButton(Mode.ADVANCED); GUILayout.EndHorizontal(); switch (mode) { case Mode.ORBITAL: GUILayout.BeginHorizontal(); TargetButton(Target.PROGRADE); TargetButton(Target.NORMAL_PLUS); TargetButton(Target.RADIAL_PLUS); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.RETROGRADE); TargetButton(Target.NORMAL_MINUS); TargetButton(Target.RADIAL_MINUS); GUILayout.EndHorizontal(); ForceRoll(); break; case Mode.SURFACE: double val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 GUILayout.BeginHorizontal(); TargetButton(Target.SURFACE_PROGRADE); TargetButton(Target.SURFACE_RETROGRADE); TargetButtonNoEngage(Target.SURFACE); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.HORIZONTAL_PLUS); TargetButton(Target.HORIZONTAL_MINUS); TargetButton(Target.VERTICAL_PLUS); GUILayout.EndHorizontal(); if (target == Target.SURFACE) { bool changed = false; GUILayout.BeginHorizontal(); forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("HDG", srfHdg, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfHdg -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfHdg += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfHdg = 0; changed = true; } if (GUILayout.Button("90", GUILayout.Width(35))) { srfHdg = 90; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("PIT", srfPit, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfPit -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfPit += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfPit = 0; changed = true; } if (GUILayout.Button("90", GUILayout.Width(35))) { srfPit = 90; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("ROL", srfRol, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfRol -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfRol += val; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfRol = 0; changed = true; } if (GUILayout.Button("180", GUILayout.Width(35))) { srfRol = 180; changed = true; } GUILayout.EndHorizontal(); if (GUILayout.Button("EXECUTE")) { Engage(); } if (changed) { Engage(false); } core.attitude.AxisControl(forcePitch, forceYaw, forceRol); } else if (target == Target.SURFACE_PROGRADE || target == Target.SURFACE_RETROGRADE) { bool changed = false; GUILayout.BeginHorizontal(); forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("ROL", srfVelRol, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelRol -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelRol += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelRol = -vesselState.vesselRoll.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelRol = 0; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("PIT", srfVelPit, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelPit -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelPit += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelPit = vesselState.AoA.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelPit = 0; changed = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false)); GuiUtils.SimpleTextBox("YAW", srfVelYaw, "°", 37); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { srfVelYaw -= val; changed = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { srfVelYaw += val; changed = true; } if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) { srfVelYaw = -vesselState.AoS.value; changed = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { srfVelYaw = 0; changed = true; } GUILayout.EndHorizontal(); if (GUILayout.Button("EXECUTE")) { Engage(); } if (changed) { Engage(false); } core.attitude.AxisControl(forcePitch, forceYaw, forceRol); } break; case Mode.TARGET: if (core.target.NormalTargetExists) { GUILayout.BeginHorizontal(); TargetButton(Target.TARGET_PLUS); TargetButton(Target.RELATIVE_PLUS); TargetButton(Target.PARALLEL_PLUS); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); TargetButton(Target.TARGET_MINUS); TargetButton(Target.RELATIVE_MINUS); TargetButton(Target.PARALLEL_MINUS); GUILayout.EndHorizontal(); ForceRoll(); } else { GUILayout.Label("Please select a target"); } break; case Mode.ADVANCED: GUILayout.Label("Reference:"); advReference = (AttitudeReference)GuiUtils.ComboBox.Box((int)advReference, ReferenceTexts, this); GUILayout.Label("Direction:"); advDirection = (Vector6.Direction)GuiUtils.ComboBox.Box((int)advDirection, directionTexts, directionTexts); ForceRoll(); if (GUILayout.Button("EXECUTE", btNormal, GUILayout.ExpandWidth(true))) { target = Target.ADVANCED; Engage(); } break; case Mode.AUTO: break; } GUILayout.EndVertical(); } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); if (GUILayout.Button("Reset")) { core.attitude.ResetConfig(); OnStart(PartModule.StartState.None); } core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GUILayout.BeginHorizontal(); GUILayout.Label("Tf (s)", GUILayout.ExpandWidth(true)); GUILayout.Label("P", GUILayout.ExpandWidth(false)); TfX.text = GUILayout.TextField(TfX.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.Label("Y", GUILayout.ExpandWidth(false)); TfY.text = GUILayout.TextField(TfY.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.Label("R", GUILayout.ExpandWidth(false)); TfZ.text = GUILayout.TextField(TfZ.text, GUILayout.ExpandWidth(true), GUILayout.Width(40)); GUILayout.EndHorizontal(); TfX = Math.Max(0.01, TfX); TfY = Math.Max(0.01, TfY); TfZ = Math.Max(0.01, TfZ); } else { GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.TfV), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); } GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); GuiUtils.SimpleTextBox("Deadband = ", deadband, "", 50); core.attitude.deadband = Math.Max(deadband, 0.0); core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); //Lower value of "kWlimit" reduces maximum angular velocity double kWlimit = core.attitude.kWlimit; var nextkWlimit = new EditableDoubleMult(kWlimit, 0.01); GuiUtils.SimpleTextBox("Maximum Relative Angular Velocity", nextkWlimit, "%"); nextkWlimit = (EditableDouble)GUILayout.HorizontalSlider((float)nextkWlimit, 0.0F, 1.0F); const int sliderPrecision = 3; if (Math.Round(Math.Abs(nextkWlimit - kWlimit), sliderPrecision) > 0) { core.attitude.kWlimit = Math.Round(nextkWlimit, sliderPrecision); } showInfos = GUILayout.Toggle(showInfos, "Show Numbers"); if (showInfos) { GUILayout.BeginHorizontal(); GUILayout.Label("Kp", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kp), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Ki", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Ki), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kd), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Error", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.error * Mathf.Rad2Deg), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Axis Control ", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.AxisState, "F0"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Torque", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + core.attitude.torque.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("torqueReactionSpeed", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vesselState.torqueReactionSpeed.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.torqueReactionSpeed), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Inertia", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + core.attitude.inertia.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, core.attitude.torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("MOI / torque", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + ratio.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(ratio), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("MOI", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vesselState.MoI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.MoI), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("MOI stock", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vessel.MOI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.MOI), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Angular Velocity", GUILayout.ExpandWidth(true)); GUILayout.Label("|" + vessel.angularVelocity.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.angularVelocity), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock"); MechJebModuleDebugArrows arrows = core.GetComputerModule <MechJebModuleDebugArrows>(); GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50); arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object"); GUILayout.BeginHorizontal(); arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false)); arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM"); arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)"); arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)"); arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)"); arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)"); arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (electric blue)"); //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)"); arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (gray)"); arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (magenta)"); arrows.debugArrow2Active = GUILayout.Toggle(arrows.debugArrow2Active, "Debug (light blue)"); GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.TfV.x != TfX || core.attitude.TfV.y != TfY || core.attitude.TfV.z != TfZ) { core.attitude.TfV.x = TfX; core.attitude.TfV.y = TfY; core.attitude.TfV.z = TfZ; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); } else { // pid.Kd = kpFactor / Tf; // pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf); // pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf); GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); } core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); showInfos = GUILayout.Toggle(showInfos, "Show Numbers"); if (showInfos) { GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label( core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = vesselState.torqueAvailable + vesselState.torqueFromEngine * vessel.ctrlState.mainThrottle; GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock"); MechJebModuleDebugArrows arrows = core.GetComputerModule<MechJebModuleDebugArrows>(); GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50); arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object"); GUILayout.BeginHorizontal(); arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false)); arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40)); GUILayout.EndHorizontal(); arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM"); arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)"); arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)"); arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)"); arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)"); arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)"); //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)"); arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)"); arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)"); GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.Tf != Tf) { core.attitude.Tf = Tf; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
// TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to public override void Drive(FlightCtrlState s) { // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up if (orbit.referenceBody != lastBody) { WaypointIndex = -1; Waypoints.Clear(); } MechJebRoverWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null); var curSpeed = vesselState.speedSurface; etaSpeed.value = curSpeed; if (wp != null && wp.Body == orbit.referenceBody) { if (controlHeading) { heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1); } if (controlSpeed) { var nextWP = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null)); var distance = Vector3.Distance(vessel.CoM, wp.Position); //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed); // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed : (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) : (distance - wp.Radius > 50 ? turnSpeed.val : 1))); minSpeed = (wp.Quicksave ? 0 : minSpeed); // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last) var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3); var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed); // reduce speed when turning a lot var radius = Math.Max(wp.Radius, 10 / 0.8); // alternative radius so negative radii can still make it go full speed through waypoints for navigation reasons if (distance < radius) { if (WaypointIndex + 1 >= Waypoints.Count) { // last waypoint newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min(); // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons if (LoopWaypoints) { WaypointIndex = 0; } else { newSpeed = -0.25; tgtSpeed.force(newSpeed); if (curSpeed < 0.85) { if (wp.Quicksave) { if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex = -1; controlHeading = controlSpeed = false; QuickSaveLoad.QuickSave(); } } else { WaypointIndex = -1; controlHeading = controlSpeed = false; } } // else { // Debug.Log("Is this even getting called?"); // WaypointIndex++; // } } } else { if (wp.Quicksave) { newSpeed = -0.25; tgtSpeed.force(newSpeed); if (curSpeed < 0.85) { if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex++; QuickSaveLoad.QuickSave(); } } } else { WaypointIndex++; } } } vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel) || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < 0.85 && newSpeed < 0.85)); // ^ brake if needed to prevent rolling, hopefully tgtSpeed.value = Math.Round(newSpeed, 1); } } if (controlHeading) { if (heading != headingLast) { headingPID.Reset(); headingLast = heading; } double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y; headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading); if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel) { float spd = Mathf.Min((float)speed, (float)turnSpeed); // if a slower speed than the turnspeed is used also be more careful with the steering float limit = (curSpeed <= turnSpeed ? 1 : Mathf.Clamp((float)((spd * spd) / (curSpeed * curSpeed)), 0.2f, 1f)); double act = headingPID.Compute(headingErr); s.wheelSteer = Mathf.Clamp((float)act, -limit, limit); } } // Brake if there is no controler (Pilot eject from seat) if (brakeOnEject && vessel.GetReferenceTransformPart() == null) { s.wheelThrottle = 0; vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); } else if (controlSpeed) { if (speed != speedLast) { speedPID.Reset(); speedLast = speed; } speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed.value) - Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.forward); if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel) { double act = speedPID.Compute(speedErr); s.wheelThrottle = Mathf.Clamp((float)act, -1, 1); } } }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label1"));//"No maneuver nodes to edit." RelativityModeSelectUI(); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) { node = vessel.patchedConicSolver.maneuverNodes[0]; } int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; if (nodeIndex < (numNodes - 1) && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button1"))) { MergeNext(nodeIndex); //"Merge next node" } } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) { gizmo.OnGizmoUpdated -= GizmoUpdateHandler; } gizmo = node.attachedGizmo; if (gizmo != null) { gizmo.OnGizmoUpdated += GizmoUpdateHandler; } } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label2"), prograde, "m/s", 60);//"Prograde:" if (LimitedRepeatButtoon("-")) { prograde -= progradeDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { prograde += progradeDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label3"), radialPlus, "m/s", 60);//"Radial+:" if (LimitedRepeatButtoon("-")) { radialPlus -= radialPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { radialPlus += radialPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label4"), normalPlus, "m/s", 60);//"Normal+:" if (LimitedRepeatButtoon("-")) { normalPlus -= normalPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { normalPlus += normalPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label5"), GUILayout.ExpandWidth(true));//"Set delta to:" if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.01; } if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.1; } if (GUILayout.Button("1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 1; } if (GUILayout.Button("10", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 10; } if (GUILayout.Button("100", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 100; } GUILayout.EndHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button2"))) { node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); //"Update" } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label6"), GUILayout.ExpandWidth(true));//"Shift time" if (GUILayout.Button("-o", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT - node.patch.period); } if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT - timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT + timeOffset); } if (GUILayout.Button("+o", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT + node.patch.period); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button3"), GUILayout.ExpandWidth(true)))//"Snap node to" { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(o.eccentricity < 1 ? UT - o.period / 2 : UT); break; case Snap.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT - o.period / 2); } break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); } break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); } break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; } node.UpdateNode(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); RelativityModeSelectUI(); if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button4")))//"Execute next node" { core.node.ExecuteOneNode(this); } if (MechJebModuleGuidanceController.isLoadedPrincipia && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button7")))//Execute next Principia node { core.node.ExecuteOnePNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button5")))//"Execute all nodes" { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button6")))//"Abort node execution" { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_NodeEd_checkbox1"), GUILayout.ExpandWidth(true)); //"Auto-warp" GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label7"), GUILayout.ExpandWidth(false)); //"Tolerance:" core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset(); } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this); } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll"); if (autopilot.forceRoll) { GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f); GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) s.onHover.textColor = s.onNormal.textColor = Color.green; autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true)); autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) sl.normal.textColor = sl.hover.textColor = Color.green; GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl); } GUILayout.EndHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) core.staging.AutostageSettingsInfoItem(); autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels"); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; autopilot.StartCountdown( vesselState.time + LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = "Launching at interplanetary window"; } else if (launchingToPlane) { desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { message = "Launching to rendezvous"; } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button("Abort")) launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } if (!vessel.patchedConicsUnlocked()) { GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station."); } MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>(); if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); GUILayout.EndVertical(); base.WindowGUI(windowID); }
void DriveCircularizationBurn(FlightCtrlState s) { if (placedCircularizeNode) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { MechJebModuleFlightRecorder recorder = core.GetComputerModule<MechJebModuleFlightRecorder>(); if (recorder != null) launchPhaseAngle = recorder.phaseAngleFromMark; //finished circularize this.users.Clear(); return; } } else { //place circularization node vessel.RemoveAllManeuverNodes(); double UT = orbit.NextApoapsisTime(vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); placedCircularizeNode = true; core.node.ExecuteOneNode(this); } if (core.node.burnTriggered) status = "Circularizing"; else status = "Coasting to circularization burn"; }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) { core.target.Unset(); } } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; lastTMinus = 999; } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; lastTMinus = 999; } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; lastTMinus = 999; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { double tMinus = 0; string message = ""; if (launchingToInterplanetary) { tMinus = interplanetaryWindowUT - vesselState.time; message = "Launching at interplanetary window"; } else if (launchingToPlane) { tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit); desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit); message = "Launching to rendezvous"; } double launchTime = vesselState.time + tMinus; if (tMinus < 3 * vesselState.deltaT || (tMinus > 10.0 && lastTMinus < 1.0)) { if (autopilot.enabled) { Staging.ActivateNextStage(); } launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } else { message += ": T-" + MuUtils.ToSI(tMinus, 0) + "s"; if (autopilot.enabled && core.node.autowarp) { core.warp.WarpToUT(launchTime - autopilot.warpCountDown); } } GUILayout.Label(message); lastTMinus = tMinus; if (GUILayout.Button("Abort")) { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>(); if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
public void setPIDParameters() { if (Tf < 2 * TimeWarp.fixedDeltaTime) Tf = 2 * TimeWarp.fixedDeltaTime; pid.Kd = 0.53 / Tf; pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf); pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) { core.target.Unset(); } } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.limitToPreventOverheats = GUILayout.Toggle(core.thrust.limitToPreventOverheats, "Prevent overheats"); core.thrust.limitToTerminalVelocity = GUILayout.Toggle(core.thrust.limitToTerminalVelocity, "Limit to terminal velocity"); GUILayout.BeginHorizontal(); core.thrust.limitAcceleration = GUILayout.Toggle(core.thrust.limitAcceleration, "Limit acceleration to", GUILayout.ExpandWidth(false)); core.thrust.maxAcceleration.text = GUILayout.TextField(core.thrust.maxAcceleration.text, GUILayout.ExpandWidth(true)); GUILayout.Label("m/s²", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); core.staging.AutostageInfoItem(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (!launchingToPlane && !launchingToRendezvous) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; } } else { launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToPlane || launchingToRendezvous) { double tMinus; if (launchingToPlane) { tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.Orbit); } else { tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.Orbit); } double launchTime = vesselState.time + tMinus; core.warp.WarpToUT(launchTime); if (launchingToPlane) { desiredInclination = core.target.Orbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.Orbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); } if (autopilot.enabled) { core.warp.WarpToUT(launchTime); } GUILayout.Label("Launching to " + (launchingToPlane ? "target plane" : "rendezvous") + ": T-" + MuUtils.ToSI(tMinus, 0) + "s"); if (tMinus < 3 * vesselState.deltaT) { if (autopilot.enabled) { Staging.ActivateNextStage(); } launchingToPlane = launchingToRendezvous = false; } if (GUILayout.Button("Abort")) { launchingToPlane = launchingToRendezvous = false; } } if (autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } } MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>(); if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
void GizmoUpdateHandler(Vector3d dV, double UT) { prograde = dV.z; radialPlus = dV.x; normalPlus = dV.y; }
protected override void WindowGUI(int windowID) { GUIStyle sty = new GUIStyle(GUI.skin.button); sty.normal.textColor = sty.focused.textColor = Color.white; sty.hover.textColor = sty.active.textColor = Color.yellow; sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = Color.green; sty.padding = new RectOffset(8, 8, 8, 8); GUILayout.BeginVertical(); if ((core.thrust.users.Count > 1) && !core.thrust.users.Contains(this)) { if (!autoMode) { windowPos = new Rect(windowPos.x, windowPos.y, 10, 10); autoMode = true; } sty.normal.textColor = Color.red; sty.onActive = sty.onFocused = sty.onHover = sty.onNormal = sty.active = sty.focused = sty.hover = sty.normal; GUILayout.Button("AUTO", sty, GUILayout.ExpandWidth(true)); } else { if (autoMode) { windowPos = new Rect(windowPos.x, windowPos.y, 10, 10); autoMode = false; } MechJebModuleThrustController.TMode newMode = (MechJebModuleThrustController.TMode)GUILayout.SelectionGrid((int)core.thrust.tmode, trans_texts, 2, sty); SetMode(newMode); float val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 -- would be better if it actually worked... core.thrust.trans_kill_h = GUILayout.Toggle(core.thrust.trans_kill_h, "Kill H/S", GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GuiUtils.SimpleTextBox("Speed", trans_spd, "", 37); bool change = false; if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { trans_spd -= val; change = true; } if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) { trans_spd = 0; change = true; } if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { trans_spd += val; change = true; } GUILayout.EndHorizontal(); if (GUILayout.Button("EXECUTE", sty, GUILayout.ExpandWidth(true)) || change) { core.thrust.trans_spd_act = (float)trans_spd.val; GUIUtility.keyboardControl = 0; } } if (core.thrust.tmode != MechJebModuleThrustController.TMode.OFF) { GUILayout.Label("Active speed: " + MuMech.MuUtils.ToSI(core.thrust.trans_spd_act) + "m/s", GUILayout.ExpandWidth(true)); } GUILayout.FlexibleSpace(); GUIStyle tsty = new GUIStyle(GUI.skin.label); tsty.alignment = TextAnchor.UpperCenter; GUILayout.Label("Automation", tsty, GUILayout.ExpandWidth(true)); sty.normal.textColor = sty.focused.textColor = sty.hover.textColor = sty.active.textColor = sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = (abort != AbortStage.OFF) ? Color.red : Color.green; if (GUILayout.Button((abort != AbortStage.OFF) ? "DON'T PANIC!" : "PANIC!!!", sty, GUILayout.ExpandWidth(true))) { PanicSwitch(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
string[] snapStrings = new string[] { Localizer.Format("#MechJeb_NodeEd_Snap1"), Localizer.Format("#MechJeb_NodeEd_Snap2"), Localizer.Format("#MechJeb_NodeEd_Snap3"), Localizer.Format("#MechJeb_NodeEd_Snap4"), Localizer.Format("#MechJeb_NodeEd_Snap5"), Localizer.Format("#MechJeb_NodeEd_Snap6") };//"periapsis""apoapsis""AN with target""DN with target""equatorial AN""equatorial DN" void GizmoUpdateHandler(Vector3d dV, double UT) { prograde = dV.z; radialPlus = dV.x; normalPlus = dV.y; }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto tunning"); if (!core.attitude.Tf_autoTune) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); } else { // pid.Kd = kpFactor / Tf; // pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf); // pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf); GUILayout.BeginHorizontal(); GUILayout.Label("Tf", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Tf range"); GuiUtils.SimpleTextBox("min", TfMin, "", 50); TfMin = Math.Max(TfMin, 0.01); GuiUtils.SimpleTextBox("max", TfMax, "", 50); TfMax = Math.Max(TfMax, 0.01); GUILayout.EndHorizontal(); GUILayout.Label("PID factors"); GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50); kdFactor = Math.Max(kdFactor, 0.01); GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50); kpFactor = Math.Max(kpFactor, 0.01); GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50); kiFactor = Math.Max(kiFactor, 0.01); } core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); core.rcs.rcsThrottle = GUILayout.Toggle(core.rcs.rcsThrottle, " RCS throttle when 0k thrust"); GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = new Vector3d( vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle, vesselState.torqueAvailable.y, vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle ); GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert()); GUILayout.BeginHorizontal(); GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true)); GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!core.attitude.Tf_autoTune) { if (core.attitude.Tf != Tf) { core.attitude.Tf = Tf; core.attitude.setPIDParameters(); } } else { if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax) { core.attitude.TfMin = TfMin; core.attitude.TfMax = TfMax; core.attitude.setPIDParameters(); } if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor) { core.attitude.kpFactor = kpFactor; core.attitude.kiFactor = kiFactor; core.attitude.kdFactor = kdFactor; core.attitude.setPIDParameters(); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem(); if (!core.attitude.useSAS) { GUILayout.Label("Larger ship do better with a larger Tf"); GuiUtils.SimpleTextBox("Tf (s)", Tf); Tf = Math.Max(0.01, Tf); core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode"); GUILayout.BeginHorizontal(); GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " + core.attitude.pid.Ki.ToString("F3") + ", " + core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("integral action.", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("PID Action", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true)); GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d torque = new Vector3d( vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle, vesselState.torqueAvailable.y, vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle ); GUILayout.BeginHorizontal(); GUILayout.Label("torque", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|torque|", GUILayout.ExpandWidth(true)); GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); Vector3d inertia = Vector3d.Scale( vesselState.angularMomentum.Sign(), Vector3d.Scale( Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum), Vector3d.Scale(torque, vesselState.MoI).Invert() ) ); GUILayout.BeginHorizontal(); GUILayout.Label("inertia", GUILayout.ExpandWidth(true)); GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true)); GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if ((core.attitude.Tf != Tf)) { core.attitude.Tf = Tf; double Kd = 0.53 / Tf; double Kp = Kd / (3 * Math.Sqrt(2) * Tf); double Ki = Kp / (12 * Math.Sqrt(2) * Tf); core.attitude.pid = new PIDControllerV2(Kp, Ki, Kd, 1, -1); } base.WindowGUI(windowID); }
public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to { // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now? if (orbit.referenceBody != lastBody) { WaypointIndex = -1; Waypoints.Clear(); } MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null); var brake = vessel.ActionGroups[KSPActionGroup.Brakes]; // keep brakes locked if they are curSpeed = Vector3d.Dot(vessel.srf_velocity, vesselState.forward); CalculateTraction(); speedIntAcc = speedPID.intAccum; if (wp != null && wp.Body == orbit.referenceBody) { if (ControlHeading) { heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1); } if (ControlSpeed) { var nextWP = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null)); var distance = Vector3.Distance(vessel.CoM, wp.Position); if (wp.Target != null) { distance += (float)(wp.Target.srfSpeed * curSpeed) / 2; } //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed); // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed : (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) : (distance - wp.Radius > 50 ? turnSpeed.val : 1))); minSpeed = (wp.Quicksave ? 1 : minSpeed); // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last) var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3); var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed); // reduce speed when turning a lot if (LimitAcceleration) { newSpeed = curSpeed + Mathf.Clamp((float)(newSpeed - curSpeed), -1.5f, 0.5f); } // newSpeed = tgtSpeed + Mathf.Clamp((float)(newSpeed - tgtSpeed), -Time.deltaTime * 8f, Time.deltaTime * 2f); var radius = Math.Max(wp.Radius, 10); if (distance < radius) { if (WaypointIndex + 1 >= Waypoints.Count) // last waypoint { newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min(); // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons if (LoopWaypoints) { WaypointIndex = 0; } else { newSpeed = 0; // tgtSpeed.force(newSpeed); if (curSpeed < brakeSpeedLimit) { if (wp.Quicksave) { //if (s.mainThrottle > 0) { s.mainThrottle = 0; } if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex = -1; ControlHeading = ControlSpeed = false; QuickSaveLoad.QuickSave(); } } else { WaypointIndex = -1; ControlHeading = ControlSpeed = false; } } // else { // Debug.Log("Is this even getting called?"); // WaypointIndex++; // } } } else { if (wp.Quicksave) { //if (s.mainThrottle > 0) { s.mainThrottle = 0; } newSpeed = 0; // tgtSpeed.force(newSpeed); if (curSpeed < brakeSpeedLimit) { if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) { WaypointIndex++; QuickSaveLoad.QuickSave(); } } } else { WaypointIndex++; } } } brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit); // ^ brake if needed to prevent rolling, hopefully tgtSpeed = (newSpeed >= 0 ? newSpeed : 0); } } if (ControlHeading) { headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1); double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y; headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading); if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel) { float spd = Mathf.Min((float)speed, (float)turnSpeed); // if a slower speed than the turnspeed is used also be more careful with the steering float limit = (Mathf.Abs((float)curSpeed) <= turnSpeed ? 1 : Mathf.Clamp((float)(spd / Mathf.Abs((float)curSpeed)), 0.35f, 1f)); double act = headingPID.Compute(headingErr); s.wheelSteer = Mathf.Clamp((float)act, -limit, limit); } } // Brake if there is no controler (Pilot eject from seat) if (BrakeOnEject && vessel.GetReferenceTransformPart() == null) { s.wheelThrottle = 0; // vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); brake = true; } else if (ControlSpeed) { speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5); speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vessel.srf_velocity, vesselState.forward); if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel) { float act = (float)speedPID.Compute(speedErr); s.wheelThrottle = !LimitAcceleration?Mathf.Clamp((float)act, -1, 1) : // I think I'm using these ( ? : ) a bit too much (traction == 0 ? 0 : (act < 0 ? Mathf.Clamp(act, -1f, 1f) : (lastThrottle + Mathf.Clamp(act - lastThrottle, -0.005f, 0.005f)) * (traction < tractionLimit ? -1 : 1))); if (curSpeed < 0 & s.wheelThrottle < 0) { s.wheelThrottle = 0; } // don't go backwards // if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0) { s.wheelThrottle = Mathf.Clamp(act, -1f, 1f); } if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) == 0) // StabilityControl && traction > 50 && // vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); { brake = true; } // else if (!stabilityControl || traction <= 50 || speedErr > -0.2 || Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { // vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel)); // } lastThrottle = s.wheelThrottle; } } if (StabilityControl) { if (!core.attitude.users.Contains(this)) { core.attitude.users.Add(this); // line.enabled = true; } // float scale = Vector3.Distance(FlightCamera.fetch.mainCamera.transform.position, vessel.CoM) / 900f; // line.SetPosition(0, vessel.CoM); // line.SetPosition(1, vessel.CoM + hit.normal * 5); // line.SetWidth(0, scale + 0.1f); var fSpeed = (float)curSpeed; // if (Mathf.Abs(fSpeed) >= turnSpeed * 0.75) { Vector3 fwd = (Vector3)(traction > 0 ? // V when the speed is low go for the vessels forward, else with a bit of velocity // ((Mathf.Abs(fSpeed) <= turnSpeed ? vesselState.forward : vessel.srf_velocity / 4) - vessel.transform.right * s.wheelSteer) * Mathf.Sign(fSpeed) : // // ^ and then add the steering vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering vessel.srf_velocity); // in the air so follow velocity Vector3.OrthoNormalize(ref norm, ref fwd); var quat = Quaternion.LookRotation(fwd, norm); // if (traction > 0 || speed <= turnSpeed) { // var u = new Vector3(0, 1, 0); // // var q = FlightGlobals.ship_rotation; // var q_s = quat; // // var q_u = new Quaternion(u.x, u.y, u.z, 0); // var a = Quaternion.Dot(q, q_s * q_u); // var q_qs = Quaternion.Dot(q, q_s); // var b = (a == 0) ? Math.Sign(q_qs) : (q_qs / a); // var g = b / Mathf.Sqrt((b * b) + 1); // var gu = Mathf.Sqrt(1 - (g * g)) * u; // var q_d = new Quaternion() { w = g, x = gu.x, y = gu.y, z = gu.z }; // var n = q_s * q_d; // // quat = n; // } core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this); // } } if (BrakeOnEnergyDepletion) { var batteries = vessel.Parts.FindAll(p => p.Resources.Contains("ElectricCharge") && p.Resources["ElectricCharge"].flowState); var energyLeft = batteries.Sum(p => p.Resources["ElectricCharge"].amount) / batteries.Sum(p => p.Resources["ElectricCharge"].maxAmount); var openSolars = vessel.mainBody.atmosphere && // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState != ModuleDeployableSolarPanel.panelStates.BROKEN && p.panelState != ModuleDeployableSolarPanel.panelStates.RETRACTED).Count > 0; if (openSolars && energyLeft > 0.99) { vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).ForEach(p => p.Retract()); } if (energyLeft < 0.05 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { s.wheelThrottle = 0; } // save remaining energy by not using it for acceleration if (openSolars || energyLeft < 0.03) { tgtSpeed = 0; } if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars)) { brake = true; } if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight && vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).Count > 0) { waitingForDaylight = true; } } // brake = brake && (s.wheelThrottle == 0); // release brake if the user or AP want to drive if (s.wheelThrottle != 0 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { brake = false; // the AP or user want to drive into the direction of momentum so release the brake } if (vessel.isActiveVessel) { if (GameSettings.BRAKES.GetKeyUp()) { brake = false; // release the brakes if the user lets go of them } if (GameSettings.BRAKES.GetKey()) { brake = true; // brake if the user brakes and we aren't about to flip } } tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100); vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && curSpeed > brakeSpeedLimit ? traction >= tractionLimit : true)); // ^ brake but hopefully prevent flipping over, assuming the user set up the limit right if (brake && curSpeed < 0.1) { s.wheelThrottle = 0; } }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset(); } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this); } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) core.staging.AutostageSettingsInfoItem(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; lastTMinus = 999; } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; lastTMinus = 999; } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; lastTMinus = 999; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { double tMinus = 0; string message = ""; if (launchingToInterplanetary) { tMinus = interplanetaryWindowUT - vesselState.time; message = "Launching at interplanetary window"; } else if (launchingToPlane) { tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit); desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit); message = "Launching to rendezvous"; } double launchTime = vesselState.time + tMinus; if (tMinus < 3 * vesselState.deltaT || (tMinus > 10.0 && lastTMinus < 1.0)) { if (autopilot.enabled) Staging.ActivateNextStage(); launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } else { message += ": T-" + MuUtils.ToSI(tMinus, 0) + "s"; if (autopilot.enabled && core.node.autowarp) core.warp.WarpToUT(launchTime - autopilot.warpCountDown); } GUILayout.Label(message); lastTMinus = tMinus; if (GUILayout.Button("Abort")) launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>(); if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); GUILayout.EndVertical(); base.WindowGUI(windowID); }