Generic protocol: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg24570.html)
(http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg22705.html)
Line 16: Line 16:


The generic protocol can be easily set up for both input and output. And it supports not just a single medium, but can be easily made to use files, FIFOs, sockets etc. The generic protocol is really good for things like exporting to a delimited ascii file for import into excel for instance.
The generic protocol can be easily set up for both input and output. And it supports not just a single medium, but can be easily made to use files, FIFOs, sockets etc. The generic protocol is really good for things like exporting to a delimited ascii file for import into excel for instance.
I think it makes sense (when dealing with live data) for the generic protocol to enter a while loop and read data until there is no more available.  That way if the sender is sending at a higher rate or FlightGear gets behind for any reason, FlightGear will get caught up each iteration.  This obviously does not work well for file input though, so you'd have to differentiate.


== XML File Layout ==
== XML File Layout ==

Revision as of 20:16, 4 May 2013

FlightGear supports multiple concurrent IO connections.

You could use the FGNetFDM (--native) protocol or the --generic protocol (which allows you to design custom packets with the specific fields you choose.) Both of these can send the data out as UDP packets which then can be read by your external program using standard socket communication.

This same basic mechanism also would permit your external program to send control commands so if some day you want to do some sort of hardware or software in the loop testing of your uav controller, that is also a possibility.

There is a slightly complex, but pretty flexible mechanism for specifying an IO channel, what type of communcation will get sent over it, which direction, and at what rate. Look for a file called README.IO that briefly explains much of this.

In addition, there is a "generic" protocol where you can create an xml file specifying exactly what data values you wish to send across your IO channel. We don't have generic "USB" support, but if you have a Serial -> USB device that looks like a com port on the computer side, then that should work without any problem ... just be careful which com port your usb device gets assigned to.

There is the native_fdm protocol to control FlightGear using an external FDM and there is the generic protocol that uses the XML configuration files.

The generic communication protocol for FlightGear provides a powerful way of adding a simple ASCII based or binary input/output protocol, just by defining an XML encoded configuration file and placing it in the $FG ROOT/Protocol/ directory.

The generic protocol can be easily set up for both input and output. And it supports not just a single medium, but can be easily made to use files, FIFOs, sockets etc. The generic protocol is really good for things like exporting to a delimited ascii file for import into excel for instance.

I think it makes sense (when dealing with live data) for the generic protocol to enter a while loop and read data until there is no more available. That way if the sender is sending at a higher rate or FlightGear gets behind for any reason, FlightGear will get caught up each iteration. This obviously does not work well for file input though, so you'd have to differentiate.

XML File Layout

A protocol file can contain either or both of <input> and <output> definition blocks. Which one is used depends on how the protocol is called. The following example would only use the <output> definitions block.

--generic=file,out,1,/tmp/data.xml,myproto

If you're using a serial port under Windows, you must use a special escape sequence for COM port numbers higher than COM9.

Ex: --generic=\\.\COM10,out,1,/tmp/data.xml,myproto

More detail can be found in this Microsoft KB article: http://msdn.microsoft.com/en-us/library/aa363858%28v=vs.85%29.aspx

Overview of the XML file

<?xml version="1.0"?>
<PropertyList>
   <generic>

       <output>
           <binary_mode>false</binary_mode>
           <line_separator></line_separator>
           <var_separator></var_separator>
           <preamble></preamble>
           <postamble></postamble>

           <chunk>
               ... first chunk spec ...
           </chunk>

           <chunk>
               ... another chunk etc. ...
           </chunk>
       </output>

       <input>
           <line_separator></line_separator>
           <var_separator></var_separator>

           <chunk>
               ... chunk spec ...
           </chunk>
       </input>

   </generic>
</PropertyList>

Input/Output Parameters

Both <input> and <input> blocks can contain information about the data mode (ascii/binary) and about separators between fields and data sets, as well as a list of <chunk>s. Each <chunk> defines a property that should be written (and how), or a variable and which property it should be written to.

ASCII protocol parameters

Output only:

<preamble>        STRING  default: ""    file header put on top of the file
<postamble>       STRING  default: ""    file footer put at the end of the file

Input & Output:

<binary_mode>	    BOOL    default: false (= ASCII mode)
<var_separator>   STRING  default: ""    field separator
<line_separator>  STRING  default: ""    separator between data sets
  • <var_separator> is put between every two output properties
  • <line_separator> is put at the end of each data set.

Both can contain arbitrary strings or one of the following keywords:

 Name             Character
------------------------------
 newline          '\n'
 tab              '\t'
 formfeed         '\f'
 carriagereturn   '\r'
 verticaltab      '\v'

Typical use could be:

<var_separator>tab</var_separator>
<line_separator>newline</var_separator>

or

<var_separator>\t</var_separator>
<line_separator>\r\n</line_separator>


Binary protocol parameters

To enable binary mode, simply include a <binary_mode>true</binary_mode> tag in your XML file. The format of the binary output is tightly packed, with 1 byte for bool, 4 bytes for int, and 8 bytes for double. At this time, strings are not supported. A configurable footer at the end of each "line" or packet of binary output can be added using the <binary_footer> tag. Options include the length of the packet, a magic number to simplify decoding. Examples:

 <binary_footer>magic,0x12345678</binary_footer>
 <binary_footer>length</binary_footer>
 <binary_footer>none</binary_footer>                 

Variable Parameters - <chunk> spec

Both <input> and <output> block can contain a list of <chunk> specs, each of which describes the properties of on variable to write/read.

<name>

For ease of use and not tranferred (like a notes tag)

<node>

The property tree node which provides the data

<type>

The value type which is needed for formatting, one of string, float, bool, int (default: int). Its recommended that this tag is present otherwise spurious results can occur.

<format>

ASCII protocol only, not used or needed in binary mode. Defines the actual piece of text which should be sent. it can include "printf" style formatting options like:

           <type>
   %s      string
   %d      integer (default)
   %f      float

Note: 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.

<factor>

An optional multiplication factor which can be used for unit conversion, for example, radians to degrees.

<offset>

An optional offset which can be used for unit conversion, for example, degrees Celcius to degrees Fahrenheit.

<format>

Chunks can also consist of a single constant <format>, like in:

<format>Data Section</format>


Examples

Example 1

Writes log of this form:

V=16
H=3.590505
P=3.59
V=12
H=3.589020
P=3.59


<?xml version="1.0"?> 
<PropertyList>
<generic>

   <output>
     <line_separator>newline</line_separator>
     <var_separator>newline</var_separator>
     <binary_mode>false</binary_mode>

     <chunk>
       <name>speed</name>
       <format>V=%d</format>
       <node>/velocities/airspeed-kt</node>
     </chunk>

     <chunk>
       <name>heading (rad)</name>
       <format>H=%.6f</format>
       <type>float</type>
       <node>/orientation/heading-deg</node>
       <factor>0.0174532925199433</factor>  
     </chunk>

     <chunk>
       <name>pitch angle (deg)</name>
       <format>P=%03.2f</format>
       <node>/orientation/pitch-deg</node>
     </chunk>
  </output>

</generic>
</PropertyList>

Writing data in XML format

Assuming the file is called $FG ROOT/Protocol/xmltest.xml, then it could be used as

fgfs --generic=file,out,1,/tmp/data.xml,xmltest


<?xml version="1.0"?>
<PropertyList>
 <generic>
   <output>
     <binary_mode>false</binary_mode>
     <var_separator>\n</var_separator>
     <line_separator>\n</line_separator>
     <preamble><?xml version="1.0"?>\n\n<data>\n</preamble>
     <postamble></data>\n</postamble>

     <chunk>
       <format>\t<set></format>
     </chunk>

     <chunk>
       <node>/position/altitude-ft</node>
       <type>float</type>
       <format>\t\t<altitude-ft>%.8f</altitude-ft></format>
     </chunk>

For more examples, see [1].

     <chunk>
       <node>/velocities/airspeed-kt</node>
       <type>float</type>
       <format>\t\t<airspeed-kt>%.8f</airspeed-kt></format>
     </chunk>

     <chunk>
       <format>\t</set></format>
     </chunk>
   </output>
</generic>
</PropertyList>

Analyzing the resulting binary packet format

A utility called generic-protocol-analyse can be found under FlightGear/utils/xmlgrep which can be used to analyze the resulting data packet for the binary protocol. The output would be something like:

bintest.xml
Generic binary output protocol packet description:

 pos | size |  type  | factor     | description
-----|------|--------|------------|------------------------
   0 |    4 |    int |            | indicated speed (kt)
   4 |    4 |  float |            | pitch att (deg)
   8 |    4 |  float |            | magnetic heading (deg)
  12 |    4 |    int |            | outside air temperarure (degF)
  16 |    1 |   bool |            | autocoord

total package size: 17 bytes

Generic Protocol

FlightGear has an inbuilt "generic" protocol to push and pull data. (todo)

To interface with FlightGear on a socket for example, the following steps need to be taken.

  1. Establish which "properties" you want to appear "on the wire"
  2. Create a my_protocol.xml file containing those properties
  3. Start flight gear on a socket using my_protocol.

For this simple example say were interested in heading and altitude, and we want to "listen" ie output to a socket at port 6789, udp and receiving 10 times a second in the format:

alt\thead\n 
// ie altitude - tab - heading - newline

The first step is establishing the nodes, in this example

/position/altitude-agl-ft  eg (22.4713923)
/orientation/heading-deg  eg (297.966325)

Next create a file my_protocol.xml. This needs to be located at

$FG_ROOT/Protocol/my_protocol.xml

The XML looks like this:

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

       <chunk>
          <node>/position/altitude-agl-ft</node>
          <name>altitude to go</name>
          <type>float</type>
          <format>%03.2f</format>
        </chunk>

       <chunk>
          <node>/orientation/heading-deg</node>
          <name>Heading</name>
          <type>float</type>
          <format>%03.3f</format>
        </chunk>

   </output>
 </generic>
</PropertyList>
  • The output tag indicates the protocol for output. The same "protocol" file can contain an "input" section, absent in this example (more later).
  • line_seperator - the end of line (todo ? is this \r\n??)
  • var_seperator - the delimiter for the properties, this could be "|", "###", any string.
  • The two chunk blocks contain our data. Note that these appear in the order presented within the xml file.
    • node - the node of data we want
    • name - it there for a reference, its not transmitted and note necessary (like a note)
    • type - the way this xml is to interpret the value. This is quite important tag. For example if its not there or a string, then "floats" go wild and end up being a string of 32 characters with two decimal places!
    • format - same syntax as printf
    • There's more that can be done {todo - link to a full blown example/reference}

We can now start FlightGear and listen with:

fgfs --generic=socket,out,10,localhost,6789,udp,my_protocol

[todo] - link here to the tutorial



External links