]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/autopilotgroup.cxx
Trivial cleanup commit, to test continuous integration server.
[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         if( get_subsystem( apName.c_str() ) != NULL ) {
181             SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot configuration name " << apName << " ignored" );
182             continue;
183         }
184
185         SGPath config( globals->get_fg_root() );
186         config.append( pathNode->getStringValue() );
187
188         SG_LOG( SG_ALL, SG_INFO, "Reading autopilot configuration from " << config.str() );
189
190         try {
191             SGPropertyNode_ptr root = new SGPropertyNode();
192             readProperties( config.str(), root );
193
194             SG_LOG( SG_AUTOPILOT, SG_INFO, "adding  autopilot subsystem " << apName );
195             FGXMLAutopilot::Autopilot * ap = new FGXMLAutopilot::Autopilot( autopilotNodes[i], root );
196             ap->set_name( apName );
197             set_subsystem( apName, ap );
198             _autopilotNames.push_back( apName );
199
200         } catch (const sg_exception& e) {
201             SG_LOG( SG_AUTOPILOT, SG_ALERT, "Failed to load autopilot configuration: "
202                     << config.str() << ":" << e.getMessage() );
203             continue;
204         }
205     }
206
207     SGSubsystemGroup::bind();
208     SGSubsystemGroup::init();
209 }
210