Skip to content

Commit

Permalink
FMS: First pass FMS SPD
Browse files Browse the repository at this point in the history
  • Loading branch information
Octal450 committed Dec 7, 2024
1 parent d41f57a commit 3bb1e80
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 97 deletions.
Binary file modified Docs/Auto_Flight_and_FCC.docx
Binary file not shown.
Binary file modified Docs/Auto_Flight_and_FCC.pdf
Binary file not shown.
Binary file modified Docs/FMS_and_MCDU.docx
Binary file not shown.
Binary file modified Docs/FMS_and_MCDU.pdf
Binary file not shown.
86 changes: 78 additions & 8 deletions Models/Instruments/FCP/FCP.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
<animation>
<name>Digits</name>
<object-name>Digits.Alt</object-name>
<object-name>Digits.VsBlank</object-name>
<object-name>Digits.VsDash</object-name>
<object-name>Digits.Fpa</object-name>
<object-name>Digits.Hdg</object-name>
<object-name>Digits.HdgBlank</object-name>
<object-name>Digits.HdgDash</object-name>
<object-name>Digits.Ias</object-name>
<object-name>Digits.Mach</object-name>
<object-name>Digits.SpdDash</object-name>
<object-name>Digits.Vs</object-name>
</animation>

Expand Down Expand Up @@ -332,6 +333,47 @@
</axis>
</animation>

<animation>
<type>pick</type>
<object-name>FmsSpd</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>cockpit.ApPanel.fmsSpd();</script>
</binding>
<binding>
<command>property-assign</command>
<property>controls/cockpit/fcp/fms-spd</property>
<value>1</value>
</binding>
<binding>
<command>nasal</command>
<script>libraries.Sound.btn1();</script>
</binding>
<mod-up>
<binding>
<command>property-assign</command>
<property>controls/cockpit/fcp/fms-spd</property>
<value>0</value>
</binding>
</mod-up>
</action>
</animation>
<animation>
<type>translate</type>
<object-name>FmsSpd</object-name>
<object-name>FmsSpd.Text</object-name>
<property>controls/cockpit/fcp/fms-spd</property>
<factor>-0.001</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>

<!-- Heading Controls -->
<animation>
<type>pick</type>
Expand Down Expand Up @@ -1058,6 +1100,27 @@
<height>32</height>
</font-resolution>
</text>
<text>
<name>Digits.SpdDash</name>
<offsets>
<x-m>-25.7247</x-m>
<y-m>-0.07908</y-m>
<z-m>11.7893</z-m>
</offsets>
<alignment>right-bottom</alignment>
<axis-alignment>yz-plane</axis-alignment>
<type>literal</type>
<text>---</text>
<font>Std7SegCustom.ttf</font>
<draw-text>true</draw-text>
<draw-alignment>false</draw-alignment>
<draw-boundingbox>false</draw-boundingbox>
<character-size>0.006</character-size>
<font-resolution>
<width>30</width>
<height>32</height>
</font-resolution>
</text>
<text>
<name>Digits.Test</name>
<offsets>
Expand Down Expand Up @@ -1128,7 +1191,7 @@
<condition>
<and>
<not><property>it-autoflight/input/kts-mach</property></not>
<!-- Will add FMS spd = 0 condition here, when implemented in ITAF -->
<property>it-autoflight/output/show-spd</property>
</and>
</condition>
</animation>
Expand All @@ -1138,10 +1201,17 @@
<condition>
<and>
<property>it-autoflight/input/kts-mach</property>
<!-- Will add FMS spd = 0 condition here, when implemented in ITAF -->
<property>it-autoflight/output/show-spd</property>
</and>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>Digits.SpdDash</object-name>
<condition>
<not><property>it-autoflight/output/show-spd</property></not>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>Digits.IasLabel</object-name>
Expand Down Expand Up @@ -1188,7 +1258,7 @@
</font-resolution>
</text>
<text>
<name>Digits.HdgBlank</name>
<name>Digits.HdgDash</name>
<offsets>
<x-m>-25.7247</x-m>
<y-m>-0.03514</y-m>
Expand Down Expand Up @@ -1281,7 +1351,7 @@
</animation>
<animation>
<type>select</type>
<object-name>Digits.HdgBlank</object-name>
<object-name>Digits.HdgDash</object-name>
<condition>
<not><property>it-autoflight/output/show-hdg</property></not>
</condition>
Expand Down Expand Up @@ -1464,7 +1534,7 @@
</font-resolution>
</text>
<text>
<name>Digits.VsBlank</name>
<name>Digits.VsDash</name>
<offsets>
<x-m>-25.7247</x-m>
<y-m>0.10633</y-m>
Expand Down Expand Up @@ -1560,7 +1630,7 @@
</animation>
<animation>
<type>select</type>
<object-name>Digits.VsBlank</object-name>
<object-name>Digits.VsDash</object-name>
<condition>
<and>
<not-equals>
Expand Down
136 changes: 101 additions & 35 deletions Nasal/AFS/AFS.nas
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ var Velocities = {
athrMax: 365,
athrMaxMach: 0.87,
athrMin: 0,
athrMinMach: 0.5,
athrMinMach: 0,
groundspeedKt: props.globals.getNode("/velocities/groundspeed-kt", 1),
groundspeedMps: 0,
indicatedAirspeedKt: props.globals.getNode("/instrumentation/airspeed-indicator/indicated-speed-kt", 1),
Expand Down Expand Up @@ -169,6 +169,7 @@ var Internal = {
driftAngleTemp: 0,
enableAthrOff: 0,
flchActive: 0,
fmsSpdDriving: 0,
fpa: props.globals.initNode("/it-autoflight/internal/fpa", 0, "DOUBLE"),
fpaTemp: 0,
hdg: props.globals.initNode("/it-autoflight/internal/hdg", 0, "INT"),
Expand All @@ -178,6 +179,7 @@ var Internal = {
hdgTrk: props.globals.initNode("/it-autoflight/internal/heading", 0, "DOUBLE"),
kts: props.globals.initNode("/it-autoflight/internal/kts", 250, "INT"),
ktsMach: props.globals.initNode("/it-autoflight/internal/kts-mach", 0, "BOOL"),
ktsMachTemp: 0,
ktsTemp: 250,
landCondition: 0,
landModeActive: 0,
Expand Down Expand Up @@ -206,6 +208,7 @@ var Internal = {
takeoffHdgCalc: 0,
takeoffHdgNew: 0,
takeoffLvl: props.globals.initNode("/it-autoflight/internal/takeoff-lvl", 1, "BOOL"),
takeoffSpdDriving: 0,
targetHdgError: 0,
targetKts: 0,
targetKtsError: 0,
Expand Down Expand Up @@ -235,6 +238,7 @@ var Output = {
lnavArm: props.globals.initNode("/it-autoflight/output/lnav-arm", 0, "BOOL"),
locArm: props.globals.initNode("/it-autoflight/output/loc-arm", 0, "BOOL"),
showHdg: props.globals.initNode("/it-autoflight/output/show-hdg", 1, "BOOL"),
showSpd: props.globals.initNode("/it-autoflight/output/show-spd", 1, "BOOL"),
spdCaptured: 1,
spdProt: props.globals.initNode("/it-autoflight/output/spd-prot", 0, "INT"),
spdProtTemp: 0,
Expand Down Expand Up @@ -329,11 +333,14 @@ var ITAF = {
UpdateFma.arm();
me.updateLatText("T/O");
me.updateVertText("T/O CLB");
Internal.fmsSpdDriving = 0;
Internal.takeoffSpdDriving = 0;
Internal.retardLock = 0;
Text.land.setValue("OFF");
Output.spdCaptured = 1;
Output.hdgCaptured = 1;
Output.showHdg.setBoolValue(1);
Output.showSpd.setBoolValue(1);
if (t != 1) {
Sound.apOff.setBoolValue(0);
Warning.ap.setBoolValue(0);
Expand Down Expand Up @@ -649,31 +656,82 @@ var ITAF = {
Internal.spdPitchAvailTemp = Internal.spdPitchAvail.getBoolValue();

# Takeoff Speed Guidance
me.takeoffSpdLogic();
Internal.takeoffSpdDriving = me.takeoffSpdLogic();

# FMS SPD Logic
Input.ktsMachTemp = Input.ktsMach.getBoolValue();
Internal.ktsMachTemp = Internal.ktsMach.getBoolValue();

# FMS SPD
if (fms.FmsSpd.active) { # Separate from Takeoff Speed Guidance
Output.spdCaptured = 1; # Always captured when driven
Internal.kts.setValue(fms.FmsSpd.toKts);
if (fms.FmsSpd.active and fms.Internal.phase >= 2) { # Don't drive before climb phase
Internal.fmsSpdDriving = 1;
} else {
Internal.fmsSpdDriving = 0;
}

if (Internal.fmsSpdDriving) {
if (fms.FmsSpd.ktsMach) {
if (!Internal.ktsMachTemp) {
Internal.ktsMach.setBoolValue(1);
}
Internal.mach.setValue(fms.FmsSpd.mach);

if (!Output.showSpd.getBoolValue()) {
if (!Input.ktsMachTemp) {
Input.ktsMach.setBoolValue(1);
}
Input.mach.setValue(fms.FmsSpd.mach);
}
} else {
if (Internal.ktsMachTemp) {
Internal.ktsMach.setBoolValue(0);
}
Internal.kts.setValue(fms.FmsSpd.kts);

if (!Output.showSpd.getBoolValue()) { # Also in takeoffSpdLogic
if (Input.ktsMachTemp) {
Input.ktsMach.setBoolValue(0);
}
Input.kts.setValue(fms.FmsSpd.kts);
}
}
}

# Speed Capture + ATS Speed Limits
Velocities.athrMax = fms.Speeds.athrMax.getValue();
Velocities.athrMaxMach = fms.Speeds.athrMaxMach.getValue();
Velocities.athrMin = fms.Speeds.athrMin.getValue();
Velocities.athrMinMach = fms.Speeds.athrMinMach.getValue();
Input.ktsMachTemp = Input.ktsMach.getBoolValue();
Input.ktsTemp = Input.kts.getValue();
Input.machTemp = Input.mach.getValue();
Internal.ktsTemp = Internal.kts.getValue();
Internal.machTemp = Internal.mach.getValue();

if (!Output.spdCaptured or !Internal.spdPitchAvailTemp) { # If takeoff speed target is not available (spdPitchAvail = false), then force sync to FCP value
if (Internal.takeoffSpdDriving or Internal.fmsSpdDriving) { # Takeoff Guidance and FMS SPD have their own limiting logic, and always stay captured
Output.spdCaptured = 1;
} else if (!Output.spdCaptured or !Internal.spdPitchAvailTemp) { # If takeoff speed target is not available (spdPitchAvail = false), then force sync to FCP value
if (Input.ktsMachTemp) {
Internal.mach.setValue(math.clamp(Input.machTemp, Velocities.athrMinMach, Velocities.athrMaxMach));
if (Velocities.athrMinMach > Velocities.athrMaxMach) { # Max takes priority
Internal.mach.setValue(Velocities.athrMaxMach);
} else if (Input.machTemp > Velocities.athrMaxMach) {
Internal.mach.setValue(Velocities.athrMaxMach);
} else if (Input.machTemp < Velocities.athrMinMach) {
Internal.mach.setValue(Velocities.athrMinMach);
} else {
Internal.mach.setValue(Input.machTemp);
}

Internal.targetKts = Internal.mach.getValue() * (Velocities.indicatedAirspeedKt.getValue() / Velocities.indicatedMach.getValue()); # Convert to Knots
} else {
Internal.kts.setValue(math.clamp(Input.ktsTemp, Velocities.athrMin, Velocities.athrMax));
if (Velocities.athrMin > Velocities.athrMax) { # Max takes priority
Internal.kts.setValue(Velocities.athrMax);
} else if (Input.ktsTemp > Velocities.athrMax) {
Internal.kts.setValue(Velocities.athrMax);
} else if (Input.ktsTemp < Velocities.athrMin) {
Internal.kts.setValue(Velocities.athrMin);
} else {
Internal.kts.setValue(Input.ktsTemp);
}

Internal.targetKts = Internal.kts.getValue();
}

Expand All @@ -685,26 +743,22 @@ var ITAF = {
} else {
Output.spdCaptured = 0;
}
} else if (!Gear.wow1Temp and !Gear.wow2Temp) {
if (Internal.ktsMach.getBoolValue()) {
if (Velocities.athrMinMach > Velocities.athrMaxMach) { # For extreme bank, max takes priority
} else if (!Gear.wow1Temp and !Gear.wow2Temp and !Internal.fmsSpdDriving) {
if (Internal.ktsMachTemp) {
if (Velocities.athrMinMach > Velocities.athrMaxMach) { # Max takes priority
Internal.mach.setValue(Velocities.athrMaxMach);
} else {
if (Internal.machTemp > Velocities.athrMaxMach) {
Internal.mach.setValue(Velocities.athrMaxMach);
} else if (Internal.machTemp < Velocities.athrMinMach) {
Internal.mach.setValue(Velocities.athrMinMach);
}
} else if (Internal.machTemp > Velocities.athrMaxMach) {
Internal.mach.setValue(Velocities.athrMaxMach);
} else if (Internal.machTemp < Velocities.athrMinMach) {
Internal.mach.setValue(Velocities.athrMinMach);
}
} else {
if (Velocities.athrMin > Velocities.athrMax) { # For extreme bank, max takes priority
if (Velocities.athrMin > Velocities.athrMax) { # Max takes priority
Internal.kts.setValue(Velocities.athrMax);
} else {
if (Internal.ktsTemp > Velocities.athrMax) {
Internal.kts.setValue(Velocities.athrMax);
} else if (Internal.ktsTemp < Velocities.athrMin) {
Internal.kts.setValue(Velocities.athrMin);
}
} else if (Internal.ktsTemp > Velocities.athrMax) {
Internal.kts.setValue(Velocities.athrMax);
} else if (Internal.ktsTemp < Velocities.athrMin) {
Internal.kts.setValue(Velocities.athrMin);
}
}
} # Refresh Internal.ktsTemp and Internal.machTemp if using past this point
Expand Down Expand Up @@ -857,7 +911,7 @@ var ITAF = {
}

# Mach Switchover
if (!fms.FmsSpd.active) {
if (!fms.FmsSpd.active) { # When FMS SPD is active, it handles switchover automatically
if (Internal.machSwitchover) {
if (Position.indicatedAltitudeFt.getValue() < 25990) {
Internal.machSwitchover = 0;
Expand Down Expand Up @@ -1520,6 +1574,26 @@ var ITAF = {
}
}
},
takeoffSpdLogic: func() {
if (fms.Internal.phase <= 1 and Internal.spdPitchAvail.getBoolValue() and fms.FmsSpd.toKts > 0) {
if (Gear.wow1Temp or Gear.wow2Temp or Position.gearAglFtTemp < 400 or fms.FmsSpd.toDriving) {
Internal.kts.setValue(fms.FmsSpd.toKts);

if (!Output.showSpd.getBoolValue()) { # Also in FMS SPD Logic
if (Input.ktsMachTemp) {
Input.ktsMach.setBoolValue(0);
}
Input.kts.setValue(fms.FmsSpd.toKts);
}

return 1;
} else {
return 0;
}
} else {
return 0;
}
},
setClimbRateLim: func() {
Internal.vsTemp = Internal.vs.getValue();
if (Internal.alt.getValue() >= Position.indicatedAltitudeFt.getValue()) {
Expand Down Expand Up @@ -1634,14 +1708,6 @@ var ITAF = {
Output.spdCaptured = 0;
}
},
takeoffSpdLogic: func() {
if (Text.vert.getValue() == "T/O CLB" and Internal.spdPitchAvail.getBoolValue() and fms.FmsSpd.toKts > 0) {
if (Gear.wow1Temp or Gear.wow2Temp or Position.gearAglFtTemp < 400 or fms.FmsSpd.toDriving) {
Output.spdCaptured = 1; # Always captured when driven
Internal.kts.setValue(fms.FmsSpd.toKts);
}
}
},
autoflight: func() {
Input.ovrd1Temp = Input.ovrd1.getBoolValue();
Input.ovrd2Temp = Input.ovrd2.getBoolValue();
Expand Down
Loading

0 comments on commit 3bb1e80

Please sign in to comment.