Property Tree/Native Protocol Slaving

From FlightGear wiki
Jump to navigation Jump to search

FlightGear can also be configured to dump UDP or TCP data packets out over the network at a high speed. Other copies of FG can be configured to read these packets and use that data (and disable the internal FDM calculations.)

In this case, depending on your command line options, FG can be configured to be a telnet server, an http server, a "dynamics" master/server, or a "dynamics" slave/client, and possibly some combination of all of those simultaneously depending on the context and what you are trying to accomplish.

There is an --native-ctrls= command line option to send a set of flight control related properties. It works just like the --native-fdm option, just remember to use a different port number.

For past projects, I've used the --props= option to accept property configuration changes (things like weather effects and time of day.) You can use this interface to read/write individual properties. I setup a separate gui that was configured to know the ip addresses of all the slaves so it could update them appropriately when I wanted to make a change. For the time of day, this presupposes that all the computer clocks are pretty closely in sync ... then you can send the same time offset to them (in seconds) so they all can display the same time of day effects.


There is no synchronization in the native-fdm and native-ctrls protocols used for multiple displays. The master instance just transmit to the slaves, who process the data when and in the order it is received. This ought to work without problems in a local network.

native_ctrls is what gets sent to a remote fdm (i.e. the control positions) and native_fdm is what gets sent back to flightgear (i.e. the fdm data.) There's no reason you can't send both in your application if you need to.

The FDM defines the control surface position (deflection) so that data is passed to FlightGear in the native_fdm structure.

I will not claim that the existing FG interfaces cover every possible case. They have been designed to try to serve existing needs with some sort of logical consistency.

If you have a specific need that doesn't easily fall within the existing interface structure, it's not all that hard to add your own custom interface. There are several examples (i.e. native_ctrls, native_fdm, native_gui, etc.) which you can copy and modify to suit your needs. If the new interface is of general interest or if you make a persuasive argument, we could probably add it to the FG code base.

I'd take a look at net_fdm.h and native_fdm.c. The data structure received by FlightGear can easily be modified to include whichever parameters you'd like to control from your Matlab sim. You just need to add code to set the appropriate FlightGear properties.

It doesn't make sense to modify the current version of FlightGear because different people have different requirements. For instance, if you allow both control positions and surface deflections to be sent, how does the fdm know which one to use? Furthermore, the native_fdm is designed to control actual rotation rates and velocities, so control positions don't factor into this. It seems like you'd like a little bit of each, which to me means a custom modification.

We have discussed a more flexible (xml configurable) udp binary interface, but no work has commenced on that front.

It might not be a good idea to throttle the frame rate to the data rate - FG will only check for input (at most) once per frame and that could easily fall out of sync with the producer in this case (if data arrives too late in some frames). If FG consumes all pending data it finds that could explain the jerks. Can you try throttling to 2x the data rate?

Asymmetric View Frustrums

Supporting mutliple displays are well supported in FlightGear. There is a document called README.IO that touches on this. You may also want to check out [1]. If you need more help, just ask.

You can set up your view parameters for each instance individually, e.g.:

--fov=35
--prop:/sim/view/config/heading-offset-deg=42
--prop:/sim/view/config/pitch-offset-deg=3

You can adjust these properties in real time if you need to, but typically you set these once for a particular monitor configuration and you simply send over the position and orientation to the slave machines and everything happens automatically. The configurable numbers are offsets from straight ahead.

If you need to model your view point changing relative to your monitors (head tracker?) and need to fiddle with your frustums and view direction offsets in real time, then that's a bit more difficult. I'm not aware of anyone doing this, but it shouldn't be all that much additional effort to add support for this sort of thing.

I should point out that we also have some capabilities for configuring asymmetric view frustums if you need that. We use a higher level mechanism (that meshed well with what we already had in place) so you specify a larger screen and then specify the horizontal and vertical subsections of that larger display that will be shown on a particular monitor. This probably doesn't cover all asymmetric view frustum needs, but it does let you do a lot in a way that people can conceptually get their head around (rather than using obscure l, r, t, b, n, f numbers that takes an opengl guru to derive.)

For my specific need I wanted 3 monitors side by side in a straight line, and I wanted the projection plane to also be a straight line. So referencing your link, Example 1 is what we originally could do, but is not what I wanted. I wanted to do something similar to Example .... errr ... I guess there isn't an example on that page of what I wanted to do. Kind of like Example 5 I guess except with the "red" line (plane of projection) extending straight across. The center view frustum would be symmetic and the sides would be asymmetric. I realize this isn't "correct" but I need a compromise to build a display system that look "reasonable" from a large variety of perspectives at the same time.

So anyway, here's my approach. Let's say I wanted 3 monitors, each covering 30 degrees FOV.

  • I added an --aspect-ratio-multipler=x.xx option. FG automatically calculates aspect ratio based on X, Y screen resolution. This option scales the Y FOV.
  • I created a super wide display with something like --fov=90 --aspect-ratio-multiplier=0.33333
  • I added some options to select a portion of this wide screen to draw onto the individual monitor:
--prop:/sim/current-view/frustum-left-pct=0.00000
--prop:/sim/current-view/frustum-right-pct=0.333333

This gives me the leftmost 1/3 of my wide (--fov=90) screen. And the aspect ratio multiplier option allows me to get the desired vertical field of view. Well, technically, my scheme still requires a separate running copy of FG and a separate video card for each monitor. I've had the best results doing this from 3 different machines, but I've heard stories of others having reasonable results with running multiple copies of FG on a single machine. At the moment FG doesn't have direct support for opening up multiple windows to drive multiple displays from a single instance of FG.

There really isn't any extra performance hit though for asymmetric view frustums. The frustum is trimmed down before the cull and draw phase.

I should say though that most people will just want to point their displays perpendicular to the viewer and use a more standard/straightforward symetric view frustums. I had to do asymmetric view frustums for a particular project with specialized needs. We ended up with a combination of compromises that I wasn't entirely happy about. We were trying to achieve a middle of the road solution that wasn't perfect anywhere, but wasn't horrible anywhere either.

Syncing multiple instances

For anyone trying to sync multiple copies of flightgear and get silky smooth frame rates, or anyone trying to get silky smooth frame rates in a single copy of FG the following is some important information I learned the hard way...

If you want smooth rendering, you need to do a couple things. First, make sure that your copy of FG can render a sustained consistant frame rate. One *good* option is to sync to the vertical refresh signal on your monitor. With linux/nvidia there is an environemental variable you need to set to activate this feature (see readme that comes with the driver.) For other cards or platforms, there may be some different mechanism. Secondly, there is a tool that FG gives you to throttle frame rates to a maximum value. Set the property /sim/frame-rate-throttle to some value that is a multiple of your monitor's refresh rate, but is fast enough for your machine to keep up with consistently. From the command line or your ~/.fgfsrc you could do this:

 --prop:/sim/frame-rate-throttle-hz=30

Just to convince yourself this is working, you might want to try something like:

 --prop:/sim/frame-rate-throttle-hz=5

This will limit your maximum frame rate to the specified hertz (if your machine can go that fast.) The internal FG mechanism to do this is a simple busy/wait loop so you don't gain any CPU cycles with this, but you do get pretty accurate timing.

Getting the rendering speed consistent is one side of the coin. The other is that you need to feed the data input stream at the same consistent rate. This can be hard to control if you are communicating over the network.

Consider this: here in the USA our monitors really like to run at 60 hz (or 72 or 75.) I usually run them at 60hz because that's easier to keep up with for FG rendering. For one particular example, I was stepping FG down to 30hz. I was trying to feed FG from another application running on the same machine. This was a really low cpu-usage process so I was using timer interrupts to wakeup every 33ms and send the data over the network. I was about to congratulate myself on my own cleverness, but I was continually nagged by much choppier rendering than I thought I should be seeing. Something wasn't right. It just so happened that someone had an oscilliscope they could connect in to one of the interfaces and see exactly how fast my data feeding program was running ... I was shocked that it was doing 25hz (or one data output every 40ms even though my timer was set to wake up every 33ms.) A 25hz input stream combined with a 30hz renderer just can't provide jitter free video output, in fact it's pretty horrible.

Upon further investigation I discovered that the underlying linux CPU scheduler runs at 100hz (20ms cpu scheduler interrupt rate.) This is hard coded into the kernel and at one time represented a good balance between not burning too much CPU with excessive context switching, yet switching processes often enough so that they didn't become too unresponsive.

Apparently the linux timer interrupt system only checks for a timer interrupt during a context switch (or every 20ms.) So I requested a 33ms wakeup ... after the first 20ms context switch, the timer hadn't expired yet, and the system wouldn't check again for another 20ms ... so I was getting 40ms interrupt times when I asked for 33ms... Actually you get 40ms interrupts if you ask for anything > 20ms or <= 40ms. Frustrating! I actually tried playing with the system cpu scheduler rate and recompiling my kernel and never got the results I was hoping for.

This message is starting to get a little long and tedious, but my point here is that for smooth frame rates: (1) you need to draw the scene at a consistant rate (and I mean a consistant frame rate, not a variable rate faster than movie frame rates, but that's another tedious discussion for another time.) And (2) you need to feed your position/orientation updates at that exact same rate (and my example was to show why that's not always easy.) :-)

What I ended up doing on the Linux platform was to keep the two applications running on the same machine, but communicate between them using a named pipe. Each application blocks waiting for input from the other side of the pipe, so you aren't held hostage to your OS's CPU scheduling/timing interrupt voodoo. FG acts in sort of a "master" or "commander" roll. The other application which feeds the data waits for a request and immediate responds with the result. This way FG runs essentially at full speed and isn't hindered by blocking on the other application's output (because even though it does block, it get's a reply back immediately to unblock it.) The other application blocks on FG's output which means it sit's idle (not burning any CPU) until a request/command comes in on the pipe. Of course you have to make sure your communication is all sequenced perfectly or you risk a dead lock scenario.

Hopefully this message doesn't read too much like a computer science operating systems class, but any similarities you do see are intentional. :-)

Windows doesn't have a real concept of "pipes" in it's underlying kernel, especially "real time" pipes which can't be faked with a temporary file, so shared memory is another solution for getting two applications to talk to each other. I'm sure that's where the "sharemem.dll" comes into play.

Also it should be noted that if you can run your monitors/projectors at 60hz refresh rate, and then sync FG to the vertical refresh signal, and if your hardware is fast enough to sustain at least 60hz, then you can have extremely smooth displays. If you are able to send the NetFDM packets at exactly 60hz to all your display channels, you can have remarkably good syncronization between channels, and very smooth animation over all. But the key is to have *everything* running at a solid consistant frame rate. If you can't do 60hz, we have a mechanism to artificially throttle the frame rate to something lower, like 30hz or 20hz. Sometimes a slower consistant frame rate produces much smoother results than a faster, but varying frame rate.

if you're really seeking for a 'clean' solution there are more topics to add. For instance you have to synchronize the yoke positions because you are likely to have a setup where the co-pilot's yoke is visible in the right-window view. Neither protocol will handle this. You might see AI aircraft taking off at the local airfield, an aircraft carrier or whatever else which lack synchronization as well, no matter which protocol you use.

Distributing the AI stuff over the general/official MultiPlayer server might not be such a nice thing to do, so it might make more sense so synchronize the slave views locally. This still lacks synchronization of AI objects but at least you don't annoy other people which are using the MP server.

Having the MP protocol extended to handle the needs of local synchronization might be the solution of choice, because apparently it puts less load onto the master machine than the 'native' protocol and it is platform independent - and while everybody is waiting for a chance to implement new features inside the MP protocol, 'they' might add a viewer-only mode as well

In my application with one cockpit computer and 3 out-the-window computers, I already am using the FGNetFDM and FGNetCtrls structures to pass data between these 4 machines. Flight dynamics, cockpit controls, control surface animations, etc. are already synced. That is taken care of.

Now I want to fly this system of computers in the multiplayer world. An invisible player option (view only) for each of my visual channels would be a quick and dirty solution to my problem. I realize it wouldn't be perfect and there could be synchronization issues with the MP aircraft locations when passing between displays, but I can live with that for now.

AI aircraft is an entirely different issue. I just turn all that off on this system because precisely as you point out, the AI stuff operates independently in each display and that is not helpful. There are a lot of things we could discuss with AI aircraft, but I don't want to distract everyone from my main request, a viewer only mode for the Multiplayer system.


 //*** example to slave one copy of fgfs to another ***
 
 // This instructs the first instance of fgfs to send UDP packets in the native format to a machine called seattle.com on port 5500.
 fgfs1:  --native=socket,out,30,seattle.com,5500,udp
 
 // The second instance of fgfs will accept UDP packets (from anywhere) on port 5500.  
 // Note the additional --fdm=external option which tells the second instance of fgfs to not run the normal flight model,
 // but instead set the FDM values based on an external source (the network in this case.)
 fgfs2:  --native=socket,in,30,toulouse.net,5500,udp --fdm=external

Slaving Controls (Joystick)

--native-ctrls transmits many variables concerned with flight control positions, cockpit switches, radio settings, sim status (paused?), etc. See net_ctrls.hxx

Look at the Network subdirectory for all the various options and the mini-docs for a howto. the necessary socket code is built into flightgear and envoked as " --native-ctrls=socket,in,32,,5700,tcp " where:

  • 32 is the data rate (packets/sec)
  • 5700 is the socket address used by the slave and server
  • tcp is the IP protocol (you can use udp, but packert deliver is not guaranteed)

Slaving Dynamics (FDM)

There is a sample implementation that shows how to do this in the sourcecode under FlightGear/examples/netfdm.

Example: Syncing custom properties (animations etc) using a generic protocol

For the full thread, see [2].

(Required background reading: $FG_ROOT/Docs/README.IO and $FG_ROOT/Docs/README.generic)

Multi-Instance Setup

  • I was under the impression that using only one computer and multiple displays with FlightGear would be too taxing on the computer and graphics hardware. I've done multiple screens with GEFS (Google Earth Flight Simulator) and got some pretty slow frame rates doing it. Multiple computers with FGFS though is *so* much smoother most of the time. Much, much better.
  • After much trial and error, I've succeeded in setting up slave computers for displaying different camera views, and it's pretty freaking awesome. I'd like to do some fine tuning now and hope I can find some help here on the forum.
  • I've pretty much been working with just one aircraft in getting the multi-computer thing going. The way I implemented it was to add a new view to the Aircrane aircraft on each computer - slave left view, master view, slave right view.

Syncing Shadows

  • The first thing I'd like to tackle is - how to not have inappropriate shadows - in the slave displays. The aircraft can be well above the ground and yet cast *in the air* the shadow it would cast if it were on the ground. And possibly related to that, the props/rotors/etc. are frozen and don't move at all. Is there anything that can be done about this? I'm using native-fdm and native-ctrls between the computers but know next-to-nothing about the capabilities of the other options/protocols. I had some success with native-gui (I think it was), but so far, the fdm and ctrls combo works best for me.
  • One more thing I noticed today was that while the attitude may change, there doesn't seem to be a corresponding change in the shadow. It always looks like it would look if the aircraft were parked on the ground
  • sounds to me like you are using a combination of I/O protocols that isn't suitable to synchronize aircraft properties to update the slave instances.
  • This is an aircraft-specific issue, due to the limitations of the protocols that's used - basically, the aircraft uses animations and properties that are not synchronized with other instances. So that animations from the main/master instance are not properly propagated to the slaves.

The Problem

  • The way you described your setup, you are running multiple instances of FG, which are connected in a master/slave fashion - which basically means that important properties need to be replicated/copied over to the slaves instances. These are properties like position, orientation, view, velocities etc - each FG instance will then individually compute a corresponding view. The frame/image itself will never be copied to the other instances - just the variables.
  • So are there additional protocols I should/could be using maybe? Is sending just the master computer's camera views - without its fdm etc. - something that's possible, or does that require too much work from the master's graphics card and defeat the whole purpose of using multiple computers?
  • Meanwhile, I'm thinking the wierd shadows are only a symptom, and the props/rotors not moving is another sympton. It's as though the aircraft models in the slave computers get no instruction to be anything but parked on the ground with the engines off. You see (at least I see) the changes in attitude as you fly, but that's it. Nothing else ever changes...
  • the animation properties don't seem to be properly synchronized - you'll need to handle that explicitly using another sync protocol, the FDM/input protocols don't transmit animation properties - they just transmit the "fundamental" properties. Basically, your slaved instance knows nothing about the properties that it needs to get from the master instance.

Using a custom protocol to sync properties

  • Also, you can easily come up with your own custom protocols by editing/creating XML files Generic Protocol
  • it looks like generic protocol might be the way I want to go, but how do I determine which properties need to be included and which ones don't? Or am I asking the wrong question?
  • You could try to run a single master instance and check the values of the properties via the property browser. That should give you an idea of working values, even without understanding all the XML/animation magic.
  • We've been discussing weird shadows, and propellers not spinning and such, but my focus is primarily on the shadow problem. I can put up with animations of flight control surfaces not working in the 'at aircraft' views, because I'd probably only use those views occasionally. However, in views from the pilot's perspective, pitching down and banking can cause extremely distracting dark shadows to come into view that darken huge chunks of real estate below. The size of the shadow is constant, regardless of altitude; it's the shadow that would be cast on the ground when the aircraft is on the ground. I nearly jump out of my seat sometimes when they suddenly appear during a dive etc.
  • Well I've started thinking it might simply be a matter of *altitude updating* of the aircraft's shadow casting properties that's not being received by the slave instances via the native-fdm protocol. The 'shadowcasters' of the slaves, so to speak, always think the aircraft is on the ground. If this is the case, I would imagine that somewhere in the properties browsers of the master and the slaves I would see the values of certain altitude properties being updated in the master and remaining constant in the slaves?

Finding relevant properties

  • So if any following this thread think I'm on the right track here, could you offer some suggestions as to what properties I might look at or what altitude related keywords in the xml files and properties browser might be worth taking a look at? I've done some searching on "agl" (above ground level, I assume)and "elev*" and "shadow*," but haven't come across anything yet that looks all that promising. Of course looks can be deceiving, so any insights at all would be greatly appreciated.
  • if this is "stock" FG in non-Rembrandt mode, the shadows are unlikely to be actually computed - they are just a "hack" added by modelers, in the form of semi-transparent 3D models usually.
  • In the master computer's view, the same shadows I've been talking about *change* as altitude changes. It's the ground shadow you see with all aircraft. The higher the aircraft goes, the smaller the shadow on the ground appears to the pilot. In the slave views, the shadow doesn't change at all with change in altitude. The shadow is always the same size to the pilot; it's always the size it is when the aircraft is on the ground. What I need to know (I think) is what properties effect that change in the master's views that are missing in the slave instances. Would it matter whether or not that change is caused by a hack or whether or not it's a hack that gets changed? Couldn't such a change be transmitted via the generic protocol nevertheless?
  • Regarding the shadows: that'd depend on the animations that are used there - so, you'll want to check out the animations on the master, see how they work exactly, and then provide the correponding data (=properties) by sync'ing them from the master to the slaves. Given your progress, that should be all do-able now, you just need to find the animations and check what properties are used. A fair deal of stuff can be learned just by using the property browser or the Nasal console and playing around with various properties, and changing them at runtime - no slaves needed for that, just to make sense of how the animations and properties hang together.
  • Actually, the shadow is 95% generic/standard across aircraft, and only has two rotates (/orientation/pitch and /orientation/yaw) and a translate (/position/altitude-agl or /position/gear-agl-ft) and sometimes one more for the rotors (I forget the property, but it's under /rotors/main and it's absolute position in degrees). I think it will work, but it's odd that the shadow is not showing up (I wonder if it is possibly below-ground?).
  • I meant to say was that it was the /position/gear-agl-ft property I wanted to try, because when I inspected that property in the slave with the internal properties browser, it showed a value of ' ' (blank), whereas the same property on the master did show a value.
  • I'm trying to set up generic protocol communication between a master and slave computer.

The generic protocol

  • I created an xml protocol file with an output block for the master and opened a generic protocol output.
  • A protocol file can contain either or both of <input> and <output> definition blocks.
  • Well, I think I'm on the right track. First of all, I took the protocol file with the output block for the master and copied it to the slave computer and simply changed both output tags to input tags.
  • Then I created the input generic protocol on the slave and gave her a shot. Well, lo and behold, the shadows are gone, although not as I had hoped. I was thinking I would still see *appropriate* ground shadows, but it turned out there are now no shadows at all...which is a far cry better than it was before. I can definitely live with this, but if anyone can think of any tweaks to get the appropriate shadows back, that would be way cool.
  • In the protocol files I used, I wasn't sure what value to put in for the 'format' tag, so I edited it out. I didn't know how to find out what it should be. Wouldn't it be great if the correct value for that would bring back the appropriate shadows?
  • Someone with more expertise could probably look at the value for the /position/gear-agl-ft property in the properties browser and determine by the number that's displayed what the format is, but I'm not in possession of that knowledge at the moment.
  • I'm making progress. I have shadows behaving pretty well and am starting to get rotors moving, but the rotors are behaving badly. They spin in the slave when they're stationary in the master. They start looking like they're robo-spider-legs, drawing in and out and in and up and in and down, all with quick jerky moves and blurring going on. It's wild!

Format tags

  • Well I've not put in many format tags at all, and I'm wondering if that can matter. The values of a property in the slave property browser can be radically different from the values of the same property in the master's property browser. Is there a way to find out which format tags to use for properties on the tree?
  • Generally, I think you will be wanting to use %f. Read up on printf formatting flags: %d is an integer and %f a float/double. I think that all properties will almost certainly be doubles.
  • I use "type" tags to declare property values as double, float, etc. When you, for instance, declare a type to be float, what does formatting as %f do? I know you can dictate how many decimal places there should be on either side of the decimal point with something like %xx.xf, but what does %f default to? It's the number of places on either side of the decimal point that I was wondering what would be best.
  • I guess I'll go ahead and experiment with it while I wait for any reply you might be able to offer. I don't think I'd do too much damage doing that...
  • the type attribute tells the property tree how to store a value internally, using the most appropriate data type saves memory and reduces conversion overhead (bool, int, float, double, string). Using the printf-style format strings in a generic protocol XML file, merely tells the I/O system how to encode/decode a property - so that it can be saved/transmitted and restored properly. Using the wrong type and/or format string in a binary protocol, would cause wrong data to be transmitted/processed by FG. Basically, each type specifier tells FG how long each data type is in memory (bits-wise). For example, a boolean value is just 0 or 1 - so it only requires a single bit. A byte, on the other hand, requires 8 bits - and an integer (int) 4 bytes (32 bit). So telling FG that something is a bit, will cause the data to be truncated to just a bit - which is what the format specifiers are all about: you can affect the re-interpretation of values from the property tree. In addition, there's the concept of signed-ness, i.e. numbers being positive or negative, or numbers having a mantissa - these affect how the values are stored in memory, and accordingly, the receiver must know how a value was encoded, to transform it back to what you want it to be.

Success !

  • Well I'll be! I added %f formatting to everything, and now everything appears to be working almost perfectly. The shadows are appropriate and the main rotor on the slave appears to be behaving exactly like the one on the master. This is awesome. The only difference I can see is that the animated main rotor shadow appears to have fewer blades on the slave, but if I never find out why and fix it, it will barely matter. I'm completely stoked! All I basically have left to do is put in pretty much the same code for the tail rotor that I did for the main rotor.


<?xml version="1.0"?>
<PropertyList>
	<generic>
		<output>
			<line_separator>newline</line_separator>
			<var_separator>,</var_separator>

			<chunk>
				<node>/position/gear-agl-ft</node>
				<type>float</type>
				<format>%1.9f</format>
			</chunk>
			<!-- <chunk>
				<node>/orientation/pitch-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/orientation/roll-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk> -->

			<chunk>
				<node>/rotors/main/blade/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<!-- <chunk>
				<node>/rotors/main/blade[0]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[0]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk> -->

			<chunk>
				<node>/rotors/main/cone-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone1-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone2-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone3-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone4-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/roll-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/rpm</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/stall</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/stall-filtered</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/torque</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/yaw-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>
		</output>
		<!-- ******************************************************** -->
		<input>
			<line_separator>newline</line_separator>
			<var_separator>,</var_separator>

			<chunk>
				<node>/position/gear-agl-ft</node>
				<type>float</type>
				<format>%1.9f</format>
			</chunk>
			<!-- <chunk>
				<node>/orientation/pitch-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/orientation/roll-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk> -->

			<chunk>
				<node>/rotors/main/blade/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[1]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[2]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[3]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[4]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/flap-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[5]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<!-- <chunk>
				<node>/rotors/main/blade[0]/position-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/blade[0]/incidence-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk> -->

			<chunk>
				<node>/rotors/main/cone-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone1-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone2-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone3-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/cone4-deg</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/roll-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/rpm</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/stall</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/stall-filtered</node>
				<type>double</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/torque</node>
				<type>float</type>
				<format>%f</format>
			</chunk>

			<chunk>
				<node>/rotors/main/yaw-deg</node>
				<type>float</type>
				<format>%f</format>
			</chunk>
		</input>
	</generic>
</PropertyList>

Examples

For setting up slaved visual channels, here are some of the options I have used:

--enable-game-mode (--enable-fullscreen depending on glut vs. sdl)
--prop:/sim/menubar/visibility=false
--prop:/sim/ai/enabled=false (prevents the ai ATC text at the top of the screen.) --prop:/sim/ai-traffic/enabled=false (prevents strange planes from flying across a single view)
--prop:/sim/rendering/bump-mapping=false
--fov=35
--prop:/sim/view/config/heading-offset-deg=-35
--prop:/sim/view/config/pitch-offset-deg=3
--native-fdm=socket,in,60,,5505,udp
--native-ctrls=socket,in,60,,5506,udp
--fdm=null

Time Syncing

You can set /sim/time/cur-time-override to override the current time. If you do so, you also have to do this continously to keep the time up-to-date. The value to feed into this property is the return value of the posix time() function. Unfortunately there is no output property for this values. The other input property for setting time is /sim/time/warp to set the offset to the system's clock.

Also see:

Troubleshooting

Check the hardwired version number in the packet. That will get incremented when the structure changes. It's also there if you want to get crazy and build a system that can read the packet version and decode it differently for different versions. I suspect there probably was a change