Skip to content

Commit 9caf9f3

Browse files
committed
AAU2 SDK Update
1 parent 90ade0e commit 9caf9f3

File tree

1,037 files changed

+70015
-12921
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,037 files changed

+70015
-12921
lines changed

src/garminsdk/autopilot/GarminAPConfig.ts

Lines changed: 89 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import { GarminObsDirector } from './directors';
88
import { GarminNavToNavManager } from './GarminNavToNavManager';
99
import { GarminVNavGuidanceOptions, GarminVNavManager2 } from './GarminVNavManager2';
10+
import { AutopilotDriverOptions } from '@microsoft/msfs-sdk/autopilot/AutopilotDriver';
1011

1112
/**
1213
* Options for configuring a Garmin LNAV director.
@@ -17,38 +18,63 @@ export type GarminLNavDirectorOptions = Pick<LNavDirectorOptions, 'disableArming
1718
* Options for configuring Garmin autopilot directors.
1819
*/
1920
export type GarminAPConfigDirectorOptions = {
21+
/** The default rate at which commanded pitch changes, in degrees per second. Defaults to `5`. */
22+
defaultPitchRate?: number;
23+
24+
/** The default rate at which commanded bank changes, in degrees per second. Defaults to `10`. */
25+
defaultBankRate?: number;
26+
2027
/** Options for the LNAV director. */
21-
lnavOptions: Partial<Readonly<GarminLNavDirectorOptions>>;
28+
lnavOptions?: Partial<Readonly<GarminLNavDirectorOptions>>;
2229

2330
/** Options for the VNAV director. */
24-
vnavOptions: Partial<Readonly<GarminVNavGuidanceOptions>>;
31+
vnavOptions?: Partial<Readonly<GarminVNavGuidanceOptions>>;
32+
33+
/** The minimum bank angle, in degrees, supported by the ROL director. Defaults to `6`. */
34+
rollMinBankAngle?: number;
2535

26-
/** The minimum bank angle, in degrees, supported by the ROL director. */
27-
rollMinBankAngle: number;
36+
/** The maximum bank angle, in degrees, supported by the ROL director. Defaults to `25`. */
37+
rollMaxBankAngle?: number;
2838

29-
/** The maximum bank angle, in degrees, supported by the ROL director. */
30-
rollMaxBankAngle: number;
39+
/** The maximum bank angle, in degrees, supported by the HDG director. Defaults to `25`. */
40+
hdgMaxBankAngle?: number;
3141

32-
/** The maximum bank angle, in degrees, supported by the HDG director. */
33-
hdgMaxBankAngle: number;
42+
/** The maximum bank angle, in degrees, supported by the VOR director. Defaults to `25`. */
43+
vorMaxBankAngle?: number;
3444

35-
/** The maximum bank angle, in degrees, supported by the VOR director. */
36-
vorMaxBankAngle: number;
45+
/** The maximum bank angle, in degrees, supported by the LOC director. Defaults to `25`. */
46+
locMaxBankAngle?: number;
3747

38-
/** The maximum bank angle, in degrees, supported by the LOC director. */
39-
locMaxBankAngle: number;
48+
/** The maximum bank angle, in degrees, supported by the LNAV director. Defaults to `25`. */
49+
lnavMaxBankAngle?: number;
4050

41-
/** The maximum bank angle, in degrees, supported by the LNAV director. */
42-
lnavMaxBankAngle: number;
51+
/**
52+
* The maximum bank angle, in degrees, to apply to the HDG, VOR, LOC, and LNAV directors while in Low Bank Mode.
53+
* Defaults to `15`.
54+
*/
55+
lowBankAngle?: number;
4356

44-
/** The maximum bank angle, in degrees, to apply to the HDG, VOR, LOC, and LNAV directors while in Low Bank Mode. */
45-
lowBankAngle: number;
57+
/**
58+
* The threshold difference between selected heading and current heading, in degrees, at which the heading director
59+
* unlocks its commanded turn direction and chooses a new optimal turn direction to establish on the selected
60+
* heading, potentially resulting in a turn reversal. Any value less than or equal to 180 degrees effectively
61+
* prevents the director from locking a commanded turn direction. Any value greater than or equal to 360 degrees will
62+
* require the selected heading to traverse past the current heading in the desired turn direction in order for the
63+
* director to issue a turn reversal. Defaults to `331`.
64+
*/
65+
hdgTurnReversalThreshold?: number;
4666
};
4767

4868
/**
4969
* A Garmin Autopilot Configuration.
5070
*/
5171
export class GarminAPConfig implements APConfig {
72+
/** The default commanded pitch angle rate, in degrees per second. */
73+
public static readonly DEFAULT_PITCH_RATE = 5;
74+
75+
/** The default commanded bank angle rate, in degrees per second. */
76+
public static readonly DEFAULT_BANK_RATE = 10;
77+
5278
/** The default minimum bank angle, in degrees, for ROL director. */
5379
public static readonly DEFAULT_ROLL_MIN_BANK_ANGLE = 6;
5480

@@ -58,10 +84,15 @@ export class GarminAPConfig implements APConfig {
5884
/** The default maximum bank angle, in degrees, in Low Bank Mode. */
5985
public static readonly DEFAULT_LOW_BANK_ANGLE = 15;
6086

87+
/** The default HDG director turn direction unlock threshold, in degrees. */
88+
public static readonly DEFAULT_HDG_DIRECTION_UNLOCK_THRESHOLD = 331;
89+
6190
public defaultLateralMode = APLateralModes.ROLL;
6291
public defaultVerticalMode = APVerticalModes.PITCH;
6392
public defaultMaxBankAngle = GarminAPConfig.DEFAULT_MAX_BANK_ANGLE;
6493

94+
public autopilotDriverOptions: AutopilotDriverOptions;
95+
6596
/** Options for the LNAV director. */
6697
private readonly lnavOptions: Partial<Readonly<GarminLNavDirectorOptions>>;
6798

@@ -76,28 +107,26 @@ export class GarminAPConfig implements APConfig {
76107
private readonly lnavMaxBankAngle: number;
77108
private readonly lowBankAngle: number;
78109

110+
private readonly hdgTurnReversalThreshold: number;
111+
79112
/**
80113
* Creates a new instance of GarminAPConfig.
81114
* @param bus The event bus.
82115
* @param flightPlanner The flight planner.
83116
* @param verticalPathCalculator The vertical path calculator to use for the VNAV director.
84-
* @param options Options to configure the directors. Option values default to the following if not defined:
85-
* * `lnavOptions`: `undefined`
86-
* * `vnavOptions`: `undefined`
87-
* * `rollMinBankAngle`: `GarminAPConfig.DEFAULT_ROLL_MIN_BANK_ANGLE`
88-
* * `rollMaxBankAngle`: `GarminAPConfig.DEFAULT_MAX_BANK_ANGLE`
89-
* * `hdgMaxBankAngle`: `GarminAPConfig.DEFAULT_MAX_BANK_ANGLE`
90-
* * `vorMaxBankAngle`: `GarminAPConfig.DEFAULT_MAX_BANK_ANGLE`
91-
* * `locMaxBankAngle`: `GarminAPConfig.DEFAULT_MAX_BANK_ANGLE`
92-
* * `lnavMaxBankAngle`: `GarminAPConfig.DEFAULT_MAX_BANK_ANGLE`
93-
* * `lowBankAngle`: `GarminAPConfig.DEFAULT_LOW_BANK_ANGLE`
117+
* @param options Options to configure the directors.
94118
*/
95119
constructor(
96120
private readonly bus: EventBus,
97121
private readonly flightPlanner: FlightPlanner,
98122
private readonly verticalPathCalculator: VNavPathCalculator,
99-
options?: Partial<Readonly<GarminAPConfigDirectorOptions>>
123+
options?: Readonly<GarminAPConfigDirectorOptions>
100124
) {
125+
this.autopilotDriverOptions = {
126+
pitchServoRate: options?.defaultPitchRate ?? GarminAPConfig.DEFAULT_PITCH_RATE,
127+
bankServoRate: options?.defaultBankRate ?? GarminAPConfig.DEFAULT_BANK_RATE
128+
};
129+
101130
this.lnavOptions = { ...options?.lnavOptions };
102131
this.vnavOptions = { ...options?.vnavOptions };
103132
this.rollMinBankAngle = options?.rollMinBankAngle ?? GarminAPConfig.DEFAULT_ROLL_MIN_BANK_ANGLE;
@@ -107,6 +136,7 @@ export class GarminAPConfig implements APConfig {
107136
this.locMaxBankAngle = options?.locMaxBankAngle ?? GarminAPConfig.DEFAULT_MAX_BANK_ANGLE;
108137
this.lnavMaxBankAngle = options?.lnavMaxBankAngle ?? GarminAPConfig.DEFAULT_MAX_BANK_ANGLE;
109138
this.lowBankAngle = options?.lowBankAngle ?? GarminAPConfig.DEFAULT_LOW_BANK_ANGLE;
139+
this.hdgTurnReversalThreshold = options?.hdgTurnReversalThreshold ?? GarminAPConfig.DEFAULT_HDG_DIRECTION_UNLOCK_THRESHOLD;
110140
}
111141

112142
/** @inheritdoc */
@@ -117,7 +147,8 @@ export class GarminAPConfig implements APConfig {
117147
/** @inheritdoc */
118148
public createHeadingDirector(apValues: APValues): APHdgDirector {
119149
return new APHdgDirector(this.bus, apValues, {
120-
maxBankAngle: () => apValues.maxBankId.get() === 1 ? Math.min(this.hdgMaxBankAngle, this.lowBankAngle) : this.hdgMaxBankAngle
150+
maxBankAngle: () => apValues.maxBankId.get() === 1 ? Math.min(this.hdgMaxBankAngle, this.lowBankAngle) : this.hdgMaxBankAngle,
151+
turnReversalThreshold: this.hdgTurnReversalThreshold
121152
});
122153
}
123154

@@ -138,12 +169,12 @@ export class GarminAPConfig implements APConfig {
138169

139170
/** @inheritdoc */
140171
public createRollDirector(apValues: APValues): APRollDirector {
141-
return new APRollDirector(this.bus, apValues, { minBankAngle: this.rollMinBankAngle, maxBankAngle: this.rollMaxBankAngle });
172+
return new APRollDirector(apValues, { minBankAngle: this.rollMinBankAngle, maxBankAngle: this.rollMaxBankAngle });
142173
}
143174

144175
/** @inheritdoc */
145-
public createWingLevelerDirector(): APLvlDirector {
146-
return new APLvlDirector(this.bus);
176+
public createWingLevelerDirector(apValues: APValues): APLvlDirector {
177+
return new APLvlDirector(this.bus, apValues);
147178
}
148179

149180
/** @inheritdoc */
@@ -185,7 +216,7 @@ export class GarminAPConfig implements APConfig {
185216

186217
/** @inheritdoc */
187218
public createBcDirector(apValues: APValues): APBackCourseDirector {
188-
return new APBackCourseDirector(this.bus, apValues, APLateralModes.BC, {
219+
return new APBackCourseDirector(this.bus, apValues, {
189220
maxBankAngle: () => apValues.maxBankId.get() === 1 ? Math.min(this.locMaxBankAngle, this.lowBankAngle) : this.locMaxBankAngle,
190221
lateralInterceptCurve: GarminAPConfig.navInterceptCurve
191222
});
@@ -203,7 +234,7 @@ export class GarminAPConfig implements APConfig {
203234

204235
/** @inheritdoc */
205236
public createVsDirector(apValues: APValues): APVSDirector {
206-
return new APVSDirector(this.bus, apValues);
237+
return new APVSDirector(apValues);
207238
}
208239

209240
/** @inheritdoc */
@@ -213,17 +244,17 @@ export class GarminAPConfig implements APConfig {
213244

214245
/** @inheritdoc */
215246
public createFlcDirector(apValues: APValues): APFLCDirector {
216-
return new APFLCDirector(this.bus, apValues);
247+
return new APFLCDirector(apValues);
217248
}
218249

219250
/** @inheritdoc */
220251
public createAltHoldDirector(apValues: APValues): APAltDirector {
221-
return new APAltDirector(this.bus, apValues);
252+
return new APAltDirector(apValues);
222253
}
223254

224255
/** @inheritdoc */
225256
public createAltCapDirector(apValues: APValues): APAltCapDirector {
226-
return new APAltCapDirector(this.bus, apValues);
257+
return new APAltCapDirector(apValues);
227258
}
228259

229260
/** @inheritdoc */
@@ -232,8 +263,9 @@ export class GarminAPConfig implements APConfig {
232263
}
233264

234265
/** @inheritdoc */
266+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
235267
public createVNavPathDirector(apValues: APValues): PlaneDirector | undefined {
236-
return new APVNavPathDirector(this.bus, apValues);
268+
return new APVNavPathDirector(this.bus);
237269
}
238270

239271
/** @inheritdoc */
@@ -264,13 +296,18 @@ export class GarminAPConfig implements APConfig {
264296
}
265297

266298
/** @inheritdoc */
267-
public createToLateralDirector(): PlaneDirector | undefined {
268-
return new APLvlDirector(this.bus, true);
299+
public createToLateralDirector(apValues: APValues): PlaneDirector | undefined {
300+
return new APLvlDirector(this.bus, apValues, { isToGaMode: true });
301+
}
302+
303+
/** @inheritdoc */
304+
public createGaLateralDirector(apValues: APValues): PlaneDirector | undefined {
305+
return new APLvlDirector(this.bus, apValues, { isToGaMode: true });
269306
}
270307

271308
/** @inheritdoc */
272-
public createGaLateralDirector(): PlaneDirector | undefined {
273-
return new APLvlDirector(this.bus, true);
309+
public createFmsLocLateralDirector(): undefined {
310+
return undefined;
274311
}
275312

276313
/** @inheritdoc */
@@ -282,18 +319,18 @@ export class GarminAPConfig implements APConfig {
282319
* Calculates intercept angles for radio nav.
283320
* @param distanceToSource The distance from the plane to the source of the navigation signal, in nautical miles.
284321
* @param deflection The lateral deflection of the desired track relative to the plane, normalized from `-1` to `1`.
285-
* Negative values indicate that the desired track is to the left of the plane.
322+
* Positive values indicate that the desired track is to the right of the plane.
323+
* @param xtk The cross-track error of the plane from the desired track, in nautical miles. Positive values indicate
324+
* indicate that the plane is to the right of the track.
286325
* @param tas The true airspeed of the plane, in knots.
287326
* @param isLoc Whether the source of the navigation signal is a localizer. Defaults to `false`.
288327
* @returns The intercept angle, in degrees, to capture the desired track from the navigation signal.
289328
*/
290-
private static navInterceptCurve(distanceToSource: number, deflection: number, tas: number, isLoc?: boolean): number {
329+
private static navInterceptCurve(distanceToSource: number, deflection: number, xtk: number, tas: number, isLoc?: boolean): number {
291330
if (isLoc) {
292-
return GarminAPConfig.localizerInterceptCurve(distanceToSource, deflection, tas);
331+
return GarminAPConfig.localizerInterceptCurve(xtk, tas);
293332
} else {
294-
// max deflection is 10 degrees or 0.175 radians
295-
const fullScaleDeflectionInRadians = 0.175;
296-
return GarminAPConfig.defaultInterceptCurve(Math.sin(fullScaleDeflectionInRadians * -deflection) * distanceToSource, tas);
333+
return GarminAPConfig.defaultInterceptCurve(xtk, tas);
297334
}
298335
}
299336

@@ -311,24 +348,19 @@ export class GarminAPConfig implements APConfig {
311348

312349
/**
313350
* Calculates intercept angles for localizers.
314-
* @param distanceToSource The distance from the plane to the localizer, in nautical miles.
315-
* @param deflection The lateral deflection of the desired track relative to the plane, normalized from `-1` to `1`.
316-
* Negative values indicate that the desired track is to the left of the plane.
351+
* @param xtk The cross-track error of the plane from the desired track, in nautical miles. Positive values indicate
352+
* indicate that the plane is to the right of the track.
317353
* @param tas The true airspeed of the plane, in knots.
318354
* @returns The intercept angle, in degrees, to capture the localizer course.
319355
*/
320-
private static localizerInterceptCurve(distanceToSource: number, deflection: number, tas: number): number {
321-
// max deflection is 2.5 degrees or 0.0436332 radians
322-
const fullScaleDeflectionInRadians = 0.0436332;
323-
324-
const xtkNM = Math.sin(fullScaleDeflectionInRadians * -deflection) * distanceToSource;
325-
const xtkMeters = UnitType.NMILE.convertTo(xtkNM, UnitType.METER);
356+
private static localizerInterceptCurve(xtk: number, tas: number): number {
357+
const xtkMeters = UnitType.NMILE.convertTo(xtk, UnitType.METER);
326358
const xtkMetersAbs = Math.abs(xtkMeters);
327359

328360
if (xtkMetersAbs < 4) {
329361
return 0;
330362
} else if (xtkMetersAbs < 250) {
331-
return NavMath.clamp(Math.abs(xtkNM * 75), 1, 5);
363+
return NavMath.clamp(Math.abs(xtk * 75), 1, 5);
332364
}
333365

334366
const turnRadiusMeters = NavMath.turnRadius(tas, 22.5);

src/garminsdk/autopilot/GarminVNavManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export class GarminVNavManager implements VNavManager {
267267

268268
/** Method called to arm Path Mode. */
269269
private armPath(): void {
270-
if (this.awaitingAltCap < 0 && this.awaitingRearm < 0) {
270+
if (this.awaitingAltCap < 0 && this.awaitingRearm < 0 && this.apValues.verticalActive.get() !== APVerticalModes.CAP) {
271271
if (this.pathMode !== VNavPathMode.PathArmed) {
272272
this.pathMode = VNavPathMode.PathArmed;
273273
SimVar.SetSimVarValue(VNavVars.PathMode, SimVarValueType.Number, this.pathMode);

0 commit comments

Comments
 (0)