public override void OnModuleEnabled() { if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } }
public override void OnModuleEnabled() { vessel.RemoveAllManeuverNodes(); if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } }
public void Reset() { // lambda and lambdaDot are deliberately not cleared here //Debug.Log("call stack: + " + Environment.StackTrace); if (p != null) { p.KillThread(); p = null; } status = PVGStatus.INITIALIZING; last_stage_time = 0.0; last_optimizer_time = 0.0; last_success_time = 0.0; autowarp = false; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } }
void FixedUpdatePlaneChange() { Vector3d targetRadialVector = mainBody.GetRelSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0); Vector3d currentRadialVector = vesselState.CoM - mainBody.position; double angleToTarget = Vector3d.Angle(targetRadialVector, currentRadialVector); bool approaching = Vector3d.Dot(targetRadialVector - currentRadialVector, vesselState.velocityVesselOrbit) > 0; if (!planeChangeTriggered && approaching && (angleToTarget > 80) && (angleToTarget < 90)) { if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(true); } planeChangeTriggered = true; } if (planeChangeTriggered) { Vector3d horizontalToTarget = ComputePlaneChange(); Vector3d finalVelocity = Quaternion.FromToRotation(vesselState.horizontalOrbit, horizontalToTarget) * vesselState.velocityVesselOrbit; Vector3d deltaV = finalVelocity - vesselState.velocityVesselOrbit; //burn normal+ or normal- to avoid dropping the Pe: Vector3d burnDir = Vector3d.Exclude(vesselState.up, Vector3d.Exclude(vesselState.velocityVesselOrbit, deltaV)); planeChangeDVLeft = Math.PI / 180 * Vector3d.Angle(finalVelocity, vesselState.velocityVesselOrbit) * vesselState.speedOrbitHorizontal; core.attitude.attitudeTo(burnDir, AttitudeReference.INERTIAL, this); if (planeChangeDVLeft < 0.1F) { landStep = LandStep.LOW_DEORBIT_BURN; } status = "Executing low orbit plane change of about " + planeChangeDVLeft.ToString("F0") + " m/s"; } else { if (core.node.autowarp) { core.warp.WarpRegularAtRate((float)(orbit.period / 6)); } status = "Moving to low orbit plane change burn point"; } }
public override void OnFixedUpdate() { if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } //check if we've finished a node: ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First(); double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5) { burnTriggered = false; node.RemoveSelf(); if (mode == Mode.ONE_NODE) { Abort(); return; } else if (mode == Mode.ALL_NODES) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } else { node = vessel.patchedConicSolver.maneuverNodes.First(); } } } //aim along the node core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this); double halfBurnTime; double burnTime = BurnTime(dVLeft, out halfBurnTime); double timeToNode = node.UT - vesselState.time; if (timeToNode < halfBurnTime) { burnTriggered = true; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } } //autowarp, but only if we're already aligned with the node if (autowarp && !burnTriggered) { if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning())) { core.warp.WarpToUT(node.UT - halfBurnTime - leadTime); } else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600) { //realign core.warp.MinimumWarp(); } } core.thrust.targetThrottle = 0; if (burnTriggered) { if (alignedForBurn) { if (core.attitude.attitudeAngleFromTarget() < 90) { double timeConstant = (dVLeft > 10 || vesselState.minThrustAccel > 0.25 * vesselState.maxThrustAccel ? 0.5 : 2); core.thrust.ThrustForDV(dVLeft + tolerance, timeConstant); } else { alignedForBurn = false; } } else { if (core.attitude.attitudeAngleFromTarget() < 2) { alignedForBurn = true; } } } }
void FixedUpdateDecelerationBurn() { if (vesselState.altitudeASL < DecelerationEndAltitude() + 5) { if (UseAtmosphereToBrake()) { landStep = LandStep.FINAL_DESCENT; } else { landStep = LandStep.KILLING_HORIZONTAL_VELOCITY; } core.warp.MinimumWarp(); return; } double decelerationStartTime = (prediction.trajectory.Any() ? prediction.trajectory.First().UT : vesselState.time); if (decelerationStartTime - vesselState.time > 5) { core.thrust.targetThrottle = 0; status = "Warping to start of braking burn."; //warp to deceleration start Vector3d decelerationStartAttitude = -orbit.SwappedOrbitalVelocityAtUT(decelerationStartTime); decelerationStartAttitude += mainBody.getRFrmVel(orbit.SwappedAbsolutePositionAtUT(decelerationStartTime)); decelerationStartAttitude = decelerationStartAttitude.normalized; core.attitude.attitudeTo(decelerationStartAttitude, AttitudeReference.INERTIAL, this); bool warpReady = core.attitude.attitudeAngleFromTarget() < 5; if (warpReady && core.node.autowarp) { core.warp.WarpToUT(decelerationStartTime - 5); } else if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } return; } Vector3d desiredThrustVector = -vesselState.velocityVesselSurfaceUnit; Vector3d courseCorrection = ComputeCourseCorrection(false); double correctionAngle = courseCorrection.magnitude / (2.0 * vesselState.limitedMaxThrustAccel); correctionAngle = Math.Min(0.1, correctionAngle); desiredThrustVector = (desiredThrustVector + correctionAngle * courseCorrection.normalized).normalized; if (Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.up) > 0 || Vector3d.Dot(vesselState.forward, desiredThrustVector) < 0.75) { core.thrust.targetThrottle = 0; status = "Braking"; } else { double controlledSpeed = vesselState.speedSurface * Math.Sign(Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.up)); //positive if we are ascending, negative if descending double desiredSpeed = -MaxAllowedSpeed(); double desiredSpeedAfterDt = -MaxAllowedSpeedAfterDt(vesselState.deltaT); double minAccel = -vesselState.localg * Math.Abs(Vector3d.Dot(vesselState.velocityVesselSurfaceUnit, vesselState.up)); double maxAccel = vesselState.maxThrustAccel * Vector3d.Dot(vesselState.forward, -vesselState.velocityVesselSurfaceUnit) - vesselState.localg * Math.Abs(Vector3d.Dot(vesselState.velocityVesselSurfaceUnit, vesselState.up)); double speedCorrectionTimeConstant = 0.3; double speedError = desiredSpeed - controlledSpeed; double desiredAccel = speedError / speedCorrectionTimeConstant + (desiredSpeedAfterDt - desiredSpeed) / vesselState.deltaT; if (maxAccel - minAccel > 0) { core.thrust.targetThrottle = Mathf.Clamp((float)((desiredAccel - minAccel) / (maxAccel - minAccel)), 0.0F, 1.0F); } else { core.thrust.targetThrottle = 0; } status = "Braking: target speed = " + Math.Abs(desiredSpeed).ToString("F1") + " m/s"; } core.attitude.attitudeTo(desiredThrustVector, AttitudeReference.INERTIAL, this); }
void FixedUpdateDeorbitBurn() { //if we don't want to deorbit but we're already on a reentry trajectory, we can't wait until the ideal point //in the orbit to deorbt; we already have deorbited. if (part.vessel.orbit.ApA < part.vessel.mainBody.RealMaxAtmosphereAltitude()) { landStep = LandStep.COURSE_CORRECTIONS; core.thrust.targetThrottle = 0; return; } //We aim for a trajectory that // a) has the same vertical speed as our current trajectory // b) has a horizontal speed that will give it a periapsis of -10% of the body's radius // c) has a heading that points toward where the target will be at the end of free-fall, accounting for planetary rotation Vector3d horizontalDV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, vesselState.time, 0.9 * mainBody.Radius); //Imagine we are going to deorbit now. Find the burn that would lower our periapsis to -10% of the planet's radius Orbit forwardDeorbitTrajectory = orbit.PerturbedOrbit(vesselState.time, horizontalDV); //Compute the orbit that would put us on double freefallTime = forwardDeorbitTrajectory.NextTimeOfRadius(vesselState.time, mainBody.Radius) - vesselState.time; //Find how long that orbit would take to impact the ground double planetRotationDuringFreefall = 360 * freefallTime / mainBody.rotationPeriod; //Find how many degrees the planet will rotate during that time Vector3d currentTargetRadialVector = mainBody.GetRelSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0); //Find the current vector from the planet center to the target landing site Quaternion freefallPlanetRotation = Quaternion.AngleAxis((float)planetRotationDuringFreefall, mainBody.angularVelocity); //Construct a quaternion representing the rotation of the planet found above Vector3d freefallEndTargetRadialVector = freefallPlanetRotation * currentTargetRadialVector; //Use this quaternion to find what the vector from the planet center to the target will be when we hit the ground Vector3d freefallEndTargetPosition = mainBody.position + freefallEndTargetRadialVector; //Then find the actual position of the target at that time Vector3d freefallEndHorizontalToTarget = Vector3d.Exclude(vesselState.up, freefallEndTargetPosition - vesselState.CoM).normalized; //Find a horizontal unit vector that points toward where the target will be when we hit the ground Vector3d currentHorizontalVelocity = Vector3d.Exclude(vesselState.up, vesselState.velocityVesselOrbit); //Find our current horizontal velocity double finalHorizontalSpeed = (currentHorizontalVelocity + horizontalDV).magnitude; //Find the desired horizontal speed after the deorbit burn Vector3d finalHorizontalVelocity = finalHorizontalSpeed * freefallEndHorizontalToTarget; //Combine the desired speed and direction to get the desired velocity after the deorbi burn //Compute the angle between the location of the target at the end of freefall and the normal to our orbit: Vector3d currentRadialVector = vesselState.CoM - part.vessel.mainBody.position; double targetAngleToOrbitNormal = Vector3d.Angle(orbit.SwappedOrbitNormal(), freefallEndTargetRadialVector); targetAngleToOrbitNormal = Math.Min(targetAngleToOrbitNormal, 180 - targetAngleToOrbitNormal); double targetAheadAngle = Vector3d.Angle(currentRadialVector, freefallEndTargetRadialVector); //How far ahead the target is, in degrees double planeChangeAngle = Vector3d.Angle(currentHorizontalVelocity, freefallEndHorizontalToTarget); //The plane change required to get onto the deorbit trajectory, in degrees //If the target is basically almost normal to our orbit, it doesn't matter when we deorbit; might as well do it now //Otherwise, wait until the target is ahead if (targetAngleToOrbitNormal < 10 || (targetAheadAngle < 90 && targetAheadAngle > 60 && planeChangeAngle < 90)) { deorbitBurnTriggered = true; } if (deorbitBurnTriggered) { if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(true); //get out of warp } Vector3d deltaV = finalHorizontalVelocity - currentHorizontalVelocity; core.attitude.attitudeTo(deltaV.normalized, AttitudeReference.INERTIAL, this); if (deltaV.magnitude < 2.0) { landStep = LandStep.COURSE_CORRECTIONS; } status = "Doing high deorbit burn"; } else { core.attitude.attitudeTo(Vector3d.back, AttitudeReference.ORBIT, this); if (core.node.autowarp) { core.warp.WarpRegularAtRate((float)(orbit.period / 10)); } status = "Moving to high deorbit burn point"; } }
void FixedUpdateLowDeorbitBurn() { //Decide when we will start the deorbit burn: double stoppingDistance = Math.Pow(vesselState.speedSurfaceHorizontal, 2) / (2 * vesselState.limitedMaxThrustAccel); double triggerDistance = lowDeorbitBurnTriggerFactor * stoppingDistance; double heightAboveTarget = vesselState.altitudeASL - DecelerationEndAltitude(); if (triggerDistance < heightAboveTarget) { triggerDistance = heightAboveTarget; } //See if it's time to start the deorbit burn: double rangeToTarget = Vector3d.Exclude(vesselState.up, core.target.GetPositionTargetPosition() - vesselState.CoM).magnitude; if (!deorbitBurnTriggered && rangeToTarget < triggerDistance) { if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(true); } deorbitBurnTriggered = true; } if (deorbitBurnTriggered) { status = "Executing low deorbit burn"; } else { status = "Moving to low deorbit burn point"; } //Warp toward deorbit burn if it hasn't been triggerd yet: if (!deorbitBurnTriggered && core.node.autowarp && rangeToTarget > 2 * triggerDistance) { core.warp.WarpRegularAtRate((float)(orbit.period / 6)); } if (rangeToTarget < triggerDistance && !MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } //By default, thrust straight back at max throttle Vector3d thrustDirection = -vesselState.velocityVesselSurfaceUnit; lowDeorbitBurnMaxThrottle = 1; //If we are burning, we watch the predicted landing site and switch to the braking //burn when the predicted landing site crosses the target. We also use the predictions //to steer the predicted landing site toward the target if (deorbitBurnTriggered && PredictionReady) { //angle slightly left or right to fix any cross-range error in the predicted landing site: Vector3d horizontalToLandingSite = Vector3d.Exclude(vesselState.up, LandingSite - vesselState.CoM).normalized; Vector3d horizontalToTarget = Vector3d.Exclude(vesselState.up, core.target.GetPositionTargetPosition() - vesselState.CoM).normalized; double angleGain = 4; Vector3d angleCorrection = angleGain * (horizontalToTarget - horizontalToLandingSite); if (angleCorrection.magnitude > 0.1) { angleCorrection *= 0.1 / angleCorrection.magnitude; } thrustDirection = (thrustDirection + angleCorrection).normalized; double rangeToLandingSite = Vector3d.Exclude(vesselState.up, LandingSite - vesselState.CoM).magnitude; double maxAllowedSpeed = MaxAllowedSpeed(); if (!lowDeorbitEndConditionSet && Vector3d.Distance(LandingSite, vesselState.CoM) < mainBody.Radius + vesselState.altitudeASL) { lowDeorbitEndOnLandingSiteNearer = rangeToLandingSite > rangeToTarget; lowDeorbitEndConditionSet = true; } lowDeorbitBurnMaxThrottle = 1; if (orbit.PeA < 0) { if (rangeToLandingSite > rangeToTarget) { if (lowDeorbitEndConditionSet && !lowDeorbitEndOnLandingSiteNearer) { landStep = LandStep.DECELERATING; core.thrust.targetThrottle = 0; } double maxAllowedSpeedAfterDt = MaxAllowedSpeedAfterDt(vesselState.deltaT); double speedAfterDt = vesselState.speedSurface + vesselState.deltaT * Vector3d.Dot(vesselState.gravityForce, vesselState.velocityVesselSurfaceUnit); double throttleToMaintainLandingSite; if (vesselState.speedSurface < maxAllowedSpeed) { throttleToMaintainLandingSite = 0; } else { throttleToMaintainLandingSite = (speedAfterDt - maxAllowedSpeedAfterDt) / (vesselState.deltaT * vesselState.maxThrustAccel); } lowDeorbitBurnMaxThrottle = throttleToMaintainLandingSite + 1 * (rangeToLandingSite / rangeToTarget - 1) + 0.2; } else { if (lowDeorbitEndConditionSet && lowDeorbitEndOnLandingSiteNearer) { landStep = LandStep.DECELERATING; core.thrust.targetThrottle = 0; } else { lowDeorbitBurnMaxThrottle = 0; status = "Deorbit burn complete: waiting for the right moment to start braking"; } } } } core.attitude.attitudeTo(thrustDirection, AttitudeReference.INERTIAL, this); }
public override void OnFixedUpdate() { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } //check if we've finished a node: ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First(); double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5) { burnTriggered = false; vessel.patchedConicSolver.RemoveManeuverNode(node); if (mode == Mode.ONE_NODE) { Abort(); return; } else if (mode == Mode.ALL_NODES) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } else { node = vessel.patchedConicSolver.maneuverNodes.First(); } } } //aim along the node core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this); double burnTime = BurnTime(dVLeft); double timeToNode = node.UT - vesselState.time; if (timeToNode < burnTime * leadFraction) { burnTriggered = true; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } } //autowarp, but only if we're already aligned with the node if (autowarp && !burnTriggered) { if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning())) { core.warp.WarpToUT(node.UT - burnTime * leadFraction - leadTime); } else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600) { //realign core.warp.MinimumWarp(); } } core.thrust.targetThrottle = 0; if (burnTriggered) { if (alignedForBurn) { if (core.attitude.attitudeAngleFromTarget() < 90) { double timeConstant = (dVLeft > 10 ? 0.5 : 2); double desiredAcceleration = dVLeft / timeConstant; desiredAcceleration = Math.Max(tolerance, desiredAcceleration); core.thrust.targetThrottle = Mathf.Clamp01((float)(desiredAcceleration / vesselState.maxThrustAccel)); } else { alignedForBurn = false; } } else { if (core.attitude.attitudeAngleFromTarget() < 2) { alignedForBurn = true; } } } }