Runway Awareness and Advisory System

From FlightGear wiki
Revision as of 23:05, 22 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

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

  • Find a core dev to commit logger.nas and runway_announcer.nas to FlightGear's fgdata repository.
  • Use *.groundnet.xml to detect when the aircraft is near a holding point to more accurately emit "approaching-runway" signal.
  • Give an advisory of which runway the aircraft is lined up with when the aircraft is airborne and approaching a runway.

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.