Runway Awareness and Advisory System: Difference between revisions
No edit summary |
No edit summary |
||
Line 15: | Line 15: | ||
The Runway Advisory and Awareness System can give a number of advisories: | The Runway Advisory and Awareness System can give a number of advisories: | ||
* Advisory when approaching a runway while taxiing | * Advisory when approaching a runway while taxiing if groundspeed is less than 40 knots | ||
* Advisory when the aircraft is on the runway and aligned within 20 degrees with runway | * Advisory when the aircraft is on the runway and aligned within 20 degrees with runway | ||
Line 121: | Line 121: | ||
var copilot_say = func (message) { | var copilot_say = func (message) { | ||
setprop("/sim/messages/copilot", message); | setprop("/sim/messages/copilot", message); | ||
logger.info(sprintf("Announcing '%s'", message)); | |||
}; | }; | ||
Line 161: | Line 135: | ||
var stop_announcer = func { | var stop_announcer = func { | ||
landing_announcer.stop(); | landing_announcer.stop(); | ||
logger.warn("Stopping landing | logger.warn("Stopping landing announcer"); | ||
takeoff_announcer.set_mode("taxi-and-takeoff"); | takeoff_announcer.set_mode("taxi-and-takeoff"); | ||
Line 173: | Line 147: | ||
takeoff_announcer.set_mode("takeoff"); | takeoff_announcer.set_mode("takeoff"); | ||
logger.warn(sprintf("Takeoff mode: %s", takeoff_announcer.mode)); | logger.warn(sprintf("Takeoff mode: %s", takeoff_announcer.mode)); | ||
landing_announcer.set_mode("takeoff"); | |||
landing_announcer.start(); | |||
logger.warn(sprintf("Starting landing (%s) announcer", landing_announcer.mode)); | |||
} | } | ||
}; | }; | ||
Line 186: | Line 164: | ||
# Let the announcer emit the "approaching-runway" signal if the | # Let the announcer emit the "approaching-runway" signal if the | ||
# aircraft comes within | # nose of the aircraft comes within 120 meters of the runway | ||
takeoff_config.distance_edge_max_m = | takeoff_config.distance_edge_max_m = 150; | ||
var takeoff_announcer = runway.TakeoffRunwayAnnounceClass.new(takeoff_config); | var takeoff_announcer = runway.TakeoffRunwayAnnounceClass.new(takeoff_config); | ||
takeoff_announcer.connect("on-runway", | takeoff_announcer.connect("on-runway", runway.make_betty_cb(copilot_say, "On runway %s", switch_to_takeoff)); | ||
takeoff_announcer.connect("on-short-runway", | takeoff_announcer.connect("on-short-runway", runway.make_betty_cb(copilot_say, on_short_runway_format, switch_to_takeoff)); | ||
takeoff_announcer.connect("approaching-runway", | takeoff_announcer.connect("approaching-runway", runway.make_betty_cb(copilot_say, "Approaching runway %s")); | ||
var landing_config = { parents: [runway.LandingRunwayAnnounceConfig] }; | var landing_config = { parents: [runway.LandingRunwayAnnounceConfig] }; | ||
Line 201: | Line 179: | ||
var landing_announcer = runway.LandingRunwayAnnounceClass.new(landing_config); | var landing_announcer = runway.LandingRunwayAnnounceClass.new(landing_config); | ||
landing_announcer.connect("remaining-distance", | landing_announcer.connect("remaining-distance", runway.make_betty_cb(copilot_say, remaining_distance_format)); | ||
landing_announcer.connect("vacated-runway", | landing_announcer.connect("vacated-runway", runway.make_betty_cb(copilot_say, "Vacated runway %s", stop_announcer)); | ||
landing_announcer.connect("landed-runway", | landing_announcer.connect("landed-runway", runway.make_betty_cb(copilot_say, "Touchdown on runway %s")); | ||
landing_announcer.connect("landed-outside-runway", | landing_announcer.connect("landed-outside-runway", runway.make_betty_cb(nil, nil, stop_announcer)); | ||
var have_been_in_air = 0; | var have_been_in_air = 0; | ||
Line 239: | Line 196: | ||
takeoff_announcer.set_mode(""); | takeoff_announcer.set_mode(""); | ||
landing_announcer.set_mode("landing"); | |||
landing_announcer.start(); | landing_announcer.start(); | ||
logger.warn(sprintf("Starting landing (%s) announcer", landing_announcer.mode)); | |||
} | |||
else { | |||
takeoff_announcer.set_mode("taxi-and-takeoff"); | |||
} | } | ||
takeoff_announcer.start(); | |||
logger.warn(sprintf("Starting takeoff (%s) announcer", takeoff_announcer.mode)); | |||
} | } | ||
else { | else { | ||
takeoff_announcer.stop(); | takeoff_announcer.stop(); | ||
logger.warn("Stopping takeoff | logger.warn("Stopping takeoff announcer"); | ||
landing_announcer.stop(); | landing_announcer.stop(); | ||
logger.warn("Stopping landing | logger.warn("Stopping landing announcer"); | ||
if (have_been_in_air == 0) { | if (have_been_in_air == 0) { | ||
Line 258: | Line 220: | ||
var init_announcers = func { | var init_announcers = func { | ||
setlistener("/gear/ | setlistener("/gear/on-ground", func (node) { | ||
test_on_ground( | test_on_ground(node.getBoolValue()); | ||
}, startup=1, runtime=0); | }, startup=1, runtime=0); | ||
}; | }; | ||
setlistener("/sim/signals/fdm-initialized", func { | setlistener("/sim/signals/fdm-initialized", func { | ||
var timer = maketimer(5.0, func init_announcers()); | var timer = maketimer(5.0, func init_announcers()); | ||
timer.singleShot = 1; | timer.singleShot = 1; | ||
Line 276: | Line 232: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{{Note|In this | {{Note|In this example the /gear/on-ground property is used to detect whether the aircraft is on the ground or in the air. Make sure to use a <logic> element in a <autopilot> XML file to set this to true or false depending on your gears' wow values.}} | ||
{{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|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.}} | ||
Line 317: | Line 273: | ||
# The unit to use for the remaining distance of short runways. Can | # The unit to use for the remaining distance of short runways. Can | ||
# be "meter" or "feet". | # be "meter" or "feet". | ||
groundspeed_max_kt: 40, | |||
# Maximum groundspeed in knots for approaching runway callouts | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 02:08, 28 September 2014
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 if groundspeed is less than 40 knots
- Advisory when the aircraft is on the runway and aligned within 20 degrees with runway
- Advisory when the aircraft is on a short 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 of remaining distance during RTO after passing 50 % of 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
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 |
---|---|
takeoff | remaining-distance, vacated-runway |
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);
logger.info(sprintf("Announcing '%s'", message));
};
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 announcer");
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));
landing_announcer.set_mode("takeoff");
landing_announcer.start();
logger.warn(sprintf("Starting landing (%s) announcer", landing_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
# nose of the aircraft comes within 120 meters of the runway
takeoff_config.distance_edge_max_m = 150;
var takeoff_announcer = runway.TakeoffRunwayAnnounceClass.new(takeoff_config);
takeoff_announcer.connect("on-runway", runway.make_betty_cb(copilot_say, "On runway %s", switch_to_takeoff));
takeoff_announcer.connect("on-short-runway", runway.make_betty_cb(copilot_say, on_short_runway_format, switch_to_takeoff));
takeoff_announcer.connect("approaching-runway", runway.make_betty_cb(copilot_say, "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", runway.make_betty_cb(copilot_say, remaining_distance_format));
landing_announcer.connect("vacated-runway", runway.make_betty_cb(copilot_say, "Vacated runway %s", stop_announcer));
landing_announcer.connect("landed-runway", runway.make_betty_cb(copilot_say, "Touchdown on runway %s"));
landing_announcer.connect("landed-outside-runway", runway.make_betty_cb(nil, nil, stop_announcer));
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.set_mode("landing");
landing_announcer.start();
logger.warn(sprintf("Starting landing (%s) announcer", landing_announcer.mode));
}
else {
takeoff_announcer.set_mode("taxi-and-takeoff");
}
takeoff_announcer.start();
logger.warn(sprintf("Starting takeoff (%s) announcer", takeoff_announcer.mode));
}
else {
takeoff_announcer.stop();
logger.warn("Stopping takeoff announcer");
landing_announcer.stop();
logger.warn("Stopping landing announcer");
if (have_been_in_air == 0) {
have_been_in_air = 1;
}
}
};
var init_announcers = func {
setlistener("/gear/on-ground", func (node) {
test_on_ground(node.getBoolValue());
}, startup=1, runtime=0);
};
setlistener("/sim/signals/fdm-initialized", func {
var timer = maketimer(5.0, func init_announcers());
timer.singleShot = 1;
timer.start();
});
Note In this example the /gear/on-ground property is used to detect whether the aircraft is on the ground or in the air. Make sure to use a <logic> element in a <autopilot> XML file to set this to true or false depending on your gears' wow values. |
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".
groundspeed_max_kt: 40,
# Maximum groundspeed in knots for approaching runway callouts
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