]> git.mxchange.org Git - flightgear.git/blobdiff - src/Autopilot/xmlauto.cxx
James Turner:
[flightgear.git] / src / Autopilot / xmlauto.cxx
index 243cd9568308fc14b17cac886a70e42a49a341a6..17ea68cbaf949a4a7ee28f4f1488fea24a084a1d 100644 (file)
 //
 // $Id$
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <iostream>
 
 #include <simgear/structure/exception.hxx>
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/sg_inlines.h>
+#include <simgear/props/props_io.hxx>
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
@@ -31,6 +37,8 @@
 
 #include "xmlauto.hxx"
 
+using std::cout;
+using std::endl;
 
 FGPIDController::FGPIDController( SGPropertyNode *node ):
     debug( false ),
@@ -52,7 +60,8 @@ FGPIDController::FGPIDController( SGPropertyNode *node ):
     edf_n_1( 0.0 ),
     edf_n_2( 0.0 ),
     u_n_1( 0.0 ),
-    desiredTs( 0.0 )
+    desiredTs( 0.0 ),
+    elapsedTime( 0.0 )
 {
     int i;
     for ( i = 0; i < node->nChildren(); ++i ) {
@@ -76,6 +85,10 @@ FGPIDController::FGPIDController( SGPropertyNode *node ):
             if ( val != NULL ) {
                 enable_value = val->getStringValue();
             }
+            SGPropertyNode *pass = child->getChild( "honor-passive" );
+            if ( pass != NULL ) {
+                honor_passive = pass->getBoolValue();
+            }
         } else if ( cname == "input" ) {
             SGPropertyNode *prop = child->getChild( "prop" );
             if ( prop != NULL ) {
@@ -96,7 +109,7 @@ FGPIDController::FGPIDController( SGPropertyNode *node ):
             } else {
                 prop = child->getChild( "value" );
                 if ( prop != NULL ) {
-                    r_n = prop->getDoubleValue();
+                    r_n_value = prop->getDoubleValue();
                 }
             }
             prop = child->getChild( "scale" );
@@ -116,51 +129,151 @@ FGPIDController::FGPIDController( SGPropertyNode *node ):
                 i++;
             }
         } else if ( cname == "config" ) {
-            SGPropertyNode *prop;
+            SGPropertyNode *config;
 
-            prop = child->getChild( "Ts" );
-            if ( prop != NULL ) {
-                desiredTs = prop->getDoubleValue();
+            config = child->getChild( "Ts" );
+            if ( config != NULL ) {
+                desiredTs = config->getDoubleValue();
             }
             
-            prop = child->getChild( "Kp" );
-            if ( prop != NULL ) {
-                Kp = prop->getDoubleValue();
+            config = child->getChild( "Kp" );
+            if ( config != NULL ) {
+                SGPropertyNode *val = config->getChild( "value" );
+                if ( val != NULL ) {
+                    Kp = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop = config->getChild( "prop" );
+                if ( prop != NULL ) {
+                    Kp_prop = fgGetNode( prop->getStringValue(), true );
+                    if ( val != NULL ) {
+                        Kp_prop->setDoubleValue(Kp);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop == NULL) {
+                    Kp = config->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated Kp config. Please use <prop> and/or <value> tags." );
+                    if ( name.length() ) {
+                        SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+                    }
+                }
             }
 
-            prop = child->getChild( "beta" );
-            if ( prop != NULL ) {
-                beta = prop->getDoubleValue();
+            config = child->getChild( "beta" );
+            if ( config != NULL ) {
+                beta = config->getDoubleValue();
             }
 
-            prop = child->getChild( "alpha" );
-            if ( prop != NULL ) {
-                alpha = prop->getDoubleValue();
+            config = child->getChild( "alpha" );
+            if ( config != NULL ) {
+                alpha = config->getDoubleValue();
             }
 
-            prop = child->getChild( "gamma" );
-            if ( prop != NULL ) {
-                gamma = prop->getDoubleValue();
+            config = child->getChild( "gamma" );
+            if ( config != NULL ) {
+                gamma = config->getDoubleValue();
             }
 
-            prop = child->getChild( "Ti" );
-            if ( prop != NULL ) {
-                Ti = prop->getDoubleValue();
+            config = child->getChild( "Ti" );
+            if ( config != NULL ) {
+                SGPropertyNode *val = config->getChild( "value" );
+                if ( val != NULL ) {
+                    Ti = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop = config->getChild( "prop" );
+                if ( prop != NULL ) {
+                    Ti_prop = fgGetNode( prop->getStringValue(), true );
+                    if ( val != NULL ) {
+                        Ti_prop->setDoubleValue(Kp);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop == NULL) {
+                Ti = config->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated Ti config. Please use <prop> and/or <value> tags." );
+                    if ( name.length() ) {
+                        SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+                    }
+                }
             }
 
-            prop = child->getChild( "Td" );
-            if ( prop != NULL ) {
-                Td = prop->getDoubleValue();
+            config = child->getChild( "Td" );
+            if ( config != NULL ) {
+                SGPropertyNode *val = config->getChild( "value" );
+                if ( val != NULL ) {
+                    Td = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop = config->getChild( "prop" );
+                if ( prop != NULL ) {
+                    Td_prop = fgGetNode( prop->getStringValue(), true );
+                    if ( val != NULL ) {
+                        Td_prop->setDoubleValue(Kp);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop == NULL) {
+                Td = config->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated Td config. Please use <prop> and/or <value> tags." );
+                    if ( name.length() ) {
+                        SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+                    }
+                }
             }
 
-            prop = child->getChild( "u_min" );
-            if ( prop != NULL ) {
-                u_min = prop->getDoubleValue();
+            config = child->getChild( "u_min" );
+            if ( config != NULL ) {
+                SGPropertyNode *val = config->getChild( "value" );
+                if ( val != NULL ) {
+                    u_min = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop = config->getChild( "prop" );
+                if ( prop != NULL ) {
+                    umin_prop = fgGetNode( prop->getStringValue(), true );
+                    if ( val != NULL ) {
+                        umin_prop->setDoubleValue(u_min);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop == NULL) {
+                u_min = config->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated u_min config. Please use <prop> and/or <value> tags." );
+                    if ( name.length() ) {
+                        SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+                    }
+                }
             }
 
-            prop = child->getChild( "u_max" );
-            if ( prop != NULL ) {
-                u_max = prop->getDoubleValue();
+            config = child->getChild( "u_max" );
+            if ( config != NULL ) {
+                SGPropertyNode *val = config->getChild( "value" );
+                if ( val != NULL ) {
+                    u_max = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop = config->getChild( "prop" );
+                if ( prop != NULL ) {
+                    umax_prop = fgGetNode( prop->getStringValue(), true );
+                    if ( val != NULL ) {
+                        umax_prop->setDoubleValue(u_max);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop == NULL) {
+                u_max = config->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated u_max config. Please use <prop> and/or <value> tags." );
+                    if ( name.length() ) {
+                        SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << name );
+                    }
+                }
             }
         } else {
             SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in autopilot config logic" );
@@ -232,6 +345,10 @@ void FGPIDController::update( double dt ) {
     double delta_u_n = 0.0; // incremental output
     double u_n = 0.0;       // absolute output
     double Ts;              // sampling interval (sec)
+    if (umin_prop != NULL)u_min = umin_prop->getDoubleValue();
+    if (umax_prop != NULL)u_max = umax_prop->getDoubleValue();
+    if (Ti_prop != NULL)Ti = Ti_prop->getDoubleValue();
+    if (Td_prop != NULL)Td = Td_prop->getDoubleValue();
     
     elapsedTime += dt;
     if ( elapsedTime <= desiredTs ) {
@@ -303,6 +420,9 @@ void FGPIDController::update( double dt ) {
 
         // Calculates the incremental output:
         if ( Ti > 0.0 ) {
+            if (Kp_prop != NULL) {
+                Kp = Kp_prop->getDoubleValue();
+            }
             delta_u_n = Kp * ( (ep_n - ep_n_1)
                                + ((Ts/Ti) * e_n)
                                + ((Td/Ts) * (edf_n - 2*edf_n_1 + edf_n_2)) );
@@ -335,9 +455,18 @@ void FGPIDController::update( double dt ) {
         edf_n_2 = edf_n_1;
         edf_n_1 = edf_n;
 
-        unsigned int i;
-        for ( i = 0; i < output_list.size(); ++i ) {
-            output_list[i]->setDoubleValue( u_n );
+        // passive_ignore == true means that we go through all the
+        // motions, but drive the outputs.  This is analogous to
+        // running the autopilot with the "servos" off.  This is
+        // helpful for things like flight directors which position
+        // their vbars from the autopilot computations.
+        if ( passive_mode->getBoolValue() && honor_passive ) {
+            // skip output step
+        } else {
+            unsigned int i;
+            for ( i = 0; i < output_list.size(); ++i ) {
+                output_list[i]->setDoubleValue( u_n );
+            }
         }
     } else if ( !enabled ) {
         ep_n  = 0.0;
@@ -406,7 +535,7 @@ FGPISimpleController::FGPISimpleController( SGPropertyNode *node ):
             } else {
                 prop = child->getChild( "value" );
                 if ( prop != NULL ) {
-                    r_n = prop->getDoubleValue();
+                    r_n_value = prop->getDoubleValue();
                 }
             }
             prop = child->getChild( "scale" );
@@ -426,7 +555,24 @@ FGPISimpleController::FGPISimpleController( SGPropertyNode *node ):
 
             prop = child->getChild( "Kp" );
             if ( prop != NULL ) {
+                SGPropertyNode *val = prop->getChild( "value" );
+                if ( val != NULL ) {
+                    Kp = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop1 = prop->getChild( "prop" );
+                if ( prop1 != NULL ) {
+                    Kp_prop = fgGetNode( prop1->getStringValue(), true );
+                    if ( val != NULL ) {
+                        Kp_prop->setDoubleValue(Kp);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop1 == NULL) {
                 Kp = prop->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated Kp config. Please use <prop> and/or <value> tags." );
+                }
                 proportional = true;
             }
 
@@ -438,13 +584,47 @@ FGPISimpleController::FGPISimpleController( SGPropertyNode *node ):
 
             prop = child->getChild( "u_min" );
             if ( prop != NULL ) {
+                SGPropertyNode *val = prop->getChild( "value" );
+                if ( val != NULL ) {
+                    u_min = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop1 = prop->getChild( "prop" );
+                if ( prop1 != NULL ) {
+                    umin_prop = fgGetNode( prop1->getStringValue(), true );
+                    if ( val != NULL ) {
+                        umin_prop->setDoubleValue(u_min);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop1 == NULL) {
                 u_min = prop->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated u_min config. Please use <prop> and/or <value> tags." );
+                }
                 clamp = true;
             }
 
             prop = child->getChild( "u_max" );
             if ( prop != NULL ) {
+                SGPropertyNode *val = prop->getChild( "value" );
+                if ( val != NULL ) {
+                    u_max = val->getDoubleValue();
+                }
+
+                SGPropertyNode *prop1 = prop->getChild( "prop" );
+                if ( prop1 != NULL ) {
+                    umax_prop = fgGetNode( prop1->getStringValue(), true );
+                    if ( val != NULL ) {
+                        umax_prop->setDoubleValue(u_max);
+                    }
+                }
+
+                // output deprecated usage warning
+                if (val == NULL && prop1 == NULL) {
                 u_max = prop->getDoubleValue();
+                    SG_LOG( SG_AUTOPILOT, SG_WARN, "Deprecated u_max config. Please use <prop> and/or <value> tags." );
+                }
                 clamp = true;
             }
         } else {
@@ -458,6 +638,10 @@ FGPISimpleController::FGPISimpleController( SGPropertyNode *node ):
 
 
 void FGPISimpleController::update( double dt ) {
+    if (umin_prop != NULL)u_min = umin_prop->getDoubleValue();
+    if (umax_prop != NULL)u_max = umax_prop->getDoubleValue();
+    if (Kp_prop != NULL)Kp = Kp_prop->getDoubleValue();
+
     if (enable_prop != NULL && enable_prop->getStringValue() == enable_value) {
         if ( !enabled ) {
             // we have just been enabled, zero out int_sum
@@ -610,10 +794,15 @@ void FGPredictor::update( double dt ) {
 }
 
 
-FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node)
+FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node):
+    Tf( 1.0 ),
+    samples( 1 ),
+    rateOfChange( 1.0 ),
+    gainFactor( 1.0 ),
+    gain_prop( NULL ),
+    output_min_clamp( -std::numeric_limits<double>::max() ),
+    output_max_clamp( std::numeric_limits<double>::max() )
 {
-    samples = 1;
-
     int i;
     for ( i = 0; i < node->nChildren(); ++i ) {
         SGPropertyNode *child = node->getChild(i);
@@ -623,6 +812,19 @@ FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node)
             name = cval;
         } else if ( cname == "debug" ) {
             debug = child->getBoolValue();
+        } else if ( cname == "enable" ) {
+            SGPropertyNode *prop = child->getChild( "prop" );
+            if ( prop != NULL ) {
+                enable_prop = fgGetNode( prop->getStringValue(), true );
+            }
+            SGPropertyNode *val = child->getChild( "value" );
+            if ( val != NULL ) {
+                enable_value = val->getStringValue();
+            }
+            SGPropertyNode *pass = child->getChild( "honor-passive" );
+            if ( pass != NULL ) {
+                honor_passive = pass->getBoolValue();
+            }
         } else if ( cname == "type" ) {
             if ( cval == "exponential" ) {
                 filterType = exponential;
@@ -632,6 +834,10 @@ FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node)
                 filterType = movingAverage;
             } else if (cval == "noise-spike") {
                 filterType = noiseSpike;
+            } else if (cval == "gain") {
+                filterType = gain;
+            } else if (cval == "reciprocal") {
+                filterType = reciprocal;
             }
         } else if ( cname == "input" ) {
             input_prop = fgGetNode( child->getStringValue(), true );
@@ -641,6 +847,20 @@ FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node)
             samples = child->getIntValue();
         } else if ( cname == "max-rate-of-change" ) {
             rateOfChange = child->getDoubleValue();
+        } else if ( cname == "gain" ) {
+            SGPropertyNode *val = child->getChild( "value" );
+            if ( val != NULL ) {
+                gainFactor = val->getDoubleValue();
+            }
+            SGPropertyNode *prop = child->getChild( "prop" );
+            if ( prop != NULL ) {
+                gain_prop = fgGetNode( prop->getStringValue(), true );
+                gain_prop->setDoubleValue(gainFactor);
+            }
+        } else if ( cname == "u_min" ) {
+            output_min_clamp = child->getDoubleValue();
+        } else if ( cname == "u_max" ) {
+            output_max_clamp = child->getDoubleValue();
         } else if ( cname == "output" ) {
             SGPropertyNode *tmp = fgGetNode( child->getStringValue(), true );
             output_list.push_back( tmp );
@@ -653,10 +873,21 @@ FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node)
 
 void FGDigitalFilter::update(double dt)
 {
-    if ( input_prop != NULL ) {
+    if ( (input_prop != NULL && 
+          enable_prop != NULL && 
+          enable_prop->getStringValue() == enable_value) ||
+         (enable_prop == NULL &&
+          input_prop != NULL) ) {
+
         input.push_front(input_prop->getDoubleValue());
         input.resize(samples + 1, 0.0);
-        // no sense if there isn't an input :-)
+
+        if ( !enabled ) {
+            // first time being enabled, initialize output to the
+            // value of the output property to avoid bumping.
+            output.push_front(output_list[0]->getDoubleValue());
+        }
+
         enabled = true;
     } else {
         enabled = false;
@@ -675,11 +906,6 @@ void FGDigitalFilter::update(double dt)
             double alpha = 1 / ((Tf/dt) + 1);
             output.push_front(alpha * input[0] + 
                               (1 - alpha) * output[0]);
-            unsigned int i;
-            for ( i = 0; i < output_list.size(); ++i ) {
-                output_list[i]->setDoubleValue( output[0] );
-            }
-            output.resize(1);
         } 
         else if (filterType == doubleExponential)
         {
@@ -687,21 +913,11 @@ void FGDigitalFilter::update(double dt)
             output.push_front(alpha * alpha * input[0] + 
                               2 * (1 - alpha) * output[0] -
                               (1 - alpha) * (1 - alpha) * output[1]);
-            unsigned int i;
-            for ( i = 0; i < output_list.size(); ++i ) {
-                output_list[i]->setDoubleValue( output[0] );
-            }
-            output.resize(2);
         }
         else if (filterType == movingAverage)
         {
             output.push_front(output[0] + 
                               (input[0] - input.back()) / samples);
-            unsigned int i;
-            for ( i = 0; i < output_list.size(); ++i ) {
-                output_list[i]->setDoubleValue( output[0] );
-            }
-            output.resize(1);
         }
         else if (filterType == noiseSpike)
         {
@@ -719,13 +935,37 @@ void FGDigitalFilter::update(double dt)
             {
                 output.push_front(input[0]);
             }
-
-            unsigned int i;
-            for ( i = 0; i < output_list.size(); ++i ) {
-                output_list[i]->setDoubleValue( output[0] );
+        }
+        else if (filterType == gain)
+        {
+            if (gain_prop != NULL) {
+                gainFactor = gain_prop->getDoubleValue();
+            }
+            output[0] = gainFactor * input[0];
+        }
+        else if (filterType == reciprocal)
+        {
+            if (gain_prop != NULL) {
+                gainFactor = gain_prop->getDoubleValue();
+            }
+            if (input[0] != 0.0) {
+                output[0] = gainFactor / input[0];
             }
-            output.resize(1);
         }
+
+        if (output[0] < output_min_clamp) {
+            output[0] = output_min_clamp;
+        }
+        else if (output[0] > output_max_clamp) {
+            output[0] = output_max_clamp;
+        }
+
+        unsigned int i;
+        for ( i = 0; i < output_list.size(); ++i ) {
+            output_list[i]->setDoubleValue( output[0] );
+        }
+        output.resize(2);
+
         if (debug)
         {
             cout << "input:" << input[0] 
@@ -781,7 +1021,6 @@ void FGXMLAutopilot::init() {
 void FGXMLAutopilot::reinit() {
     components.clear();
     init();
-    build();
 }
 
 
@@ -801,17 +1040,13 @@ bool FGXMLAutopilot::build() {
         string name = node->getName();
         // cout << name << endl;
         if ( name == "pid-controller" ) {
-            FGXMLAutoComponent *c = new FGPIDController( node );
-            components.push_back( c );
+            components.push_back( new FGPIDController( node ) );
         } else if ( name == "pi-simple-controller" ) {
-            FGXMLAutoComponent *c = new FGPISimpleController( node );
-            components.push_back( c );
+            components.push_back( new FGPISimpleController( node ) );
         } else if ( name == "predict-simple" ) {
-            FGXMLAutoComponent *c = new FGPredictor( node );
-            components.push_back( c );
+            components.push_back( new FGPredictor( node ) );
         } else if ( name == "filter" ) {
-            FGXMLAutoComponent *c = new FGDigitalFilter( node );
-            components.push_back( c );
+            components.push_back( new FGDigitalFilter( node ) );
         } else {
             SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: " 
                     << name );
@@ -971,3 +1206,4 @@ void FGXMLAutopilot::update( double dt ) {
         components[i]->update( dt );
     }
 }
+