void DriveAscent(FlightCtrlState s) { if (timedLaunch) { status = Localizer.Format("#MechJeb_Ascent_status6");//"Awaiting liftoff" Log.dbg("Awaiting Liftoff"); // kill the optimizer if it is running. core.guidance.enabled = false; core.attitude.AxisControl(false, false, false); return; } DriveDeployableComponents(s); if (ascentPath.DriveAscent(s)) { Log.detail("Remaining in Ascent"); status = ascentPath.status; } else { Log.detail("Ascend -> Circularize"); mode = AscentMode.CIRCULARIZE; } }
private void handleStageEvent(int data) { if (!enabled || stages.Count == 0) { return; } while (stages[0].ksp_stage > (vessel.currentStage - 1)) { // we did drop a relevant stage stageCount += 1; stages[0].staged = true; stages.RemoveAt(0); Log.detail("[MechJebModuleLogicalStageTracking] dropping a stage"); } }
public void Update() { if (lastTime == Planetarium.GetUniversalTime()) { return; } core.stageStats.RequestUpdate(this, true); int j = 0; for (int i = core.stageStats.vacStats.Length - 1; i >= 0; i--) { var stats = core.stageStats.vacStats[i]; // FIXME: either tweakability or identify ullage + sep motors correctly if (stats.deltaV < 20) { if (!(j == 0 && stages.Count > 0 && stages[0].ksp_stage == i)) // check if we're just burning down the current stage { continue; } } if (j >= stages.Count) { Log.detail("[MechJebModuleLogicalStageTracking] adding a new stage: " + j); stages.Add(new Stage(this)); } stages[j].ksp_stage = i; stages[j].rocket_stage = j + stageCount; stages[j].Sync(); j++; } while (stages.Count > core.stageStats.vacStats.Length) { Log.detail("[MechJebModuleLogicalStageTracking] upper stage disappeared (user reconfig most likely)"); stages.RemoveAt(stages.Count - 1); } lastTime = Planetarium.GetUniversalTime(); }
public override void Drive(FlightCtrlState s) { float threshold = 0.1F; bool _userCommandingRotation = !(Mathfx.Approx(s.pitch, s.pitchTrim, threshold) && Mathfx.Approx(s.yaw, s.yawTrim, threshold) && Mathfx.Approx(s.roll, s.rollTrim, threshold)); bool _userCommandingTranslation = !(Math.Abs(s.X) < threshold && Math.Abs(s.Y) < threshold && Math.Abs(s.Z) < threshold); if (_userCommandingRotation && !_userCommandingTranslation) { userCommandingRotationSmoothed = 2; } else if (userCommandingRotationSmoothed > 0) { userCommandingRotationSmoothed--; } if (core.GetComputerModule <MechJebModuleThrustWindow>().hidden&& core.GetComputerModule <MechJebModuleAscentGuidance>().hidden) { return; } if ((tmode != TMode.OFF) && (vesselState.thrustAvailable > 0)) { double spd = 0; switch (tmode) { case TMode.KEEP_ORBITAL: spd = vesselState.speedOrbital; break; case TMode.KEEP_SURFACE: spd = vesselState.speedSurface; break; case TMode.KEEP_VERTICAL: spd = vesselState.speedVertical; Vector3d rot = Vector3d.up; if (trans_kill_h) { Vector3 hsdir = Vector3.ProjectOnPlane(vesselState.surfaceVelocity, vesselState.up); Vector3 dir = -hsdir + vesselState.up * Math.Max(Math.Abs(spd), 20 * mainBody.GeeASL); if ((Math.Min(vesselState.altitudeASL, vesselState.altitudeTrue) > 5000) && (hsdir.magnitude > Math.Max(Math.Abs(spd), 100 * mainBody.GeeASL) * 2)) { tmode = TMode.DIRECT; trans_spd_act = 100; rot = -hsdir; } else { rot = dir.normalized; } core.attitude.attitudeTo(rot, AttitudeReference.INERTIAL, null); } break; } double t_err = (trans_spd_act - spd) / vesselState.maxThrustAccel; if ((tmode == TMode.KEEP_ORBITAL && Vector3d.Dot(vesselState.forward, vesselState.orbitalVelocity) < 0) || (tmode == TMode.KEEP_SURFACE && Vector3d.Dot(vesselState.forward, vesselState.surfaceVelocity) < 0)) { //allow thrust to declerate t_err *= -1; } double t_act = pid.Compute(t_err); if ((tmode != TMode.KEEP_VERTICAL) || !trans_kill_h || (core.attitude.attitudeError < 2) || ((Math.Min(vesselState.altitudeASL, vesselState.altitudeTrue) < 1000) && (core.attitude.attitudeError < 90))) { if (tmode == TMode.DIRECT) { trans_prev_thrust = targetThrottle = trans_spd_act / 100.0F; } else { trans_prev_thrust = targetThrottle = Mathf.Clamp01(trans_prev_thrust + (float)t_act); } } else { bool useGimbal = (vesselState.torqueGimbal.positive.x > vesselState.torqueAvailable.x * 10) || (vesselState.torqueGimbal.positive.z > vesselState.torqueAvailable.z * 10); bool useDiffThrottle = (vesselState.torqueDiffThrottle.x > vesselState.torqueAvailable.x * 10) || (vesselState.torqueDiffThrottle.z > vesselState.torqueAvailable.z * 10); if ((core.attitude.attitudeError >= 2) && (useGimbal || (useDiffThrottle && core.thrust.differentialThrottle))) { trans_prev_thrust = targetThrottle = 0.1F; Log.detail(" targetThrottle = 0.1F"); } else { trans_prev_thrust = targetThrottle = 0; } } } // Only set throttle if a module need it. Otherwise let the user or other mods set it // There is always at least 1 user : the module itself (why ?) if (users.Count > 1) { s.mainThrottle = targetThrottle; } throttleLimit = 1; throttleFixedLimit = 1; limiter = LimitMode.None; if (limitThrottle) { if (maxThrottle < throttleLimit) { setFixedLimit((float)maxThrottle, LimitMode.Throttle); } } if (limitToTerminalVelocity) { float limit = TerminalVelocityThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.TerminalVelocity); } } if (limitDynamicPressure) { float limit = MaximumDynamicPressureThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.DynamicPressure); } } if (limitToPreventOverheats) { float limit = (float)TemperatureSafetyThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.Temperature); } } if (limitAcceleration) { float limit = AccelerationLimitedThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.Acceleration); } } if (electricThrottle && ElectricEngineRunning()) { float limit = ElectricThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.Electric); } } if (limitToPreventFlameout) { // This clause benefits being last: if we don't need much air // due to prior limits, we can close some intakes. float limit = FlameoutSafetyThrottle(); if (limit < throttleLimit) { setFixedLimit(limit, LimitMode.Flameout); } } // Any limiters which can limit to non-zero values must come before this, any // limiters (like ullage) which enforce zero throttle should come after. The // minThrottle setting has authority over any other limiter that sets non-zero throttle. if (limiterMinThrottle && limiter != LimitMode.None) { if (minThrottle > throttleFixedLimit) { setFixedLimit((float)minThrottle, LimitMode.MinThrottle); } if (minThrottle > throttleLimit) { setTempLimit((float)minThrottle, LimitMode.MinThrottle); } } /* auto-RCS ullaging up to very stable */ if (autoRCSUllaging && s.mainThrottle > 0.0F && throttleLimit > 0.0F) { if (vesselState.lowestUllage < VesselState.UllageState.VeryStable) { Log.info("RCS auto-ullaging: found state below very stable: {0}", vesselState.lowestUllage); if (vessel.hasEnabledRCSModules()) { if (!vessel.ActionGroups[KSPActionGroup.RCS]) { Log.info("RCS auto-ullaging: enabling RCS action group for automatic ullaging"); vessel.ActionGroups.SetGroup(KSPActionGroup.RCS, true); } Log.info("RCS auto-ullaging: firing RCS to stabilize ulllage"); setTempLimit(0.0F, LimitMode.UnstableIgnition); s.Z = -1.0F; } else { Log.info("RCS auto-ullaging: vessel has no enabled/staged RCS modules"); } } } /* prevent unstable ignitions */ if (limitToPreventUnstableIgnition && s.mainThrottle > 0.0F && throttleLimit > 0.0F) { if (vesselState.lowestUllage < VesselState.UllageState.Stable) { ScreenMessages.PostScreenMessage(preventingUnstableIgnitionsMessage); Log.info("Unstable Ignitions: preventing ignition in state: {0}", vesselState.lowestUllage); setTempLimit(0.0F, LimitMode.UnstableIgnition); } } // we have to force the throttle here so that rssMode can work, otherwise we don't get our last throttle command // back on the next tick after disabling. we save this before applying the throttle limits so that we preserve // the requested throttle, and not the limited throttle. if (core.rssMode) { SetFlightGlobals(s.mainThrottle); } if (double.IsNaN(throttleLimit)) { throttleLimit = 1.0F; } throttleLimit = Mathf.Clamp01(throttleLimit); /* we do not _apply_ the "fixed" limit, the actual throttleLimit should always be the more limited and lower one */ /* the purpose of the "fixed" limit is for external consumers like the node executor to consume */ if (double.IsNaN(throttleFixedLimit)) { throttleFixedLimit = 1.0F; } throttleFixedLimit = Mathf.Clamp01(throttleFixedLimit); vesselState.throttleLimit = throttleLimit; vesselState.throttleFixedLimit = throttleFixedLimit; if (s.mainThrottle < throttleLimit) { limiter = LimitMode.None; } s.mainThrottle = Mathf.Min(s.mainThrottle, throttleLimit); if (smoothThrottle) { s.mainThrottle = SmoothThrottle(s.mainThrottle); } if (double.IsNaN(s.mainThrottle)) { s.mainThrottle = 0; } s.mainThrottle = Mathf.Clamp01(s.mainThrottle); if (s.Z == 0 && core.rcs.rcsThrottle && vesselState.rcsThrust) { s.Z = -s.mainThrottle; } lastThrottle = s.mainThrottle; if (!core.attitude.enabled) { Vector3d act = new Vector3d(s.pitch, s.yaw, s.roll); differentialThrottleDemandedTorque = -Vector3d.Scale(act.xzy, vesselState.torqueDiffThrottle * s.mainThrottle * 0.5f); } }
public void SetupToolBarButtons() { if (!ToolbarManager.ToolbarAvailable) { return; } SetupMainToolbarButton(); foreach (DisplayModule module in core.GetDisplayModules(DisplayOrder.instance).Where(m => !m.hidden)) { Button button; if (!toolbarButtons.ContainsKey(module)) { Log.detail("Create button for module {0}", module.GetName()); String name = GetCleanName(module.GetName()); String TexturePath = "MechJeb2/Icons/" + name; String TexturePathActive = TexturePath + "_active"; button = new Button(); button.button = ToolbarManager.Instance.add("MechJeb2", name); if (GameDatabase.Instance.GetTexture(TexturePath, false) == null) { button.texturePath = Qmark; Log.info("No icon for {0}", name); } else { button.texturePath = TexturePath; } if (GameDatabase.Instance.GetTexture(TexturePathActive, false) == null) { button.texturePathActive = TexturePath; Log.dbg("No icon for {0}_active", name); } else { button.texturePathActive = TexturePathActive; } toolbarButtons[module] = button; button.button.ToolTip = "MechJeb " + module.GetName(); button.button.OnClick += (b) => { DisplayModule mod = FlightGlobals.ActiveVessel.GetMasterMechJeb().GetDisplayModules(DisplayOrder.instance).FirstOrDefault(m => m == module); if (mod != null) { mod.enabled = !mod.enabled; } }; } else { button = toolbarButtons[module]; } button.button.Visible = module.showInCurrentScene; button.button.TexturePath = module.isActive() ? button.texturePathActive : button.texturePath; } // create toolbar buttons for features if (featureButtons.Count == 0) { var maneuverPlannerModule = core.GetComputerModule <MechJebModuleManeuverPlanner>(); if (!HighLogic.LoadedSceneIsEditor && maneuverPlannerModule != null && !maneuverPlannerModule.hidden) { CreateFeatureButton(maneuverPlannerModule, "Exec_Node", "MechJeb Execute Next Node", (b) => { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && core.node != null) { if (core.node.enabled) { core.node.Abort(); } else { if (vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude > 0.0001) { core.node.ExecuteOneNode(maneuverPlannerModule); } else { ScreenMessages.PostScreenMessage("Maneuver burn vector not set", 3f); } } } else { ScreenMessages.PostScreenMessage("No maneuver nodes", 2f); } }, () => vessel.patchedConicSolver.maneuverNodes.Count > 0 && core.node != null && core.node.enabled); CreateFeatureButton(maneuverPlannerModule, "Autostage_Once", "MechJeb Autostage Once", (b) => { var w = core.GetComputerModule <MechJebModuleThrustWindow>(); if (core.staging.enabled && core.staging.autostagingOnce) { if (core.staging.users.Contains(w)) { core.staging.users.Remove(w); w.autostageSavedState = false; } } else { core.staging.AutostageOnce(w); } }, () => core.staging.enabled && core.staging.autostagingOnce); CreateFeatureButton(maneuverPlannerModule, "Auto_Warp", "MechJeb Auto-warp", (b) => { core.node.autowarp = !core.node.autowarp; }, () => core.node.autowarp); } } }