FlightGear implements this PID algorithm in a flexible and reusable way. It reads an autopilot config file that can define any number of PID controllers. Each controller can specify it's own process value, it's own reference point, any number of output values, as well as values for all the other tuning constants.
You can create cascading controllers by specify multiple PID controllers (all with the same enabling condition) where the output of the first stage is used as the input to the second, and the output of the second is used as the input to the third, etc.
The FlightGear
.../data/preferences.xml
file contains a reference to the default autopilot file:
<sim> <systems> <autopilot> <path>Aircraft/Generic/generic-autopilot.xml</path> </autopilot> </systems> </sim>
If you would like to specify a different autopilot configuration file
for a particular aircraft, you can override this definition in the
aircraft's <aircraft>-set.xml
file.
The autopilot configuration file is a standard FlightGear .xml
file. It's basic structure is as follows:
<?xml version="1.0"?> <PropertyList> <pid-controller> <!-- First PID controller params --> </pid-controller> <pid-controller> <!-- Second PID controller params --> </pid-controller> <pid-controller> <!-- Third PID controller params --> </pid-controller> . . . </PropertyList>
Each PID controller section can list a name, the input (or process)
property, the target (or reference) property, and any number of output
properties. Here ``property'' means the name of an internal
FlightGear property from the FG property system. You also specify a
property name and value that is check to see if the controller is
activated or not, and you can turn debugging output on or off for this
controller. Finally there is a <config>
section listing all
the parameters you can tune. Here is an example of a simple PID
controller which holds a fixed pitch.
<!-- Simple pitch hold --> <pid-controller> <name>Pitch hold</name> <debug>false</debug> <enable> <prop>/autopilot/locks/altitude</prop> <value>pitch-hold</value> </enable> <input> <prop>/orientation/pitch-deg</prop> </input> <reference> <prop>/autopilot/settings/target-pitch-deg</prop> </reference> <output> <prop>/controls/flight/elevator-trim</prop> </output> <config> <Kp>-0.05</Kp> <!-- proportional gain --> <beta>1.0</beta> <!-- input value weighing factor --> <alpha>0.1</alpha> <!-- low pass filter weighing factor --> <gamma>0.0</gamma> <!-- input value weighing factor for --> <!-- unfiltered derivative error --> <Ti>1.0</Ti> <!-- integrator time --> <Td>0.00001</Td> <!-- derivator time --> <u_min>-1.0</u_min> <!-- minimum output clamp --> <u_max>1.0</u_max> <!-- maximum output clamp --> </config> </pid-controller>
In this example we give the <pid-controller>
a <name>
of
``Pitch Hold''. This name is only used when outputting debug
information.
You can set <debug>
to be true
or false
.
The controller will be activated when ever
/autopilot/locks/altitude
has a value of pitch-hold
.
The <input>
(or process) value is
/orientation/pitch-deg
. This is the value that we are trying
to control indirectly via this PID controller.
The <reference>
(or target) value is
/autopilot/settings/target-pitch-deg
. The PID controller is
trying to make the input value equal the reference value. (In other
words it is trying to make the error or difference between the two be
as close to zero as possible.)
The <output>
tag list the property where the output of the PID
algorithm will be written. This is typically something in the
/controls/
section of the property tree. In this example, we
know that adjusting elevator trim will affect the aircraft's pitch.
We hope that the PID magic will figure out what trim setting will
produce our target pitch.
Finally we have the <config>
section. Please see the xml comments
in this example as well as the previous section for a more complete
explanation of what they are and how they plug into and affect the PID
algorithm.
Cascading controllers are useful for more complex situations. Cascading controllers link the output from one PID unit as the input to another PID unit.
For example, a heading hold autopilot could be constructed with two PID units. The first unit would have the current heading as the ``process value'' and the target heading as the ``reference value''. It would output a ``target roll'' proportional to the heading error. The second unit would have the current roll angle as it's process value and the target roll as it's reference value. Notice that in this case, the reference value can be a moving target. The second PID controller would then output an aileron deflection to achieve the desired roll angle.
The autopilot system evaluates each PID controller in the order they
are specified. You are allowed to use (or make up) any property name
for the <input>
, <output>
, and <reference>
sections.
This allows you to easily build cascading controllers. The
generic-autopilot.xml file has several examples of these. I usually
choose a property name called /autopilot/internal/abcdefg
as
the intermediate value which is output from the first stage as input
to the second stage.
It is important to think through your design very carefully so you can get the proper process value, reference value, and output value for each stage.
Curtis L. Olson 2004-02-04