Hello,
I found little help online and struggled to make those compile and actually run without CTD so I thought I'd might share how I did to get working procedures in MSFS2020.
First, since these features of MSFS are directly inherited from FSX all xml elements and attributes information found here are still 100% valid.
Also, all the xml stuff described below is to be included inside the <Airport/> element.
1. Terminal waypoints and navaids.
All can be declared inside the Airport element, even those already included in the stock scenery. This example is from a new, non-stock airport I'm working (ZGNN Nanning) on and thus I didn't use at all the DeleteNavigation element at all, from what I've read here and there it seems wise to refrain from using it even upgrading a stock airport.
The data was sourced from the AIP:
Turns into this in xml format:
VORs and NAMED waypoints already in stock scenery were added aswell:
2. STARs
Now lets' code this arrival:
into this (with all transistions, not only LBN):
fixType should allways TERMINAL_WAYPOINT unless it's a VOR or NDB. That way the compiler will look for those into the waypoint list I coded above.
Notice that I didn't provide the magneticCourse information although this attribute is mandatory. Also, I didn't make any use of the CommonRouteLegs section. And the RunwayTransitions section MUST be empty, those transitions will actually be in the Approach elements.
Once compiled this looks just fine on the world map, without any CTD when selecting IFR:
3. Approaches.
Here's an ILS approach with RNAV transitions, following the above STAR:
And how it's coded:
It's almost straightforward except the FAF (that I called FF005) that is not part yet of all our Terminal waypoints. I had to find it's exact coordinates with Google Earth Viewer, drawing a line to a point 6.2NM from the glideslope (where the DME is colocated) along the extended runway centerline. The coordinates of our FAF in then picked in the lower right corner:
Then I added that FAF and also the one for the opposite runway in my waypoint list:
The approach legs themselves have a few attributes that need clarification:
recommendedIdent: identifier of the ILS, usually a 3 or 4 letter string beginning with 'I'. Here it's IXU.
NB: for reference here is also the xml adding the ILS 'IXU' to the airport:
theta: it's a bearing, in degrees, from the recommendedIdent navaid or fix. Initial Fix NN520 is 228° from LOCALIZER IXU (reversed from the final approach course). Not 100% sure about it but I'd say it's a magnetic bearing.
rho: it's a distance from the recommendedIdent navaid or fix. Could be either in meters (default) or in nautical miles (N). Initial fix NN520 is 12.0NM from the LOCALIZER IXU (10.3 NM from DME from the charts + 1.7NM on the field between DME and LOCALIZER measured in Google Earth Viewer).
In next CF legs (Course to Fix), an additionnal distance attribute is required. It's the lenght of the leg. If the first CF leg, distance between NN520 and FF005 is 7.9NM. Then the final leg is 6.0NM between FAF and runway 05 threshold.
Again, I'm not sure all these attributes are actually used in a way or another by the sim despite some of them being mandatory for compilation. I've seen the AI being assigned and performing well those ILS approaches at ZGNN before I had sorted all this properly.
NB: Some extra remarks about magnetic variation: Opposite to the wiki definition, MSFS magvar is positive for declinations to the west and negative for declinations to the east.
Then you get the following formula: Magnetic Heading = True Heading + magvar.
For ZGNN rwy 05: true heading = 46.8° (from the way I placed the runway over aerial imagery). Magvar= 1.7°W (from AIP) converted to +1.7 in xml files and SDK airport properties
==> Magnetic heading = 46.8 + 1.7 = 48.5°
This magnetic heading is reported in the ILS xml definition along with the Magvar. Those two parameters have to be consistent to get the ILS beam to actually follow the runway extended centerline.
4. SIDs.
Let's code SID 19D from the AIP:
First DF (direct to fix) legs need the flyOver attribute to load and compile properly, it took me a while to figure this. Here I put all magneticCourses but again I'm not sure whether it's actually used by the sim or not, still this attribute is required for compilation. Again, allways use TERMINAL_WAYPOINT instead of WAYPOINT.
SID Chart:
And it's rendition in the world map:
I lost a lot of time tweaking the xml code before coming to something that both compile and don't crash the sim when selected in the world map, so I hope that these tips will save you some time. I haven't coded anything else that ILS approaches so this little tutorial is by no way complete. Also, I haven't bothered yet with Arc-DME procedures (ZGNN has some), my goal was to get at least one set of procedures enabling ILS to user and AI.
EDIT1: added extra stuff to the ILS approach part.
EDIT2: added nota bene about the use of magvar and ILS xml definition.
I found little help online and struggled to make those compile and actually run without CTD so I thought I'd might share how I did to get working procedures in MSFS2020.
First, since these features of MSFS are directly inherited from FSX all xml elements and attributes information found here are still 100% valid.
Also, all the xml stuff described below is to be included inside the <Airport/> element.
1. Terminal waypoints and navaids.
All can be declared inside the Airport element, even those already included in the stock scenery. This example is from a new, non-stock airport I'm working (ZGNN Nanning) on and thus I didn't use at all the DeleteNavigation element at all, from what I've read here and there it seems wise to refrain from using it even upgrading a stock airport.
The data was sourced from the AIP:
Turns into this in xml format:
XML:
<Waypoint lat="23.025" lon="108.655" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN402"/>
<Waypoint lat="22.62667" lon="108.3667" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN403"/>
<Waypoint lat="22.29" lon="107.5183" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN404"/>
<Waypoint lat="23.00833" lon="108.525" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN406"/>
<Waypoint lat="22.925" lon="108.645" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN407"/>
<Waypoint lat="22.75333" lon="108.5067" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN408"/>
<Waypoint lat="22.76167" lon="109.005" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="NN411"/>
VORs and NAMED waypoints already in stock scenery were added aswell:
XML:
<Waypoint lat="21.58667" lon="109.4317" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="BHY"/>
<Waypoint lat="23.89167" lon="106.645" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="BSE"/>
<Waypoint lat="23.07" lon="112.4867" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="GYA"/>
<Waypoint lat="23.76333" lon="109.1467" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="LBN"/>
<Waypoint lat="22.35667" lon="106.8683" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="LON"/>
<Waypoint lat="22.585" lon="108.1483" magvar="1.7" waypointType="VOR" waypointRegion="ZG" waypointIdent="WUY"/>
<Waypoint lat="22.42667" lon="109.04" magvar="1.7" waypointType="RNAV" waypointRegion="ZG" waypointIdent="P1"/>
<Waypoint lat="21.85" lon="109.095" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="ALEKI"/>
<Waypoint lat="22.11667" lon="108.7517" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="NIKUK"/>
<Waypoint lat="22.855" lon="110.5533" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="OSIKA"/>
<Waypoint lat="23.24667" lon="108.7067" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="SARUG"/>
<Waypoint lat="22.03" lon="107.6417" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="UVUNO"/>
<Waypoint lat="22.695" lon="109.1217" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="VAPNA"/>
<Waypoint lat="22.42667" lon="107.255" magvar="1.7" waypointType="NAMED" waypointRegion="ZG" waypointIdent="XEREN"/>
2. STARs
Now lets' code this arrival:
into this (with all transistions, not only LBN):
XML:
<Arrival name="08A">
<EnrouteTransitions>
<EnrouteTransitionLegs>
<Leg type="IF" fixType="VOR" fixRegion="ZG" fixIdent="LBN"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="SARUG" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN468" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN463" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN464" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN466" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN467" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN473" magneticCourse="0.0" altitudeDescriptor="A" altitude1="1628M"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN457" magneticCourse="0.0" altitudeDescriptor="+" altitude1="1028M"/>
</EnrouteTransitionLegs>
<EnrouteTransitionLegs>
<Leg type="IF" fixType="VOR" fixRegion="ZG" fixIdent="BHY"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="ALEKI" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="P1" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN412" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN463" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN464" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN466" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN467" magneticCourse="0.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN473" magneticCourse="0.0" altitudeDescriptor="A" altitude1="1628M"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN457" magneticCourse="0.0" altitudeDescriptor="+" altitude1="1028M"/>
</EnrouteTransitionLegs>
</EnrouteTransitions>
<CommonRouteLegs/>
<RunwayTransitions/>
</Arrival>
Notice that I didn't provide the magneticCourse information although this attribute is mandatory. Also, I didn't make any use of the CommonRouteLegs section. And the RunwayTransitions section MUST be empty, those transitions will actually be in the Approach elements.
Once compiled this looks just fine on the world map, without any CTD when selecting IFR:
3. Approaches.
Here's an ILS approach with RNAV transitions, following the above STAR:
And how it's coded:
XML:
<Approach type="ILS" runway="05" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="FF005" altitude="727M" heading="048" missedAltitude="1028M">
<ApproachLegs>
<Leg type="IF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN520" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="12.0N" altitudeDescriptor="I" altitude1="727M" altitude2="727M"/>
<Leg type="CF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="FF005" flyOver="FALSE" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="7.9N" magneticCourse="48" distance="4.1N" altitudeDescriptor="A" altitude1="727M"/>
<Leg type="CF" fixType="RUNWAY" fixRegion="ZG" fixIdent="RW05" flyOver="TRUE" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="1.7N" magneticCourse="48" distance="6.0N" altitudeDescriptor="A" altitude1="127.1M"/>
</ApproachLegs>
<MissedApproachLegs>
<Leg type="CA" magneticCourse="48.0" altitudeDescriptor="+" altitude1="427M"/>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN521" flyOver="TRUE" turnDirection="R" altitudeDescriptor="A" altitude1="1028M"/>
<Leg type="HM" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN521" turnDirection="L" magneticCourse="223" time="1.0" altitudeDescriptor="A" altitude1="1028M"/>
</MissedApproachLegs>
<Transition transitionType="FULL" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN457" altitude="1028M">
<TransitionLegs>
<Leg type="IF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN457" altitudeDescriptor="+" altitude1="1028M"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN520" flyOver="FALSE" magneticCourse="318" altitudeDescriptor="A" altitude1="727M"/>
</TransitionLegs>
</Transition>
<Transition transitionType="FULL" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN454" altitude="1028M">
<TransitionLegs>
<Leg type="IF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN454" altitudeDescriptor="+" altitude1="1028M"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN520" flyOver="FALSE" magneticCourse="138" altitudeDescriptor="A" altitude1="727M"/>
</TransitionLegs>
</Transition>
</Approach>
It's almost straightforward except the FAF (that I called FF005) that is not part yet of all our Terminal waypoints. I had to find it's exact coordinates with Google Earth Viewer, drawing a line to a point 6.2NM from the glideslope (where the DME is colocated) along the extended runway centerline. The coordinates of our FAF in then picked in the lower right corner:
Then I added that FAF and also the one for the opposite runway in my waypoint list:
XML:
<Waypoint lat="22.529811" lon="108.085062" magvar="1.7" waypointType="FAF" waypointRegion="ZG" waypointIdent="FF005"/>
<Waypoint lat="22.687552" lon="108.266258" magvar="1.7" waypointType="FAF" waypointRegion="ZG" waypointIdent="FF023"/>
The approach legs themselves have a few attributes that need clarification:
XML:
<ApproachLegs>
<Leg type="IF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN520" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="12.0N" altitudeDescriptor="I" altitude1="727M" altitude2="727M"/>
<Leg type="CF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="FF005" flyOver="FALSE" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="7.9N" magneticCourse="48" distance="4.1N" altitudeDescriptor="A" altitude1="727M"/>
<Leg type="CF" fixType="RUNWAY" fixRegion="ZG" fixIdent="RW05" flyOver="TRUE" recommendedType="LOCALIZER" recommendedRegion="ZG" recommendedIdent="IXU" theta="228" rho="1.7N" magneticCourse="48" distance="6.0N" altitudeDescriptor="A" altitude1="127.1M"/>
</ApproachLegs>
recommendedIdent: identifier of the ILS, usually a 3 or 4 letter string beginning with 'I'. Here it's IXU.
NB: for reference here is also the xml adding the ILS 'IXU' to the airport:
XML:
<Ils lat="22.620295" lon="108.189016" alt="127.1M" heading="48.5" frequency="108.9" magvar="1.7" ident="IXU" width="5.0" name="ILS05">
<GlideSlope lat="22.599874" lon="108.167316" alt="127.1M" pitch="3" range="27N"/>
<Dme lat="22.599874" lon="108.167316" alt="127.1M" range="27N"/>
</Ils>
theta: it's a bearing, in degrees, from the recommendedIdent navaid or fix. Initial Fix NN520 is 228° from LOCALIZER IXU (reversed from the final approach course). Not 100% sure about it but I'd say it's a magnetic bearing.
rho: it's a distance from the recommendedIdent navaid or fix. Could be either in meters (default) or in nautical miles (N). Initial fix NN520 is 12.0NM from the LOCALIZER IXU (10.3 NM from DME from the charts + 1.7NM on the field between DME and LOCALIZER measured in Google Earth Viewer).
In next CF legs (Course to Fix), an additionnal distance attribute is required. It's the lenght of the leg. If the first CF leg, distance between NN520 and FF005 is 7.9NM. Then the final leg is 6.0NM between FAF and runway 05 threshold.
Again, I'm not sure all these attributes are actually used in a way or another by the sim despite some of them being mandatory for compilation. I've seen the AI being assigned and performing well those ILS approaches at ZGNN before I had sorted all this properly.
NB: Some extra remarks about magnetic variation: Opposite to the wiki definition, MSFS magvar is positive for declinations to the west and negative for declinations to the east.
Then you get the following formula: Magnetic Heading = True Heading + magvar.
For ZGNN rwy 05: true heading = 46.8° (from the way I placed the runway over aerial imagery). Magvar= 1.7°W (from AIP) converted to +1.7 in xml files and SDK airport properties
==> Magnetic heading = 46.8 + 1.7 = 48.5°
This magnetic heading is reported in the ILS xml definition along with the Magvar. Those two parameters have to be consistent to get the ILS beam to actually follow the runway extended centerline.
4. SIDs.
Let's code SID 19D from the AIP:
XML:
<Departure name="19D">
<RunwayTransitions>
<RunwayTransitionLegs number="23" designator="NONE">
<Leg type="CA" magneticCourse="228.0" altitudeDescriptor="A" altitude1="428M"/>
</RunwayTransitionLegs>
</RunwayTransitions>
<CommonRouteLegs/>
<EnrouteTransitions>
<EnrouteTransitionLegs>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN422" flyOver="FALSE"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN501" magneticCourse="122.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN502" magneticCourse="48.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN458" magneticCourse="32.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="SARUG" magneticCourse="348.0"/>
<Leg type="TF" fixType="VOR" fixRegion="ZG" fixIdent="LBN" magneticCourse="39.0"/>
</EnrouteTransitionLegs>
<EnrouteTransitionLegs>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN422" flyOver="FALSE"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN501" magneticCourse="122.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN502" magneticCourse="48.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="VAPNA" magneticCourse="87.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN413" magneticCourse="85.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="OSIKA" magneticCourse="85.0"/>
<Leg type="TF" fixType="VOR" fixRegion="ZG" fixIdent="GYA" magneticCourse="85.0"/>
</EnrouteTransitionLegs>
<EnrouteTransitionLegs>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN422" flyOver="FALSE"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN501" magneticCourse="122.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NIKUK" magneticCourse="124.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="ALEKI" magneticCourse="132.0"/>
<Leg type="TF" fixType="VOR" fixRegion="ZG" fixIdent="BHY" magneticCourse="132.0"/>
</EnrouteTransitionLegs>
<EnrouteTransitionLegs>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN503" flyOver="FALSE"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN404" magneticCourse="260.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="XEREN" magneticCourse="301.0"/>
<Leg type="TF" fixType="VOR" fixRegion="ZG" fixIdent="LON" magneticCourse="261.0"/>
</EnrouteTransitionLegs>
<EnrouteTransitionLegs>
<Leg type="DF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN454" flyOver="FALSE"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="NN452" magneticCourse="318.0"/>
<Leg type="TF" fixType="TERMINAL_WAYPOINT" fixRegion="ZG" fixIdent="UVUNO" magneticCourse="350.0"/>
<Leg type="TF" fixType="VOR" fixRegion="ZG" fixIdent="BSE" magneticCourse="315.0"/>
</EnrouteTransitionLegs>
</EnrouteTransitions>
</Departure>
First DF (direct to fix) legs need the flyOver attribute to load and compile properly, it took me a while to figure this. Here I put all magneticCourses but again I'm not sure whether it's actually used by the sim or not, still this attribute is required for compilation. Again, allways use TERMINAL_WAYPOINT instead of WAYPOINT.
SID Chart:
And it's rendition in the world map:
I lost a lot of time tweaking the xml code before coming to something that both compile and don't crash the sim when selected in the world map, so I hope that these tips will save you some time. I haven't coded anything else that ILS approaches so this little tutorial is by no way complete. Also, I haven't bothered yet with Arc-DME procedures (ZGNN has some), my goal was to get at least one set of procedures enabling ILS to user and AI.
EDIT1: added extra stuff to the ILS approach part.
EDIT2: added nota bene about the use of magvar and ILS xml definition.
Last edited: