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
29 I'd like to deprecate the so called autopilot helper function
30 (which is now part of the AutopilotGroup::update() method).
31 Every property calculated within this helper can be calculated
32 using filters defined in an external autopilot definition file.
33 The complete set of calculations may be extracted into a separate
34 configuration file. The current implementation is able to hande
35 multiple config files and autopilots. The helper doubles code
36 and writes properties used only by a few aircraft.
38 // FIXME: this should go into config.h and/or configure
39 // or removed along with the "helper" one day.
40 #define XMLAUTO_USEHELPER
42 #include <simgear/compiler.h>
48 #include <simgear/props/props.hxx>
49 #include <simgear/structure/subsystem_mgr.hxx>
54 typedef SGExpression<double> SGExpressiond;
57 typedef SGSharedPtr<class FGXMLAutoInput> FGXMLAutoInput_ptr;
58 typedef SGSharedPtr<class FGPeriodicalValue> FGPeriodicalValue_ptr;
60 class FGPeriodicalValue : public SGReferenced {
62 FGXMLAutoInput_ptr minPeriod; // The minimum value of the period
63 FGXMLAutoInput_ptr maxPeriod; // The maximum value of the period
65 FGPeriodicalValue( SGPropertyNode_ptr node );
66 double normalize( double value );
69 class FGXMLAutoInput : public SGReferenced {
71 double value; // The value as a constant or initializer for the property
72 bool abs; // return absolute value
73 SGPropertyNode_ptr property; // The name of the property containing the value
74 FGXMLAutoInput_ptr offset; // A fixed offset, defaults to zero
75 FGXMLAutoInput_ptr scale; // A constant scaling factor defaults to one
76 FGXMLAutoInput_ptr min; // A minimum clip defaults to no clipping
77 FGXMLAutoInput_ptr max; // A maximum clip defaults to no clipping
78 FGPeriodicalValue_ptr periodical; //
79 SGSharedPtr<const SGCondition> _condition;
80 SGSharedPtr<SGExpressiond> _expression; ///< expression to generate the value
83 FGXMLAutoInput( SGPropertyNode_ptr node = NULL, double value = 0.0, double offset = 0.0, double scale = 1.0 );
85 void parse( SGPropertyNode_ptr, double value = 0.0, double offset = 0.0, double scale = 1.0 );
87 /* get the value of this input, apply scale and offset and clipping */
90 /* set the input value after applying offset and scale */
91 void set_value( double value );
93 inline double get_scale() {
94 return scale == NULL ? 1.0 : scale->get_value();
97 inline double get_offset() {
98 return offset == NULL ? 0.0 : offset->get_value();
101 inline bool is_enabled() {
102 return _condition == NULL ? true : _condition->test();
107 class FGXMLAutoInputList : public std::vector<FGXMLAutoInput_ptr> {
109 FGXMLAutoInput_ptr get_active() {
110 for (iterator it = begin(); it != end(); ++it) {
111 if( (*it)->is_enabled() )
117 double get_value( double def = 0.0 ) {
118 FGXMLAutoInput_ptr input = get_active();
119 return input == NULL ? def : input->get_value();
125 * Base class for other autopilot components
128 class FGXMLAutoComponent : public SGReferenced {
131 simgear::PropertyList output_list;
133 SGSharedPtr<const SGCondition> _condition;
134 SGPropertyNode_ptr enable_prop;
135 std::string * enable_value;
137 SGPropertyNode_ptr passive_mode;
142 /* Feed back output property to input property if
143 this filter is disabled. This is for multi-stage
144 filter where one filter sits behind a pid-controller
145 to provide changes of the overall output to the pid-
147 feedback is disabled by default.
149 bool feedback_if_disabled;
150 void do_feedback_if_disabled();
153 FGXMLAutoComponent();
156 * Parse a component specification read from a property-list.
157 * Calls the hook methods below to allow derived classes to
158 * specialise parsing bevaiour.
160 void parseNode(SGPropertyNode* aNode);
163 * Helper to parse the config section
165 void parseConfig(SGPropertyNode* aConfig);
168 * Over-rideable hook method to allow derived classes to refine top-level
169 * node parsing. Return true if the node was handled, false otherwise.
171 virtual bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
174 * Over-rideable hook method to allow derived classes to refine config
175 * node parsing. Return true if the node was handled, false otherwise.
177 virtual bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
179 FGXMLAutoInputList valueInput;
180 FGXMLAutoInputList referenceInput;
181 FGXMLAutoInputList uminInput;
182 FGXMLAutoInputList umaxInput;
183 FGPeriodicalValue_ptr periodical;
189 inline void do_feedback() {
190 if( feedback_if_disabled ) do_feedback_if_disabled();
195 virtual ~FGXMLAutoComponent();
197 virtual void update (double dt)=0;
199 inline const std::string& get_name() { return name; }
201 double clamp( double value );
203 inline void set_output_value( double value ) {
204 // passive_ignore == true means that we go through all the
205 // motions, but drive the outputs. This is analogous to
206 // running the autopilot with the "servos" off. This is
207 // helpful for things like flight directors which position
208 // their vbars from the autopilot computations.
209 if ( honor_passive && passive_mode->getBoolValue() ) return;
210 for( simgear::PropertyList::iterator it = output_list.begin();
211 it != output_list.end(); ++it)
212 (*it)->setDoubleValue( clamp( value ) );
215 inline void set_output_value( bool value ) {
216 // passive_ignore == true means that we go through all the
217 // motions, but drive the outputs. This is analogous to
218 // running the autopilot with the "servos" off. This is
219 // helpful for things like flight directors which position
220 // their vbars from the autopilot computations.
221 if ( honor_passive && passive_mode->getBoolValue() ) return;
222 for( simgear::PropertyList::iterator it = output_list.begin();
223 it != output_list.end(); ++it)
224 (*it)->setBoolValue( value ); // don't use clamp here, bool is clamped anyway
227 inline double get_output_value() {
228 return output_list.size() == 0 ? 0.0 : clamp(output_list[0]->getDoubleValue());
231 inline bool get_bool_output_value() {
232 return output_list.size() == 0 ? false : output_list[0]->getBoolValue();
236 Returns true if the enable-condition is true.
238 If a <condition> is defined, this condition is evaluated,
239 <prop> and <value> tags are ignored.
241 If a <prop> is defined and no <value> is defined, the property
242 named in the <prop></prop> tags is evaluated as boolean.
244 If a <prop> is defined a a <value> is defined, the property named
245 in <prop></prop> is compared (as a string) to the value defined in
248 Returns true, if neither <condition> nor <prop> exists
251 Using a <condition> tag
254 <!-- any legal condition goes here and is evaluated -->
256 <prop>This is ignored</prop>
257 <value>This is also ignored</value>
260 Using a single boolean property
262 <prop>/some/property/that/is/evaluated/as/boolean</prop>
265 Using <prop> == <value>
266 This is the old style behaviour
268 <prop>/only/true/if/this/equals/true</prop>
272 bool isPropertyEnabled();
275 typedef SGSharedPtr<FGXMLAutoComponent> FGXMLAutoComponent_ptr;
279 * Roy Ovesen's PID controller
282 class FGPIDController : public FGXMLAutoComponent {
287 // Configuration values
288 FGXMLAutoInputList Kp; // proportional gain
289 FGXMLAutoInputList Ti; // Integrator time (sec)
290 FGXMLAutoInputList Td; // Derivator time (sec)
292 double alpha; // low pass filter weighing factor (usually 0.1)
293 double beta; // process value weighing factor for
294 // calculating proportional error
296 double gamma; // process value weighing factor for
297 // calculating derivative error
300 // Previous state tracking values
301 double ep_n_1; // ep[n-1] (prop error)
302 double edf_n_1; // edf[n-1] (derivative error)
303 double edf_n_2; // edf[n-2] (derivative error)
304 double u_n_1; // u[n-1] (output)
305 double desiredTs; // desired sampling interval (sec)
306 double elapsedTime; // elapsed time (sec)
310 bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
314 FGPIDController( SGPropertyNode *node );
315 FGPIDController( SGPropertyNode *node, bool old );
316 ~FGPIDController() {}
318 void update( double dt );
323 * A simplistic P [ + I ] PID controller
326 class FGPISimpleController : public FGXMLAutoComponent {
330 // proportional component data
331 FGXMLAutoInputList Kp;
333 // integral component data
334 FGXMLAutoInputList Ki;
338 bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode);
342 FGPISimpleController( SGPropertyNode *node );
343 ~FGPISimpleController() {}
345 void update( double dt );
350 * Predictor - calculates value in x seconds future.
353 class FGPredictor : public FGXMLAutoComponent {
358 FGXMLAutoInputList seconds;
359 FGXMLAutoInputList filter_gain;
362 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
365 FGPredictor( SGPropertyNode *node );
368 void update( double dt );
373 * FGDigitalFilter - a selection of digital filters
376 * Double exponential filter
377 * Moving average filter
380 * All these filters are low-pass filters.
384 class FGDigitalFilter : public FGXMLAutoComponent
387 FGXMLAutoInputList samplesInput; // Number of input samples to average
388 FGXMLAutoInputList rateOfChangeInput; // The maximum allowable rate of change [1/s]
389 FGXMLAutoInputList gainInput; //
390 FGXMLAutoInputList TfInput; // Filter time [s]
392 std::deque <double> output;
393 std::deque <double> input;
394 enum FilterTypes { exponential, doubleExponential, movingAverage,
395 noiseSpike, gain, reciprocal, differential, none };
396 FilterTypes filterType;
399 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
402 FGDigitalFilter(SGPropertyNode *node);
403 ~FGDigitalFilter() {}
405 void update(double dt);
408 class FGXMLAutoLogic : public FGXMLAutoComponent
411 SGSharedPtr<SGCondition> input;
415 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
418 FGXMLAutoLogic(SGPropertyNode * node );
421 void update(double dt);
424 class FGXMLAutoFlipFlop : public FGXMLAutoComponent
428 SGSharedPtr<SGCondition> sInput;
429 SGSharedPtr<SGCondition> rInput;
430 SGSharedPtr<SGCondition> clockInput;
431 SGSharedPtr<SGCondition> jInput;
432 SGSharedPtr<SGCondition> kInput;
433 SGSharedPtr<SGCondition> dInput;
435 FGXMLAutoFlipFlop( SGPropertyNode * node );
436 bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
438 void update( double dt );
441 ~FGXMLAutoFlipFlop() {};
442 virtual bool getState( bool & result ) = 0;
446 * Model an autopilot system.
450 class FGXMLAutopilotGroup : public SGSubsystemGroup
453 FGXMLAutopilotGroup();
456 void update( double dt );
458 std::vector<std::string> _autopilotNames;
460 #ifdef XMLAUTO_USEHELPER
463 double last_static_pressure;
465 SGPropertyNode_ptr vel;
466 SGPropertyNode_ptr lookahead5;
467 SGPropertyNode_ptr lookahead10;
468 SGPropertyNode_ptr bug;
469 SGPropertyNode_ptr mag_hdg;
470 SGPropertyNode_ptr bug_error;
471 SGPropertyNode_ptr fdm_bug_error;
472 SGPropertyNode_ptr target_true;
473 SGPropertyNode_ptr true_hdg;
474 SGPropertyNode_ptr true_error;
475 SGPropertyNode_ptr target_nav1;
476 SGPropertyNode_ptr true_nav1;
477 SGPropertyNode_ptr true_track_nav1;
478 SGPropertyNode_ptr nav1_course_error;
479 SGPropertyNode_ptr nav1_selected_course;
480 SGPropertyNode_ptr vs_fps;
481 SGPropertyNode_ptr vs_fpm;
482 SGPropertyNode_ptr static_pressure;
483 SGPropertyNode_ptr pressure_rate;
484 SGPropertyNode_ptr track;
488 class FGXMLAutopilot : public SGSubsystem
500 void update( double dt );
503 bool build( SGPropertyNode_ptr );
505 typedef std::vector<FGXMLAutoComponent_ptr> comp_list;
509 comp_list components;
514 #endif // _XMLAUTO_HXX