public override void OnFixedUpdate() { if (markUT == 0) { Mark(); } timeSinceMark = vesselState.time - markUT; if (vessel.situation == Vessel.Situations.PRELAUNCH) { Mark(); //keep resetting stats until we launch return; } gravityLosses += vesselState.deltaT * Vector3d.Dot(-vessel.srf_velocity.normalized, vesselState.gravityForce); gravityLosses -= vesselState.deltaT * Vector3d.Dot(vessel.srf_velocity.normalized, vesselState.up * vesselState.radius * Math.Pow(2 * Math.PI / part.vessel.mainBody.rotationPeriod, 2)); double dragAccel = mainBody.DragAccel(vesselState.CoM, vessel.obt_velocity, vesselState.massDrag / vesselState.mass).magnitude; dragLosses += vesselState.deltaT * dragAccel; maxDragGees = Math.Max(maxDragGees, dragAccel / 9.81); double circularPeriod = 2 * Math.PI * vesselState.radius / OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, vesselState.radius); double angleTraversed = (vesselState.longitude - markLongitude) + 360 * (vesselState.time - markUT) / part.vessel.mainBody.rotationPeriod; phaseAngleFromMark = MuUtils.ClampDegrees360(360 * (vesselState.time - markUT) / circularPeriod - angleTraversed); }
public override void OnFixedUpdate() { if (markUT == 0) { Mark(); } timeSinceMark = vesselState.time - markUT; if (vessel.situation == Vessel.Situations.PRELAUNCH) { Mark(); //keep resetting stats until we launch return; } if (vesselState.currentThrustAccel > 0) { gravityLosses += vesselState.deltaT * Vector3d.Dot(-vesselState.orbitalVelocity.normalized, vesselState.gravityForce); } dragLosses += vesselState.deltaT * vesselState.drag; deltaVExpended += vesselState.deltaT * vesselState.currentThrustAccel; steeringLosses += vesselState.deltaT * vesselState.currentThrustAccel * (1 - Vector3d.Dot(vesselState.orbitalVelocity.normalized, vesselState.forward)); maxDragGees = Math.Max(maxDragGees, vesselState.drag / 9.81); double circularPeriod = 2 * Math.PI * vesselState.radius / OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, vesselState.radius); double angleTraversed = (vesselState.longitude - markLongitude) + 360 * (vesselState.time - markUT) / part.vessel.mainBody.rotationPeriod; phaseAngleFromMark = MuUtils.ClampDegrees360(360 * (vesselState.time - markUT) / circularPeriod - angleTraversed); if (paused) { return; } //int oldHistoryIdx = historyIdx; //historyIdx = Mathf.Min(Mathf.FloorToInt((float)(timeSinceMark / precision)), history.Length - 1); if (vesselState.time >= (lastRecordTime + precision) && historyIdx < history.Length - 1) { lastRecordTime = vesselState.time; historyIdx++; Record(historyIdx); #if DEBUG if (TimeWarp.WarpMode == TimeWarp.Modes.HIGH) { Log.dbg("WRP {0} {1:0} {2:0.00}", historyIdx, history[historyIdx].downRange, history[historyIdx].AoA); } else { Log.dbg("STD {0} {1:0} {2:0.00}", historyIdx, history[historyIdx].downRange, history[historyIdx].AoA); } #endif } }
public override void OnFixedUpdate() { if (markUT == 0) { Mark(); } timeSinceMark = vesselState.time - markUT; if (vessel.situation == Vessel.Situations.PRELAUNCH) { Mark(); //keep resetting stats until we launch return; } gravityLosses += vesselState.deltaT * Vector3d.Dot(-vesselState.surfaceVelocity.normalized, vesselState.gravityForce); gravityLosses -= vesselState.deltaT * Vector3d.Dot(vesselState.surfaceVelocity.normalized, vesselState.up * vesselState.radius * Math.Pow(2 * Math.PI / part.vessel.mainBody.rotationPeriod, 2)); dragLosses += vesselState.deltaT * vesselState.drag; maxDragGees = Math.Max(maxDragGees, vesselState.drag / 9.81); double circularPeriod = 2 * Math.PI * vesselState.radius / OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, vesselState.radius); double angleTraversed = (vesselState.longitude - markLongitude) + 360 * (vesselState.time - markUT) / part.vessel.mainBody.rotationPeriod; phaseAngleFromMark = MuUtils.ClampDegrees360(360 * (vesselState.time - markUT) / circularPeriod - angleTraversed); if (paused) { return; } //int oldHistoryIdx = historyIdx; //historyIdx = Mathf.Min(Mathf.FloorToInt((float)(timeSinceMark / precision)), history.Length - 1); if (vesselState.time >= (lastRecordTime + precision) && historyIdx < history.Length - 1) { lastRecordTime = vesselState.time; historyIdx++; Record(historyIdx); //if (TimeWarp.WarpMode == TimeWarp.Modes.HIGH) // print("WRP " + historyIdx + " " + history[historyIdx].downRange.ToString("F0") + " " + history[historyIdx].AoA.ToString("F2")); //else //{ // print("STD " + historyIdx + " " + history[historyIdx].downRange.ToString("F0") + " " + history[historyIdx].AoA.ToString("F2")); //} } }
void DriveCoastToApoapsis(FlightCtrlState s) { core.thrust.targetThrottle = 0; double circularSpeed = OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, orbit.ApR); double apoapsisSpeed = orbit.SwappedOrbitalVelocityAtUT(orbit.NextApoapsisTime(vesselState.time)).magnitude; double circularizeBurnTime = (circularSpeed - apoapsisSpeed) / vesselState.limitedMaxThrustAccel; //Once we get above the atmosphere, plan and execute the circularization maneuver. //For orbits near the edge of the atmosphere, we can't wait until we break the atmosphere //to start the burn, so we also compare the timeToAp with the expected circularization burn time. //if ((vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) // || (vesselState.limitedMaxThrustAccel > 0 && orbit.timeToAp < circularizeBurnTime / 1.8)) // Sarbian : removed the special case for now. Some ship where turning whil still in atmosphere if (vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) { mode = AscentMode.CIRCULARIZE; core.warp.MinimumWarp(); return; } //if our apoapsis has fallen too far, resume the gravity turn if (orbit.ApA < desiredOrbitAltitude - 1000.0) { mode = AscentMode.GRAVITY_TURN; core.warp.MinimumWarp(); return; } //point prograde and thrust gently if our apoapsis falls below the target core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.ORBIT, this); core.thrust.targetThrottle = 0; if (autoThrottle && orbit.ApA < desiredOrbitAltitude) { core.thrust.targetThrottle = ThrottleToRaiseApoapsis(orbit.ApR, desiredOrbitAltitude + mainBody.Radius); } if (core.node.autowarp) { //warp at x2 physical warp: core.warp.WarpPhysicsAtRate(2); } status = "Coasting to edge of atmosphere"; }
void DriveCoastToApoapsis(FlightCtrlState s) { core.thrust.targetThrottle = 0; double circularSpeed = OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, orbit.ApR); double apoapsisSpeed = orbit.SwappedOrbitalVelocityAtUT(orbit.NextApoapsisTime(vesselState.time)).magnitude; double circularizeBurnTime = (circularSpeed - apoapsisSpeed) / vesselState.limitedMaxThrustAccel; if (vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) { mode = AscentMode.EXIT; core.warp.MinimumWarp(); return; } //if our apoapsis has fallen too far, resume the gravity turn if (orbit.ApA < autopilot.desiredOrbitAltitude - 1000.0) { mode = AscentMode.HOLD_AP; core.warp.MinimumWarp(); return; } core.thrust.targetThrottle = 0; // follow surface velocity to reduce flipping attitudeTo(srfvelPitch()); if (autopilot.autoThrottle && orbit.ApA < autopilot.desiredOrbitAltitude) { core.warp.WarpPhysicsAtRate(1); core.thrust.targetThrottle = ThrottleToRaiseApoapsis(orbit.ApR, autopilot.desiredOrbitAltitude + mainBody.Radius); } else { if (core.node.autowarp) { //warp at x2 physical warp: core.warp.WarpPhysicsAtRate(2); } } status = "Coasting to edge of atmosphere"; }
void DriveCoastToApoapsis(FlightCtrlState s) { core.thrust.targetThrottle = 0; double circularSpeed = OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, orbit.ApR); double apoapsisSpeed = orbit.SwappedOrbitalVelocityAtUT(orbit.NextApoapsisTime(vesselState.time)).magnitude; double circularizeBurnTime = (circularSpeed - apoapsisSpeed) / vesselState.limitedMaxThrustAccel; //Once we get above the atmosphere, plan and execute the circularization maneuver. //For orbits near the edge of the atmosphere, we can't wait until we break the atmosphere //to start the burn, so we also compare the timeToAp with the expected circularization burn time. //if ((vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) // || (vesselState.limitedMaxThrustAccel > 0 && orbit.timeToAp < circularizeBurnTime / 1.8)) // Sarbian : removed the special case for now. Some ship where turning while still in atmosphere if (vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) { if (core.solarpanel.autodeploySolarPanels) { core.solarpanel.ExtendAll(); } mode = AscentMode.CIRCULARIZE; core.warp.MinimumWarp(); return; } //if our apoapsis has fallen too far, resume the gravity turn if (orbit.ApA < desiredOrbitAltitude - 1000.0) { mode = AscentMode.GRAVITY_TURN; core.warp.MinimumWarp(); return; } //point prograde and thrust gently if our apoapsis falls below the target //core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.ORBIT, this); // Actually I have a better idea: Don't initiate orientation changes when there's a chance that our main engine // might reignite. There won't be enough control authority to counteract that much momentum change. // - Starwaster core.thrust.targetThrottle = 0; double desiredHeading = Math.PI / 180 * OrbitalManeuverCalculator.HeadingForInclination(desiredInclination, vesselState.latitude); Vector3d desiredHeadingVector = Math.Sin(desiredHeading) * vesselState.east + Math.Cos(desiredHeading) * vesselState.north; double desiredFlightPathAngle = ascentPath.FlightPathAngle(vesselState.altitudeASL); Vector3d desiredThrustVector = Math.Cos(desiredFlightPathAngle * Math.PI / 180) * desiredHeadingVector + Math.Sin(desiredFlightPathAngle * Math.PI / 180) * vesselState.up; core.attitude.attitudeTo(desiredThrustVector.normalized, AttitudeReference.INERTIAL, this); if (autoThrottle && orbit.ApA < desiredOrbitAltitude) { core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.INERTIAL, this); core.thrust.targetThrottle = ThrottleToRaiseApoapsis(orbit.ApR, desiredOrbitAltitude + mainBody.Radius); } if (core.node.autowarp) { //warp at x2 physical warp: core.warp.WarpPhysicsAtRate(2); } status = "Coasting to edge of atmosphere"; }
public override void OnFixedUpdate() { if (NavBallGuidance && autopilot != null && autopilot.ascentPath != null) { double angle = Math.PI / 180 * autopilot.ascentPath.FlightPathAngle(vesselState.altitudeASL, vesselState.speedSurface); double heading = Math.PI / 180 * OrbitalManeuverCalculator.HeadingForLaunchInclination(vessel.mainBody, autopilot.desiredInclination, launchLatitude, OrbitalManeuverCalculator.CircularOrbitSpeed(vessel.mainBody, autopilot.desiredOrbitAltitude + mainBody.Radius)); Vector3d horizontalDir = Math.Cos(heading) * vesselState.north + Math.Sin(heading) * vesselState.east; Vector3d dir = Math.Cos(angle) * horizontalDir + Math.Sin(angle) * vesselState.up; core.target.UpdateDirectionTarget(dir); } }
//Computes the time and delta-V of an ejection burn to a Hohmann transfer from one planet to another. //It's assumed that the initial orbit around the first planet is circular, and that this orbit //is in the same plane as the orbit of the first planet around the sun. It's also assumed that //the target planet has a fairly low relative inclination with respect to the first planet. If the //inclination change is nonzero you should also do a mid-course correction burn, as computed by //DeltaVForCourseCorrection. public static Vector3d DeltaVAndTimeForInterplanetaryLambertTransferEjection(Orbit o, double UT, Orbit target, out double burnUT) { Orbit planetOrbit = o.referenceBody.orbit; //Compute the time and dV for a Hohmann transfer where we pretend that we are the planet we are orbiting. //This gives us the "ideal" deltaV and UT of the ejection burn, if we didn't have to worry about waiting for the right //ejection angle and if we didn't have to worry about the planet's gravity dragging us back and increasing the required dV. double idealBurnUT; Vector3d idealDeltaV; //time the ejection burn to intercept the target //idealDeltaV = DeltaVAndTimeForHohmannTransfer(planetOrbit, target, UT, out idealBurnUT); double vesselOrbitVelocity = OrbitalManeuverCalculator.CircularOrbitSpeed(o.referenceBody, o.semiMajorAxis); idealDeltaV = DeltaVAndTimeForHohmannLambertTransfer(planetOrbit, target, UT, out idealBurnUT, vesselOrbitVelocity); Debug.Log("idealBurnUT = " + idealBurnUT + ", idealDeltaV = " + idealDeltaV); //Compute the actual transfer orbit this ideal burn would lead to. Orbit transferOrbit = planetOrbit.PerturbedOrbit(idealBurnUT, idealDeltaV); //Now figure out how to approximately eject from our current orbit into the Hohmann orbit we just computed. //Assume we want to exit the SOI with the same velocity as the ideal transfer orbit at idealUT -- i.e., immediately //after the "ideal" burn we used to compute the transfer orbit. This isn't quite right. //We intend to eject from our planet at idealUT and only several hours later will we exit the SOI. Meanwhile //the transfer orbit will have acquired a slightly different velocity, which we should correct for. Maybe //just add in (1/2)(sun gravity)*(time to exit soi)^2 ? But how to compute time to exit soi? Or maybe once we //have the ejection orbit we should just move the ejection burn back by the time to exit the soi? Vector3d soiExitVelocity = idealDeltaV; Debug.Log("soiExitVelocity = " + (Vector3)soiExitVelocity); //compute the angle by which the trajectory turns between periapsis (where we do the ejection burn) //and SOI exit (approximated as radius = infinity) double soiExitEnergy = 0.5 * soiExitVelocity.sqrMagnitude - o.referenceBody.gravParameter / o.referenceBody.sphereOfInfluence; double ejectionRadius = o.semiMajorAxis; //a guess, good for nearly circular orbits Debug.Log("soiExitEnergy = " + soiExitEnergy); Debug.Log("ejectionRadius = " + ejectionRadius); double ejectionKineticEnergy = soiExitEnergy + o.referenceBody.gravParameter / ejectionRadius; double ejectionSpeed = Math.Sqrt(2 * ejectionKineticEnergy); Debug.Log("ejectionSpeed = " + ejectionSpeed); //construct a sample ejection orbit Vector3d ejectionOrbitInitialVelocity = ejectionSpeed * (Vector3d)o.referenceBody.transform.right; Vector3d ejectionOrbitInitialPosition = o.referenceBody.position + ejectionRadius * (Vector3d)o.referenceBody.transform.up; Orbit sampleEjectionOrbit = MuUtils.OrbitFromStateVectors(ejectionOrbitInitialPosition, ejectionOrbitInitialVelocity, o.referenceBody, 0); double ejectionOrbitDuration = sampleEjectionOrbit.NextTimeOfRadius(0, o.referenceBody.sphereOfInfluence); Vector3d ejectionOrbitFinalVelocity = sampleEjectionOrbit.SwappedOrbitalVelocityAtUT(ejectionOrbitDuration); double turningAngle = Vector3d.Angle(ejectionOrbitInitialVelocity, ejectionOrbitFinalVelocity); Debug.Log("turningAngle = " + turningAngle); //sine of the angle between the vessel orbit and the desired SOI exit velocity double outOfPlaneAngle = (Math.PI / 180) * (90 - Vector3d.Angle(soiExitVelocity, o.SwappedOrbitNormal())); Debug.Log("outOfPlaneAngle (rad) = " + outOfPlaneAngle); double coneAngle = Math.PI / 2 - (Math.PI / 180) * turningAngle; Debug.Log("coneAngle (rad) = " + coneAngle); Vector3d exitNormal = Vector3d.Cross(-soiExitVelocity, o.SwappedOrbitNormal()).normalized; Vector3d normal2 = Vector3d.Cross(exitNormal, -soiExitVelocity).normalized; //unit vector pointing to the spot on our orbit where we will burn. //fails if outOfPlaneAngle > coneAngle. Vector3d ejectionPointDirection = Math.Cos(coneAngle) * (-soiExitVelocity.normalized) + Math.Cos(coneAngle) * Math.Tan(outOfPlaneAngle) * normal2 - Math.Sqrt(Math.Pow(Math.Sin(coneAngle), 2) - Math.Pow(Math.Cos(coneAngle) * Math.Tan(outOfPlaneAngle), 2)) * exitNormal; Debug.Log("soiExitVelocity = " + (Vector3)soiExitVelocity); Debug.Log("vessel orbit normal = " + (Vector3)(1000 * o.SwappedOrbitNormal())); Debug.Log("exitNormal = " + (Vector3)(1000 * exitNormal)); Debug.Log("normal2 = " + (Vector3)(1000 * normal2)); Debug.Log("ejectionPointDirection = " + ejectionPointDirection); double ejectionTrueAnomaly = o.TrueAnomalyFromVector(ejectionPointDirection); burnUT = o.TimeOfTrueAnomaly(ejectionTrueAnomaly, idealBurnUT - o.period); if ((idealBurnUT - burnUT > o.period / 2) || (burnUT < UT)) { burnUT += o.period; } Vector3d ejectionOrbitNormal = Vector3d.Cross(ejectionPointDirection, soiExitVelocity).normalized; Debug.Log("ejectionOrbitNormal = " + ejectionOrbitNormal); Vector3d ejectionBurnDirection = Quaternion.AngleAxis(-(float)(turningAngle), ejectionOrbitNormal) * soiExitVelocity.normalized; Debug.Log("ejectionBurnDirection = " + ejectionBurnDirection); Vector3d ejectionVelocity = ejectionSpeed * ejectionBurnDirection; Vector3d preEjectionVelocity = o.SwappedOrbitalVelocityAtUT(burnUT); return(ejectionVelocity - preEjectionVelocity); }
void DriveGravityTurn(FlightCtrlState s) { //stop the gravity turn when our apoapsis reaches the desired altitude if (autoThrottle && orbit.ApA > desiredOrbitAltitude) { mode = AscentMode.COAST_TO_APOAPSIS; return; } //if we've fallen below the turn start altitude, go back to vertical ascent if (ascentPath.IsVerticalAscent(vesselState.altitudeASL, vesselState.speedSurface)) { mode = AscentMode.VERTICAL_ASCENT; return; } if (autoThrottle) { core.thrust.targetThrottle = ThrottleToRaiseApoapsis(orbit.ApR, desiredOrbitAltitude + mainBody.Radius); if (core.thrust.targetThrottle < 1.0F) { //when we are bringing down the throttle to make the apoapsis accurate, we're liable to point in weird //directions because thrust goes down and so "difficulty" goes up. so just burn prograde core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.ORBIT, this); status = "Fine tuning apoapsis"; return; } } //transition gradually from the rotating to the non-rotating reference frame. this calculation ensures that //when our maximum possible apoapsis, given our orbital energy, is desiredOrbitalRadius, then we are //fully in the non-rotating reference frame and thus doing the correct calculations to get the right inclination double GM = mainBody.gravParameter; double potentialDifferenceWithApoapsis = GM / vesselState.radius - GM / (mainBody.Radius + desiredOrbitAltitude); double verticalSpeedForDesiredApoapsis = Math.Sqrt(2 * potentialDifferenceWithApoapsis); double referenceFrameBlend = Mathf.Clamp((float)(vesselState.speedOrbital / verticalSpeedForDesiredApoapsis), 0.0F, 1.0F); Vector3d actualVelocityUnit = ((1 - referenceFrameBlend) * vesselState.surfaceVelocity.normalized + referenceFrameBlend * vesselState.orbitalVelocity.normalized).normalized; double desiredHeading = MathExtensions.Deg2Rad * OrbitalManeuverCalculator.HeadingForLaunchInclination(vessel.mainBody, desiredInclination, launchLatitude, OrbitalManeuverCalculator.CircularOrbitSpeed(vessel.mainBody, desiredOrbitAltitude + mainBody.Radius)); Vector3d desiredHeadingVector = Math.Sin(desiredHeading) * vesselState.east + Math.Cos(desiredHeading) * vesselState.north; double desiredFlightPathAngle = ascentPath.FlightPathAngle(vesselState.altitudeASL, vesselState.speedSurface); Vector3d desiredVelocityUnit = Math.Cos(desiredFlightPathAngle * Math.PI / 180) * desiredHeadingVector + Math.Sin(desiredFlightPathAngle * Math.PI / 180) * vesselState.up; Vector3d desiredThrustVector = desiredVelocityUnit; if (correctiveSteering) { Vector3d velocityError = (desiredVelocityUnit - actualVelocityUnit); const double Kp = 5.0; //control gain //"difficulty" scales the controller gain to account for the difficulty of changing a large velocity vector given our current thrust double difficulty = vesselState.surfaceVelocity.magnitude / (50 + 10 * vesselState.ThrustAccel(core.thrust.targetThrottle)); if (difficulty > 5) { difficulty = 5; } if (vesselState.limitedMaxThrustAccel == 0) { difficulty = 1.0; //so we don't freak out over having no thrust between stages } Vector3d steerOffset = Kp * difficulty * velocityError; //limit the amount of steering to 10 degrees. Furthermore, never steer to a FPA of > 90 (that is, never lean backward) double maxOffset = 10 * Math.PI / 180; if (desiredFlightPathAngle > 80) { maxOffset = (90 - desiredFlightPathAngle) * Math.PI / 180; } if (steerOffset.magnitude > maxOffset) { steerOffset = maxOffset * steerOffset.normalized; } desiredThrustVector += steerOffset; } desiredThrustVector = desiredThrustVector.normalized; if (limitAoA) { float fade = vesselState.dynamicPressure < aoALimitFadeoutPressure ? (float)(aoALimitFadeoutPressure / vesselState.dynamicPressure) : 1; currentMaxAoA = Math.Min(fade * maxAoA, 180d); limitingAoA = vessel.altitude <mainBody.atmosphereDepth && Vector3.Angle(vesselState.surfaceVelocity, desiredThrustVector)> currentMaxAoA; if (limitingAoA) { desiredThrustVector = Vector3.RotateTowards(vesselState.surfaceVelocity, desiredThrustVector, (float)(currentMaxAoA * Mathf.Deg2Rad), 1).normalized; } } if (forceRoll && Vector3.Angle(vesselState.up, vesselState.forward) > 7 && core.attitude.attitudeError < 5) { var pitch = 90 - Vector3.Angle(vesselState.up, desiredThrustVector); var hdg = core.rover.HeadingToPos(vessel.CoM, vessel.CoM + desiredThrustVector); core.attitude.attitudeTo(hdg, pitch, turnRoll, this); } else { core.attitude.attitudeTo(desiredThrustVector, AttitudeReference.INERTIAL, this); } status = "Gravity turn"; }
void DriveVerticalAscent(FlightCtrlState s) { if (timedLaunch) { status = "Awaiting liftoff"; core.attitude.AxisControl(false, false, false); return; } if (!ascentPath.IsVerticalAscent(vesselState.altitudeASL, vesselState.speedSurface)) { mode = AscentMode.GRAVITY_TURN; } if (autoThrottle && orbit.ApA > desiredOrbitAltitude) { mode = AscentMode.COAST_TO_APOAPSIS; } //during the vertical ascent we just thrust straight up at max throttle if (forceRoll) { // pre-align roll unless correctiveSteering is active as it would just interfere with that double desiredHeading = OrbitalManeuverCalculator.HeadingForLaunchInclination(vessel.mainBody, desiredInclination, launchLatitude, OrbitalManeuverCalculator.CircularOrbitSpeed(vessel.mainBody, desiredOrbitAltitude + mainBody.Radius)); core.attitude.attitudeTo(desiredHeading, 90, verticalRoll, this); } else { core.attitude.attitudeTo(Vector3d.up, AttitudeReference.SURFACE_NORTH, this); } core.attitude.AxisControl(!vessel.Landed, !vessel.Landed, !vessel.Landed && vesselState.altitudeBottom > 50); if (autoThrottle) { core.thrust.targetThrottle = 1.0F; } if (!vessel.LiftedOff() || vessel.Landed) { status = "Awaiting liftoff"; } else { status = "Vertical ascent"; } }
public double CircularOrbitSpeed() { return(OrbitalManeuverCalculator.CircularOrbitSpeed(mainBody, vesselState.radius)); }