]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/autopilotgroup.cxx
Merge branch 'work4' into next
[flightgear.git] / src / Autopilot / autopilotgroup.cxx
1 // autopilotgroup.cxx - an even more flexible, generic way to build autopilots
2 //
3 // Written by Torsten Dreyer
4 // Based heavily on work created by Curtis Olson, started January 2004.
5 //
6 // Copyright (C) 2004  Curtis L. Olson  - http://www.flightgear.org/~curt
7 // Copyright (C) 2010  Torsten Dreyer - Torsten (at) t3r (dot) de
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of the
12 // License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include "autopilot.hxx"
29 #include "autopilotgroup.hxx"
30
31 #include <Main/fg_props.hxx>
32 #include <Main/globals.hxx>
33 #include <Main/util.hxx>
34
35 #include <simgear/misc/sg_path.hxx>
36 #include <simgear/props/props_io.hxx>
37 #include <simgear/structure/SGExpression.hxx>
38
39 using std::cout;
40 using std::endl;
41
42 using simgear::PropertyList;
43
44 FGXMLAutopilotGroup::FGXMLAutopilotGroup() :
45   SGSubsystemGroup()
46 #ifdef XMLAUTO_USEHELPER
47   ,average(0.0), // average/filtered prediction
48   v_last(0.0),  // last velocity
49   last_static_pressure(0.0),
50   vel(fgGetNode( "/velocities/airspeed-kt", true )),
51   // Estimate speed in 5,10 seconds
52   lookahead5(fgGetNode( "/autopilot/internal/lookahead-5-sec-airspeed-kt", true )),
53   lookahead10(fgGetNode( "/autopilot/internal/lookahead-10-sec-airspeed-kt", true )),
54   bug(fgGetNode( "/autopilot/settings/heading-bug-deg", true )),
55   mag_hdg(fgGetNode( "/orientation/heading-magnetic-deg", true )),
56   bug_error(fgGetNode( "/autopilot/internal/heading-bug-error-deg", true )),
57   fdm_bug_error(fgGetNode( "/autopilot/internal/fdm-heading-bug-error-deg", true )),
58   target_true(fgGetNode( "/autopilot/settings/true-heading-deg", true )),
59   true_hdg(fgGetNode( "/orientation/heading-deg", true )),
60   true_error(fgGetNode( "/autopilot/internal/true-heading-error-deg", true )),
61   target_nav1(fgGetNode( "/instrumentation/nav[0]/radials/target-auto-hdg-deg", true )),
62   true_nav1(fgGetNode( "/autopilot/internal/nav1-heading-error-deg", true )),
63   true_track_nav1(fgGetNode( "/autopilot/internal/nav1-track-error-deg", true )),
64   nav1_course_error(fgGetNode( "/autopilot/internal/nav1-course-error", true )),
65   nav1_selected_course(fgGetNode( "/instrumentation/nav[0]/radials/selected-deg", true )),
66   vs_fps(fgGetNode( "/velocities/vertical-speed-fps", true )),
67   vs_fpm(fgGetNode( "/autopilot/internal/vert-speed-fpm", true )),
68   static_pressure(fgGetNode( "/systems/static[0]/pressure-inhg", true )),
69   pressure_rate(fgGetNode( "/autopilot/internal/pressure-rate", true )),
70   track(fgGetNode( "/orientation/track-deg", true ))
71 #endif
72 {
73 }
74
75 void FGXMLAutopilotGroup::update( double dt )
76 {
77     // update all configured autopilots
78     SGSubsystemGroup::update( dt );
79 #ifdef XMLAUTO_USEHELPER
80     // update helper values
81     double v = vel->getDoubleValue();
82     double a = 0.0;
83     if ( dt > 0.0 ) {
84         a = (v - v_last) / dt;
85
86         if ( dt < 1.0 ) {
87             average = (1.0 - dt) * average + dt * a;
88         } else {
89             average = a;
90         }
91
92         lookahead5->setDoubleValue( v + average * 5.0 );
93         lookahead10->setDoubleValue( v + average * 10.0 );
94         v_last = v;
95     }
96
97     // Calculate heading bug error normalized to +/- 180.0
98     double diff = bug->getDoubleValue() - mag_hdg->getDoubleValue();
99     SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
100     bug_error->setDoubleValue( diff );
101
102     fdm_bug_error->setDoubleValue( diff );
103
104     // Calculate true heading error normalized to +/- 180.0
105     diff = target_true->getDoubleValue() - true_hdg->getDoubleValue();
106     SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
107     true_error->setDoubleValue( diff );
108
109     // Calculate nav1 target heading error normalized to +/- 180.0
110     diff = target_nav1->getDoubleValue() - true_hdg->getDoubleValue();
111     SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
112     true_nav1->setDoubleValue( diff );
113
114     // Calculate true groundtrack
115     diff = target_nav1->getDoubleValue() - track->getDoubleValue();
116     SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
117     true_track_nav1->setDoubleValue( diff );
118
119     // Calculate nav1 selected course error normalized to +/- 180.0
120     diff = nav1_selected_course->getDoubleValue() - mag_hdg->getDoubleValue();
121     SG_NORMALIZE_RANGE( diff, -180.0, 180.0 );
122     nav1_course_error->setDoubleValue( diff );
123
124     // Calculate vertical speed in fpm
125     vs_fpm->setDoubleValue( vs_fps->getDoubleValue() * 60.0 );
126
127
128     // Calculate static port pressure rate in [inhg/s].
129     // Used to determine vertical speed.
130     if ( dt > 0.0 ) {
131         double current_static_pressure = static_pressure->getDoubleValue();
132         double current_pressure_rate = 
133             ( current_static_pressure - last_static_pressure ) / dt;
134
135         pressure_rate->setDoubleValue(current_pressure_rate);
136         last_static_pressure = current_static_pressure;
137     }
138 #endif
139 }
140
141 void FGXMLAutopilotGroup::reinit()
142 {
143     SGSubsystemGroup::unbind();
144
145     for( vector<string>::size_type i = 0; i < _autopilotNames.size(); i++ ) {
146       FGXMLAutopilot::Autopilot * ap = (FGXMLAutopilot::Autopilot*)get_subsystem( _autopilotNames[i] );
147       if( ap == NULL ) continue; // ?
148       remove_subsystem( _autopilotNames[i] );
149       delete ap;
150     }
151     _autopilotNames.clear();
152     init();
153 }
154
155 void FGXMLAutopilotGroup::init()
156 {
157     PropertyList autopilotNodes = fgGetNode( "/sim/systems", true )->getChildren("autopilot");
158     if( autopilotNodes.size() == 0 ) {
159         SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration specified for this model!");
160         return;
161     }
162
163     for( PropertyList::size_type i = 0; i < autopilotNodes.size(); i++ ) {
164         SGPropertyNode_ptr pathNode = autopilotNodes[i]->getNode( "path" );
165         if( pathNode == NULL ) {
166             SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration file specified for this autopilot!");
167             continue;
168         }
169
170         string apName;
171         SGPropertyNode_ptr nameNode = autopilotNodes[i]->getNode( "name" );
172         if( nameNode != NULL ) {
173             apName = nameNode->getStringValue();
174         } else {
175           std::ostringstream buf;
176           buf <<  "unnamed_autopilot_" << i;
177           apName = buf.str();
178         }
179
180         {
181           // check for duplicate names
182           string name = apName;
183           for( unsigned i = 0; get_subsystem( apName.c_str() ) != NULL; i++ ) {
184               ostringstream buf;
185               buf <<  apName << "_" << i;
186               apName = buf.str();
187           }
188           if( apName != name )
189             SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot component " << name << ", renamed to " << apName );
190         }
191
192         if( get_subsystem( apName.c_str() ) != NULL ) {
193             SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot configuration name " << apName << " ignored" );
194             continue;
195         }
196
197         SGPath config( globals->get_fg_root() );
198         config.append( pathNode->getStringValue() );
199
200         SG_LOG( SG_ALL, SG_INFO, "Reading autopilot configuration from " << config.str() );
201
202         try {
203             SGPropertyNode_ptr root = new SGPropertyNode();
204             readProperties( config.str(), root );
205
206             SG_LOG( SG_AUTOPILOT, SG_INFO, "adding  autopilot subsystem " << apName );
207             FGXMLAutopilot::Autopilot * ap = new FGXMLAutopilot::Autopilot( autopilotNodes[i], root );
208             ap->set_name( apName );
209             set_subsystem( apName, ap );
210             _autopilotNames.push_back( apName );
211
212         } catch (const sg_exception& e) {
213             SG_LOG( SG_AUTOPILOT, SG_ALERT, "Failed to load autopilot configuration: "
214                     << config.str() << ":" << e.getMessage() );
215             continue;
216         }
217     }
218
219     SGSubsystemGroup::bind();
220     SGSubsystemGroup::init();
221 }
222