1 // xmlauto.hxx - a more flexible, generic way to build autopilots
3 // Written by Curtis Olson, started January 2004.
5 // Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #define _XMLAUTO_HXX 1
28 # error This library requires C++
35 #include <simgear/compiler.h>
45 #include <simgear/props/props.hxx>
46 #include <simgear/structure/subsystem_mgr.hxx>
47 #include <simgear/props/condition.hxx>
49 #include <Main/fg_props.hxx>
52 class FGXMLAutoInput : public SGReferenced {
54 double value; // The value as a constant or initializer for the property
55 bool abs; // return absolute value
56 SGPropertyNode_ptr property; // The name of the property containing the value
57 SGSharedPtr<FGXMLAutoInput> offset; // A fixed offset, defaults to zero
58 SGSharedPtr<FGXMLAutoInput> scale; // A constant scaling factor defaults to one
59 SGSharedPtr<FGXMLAutoInput> min; // A minimum clip defaults to no clipping
60 SGSharedPtr<FGXMLAutoInput> max; // A maximum clip defaults to no clipping
61 SGSharedPtr<const SGCondition> _condition;
64 FGXMLAutoInput( SGPropertyNode_ptr node = NULL, double value = 0.0, double offset = 0.0, double scale = 1.0 ) :
73 parse( node, value, offset, scale );
76 void parse( SGPropertyNode_ptr, double value = 0.0, double offset = 0.0, double scale = 1.0 );
78 /* get the value of this input, apply scale and offset and clipping */
81 /* set the input value after applying offset and scale */
82 void set_value( double value );
84 inline double get_scale() {
85 return scale == NULL ? 1.0 : scale->get_value();
88 inline double get_offset() {
89 return offset == NULL ? 0.0 : offset->get_value();
92 inline bool is_enabled() {
93 return _condition == NULL ? true : _condition->test();
98 class FGXMLAutoInputList : public vector<SGSharedPtr<FGXMLAutoInput> > {
100 FGXMLAutoInput * get_active() {
101 for (iterator it = begin(); it != end(); ++it) {
102 if( (*it)->is_enabled() )
108 double get_value( double def = 0.0 ) {
109 FGXMLAutoInput * input = get_active();
110 return input == NULL ? def : input->get_value();
116 * Base class for other autopilot components
119 class FGXMLAutoComponent : public SGReferenced {
122 vector <SGPropertyNode_ptr> output_list;
124 SGSharedPtr<const SGCondition> _condition;
125 SGPropertyNode_ptr enable_prop;
126 string * enable_value;
128 SGPropertyNode_ptr passive_mode;
133 /* Feed back output property to input property if
134 this filter is disabled. This is for multi-stage
135 filter where one filter sits behind a pid-controller
136 to provide changes of the overall output to the pid-
138 feedback is disabled by default.
140 bool feedback_if_disabled;
141 void do_feedback_if_disabled();
145 FGXMLAutoInputList valueInput;
146 FGXMLAutoInputList referenceInput;
147 FGXMLAutoInputList uminInput;
148 FGXMLAutoInputList umaxInput;
154 inline void do_feedback() {
155 if( feedback_if_disabled ) do_feedback_if_disabled();
160 FGXMLAutoComponent( SGPropertyNode *node);
161 virtual ~FGXMLAutoComponent();
163 virtual void update (double dt)=0;
165 inline const string& get_name() { return name; }
167 double clamp( double value );
169 inline void set_output_value( double value ) {
170 // passive_ignore == true means that we go through all the
171 // motions, but drive the outputs. This is analogous to
172 // running the autopilot with the "servos" off. This is
173 // helpful for things like flight directors which position
174 // their vbars from the autopilot computations.
175 if ( honor_passive && passive_mode->getBoolValue() ) return;
176 for( vector <SGPropertyNode_ptr>::iterator it = output_list.begin(); it != output_list.end(); ++it)
177 (*it)->setDoubleValue( clamp( value ) );
180 inline double get_output_value() {
181 return output_list.size() == 0 ? 0.0 : clamp(output_list[0]->getDoubleValue());
185 Returns true if the enable-condition is true.
187 If a <condition> is defined, this condition is evaluated,
188 <prop> and <value> tags are ignored.
190 If a <prop> is defined and no <value> is defined, the property
191 named in the <prop></prop> tags is evaluated as boolean.
193 If a <prop> is defined a a <value> is defined, the property named
194 in <prop></prop> is compared (as a string) to the value defined in
197 Returns true, if neither <condition> nor <prop> exists
200 Using a <condition> tag
203 <!-- any legal condition goes here and is evaluated -->
205 <prop>This is ignored</prop>
206 <value>This is also ignored</value>
209 Using a single boolean property
211 <prop>/some/property/that/is/evaluated/as/boolean</prop>
214 Using <prop> == <value>
215 This is the old style behaviour
217 <prop>/only/true/if/this/equals/true</prop>
221 bool isPropertyEnabled();
226 * Roy Ovesen's PID controller
229 class FGPIDController : public FGXMLAutoComponent {
234 // Configuration values
235 FGXMLAutoInputList Kp; // proportional gain
236 FGXMLAutoInputList Ti; // Integrator time (sec)
237 FGXMLAutoInputList Td; // Derivator time (sec)
239 double alpha; // low pass filter weighing factor (usually 0.1)
240 double beta; // process value weighing factor for
241 // calculating proportional error
243 double gamma; // process value weighing factor for
244 // calculating derivative error
247 // Previous state tracking values
248 double ep_n_1; // ep[n-1] (prop error)
249 double edf_n_1; // edf[n-1] (derivative error)
250 double edf_n_2; // edf[n-2] (derivative error)
251 double u_n_1; // u[n-1] (output)
252 double desiredTs; // desired sampling interval (sec)
253 double elapsedTime; // elapsed time (sec)
259 FGPIDController( SGPropertyNode *node );
260 FGPIDController( SGPropertyNode *node, bool old );
261 ~FGPIDController() {}
263 void update( double dt );
268 * A simplistic P [ + I ] PID controller
271 class FGPISimpleController : public FGXMLAutoComponent {
275 // proportional component data
276 FGXMLAutoInputList Kp;
278 // integral component data
279 FGXMLAutoInputList Ki;
285 FGPISimpleController( SGPropertyNode *node );
286 ~FGPISimpleController() {}
288 void update( double dt );
293 * Predictor - calculates value in x seconds future.
296 class FGPredictor : public FGXMLAutoComponent {
300 FGXMLAutoInputList seconds;
301 FGXMLAutoInputList filter_gain;
304 FGPredictor( SGPropertyNode *node );
307 void update( double dt );
312 * FGDigitalFilter - a selection of digital filters
315 * Double exponential filter
316 * Moving average filter
319 * All these filters are low-pass filters.
323 class FGDigitalFilter : public FGXMLAutoComponent
326 FGXMLAutoInputList samplesInput; // Number of input samples to average
327 FGXMLAutoInputList rateOfChangeInput; // The maximum allowable rate of change [1/s]
328 FGXMLAutoInputList gainInput; //
329 FGXMLAutoInputList TfInput; // Filter time [s]
331 deque <double> output;
332 deque <double> input;
333 enum filterTypes { exponential, doubleExponential, movingAverage,
334 noiseSpike, gain, reciprocal, none };
335 filterTypes filterType;
338 FGDigitalFilter(SGPropertyNode *node);
339 ~FGDigitalFilter() {}
341 void update(double dt);
345 * Model an autopilot system.
349 class FGXMLAutopilot : public SGSubsystem
361 void update( double dt );
367 typedef vector<SGSharedPtr<FGXMLAutoComponent> > comp_list;
372 SGPropertyNode_ptr config_props;
373 comp_list components;
377 #endif // _XMLAUTO_HXX