Nasal Flightplan: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(Some more cleanup; comment out examples for now, because it uses APIs that aren't implemented. (Several bits of this article appear to have been based on the Airbus A320neo implementation of an FMS)
(Finish cleanup for now. When I've finished docing the Nasal extension funcs, I'll come back to this.)
Line 1: Line 1:
{{WIP}}
{{Systems Modeling Disclaimer}}
{{Systems Modeling Disclaimer}}
{{Autoflight Navigation}}
{{Autoflight Navigation}}
{{Nasal Navigation}}
{{Nasal Navigation}}


Because FlightGear's [[route manager]] flightplan system is exposed to [[Nasal]], '''Nasal can be used to interact with flightplans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.
Because FlightGear's [[route manager]] flight plan system is exposed to [[Nasal]], '''Nasal can be used to interact with flight plans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.


== Background ==
== Background ==
Line 11: Line 10:
* {{func link|airwaysRoute()|page=Nasal library}}
* {{func link|airwaysRoute()|page=Nasal library}}


Flightplans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.
Flight plans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.


=== Waypoint hashes ===
== Waypoint hashes ==
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()|page=Nasal library}}:
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()|page=Nasal library}}:


Line 26: Line 25:
; heading_course : Heading of runway.
; heading_course : Heading of runway.


<!-- == Examples ==
== Examples ==
Setting flight-plan global (non-waypoint) data. Potentially this can include lots of FMS data - cruise profile, EPR setting, company route ID and so on. But most of that is probably better handled in Nasal, so long as the flight plan object provides a way to persist it.
<syntaxhighlight lang="nasal">
<syntaxhighlight lang="nasal">
# methods on airport (as returned from airportinfo())
var apt = airportinfo('eddm');
var rwy = apt.runway('28L');
# at some point in the future (not for the next release) there will hopefully be:
var rwy = apt.getActiveRunwayFor('departure', <enroute point>);
# which will return the active runway(s) for an airport based on type (arrival / departure)
# and enroute direction (e.g., departing north or arriving from the west)
# get the active flight plan (the one being used by the route manager)
# get the active flight plan (the one being used by the route manager)
fms.flightplan()
var fp = flightplan();


# or create one from Nasal
# or create one an XML file
fms.load('/path/to/xml')
fp = flightplan('/path/to/xml');


# save the active flight plan
# save the active flight plan
var fp = fms.flightplan()
fgcommand("save-flightplan", props.Node.new({"path": 'path/to/xml'}));
fp.save("/path/to/xml")


# duplicate a flight-plan
# duplicate a flight-plan
var secondary = fmd.flightplan().copy();
var secondary = fp.clone();


var dest = airportinfo('EDDM')
var dest = airportinfo('KSFO');
var rwy = dest.runway('08R');
var rwy = dest.runway('19L');
# the the arrival runway (and airport, automatically)
# the the arrival runway (and airport, automatically)
fp.setArrival(rwy)
fp.destination_runway(rwy)
 
# or if no runway is known / specified
fp.setArrival(dest)  


# optional, not used by anything in C++, but worth adding?
# or if no runway is known/specified
fg.setAlternate(<airport>);
fp.destination(dest)
</syntaxhighlight>
</syntaxhighlight>


Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.
Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.
<syntaxhighlight lang="nasal">
<syntaxhighlight lang="nasal">
# example for sids, stars are the same, approaches too
var apt = airportinfo('KSFO');
# example for SIDs, STARs are the same, approaches too
var allSids = apt.sids();
var allSids = apt.sids();


# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code
# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code
var rwySids = apt.sids('28L')
var rwySids = apt.sids('28L');
# or (potentially)
var rwySids = rwy.sids();
# rwySids = ['TALLA', 'GRICE', 'BEKNO']
 
# here's the actual call to get a procedure object by ID, from an airport
var sid = apt.procedure('BEKNO')
# sid is very similar to fmsTP above, has runways[], ident, type,
 
var star = dest.procedure('FOOBZ')
# methods: find transition for runway, find transition for location
 
# given a waypoint or geod, find the closest STAR transition point
var transition = star.findTransitionFor(fp.lastEnrouteLeg());
 
# or some other way to compute thr transition ....
 
# clear all existing arrival waypoints and rebuild from the star and approach
 
# similarly, find the best approach for our runway
var app = star.findRunwayTransition(rwy)
 
# finally, delete all existing arrival waypoints from the plan, and insert new
# waypoints from the transition, STAR and approach.
# the replaced 'buildArrival' in FGRouteManager and FGAirport (which is good!)
fp.setArrivalWaypoints(star, transition, app);
</syntaxhighlight>
 
Setting waypoint restrictions / clearing them / setting computed speeds and altitudes from the FMS
<syntaxhighlight lang="nasal">
 
var wpt = fp.firstEnrouteLeg();
# specify a manual user constraint on  this WP
# presumably do this from a CDU page
wpt.setSpeed(210);
# or in Mach
wpt.setMach(0.77)
 
wpt.setAltitude(18000);
 
# or (again from a CDU page?)
wpt.deleteRestrictions();
 
# save some data persistently to a flight plan leg
# (maybe not saved to XML? depends on the type)
wpt.setData('customfield', ..... any nasal var .... );
</syntaxhighlight>
</syntaxhighlight>


Inserting and deleting waypoints (possibly in batches)
Inserting and deleting waypoints (possibly in batches)
<syntaxhighlight lang="nasal">
<syntaxhighlight lang="nasal">
 
var fp = flightplan();
# waypoint created from lat,lon, or a navaid, or anything else?
# waypoint created from lat, lon, or a navaid, or anything else?
var wpt = fp.createWaypoint(<waypoint args>)
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 100000);
var wp = createWP(pos.lat(), pos.lon(), "EPICA");


# manually insert a waypoint into the plan
# manually insert a waypoint into the plan
fp.insertWayptAt(index, wpt);
fp.insertWP(fp.getPlanSize(), wp);


# route along airways, and insert a whole bunch of waypoints
# route along airways, and insert a whole bunch of waypoints
# this is needed for the route-manager dialog, maybe not for a
# this is needed for the route-manager dialog, maybe not for a
# real FMS interface....
# real FMS interface....
var segment = airways.route(<some geo pos or similar>, <some other geo pos>);
var segment = [<waypoint object>, <waypoint object>, <waypoint object>];
# segment is a vector of waypoints now
# segment is a vector of waypoints now
fp.insertWaypoints(index, segment);
fp.insertWaypoints(segment, fp.getPlanSize());
 
# in the future, VOR-VOR routing could be added (for GA flights, although this is rathe irrelevant thanks to GPS)
var route = routeVORtoVOR(<some pos>, <some other pos>)
fp.insertWaypoints(index, route);
 
# any other way of building up an array of waypoints is also find - suggestions?
</syntaxhighlight>
</syntaxhighlight>


Callback from C++ when the flight plan is modified, to allow the FMS to rebuild pseduo-waypoints and compute the VNAV profile. This function can be fairly intensive, but it's only going to be called occasionally, in response to user interaction.
== Related content ==
<syntaxhighlight lang="nasal">
=== Wiki articles ===
 
* [[Nasal library#Extension functions|Nasal library § Extension functions]]
# set the callback on the flight plan
* [[Navdata cache#Accessing via Nasal|Navdata cache § Accessing via Nasal]]
fp.setUpdateCallback(cb);
 
var cb = func(fp)
{
    # delete the existing pseudso waypoints
    fp.clearWPType('pseudo')
   
    # compute T/D and T/C location
   
    var wp = fp.createPseudoWP('T/D', ... other info .....);
    fp.insertWayptAt(wp , index);
   
    var tc = fp.createPseudoWP('T/C', ....)
    fp.insertWayptAt(tc, someindex);
   
# update the calculated speed / altitude values
# this needs the difficult VNAV bit to work forwards / backwards
# along the route.
    foreach (var leg, fp.legs()) {
        if (leg.alt_cstr == 'none') {
            var altitude = .... ;
            leg.setCalculatedAlt(altitude);
        }
       
        if (leg.speed_cstr == 'none') {
            var speed = .... ;
            leg.setCalculatedSpeed(speed);
        }
       
    }
}


</syntaxhighlight> -->
=== Documentation ===
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00585 flight planGhostSetMember] — ''Members of a flight plan object that can be set.''
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00557 flight planGhostGetMember] — ''Members of flight plan object that can be read.''
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l02485 initNasalPositioned] — ''Contains a list of functions that can be called on airport, flight plan, waypoint, procedure, or flight plan leg objects.''
* [http://api-docs.freeflightsim.org/flightgear/route__mgr_8cxx_source.html#l00220 FGRouteMgr::FGRouteMgr] — ''List of [[fgcommands]] relating to the route manager.''


[[Category:Nasal]]
[[Category:Nasal]]
[[Category: Core development projects]]
[[Category: Core developer documentation]]

Revision as of 10:44, 9 November 2015

Note  Whenever possible, please refrain from modeling complex systems, like an FDM, autopilot or Route Manager with Nasal. This is primarily to help reduce Nasal overhead (especially GC overhead). It will also help to unify duplicated code. The FlightGear/SimGear code base already contains fairly generic and efficient systems and helpers, implemented in C++, that merely need to be better generalized and exposed to Nasal so that they can be used elsewhere. For example, this would enable Scripted AI Objects to use full FDM implementations and/or built-in route manager systems.

Technically, this is also the correct approach, as it allows us to easily reuse existing code that is known to be stable and working correctly, .

For details on exposing these C++ systems to Nasal, please refer to Nasal/CppBind. If in doubt, please get in touch via the mailing list or the forum first.


Because FlightGear's route manager flight plan system is exposed to Nasal, Nasal can be used to interact with flight plans. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.

Background

The Nasal functions relating to the route manager system include:

Flight plans are based on waypoints, which, in C++, inherit from the FGPositioned (doxygen) class.

Waypoint hashes

The following are members of a waypoint ghost, as generated by, for example, airwaysRoute() :

wp_name
Name of the waypoint, returned as string.
wp_type
Waypoint type, returned as string. One of "basic," "navaid," "offset-navaid," "runway," "hdgToAlt," "dmeIntercept," "radialIntercept," or "vectors."
wp_role
Role of waypoint.
wp_lat or lat
Latitude of waypoint.
wp_lon or lon
Longitude of waypoint.
wp_parent_name
Name of waypoint's parent.
wp_parent
Waypoint's parent.
fly_type
How to waypoint should be flown over or reacted to. One of "Hold," "flyOver," or "flyBy."
heading_course
Heading of runway.

Examples

# get the active flight plan (the one being used by the route manager)
var fp = flightplan();

# or create one an XML file
fp = flightplan('/path/to/xml');

# save the active flight plan
fgcommand("save-flightplan", props.Node.new({"path": 'path/to/xml'}));

# duplicate a flight-plan
var secondary = fp.clone();

var dest = airportinfo('KSFO');
var rwy = dest.runway('19L');
# the the arrival runway (and airport, automatically)
fp.destination_runway(rwy)

# or if no runway is known/specified
fp.destination(dest)

Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.

var apt = airportinfo('KSFO');
# example for SIDs, STARs are the same, approaches too
var allSids = apt.sids();

# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code
var rwySids = apt.sids('28L');

Inserting and deleting waypoints (possibly in batches)

var fp = flightplan();
# waypoint created from lat, lon, or a navaid, or anything else?
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 100000);
var wp = createWP(pos.lat(), pos.lon(), "EPICA");

# manually insert a waypoint into the plan
fp.insertWP(fp.getPlanSize(), wp);

# route along airways, and insert a whole bunch of waypoints
# this is needed for the route-manager dialog, maybe not for a
# real FMS interface....
var segment = [<waypoint object>, <waypoint object>, <waypoint object>];
# segment is a vector of waypoints now
fp.insertWaypoints(segment, fp.getPlanSize());

Related content

Wiki articles

Documentation