Runway Awareness and Advisory System

From FlightGear wiki
Revision as of 13:21, 25 September 2014 by Onox (talk | contribs)
Jump to navigation Jump to search
Runway Awareness and Advisory System
Started in 08/2014
Description System to give advisories about runways
Contributor(s) onox
Status Under active development as of 08/2014
Subforum http://forum.flightgear.org/viewtopic.php?f=66&t=21266

Features

The Runway Advisory and Awareness System can give a number of advisories:

  • Advisory when approaching a runway while taxiing
  • Advisory when the aircraft is on the runway and pointing in the right direction for takeoff
  • Advisory of remaining distance to the end of the runway during a landing

https://www.youtube.com/watch?feature=player_detailpage&v=59ymnKUi49A#t=117

https://www.youtube.com/watch?feature=player_detailpage&v=0jkRhIMZAZo#t=171

TODO

  • Use *.groundnet.xml to detect when the aircraft is near a holding point to more accurately emit "approaching-runway" signal Not done Not done
  • Give an advisory of which runway the aircraft is lined up with when the aircraft is airborne and approaching a runway Not done Not done
  • Give "Approaching short runway <runway>" advisory and/or caution when approaching short runway in air Not done Not done
  • Give caution of distance remaining during rejected takeoff Not done Not done
  • Give "Long landing" caution when aircraft has less than a specified distance/percentage remaining Not done Not done
  • Allow aircraft developers to program whether between feet/meter should be used for distance remaining advisory 100}% completed
  • Allow distance from center to nose to be specified for a more accurate remaining distance Not done Not done

Signals

In order to give these advisories, callbacks for a number of signals can be registered to two announcers. Depending on the current mode of each announcer they will emit certain signals:

Takeoff announcer

Mode Emitted signals
taxi-and-takeoff approaching-runway, on-runway
taxi approaching-runway
takeoff on-runway

Landing announcer

Mode Emitted signals
landing remaining-distance, landed-runway, vacated-runway, landed-outside-runway

Installation

In case logger.nas and runway_announcer.nas have not been added to FlightGear's fgdata project yet, add the following to the beginning of the <nasal> element in your aircraft's -set.xml file:

<logger>
    <file>Aircraft/$YOUR_AIRCRAFT_FOLDER/Nasal/logger.nas</file>
</logger>
<runway>
    <file>Aircraft/$YOUR_AIRCRAFT_FOLDER/Nasal/runway_announcer.nas</file>
</runway>

Add the following to the <nasal> element below the previous two:

<file>Aircraft/$YOUR_AIRCRAFT_FOLDER/Nasal/runway.nas</file>

Add the file runway.nas to your aircraft's Nasal folder. The following example listens for gear[1] and gear[2] and overrides a number of properties of the takeoff_config object so that it can be used for large airliners:

# Copyright (C) 2014  onox
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

var copilot_say = func (message) {
    setprop("/sim/messages/copilot", message);
};

var make_notification_cb = func (format, action=nil) {
    return func (data=nil) {
        if (format != nil) {
            if (data != nil) {
                var message = sprintf(format, data.getValue());
            }
            else {
                var message = format;
            }

            copilot_say(message);
            logger.info(sprintf("Announcing '%s'", message));
        }

        if (typeof(action) == "func") {
            action();
        }
    };
};

var stop_announcer = func {
    landing_announcer.stop();
    logger.warn("Stopping landing announce");

    takeoff_announcer.set_mode("taxi-and-takeoff");
};

var switch_to_takeoff = func {
    # Switch to takeoff mode so that the "approaching-runway" signal
    # is not emitted for any runways that are crossed during takeoff
    if (takeoff_announcer.mode == "taxi-and-takeoff") {
        takeoff_announcer.set_mode("takeoff");
    }
};

var takeoff_config = { parents: [runway.TakeoffRunwayAnnounceConfig] };

# Will cause the announcer to emit the "on-runway" signal if the
# aircraft is within 600 meters of the beginning of the runway and
# at most 15 meters from the center line of the runway
takeoff_config.distance_center_line_m = 15;
takeoff_config.distance_start_m = 600;

# Let the announcer emit the "approaching-runway" signal if the
# aircraft comes within 200 meters of the runway
takeoff_config.distance_edge_max_m = 200;

var takeoff_announcer = runway.TakeoffRunwayAnnounceClass.new(takeoff_config);
takeoff_announcer.connect("on-runway", make_notification_cb("On runway %s", switch_to_takeoff));
takeoff_announcer.connect("approaching-runway", make_notification_cb("Approaching runway %s"));

var landing_config = { parents: [runway.LandingRunwayAnnounceConfig] };

var landing_announcer = runway.LandingRunwayAnnounceClass.new(landing_config);
landing_announcer.connect("remaining-distance", make_notification_cb("%d remaining"));
landing_announcer.connect("vacated-runway", make_notification_cb("Vacated runway %s", stop_announcer));
landing_announcer.connect("landed-runway", make_notification_cb("Touchdown on runway %s"));
landing_announcer.connect("landed-outside-runway", make_notification_cb(nil, stop_announcer));

var make_switch_mode_cb = func (wow_mode, no_wow_mode) {
    return func (node) {
        if (node.getBoolValue()) {
            if (getprop("/gear/gear[1]/wow") and getprop("/gear/gear[2]/wow")) {
                takeoff_announcer.set_mode(wow_mode);
            }
            else {
                takeoff_announcer.set_mode(no_wow_mode);
            }
        }
        else {
            takeoff_announcer.set_mode("");
        }
    };
};

setlistener("/controls/lighting/nav-lights",
  make_switch_mode_cb("taxi-and-takeoff", "taxi"),
  startup=1, runtime=0);

var have_been_in_air = 0;

var test_on_ground = func (on_ground) {
    if (on_ground) {
        takeoff_announcer.start();
        logger.warn("Starting takeoff announce");

        if (have_been_in_air == 1) {
            have_been_in_air = 0;

            takeoff_announcer.set_mode("");

            landing_announcer.start();
            landing_announcer.set_mode("landing");
            logger.warn("Starting landing announce");
        }
    }
    else {
        takeoff_announcer.stop();
        logger.warn("Stopping takeoff announce");

        landing_announcer.stop();
        logger.warn("Stopping landing announce");

        if (have_been_in_air == 0) {
            have_been_in_air = 1;
        }
    }
};

var init_announcers = func {
    setlistener("/gear/gear[1]/wow", func (n) {
        test_on_ground(getprop("/gear/gear[1]/wow") and getprop("/gear/gear[2]/wow"));
    }, startup=1, runtime=0);

    setlistener("/gear/gear[2]/wow", func (n) {
        test_on_ground(getprop("/gear/gear[1]/wow") and getprop("/gear/gear[2]/wow"));
    }, startup=1, runtime=0);
};

setlistener("/sim/signals/fdm-initialized", func {
    logger.warn("FDM initialized");

    var timer = maketimer(5.0, func init_announcers());
    timer.singleShot = 1;
    timer.start();
});
Note  In this case gear[1] and gear[2] are used to detect whether the aircraft is on the ground or in the air. You may want to modify this for your aircraft.
Note  It is your responsibility to start and stop the announcers and to set the correct modes. Therefore it is necessary to connect to signals like landed-outside-runway and vacated-runway, even if they appear to be useless for your specific aircraft. The example of runway.nas above already does this for you.
Note  You might want to replace copilot_say().

The configuration object takeoff_config has a number of properties with default values. These properties can be modified if you want to change when certain signals are emitted. For example, in the example of runway.nas above, distance_center_line_m, distance_start_m, and distance_edge_max_m where overridden for large airliners. The defaults are:

distance_start_m: 200,
# The maximum distance in meters from the starting position
# on the runway. Large runways are usually 40 to 60 meters wide.

diff_runway_heading_deg: 10,
# Difference in heading between runway and aircraft in order to
# get an announcement that the aircraft is on the runway for takeoff.

diff_approach_heading_deg: 40,
# Maximum angle at which the aircraft should approach the runway.
# Must be higher than 0 and lower than 90.

distance_center_line_m: 10,
# The distance in meters from the center line of the runway

distance_edge_min_m: 20,
distance_edge_max_m: 80,
# Minimum and maximum distance in meters from the edge of the runway
# for announcing approaches.

The same applies to the configuration object landing_config:

distances: [30, 100, 300, 600, 900, 1200, 2000, 3000, 4000],

diff_runway_heading_deg: 15,
# Difference in heading between runway and aircraft in order to
# detect the correct runway on which the aircraft is landing.