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
27 #include <simgear/compiler.h>
33 #include <simgear/props/props.hxx>
34 #include <simgear/structure/subsystem_mgr.hxx>
35 #include <simgear/props/condition.hxx>
37 typedef SGSharedPtr<class FGXMLAutoInput> FGXMLAutoInput_ptr;
38 typedef SGSharedPtr<class FGPeriodicalValue> FGPeriodicalValue_ptr;
40 class FGPeriodicalValue : public SGReferenced {
42 FGXMLAutoInput_ptr minPeriod; // The minimum value of the period
43 FGXMLAutoInput_ptr maxPeriod; // The maximum value of the period
45 FGPeriodicalValue( SGPropertyNode_ptr node );
46 double normalize( double value );
49 class FGXMLAutoInput : public SGReferenced {
51 double value; // The value as a constant or initializer for the property
52 bool abs; // return absolute value
53 SGPropertyNode_ptr property; // The name of the property containing the value
54 FGXMLAutoInput_ptr offset; // A fixed offset, defaults to zero
55 FGXMLAutoInput_ptr scale; // A constant scaling factor defaults to one
56 FGXMLAutoInput_ptr min; // A minimum clip defaults to no clipping
57 FGXMLAutoInput_ptr max; // A maximum clip defaults to no clipping
58 FGPeriodicalValue_ptr periodical; //
59 SGSharedPtr<const SGCondition> _condition;
62 FGXMLAutoInput( SGPropertyNode_ptr node = NULL, double value = 0.0, double offset = 0.0, double scale = 1.0 );
64 void parse( SGPropertyNode_ptr, double value = 0.0, double offset = 0.0, double scale = 1.0 );
66 /* get the value of this input, apply scale and offset and clipping */
69 /* set the input value after applying offset and scale */
70 void set_value( double value );
72 inline double get_scale() {
73 return scale == NULL ? 1.0 : scale->get_value();
76 inline double get_offset() {
77 return offset == NULL ? 0.0 : offset->get_value();
80 inline bool is_enabled() {
81 return _condition == NULL ? true : _condition->test();
86 class FGXMLAutoInputList : public std::vector<FGXMLAutoInput_ptr> {
88 FGXMLAutoInput_ptr get_active() {
89 for (iterator it = begin(); it != end(); ++it) {
90 if( (*it)->is_enabled() )
96 double get_value( double def = 0.0 ) {
97 FGXMLAutoInput_ptr input = get_active();
98 return input == NULL ? def : input->get_value();
104 * Base class for other autopilot components
107 class FGXMLAutoComponent : public SGReferenced {
110 std::vector <SGPropertyNode_ptr> output_list;
112 SGSharedPtr<const SGCondition> _condition;
113 SGPropertyNode_ptr enable_prop;
114 std::string * enable_value;
116 SGPropertyNode_ptr passive_mode;
121 /* Feed back output property to input property if
122 this filter is disabled. This is for multi-stage
123 filter where one filter sits behind a pid-controller
124 to provide changes of the overall output to the pid-
126 feedback is disabled by default.
128 bool feedback_if_disabled;
129 void do_feedback_if_disabled();
132 FGXMLAutoComponent();
135 * Parse a component specification read from a property-list.
136 * Calls the hook methods below to allow derived classes to
137 * specialise parsing bevaiour.
139 void parseNode(SGPropertyNode* aNode);
142 * Helper to parse the config section
144 void parseConfig(SGPropertyNode* aConfig);
147 * Over-rideable hook method to allow derived classes to refine top-level
148 * node parsing. Return true if the node was handled, false otherwise.
150 virtual bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
153 * Over-rideable hook method to allow derived classes to refine config
154 * node parsing. Return true if the node was handled, false otherwise.
156 virtual bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
158 FGXMLAutoInputList valueInput;
159 FGXMLAutoInputList referenceInput;
160 FGXMLAutoInputList uminInput;
161 FGXMLAutoInputList umaxInput;
162 FGPeriodicalValue_ptr periodical;
168 inline void do_feedback() {
169 if( feedback_if_disabled ) do_feedback_if_disabled();
174 virtual ~FGXMLAutoComponent();
176 virtual void update (double dt)=0;
178 inline const std::string& get_name() { return name; }
180 double clamp( double value );
182 inline void set_output_value( double value ) {
183 // passive_ignore == true means that we go through all the
184 // motions, but drive the outputs. This is analogous to
185 // running the autopilot with the "servos" off. This is
186 // helpful for things like flight directors which position
187 // their vbars from the autopilot computations.
188 if ( honor_passive && passive_mode->getBoolValue() ) return;
189 for( std::vector <SGPropertyNode_ptr>::iterator it = output_list.begin(); it != output_list.end(); ++it)
190 (*it)->setDoubleValue( clamp( value ) );
193 inline double get_output_value() {
194 return output_list.size() == 0 ? 0.0 : clamp(output_list[0]->getDoubleValue());
198 Returns true if the enable-condition is true.
200 If a <condition> is defined, this condition is evaluated,
201 <prop> and <value> tags are ignored.
203 If a <prop> is defined and no <value> is defined, the property
204 named in the <prop></prop> tags is evaluated as boolean.
206 If a <prop> is defined a a <value> is defined, the property named
207 in <prop></prop> is compared (as a string) to the value defined in
210 Returns true, if neither <condition> nor <prop> exists
213 Using a <condition> tag
216 <!-- any legal condition goes here and is evaluated -->
218 <prop>This is ignored</prop>
219 <value>This is also ignored</value>
222 Using a single boolean property
224 <prop>/some/property/that/is/evaluated/as/boolean</prop>
227 Using <prop> == <value>
228 This is the old style behaviour
230 <prop>/only/true/if/this/equals/true</prop>
234 bool isPropertyEnabled();
237 typedef SGSharedPtr<FGXMLAutoComponent> FGXMLAutoComponent_ptr;
241 * Roy Ovesen's PID controller
244 class FGPIDController : public FGXMLAutoComponent {
249 // Configuration values
250 FGXMLAutoInputList Kp; // proportional gain
251 FGXMLAutoInputList Ti; // Integrator time (sec)
252 FGXMLAutoInputList Td; // Derivator time (sec)
254 double alpha; // low pass filter weighing factor (usually 0.1)
255 double beta; // process value weighing factor for
256 // calculating proportional error
258 double gamma; // process value weighing factor for
259 // calculating derivative error
262 // Previous state tracking values
263 double ep_n_1; // ep[n-1] (prop error)
264 double edf_n_1; // edf[n-1] (derivative error)
265 double edf_n_2; // edf[n-2] (derivative error)
266 double u_n_1; // u[n-1] (output)
267 double desiredTs; // desired sampling interval (sec)
268 double elapsedTime; // elapsed time (sec)
272 bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
276 FGPIDController( SGPropertyNode *node );
277 FGPIDController( SGPropertyNode *node, bool old );
278 ~FGPIDController() {}
280 void update( double dt );
285 * A simplistic P [ + I ] PID controller
288 class FGPISimpleController : public FGXMLAutoComponent {
292 // proportional component data
293 FGXMLAutoInputList Kp;
295 // integral component data
296 FGXMLAutoInputList Ki;
300 bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
304 FGPISimpleController( SGPropertyNode *node );
305 ~FGPISimpleController() {}
307 void update( double dt );
312 * Predictor - calculates value in x seconds future.
315 class FGPredictor : public FGXMLAutoComponent {
320 FGXMLAutoInputList seconds;
321 FGXMLAutoInputList filter_gain;
324 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
327 FGPredictor( SGPropertyNode *node );
330 void update( double dt );
335 * FGDigitalFilter - a selection of digital filters
338 * Double exponential filter
339 * Moving average filter
342 * All these filters are low-pass filters.
346 class FGDigitalFilter : public FGXMLAutoComponent
349 FGXMLAutoInputList samplesInput; // Number of input samples to average
350 FGXMLAutoInputList rateOfChangeInput; // The maximum allowable rate of change [1/s]
351 FGXMLAutoInputList gainInput; //
352 FGXMLAutoInputList TfInput; // Filter time [s]
354 std::deque <double> output;
355 std::deque <double> input;
356 enum filterTypes { exponential, doubleExponential, movingAverage,
357 noiseSpike, gain, reciprocal, none };
358 filterTypes filterType;
361 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
364 FGDigitalFilter(SGPropertyNode *node);
365 ~FGDigitalFilter() {}
367 void update(double dt);
371 * Model an autopilot system.
375 class FGXMLAutopilotGroup : public SGSubsystemGroup
378 FGXMLAutopilotGroup();
382 std::vector<std::string> _autopilotNames;
385 class FGXMLAutopilot : public SGSubsystem
397 void update( double dt );
400 bool build( SGPropertyNode_ptr );
402 typedef std::vector<FGXMLAutoComponent_ptr> comp_list;
407 comp_list components;
411 #endif // _XMLAUTO_HXX