Skip to content

Commit

Permalink
RELEASE: main script, front page update
Browse files Browse the repository at this point in the history
  • Loading branch information
Noiredd committed Jul 29, 2017
1 parent 1be0591 commit 66a4dac
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 14 deletions.
42 changes: 28 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
## PEGAS
*Powered Explicit Guidance Ascent System* is an autopilot for Kerbal Space Program made and ran in [kOS](http://forum.kerbalspaceprogram.com/index.php?/topic/61827-122-kos-scriptable-autopilot-system-v103-20161207/), designed to control launch vehicles under a modified version of the game running [Realism Overhaul](http://forum.kerbalspaceprogram.com/threads/99966). Its unique feature is an implementation of a real-word rocket guidance algorithm: previously [Powered Explicit Guidance](http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19660006073.pdf), more recently [Unified Powered Flight Guidance](https://ntrs.nasa.gov/search.jsp?R=19740004402) - as used in the **Space Shuttle** GN&C computer.
*Powered Explicit Guidance Ascent System*, from here referred to as *PEGAS*, is an ascent autopilot for Kerbal Space Program made and ran in [kOS](http://forum.kerbalspaceprogram.com/index.php?/topic/61827-122-kos-scriptable-autopilot-system-v103-20161207/), designed to control launch vehicles under a modified version of the game running [Realism Overhaul](http://forum.kerbalspaceprogram.com/index.php?/topic/155700-113-realism-overhaul).
Its unique feature is an implementation of a real-word rocket guidance algorithm: Unified Powered Flight Guidance, as used in the **Space Shuttle** GN&C computer for the standard ascent flight mode.
Short list of what PEGAS is capable of:
* estimation of a launch window,
* calculation of a launch azimuth,
* simple atmospheric ascent by pitching over and holding prograde with zero angle of attack,
* automatic guidance to orbits defined by:
* apoapse
* periapse
* inclination
* longitude of ascending node
* or, alternatively, selecting an existing target,
* executing of timed events (engine ignition, payload fairing jettison etc.),
* automatic staging with ullage handling.

Right now PEGAS is undergoing a major rework: previously it implemented an old version of PEG, which (among its many limitations) only supported launching to circular orbits with no control over plane - constant azimuth was assumed throughout the mission. Now a full implementation of UPFG (in standard ascent mode) is being coded - this will allow it to target orbits not only of a given shape (apoapsis + periapsis), but also in a given plane (inclination + longitude of ascending node).
More info on my KSP [forum thread](http://forum.kerbalspaceprogram.com/index.php?/topic/142213-pegas-powered-explicit-guidance-ascent-system-devlog/), also see my [prototype repository](https://github.com/Noiredd/PEGAS-MATLAB).

### Recent advances
**IMPORTANT**: PEGAS repository has been split into two: [PEGAS-MATLAB](https://github.com/Noiredd/PEGAS-MATLAB) contains the prototype written in MATLAB, with all its bells, whistles and sophistication. This repository ([PEGAS](https://github.com/Noiredd/PEGAS)) *will contain* kOS code, ready-to-use for your launches.
### How to use - see [tutorial](tutorial.md) and [reference](reference.md)
1. Dowload files from this repository's [kOS folder](kOS) and place them in your `Script` folder.
2. Define your vehicle and mission.
3. Once on the launch pad, load the definitions from pt. 2. and type `run pegas.` in kOS terminal.

PEGAS now uses a very general guidance algorithm, the Unified Powered Flight Guidance. Brief list of most important features includes:
* targetting orbits with periapsis/apoapsis and **plane** constraints (inclination + longitude of ascending node),
* support for multistage vehicles with constant-thrust and acceleration-limited modes,
* simple atmospheric stage guidance in a "pitch over and hold prograde" mode,
* automatically estimated launch window basing on launch site position and target orbit,
* no complicated pre-flight analysis needed - as long as the vehicle has enough power, missing the window slightly will not affect insertion precision.
### Disclaimer
This is a first public release of PEGAS.
Due to sheer amount of work on prototyping and coding it, and the range of potential problems with launch vehicles, I have been unable to test it with many rockets.
Therefore, I cannot guarantee that it will handle *any* vehicle or that it is entirely bug-free.
Likely, it will take you several tries before you get your rocket flying - and maybe you will find yourself unable to do that at all.
I am willing to provide support, correct bugs and (to some extent) introduce new functionalities to PEGAS.
In case of problems: read the [how to submit issues](docs/issues.md) page and then visit the issue tracker.

### Preview
You can see the old version of PEGAS in my youtube video below. This will be soon replaced by a new thing, once it's ready.

<a href="https://youtu.be/0LGAizO-6K4" target="_blank"><img src="http://img.youtube.com/vi/0LGAizO-6K4/0.jpg" width="240" height="180" border="10" /></a>
### Demo
<a href="https://youtu.be/NEQD7AQoLXk" target="_blank"><img src="http://img.youtube.com/vi/NEQD7AQoLXk/0.jpg" width="240" height="180" border="10" /></a>
171 changes: 171 additions & 0 deletions kOS/pegas.ks
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// If no boot file was loaded, this check will immediately crash PEGAS, saving time that would otherwise be wasted on loading libraries.
IF NOT (DEFINED vehicle) OR NOT (DEFINED sequence) OR NOT (DEFINED controls) OR NOT (DEFINED mission) {
PRINT "".
PRINT "No boot file loaded! Crashing...".
PRINT "".
SET _ TO sequence.
SET _ TO controls.
SET _ TO vehicle.
SET _ TO mission.
}

// The following is absolutely necessary to run UPFG fast enough.
SET CONFIG:IPU TO 500.

// Set up constants.
GLOBAL g0 IS 9.8067. // PEGAS will launch from any planet or moon - "g0" is a standard constant for thrust computation and shall not be changed!
GLOBAL pitchOverTimeLimit IS 20. // In atmospheric part of ascent, when the vehicle pitches over, the wait for velocity vector to align will be forcibly broken after that many second.
GLOBAL upfgConvergenceDelay IS 5. // seconds before "upfgActivation" that we switch into loop 2 to give UPFG time to converge
GLOBAL upfgFinalizationTime IS 5. // When time-to-go gets below that, keep attitude stable and simply count down time to cutoff.
GLOBAL stagingKillRotTime IS 5. // That many seconds before staging, updating attitude commands will be forbidden, allowing clean separation.
GLOBAL upfgConvergenceCriterion IS 0.1. // Maximum difference between consecutive UPFG T-go predictions that allow accepting the solution.
GLOBAL upfgGoodSolutionCriterion IS 15. // Maximum angle between guidance vectors calculated by UPFG between stages that allow accepting the solution.

// Load libraries.
RUN pegas_cser.
RUN pegas_upfg.
RUN pegas_util.
RUN pegas_misc.

// Initialize global flags
GLOBAL upfgStage IS -1. // Seems wrong (we use "vehicle[upfgStage]") but first run of stageEventHandler increments this automatically
GLOBAL stageEventFlag IS FALSE.
GLOBAL systemEvents IS LIST().
GLOBAL systemEventPointer IS -1. // Same deal as with "upfgStage"
GLOBAL systemEventFlag IS FALSE.
GLOBAL userEventPointer IS -1. // As above
GLOBAL userEventFlag IS FALSE.
GLOBAL throttleSetting IS 1.
GLOBAL steeringVector IS LOOKDIRUP(SHIP:FACING:FOREVECTOR, SHIP:FACING:TOPVECTOR).
GLOBAL upfgConverged IS FALSE.
GLOBAL stagingInProgress IS FALSE.


// PREFLIGHT ACTIVITIES
// Set up UPFG target and silently upgrade mission target
SET upfgTarget TO targetSetup().
// Calculate time to launch
SET currentTime TO TIME.
SET timeToOrbitIntercept TO orbitInterceptTime().
GLOBAL liftoffTime IS currentTime + timeToOrbitIntercept - controls["launchTimeAdvance"].
IF timeToOrbitIntercept < controls["launchTimeAdvance"] { SET liftoffTime TO liftoffTime + SHIP:BODY:ROTATIONPERIOD. }
// Calculate launch azimuth if not specified
IF NOT mission:HASKEY("launchAzimuth") {
mission:ADD("launchAzimuth", launchAzimuth()).
}
// Set up the system for flight
setSystemEvents(). // Set up countdown messages
setUserEvents(). // Initialize vehicle sequence
setVehicle(). // Complete vehicle definition (as given by user)


// PEGAS TAKES CONTROL OF THE MISSION
createUI().
// Prepare control for vertical ascent
LOCK THROTTLE TO throttleSetting.
LOCK STEERING TO steeringVector.
SET ascentFlag TO 0. // 0 = vertical, 1 = pitching over, 2 = notify about holding prograde, 3 = just hold prograde
// Main loop - wait on launch pad, lift-off and passive guidance
UNTIL ABORT {
// Sequence handling
IF systemEventFlag = TRUE { systemEventHandler(). }
IF userEventFlag = TRUE { userEventHandler(). }
// Control handling
IF ascentFlag = 0 {
// The vehicle is going straight up for given amount of time
IF TIME:SECONDS >= liftoffTime:SECONDS + controls["verticalAscentTime"] {
// Then it changes attitude for an initial pitchover "kick"
SET steeringVector TO LOOKDIRUP(HEADING(mission["launchAzimuth"],90-controls["pitchOverAngle"]):VECTOR, SHIP:FACING:TOPVECTOR).
SET ascentFlag TO 1.
pushUIMessage( "Pitching over by " + ROUND(controls["pitchOverAngle"],1) + " degrees." ).
}
}
ELSE IF ascentFlag = 1 {
// It keeps this attitude until velocity vector matches it closely
IF TIME:SECONDS < liftoffTime:SECONDS + controls["verticalAscentTime"] + 3 {
// Delay this check for the first few seconds to allow the vehicle to pitch away from current prograde
} ELSE {
// Attitude must be recalculated at every iteration though
SET velocityAngle TO VANG(SHIP:UP:VECTOR, SHIP:VELOCITY:SURFACE).
IF controls["pitchOverAngle"] - velocityAngle < 0.1 {
SET ascentFlag TO 2.
}
}
// As a safety check - do not stay deadlocked in this state for too long (might be unnecessary).
IF TIME:SECONDS >= liftoffTime:SECONDS + controls["verticalAscentTime"] + pitchOverTimeLimit {
SET ascentFlag TO 2.
pushUIMessage( "Pitchover time limit exceeded!", 5, PRIORITY_HIGH ).
}
}
ELSE IF ascentFlag = 2 {
// We cannot blindly hold prograde though, because this will provide no azimuth control
// Much better option is to read current velocity angle and aim for that, but correct for azimuth
SET velocityAngle TO 90-VANG(SHIP:UP:VECTOR, SHIP:VELOCITY:SURFACE).
SET steeringVector TO LOOKDIRUP(HEADING(mission["launchAzimuth"],velocityAngle):VECTOR, SHIP:FACING:TOPVECTOR).
// There are two almost identical cases, in the first we set the initial message, in the next we just keep attitude.
pushUIMessage( "Holding prograde at " + ROUND(mission["launchAzimuth"],1) + " deg azimuth." ).
SET ascentFlag TO 3.
}
ELSE {
SET velocityAngle TO 90-VANG(SHIP:UP:VECTOR, SHIP:VELOCITY:SURFACE).
SET steeringVector TO LOOKDIRUP(HEADING(mission["launchAzimuth"],velocityAngle):VECTOR, SHIP:FACING:TOPVECTOR).
}
// The passive guidance loop ends a few seconds before actual ignition of the first UPFG-controlled stage.
// This is to give UPFG time to converge. Actual ignition occurs via stagingEvents.
IF TIME:SECONDS >= liftoffTime:SECONDS + controls["upfgActivation"] - upfgConvergenceDelay {
pushUIMessage( "Initiating UPFG!" ).
BREAK.
}
// UI - recalculate UPFG target solely for printing relative angle
SET upfgTarget["normal"] TO targetNormal(mission["inclination"], mission["LAN"]).
refreshUI().
WAIT 0.
}.


// ACTIVE GUIDANCE
createUI().
// Initialize UPFG
initializeVehicle().
SET upfgState TO acquireState().
SET upfgInternal TO setupUPFG().
// Main loop - iterate UPFG (respective function controls attitude directly)
UNTIL ABORT {
// Sequence handling
IF systemEventFlag = TRUE { systemEventHandler(). }
IF userEventFlag = TRUE { userEventHandler(). }
IF stageEventFlag = TRUE { stageEventHandler(). }
// Update UPFG target and vehicle state
SET upfgTarget["normal"] TO targetNormal(mission["inclination"], mission["LAN"]).
SET upfgState TO acquireState().
// Iterate UPFG and preserve its state
SET upfgInternal TO upfgSteeringControl(vehicle, upfgStage, upfgTarget, upfgState, upfgInternal).
// Manage throttle, with the exception of initial portion of guided flight (where we're technically still flying the first stage).
IF upfgStage >= 0 { throttleControl(). }
// For the final seconds of the flight, just hold attitude and wait.
IF upfgConverged AND upfgInternal["tgo"] < upfgFinalizationTime { BREAK. }
// UI
refreshUI().
WAIT 0.
}.
// Final orbital insertion loop
pushUIMessage( "Holding attitude for burn finalization!" ).
SET previousTime TO TIME:SECONDS.
UNTIL ABORT {
LOCAL finalizeDT IS TIME:SECONDS - previousTime.
SET previousTime TO TIME:SECONDS.
SET upfgInternal["tgo"] TO upfgInternal["tgo"] - finalizeDT.
IF upfgInternal["tgo"] < finalizeDT { BREAK. } // Exit loop before entering the next refresh cycle
// We could have done "tgo < 0" but this would mean that the previous loop tgo was 0.01 yet we still didn't break
refreshUI().
WAIT 0.
}.


// EXIT
UNLOCK STEERING.
UNLOCK THROTTLE.
SET SHIP:CONTROL:PILOTMAINTHROTTLE TO 0.
WAIT 0.
missionValidation().
refreshUI().

0 comments on commit 66a4dac

Please sign in to comment.