Skip to content

Commit

Permalink
fix(fmgc): remove TAKEOFF to PREFLIGHT transition (#7117)
Browse files Browse the repository at this point in the history
  • Loading branch information
beheh authored and aguther committed May 9, 2022
1 parent 583648e commit 0faa72b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 65 deletions.
55 changes: 51 additions & 4 deletions src/fmgc/src/flightphase/FlightPhaseManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Phase, PreFlightPhase, TakeOffPhase, ClimbPhase, CruisePhase, DescentPhase, ApproachPhase, GoAroundPhase, DonePhase } from '@fmgc/flightphase/Phase';
import { VerticalMode } from '@shared/autopilot';
import { FmgcFlightPhase } from '@shared/flightphase';
import { FmgcFlightPhase, isAnEngineOn, isOnGround, isReady, isSlewActive } from '@shared/flightphase';
import { ConfirmationNode } from '@shared/logic';

function canInitiateDes(distanceToDestination: number): boolean {
const fl = Math.round(Simplane.getAltitude() / 100);
Expand All @@ -13,7 +14,9 @@ function canInitiateDes(distanceToDestination: number): boolean {
}

export class FlightPhaseManager {
private activePhase: FmgcFlightPhase = SimVar.GetSimVarValue('L:A32NX_INITIAL_FLIGHT_PHASE', 'number') || FmgcFlightPhase.Preflight;
private onGroundConfirmationNode = new ConfirmationNode(30 * 1000);

private activePhase: FmgcFlightPhase = this.initialPhase || FmgcFlightPhase.Preflight;

private phases: { [key in FmgcFlightPhase]: Phase } = {
[FmgcFlightPhase.Preflight]: new PreFlightPhase(),
Expand All @@ -32,14 +35,30 @@ export class FlightPhaseManager {
return this.activePhase;
}

get initialPhase() {
return SimVar.GetSimVarValue('L:A32NX_INITIAL_FLIGHT_PHASE', 'number');
}

init(): void {
console.log(`FMGC Flight Phase: ${this.phase}`);
this.phases[this.phase].init();
this.changePhase(this.activePhase);
}

shouldActivateNextPhase(_deltaTime: number): void {
if (this.phases[this.phase].shouldActivateNextPhase(_deltaTime)) {
this.changePhase(this.phases[this.phase].nextPhase);
// process transitions only when plane is ready
if (isReady() && !isSlewActive()) {
if (this.shouldActivateDonePhase(_deltaTime)) {
this.changePhase(FmgcFlightPhase.Done);
} else if (this.phases[this.phase].shouldActivateNextPhase(_deltaTime)) {
this.changePhase(this.phases[this.phase].nextPhase);
}
} else if (isReady() && isSlewActive()) {
this.handleSlewSituation(_deltaTime);
} else if (this.activePhase !== this.initialPhase) {
// ensure correct init of phase
this.activePhase = this.initialPhase;
this.changePhase(this.initialPhase);
}
}

Expand Down Expand Up @@ -110,6 +129,15 @@ export class FlightPhaseManager {
}
}

handleNewDestinationAirportEntered(): void {
if (this.activePhase === FmgcFlightPhase.GoAround) {
const accAlt = SimVar.GetSimVarValue('L:AIRLINER_ACC_ALT_GOAROUND', 'Number');
if (Simplane.getAltitude() > accAlt) {
this.changePhase(FmgcFlightPhase.Climb);
}
}
}

changePhase(newPhase: FmgcFlightPhase): void {
const prevPhase = this.phase;
console.log(`FMGC Flight Phase: ${prevPhase} => ${newPhase}`);
Expand Down Expand Up @@ -142,4 +170,23 @@ export class FlightPhaseManager {

return true;
}

shouldActivateDonePhase(_deltaTime: number): boolean {
this.onGroundConfirmationNode.input = isOnGround();
this.onGroundConfirmationNode.update(_deltaTime);
return this.onGroundConfirmationNode.output && !isAnEngineOn() && this.phase !== FmgcFlightPhase.Done && this.phase !== FmgcFlightPhase.Preflight;
}

handleSlewSituation(_deltaTime: number) {
switch (this.phase) {
case FmgcFlightPhase.Preflight:
case FmgcFlightPhase.Takeoff:
case FmgcFlightPhase.Done:
if (Simplane.getAltitudeAboveGround() >= 1500) {
this.changePhase(FmgcFlightPhase.Climb);
}
break;
default:
}
}
}
81 changes: 22 additions & 59 deletions src/fmgc/src/flightphase/Phase.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,25 @@
import { FmgcFlightPhase, isAllEngineOn, isAnEngineOn } from '@shared/flightphase';
import { VerticalMode } from '@shared/autopilot';
import { FmgcFlightPhase, getAutopilotVerticalMode, isAllEngineOn, isAnEngineOn, isOnGround, conditionTakeOff } from '@shared/flightphase';
import { ConfirmationNode } from '@shared/logic';

export abstract class Phase {
// eslint-disable-next-line no-empty-function
init(): void { }
init(): void { /* prototype function */ }

abstract shouldActivateNextPhase(time: any): boolean;

nextPhase: FmgcFlightPhase;

protected canInitiateTO(): boolean {
const v2 = SimVar.GetSimVarValue('L:AIRLINER_V2_SPEED', 'knots');

return SimVar.GetSimVarValue('CAMERA STATE', 'number') < 10 && Simplane.getAltitudeAboveGround() > 1.5
|| (
Math.max(SimVar.GetSimVarValue('L:A32NX_AUTOTHRUST_TLA:1', 'number'), SimVar.GetSimVarValue('L:A32NX_AUTOTHRUST_TLA:2', 'number')) >= 35
&& !Number.isNaN(v2)
&& (
(
SimVar.GetSimVarValue('ENG N1 RPM:1', 'percent') > 0.85
&& SimVar.GetSimVarValue('ENG N1 RPM:2', 'percent') > 0.85
)
|| Math.abs(Simplane.getGroundSpeed()) > 80
)
);
}
}

export class PreFlightPhase extends Phase {
takeoffConfirmation = new ConfirmationNode(0.2 * 1000);

nextPhase = FmgcFlightPhase.Takeoff;
init() {
this.nextPhase = FmgcFlightPhase.Takeoff;
}

shouldActivateNextPhase(_deltaTime) {
this.takeoffConfirmation.input = this.canInitiateTO();
this.takeoffConfirmation.input = conditionTakeOff();
this.takeoffConfirmation.update(_deltaTime);
return this.takeoffConfirmation.output;
}
Expand All @@ -54,18 +40,6 @@ export class TakeOffPhase extends Phase {
}

shouldActivateNextPhase(_deltaTime) {
const isAcOnGround = Simplane.getAltitudeAboveGround() <= 1.5;

if (isAcOnGround && Math.max(SimVar.GetSimVarValue('L:A32NX_AUTOTHRUST_TLA:1', 'number'), SimVar.GetSimVarValue('L:A32NX_AUTOTHRUST_TLA:2', 'number')) < 35) {
this.nextPhase = FmgcFlightPhase.Preflight;
return true;
}

if (isAcOnGround && !isAnEngineOn()) {
this.nextPhase = FmgcFlightPhase.Done;
return true;
}

return Simplane.getAltitude() > (isAllEngineOn() ? this.accelerationAltitudeMsl : this.accelerationAltitudeMslEo);
}
}
Expand All @@ -77,21 +51,19 @@ export class ClimbPhase extends Phase {

shouldActivateNextPhase(_deltaTime) {
const cruiseFl = SimVar.GetSimVarValue('L:AIRLINER_CRUISE_ALTITUDE', 'number') / 100;

if (!isAnEngineOn() && Simplane.getAltitudeAboveGround() < 1.5) {
this.nextPhase = FmgcFlightPhase.Done;
return true;
}

return Math.round(SimVar.GetSimVarValue('INDICATED ALTITUDE:3', 'feet') / 100) >= cruiseFl;
const fl = Math.round(SimVar.GetSimVarValue('INDICATED ALTITUDE:3', 'feet') / 100);
return fl >= cruiseFl;
}
}

export class CruisePhase extends Phase {
nextPhase = FmgcFlightPhase.Done;
init() {
// switch out of cruise phase is handled in FlightPhaseManager
this.nextPhase = FmgcFlightPhase.Cruise;
}

shouldActivateNextPhase(_deltaTime) {
return !isAnEngineOn() && Simplane.getAltitudeAboveGround() < 1.5;
return false;
}
}

Expand All @@ -110,11 +82,6 @@ export class DescentPhase extends Phase {
return true;
}

if (!isAnEngineOn() && Simplane.getAltitudeAboveGround() < 1.5) {
this.nextPhase = FmgcFlightPhase.Done;
return true;
}

// APPROACH phase from DECEL pseudo waypoint case. This is decided by the new TS FMS.
return !!SimVar.GetSimVarValue('L:A32NX_FM_ENABLE_APPROACH_PHASE', 'Bool');
}
Expand All @@ -129,41 +96,37 @@ export class ApproachPhase extends Phase {
}

shouldActivateNextPhase(_deltaTime) {
if (SimVar.GetSimVarValue('L:A32NX_FMA_VERTICAL_MODE', 'number') === 41) {
if (getAutopilotVerticalMode() === VerticalMode.SRS_GA) {
this.nextPhase = FmgcFlightPhase.GoAround;
return true;
}

this.landingConfirmation.input = Simplane.getAltitudeAboveGround() < 1.5;
this.landingConfirmation.input = isOnGround();
this.landingConfirmation.update(_deltaTime);
return this.landingConfirmation.output || !isAnEngineOn();
}
}

export class GoAroundPhase extends Phase {
nextPhase = FmgcFlightPhase.Done;

init() {
SimVar.SetSimVarValue('L:AIRLINER_TO_FLEX_TEMP', 'Number', 0);
this.nextPhase = FmgcFlightPhase.GoAround;
}

shouldActivateNextPhase(_deltaTime) {
return !isAnEngineOn() && Simplane.getAltitudeAboveGround() < 1.5;
// there is no automatic switch from this phase
return false;
}
}

export class DonePhase extends Phase {
takeoffConfirmation = new ConfirmationNode(0.2 * 1000);

nextPhase = FmgcFlightPhase.Takeoff;

init() {
SimVar.SetSimVarValue('L:AIRLINER_TO_FLEX_TEMP', 'Number', 0);
this.nextPhase = FmgcFlightPhase.Done;
}

shouldActivateNextPhase(_deltaTime) {
this.takeoffConfirmation.input = this.canInitiateTO();
this.takeoffConfirmation.update(_deltaTime);
return this.takeoffConfirmation.output;
// there is no automatic switch from this phase
return false;
}
}
38 changes: 36 additions & 2 deletions src/shared/src/flightphase.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { VerticalMode } from '@shared/autopilot';

export enum FmgcFlightPhase {
Preflight,
Takeoff,
Expand All @@ -9,10 +11,42 @@ export enum FmgcFlightPhase {
Done,
}

export function isReady(): boolean {
return SimVar.GetSimVarValue('L:A32NX_IS_READY', 'number') === 1;
}

export function isSlewActive(): boolean {
return SimVar.GetSimVarValue('IS SLEW ACTIVE', 'bool');
}

export function isOnGround(): boolean {
return SimVar.GetSimVarValue('L:A32NX_LGCIU_1_NOSE_GEAR_COMPRESSED', 'bool')
|| SimVar.GetSimVarValue('L:A32NX_LGCIU_2_NOSE_GEAR_COMPRESSED', 'bool');
}

function isEngineOn(index: number): boolean {
return SimVar.GetSimVarValue(`L:A32NX_ENGINE_N2:${index}`, 'number') > 20;
}

function isEngineOnTakeOffThrust(index: number): boolean {
return SimVar.GetSimVarValue(`L:A32NX_ENGINE_N1:${index}`, 'number') >= 70;
}

export function isAnEngineOn(): boolean {
return Simplane.getEngineActive(0) || Simplane.getEngineActive(1);
return isEngineOn(1) || isEngineOn(2);
}

export function isAllEngineOn(): boolean {
return Simplane.getEngineActive(0) && Simplane.getEngineActive(1);
return isEngineOn(1) && isEngineOn(2);
}

export function getAutopilotVerticalMode(): VerticalMode {
return SimVar.GetSimVarValue('L:A32NX_FMA_VERTICAL_MODE', 'Enum');
}

export function conditionTakeOff(): boolean {
return (
(getAutopilotVerticalMode() === VerticalMode.SRS && isEngineOnTakeOffThrust(1) && isEngineOnTakeOffThrust(2))
|| Math.abs(Simplane.getGroundSpeed()) > 90
);
}

0 comments on commit 0faa72b

Please sign in to comment.