Autopilot configuration reference: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(36 intermediate revisions by 10 users not shown)
Line 1: Line 1:
{{Systems_Modeling_Disclaimer}}
[[File:FgPlot.jpg|400px|thumb|[[FGPlot]] can be used to plot the value properties while tuning an autopilot.]]
[[File:FgPlot.jpg|400px|thumb|[[FGPlot]] can be used to plot the value properties while tuning an autopilot.]]


Line 4: Line 6:
{{Autoflight Navigation}}
{{Autoflight Navigation}}


This page serves as a reference for the elements of [[FlightGear]] xml [[autopilot]] configuration files. It describes all elements available within the autopilot configuration file supported in the bleeding edge [[Git]] sources. Some of the elements may not be available in the current release version of FlightGear.
: ''For a guide on how to model an autopilot using these elements, see [[Howto:Design an autopilot]].''


The flightgear xml based autopilot system can run at FDM rate or at frame rate. Using a <autopilot> tag in your aircraft's -set.xml
The '''property rules''' used for '''autopilot configuration''' can also be used for other kinds of systems modeling. The controllers and filters allow for both simple and complex systems to be modeled. By using the output from one as the input to another one, very complex systems such as fly-by-wire systems with different control laws can be modeled.
adds the autopilot at fdm rate, using a <property-rule> runs the same config at frame rate.


Refer to [[Howto:Design an autopilot]] as a guide how to use these elements.  
This page serves as a reference for the elements of [[FlightGear]] XML [[autopilot]] and property rule configuration files. It describes all elements available within the autopilot configuration file supported in the bleeding edge [[Git]] sources. Some of the elements may not be available in the current release version of FlightGear.


For built-in runtime plotting of FlightGear properties (including FDM/Autopilot properties), check out [[FGPlot]] (available in FlightGear 2.11+).
For built-in runtime plotting of FlightGear properties (including FDM/Autopilot properties), check out [[FGPlot]] (available in FlightGear 2.11+).


== Structure Of a Configuration File ==
== Autopilot vs. property-rule configurations ==
Autopilot configurations live in a separate file, formatted using the well known XML syntax like so many other FlightGear files with a PropertyList node as a root element. A basic skeleton file looks like this:
The main difference between XML based autopilot and property-rule systems is the update rate:
<syntaxhighlight lang="xml">
 
  <?xml version="1.0" encoding="UTF-8"?>
* Autopilot configurations run at [[FDM]] rate
  <PropertyList>
* Property-rule configurations run at frame rate
  <params>
 
    <controls>
=== Performance considerations ===
      <aileron>controls/flight/aileron</aileron>
Using property-rule elements for things that does not have to run a FDM rate can improve the frame rate, in particular for complex systems and on weaker computers.  Depending on FlightGear settings and the hardware, the FDM rate is about 2–10 times higher than the frame rate.
      <rudder>controls/flight/rudder</rudder>
 
      <elevator>controls/flight/elevator</elevator>
It is possible to implement a system using both autopilot and property-rule based elements. They can communicate with each other using [[Property tree|properties]]The only disadvantage is that they will be split between an autopilot and a property-rule configuration file.
    </controls>
 
  </params>
For example would a fly-by-wire flight control system element augmenting an unstable aircraft need to run at FDM rate, while an element depending on the flap extension would work just as well at frame rate.
  <!-- Place your components here -->
  <!--
  <filter>
    <name>Myfilter</name>
    <input>/foo</input>
    <output>/bar</output>
  </filter>
  -->
</PropertyList>
</syntaxhighlight>


{{note|Using aliased property names is good style and makes the configuration file more readable. For complex autopilot systems spread over multiple autopilot configuration files, the params section may be included from an external file using <tt><nowiki><params include="my-params.xml"/></nowiki></tt> to avoid duplication of code.}}
== Adding a configuration to an aircraft ==
A configuration is added to an aircraft by adding the path to an XML configuration file to the <code>&lt;Aircraft&gt;-set.xml</code> file.


The location and the name of the configuration file is up to the developer. A descriptive name like 'autopilot.xml' might be a good choice. Most developers put these files into the Systems folder of the aircraft.
=== Adding an autopilot configuration ===
Autopilot configuration files are added to the aircraft by adding


== Adding an Autopilot Configuration to Aircraft ==
Autopilot configuration files are added to the aircraft by adding
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
   <autopilot>
   <autopilot n="100">
     <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
     <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
   </autopilot>
   </autopilot>
</syntaxhighlight>
</syntaxhighlight>


to the  
to the
 
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
  <sim>
  <sim>
   <systems>
   <systems>
     <!-- many other elements live here -->
     <!-- many other elements live here -->
     <autopilot>
     <autopilot n="100">
       <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
       <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
     </autopilot>
     </autopilot>
Line 60: Line 52:
</syntaxhighlight>
</syntaxhighlight>


node of your aircraft-set.xml file. Note, that more than one <autopilot> node may be present, each will create a new instance of the autopilot subsystem when running FlightGear. They run in the order of appearance under <systems>. For example, lateral and vertical autopilot modes could live in separate files, as could a yaw-damper system.
node of your <code>aircraft-set.xml</code> file. Note, that more than one <syntaxhighlight lang="xml" inline><autopilot></syntaxhighlight> node may be present, each will create a new instance of the autopilot subsystem when running FlightGear. They run in the order of appearance under <syntaxhighlight lang="xml" inline><systems></syntaxhighlight>. For example, lateral and vertical autopilot modes could live in separate files, as could a yaw-damper system.


== Adding a Property-rule Configuration to Aircraft ==
{{note|While the above seems to be the recommended standard, it has occasionally lead to trouble, not to index additional autopilot configurations. Anyway, it shouldn't hurt to do so.<br>
FG first loads generic configs, which get indexed atomatically as they appear. Then you override these generic configs with your own, which may lead to strange behaviour, if you for example overwrite the weather rules with an autopilot-helper configuration. Not only will you have no weather anymore, but also 2 systems that will most likely overwrite each others results all the time. Check the property-tree at /sim/systems/autopilot[*]
}}
 
=== Adding a property-rule configuration ===
Property-rules can also be used in which case they will run at frame rate. You can use these to process properties so their values can be used by other systems outside of the autopilot scope (for example to create smooth animations for switches that normally have discrete values)
Property-rules can also be used in which case they will run at frame rate. You can use these to process properties so their values can be used by other systems outside of the autopilot scope (for example to create smooth animations for switches that normally have discrete values)


To achieve this load your filters configuration by adding:
To achieve this load your filters configuration by adding:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
   <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
   <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
Line 72: Line 69:
   </property-rule>
   </property-rule>
</syntaxhighlight>
</syntaxhighlight>
(Do NOT use the filename "propertyrules.xml")


to the :
to the :
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<sim>
  <sim>
  <systems>
    <systems>
    <!-- many other elements live here -->
      <!-- many other elements live here -->
    <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
      <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
      <name>My property rule</name>  <!--  Optional name tag useful for debugging and other maintenance -->
        <name>My property rule</name>  <!--  Optional name tag useful for debugging and other maintenance -->
      <path>Systems/my-propertyrules.xml</path>  <!-- path can be relative to the current aircraft-set.xml location -->
        <path>Systems/my-propertyrules.xml</path>  <!-- path can be relative to the current aircraft-set.xml location -->
    </property-rule>
      </property-rule>
  </systems>
    </systems>
   </sim>
   </sim>
</syntaxhighlight>
</syntaxhighlight>
node of your aircraft-set.xml file. Note that you can add multiple <property-rule> elements, similar to the <autopilot> as described above.


== Available Elements ==
node of your <code>&lt;aircraft&gt;-set.xml</code> file. Note that you can add multiple <syntaxhighlight lang="xml" inline><property-rule></syntaxhighlight> elements, similar to the <syntaxhighlight lang="xml" inline><autopilot></syntaxhighlight> as described above.
 
{{tip|Configurations can be enabled and disabled through the boolean properties <code>/sim/systems/autopilot[''n'']/serviceable</code> and <code>/sim/systems/property-rule[''n'']/serviceable</code>, where''n'' is the index for a configuration}}
 
== Structure of a configuration file ==
Autopilot configurations live in a separate file, formatted using the well known XML syntax like so many other FlightGear files with a <syntaxhighlight lang="xml" inline><PropertyList></syntaxhighlight> node as a root element. A basic skeleton file looks like this:
 
<syntaxhighlight lang="xml">
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
  <params include="MyParams.xml"> <!-- Params can be included like this -->
    <controls>
      <aileron>controls/flight/aileron</aileron>
      <rudder>controls/flight/rudder</rudder>
      <elevator>controls/flight/elevator</elevator>
    </controls>
  </params>
 
  <!-- Place your components here -->
  <!--
  <filter>
    <name>Myfilter</name>
    <input>/foo</input>
    <output>/bar</output>
  </filter>
  <filter>
    <name>Myfilter</name>
    <input alias="/params/control/aileron"/>  Aliasing a property name
    <output>/bar</output>
  </filter>
  -->
</PropertyList>
</syntaxhighlight>
 
The location and the name of the configuration file is up to the developer. A descriptive name like <code>autopilot.xml</code> might be a good choice. Most developers put these files into the <code>Systems</code> folder of the aircraft.
 
{{tip|Using [[PropertyList XML files#Aliased properties|aliased property names]] is good style and makes the configuration file more readable.  The params section may be included from an external file to avoid duplication of code.
 
For complex systems, spread over multiple autopilot and/or property-rule configuration files, this can greatly aid debugging and maintenance.}}
 
{{tip|Commenting the configuration file to document the purpose elements and groups of elements and what they are intended to do can also aid debugging and maintenance.}}
 
== Available elements ==
All elements may contain the attributes "include" and "alias".  
All elements may contain the attributes "include" and "alias".  
The "include" property takes a file name as a parameter. This can be used to read the document tree of an external XML file into the node containing the "include" attribute. The included file must have a PropertyList node as the root node. All nodes under this PropertyList node will be added to the node containing the "include" attribute.
The "include" property takes a file name as a parameter. This can be used to read the document tree of an external XML file into the node containing the "include" attribute. The included file must have a PropertyList node as the root node. All nodes under this PropertyList node will be added to the node containing the "include" attribute.
The "alias" attribute refers to an element defined elsewhere in this XMl document. Alias references are in a path-style syntax, either as a relative or absolute path. Absolute paths start with a slash, like <foo alias="/params/bar/baz"/>. Use the colon to move through the document tree, similar to file system paths like <foo alias="../../bar/baz"/>.
The "alias" attribute refers to an element defined elsewhere in this XMl document. Alias references are in a path-style syntax, either as a relative or absolute path. Absolute paths start with a slash, like <syntaxhighlight lang="xml" inline><foo alias="/params/bar/baz"/></syntaxhighlight>. Use the colon to move through the document tree, similar to file system paths like <syntaxhighlight lang="xml" inline><foo alias="../../bar/baz"/></syntaxhighlight>.


Any top-level element can appear in an autopilot XML file, but only the following elements will be recognised and used:
Any top-level element can appear in an autopilot XML file, but only the following elements will be recognised and used:
* <pid-controller>
* <syntaxhighlight lang="xml" inline><pid-controller></syntaxhighlight>
* <pi-simple-controller>
* <syntaxhighlight lang="xml" inline><pi-simple-controller></syntaxhighlight>
* <filter>
* <syntaxhighlight lang="xml" inline><filter></syntaxhighlight>
* <predict-simple>
* <syntaxhighlight lang="xml" inline><predict-simple></syntaxhighlight>
* <logic>
* <syntaxhighlight lang="xml" inline><logic></syntaxhighlight>
* <flipflop>
* <syntaxhighlight lang="xml" inline><flipflop></syntaxhighlight>
* <syntaxhighlight lang="xml" inline><state-machine></syntaxhighlight>
 
== Common elements used by all elements ==
 
=== Name of filter and controller &lt;name&gt; ===
The <syntaxhighlight lang="xml" inline><name></syntaxhighlight> element is optional, but should be added to give the controller a distinct name. It is only used in debug output.


== Common Elements Used By All Elements ==
<syntaxhighlight lang="xml">
<name>NAV hold</name>
</syntaxhighlight>


=== Name ===
=== Feedback &lt;feedback-if-disabled&gt; ===
The <name> element is optional, but should be added to give the controller a distinct name. It is only used in debug output.
The <syntaxhighlight lang="xml" inline><feedback-if-disabled></syntaxhighlight> element advises the controller to feed back the output property value to the active input property if the condition defined in the <syntaxhighlight lang="xml" inline><enable></syntaxhighlight> tag evaluates to false. This is usually required for controllers like servo drivers behind a PID-controller to give that PID-controller a valid starting value when it becomes enabled. The absence of this element or anything but the word <syntaxhighlight lang="xml" inline>true</syntaxhighlight> within this element results in feedback disabled.
<name>NAV hold</name>


=== Feedback if disabled ===
<syntaxhighlight lang="xml">
The <feedback-if-disabled> element advises the controller to feed back the output property value to the active input property if the
<feedback-if-disabled>true</feedback-if-disabled>
condition defined in the <enable> tag evaluates to false. This is usually required for controllers like servo drivers behind a PID-controller to give that PID-controller a valid starting value when it becomes enabled. The absence of this element or anything but the word ''true'' within this element results in feedback disabled.
</syntaxhighlight>
<feedback-if-disabled>true</feedback-if-disabled>


=== Debug ===
=== Printing debug output &lt;debug&gt; ===
If the <debug> element is present and if it contains the word ''true'', the containing controller prints out some diagnostic information on the console for each processing loop.
If the <syntaxhighlight lang="xml" inline><debug></syntaxhighlight> element is present and if it contains the word <syntaxhighlight lang="xml" inline>true</syntaxhighlight>, the containing controller prints out some diagnostic information on the console for each processing loop.
<debug>true</debug>


=== Input and Reference ===
<syntaxhighlight lang="xml">
Each controller has two input "lines", denoted by the tags <input> and <reference>. The arithmetic difference of these two values is used by the respective controller to compute it's output. Unfortunately due to historical reasons, the sign of input and reference is not consistent for all controllers. While the pid-controller and the pi-simple-controller compute "reference-input", the filter controller computes "input-reference". Each element is optional with a default value of zero. These elements are made of so called '''Input Values''' described further down in this document.
<debug>true</debug>
</syntaxhighlight>
 
=== Input and reference properties or values &lt;input&gt; and &lt;reference&gt; ===
Each controller has two input "lines", denoted by the tags <syntaxhighlight lang="xml" inline><input></syntaxhighlight> and <syntaxhighlight lang="xml" inline><reference></syntaxhighlight>. The arithmetic difference of these two values is used by the respective controller to compute it's output. Unfortunately due to historical reasons, the sign of input and reference is not consistent for all controllers. While the pid-controller and the pi-simple-controller compute "reference-input", the filter controller computes "input-reference". Each element is optional with a default value of zero. These elements are made of so called ''input values'' described further down in this document.


Example for a simple differential amplifier, computing output = (input-reference)*2
Example for a simple differential amplifier, computing output = (input-reference)*2
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>gain</type>
  <type>gain</type>
  <gain>1.0</gain>
  <gain>2.0</gain>
  <input>/some/input</input>
  <input>/some/input</input>
  <reference>/some/output</reference>
  <reference>/some/output</reference>
  <output>/some/output</output>
  <output>/some/output</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Output ===
=== Output property &lt;output&gt; ===
The <outptu> element names the properties, the computed value should be written to. More than one <output> may be present, each named property will be assigned the computed value.
The <syntaxhighlight lang="xml" inline><output></syntaxhighlight> element names the properties, the computed value should be written to. More than one <syntaxhighlight lang="xml" inline><output></syntaxhighlight> may be present, each named property will be assigned the computed value.
<output>controls/flight/elevator</output>
 
<syntaxhighlight lang="xml">
<output>controls/flight/elevator</output>
</syntaxhighlight>
   
   
=== Enable ===
=== Enabling and disabling a filter &lt;enable&gt; ===
Controllers can be enabled or disabled using property values. This element <enable> may contain a <prop> and a <value> element. The controller is enabled, if the value of the named property equals the given value. This feature is considered deprecated and might go away in future releases. The preferred way of defining the enable-condition is by adding a <condition> element to the <enable> element. This <condition> follows the same syntactical rules as the one used in model animations and can model complex expression trees.
Controllers can be enabled or disabled using property values. This element <syntaxhighlight lang="xml" inline><enable></syntaxhighlight> may contain a <syntaxhighlight lang="xml" inline><prop></syntaxhighlight> and a <syntaxhighlight lang="xml" inline><value></syntaxhighlight> element. The controller is enabled, if the value of the named property equals the given value. This feature is considered deprecated and might go away in future releases. The preferred way of defining the enable-condition is by adding a <syntaxhighlight lang="xml" inline><condition></syntaxhighlight> element to the <syntaxhighlight lang="xml" inline><enable></syntaxhighlight> element. This <syntaxhighlight lang="xml" inline><condition></syntaxhighlight> follows the same syntactical rules as the one used in model animations and can model complex expression trees.
To enable a wing leveler only if the current bank angle does not exceed 30° of bank, use this condition
To enable a wing leveler only if the current bank angle does not exceed 30° of bank, use this condition
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<enable>
<enable>
  <condition>
  <condition>
    <less-than>
    <less-than>
      <property>orientation/bank-angle-deg</property>
      <property>orientation/bank-angle-deg</property>
      <value>30.0</value>
      <value>30.0</value>
    </less-than>
    </less-than>
    <greater-than>
    <greater-than>
      <property>orientation/bank-angle-deg</property>
      <property>orientation/bank-angle-deg</property>
      <value>-30.0</value>
      <value>-30.0</value>
    </greater-than>
    </greater-than>
  </condition>
  </condition>
</enable>
</enable>
</syntaxhighlight>
</syntaxhighlight>


=== Input Values ===
=== Input values ===
Input values for controllers may be specified in several notations. Values may be supplied as constants, from properties or by means of simple linear transformations. Conditions allow the selection of one of multiple input sources. The following text will use the <tt>reference</tt> element as an example but it may be substituted by any other input element like <tt>Kp</tt>, <tt>gain</tt> etc. Input values will be interpreted as double values.
Input values for controllers may be specified in several notations. Values may be supplied as constants, from properties or by means of simple linear transformations. Conditions allow the selection of one of multiple input sources. The following text will use the <syntaxhighlight lang="xml" inline><reference></syntaxhighlight> element as an example but it may be substituted by any other input element like <syntaxhighlight lang="xml" inline><Kp></syntaxhighlight>, <syntaxhighlight lang="xml" inline><gain></syntaxhighlight> etc. Input values will be interpreted as double values.


==== A constant value ====
==== A constant value &lt;value&gt; or &lt;reference&gt; ====
A constant value is defined by just adding the value as text to the input element:  
A constant value is defined by just adding the value as text to the input element:  
<reference>
 
  <value>3.5</value>
<syntaxhighlight lang="xml">
</reference>
<reference>
  <value>3.5</value>
</reference>
</syntaxhighlight>
 
The shortcut syntax is also valid:
The shortcut syntax is also valid:
<reference>3.5</reference>


If the text can be parsed by <tt>strtod()</tt> to a double value, it will be used as a constant value, otherwise it will be interpreted as a property value (see next paragraph)
<syntaxhighlight lang="xml">
<reference>3.5</reference>
</syntaxhighlight>
 
If the text can be parsed by <code>strtod()</code> to a double value, it will be used as a constant value, otherwise it will be interpreted as a property value (see next paragraph)


==== A property value ====
==== A property value ====
To evaluate the value of a property, place the name of the property into the text element:
To evaluate the value of a property, place the name of the property into the text element:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/my/property</property>
  <property>/my/property</property>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


The shortcut syntax is also valid:
The shortcut syntax is also valid:
<reference>/my/property</reference>
<syntaxhighlight lang="xml">
<reference>/my/property</reference>
</syntaxhighlight>


{{note|The shortcut syntax is only valid, if neither <property> nor <value> element exists.
{{note|The shortcut syntax is only valid, if neither <syntaxhighlight lang="xml" inline><property></syntaxhighlight> nor <syntaxhighlight lang="xml" inline><value></syntaxhighlight> element exists.
If both <property> '''and''' <value> element exist, the property will be initialized with the given value with scale and offset applied correctly.
If both <syntaxhighlight lang="xml" inline><property></syntaxhighlight> '''and''' <syntaxhighlight lang="xml" inline><value></syntaxhighlight> element exist, the property will be initialized with the given value with scale and offset applied correctly.
Properties don't have to exist, the will be created as needed.}}
Properties don't have to exist, the will be created as needed.}}
{{note|For backward compatibility, the notation <prop> instead of <property> is also valid but considered deprecated and might go away in future releases.}}


==== Linear transformation of the input value ====
{{note|For backward compatibility, the notation <syntaxhighlight lang="xml" inline><prop></syntaxhighlight> instead of <syntaxhighlight lang="xml" inline><property></syntaxhighlight> is also valid but considered deprecated and might go away in future releases.}}
 
==== Linear transformation of the input value &lt;offset&gt; ====
Input values may be scaled and shifted before they are processed by the controller using the formula <tt>y = value * scale + offset</tt>
Input values may be scaled and shifted before they are processed by the controller using the formula <tt>y = value * scale + offset</tt>
To use a celsius temperature property in a controller which expects the temperature in fahrenheit you might use
To use a Celsius temperature property in a controller which expects the temperature in Fahrenheit you might use
 
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/environment/temperature-degc</property>
  <property>/environment/temperature-degc</property>
  <scale>1.8</scale>
  <scale>1.8</scale>
  <offset>32</offset>
  <offset>32</offset>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


==== Periodical transformation of the input value ====
==== Periodical transformation of the input value &lt;period&gt; ====
Periodical (like angular) input values can be transformed to appear in the correct phase before they are processed by the controller by adding or substracting multiples of the period to the input value until the values is in the requested periods interval.
Periodical (like angular) input values can be transformed to appear in the correct phase before they are processed by the controller by adding or subtracting multiples of the period to the input value until the values is in the requested periods interval.
The following example converts the heading which comes in the range of [0..360] into the range of [-180..+180]. This will cause a heading of 270 to be processed as a value of -90.
The following example converts the heading which comes in the range of [0..360] into the range of [-180..+180]. This will cause a heading of 270 to be processed as a value of -90.
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/orientation/heading-deg</property>
  <property>/orientation/heading-deg</property>
  <period>
  <period>
    <min>-180.0</min>
    <min>-180.0</min>
    <max>180.0</max>
    <max>180.0</max>
  </period>
  </period>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


==== Input clamping ====
==== Input clamping &lt;min&gt; and &lt;max&gt; ====
To clamp the input to a minimum value, maximum value or both, the tags <tt><min></tt> and <tt><max></tt> can be used. Clamping will occur after the linear transformation has been applied. Note the difference of input clamping to output clamping. While input clamping is applied '''before''' the signal reaches the controller, output clamping will be applied to the output signal '''after''' it has been processed.
To clamp the input to a minimum value, maximum value or both, the tags <syntaxhighlight lang="xml" inline><min></syntaxhighlight> and <syntaxhighlight lang="xml" inline><max></syntaxhighlight> can be used. Clamping will occur after the linear transformation has been applied. Note the difference of input clamping to output clamping. While input clamping is applied '''before''' the signal reaches the controller, output clamping will be applied to the output signal '''after''' it has been processed.


The following code will keep the input to the controller in the range of 60 to 80 degrees Fahrenheit:
The following code will keep the input to the controller in the range of 60 to 80 degrees Fahrenheit:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/environment/temperature-degc</property>
  <property>/environment/temperature-degc</property>
  <scale>1.8</scale>
  <scale>1.8</scale>
  <offset>32</offset>
  <offset>32</offset>
  <min>60</min>
  <min>60</min>
  <max>80</max>
  <max>80</max>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


==== Absolute values ====
==== Absolute values &lt;abs&gt; ====
To use the absolute (unsigned) value of the input, add <tt><abs type="bool">true</abs></tt>.
To use the absolute (unsigned) value of the input, add <syntaxhighlight lang="xml" inline><abs type="bool">true</abs></syntaxhighlight>.
 
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/autopilot/internal/course-error-deg</property>
  <property>/autopilot/internal/course-error-deg</property>
  <abs type="bool">true</abs>
  <abs type="bool">true</abs>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


==== Recursive definition ====
==== Recursive definition ====
The elements <tt><scale></tt>, <tt><offset></tt>, <tt><min></tt> and <tt><max></tt> itself can be defined as input values. This code uses as reference the value of course-error-deg, scaled by two and an offset applied which is calculated as the product of the bank-angle-de and the property some/property which itself is limited within the range of -1.5 .. +1.5.
The elements <syntaxhighlight lang="xml" inline><scale></syntaxhighlight>, <syntaxhighlight lang="xml" inline><offset></syntaxhighlight>, <syntaxhighlight lang="xml" inline><min></syntaxhighlight> and <syntaxhighlight lang="xml" inline><max></syntaxhighlight> itself can be defined as input values. This code uses as reference the value of course-error-deg, scaled by two and an offset applied which is calculated as the product of the bank-angle-de and the property some/property which itself is limited within the range of -1.5 .. +1.5.
 
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <property>/autopilot/internal/course-error-deg</property>
  <property>/autopilot/internal/course-error-deg</property>
  <scale>2.0</scale>
  <scale>2.0</scale>
  <offset>
  <offset>
    <property>orientation/bank-angle-deg</property>
    <property>orientation/bank-angle-deg</property>
    <scale>
    <scale>
      <property>some/property
      <property>some/property</property>
      <min>-1.5</min>
      <min>-1.5</min>
      <max>1.5</max>
      <max>1.5</max>
    </scale>
    </scale>
  </offset>
  </offset>
</reference>
</reference>
</syntaxhighlight>
</syntaxhighlight>


==== Conditional input values ====
==== Conditional input values &lt;condition&gt; ====
The direct inputs of controller and filter elements support so called input value lists. This is useful, if the input should be connected to one of many separate inputs like autopilots connected to NAV1, NAV2 or the GPS. A standard <tt><condition></tt> element is allowed within an input value element. The input value list will be traversed until the first input value with a successful condition is found. The behavior is much like the switch statement in programming languages.
The direct inputs of controller and filter elements support so called input value lists. This is useful, if the input should be connected to one of many separate inputs like autopilots connected to NAV1, NAV2 or the GPS. A standard <syntaxhighlight lang="xml" inline><condition></syntaxhighlight> element is allowed within an input value element. The input value list will be traversed until the first input value with a successful condition is found. The behavior is much like the switch statement in programming languages.
 
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<reference>
<reference>
  <condition>
  <condition>
    <property>/autopilot/coupled-to-gps</property>
    <property>/autopilot/coupled-to-gps</property>
  </condition>
  </condition>
  <property>instrumentation/gps/desired-track-deg</property>
  <property>instrumentation/gps/desired-track-deg</property>
</reference>
</reference>
<reference>
<reference>
  <condition>
  <condition>
    <property>/autopilot/coupled-to-nav2</property>
    <property>/autopilot/coupled-to-nav2</property>
  </condition>
  </condition>
  <property>instrumentation/nav[1]/radials/selected-deg</property>
  <property>instrumentation/nav[1]/radials/selected-deg</property>
</reference>
</reference>
<reference>instrumentation/nav[0]/radials/selected-deg</reference>
<reference>instrumentation/nav[0]/radials/selected-deg</reference>
</syntaxhighlight>
</syntaxhighlight>


Note the unconditional last <tt><reference<></tt> element which acts as an "if all others fail, use NAV1" anchor. If no input value return with a successful condition, the input value is undefined.<br />
Note the unconditional last <syntaxhighlight lang="xml" inline><reference></syntaxhighlight> element which acts as an "if all others fail, use NAV1" anchor. If no input value return with a successful condition, the input value is undefined.
The <tt><scale></tt>, <tt><offset></tt>, <tt><min></tt> and <tt><max></tt> elements of input values itself currently don't support input value lists.


==== Expressions ====
The <syntaxhighlight lang="xml" inline><scale></syntaxhighlight>, <syntaxhighlight lang="xml" inline><offset></syntaxhighlight>, <syntaxhighlight lang="xml" inline><min></syntaxhighlight> and <syntaxhighlight lang="xml" inline><max></syntaxhighlight> elements of input values itself currently don't support input value lists.
Complex math or lookup tables may be represented using the [[Expression]] syntax. The expression has to be enclosed in <expression> tag.


=== Output Values ===
==== Expressions &lt;expression&gt; ====
After processing of a component, the resulting value passes a transformation stage where it can be clipped or normalized into a given period. Periodic values such as angular properties may be normalized into a given period by adding a <period> element, defining the lower and upper bounds of the period. Additionally, a maximun and a minimum value may be given which will guarantee that the output value will ever exceed a defined value.  
Complex math or lookup tables may be represented using the [[expression]] syntax. The expression has to be enclosed in <syntaxhighlight lang="xml" inline><expression></syntaxhighlight> tag.
 
=== Output values ===
After processing of a component, the resulting value passes a transformation stage where it can be clipped or normalized into a given period. Periodic values such as angular properties may be normalized into a given period by adding a <syntaxhighlight lang="xml" inline><period></syntaxhighlight> element, defining the lower and upper bounds of the period. Additionally, a maximun and a minimum value may be given which will guarantee that the output value will ever exceed a defined value.  


{{note|Both periodical normalization and clipping may be defined. If both are given, the value will be normalized first and the clipping will be applied to the normalized value.}}
{{note|Both periodical normalization and clipping may be defined. If both are given, the value will be normalized first and the clipping will be applied to the normalized value.}}


The following example shifts the computed value into the interval of [-180..180] thereafter being limited into the interval of [-30..30]. The following table contains some computed values and the resulting written value:
The following example shifts the computed value into the interval of [-180..180] thereafter being limited into the interval of [-30..30]. The following table contains some computed values and the resulting written value:
{| class="prettytable"
{| class="prettytable"
!computed
! computed !! written
!written
|-
|-
|-
| -350
|     -350 |10
|10
|-
|-
| -270
|     -270 |30
|30
|-
|-
| -90
|     -90 || -30
| -30
|-
|-
| -29
|     -29 || -29
| -29
|-
|-
|29
|       29 |29
|29
|-
|-
|90
|       90 |30
|30
|-
|-
|350
|     350 || -10
| -10
|}
|}
<syntaxhighlight lang="xml">
<output>/some/property</output>
<period>
  <min>-180</min>
  <max>180</max>
</period>
<min>-30</min>
<max>30</max>
</syntaxhighlight>
This example shows how to use a table to vary an output with height. At sea level, the output is 0.045, at 22400 the output is 0.1196, and at 56000 ft the output is 0.7
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<output>/some/property</output>
<filter>
<period>
  <name>GAy</name>
  <min>-180</min>
  <debug>false</debug>
  <max>180</max>
  <type>gain</type>
</period>
  <gain>1.0</gain>
<min>-30</min>
  <input>
<max>30</max>
    <expression>
      <table>
        <property>/instrumentation/altimeter/indicated-altitude-ft</property>
        <entry><ind>0.0</ind><dep>0.045</dep></entry>
        <entry><ind>22400</ind><dep>0.1196</dep></entry>
        <entry><ind>56000</ind><dep>0.7</dep></entry>
      </table>
    </expression>
  </input>
  <output>
    <property>/autopilot/gain/GAy</property>
  </output>
</filter>
</syntaxhighlight>
</syntaxhighlight>


== logic ==
== Logic controller &lt;logic&gt; ==
The logic controller provides a simple way of creating property values from the result of the condition expression in the <input> element. The condition expression is evaluated once per iteration and the result is written as a boolean value to the named output property or properties. An optional <inverted> element inverts the logic. The default is "not inverted".
The logic controller provides a simple way of creating property values from the result of the condition expression in the <syntaxhighlight lang="xml" inline><input></syntaxhighlight> element. The condition expression is evaluated once per iteration and the result is written as a boolean value to the named output property or properties. An optional <syntaxhighlight lang="xml" inline><inverted></syntaxhighlight> element inverts the logic. The default is "not inverted".


Example: output = not( ( a is true ) or ( ( b greater than c ) and ( d is true ) )
Example: output = not( ( a is true ) or ( ( b greater than c ) and ( d is true ) )
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<logic>
<logic>
  <inverted>true</inverted>
  <inverted>true</inverted>
  <input>
  <input>
    <property>a</property>
    <property>a</property>
    <or>
    <or>
      <greater-than>
      <greater-than>
        <property>b</property>
        <property>b</property>
        <property>c</property>
        <property>c</property>
      <greater-than>
      </greater-than>
      <property>d</property>
      <property>d</property>
    </or>
    </or>
  </input>
  </input>
  <output>output</output>
  <output>output</output>
</logic>
</logic>
</syntaxhighlight>
</syntaxhighlight>


== Flip Flop ==
== Flip flop logic &lt;flipflop&gt; ==
A flip flop is a controller that has two stable states so it can be used as a one bit memory. Four types of flip flops are implemented: '''RS''', '''JK''', '''D''' and '''T'''. All use positive logic and operate on the raising edge of the clock signal if a clock is used.
A flip flop is a controller that has two stable states so it can be used as a one bit memory. Four types of flip flops are implemented: '''RS''', '''JK''', '''D''' and '''T'''. All use positive logic and operate on the raising edge of the clock signal if a clock is used.
All input lines, including the clock line, are encoded as condition constructs.
All input lines, including the clock line, are encoded as condition constructs.
If negative logic for the input line is required, wrap the condition into a <not> tag to invert the logic.
If negative logic for the input line is required, wrap the condition into a <syntaxhighlight lang="xml" inline><not></syntaxhighlight> tag to invert the logic.


=== RS Flip Flop ===
{{note|The type, for example '''RS''', is case sensitive.}}
This flip flop sets its output according to the set (S) or reset (R) input lines. If the set line is set, the output gets set. If the reset line is set, the output gets reset. If no line is set, the output stays unchanged. For the special case where set and reset lines are both set, two types of RS flip flops exist: for the RS flip flop (<type>RS</type>), the reset line is dominant and the output is reset. Alternatively, a SR flip flop (<type>SR</type>) has a dominant set line and the output gets set if set and reset line are set.
{{note|Using <syntaxhighlight lang="xml" inline><condition></syntaxhighlight> tags will break the logic.}}
 
=== RS flip flop &lt;RS&gt; ===
This flip flop sets its output according to the set (S) or reset (R) input lines. If the set line is set, the output gets set. If the reset line is set, the output gets reset. If no line is set, the output stays unchanged. For the special case where set and reset lines are both set, two types of RS flip flops exist: for the RS flip flop (<syntaxhighlight lang="xml" inline><type>RS</type></syntaxhighlight>), the reset line is dominant and the output is reset. Alternatively, a SR flip flop (<syntaxhighlight lang="xml" inline><type>SR</type></syntaxhighlight>) has a dominant set line and the output gets set if set and reset line are set.


Example: simple RS flip flop
Example: simple RS flip flop
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<flipflop>
<flipflop>
  <type>RS</type> <!-- or SR -->
  <type>RS</type> <!-- or SR -->
  <S>
  <S>
    <property>/myflipflop/set</property>
    <property>/myflipflop/set</property>
  </S>
  </S>
  <R>
  <R>
    <property>/myflipflop/reset</property>
    <property>/myflipflop/reset</property>
  </R>
  </R>
  <output>/myflipflop/output</output>
  <output>/myflipflop/output</output>
</flipflop>
</flipflop>
</syntaxhighlight>
</syntaxhighlight>


=== JK Flip Flop ===
=== JK flip flop &lt;JK&gt; ===
The JK flip flop is an extension of the RS flip flop. In addition to the set and reset lines of the RS flip flop it uses J, K and a clock input.
The JK flip flop is an extension of the RS flip flop. In addition to the set and reset lines of the RS flip flop it uses J, K and a clock input.
The J line serves as a clock dependent set input while the K line does the reset job. Optionally, a clock input may be provided. State changes do not occour immediately, but on the next raising edge of the clock signal. The state of J=K=true causes the output to toggle it's current state on the next raising edge of the clock signal.
The J line serves as a clock dependent set input while the K line does the reset job. Optionally, a clock input may be provided. State changes do not occur immediately, but on the next raising edge of the clock signal. The state of J=K=true causes the output to toggle it's current state on the next raising edge of the clock signal.
If no clock signal is provided, the frame rate serves as the clock input.
If no clock signal is provided, the frame rate serves as the clock input.


Example: simple JK flip flop with negative edge clock
Example: simple JK flip flop with negative edge clock
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<flipflop>
<flipflop>
  <type>JK</type>
  <type>JK</type>
  <J>
  <J>
    <property>/myflipflop/set</property>
    <property>/myflipflop/set</property>
  </J>
  </J>
  <K>
  <K>
    <property>/myflipflop/reset</property>
    <property>/myflipflop/reset</property>
  </K>
  </K>
  <clock>
  <clock>
    <not>
    <not>
      <property>/myflipflop/clock</property>
      <property>/myflipflop/clock</property>
    </not>
    </not>
  </clock>
  </clock>
  <output>/myflipflop/output</output>
  <output>/myflipflop/output</output>
</flipflop>
</flipflop>
</syntaxhighlight>
</syntaxhighlight>


=== D Flip Flop ===
=== D flip flop &lt;D&gt; ===
The D flip flop transfers the state of the input signal '''D''' to the output line at the next raising edge of the clock signal, which is mandatory for this flip flop.
The D flip flop transfers the state of the input signal '''D''' to the output line at the next raising edge of the clock signal, which is mandatory for this flip flop.


Example: simple D flip flop with inverted output
Example: simple D flip flop with inverted output
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<flipflop>
<flipflop>
  <type>D</type>
  <type>D</type>
  <D>
  <D>
    <property>/myflipflop/data</property>
    <property>/myflipflop/data</property>
  </D>
  </D>
  <clock>
  <clock>
    <property>/myflipflop/clock</property>
    <property>/myflipflop/clock</property>
  </clock>
  </clock>
  <output>/myflipflop/output</output>
  <output>/myflipflop/output</output>
  <inverted type="bool">true</inverted>
  <inverted type="bool">true</inverted>
</flipflop>
</flipflop>
</syntaxhighlight>
</syntaxhighlight>


=== T Flip Flop ===
=== T flip flop &lt;T&gt; ===
The T flip flop toggles the state of the output signal at the next raising edge of the clock signal, which is mandatory for this flip flop.
The T flip flop toggles the state of the output signal at the next raising edge of the clock signal, which is mandatory for this flip flop.


Example: simple T flip flop
Example: simple T flip flop
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<flipflop>
<flipflop>
  <type>T</type>
  <type>T</type>
  <clock>
  <clock>
    <property>/myflipflop/clock</property>
    <property>/myflipflop/clock</property>
  </clock>
  </clock>
  <output>/myflipflop/output</output>
  <output>/myflipflop/output</output>
</flipflop>
</flipflop>
</syntaxhighlight>
</syntaxhighlight>


=== Monostable ===
=== Monostable flip flop &lt;monostable&gt; ===
A monostable flip flop has only one stable state which will be reentered after a well defined time. The stable state in current implementation is the output set 'false' or 0. The Monostable is an extension of the JK flip flop. Additionally to the input values defined there, an InputValue for the definition of the pulse time is mandatory.  
A monostable flip flop has only one stable state which will be reentered after a well defined time. The stable state in current implementation is the output set 'false' or 0. The Monostable is an extension of the JK flip flop. Additionally to the input values defined there, an InputValue for the definition of the pulse time is mandatory.  


The moment the time for the astable state starts counting depends on the input used to set the output. If the output is set from the SET input of the RS flipflop, the output is kept true for the defined time after the SET input enters it's false state. The total time the output is true equals the time, the SET input is true plus the time defined in the <time> element.
The moment the time for the astable state starts counting depends on the input used to set the output. If the output is set from the SET input of the RS flipflop, the output is kept true for the defined time ''after'' the SET input enters it's false state. The total time the output is true equals the time, the SET input is true plus the time defined in the <time> element.
If the output is set from the J and clock inputs of the JK flipflop, the timer starts on the raising edge of the clock input. The output signal will be true for exactly the time defined in the <time> element.  
If the output is set from the J and clock inputs of the JK flipflop, the timer starts on the raising edge of the clock input. The output signal will be true for exactly the time defined in the <syntaxhighlight lang="xml" inline><time></syntaxhighlight> element.  


{{note|The optional <R> and <K> inputs may be used to reset the output before the internal timer expired. This will also reset the timer to zero, so no additional event will be triggered after the defined timer interval.}}
{{note|The optional <syntaxhighlight lang="xml" inline><R></syntaxhighlight> and <syntaxhighlight lang="xml" inline><K></syntaxhighlight> inputs may be used to reset the output before the internal timer expired. This will also reset the timer to zero, so no additional event will be triggered after the defined timer interval.}}


<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<flipflop>
<flipflop>
  <name>Test mf</name>
  <name>Test mf</name>
  <type>monostable</type>
  <type>monostable</type>
  <time>
  <time>
    <property>/myflipflop/pulsetime-sec</property>
    <property>/myflipflop/pulsetime-sec</property>
    <value>10</value>
    <value>10</value>
  </time>
  </time>
  <S><property>/myflipflop/s</property></S>
  <S><property>/myflipflop/s</property></S>
  <J><property>/myflipflop/j</property></J>
  <J><property>/myflipflop/j</property></J>
  <clock><property>/myflipflop/clock</property></clock>
  <clock><property>/myflipflop/clock</property></clock>
  <output>/myflipflop/output</output>
  <output>/myflipflop/output</output>
  </flipflop>
</flipflop>
</syntaxhighlight>
</syntaxhighlight>


== filter ==
The following example shows how a monostable can be used to enable a certain property (/myflipflop/output) if another property (/myflipflop/s) is true for at least the specified amount of time:


=== Pure Gain <gain> ===
<syntaxhighlight lang="xml">
A gain filter multiplies the <input> value by a given factor or gain <gain> and returns the output to <output>. More than one <gain> element formatted as in [[Autopilot Configuration Reference#Input Values|Input Values]] may be present.  Within a <condition> evaluating as true the first <gain> will define the used gain.
<flipflop>
  <name>Test mf</name>
  <type>monostable</type>
  <inverted type="bool">true</inverted>
  <S>
    <not>
      <property>/myflipflop/s</property>
    </not>
  </S>
  <time>
    <value>10.0</value>
  </time>
  <output>
    <property>/myflipflop/output</property>
  </output>
</flipflop>
</syntaxhighlight>
 
In this example the monostable is inverted, which means the stable state is true instead of false. The key idea here is to keep the monostable in its unstable state (false) by keeping the set line true, which is the case when /myflipflop/s is false. Then, when /myflipflop/s becomes true the set line becomes false, which causes the timer to start. When the timer expires (in this case 10 seconds) the monostable will enter its stable state (true). At any time when the set line becomes true (when /myflipflop/s becomes false) the monostable will immediately enter its unstable state (false) again, resulting in /myflipflop/output to become false immediately.
 
== Filters &lt;filter&gt; ==
 
=== Pure gain filter &lt;gain&gt; ===
A gain filter multiplies the <syntaxhighlight lang="xml" inline><input></syntaxhighlight> value by a given factor or gain <syntaxhighlight lang="xml" inline><gain></syntaxhighlight> and returns the output to <syntaxhighlight lang="xml" inline><output></syntaxhighlight>. More than one <syntaxhighlight lang="xml" inline><gain></syntaxhighlight> element formatted as in [[Autopilot Configuration Reference#Input Values|Input Values]] may be present.  Within a <syntaxhighlight lang="xml" inline><condition></syntaxhighlight> evaluating as true the first <syntaxhighlight lang="xml" inline><gain></syntaxhighlight> will define the used gain.


<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>gain</type>
  <type>gain</type>
  <gain>6.28</gain>
  <gain>6.28</gain>
  <input>radius</input>
  <input>radius</input>
  <output>circumfence</output>
  <output>circumfence</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== First Order Low Pass Filter <exponential> ===
=== First order low pass filter &lt;exponential&gt; ===
The exponential filter is a typical [http://en.wikipedia.org/wiki/Low-pass_filter low pass filter]. The magic euler number and the associated mathematical funtion exp() plays a major role here. As the name implies, lower frequencies can pass this filter while higher frequencies are cut. The frequency where only half of the input signal reaches the output is called cutoff frequency. This cutoff frequency is defined by the parameter <filter-time> and resolves as cutoff-frequency = 1/(2*pi*cutoff-frequency).
The exponential filter is a typical [http://en.wikipedia.org/wiki/Low-pass_filter low pass filter]. The magic Euler number and the associated mathematical function exp() plays a major role here. As the name implies, lower frequencies can pass this filter while higher frequencies are cut. The frequency where only half of the input signal reaches the output is called cutoff frequency. This cutoff frequency is defined by the parameter <syntaxhighlight lang="xml" inline><filter-time></syntaxhighlight> and resolves as cutoff-frequency = 1/(2*pi*cutoff-frequency).


Example: a 1Hz first order low pass filter  
Example: a 1Hz first order low pass filter  


<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>exponential</type>
  <type>exponential</type>
  <filter-time>0.16</filter-time>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <input>/some/input</input>
  <output>/some/output/</output>
  <output>/some/output/</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Second Order Low Pass Filter <double-exponential> ===
 
 
=== Second order low pass filter &lt;double-exponential&gt; ===
The double exponential filter is a low pass filter like the exponential filter with a steeper slope of the filter diagram. It acts basically like two chained exponential filters and it is some times called second order filter.  
The double exponential filter is a low pass filter like the exponential filter with a steeper slope of the filter diagram. It acts basically like two chained exponential filters and it is some times called second order filter.  


The configuration is the same for exponential and double-exponential filters, just the type entry differs.
The configuration is the same for exponential and double-exponential filters, just the type entry differs.
<syntaxhighlight lang="xml">
<filter>
  <type>double-exponential</type>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <output>/some/output/<output>
</filter>
</syntaxhighlight>
=== First order high pass filter &lt;high-pass&gt; ===
The high pass filter is a typical [http://en.wikipedia.org/wiki/High-pass_filter high pass filter]. The magic euler number and the associated mathematical funtion exp() plays a major role here. As the name implies, higher frequencies can pass this filter while lower frequencies are cut. The frequency where only half of the input signal reaches the output is called cutoff frequency. This cutoff frequency is defined by the parameter <syntaxhighlight lang="xml" inline><filter-time></syntaxhighlight> and resolves as cutoff-frequency = 1/(2*pi*cutoff-frequency). It is commonly known as a wash-out filter or a 1st order lead filter
Example: a 1Hz first order high pass filter
<syntaxhighlight lang="xml">
<filter>
  <type>high-pass</type>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <output>/some/output/</output>
</filter>
</syntaxhighlight>
=== Lead-Lag filter &lt;lead-lag&gt; ===
The lead-lag filter  is a typical [https://en.wikipedia.org/wiki/Lead%E2%80%93lag_compensator] lead lag filter. As the name implies it is a combination of a lead (high-pass) filter and a lag (low-pass) filter.
Example: a lead lag filter k(s+a)/s+b).
The gain is k, filter-time-a is a, and filter-time-b is b.
In an autopilot is is often used to sharpen up the response to an input.
<syntaxhighlight lang="xml">
<filter>
  <name>loc-deg leadlag</name>
  <debug>false</debug>
  <type>lead-lag</type>
  <gain>5</gain>
  <filter-time-a>5.0</filter-time-a>
  <filter-time-b>1.0</filter-time-b>
  <input>
    <property>/autopilot/internal/loc-deg</property>
  </input>
  <output>
    <property>/autopilot/internal/loc-deg-leadlag</property>
  </output>
</filter>
</syntaxhighlight>
=== Integrator filter &lt;integrator&gt; ===
The integrator filter provides integration with time.
Example: an integrator filter k(1/s).
In this example, the normal input (<syntaxhighlight lang="xml" inline><property>/autopilot/internal/p-deg_sec</property></syntaxhighlight>)is disconnected and replaved by (output x 10) input when relay Rb is closed. This has the effect of rapidly ramping the integrator output to zero.
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>double-exponential</type>
  <name>synthetic bank from roll rate</name>
  <filter-time>0.16</filter-time>
  <debug>false</debug>
  <input>/some/input</input>
  <type>integrator</type>
  <output>/some/output/<output>
  <gain>1.0</gain>
</filter>
  <input>
    <condition>
      <property>/autopilot/internal/Rb</property>
    </condition>
    <property>/autopilot/internal/p-deg_sec</property>
  </input>
  <input> <!-- zero integrator when Rb is not set -->
    <expression>
      <product>
        <value>-10.0</value>
        <property>/autopilot/internal/phi-deg_synth</property>
      </product>
    </expression>
  </input>
  <output>
    <property>/autopilot/internal/phi-deg_synth</property>
  </output>
  <u_min>-180</u_min>
  <u_max>180</u_max>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Moving Average Filter <moving-average> ===
=== Moving average filter &lt;moving-average&gt; ===
Calculates average of specified number of values.
Calculates average of specified number of values.


Currently the average length can only be given as number of samples and not time.
Currently the average length can only be given as number of samples and not time.
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
   <type>moving-average</type>
   <type>moving-average</type>
   <samples>120</samples>
   <samples>120</samples>
   <input>/some/input</input>
   <input>/some/input</input>
   <output>/some/output</output>
   <output>/some/output</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Rate Limit Filter <noise-spike> ===
=== Rate limit filter &lt;noise-spike&gt; ===
A better name for a noise spike filter would probably have been "rate limit filter". This is exactly what it does: limit the rate of change of the output value. The relevant configuration element is <max-rate-of-change> setting the maximum rate of change of the output property per second.
A better name for a noise spike filter would probably have been "rate limit filter". This is exactly what it does: limit the rate of change of the output value. The relevant configuration element is <syntaxhighlight lang="xml" inline><max-rate-of-change></syntaxhighlight> setting the maximum rate of change of the output property per second.


Example: A transition from 0 to 4 at the input property results in a linear increase of the output property over 8 seconds from 0 to 4 at a rate of 0.5/sec.
Example: A transition from 0 to 4 at the input property results in a linear increase of the output property over 8 seconds from 0 to 4 at a rate of 0.5/sec.
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>noise-spike</type>
  <type>noise-spike</type>
  <max-rate-of-change>0.5</max-rate-of-change>
  <max-rate-of-change>0.5</max-rate-of-change>
  <input>/some/input</input>
  <input>/some/input</input>
  <output>/some/output</output>
  <output>/some/output</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Reciprocal Filter <reciprocal> ===
=== Reciprocal filter &lt;reciprocal&gt; ===
Compute the reciprocal (1/x) value of the input property. If x is zero, no computation is performed. The optional <gain> element may be used to scale the value. Output computes as gain divided by input.
Compute the reciprocal (1/x) value of the input property. If x is zero, no computation is performed. The optional <syntaxhighlight lang="xml" inline><gain></syntaxhighlight> element may be used to scale the value. Output computes as gain divided by input.


Example: compute the flight time per pound of burned fuel from the fuel flow
Example: compute the flight time per pound of burned fuel from the fuel flow
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
  <type>reciprocal</type>
  <type>reciprocal</type>
  <gain>1.0</gain>
  <gain>1.0</gain>
  <input>/engines/engine[0]/fuel-flow-pph</input>
  <input>/engines/engine[0]/fuel-flow-pph</input>
  <output>/engines/engine[0]/fuel-flow-hpp</output>
  <output>/engines/engine[0]/fuel-flow-hpp</output>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


=== Derivative Filter <derivative> ===
=== Derivative filter &lt;derivative&gt; ===
Compute first time derivative of the input property, that is change per unit of time. Time is measured in seconds. A <filter-time> acts as gain and must be given because it has default 0.
Compute first time derivative of the input property, that is change per unit of time. Time is measured in seconds. A <syntaxhighlight lang="xml" inline><filter-time></syntaxhighlight> acts as gain and must be given because it has default 0.


Example: compute derivative of static port pressure
Example: compute derivative of static port pressure
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<filter>
<filter>
   <type>derivative</type>
   <type>derivative</type>
   <input>systems/static[0]/pressure-inhg</input>
   <input>systems/static[0]/pressure-inhg</input>
   <output>autopilot/internal/pressure-rate</output>
   <output>autopilot/internal/pressure-rate</output>
   <filter-time>1.0</filter-time>
   <filter-time>1.0</filter-time>
</filter>
</filter>
</syntaxhighlight>
</syntaxhighlight>


== PID Controller <pid-controller> ==
== PID controller &lt;pid-controller&gt; ==
The [http://en.wikipedia.org/wiki/PID_controller PID controller] is the swiss army knife of automation and this implementation is suitable for most situations. It has a builtin anti-windup logic, and usage of <max> and <min> elements for clamping the output is mandatory. The most important thing to know is that this controller 'does not' compute absolute output values but an offset from the current value of the output property. This can lead to unexpected behavior if the current value of the output property is unknown when the controller is enabled. This behavior is different to that of the pi-simple-controller.
The [http://en.wikipedia.org/wiki/PID_controller PID controller] is the swiss army knife of automation and this implementation is suitable for most situations. It has a builtin anti-windup logic, and usage of <syntaxhighlight lang="xml" inline><max></syntaxhighlight> and <syntaxhighlight lang="xml" inline><min></syntaxhighlight> elements for clamping the output is mandatory. The most important thing to know is that this controller 'does not' compute absolute output values but an offset from the current value of the output property. This can lead to unexpected behavior if the current value of the output property is unknown when the controller is enabled. This behavior is different to that of the pi-simple-controller.
The xml element creating a pid controller is <tt><pid-controller></tt>.
 
The xml element creating a pid controller is <syntaxhighlight lang="xml" inline><pid-controller></syntaxhighlight>.


Legal elements are:
Legal elements are:


{| class="prettytable"
{| class="prettytable"
!Kp
! <syntaxhighlight lang="xml" inline><Kp></syntaxhighlight>
|the overall gain for the proportional, integral and derivative part
| The overall gain for the proportional, integral and derivative part
|-
|-
!Ti
! <syntaxhighlight lang="xml" inline><Ti></syntaxhighlight>
|integrator time
| Integrator time
|-
|-
!Td
! <syntaxhighlight lang="xml" inline><Td></syntaxhighlight>
|derivator time
| Derivator time
|-
|-
!Ts
! <syntaxhighlight lang="xml" inline><Ts></syntaxhighlight>
|sampling interval (default: sample at frame rate)
| Sampling interval (default: sample at frame rate)
|-
|-
!alpha
! <syntaxhighlight lang="xml" inline><alpha></syntaxhighlight>
|scaling factor for Td (defaults to 0.1)
| Scaling factor for Td (defaults to 0.1)
|-
|-
!beta
! <syntaxhighlight lang="xml" inline><beta></syntaxhighlight>
|reference weighing factor for the proportional component (defaults to 1.0)
| Reference weighing factor for the proportional component (defaults to 1.0)
|-
|-
!gamma
! <syntaxhighlight lang="xml" inline><gamma></syntaxhighlight>
|reference weighing factor for the derivate component (defaults to 0.0)
| Reference weighing factor for the derivate component (defaults to 0.0)
|}
|}


== PI Controller <pi-simple-controller> ==
== PI controller &lt;pi-simple-controller&gt; ==
This controller implements a PI controller. Other than the PID controller, it computes absolute output values, regardless of the value of the output property. It can by configured as an I-only, P-only or PI-controller. It has anti windup logic if <min> and <max> elements are present.
This controller implements a PI controller. Other than the PID controller, it computes absolute output values, regardless of the value of the output property. It can by configured as an I-only, P-only or PI-controller. It has anti windup logic if <syntaxhighlight lang="xml" inline><min></syntaxhighlight> and <syntaxhighlight lang="xml" inline><max></syntaxhighlight> elements are present.
The xml element creating a PI controller is <tt><pi-simple-controller></tt>
The xml element creating a PI controller is <syntaxhighlight lang="xml" inline><pi-simple-controller></syntaxhighlight>
Legal elements are:
Legal elements are:


{| class="prettytable"
{| class="prettytable"
!Kp
! <syntaxhighlight lang="xml" inline><Kp></syntaxhighlight>
|gain of the proportional component
| Gain of the proportional component
|-
|-
!Ki
! <syntaxhighlight lang="xml" inline><Ki></syntaxhighlight>
|gain of the integrator component
| Gain of the integrator component
|}
|}


== Predictor <predict-simple> ==
== Predictor &lt;predict-simple&gt; ==
Estimates the future value for a given property based on its current (or averaged) rate of change.
Estimates the future value for a given property based on its current (or averaged) rate of change.


Line 573: Line 779:


{| class="prettytable"
{| class="prettytable"
!seconds
! <syntaxhighlight lang="xml" inline><seconds></syntaxhighlight>
|the time to be estimated ahead
| The time to be estimated ahead
|-
|-
!filter-gain
! <syntaxhighlight lang="xml" inline><filter-gain></syntaxhighlight>
|Smoothing factor (0.0-1.0, 1.0=no smoothing)
| Smoothing factor (0.0-1.0, 1.0=no smoothing)
|}
|}


Example: compute estimated speed 5 seconds ahead
Example: compute estimated speed 5 seconds ahead
<syntaxhighlight lang="xml">
<predict-simple>
  <name>predicted air speed 5 seconds ahead</name>
  <debug>false</debug>
  <input>velocities/airspeed-kt</input>
  <output>autopilot/internal/airspeed-5-sec-ahead</output>
  <seconds>5.0</seconds>
  <filter-gain>0.1</filter-gain>
</predict-simple>
</syntaxhighlight>
== State Machine &lt;state-machine&gt; ==
For a description of what a state machine can do, look here: [http://en.wikipedia.org/wiki/Finite-state_machine].
{{note|Current behaviour with enter, exit and update tags differs from this documentation. Refer to the developer mailing list [https://sourceforge.net/p/flightgear/mailman/message/35557652/] before implementing bindings in state machines.}}
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<predict-simple>
<state-machine>
  <name>predicted air speed 5 seconds ahead</name>
  <branch>/my-statemachine</branch>
  <debug>false</debug>
  <state>
  <input>velocities/airspeed-kt</input>
    <name>init</name>
  <output>autopilot/internal/airspeed-5-sec-ahead</output>
    <enter>
  <seconds>5.0</seconds>
      <binding></binding>
  <filter-gain>0.1</filter-gain>
      <binding></binding>
</predict-simple>
    </enter>
    <exit>
      <binding></binding>
    </exit>
    <update>
      <binding></binding>
    </update>
  </state>
  <state>
    <name>finished</name>
    <enter>Zero to many bindings, fired upon state enter</enter>
    <exit>Zero to many bindings, fired upon state exit</exit>
    <update>Zero to many bindings, fired upon every state change</update>
  </state>
  <transition>
    <name>ready</name>
    <source>init</source>
    <target>finished</target>
    <exclude-target type="bool">true</exclude-target>
    <condition>
      <greater-than>
        <property>/sim/time/elapsed-sec</property>
        <value>30</value>
      </greater-than>
    </condition>
    <binding>Zero to many bindings, fired upon state change</binding>
  </transition>
</state-machine>
</syntaxhighlight>
</syntaxhighlight>
Legal elements for the state machine are:
{| class="prettytable"
! <syntaxhighlight lang="xml" inline><branch></syntaxhighlight>
| A path to a property node where the internal states of the machine gets written to. Can be empty.
|-
! <syntaxhighlight lang="xml" inline><state></syntaxhighlight>
| Two ore more state elements are required for a minimal state machine
|-
! <syntaxhighlight lang="xml" inline><transition></syntaxhighlight>
| Any number of transition elements. Describes how to change from one state to another.
|}
Legal elements for the state element are:
{| class="prettytable"
! <syntaxhighlight lang="xml" inline><name></syntaxhighlight>
| Required, gives the state a name for reference
|-
! <syntaxhighlight lang="xml" inline><enter></syntaxhighlight>
| Optional, zero to many enter elements containing a SGBinding to fire upon state enter
|-
! <syntaxhighlight lang="xml" inline><exit></syntaxhighlight>
| Optional, zero to many exit elements containing a SGBinding to fire upon state exit
|-
! <syntaxhighlight lang="xml" inline><update></syntaxhighlight>
| Optional, zero to many update elements containing a SGBinding to fire upon state change
|}
Legal elements for the transition element are:
{| class="prettytable"
! <syntaxhighlight lang="xml" inline><name></syntaxhighlight>
| Required, gives the transition a name for reference
|-
! <syntaxhighlight lang="xml" inline><source></syntaxhighlight>
| Optional, zero to many source elements containing the name of a source state. If no source state is definied, this transition applies to all states.
|-
! <syntaxhighlight lang="xml" inline><target></syntaxhighlight>
| Required, exactly one target element defining the target state
|-
! <syntaxhighlight lang="xml" inline><condition></syntaxhighlight>
| Required, contains a SGCondition when this state change occours
|-
! <syntaxhighlight lang="xml" inline><exclude-target></syntaxhighlight>
| Optional, boolean flag defaults to true. Indicates if this transition should be evaluated even if current state equals target
|-
! <syntaxhighlight lang="xml" inline><binding></syntaxhighlight>
| Optional, zero to many binding elements containing a SGBinding to fire when this transition triggers
|}


== Proposed extensions ==
== Proposed extensions ==
This sections contains new features for the autopilot to be implemented. Nobody knows if and when this will happen. Consider this as a collection of ideas as a base for discussion on the mailing list, the forum or IRC.
This sections contains new features for the autopilot to be implemented. Nobody knows if and when this will happen. Consider this as a collection of ideas as a base for discussion on the mailing list, the forum or IRC.


Also see: [[State machines]].
=== Expose to Nasal ===
Given that Nasal is a widely-known bottleneck, people should not use it for implement FDM/AP or route-manager functionality in scripting space. However, for the time being, the underlying C++ code is not exposed to scripting space, so that aircraft developers tend to reinvent the wheel. Thus, it would make sense to expose the AP/property-rule/state machine subsystems to scripting space using the [[Nasal/CppBind]] framework, to ensure that existing C++ code can be used for such purposes:
 
{{FGCquote
|1= I have recently committed some code to allow runtime loading of &lt;strike&gt;autopilots&lt;/strike&gt; property rules and have a Nasal binding for that in mind.
|2= {{cite web
  | url    = http://forum.flightgear.org/viewtopic.php?p=149376#p149376
  | title  = <nowiki>Re: 2 Questions: vacuum & electrical</nowiki>
  | author = <nowiki>Torsten</nowiki>
  | date  = Feb 2nd, 2012
  }}
}}
 
== Related content ==
=== Wiki articles ===
* [[Autopilot PID controller tuning resources]]
* [[Howto:Design an autopilot]]
* [[Howto:Implement a Fly-By-Wire System for Airliners]]
 
=== Readme file ===
* {{readme file|digitalfilters}}
 
=== Source code ===
* {{flightgear source|src/Autopilot/digitalfilter.hxx}}
* {{flightgear source|src/Autopilot/autopilot.cxx}}


[[Category:Aircraft enhancement]]
[[Category:Aircraft enhancement]]

Revision as of 22:06, 11 October 2018

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.


FGPlot can be used to plot the value properties while tuning an autopilot.
For a guide on how to model an autopilot using these elements, see Howto:Design an autopilot.

The property rules used for autopilot configuration can also be used for other kinds of systems modeling. The controllers and filters allow for both simple and complex systems to be modeled. By using the output from one as the input to another one, very complex systems such as fly-by-wire systems with different control laws can be modeled.

This page serves as a reference for the elements of FlightGear XML autopilot and property rule configuration files. It describes all elements available within the autopilot configuration file supported in the bleeding edge Git sources. Some of the elements may not be available in the current release version of FlightGear.

For built-in runtime plotting of FlightGear properties (including FDM/Autopilot properties), check out FGPlot (available in FlightGear 2.11+).

Autopilot vs. property-rule configurations

The main difference between XML based autopilot and property-rule systems is the update rate:

  • Autopilot configurations run at FDM rate
  • Property-rule configurations run at frame rate

Performance considerations

Using property-rule elements for things that does not have to run a FDM rate can improve the frame rate, in particular for complex systems and on weaker computers. Depending on FlightGear settings and the hardware, the FDM rate is about 2–10 times higher than the frame rate.

It is possible to implement a system using both autopilot and property-rule based elements. They can communicate with each other using properties. The only disadvantage is that they will be split between an autopilot and a property-rule configuration file.

For example would a fly-by-wire flight control system element augmenting an unstable aircraft need to run at FDM rate, while an element depending on the flap extension would work just as well at frame rate.

Adding a configuration to an aircraft

A configuration is added to an aircraft by adding the path to an XML configuration file to the <Aircraft>-set.xml file.

Adding an autopilot configuration

Autopilot configuration files are added to the aircraft by adding

  <autopilot n="100">
    <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
  </autopilot>

to the

 <sim>
   <systems>
     <!-- many other elements live here -->
     <autopilot n="100">
       <path>Aircraft/MyAircraft/Systems/my-autopilot.xml</path>
     </autopilot>
   </systems>
  </sim>

node of your aircraft-set.xml file. Note, that more than one <autopilot> node may be present, each will create a new instance of the autopilot subsystem when running FlightGear. They run in the order of appearance under <systems>. For example, lateral and vertical autopilot modes could live in separate files, as could a yaw-damper system.

Note  While the above seems to be the recommended standard, it has occasionally lead to trouble, not to index additional autopilot configurations. Anyway, it shouldn't hurt to do so.

FG first loads generic configs, which get indexed atomatically as they appear. Then you override these generic configs with your own, which may lead to strange behaviour, if you for example overwrite the weather rules with an autopilot-helper configuration. Not only will you have no weather anymore, but also 2 systems that will most likely overwrite each others results all the time. Check the property-tree at /sim/systems/autopilot[*]

Adding a property-rule configuration

Property-rules can also be used in which case they will run at frame rate. You can use these to process properties so their values can be used by other systems outside of the autopilot scope (for example to create smooth animations for switches that normally have discrete values)

To achieve this load your filters configuration by adding:

  <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
    <name>My property rule</name>  <!--  Optional name tag useful for debugging and other maintenance -->
    <path>Systems/my-propertyrules.xml</path>  <!-- path can be relative to the current aircraft-set.xml location -->
  </property-rule>

(Do NOT use the filename "propertyrules.xml")

to the :

  <sim>
    <systems>
      <!-- many other elements live here -->
      <property-rule n="100">  <!-- "n" needs to be >= 100 to avoid overwriting other predefined global rules (in particular the environment ones) -->
        <name>My property rule</name>  <!--  Optional name tag useful for debugging and other maintenance -->
        <path>Systems/my-propertyrules.xml</path>  <!-- path can be relative to the current aircraft-set.xml location -->
      </property-rule>
    </systems>
  </sim>

node of your <aircraft>-set.xml file. Note that you can add multiple <property-rule> elements, similar to the <autopilot> as described above.

Tip  Configurations can be enabled and disabled through the boolean properties /sim/systems/autopilot[n]/serviceable and /sim/systems/property-rule[n]/serviceable, wheren is the index for a configuration

Structure of a configuration file

Autopilot configurations live in a separate file, formatted using the well known XML syntax like so many other FlightGear files with a <PropertyList> node as a root element. A basic skeleton file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
  <params include="MyParams.xml"> <!-- Params can be included like this -->
    <controls>
      <aileron>controls/flight/aileron</aileron>
      <rudder>controls/flight/rudder</rudder>
      <elevator>controls/flight/elevator</elevator>
    </controls>
  </params>

  <!-- Place your components here -->
  <!--
  <filter>
    <name>Myfilter</name>
    <input>/foo</input>
    <output>/bar</output>
  </filter>
  <filter>
    <name>Myfilter</name>
    <input alias="/params/control/aileron"/>  Aliasing a property name
    <output>/bar</output>
  </filter>
  -->
</PropertyList>

The location and the name of the configuration file is up to the developer. A descriptive name like autopilot.xml might be a good choice. Most developers put these files into the Systems folder of the aircraft.

Tip  Using aliased property names is good style and makes the configuration file more readable. The params section may be included from an external file to avoid duplication of code.

For complex systems, spread over multiple autopilot and/or property-rule configuration files, this can greatly aid debugging and maintenance.

Tip  Commenting the configuration file to document the purpose elements and groups of elements and what they are intended to do can also aid debugging and maintenance.

Available elements

All elements may contain the attributes "include" and "alias". The "include" property takes a file name as a parameter. This can be used to read the document tree of an external XML file into the node containing the "include" attribute. The included file must have a PropertyList node as the root node. All nodes under this PropertyList node will be added to the node containing the "include" attribute. The "alias" attribute refers to an element defined elsewhere in this XMl document. Alias references are in a path-style syntax, either as a relative or absolute path. Absolute paths start with a slash, like <foo alias="/params/bar/baz"/>. Use the colon to move through the document tree, similar to file system paths like <foo alias="../../bar/baz"/>.

Any top-level element can appear in an autopilot XML file, but only the following elements will be recognised and used:

  • <pid-controller>
  • <pi-simple-controller>
  • <filter>
  • <predict-simple>
  • <logic>
  • <flipflop>
  • <state-machine>

Common elements used by all elements

Name of filter and controller <name>

The <name> element is optional, but should be added to give the controller a distinct name. It is only used in debug output.

<name>NAV hold</name>

Feedback <feedback-if-disabled>

The <feedback-if-disabled> element advises the controller to feed back the output property value to the active input property if the condition defined in the <enable> tag evaluates to false. This is usually required for controllers like servo drivers behind a PID-controller to give that PID-controller a valid starting value when it becomes enabled. The absence of this element or anything but the word true within this element results in feedback disabled.

<feedback-if-disabled>true</feedback-if-disabled>

Printing debug output <debug>

If the <debug> element is present and if it contains the word true, the containing controller prints out some diagnostic information on the console for each processing loop.

<debug>true</debug>

Input and reference properties or values <input> and <reference>

Each controller has two input "lines", denoted by the tags <input> and <reference>. The arithmetic difference of these two values is used by the respective controller to compute it's output. Unfortunately due to historical reasons, the sign of input and reference is not consistent for all controllers. While the pid-controller and the pi-simple-controller compute "reference-input", the filter controller computes "input-reference". Each element is optional with a default value of zero. These elements are made of so called input values described further down in this document.

Example for a simple differential amplifier, computing output = (input-reference)*2

<filter>
  <type>gain</type>
  <gain>2.0</gain>
  <input>/some/input</input>
  <reference>/some/output</reference>
  <output>/some/output</output>
</filter>

Output property <output>

The <output> element names the properties, the computed value should be written to. More than one <output> may be present, each named property will be assigned the computed value.

<output>controls/flight/elevator</output>

Enabling and disabling a filter <enable>

Controllers can be enabled or disabled using property values. This element <enable> may contain a <prop> and a <value> element. The controller is enabled, if the value of the named property equals the given value. This feature is considered deprecated and might go away in future releases. The preferred way of defining the enable-condition is by adding a <condition> element to the <enable> element. This <condition> follows the same syntactical rules as the one used in model animations and can model complex expression trees. To enable a wing leveler only if the current bank angle does not exceed 30° of bank, use this condition

<enable>
  <condition>
    <less-than>
      <property>orientation/bank-angle-deg</property>
      <value>30.0</value>
    </less-than>
    <greater-than>
      <property>orientation/bank-angle-deg</property>
      <value>-30.0</value>
    </greater-than>
  </condition>
</enable>

Input values

Input values for controllers may be specified in several notations. Values may be supplied as constants, from properties or by means of simple linear transformations. Conditions allow the selection of one of multiple input sources. The following text will use the <reference> element as an example but it may be substituted by any other input element like <Kp>, <gain> etc. Input values will be interpreted as double values.

A constant value <value> or <reference>

A constant value is defined by just adding the value as text to the input element:

<reference>
  <value>3.5</value>
</reference>

The shortcut syntax is also valid:

<reference>3.5</reference>

If the text can be parsed by strtod() to a double value, it will be used as a constant value, otherwise it will be interpreted as a property value (see next paragraph)

A property value

To evaluate the value of a property, place the name of the property into the text element:

<reference>
  <property>/my/property</property>
</reference>

The shortcut syntax is also valid:

<reference>/my/property</reference>
Note  The shortcut syntax is only valid, if neither <property> nor <value> element exists.

If both <property> and <value> element exist, the property will be initialized with the given value with scale and offset applied correctly. Properties don't have to exist, the will be created as needed.

Note  For backward compatibility, the notation <prop> instead of <property> is also valid but considered deprecated and might go away in future releases.

Linear transformation of the input value <offset>

Input values may be scaled and shifted before they are processed by the controller using the formula y = value * scale + offset To use a Celsius temperature property in a controller which expects the temperature in Fahrenheit you might use

<reference>
  <property>/environment/temperature-degc</property>
  <scale>1.8</scale>
  <offset>32</offset>
</reference>

Periodical transformation of the input value <period>

Periodical (like angular) input values can be transformed to appear in the correct phase before they are processed by the controller by adding or subtracting multiples of the period to the input value until the values is in the requested periods interval. The following example converts the heading which comes in the range of [0..360] into the range of [-180..+180]. This will cause a heading of 270 to be processed as a value of -90.

<reference>
  <property>/orientation/heading-deg</property>
  <period>
    <min>-180.0</min>
    <max>180.0</max>
  </period>
</reference>

Input clamping <min> and <max>

To clamp the input to a minimum value, maximum value or both, the tags <min> and <max> can be used. Clamping will occur after the linear transformation has been applied. Note the difference of input clamping to output clamping. While input clamping is applied before the signal reaches the controller, output clamping will be applied to the output signal after it has been processed.

The following code will keep the input to the controller in the range of 60 to 80 degrees Fahrenheit:

<reference>
  <property>/environment/temperature-degc</property>
  <scale>1.8</scale>
  <offset>32</offset>
  <min>60</min>
  <max>80</max>
</reference>

Absolute values <abs>

To use the absolute (unsigned) value of the input, add <abs type="bool">true</abs>.

<reference>
  <property>/autopilot/internal/course-error-deg</property>
  <abs type="bool">true</abs>
</reference>

Recursive definition

The elements <scale>, <offset>, <min> and <max> itself can be defined as input values. This code uses as reference the value of course-error-deg, scaled by two and an offset applied which is calculated as the product of the bank-angle-de and the property some/property which itself is limited within the range of -1.5 .. +1.5.

<reference>
  <property>/autopilot/internal/course-error-deg</property>
  <scale>2.0</scale>
  <offset>
    <property>orientation/bank-angle-deg</property>
    <scale>
      <property>some/property</property>
      <min>-1.5</min>
      <max>1.5</max>
    </scale>
  </offset>
</reference>

Conditional input values <condition>

The direct inputs of controller and filter elements support so called input value lists. This is useful, if the input should be connected to one of many separate inputs like autopilots connected to NAV1, NAV2 or the GPS. A standard <condition> element is allowed within an input value element. The input value list will be traversed until the first input value with a successful condition is found. The behavior is much like the switch statement in programming languages.

<reference>
  <condition>
    <property>/autopilot/coupled-to-gps</property>
  </condition>
  <property>instrumentation/gps/desired-track-deg</property>
</reference>
<reference>
  <condition>
    <property>/autopilot/coupled-to-nav2</property>
  </condition>
  <property>instrumentation/nav[1]/radials/selected-deg</property>
</reference>
<reference>instrumentation/nav[0]/radials/selected-deg</reference>

Note the unconditional last <reference> element which acts as an "if all others fail, use NAV1" anchor. If no input value return with a successful condition, the input value is undefined.

The <scale>, <offset>, <min> and <max> elements of input values itself currently don't support input value lists.

Expressions <expression>

Complex math or lookup tables may be represented using the expression syntax. The expression has to be enclosed in <expression> tag.

Output values

After processing of a component, the resulting value passes a transformation stage where it can be clipped or normalized into a given period. Periodic values such as angular properties may be normalized into a given period by adding a <period> element, defining the lower and upper bounds of the period. Additionally, a maximun and a minimum value may be given which will guarantee that the output value will ever exceed a defined value.

Note  Both periodical normalization and clipping may be defined. If both are given, the value will be normalized first and the clipping will be applied to the normalized value.

The following example shifts the computed value into the interval of [-180..180] thereafter being limited into the interval of [-30..30]. The following table contains some computed values and the resulting written value:

computed written
-350 10
-270 30
-90 -30
-29 -29
29 29
90 30
350 -10
<output>/some/property</output>
<period>
  <min>-180</min>
  <max>180</max>
</period>
<min>-30</min>
<max>30</max>

This example shows how to use a table to vary an output with height. At sea level, the output is 0.045, at 22400 the output is 0.1196, and at 56000 ft the output is 0.7

<filter>
  <name>GAy</name>
  <debug>false</debug>
  <type>gain</type>
  <gain>1.0</gain>
  <input>
    <expression>
      <table>
        <property>/instrumentation/altimeter/indicated-altitude-ft</property>
        <entry><ind>0.0</ind><dep>0.045</dep></entry>
        <entry><ind>22400</ind><dep>0.1196</dep></entry>
        <entry><ind>56000</ind><dep>0.7</dep></entry>
      </table>
    </expression>
  </input>
  <output>
    <property>/autopilot/gain/GAy</property>
  </output>
</filter>

Logic controller <logic>

The logic controller provides a simple way of creating property values from the result of the condition expression in the <input> element. The condition expression is evaluated once per iteration and the result is written as a boolean value to the named output property or properties. An optional <inverted> element inverts the logic. The default is "not inverted".

Example: output = not( ( a is true ) or ( ( b greater than c ) and ( d is true ) )

<logic>
  <inverted>true</inverted>
  <input>
    <property>a</property>
    <or>
      <greater-than>
        <property>b</property>
        <property>c</property>
      </greater-than>
      <property>d</property>
    </or>
  </input>
  <output>output</output>
</logic>

Flip flop logic <flipflop>

A flip flop is a controller that has two stable states so it can be used as a one bit memory. Four types of flip flops are implemented: RS, JK, D and T. All use positive logic and operate on the raising edge of the clock signal if a clock is used. All input lines, including the clock line, are encoded as condition constructs. If negative logic for the input line is required, wrap the condition into a <not> tag to invert the logic.

Note  The type, for example RS, is case sensitive.
Note  Using <condition> tags will break the logic.

RS flip flop <RS>

This flip flop sets its output according to the set (S) or reset (R) input lines. If the set line is set, the output gets set. If the reset line is set, the output gets reset. If no line is set, the output stays unchanged. For the special case where set and reset lines are both set, two types of RS flip flops exist: for the RS flip flop (<type>RS</type>), the reset line is dominant and the output is reset. Alternatively, a SR flip flop (<type>SR</type>) has a dominant set line and the output gets set if set and reset line are set.

Example: simple RS flip flop

<flipflop>
  <type>RS</type> <!-- or SR -->
  <S>
    <property>/myflipflop/set</property>
  </S>
  <R>
    <property>/myflipflop/reset</property>
  </R>
  <output>/myflipflop/output</output>
</flipflop>

JK flip flop <JK>

The JK flip flop is an extension of the RS flip flop. In addition to the set and reset lines of the RS flip flop it uses J, K and a clock input. The J line serves as a clock dependent set input while the K line does the reset job. Optionally, a clock input may be provided. State changes do not occur immediately, but on the next raising edge of the clock signal. The state of J=K=true causes the output to toggle it's current state on the next raising edge of the clock signal. If no clock signal is provided, the frame rate serves as the clock input.

Example: simple JK flip flop with negative edge clock

<flipflop>
  <type>JK</type>
  <J>
    <property>/myflipflop/set</property>
  </J>
  <K>
    <property>/myflipflop/reset</property>
  </K>
  <clock>
    <not>
      <property>/myflipflop/clock</property>
    </not>
  </clock>
  <output>/myflipflop/output</output>
</flipflop>

D flip flop <D>

The D flip flop transfers the state of the input signal D to the output line at the next raising edge of the clock signal, which is mandatory for this flip flop.

Example: simple D flip flop with inverted output

<flipflop>
  <type>D</type>
  <D>
    <property>/myflipflop/data</property>
  </D>
  <clock>
    <property>/myflipflop/clock</property>
  </clock>
  <output>/myflipflop/output</output>
  <inverted type="bool">true</inverted>
</flipflop>

T flip flop <T>

The T flip flop toggles the state of the output signal at the next raising edge of the clock signal, which is mandatory for this flip flop.

Example: simple T flip flop

<flipflop>
  <type>T</type>
  <clock>
    <property>/myflipflop/clock</property>
  </clock>
  <output>/myflipflop/output</output>
</flipflop>

Monostable flip flop <monostable>

A monostable flip flop has only one stable state which will be reentered after a well defined time. The stable state in current implementation is the output set 'false' or 0. The Monostable is an extension of the JK flip flop. Additionally to the input values defined there, an InputValue for the definition of the pulse time is mandatory.

The moment the time for the astable state starts counting depends on the input used to set the output. If the output is set from the SET input of the RS flipflop, the output is kept true for the defined time after the SET input enters it's false state. The total time the output is true equals the time, the SET input is true plus the time defined in the

Note  The optional <R> and <K> inputs may be used to reset the output before the internal timer expired. This will also reset the timer to zero, so no additional event will be triggered after the defined timer interval.
<flipflop>
  <name>Test mf</name>
  <type>monostable</type>
  <time>
    <property>/myflipflop/pulsetime-sec</property>
    <value>10</value>
  </time>
  <S><property>/myflipflop/s</property></S>
  <J><property>/myflipflop/j</property></J>
  <clock><property>/myflipflop/clock</property></clock>
  <output>/myflipflop/output</output>
</flipflop>

The following example shows how a monostable can be used to enable a certain property (/myflipflop/output) if another property (/myflipflop/s) is true for at least the specified amount of time:

<flipflop>
  <name>Test mf</name>
  <type>monostable</type>
  <inverted type="bool">true</inverted>
  <S>
    <not>
      <property>/myflipflop/s</property>
    </not>
  </S>
  <time>
    <value>10.0</value>
  </time>
  <output>
    <property>/myflipflop/output</property>
  </output>
</flipflop>

In this example the monostable is inverted, which means the stable state is true instead of false. The key idea here is to keep the monostable in its unstable state (false) by keeping the set line true, which is the case when /myflipflop/s is false. Then, when /myflipflop/s becomes true the set line becomes false, which causes the timer to start. When the timer expires (in this case 10 seconds) the monostable will enter its stable state (true). At any time when the set line becomes true (when /myflipflop/s becomes false) the monostable will immediately enter its unstable state (false) again, resulting in /myflipflop/output to become false immediately.

Filters <filter>

Pure gain filter <gain>

A gain filter multiplies the <input> value by a given factor or gain <gain> and returns the output to <output>. More than one <gain> element formatted as in Input Values may be present. Within a <condition> evaluating as true the first <gain> will define the used gain.

<filter>
  <type>gain</type>
  <gain>6.28</gain>
  <input>radius</input>
  <output>circumfence</output>
</filter>

First order low pass filter <exponential>

The exponential filter is a typical low pass filter. The magic Euler number and the associated mathematical function exp() plays a major role here. As the name implies, lower frequencies can pass this filter while higher frequencies are cut. The frequency where only half of the input signal reaches the output is called cutoff frequency. This cutoff frequency is defined by the parameter <filter-time> and resolves as cutoff-frequency = 1/(2*pi*cutoff-frequency).

Example: a 1Hz first order low pass filter

<filter>
  <type>exponential</type>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <output>/some/output/</output>
</filter>


Second order low pass filter <double-exponential>

The double exponential filter is a low pass filter like the exponential filter with a steeper slope of the filter diagram. It acts basically like two chained exponential filters and it is some times called second order filter.

The configuration is the same for exponential and double-exponential filters, just the type entry differs.

<filter>
  <type>double-exponential</type>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <output>/some/output/<output>
</filter>


First order high pass filter <high-pass>

The high pass filter is a typical high pass filter. The magic euler number and the associated mathematical funtion exp() plays a major role here. As the name implies, higher frequencies can pass this filter while lower frequencies are cut. The frequency where only half of the input signal reaches the output is called cutoff frequency. This cutoff frequency is defined by the parameter <filter-time> and resolves as cutoff-frequency = 1/(2*pi*cutoff-frequency). It is commonly known as a wash-out filter or a 1st order lead filter

Example: a 1Hz first order high pass filter

<filter>
  <type>high-pass</type>
  <filter-time>0.16</filter-time>
  <input>/some/input</input>
  <output>/some/output/</output>
</filter>


Lead-Lag filter <lead-lag>

The lead-lag filter is a typical [1] lead lag filter. As the name implies it is a combination of a lead (high-pass) filter and a lag (low-pass) filter.

Example: a lead lag filter k(s+a)/s+b). The gain is k, filter-time-a is a, and filter-time-b is b.

In an autopilot is is often used to sharpen up the response to an input.

<filter>
  <name>loc-deg leadlag</name>
  <debug>false</debug>
  <type>lead-lag</type>
  <gain>5</gain>
  <filter-time-a>5.0</filter-time-a>
  <filter-time-b>1.0</filter-time-b>
  <input>
    <property>/autopilot/internal/loc-deg</property>
  </input>
  <output>
    <property>/autopilot/internal/loc-deg-leadlag</property>
  </output>
</filter>


Integrator filter <integrator>

The integrator filter provides integration with time.


Example: an integrator filter k(1/s).

In this example, the normal input (<property>/autopilot/internal/p-deg_sec</property>)is disconnected and replaved by (output x 10) input when relay Rb is closed. This has the effect of rapidly ramping the integrator output to zero.

<filter>
  <name>synthetic bank from roll rate</name>
  <debug>false</debug>
  <type>integrator</type>
  <gain>1.0</gain>
  <input>
    <condition>
      <property>/autopilot/internal/Rb</property>
    </condition>
    <property>/autopilot/internal/p-deg_sec</property>
  </input>
  <input> <!-- zero integrator when Rb is not set -->
    <expression>
      <product>
        <value>-10.0</value>
        <property>/autopilot/internal/phi-deg_synth</property>
      </product>
    </expression>
  </input>
  <output>
    <property>/autopilot/internal/phi-deg_synth</property>
  </output>
  <u_min>-180</u_min>
  <u_max>180</u_max>
</filter>

Moving average filter <moving-average>

Calculates average of specified number of values.

Currently the average length can only be given as number of samples and not time.

<filter>
  <type>moving-average</type>
  <samples>120</samples>
  <input>/some/input</input>
  <output>/some/output</output>
</filter>

Rate limit filter <noise-spike>

A better name for a noise spike filter would probably have been "rate limit filter". This is exactly what it does: limit the rate of change of the output value. The relevant configuration element is <max-rate-of-change> setting the maximum rate of change of the output property per second.

Example: A transition from 0 to 4 at the input property results in a linear increase of the output property over 8 seconds from 0 to 4 at a rate of 0.5/sec.

<filter>
  <type>noise-spike</type>
  <max-rate-of-change>0.5</max-rate-of-change>
  <input>/some/input</input>
  <output>/some/output</output>
</filter>

Reciprocal filter <reciprocal>

Compute the reciprocal (1/x) value of the input property. If x is zero, no computation is performed. The optional <gain> element may be used to scale the value. Output computes as gain divided by input.

Example: compute the flight time per pound of burned fuel from the fuel flow

<filter>
  <type>reciprocal</type>
  <gain>1.0</gain>
  <input>/engines/engine[0]/fuel-flow-pph</input>
  <output>/engines/engine[0]/fuel-flow-hpp</output>
</filter>

Derivative filter <derivative>

Compute first time derivative of the input property, that is change per unit of time. Time is measured in seconds. A <filter-time> acts as gain and must be given because it has default 0.

Example: compute derivative of static port pressure

<filter>
  <type>derivative</type>
  <input>systems/static[0]/pressure-inhg</input>
  <output>autopilot/internal/pressure-rate</output>
  <filter-time>1.0</filter-time>
</filter>

PID controller <pid-controller>

The PID controller is the swiss army knife of automation and this implementation is suitable for most situations. It has a builtin anti-windup logic, and usage of <max> and <min> elements for clamping the output is mandatory. The most important thing to know is that this controller 'does not' compute absolute output values but an offset from the current value of the output property. This can lead to unexpected behavior if the current value of the output property is unknown when the controller is enabled. This behavior is different to that of the pi-simple-controller.

The xml element creating a pid controller is <pid-controller>.

Legal elements are:

<Kp> The overall gain for the proportional, integral and derivative part
<Ti> Integrator time
<Td> Derivator time
<Ts> Sampling interval (default: sample at frame rate)
<alpha> Scaling factor for Td (defaults to 0.1)
<beta> Reference weighing factor for the proportional component (defaults to 1.0)
<gamma> Reference weighing factor for the derivate component (defaults to 0.0)

PI controller <pi-simple-controller>

This controller implements a PI controller. Other than the PID controller, it computes absolute output values, regardless of the value of the output property. It can by configured as an I-only, P-only or PI-controller. It has anti windup logic if <min> and <max> elements are present. The xml element creating a PI controller is <pi-simple-controller> Legal elements are:

<Kp> Gain of the proportional component
<Ki> Gain of the integrator component

Predictor <predict-simple>

Estimates the future value for a given property based on its current (or averaged) rate of change.

Legal elements are:

<seconds> The time to be estimated ahead
<filter-gain> Smoothing factor (0.0-1.0, 1.0=no smoothing)

Example: compute estimated speed 5 seconds ahead

<predict-simple>
  <name>predicted air speed 5 seconds ahead</name>
  <debug>false</debug>
  <input>velocities/airspeed-kt</input>
  <output>autopilot/internal/airspeed-5-sec-ahead</output>
  <seconds>5.0</seconds>
  <filter-gain>0.1</filter-gain>
</predict-simple>

State Machine <state-machine>

For a description of what a state machine can do, look here: [2].

Note  Current behaviour with enter, exit and update tags differs from this documentation. Refer to the developer mailing list [3] before implementing bindings in state machines.
<state-machine>
  <branch>/my-statemachine</branch>
  <state>
    <name>init</name>
    <enter>
      <binding></binding>
      <binding></binding>
    </enter>
    <exit>
      <binding></binding>
    </exit>
    <update>
      <binding></binding>
    </update>
  </state>
  <state>
    <name>finished</name>
    <enter>Zero to many bindings, fired upon state enter</enter>
    <exit>Zero to many bindings, fired upon state exit</exit>
    <update>Zero to many bindings, fired upon every state change</update>
  </state>
  <transition>
    <name>ready</name>
    <source>init</source>
    <target>finished</target>
    <exclude-target type="bool">true</exclude-target>
    <condition>
      <greater-than>
        <property>/sim/time/elapsed-sec</property>
        <value>30</value>
      </greater-than>
    </condition>
    <binding>Zero to many bindings, fired upon state change</binding>
  </transition>
</state-machine>

Legal elements for the state machine are:

<branch> A path to a property node where the internal states of the machine gets written to. Can be empty.
<state> Two ore more state elements are required for a minimal state machine
<transition> Any number of transition elements. Describes how to change from one state to another.


Legal elements for the state element are:

<name> Required, gives the state a name for reference
<enter> Optional, zero to many enter elements containing a SGBinding to fire upon state enter
<exit> Optional, zero to many exit elements containing a SGBinding to fire upon state exit
<update> Optional, zero to many update elements containing a SGBinding to fire upon state change

Legal elements for the transition element are:

<name> Required, gives the transition a name for reference
<source> Optional, zero to many source elements containing the name of a source state. If no source state is definied, this transition applies to all states.
<target> Required, exactly one target element defining the target state
<condition> Required, contains a SGCondition when this state change occours
<exclude-target> Optional, boolean flag defaults to true. Indicates if this transition should be evaluated even if current state equals target
<binding> Optional, zero to many binding elements containing a SGBinding to fire when this transition triggers

Proposed extensions

This sections contains new features for the autopilot to be implemented. Nobody knows if and when this will happen. Consider this as a collection of ideas as a base for discussion on the mailing list, the forum or IRC.

Expose to Nasal

Given that Nasal is a widely-known bottleneck, people should not use it for implement FDM/AP or route-manager functionality in scripting space. However, for the time being, the underlying C++ code is not exposed to scripting space, so that aircraft developers tend to reinvent the wheel. Thus, it would make sense to expose the AP/property-rule/state machine subsystems to scripting space using the Nasal/CppBind framework, to ensure that existing C++ code can be used for such purposes:

Cquote1.png I have recently committed some code to allow runtime loading of <strike>autopilots</strike> property rules and have a Nasal binding for that in mind.
— Torsten (Feb 2nd, 2012). Re: 2 Questions: vacuum & electrical.
(powered by Instant-Cquotes)
Cquote2.png

Related content

Wiki articles

Readme file

Source code