private void RenderSyncUI(GUIStyle sty, GUIStyle but) { if (!CheckVessel()) { _flyByWire = false; Mode = UIMode.SELECTED; } if (GUILayout.Button("Sync Orbits", but, GUILayout.ExpandWidth(true))) { Mode = UIMode.SELECTED; _flyByWire = false; } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); for (int i = 0; i < NumberOfPredictedSyncPoints; i++) { if (i != (int)SyncMode) { continue; } if (GUILayout.Button(SyncMode.ToString(), but, GUILayout.ExpandWidth(true))) { if (i == NumberOfPredictedSyncPoints - 1) { SyncMode = 0; } else { SyncMode = SyncMode + 1; } } //GUILayout.Box(SyncMode.ToString(),but); } GUILayout.EndHorizontal(); GUILayout.BeginVertical(); GUILayout.Box("Orbit ShipToR TgtToR ", GUILayout.ExpandWidth(true)); for (int i = 0; i < 4; i++) { GUILayout.Box(_syncString[i]); } GUILayout.Label("Closest Approach on Orbit " + _closestApproachOrbit.ToString(), sty); GUILayout.Label("Min Separation (sec) : " + _minimumPredictedTimeFromTarget.ToString("f1"), sty); if (automation == true) { if (GUILayout.Button(_autoPhaser ? _autoPhaserState.ToString() : "Auto Sync", but, GUILayout.ExpandWidth(true))) { _autoPhaser = !_autoPhaser; _autoPhaserState = AutoPhaserState.Step1WaitForTargetApsis; } } }
private void RenderSyncUI(GUIStyle sty) { if (!CheckVessel()) { _flyByWire = false; Mode = UIMode.SELECTED; } if (GUILayout.Button("Sync Orbits", sty, GUILayout.ExpandWidth(true))) { Mode = UIMode.SELECTED; _flyByWire = false; } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); for (int i = 0; i < NumberOfPredictedSyncPoints; i++) { if (i != (int) SyncMode) continue; if (GUILayout.Button(" ", sty, GUILayout.ExpandWidth(true))) { if (i == NumberOfPredictedSyncPoints - 1) SyncMode = 0; else SyncMode = SyncMode + 1; } GUILayout.Box(SyncMode.ToString()); } GUILayout.EndHorizontal(); GUILayout.BeginVertical(); GUILayout.Box("Orbit ShipToR TgtToR ", sty, GUILayout.ExpandWidth(true)); for (int i = 0; i < 4; i++) GUILayout.Box(_syncString[i]); GUILayout.Box("Closest Approach on Orbit " + _closestApproachOrbit.ToString()); GUILayout.Box("Min Separation (sec) : " + _minimumPredictedTimeFromTarget.ToString("f1")); if(GUILayout.Button(_autoPhaser ? _autoPhaserState.ToString() : "Auto Sync", sty, GUILayout.ExpandWidth(true))) { _autoPhaser = !_autoPhaser; _autoPhaserState = AutoPhaserState.Step1WaitForTargetApsis; } }
private void DriveShip(FlightCtrlState controls) { if(!CheckVessel()) return; Vessel selectedVessel = FlightGlobals.Vessels[_selectedVesselIndex] as Vessel; if(_autoAlign) { // Is it time to burn? Find soonest node. double timeToBurnAN = vessel.orbit.GetTimeToRelAN(selectedVessel.orbit); double timeToBurnDN = vessel.orbit.GetTimeToRelDN(selectedVessel.orbit); bool ascendingSoonest = timeToBurnAN < timeToBurnDN; double timeToBurnNode = ascendingSoonest ? timeToBurnAN : timeToBurnDN; // Figure out which way we want to burn to adjust our inclination. _flyByWire = true; if(!_autoAlignBurnTriggered) { if (_relativeInclination < 0.0) PointAt = ascendingSoonest ? Orient.Normal : Orient.AntiNormal; else PointAt = ascendingSoonest ? Orient.AntiNormal : Orient.Normal; } // Do a burn just ahead of the ascending node - in the 5 seconds preceding. if ((timeToBurnNode < 10.0 || _autoAlignBurnTriggered) && _headingError.magnitude < 5.0 && Math.Abs(_relativeInclination) > 0.01) { _autoAlignBurnTriggered = true; if (Math.Abs(_relativeInclination) > 0.1) { controls.mainThrottle = 1.0f; } else { controls.mainThrottle = 0.25f; } } else { controls.mainThrottle = 0.0f; } if (Math.Abs(_relativeInclination) < 0.02) { _autoAlignBurnTriggered = false; _autoAlign = false; } } if (_autoPhaser) { switch(_autoPhaserState) { case AutoPhaserState.Step1WaitForTargetApsis: double timeLeft = CalculateTimeTillNextTargetApsis(); // Set the PointAt based on who is faster at that point in time. _flyByWire = true; if (vessel.orbit.getOrbitalVelocityAt(timeLeft) > selectedVessel.orbit.getOrbitalVelocityAt(timeLeft)) PointAt = Orient.Retrograde; else PointAt = Orient.Prograde; // Advance if it's time. if (timeLeft < 5.0) { _autoPhaserState = AutoPhaserState.Step2BurnToMatchNextApsis; _autoPhaserVelocityGoal = selectedVessel.orbit.getOrbitalVelocityAt(CalculateTimeTillFurtherTargetApsis()); _autoPhaseBurnComplete = false; } break; case AutoPhaserState.Step2BurnToMatchNextApsis: double predictedVelocity = vessel.orbit.getOrbitalVelocityAt(CalculateTimeTillFurtherTargetApsis()); if (_headingError.magnitude < 5.0 && !_autoPhaseBurnComplete) { controls.mainThrottle = 1; } else { controls.mainThrottle = 0; } // Advance to next state if we hit our goal. if (Math.Abs(predictedVelocity - _autoPhaserVelocityGoal) < 10) { _autoPhaseBurnComplete = true; controls.mainThrottle = 0; } // Wait till we pass the apsis so we don't double advance. if (_autoPhaseBurnComplete && CalculateTimeTillNextTargetApsis() > 10.0) _autoPhaserState = AutoPhaserState.Step3WaitForTargetApsis; break; case AutoPhaserState.Step3WaitForTargetApsis: timeLeft = CalculateTimeTillNextTargetApsis(); // Set the PointAt based on who is faster at that point in time. _flyByWire = true; PointAt = Orient.Prograde; // Advance if it's time. if (timeLeft < 5.0) { _autoPhaserState = AutoPhaserState.Step4BurnToRendezvous; } break; case AutoPhaserState.Step4BurnToRendezvous: // TODO: Make sure we are only considering the apsis that // is spatially similar to ours, otherwise we get in sync // orbitally but go into step 5 super far away. double timeToRendezvous = 0.0, minDeltaT = 0.0; CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT); if (minDeltaT > 5) controls.mainThrottle = 0.25f; else { controls.mainThrottle = 0.0f; _autoPhaserState = AutoPhaserState.Step5WaitForRendezvous; } break; case AutoPhaserState.Step5WaitForRendezvous: timeToRendezvous = 0.0; minDeltaT = 0.0; CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT); if(timeToRendezvous < 2) _autoPhaserState = AutoPhaserState.Step6BurnToMatchVelocity; break; case AutoPhaserState.Step6BurnToMatchVelocity: if(_relativeVelocity.magnitude > 5) { _flyByWire = true; PointAt = Orient.RelativeVelocityAway; if(_headingError.magnitude < 5) { if (_relativeVelocity.magnitude > 15) controls.mainThrottle = 1.0f; else controls.mainThrottle = 0.2f; } } else { // All done! controls.mainThrottle = 0.0f; _autoPhaser = false; } break; } } if(_killRelativeVelocity) { controls.X = Mathf.Clamp(-_localRelativeVelocity.x * 8.0f, -1.0f, 1.0f); controls.Y = Mathf.Clamp(-_localRelativeVelocity.z * 8.0f, -1.0f, 1.0f); controls.Z = Mathf.Clamp(-_localRelativeVelocity.y * 8.0f, -1.0f, 1.0f); if (_localRelativeVelocity.magnitude < 0.1) _killRelativeVelocity = false; } else if (_homeOnRelativePosition) { Vector3 targetGoalPos = new Vector3(0.0f, 2.0f, 0.0f); targetGoalPos = selectedVessel.transform.localToWorldMatrix.MultiplyPoint(targetGoalPos); targetGoalPos = vessel.transform.worldToLocalMatrix.MultiplyPoint(targetGoalPos); Vector3 relPos = targetGoalPos; Vector4 goalVel = Vector3.zero; float velGoal = 0.1f; if (_targetDistance > 2.0f) velGoal = 0.3f; else if (_targetDistance > 10.0f) velGoal = 0.5f; else if (_targetDistance > 50.0f) velGoal = 1.0f; else if (_targetDistance > 150.0f) velGoal = 3.0f; if(Mathf.Abs(relPos.x) > 0.01f) goalVel.x = -Mathf.Sign(relPos.x) * velGoal; if (Mathf.Abs(relPos.y) > 0.01f) goalVel.y = -Mathf.Sign(relPos.y) * velGoal; if (Mathf.Abs(relPos.z) > 0.01f) goalVel.z = -Mathf.Sign(relPos.z) * velGoal; controls.X = Mathf.Clamp((goalVel.x - _localRelativeVelocity.x) * 8.0f, -1, 1); controls.Y = Mathf.Clamp((goalVel.z - _localRelativeVelocity.z) * 8.0f, -1, 1); controls.Z = Mathf.Clamp((goalVel.y - _localRelativeVelocity.y) * 8.0f, -1, 1); } if (!_flyByWire) return; Quaternion tgt = Quaternion.LookRotation(_tgtFwd, _tgtUp); Quaternion delta = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * tgt); _headingError = new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x, (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y, (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F; _integral += _headingError * TimeWarp.fixedDeltaTime; _deriv = (_headingError - _prevErr) / TimeWarp.fixedDeltaTime; _act = Kp * _headingError + Ki * _integral + Kd * _deriv; _prevErr = _headingError; controls.pitch = Mathf.Clamp(controls.pitch + _act.x, -1.0F, 1.0F); controls.yaw = Mathf.Clamp(controls.yaw - _act.y, -1.0F, 1.0F); controls.roll = Mathf.Clamp(controls.roll + _act.z, -1.0F, 1.0F); }
private void DriveShip(FlightCtrlState controls) { if (!CheckVessel()) { return; } Vessel selectedVessel = FlightGlobals.Vessels[_selectedVesselIndex] as Vessel; if (_autoAlign) { // Is it time to burn? Find soonest node. double timeToBurnAN = part.vessel.orbit.GetTimeToRelAN(selectedVessel.orbit); double timeToBurnDN = part.vessel.orbit.GetTimeToRelDN(selectedVessel.orbit); bool ascendingSoonest = timeToBurnAN < timeToBurnDN; double timeToBurnNode = ascendingSoonest ? timeToBurnAN : timeToBurnDN; if (timeToBurnNode > 30) { core.warpTo(this, timeToBurnNode - 30, warpLookaheadTimes); } // Figure out which way we want to burn to adjust our inclination. _flyByWire = true; if (!_autoAlignBurnTriggered) { if (_relativeInclination < 0.0) { PointAt = ascendingSoonest ? Orient.Normal : Orient.AntiNormal; } else { PointAt = ascendingSoonest ? Orient.AntiNormal : Orient.Normal; } } // Do a burn just ahead of the ascending node - in the 5 seconds preceding. if ((timeToBurnNode < 10.0 || _autoAlignBurnTriggered) && _headingError.magnitude < 5.0 && Math.Abs(_relativeInclination) > 0.01) { _autoAlignBurnTriggered = true; if (Math.Abs(_relativeInclination) > 0.1) { controls.mainThrottle = 1.0f; } else { controls.mainThrottle = 0.25f; } } else { controls.mainThrottle = 0.0f; } if (Math.Abs(_relativeInclination) < 0.02) { _autoAlignBurnTriggered = false; _autoAlign = false; } } if (_autoPhaser) { switch (_autoPhaserState) { case AutoPhaserState.Step1WaitForTargetApsis: double timeLeft = CalculateTimeTillNextTargetApsis(); // Set the PointAt based on who is faster at that point in time. _flyByWire = true; if (part.vessel.orbit.getOrbitalSpeedAt(timeLeft) > selectedVessel.orbit.getOrbitalSpeedAt(timeLeft)) { PointAt = Orient.Retrograde; } else { PointAt = Orient.Prograde; } // Advance if it's time. if (timeLeft < 5.0) { _autoPhaserState = AutoPhaserState.Step2BurnToMatchNextApsis; _autoPhaserVelocityGoal = selectedVessel.orbit.getOrbitalSpeedAt(CalculateTimeTillFurtherTargetApsis()); _autoPhaseBurnComplete = false; } break; case AutoPhaserState.Step2BurnToMatchNextApsis: double predictedVelocity = part.vessel.orbit.getOrbitalSpeedAt(CalculateTimeTillFurtherTargetApsis()); if (_headingError.magnitude < 5.0 && !_autoPhaseBurnComplete) { controls.mainThrottle = 1; } else { controls.mainThrottle = 0; } // Advance to next state if we hit our goal. if (Math.Abs(predictedVelocity - _autoPhaserVelocityGoal) < 10) { _autoPhaseBurnComplete = true; controls.mainThrottle = 0; } // Wait till we pass the apsis so we don't double advance. if (_autoPhaseBurnComplete && CalculateTimeTillNextTargetApsis() > 10.0) { _autoPhaserState = AutoPhaserState.Step3WaitForTargetApsis; } break; case AutoPhaserState.Step3WaitForTargetApsis: timeLeft = CalculateTimeTillNextTargetApsis(); // Set the PointAt based on who is faster at that point in time. _flyByWire = true; PointAt = Orient.Prograde; // Advance if it's time. if (timeLeft < 5.0) { _autoPhaserState = AutoPhaserState.Step4BurnToRendezvous; } break; case AutoPhaserState.Step4BurnToRendezvous: // TODO: Make sure we are only considering the apsis that // is spatially similar to ours, otherwise we get in sync // orbitally but go into step 5 super far away. double timeToRendezvous = 0.0, minDeltaT = 0.0; CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT); if (minDeltaT > 5) { controls.mainThrottle = 0.25f; } else { controls.mainThrottle = 0.0f; _autoPhaserState = AutoPhaserState.Step5WaitForRendezvous; } break; case AutoPhaserState.Step5WaitForRendezvous: timeToRendezvous = 0.0; minDeltaT = 0.0; CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT); if (timeToRendezvous < 2) { _autoPhaserState = AutoPhaserState.Step6BurnToMatchVelocity; } break; case AutoPhaserState.Step6BurnToMatchVelocity: if (_relativeVelocity.magnitude > 5) { _flyByWire = true; PointAt = Orient.RelativeVelocityAway; if (_headingError.magnitude < 5) { if (_relativeVelocity.magnitude > 15) { controls.mainThrottle = 1.0f; } else { controls.mainThrottle = 0.2f; } } } else { // All done! controls.mainThrottle = 0.0f; _autoPhaser = false; } break; } } if (_killRelativeVelocity) { controls.X = Mathf.Clamp(-_localRelativeVelocity.x * 8.0f, -1.0f, 1.0f); controls.Y = Mathf.Clamp(-_localRelativeVelocity.z * 8.0f, -1.0f, 1.0f); controls.Z = Mathf.Clamp(-_localRelativeVelocity.y * 8.0f, -1.0f, 1.0f); if (_localRelativeVelocity.magnitude < 0.1) { _killRelativeVelocity = false; } } else if (_homeOnRelativePosition) { Vector3 targetGoalPos = new Vector3(0.0f, 2.0f, 0.0f); targetGoalPos = selectedVessel.transform.localToWorldMatrix.MultiplyPoint(targetGoalPos); targetGoalPos = part.vessel.transform.worldToLocalMatrix.MultiplyPoint(targetGoalPos); Vector3 relPos = targetGoalPos; Vector4 goalVel = Vector3.zero; float velGoal = 0.1f; if (_targetDistance > 2.0f) { velGoal = 0.3f; } else if (_targetDistance > 10.0f) { velGoal = 0.5f; } else if (_targetDistance > 50.0f) { velGoal = 1.0f; } else if (_targetDistance > 150.0f) { velGoal = 3.0f; } if (Mathf.Abs(relPos.x) > 0.01f) { goalVel.x = -Mathf.Sign(relPos.x) * velGoal; } if (Mathf.Abs(relPos.y) > 0.01f) { goalVel.y = -Mathf.Sign(relPos.y) * velGoal; } if (Mathf.Abs(relPos.z) > 0.01f) { goalVel.z = -Mathf.Sign(relPos.z) * velGoal; } controls.X = Mathf.Clamp((goalVel.x - _localRelativeVelocity.x) * 8.0f, -1, 1); controls.Y = Mathf.Clamp((goalVel.z - _localRelativeVelocity.z) * 8.0f, -1, 1); controls.Z = Mathf.Clamp((goalVel.y - _localRelativeVelocity.y) * 8.0f, -1, 1); } if (!_flyByWire) { return; } Quaternion tgt = Quaternion.LookRotation(_tgtFwd, _tgtUp); Quaternion delta = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(part.vessel.transform.rotation) * tgt); _headingError = new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x, (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y, (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F; _integral += _headingError * TimeWarp.fixedDeltaTime; _deriv = (_headingError - _prevErr) / TimeWarp.fixedDeltaTime; _act = Kp * _headingError + Ki * _integral + Kd * _deriv; _prevErr = _headingError; controls.pitch = Mathf.Clamp(controls.pitch + _act.x, -1.0F, 1.0F); controls.yaw = Mathf.Clamp(controls.yaw - _act.y, -1.0F, 1.0F); controls.roll = Mathf.Clamp(controls.roll + _act.z, -1.0F, 1.0F); }