Howto:Design an autopilot: Difference between revisions

Jump to navigation Jump to search
m
Syntaxhighlighting
m (No longer actively worked on; fairly complete now.)
m (Syntaxhighlighting)
Line 5: Line 5:
== Pre-design ==
== Pre-design ==
Why not make things slightly easier, before we start working on the autopilot? Since we will be updating the autopilot hunderts of times, making tiny adjustments each time, we don't want to reload FlightGear every time. Therefore, we assign an "reload autopilot configuration" action to a key on our keyboard. We've chosen Shift-F5, but it could be any key. Add the code to your <tt>[[$FG ROOT]]/keyboard.xml</tt> file.
Why not make things slightly easier, before we start working on the autopilot? Since we will be updating the autopilot hunderts of times, making tiny adjustments each time, we don't want to reload FlightGear every time. Therefore, we assign an "reload autopilot configuration" action to a key on our keyboard. We've chosen Shift-F5, but it could be any key. Add the code to your <tt>[[$FG ROOT]]/keyboard.xml</tt> file.
<syntaxhighlight lang="xml">
  <key n="261">
  <key n="261">
   <name>F5</name>
   <name>F5</name>
Line 19: Line 21:
   </mod-shift>
   </mod-shift>
  </key>
  </key>
</syntaxhighlight>


== Creating the autopilot configuration file ==
== Creating the autopilot configuration file ==
Create an autopilot.xml file with the following content, somewhere inside your aircraft's root (eg. <tt>Aircraft/747-400/Systems/autopilot.xml</tt>).
Create an autopilot.xml file with the following content, somewhere inside your aircraft's root (eg. <tt>Aircraft/747-400/Systems/autopilot.xml</tt>).
<syntaxhighlight lang="xml">
  <?xml version="1.0"?>
  <?xml version="1.0"?>
   
   
Line 27: Line 32:
   
   
  </PropertyList>
  </PropertyList>
</syntaxhighlight>


== A first controller: wing leveler ==
== A first controller: wing leveler ==
Line 36: Line 42:
Be sure to add an <enable> element to easily enable/disable your controller if it gets unstable.
Be sure to add an <enable> element to easily enable/disable your controller if it gets unstable.


<syntaxhighlight lang="xml">
  <pid-controller>
  <pid-controller>
   <name>Heading hold</name>
   <name>Heading hold</name>
Line 58: Line 65:
   </config>
   </config>
  </pid-controller>
  </pid-controller>
</syntaxhighlight>


Since this is our first controller, we will give a short explenation of each part.
Since this is our first controller, we will give a short explenation of each part.
Line 83: Line 91:
Finally (for the wing-leveler) you can turn it into a roll-hold by setting your target roll as a property for the reference. If you had <reference>0.0</reference>, bind your reference to a property (<reference>autopilot/settings/target-roll-deg</reference>) and your aircraft should roll to any value you set in target-roll-deg. The complete wing-leveler will look similar to the one below (though, the config values may vary and the reference might be replaced by a property).
Finally (for the wing-leveler) you can turn it into a roll-hold by setting your target roll as a property for the reference. If you had <reference>0.0</reference>, bind your reference to a property (<reference>autopilot/settings/target-roll-deg</reference>) and your aircraft should roll to any value you set in target-roll-deg. The complete wing-leveler will look similar to the one below (though, the config values may vary and the reference might be replaced by a property).


<syntaxhighlight lang="xml">
  <pid-controller>
  <pid-controller>
   <name>Heading hold</name>
   <name>Heading hold</name>
Line 105: Line 114:
   </config>
   </config>
  </pid-controller>
  </pid-controller>
</syntaxhighlight>


This is the base for any lateral hold mode, so try to spend some time on it. It can take some hours if this is your first autopilot.
This is the base for any lateral hold mode, so try to spend some time on it. It can take some hours if this is your first autopilot.
Line 120: Line 130:
There is a filter to simulate that behaviour, it's the noise-spike filter. Here is a sample with 25 seconds transition time from -1 to +1:
There is a filter to simulate that behaviour, it's the noise-spike filter. Here is a sample with 25 seconds transition time from -1 to +1:


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>SERVO-DRIVER:elevator</name>
   <name>SERVO-DRIVER:elevator</name>
Line 133: Line 144:
   <max-rate-of-change>0.08</max-rate-of-change>
   <max-rate-of-change>0.08</max-rate-of-change>
  </filter>
  </filter>
</syntaxhighlight>


The formula for max-rate-of-change is (max-out - min-out)/transition-time. In our example (1--1)/25=2/25=0.08. Try it out, disable your pitch-hold controller and enable the servo-driver. Set your some/internal/elevator-cmd property to +1 and see your elevator moving to fully up or down within 12.5 seconds. Now set your property to -1 and it will take 25 seconds for the elevator to move to the other direction. The feedback-if-disabled property is needed, if this stage is driven from a pid-controller.  
The formula for max-rate-of-change is (max-out - min-out)/transition-time. In our example (1--1)/25=2/25=0.08. Try it out, disable your pitch-hold controller and enable the servo-driver. Set your some/internal/elevator-cmd property to +1 and see your elevator moving to fully up or down within 12.5 seconds. Now set your property to -1 and it will take 25 seconds for the elevator to move to the other direction. The feedback-if-disabled property is needed, if this stage is driven from a pid-controller.  
Line 141: Line 153:


== A simple auto throttle ==
== A simple auto throttle ==
<syntaxhighlight lang="xml">
  <pid-controller>
  <pid-controller>
   <name>Auto throttle</name>
   <name>Auto throttle</name>
Line 165: Line 178:
   </config>
   </config>
  </pid-controller>
  </pid-controller>
</syntaxhighlight>


And a filter, as our autopilot does not move the throttle levers up/down in split seconds (you can imagine how that would be potentially harmful to the flight crew). Depending on the number of engines of your aircraft, you might want to add more or delete some output properties.
And a filter, as our autopilot does not move the throttle levers up/down in split seconds (you can imagine how that would be potentially harmful to the flight crew). Depending on the number of engines of your aircraft, you might want to add more or delete some output properties.


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>SERVO-DRIVER:throttle</name>
   <name>SERVO-DRIVER:throttle</name>
Line 186: Line 201:
   <max-rate-of-change>0.1</max-rate-of-change>
   <max-rate-of-change>0.1</max-rate-of-change>
  </filter>
  </filter>
</syntaxhighlight>


== Vertical speed hold ==
== Vertical speed hold ==
Line 192: Line 208:
To get the current pitch to a property which will be modified by a pid-controller later, we will now create a controller which serves as a so called "sample-and-hold" element. It simply copies the input property value to the output property value until it is disabled. The same property, that disables the sample-and-hold controller will enable the pid-controller that computes the pitch for the rate-of climb.Here is a sample-and-hold controller implemented with a gain-filter:
To get the current pitch to a property which will be modified by a pid-controller later, we will now create a controller which serves as a so called "sample-and-hold" element. It simply copies the input property value to the output property value until it is disabled. The same property, that disables the sample-and-hold controller will enable the pid-controller that computes the pitch for the rate-of climb.Here is a sample-and-hold controller implemented with a gain-filter:


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>AP:Pitch sample and hold</name>
   <name>AP:Pitch sample and hold</name>
Line 207: Line 224:
   <output>/autopilot/internal/target-pitch-deg</output>
   <output>/autopilot/internal/target-pitch-deg</output>
  </filter>
  </filter>
</syntaxhighlight>


You probably have to adjust the property names. Note the condition element in the <enable> section - it has the same syntax as in the well-known <animation> elements. As long as the roc-lock property is false, input is copied to output. When it becomes true, the output property is no longer written by this filter and the next step can use this value as a start.  
You probably have to adjust the property names. Note the condition element in the <enable> section - it has the same syntax as in the well-known <animation> elements. As long as the roc-lock property is false, input is copied to output. When it becomes true, the output property is no longer written by this filter and the next step can use this value as a start.  
Line 212: Line 230:
Right behind this filter, add a pid-controller using your current rate-of-climb as input and a target-rate-of-climb as reference. Enable this pid if your pitch sample-and-hold is not enabled (use the same condition, just remove the <not> elements). Your output goes to target-pitch-deg which should be the same property as the input of your pitch-hold controller. Use the same procedure to obtain the values for Kp and Ti. Kp will be small. The offset computes in feet per minute and 100fpm should result in a few degrees pitch change. Something like 0.01 or smaller will probably do. I'd expect Integrator time around 10-50. You should clamp the target-pitch to something less than +/- 90° - probably -10° and +20° or whatever is a reasonable value for your aircraft. It could look like this:
Right behind this filter, add a pid-controller using your current rate-of-climb as input and a target-rate-of-climb as reference. Enable this pid if your pitch sample-and-hold is not enabled (use the same condition, just remove the <not> elements). Your output goes to target-pitch-deg which should be the same property as the input of your pitch-hold controller. Use the same procedure to obtain the values for Kp and Ti. Kp will be small. The offset computes in feet per minute and 100fpm should result in a few degrees pitch change. Something like 0.01 or smaller will probably do. I'd expect Integrator time around 10-50. You should clamp the target-pitch to something less than +/- 90° - probably -10° and +20° or whatever is a reasonable value for your aircraft. It could look like this:


<syntaxhighlight lang="xml">
  <pid-controller>
  <pid-controller>
   <name>Vertical speed pitch hold</name>
   <name>Vertical speed pitch hold</name>
Line 235: Line 254:
   </config>
   </config>
  </pid-controller>
  </pid-controller>
</syntaxhighlight>


== Logic-controlled properties ==
== Logic-controlled properties ==
These two new elements should give you a rate-of-climb hold mode for your autopilot. If you are not yet confused which controllers should be enabled in what mode, you will be very soon as we will add even more elements. If you are in the need for some logic-controlled properties, the autopilot can do this, too - no need for [[nasal]] helpers! There is a <logic> element that does all the magic:
These two new elements should give you a rate-of-climb hold mode for your autopilot. If you are not yet confused which controllers should be enabled in what mode, you will be very soon as we will add even more elements. If you are in the need for some logic-controlled properties, the autopilot can do this, too - no need for [[nasal]] helpers! There is a <logic> element that does all the magic:


<syntaxhighlight lang="xml">
  <logic>
  <logic>
   <name>Electrical Power</name>
   <name>Electrical Power</name>
Line 250: Line 271:
   <output>autopilot/servicable</output>
   <output>autopilot/servicable</output>
  </logic>
  </logic>
</syntaxhighlight>


This creates two boolean properties: has-power and serviceable, and sets them to true if the electrical system provides more than 10.0 volts. You can build complex logic tables to drive your analog stages of the autopilot.
This creates two boolean properties: has-power and serviceable, and sets them to true if the electrical system provides more than 10.0 volts. You can build complex logic tables to drive your analog stages of the autopilot.
Line 256: Line 278:
Now, that you have a ROC-hold mode, you most certainly want an altitude-hold with preselect. This will be a simple linear amplifier without any time dependencies. Again, you have to compare your current altitude with a reference value, but this time there will be no integrator involved. The bigger your offset from the reference altitude is, the bigger your rate of climb/descent should be. Let's assume, 1000ft offset should result in 500fpm ROC. The maximum rate of descent should be 1000fpm and the maximum rate of climb should be 2000fpm. Since there is no integrator involved, we use a simple gain filter to compute the rate of climb:
Now, that you have a ROC-hold mode, you most certainly want an altitude-hold with preselect. This will be a simple linear amplifier without any time dependencies. Again, you have to compare your current altitude with a reference value, but this time there will be no integrator involved. The bigger your offset from the reference altitude is, the bigger your rate of climb/descent should be. Let's assume, 1000ft offset should result in 500fpm ROC. The maximum rate of descent should be 1000fpm and the maximum rate of climb should be 2000fpm. Since there is no integrator involved, we use a simple gain filter to compute the rate of climb:


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Target Rate of Climb Computer (ALT HOLD)</name>
   <name>Target Rate of Climb Computer (ALT HOLD)</name>
Line 271: Line 294:
   <max>2000</max>
   <max>2000</max>
  </filter>
  </filter>
</syntaxhighlight>


If everything goes well, your chain of controllers for altitude hold looks something like this:
If everything goes well, your chain of controllers for altitude hold looks something like this:
Line 283: Line 307:
For heading hold, you build a two stage system. The first is a comparator comparing your selected heading and the indicated heading. 1. Stage, compute heading offset. Note the period element at the bottom, it normalizes the output into the periodic -180 to +180 range
For heading hold, you build a two stage system. The first is a comparator comparing your selected heading and the indicated heading. 1. Stage, compute heading offset. Note the period element at the bottom, it normalizes the output into the periodic -180 to +180 range


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Heading Offset Computer</name>
   <name>Heading Offset Computer</name>
Line 296: Line 321:
   </period>
   </period>
  </filter>
  </filter>
</syntaxhighlight>


The second stage computes a bank angle from a heading offset. At least for smaller planes, a rule of thumb says "roll out at half the bank angle". If you fly a right hand turn at a bank angle of, say, 20° and want to end at a heading of 270°, you start your roll out at 20°/2 = 10° before your target heading. So you start rolling out at 280°. We turn this rule around and say our bank angle is twice the heading error but not more that 30° This results in a simple gain filter. You might want to make the target roll computer switchable with an enable element, otherwise it will overwrite your target-roll-deg at all times.
The second stage computes a bank angle from a heading offset. At least for smaller planes, a rule of thumb says "roll out at half the bank angle". If you fly a right hand turn at a bank angle of, say, 20° and want to end at a heading of 270°, you start your roll out at 20°/2 = 10° before your target heading. So you start rolling out at 280°. We turn this rule around and say our bank angle is twice the heading error but not more that 30° This results in a simple gain filter. You might want to make the target roll computer switchable with an enable element, otherwise it will overwrite your target-roll-deg at all times.


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Target Roll Computer</name>
   <name>Target Roll Computer</name>
Line 313: Line 340:
   <max>30.0</max>
   <max>30.0</max>
  </filter>
  </filter>
</syntaxhighlight>


Most aircraft have pilot selectable bank-limits. You can implement these by editing the min and max options to something like this:
Most aircraft have pilot selectable bank-limits. You can implement these by editing the min and max options to something like this:


<syntaxhighlight lang="xml">
  ...
  ...
   <min>
   <min>
Line 323: Line 352:
   <max>/autopilot/settings/bank-limit</max>
   <max>/autopilot/settings/bank-limit</max>
  ...
  ...
</syntaxhighlight>


This filter feeds your wing leveler which is already done, but it requires a little edit in the <enable> and <reference> parts in order to obtain a pilot-selectable roll:
This filter feeds your wing leveler which is already done, but it requires a little edit in the <enable> and <reference> parts in order to obtain a pilot-selectable roll:


<syntaxhighlight lang="xml">
  ...
  ...
   <enable>
   <enable>
Line 337: Line 368:
   </reference>
   </reference>
  ...
  ...
</syntaxhighlight>


You can also play with the min/max values to have a nice standard rate turn. The bank angle for the standard turn is a function of your true airspeed; you can build a controller calculating the correct bank angle and feed this value into min/max (which is a commen feature on airliners).
You can also play with the min/max values to have a nice standard rate turn. The bank angle for the standard turn is a function of your true airspeed; you can build a controller calculating the correct bank angle and feed this value into min/max (which is a commen feature on airliners).
Line 364: Line 396:


First, add a new, switchable input element to your heading offset computer. Just change this:
First, add a new, switchable input element to your heading offset computer. Just change this:
<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Heading Offset Computer</name>
   <name>Heading Offset Computer</name>
Line 377: Line 410:
   </period>
   </period>
  </filter>
  </filter>
</syntaxhighlight>


to this (that is, adding the upper input part):
to this (that is, adding the upper input part):
<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Heading Offset Computer</name>
   <name>Heading Offset Computer</name>
Line 401: Line 436:
   </period>
   </period>
  </filter>
  </filter>
</syntaxhighlight>


Now, if /autopilot/locks/heading equals "nav1-hold", the heading offset computer uses the intercept-heading-deg property as the target heading to fly.For any other value, the old heading-bug value is used. You can already test, if it works. Use the property browser to set this stage to nav-hold and enter any arbitrary value into intercept-heading-deg. Your aircraft should turn to the entered heading on the shortest path. It is crucical that this mode is stable, so spend some time again and double check.
Now, if /autopilot/locks/heading equals "nav1-hold", the heading offset computer uses the intercept-heading-deg property as the target heading to fly.For any other value, the old heading-bug value is used. You can already test, if it works. Use the property browser to set this stage to nav-hold and enter any arbitrary value into intercept-heading-deg. Your aircraft should turn to the entered heading on the shortest path. It is crucical that this mode is stable, so spend some time again and double check.
Line 408: Line 444:
This is a very simple stage, it just substracts a course error (which we will compute in the next stage) from our selected course and normalizes the output into the [0..360] degree interval:
This is a very simple stage, it just substracts a course error (which we will compute in the next stage) from our selected course and normalizes the output into the [0..360] degree interval:


<syntaxhighlight lang="xml">
  <filter>
  <filter>
   <name>Intercept Heading Computer</name>
   <name>Intercept Heading Computer</name>
Line 421: Line 458:
   </period>
   </period>
  </filter>
  </filter>
</syntaxhighlight>


This stage only makes sense with a preceding one computing the course error from the cdi deflection. We want something that spits out 45 for a full CDI deflection and one might think of a <gain> filter to do this. But we also want an automatic wind correction in case of cross wind. For that we also need an integrator. Because we need to compute absolute values for the output, a pi-simple-controller is our choice here:
This stage only makes sense with a preceding one computing the course error from the cdi deflection. We want something that spits out 45 for a full CDI deflection and one might think of a <gain> filter to do this. But we also want an automatic wind correction in case of cross wind. For that we also need an integrator. Because we need to compute absolute values for the output, a pi-simple-controller is our choice here:


<syntaxhighlight lang="xml">
  <pi-simple-controller>
  <pi-simple-controller>
   <name>cdi-integrator</name>
   <name>cdi-integrator</name>
Line 436: Line 475:
   <max>45.0</max>
   <max>45.0</max>
  </pi-simple-controller>
  </pi-simple-controller>
</syntaxhighlight>


It takes our CDI deflection and compares to zero (note the missing reference element which defaults to zero). The result is multiplied by Kp (45) and a value of 0.4° per second is added to the offset. The output is clipped to 45°.
It takes our CDI deflection and compares to zero (note the missing reference element which defaults to zero). The result is multiplied by Kp (45) and a value of 0.4° per second is added to the offset. The output is clipped to 45°.

Navigation menu