The property tree is considered FlightGear's central nervous system and one of its greatest assets. It is the interface to low level, run time state variables via a very intuitive tree-like hierarchy, allowing for FlightGear's behavior to be easily controlled and manipulated at run time.
The concepts and mechanisms behind the property tree may not be immediately obvious to FlightGear beginners. This page is meant to help new users familiarize themselves with the FlightGear property tree.
- 1 The purpose of the property tree
- 2 The organization of the property tree
- 3 Customizing and manipulating the property tree through Nasal
- 4 XML and property lists
- 5 Network Protocols to access the property tree
- 6 Dumping the Property Tree to an XML File
- 7 Reference documentation to the property tree
- 8 Flight Dynamics Model (FDM)
The purpose of the property tree
The property system - or property tree - represents most of the internal state of all systems within FlightGear, like for example the flight dynamics models, or the weather simulation. The content of these internal state variables are presented in a hierarchically manner and can easily be accessed through a well known API. A system may present its current state to other systems and let them change its current state by allowing to write to its own properties.
One might think of the property system as a global, normalized communication platform, where subsystems may publish variables and access other subsystem's variables. In addition, callbacks can be registered to invoke code upon read/write access of properties, which serves as the backbone for a very simple, but powerful, signalling mechanism in FlightGear. Thus, the property system acts as a routing interface, both between different high-level FG sub-systems and the outside world. Data that is required by one FG sub-system can be exposed in the property tree, where it can then be read or modified, either by other internal FG sub-systems, or by and for external input/output.
There is some basic property-debugging support to FlightGear and SimGear. In FlightGear, the --trace-read option causes all read access for a property to be traced, and the --trace-write option causes all write access for a property to be traced, both through SG_LOG messages.
Examples of use
For example, a left banking joystick input is exposed in the property tree where it is read by the FlightGear FDM sub-system. The FDM subsystem then in turn outputs an aileron deflection back to the property tree where it is then read by the FG animation subsystem to animate the aileron deflection in the 3D model.
Alternatively the joystick input, once exposed in the property tree, can be read and modified by an external application via the FlightGear I/O subsystem, such as an external FDM. The output from the external FDM can then be fed back to FlightGear by writing its data back to the property tree, once again, via the FlightGear I/O subsystem.
There are several subsystems that implement a full API by extending the property tree, such as the AI traffic system, the multiplayer mode, but also Canvas - basically, setting certain properties (for example via Nasal's setprop()), triggering certain code (through listener callbacks) - with arguments and return values passed through the property tree, which in turn allows arbitrary 3D models to be placed, but also AI traffic to be created / controlled, as well as OpenGL textures to be created and modified and run-time, which is what we use to implement HUDs, GUIs, instruments, MFD avionics, and even liveries or scenery textures (VGDS).
The organization of the property tree
Naming a property is very much like naming a file in a file system, with levels of hierarchy. For example:
/sim/aircraft = A333 /position/ /position/longitude-deg = '-122.3576677' (double) /position/latitude-deg = '37.61372424' (double) /position/altitude-ft = '28.24418581' (double) /position/altitude-agl-ft = '22.47049626' (double) /controls/seat/eject/initiate /controls/electric/APU-generator
Some of these variables are "calculated" within the sim (for example updated regularly, in essence at frame rate), whilst others can be manipulated. Writing a variable is as easy as
/* Its my turn to play the sim */ set('/controls/seat/eject/initiate', 1)
What makes FlightGear powerful is that a new aircraft can easily be designed with its unique set of properties that somehow affect the simulation. The aircraft model has an xml file of properties that will be used within the property tree.
Customizing and manipulating the property tree through Nasal
An important feature of the property tree interface is that it can be tailored and new entries added as required through Nasal scripts, without requiring C++ changes. If you wish to use a custom-written subsystem, such as your own terrain following and avoidance subsystem, for example, and perhaps implemented in Nasal, adding new property tree branches and nodes to handle your unique data presents no problems.
The property tree is read, written, accessed and manipulated in a variety of ways, such as
- startup arguments via --prop:/sim/foo=bar
- XML files
- internal compiled code within FG - the c/c++ code
- Using native protocols, implemented in C++ (see $FG_SRC/src/Network). Property Tree/Sockets
- Using the generic protocol, either in/out/bi - this allows send/receive to the FG sim via the Generic Protocol
- telnet interface - query and fly the plane on the command line or using a scripted session (see Telnet usage)
- html interface - access the property tree using a conventional web browser like firefox/safari or chrome
- using the built in Property browser
- using other GUI dialogs
- using cockpit bindings
- using joystick bindings etc
So they can come from many places, thus there's no single source file where you'll find ALL properties/types. You will need to look at the corresponding subsystem/component. $FG_SRC/Network is the right pace to look for hardcoded protocols, make sure to also understand their inheritance (the interface being implemented).
XML and property lists
The property tree maps very nicely to XML. This is convenient for initializing the property tree and saving its state. Values in the tree are typed, but they can also be untyped strings which will be converted to a typed value when read.
PropertyList-encoded XML files are mapped to a/the property tree - typically, such XML files are not manually processed, they are "transparently" processed by FlightGear, loaded and mapped into a Property Tree.
Network Protocols to access the property tree
In addition to the protocols supported by the FlightGear I/O subsystem, other interfaces are provided by a built-in Property Tree/Web Server and a built-in Telnet server, which allow property tree data to be read and modified via these interfaces, in essence using a telnet client or a conventional web browser, at run time.
Note that you can setup as many of these servers as you want, for instance, just to be obscene you could do:
fgfs --httpd=5400 --httpd=5401 --httpd=5402 --telnet=5403 --telnet=5404 --telnet=5405
Now there are six network interfaces running that you can access from anywhere ;-)
>> "can I borrow your ipod please?" "why?"
Usually the "best" way depends on your specific circumstances. Will the two applications be running on the same machine? If not, do the two machines have a high speed network connection or some slow radio modem type connection? How much data are you sending and at what rate? Do you need really tight timing or can you get by with some delays and sloppiness in the communication?
Dumping the Property Tree to an XML File
Nasal command "io.write_properties" is used to dump all or part of the property tree to an xml file. The command can be entered interactively while using the simulator or as part of a script.
To enter the command interactively, select Nasal Console from the Debug menu and enter the command, replacing "myName" with your login directory, and replacing "/" with the path to a set of properties you want to dump. for example
io.write_properties( path: "/home/myName/.fgfs/Export/PropTree.xml", prop: "/instrumentation/kma20" );
You can dump the entire property tree. This will create a large file with more than 50,000 lines.
io.write_properties( path: "/home/myName/.fgfs/Export/PropTree.xml", prop: "/" );
In addition to debugging, there are other good reasons for doing a dump of portions of the property tree.
Reference documentation to the property tree
By what was said above, the property tree is not consistent with fixed variables, they are created dynamically, to represent a propeller plane, a Jumbo or even a "Caspian Sea Monster", or depending on which subsystems are active. Many properties availability may even depend on the startup/runtime settings you are using.
There are a bunch of "common" properties - especially among similar FDMs and aircraft. Obviously, different FDMs/aircraft will use different properties (single piston, helicopter, jet, twin turbine helicopter etc). You may want to have a look at $FG_ROOT/Docs/README.properties.
There are a couple ways that they are set, but a fair amount of them just "appear" without being documented anywhere. There are several places to look for properties; one is in the aircraft files, another is all Nasal files, and the last place (and often most useful!) is grepping (searching) through the C++ code. To determine how a property works and what it does often requires looking through any code that uses it. This is a part of FlightGear that we could certainly document better
Flight Dynamics Model (FDM)
FlightGear uses a few Flight Dynamics Models, such as
These flight dynamics models present themselves differently in the tree, using different variables, in different places. That is what an aircraft can be designed around. Most FDMs use so called tied properties, which are directly mapped to memory in C++, so that they cannot be written to - so that you would need to disable the FDM using the null FDM instead.