User:Awexome/Holding Pattern

From FlightGear wiki
Jump to navigation Jump to search

Holding Pattern

Assisted Holding Pattern. This project aims to provide generic algorithm and flexible code for assisting human and virtual pilots in conducting a holding pattern. Generally, a pilot may engage in a holding pattern to efficiently manoeuvre the aircraft to a desired (or ATC instructed) flying altitude and course, within a specified air-space; typically within the proximity of the destination airport or a holding fix. The holding pattern is also an effective way for FG ATC to manage high levels of inbound air-traffic.


Source Code: 'holding.nas' [[1]]


Below is a radar image of a holding entry based on a very early version of the code that utilized the aircraft roll and bank logic. Current versions utilize an upgraded holding logic that provides more accurate control of roll and bank directions and angular distance.

HoldingEarlyTests.png

Fgfs-holding-entry.PNG


These few examples use-cases suggests that this generic implementation likely will be of interest to pilots of varying aircraft types. This implementation also has the potential to improve AI flight patterns, providing alternative and simple ways for AI developers to mimic nice AI flying patterns, and to simulate the air-traffic situations at a busy airport. Another scenario of potential use is that developers testing new and development aircraft may use this implementation to set their new and development aircraft into a holding pattern, allowing them to focus on observing instruments and recording flight data, such as in a planned VFR landing. This implementation also provides convenient way for developers to remain airborne in airport proximity while making adjustments to test code. For example, when conducting repeated tests of auto-land and take-offs, the straights and the turns in a holding pattern allows aircraft developers to observe and record data regarding the manoeuvrability of their new and development aircraft.

More fun areas to enjoy this implementation of holding patter include enjoying a new or updated scenery while flying the holding pattern. Pilots may seek to engage a holding pattern inbound a runway to become familiar with visibility, geographic, etc. conditions at their destination airport.

This implementation also seeks to be flexible and may be engaged in manual mode, providing the pilot with heading information for conducting a holding pattern. Such heading information may be useful for an AI pilot as well.

Illustrative Code

A generally modular approach was applied in the design, allow to develop sub-functions that can be isolated when testing and debugging various parts of the system. one interesting example is the entry mode. This mode is implemented using a function that computes determines the holdign entry type based on the aircraft heading to the holding fix and the holding course.

    # compute entry type for holding pattern
    getEntryCode = func(HT) #################### holding type: RHT or LHT
    {
       var entryCode=0;
       var entryDelta=fix_trk_error_deg; # [+/-]180deg
       # normHdg # 360deg
       var entryHdg=normHdg(getprop(hpt~"fix-course-deg") + fix_trk_error_deg);

       setprop(hpt~"hold-type",HT);
       if(HT==1)
       {
          var direct1=(entryDelta>110 and entryDelta<=179.9);
          var direct2=(entryDelta>-179.9 and entryDelta<=-70);

          var directFlag = (direct1 or direct2) ? (entryCode=directCode) : 0;
          var offsetFlag = (entryDelta>-70 and entryDelta<=0) ? (entryCode=offsetCode) : 0;
          var parallelFlag = (entryDelta>0 and entryDelta<=70) ? (entryCode=parallelCode) : 0;
       }
       elsif(HT==-1)
       {
          var direct1=( entryHdg>180 and entryHdg<=250 );
          var direct2=( entryHdg>70 and entryHdg<=180 );
          ( direct1 or direct2 ) ? (entryCode=directCode) : nil;
          ( entryHdg>0 and entryHdg<=70 ) ? (entryCode=offsetCode) : nil;
          ( entryHdg>250 and entryHdg<=360 ) ? (entryCode=parallelCode) : nil;
       }
       elsif(HT==0)
       {
        return 0;
       }

       print("");
       printf("entryDelta: %d,   entryHdg: %d,   fix_trk_error_deg: %03d",
             entryDelta,entryHdg,fix_trk_error_deg);
       printf("direct1: %d,   direct2: %d ",direct1,direct2);
       printf("entryCode: %d,   dirFlag: %d,   offsFlag: %d,   parFlag: %d",
             entryCode,directFlag,offsetFlag,parallelFlag);

       entryCode ? (return entryCode) : func{ print("Invalid EntryCode!");   return entryCode; };
    } ## getEntryCode

Fgfs-holding-good03.png

Note that the entry type computation for a LEFT and a RIGHT holding type uses slightly different offsets to the holding course.

Another illustrative part of the system is the INBOUND module which maintains the holding course and guides the aircraft to the holding fix.

       if(getprop("a-holding/leg")==2) ######################### INBOUND #########################
         # what to do if missed crossingpoint i.e. from-flag
       {
         copilot("=Giorj= In-bound");
          ## CONSIDER calling guidance-mode with offset
         ## 1st stage turn
         if( (getprop("a-holding/fix-track-error-deg")>=15) and phaseInb==0 )
         {
            ## set inb course - just to make sure!
             tmpHdg=normalize_deg(getprop("/instrumentation/nav/heading-deg")-15);
             guidanceMode(tmpHdg);
            #fgCmd=b777.afds.hdg_setting.setValue(tmpHdg);
            #setprop("a-holding/fgCmdNode",fgCmd);
            #setprop("a-holding/fgCmdNode",'b777.afds.input(0,1)');
             phaseInb=1;
         }
         ## 2nd stage turn
         if( (getprop("a-holding/fix-track-error-deg")<15 or getprop("a-holding/clock")>120) and phaseInb!=2 )
         {
             copilot("=Giorj= AC [+/-]"~abs(getprop("a-holding/fix-track-error-deg"))~"deg of the fix");
             #tmpHdg=getprop("/instrumentation/nav/heading-deg");
             #fgCmd=b777.afds.hdg_setting.setValue(tmpHdg);
             #setprop("a-holding/fgCmdNode",fgCmd);
             #setprop("a-holding/fgCmdNode",'b777.afds.input(0,1)');
             #setprop("a-holding/fgCmdNode",'b777.afds.loc_armed.setValue(1)');  ## loc armed
             fgCmd=b777.afds.input(0,4);
          setprop("a-holding/fgCmdNode",fgCmd);

             getprop("a-holding/activated") ? nil : setprop("a-holding/leg",4); ## EXIT
             phaseInb=2;
         }


This code extract from an earlier version shows 2 initial stages of turn decision making. The heading and autopilot commands shows that this version and implementation has being in tests using the B777-200ER :)

Note the initial implementation of a modular autopilot command interface to send flight commands to the B777-200ER (the Autopilot Command Interface is still in development, however, the use of a more recent version (labelled as Giorj) is illustrated in the next code block). The more recent implementation of this holding pattern focus on improving reliability and more fault tolerance to inaccurate holding timing, inaccurate interception of the fix and turning points. These challenges have led to introduce better control of turns using a dedicated turn procedure (see, the property-tree nodes related to turn)

          ## phase 0, TURN
          if(currStep==0)
          {
             setprop(hpt~"turn/target-heading", getprop(hpt~"fix-course-deg"));
             setprop(hpt~"turn/turn-step", 45);
             setprop(hpt~"turn/turn-dir", bankRight); # RHT
             props.globals.getNode(hpt~"turn/turn-req").setValue(1);
             setprop(hpt~"internal/marked-heading", int(getprop("/orientation/heading-deg")));
             setprop(hpt~"internal/leg-phaseInb-step",1);
          }
          elsif(currStep==1)
          {
             #orientationError = normDiff(getprop(hpt~"fix-course-deg") - getprop("/orientation/heading-deg"));
             orientationError = normDiff(getprop(hpt~"internal/marked-heading") - getprop("/orientation/heading-deg")); # pps
             if (abs(orientationError)>7) # AC is changing course -- 7 for luck ;)
             {
               print("Moving from phase 1 to 2 on the inbound leg");
               setprop(hpt~"internal/leg-phaseInb-step",2);
             }
          }
          elsif(currStep==2)
          {
             ## phase 1, course-tracking
             orientationError = normDiff(getprop(hpt~"fix-course-deg") - getprop("/orientation/heading-deg"));
             if(abs(orientationError)<60
             and getprop(hpt~"turn/turn-req"))
                #and abs(getprop(hpt~"fix-track-error-deg")<=45)) # or 45-deg
             {
                props.globals.getNode(hpt~"turn/turn-req").setValue(0);
                print("Engaging the LNAV_LOC."); # initiating internal trackSta
                Giorj(LNAV_LOC); # props.globals.getNode(hpt~"turn/turn-req").setValue(1);
                print("Activating course-tracking.");
                setprop(hpt~"internal/leg-phaseInb-step",3);
             }

As a final note, the holding system is very useful and fun to use. The modular autopilot command inyourface is also a nice kit that will be welcomed by developers of all aircraft using autopilot systems. This interesting feature will be discussed in greater detail in coming post, soon.