Runway Awareness and Advisory System

From FlightGear wiki
Revision as of 18:09, 26 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 aligned within 20 degrees with runway
  • Advisory of remaining distance to the end of the runway during a landing while groundspeed is more than 40 knots and AGL less than 100 feet
  • Advisory when the aircraft is on a short runway

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
Give "On runway <runway>, <distance> remaining" advisory if remaining distance is less than required for a normal takeoff 100}% completed
Give remaining distance callouts after a rejected takeoff 10}% completed
Give "<distance> remaining" advisory if groundspeed is less than 40 knots and remaining distance is at most 30 meter or 100 feet 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 100}% completed
Allow distance_start_m to be nil so that on-runway signal will be emitted anywhere on the runway 100}% completed

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, on-short-runway
taxi approaching-runway
takeoff on-runway, on-short-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 (typeof(format) == "func") {
                var message_format = format();
            }
            else {
                var message_format = format;
            }

            if (data != nil) {
                var message = sprintf(message_format, data.getValue());
            }
            else {
                var message = message_format;
            }

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

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

var on_short_runway_format = func {
    var distance = getprop("/sim/runway-announcer/short-runway-distance");
    return sprintf("On runway %%s, %d %s remaining", distance, takeoff_config.distances_unit);
};

var remaining_distance_format = func {
    return sprintf("%%d %s remaining", landing_config.distances_unit);
};

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

    takeoff_announcer.set_mode("taxi-and-takeoff");
    logger.warn(sprintf("Takeoff mode: %s", takeoff_announcer.mode));
};

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");
        logger.warn(sprintf("Takeoff mode: %s", takeoff_announcer.mode));
    }
};

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

# You can modify this setting from a GUI during runtime
takeoff_config.distances_unit = "meter";

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

# 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("on-short-runway", make_notification_cb(on_short_runway_format, switch_to_takeoff));
takeoff_announcer.connect("approaching-runway", make_notification_cb("Approaching runway %s"));

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

# You can modify this setting from a GUI during runtime
landing_config.distances_unit = "meter";

var landing_announcer = runway.LandingRunwayAnnounceClass.new(landing_config);
landing_announcer.connect("remaining-distance", make_notification_cb(remaining_distance_format));
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("");
        }
        logger.warn(sprintf("Takeoff mode: %s", takeoff_announcer.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 and distance_edge_max_m where overridden for large airliners. The defaults are:

distance_start_m: nil,
# The maximum distance in meters from the starting position
# on the runway. Large runways are usually 40 to 60 meters wide
# to give you an idea of the scale. If nil then the distance is
# not taken into account, which means the aircraft can be anywhere
# on the runway for the on-runway signal to be emitted.

diff_runway_heading_deg: 20,
# 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.

nominal_distance_takeoff_m: 3000,
# Minimum distance in meters required for a normal takeoff. If
# remaining distance when entering the runway is less than the distance
# required for a normal takeoff, then the on-short-runway instead of
# on-runway signal will be emitted.

distances_unit: "meter",
# The unit to use for the remaining distance of short runways. Can
# be "meter" or "feet".

The same applies to the configuration object landing_config:

distances_meter: [ 30, 100,  300,  600,  900, 1200, 1500],

distances_feet:  [100, 300, 1000, 2000, 3000, 4000, 5000],

distances_unit: "meter",
# The unit to use for the remaining distance. Can be "meter" or "feet"

distance_center_nose_m: 0,
# Distance from the center to the nose in meters

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.

groundspeed_min_kt: 40,
# Minimum groundspeed in knots for remaining distance callouts

agl_max_ft: 100,
# Maximum AGL in feet for remaining distance callouts