/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- Module: FGFCS.cpp
+ Module: FGFCS.cpp
Author: Jon Berndt
Date started: 12/12/98
Purpose: Model the flight controls
Called by: FDMExec
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+ ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
+ the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
- You should have received a copy of the GNU General Public License along with
+ You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
- Further information about the GNU General Public License can also be found on
+ Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCS.h"
-#include <FGFDMExec.h>
-#include <input_output/FGPropertyManager.h>
+#include "FGFDMExec.h"
+#include "FGGroundReactions.h"
+#include "input_output/FGPropertyManager.h"
#include <fstream>
-
-#include <models/flight_control/FGFilter.h>
-#include <models/flight_control/FGDeadBand.h>
-#include <models/flight_control/FGGain.h>
-#include <models/flight_control/FGGradient.h>
-#include <models/flight_control/FGSwitch.h>
-#include <models/flight_control/FGSummer.h>
-#include <models/flight_control/FGKinemat.h>
-#include <models/flight_control/FGFCSFunction.h>
-#include <models/flight_control/FGSensor.h>
+#include <sstream>
+#include <iomanip>
+
+#include "models/flight_control/FGFilter.h"
+#include "models/flight_control/FGDeadBand.h"
+#include "models/flight_control/FGGain.h"
+#include "models/flight_control/FGPID.h"
+#include "models/flight_control/FGSwitch.h"
+#include "models/flight_control/FGSummer.h"
+#include "models/flight_control/FGKinemat.h"
+#include "models/flight_control/FGFCSFunction.h"
+#include "models/flight_control/FGSensor.h"
+#include "models/flight_control/FGActuator.h"
+#include "models/flight_control/FGAccelerometer.h"
+#include "models/flight_control/FGMagnetometer.h"
+#include "models/flight_control/FGGyro.h"
+
+using namespace std;
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_FCS;
-#if defined(WIN32) && !defined(__CYGWIN__)
-#define snprintf _snprintf
-#endif
-
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
GearCmd = GearPos = 1; // default to gear down
LeftBrake = RightBrake = CenterBrake = 0.0;
+ TailhookPos = WingFoldPos = 0.0;
bind();
- for (i=0;i<=NForms;i++) {
+ for (i=0;i<NForms;i++) {
DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
}
FGFCS::~FGFCS()
{
- if (PropertyManager->HasNode("fcs")) unbind( PropertyManager->GetNode("fcs") );
- if (PropertyManager->HasNode("ap")) unbind( PropertyManager->GetNode("ap") );
- PropertyManager->Untie( "gear/gear-cmd-norm" );
- PropertyManager->Untie( "gear/gear-pos-norm" );
-
ThrottleCmd.clear();
ThrottlePos.clear();
MixtureCmd.clear();
unsigned int i;
for (i=0;i<APComponents.size();i++) delete APComponents[i];
- for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
- for (i=0;i<sensors.size();i++) delete sensors[i];
-
APComponents.clear();
+ for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
FCSComponents.clear();
- sensors.clear();
- interface_properties.clear();
+ for (i=0;i<Systems.size();i++) delete Systems[i];
+ Systems.clear();
+
Debug(1);
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFCS::InitModel(void)
+{
+ unsigned int i;
+
+ if (!FGModel::InitModel()) return false;
+
+ for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = 0.0;
+ for (i=0; i<MixturePos.size(); i++) MixturePos[i] = 0.0;
+ for (i=0; i<ThrottleCmd.size(); i++) ThrottleCmd[i] = 0.0;
+ for (i=0; i<MixtureCmd.size(); i++) MixtureCmd[i] = 0.0;
+ for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = 0.0;
+ for (i=0; i<PropFeather.size(); i++) PropFeather[i] = 0.0;
+
+ DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
+ PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
+ TailhookPos = WingFoldPos = 0.0;
+
+ for (i=0;i<NForms;i++) {
+ DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
+ DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
+ }
+
+ for (unsigned int i=0; i<Systems.size(); i++) {
+ if (Systems[i]->GetType() == "LAG" ||
+ Systems[i]->GetType() == "LEAD_LAG" ||
+ Systems[i]->GetType() == "WASHOUT" ||
+ Systems[i]->GetType() == "SECOND_ORDER_FILTER" ||
+ Systems[i]->GetType() == "INTEGRATOR")
+ {
+ ((FGFilter*)Systems[i])->ResetPastStates();
+ } else if (Systems[i]->GetType() == "PID" ) {
+ ((FGPID*)Systems[i])->ResetPastStates();
+ }
+ }
+
+ for (unsigned int i=0; i<FCSComponents.size(); i++) {
+ if (FCSComponents[i]->GetType() == "LAG" ||
+ FCSComponents[i]->GetType() == "LEAD_LAG" ||
+ FCSComponents[i]->GetType() == "WASHOUT" ||
+ FCSComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
+ FCSComponents[i]->GetType() == "INTEGRATOR")
+ {
+ ((FGFilter*)FCSComponents[i])->ResetPastStates();
+ } else if (FCSComponents[i]->GetType() == "PID" ) {
+ ((FGPID*)FCSComponents[i])->ResetPastStates();
+ }
+ }
+
+ for (unsigned int i=0; i<APComponents.size(); i++) {
+ if (APComponents[i]->GetType() == "LAG" ||
+ APComponents[i]->GetType() == "LEAD_LAG" ||
+ APComponents[i]->GetType() == "WASHOUT" ||
+ APComponents[i]->GetType() == "SECOND_ORDER_FILTER" ||
+ APComponents[i]->GetType() == "INTEGRATOR")
+ {
+ ((FGFilter*)APComponents[i])->ResetPastStates();
+ } else if (APComponents[i]->GetType() == "PID" ) {
+ ((FGPID*)APComponents[i])->ResetPastStates();
+ }
+ }
+
+ return true;
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Notes: In this logic the default engine commands are set. This is simply a
// sort of safe-mode method in case the user has not defined control laws for
if (FGModel::Run()) return true; // fast exit if nothing to do
if (FDMExec->Holding()) return false;
+ RunPreFunctions();
+
for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
-
// Set the default steering angle
for (i=0; i<SteerPosDeg.size(); i++) {
FGLGear* gear = GroundReactions->GetGearUnit(i);
SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
}
- // Cycle through the sensor, autopilot, and flight control components
- for (i=0; i<sensors.size(); i++) sensors[i]->Run();
+ // Execute Systems in order
+ for (i=0; i<Systems.size(); i++) Systems[i]->Run();
+
+ // Execute Autopilot
for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
+
+ // Execute Flight Control System
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
+ RunPostFunctions();
+
return false;
}
if (engineNum < (int)ThrottlePos.size()) {
if (engineNum < 0) {
- for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
+ for (ctr=0;ctr<MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
} else {
MixturePos[engineNum] = setting;
}
if (engineNum < (int)ThrottlePos.size()) {
if (engineNum < 0) {
- for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
+ for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
} else {
PropAdvance[engineNum] = setting;
}
if (engineNum < (int)ThrottlePos.size()) {
if (engineNum < 0) {
- for (ctr=0;ctr<=PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
+ for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
} else {
PropFeather[engineNum] = setting;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFCS::Load(Element* el)
+bool FGFCS::Load(Element* el, SystemType systype)
{
- string name, file, fname, comp_name, interface_property_string;
- unsigned i;
+ string name, file, fname="", interface_property_string, parent_name;
vector <FGFCSComponent*> *Components;
- Element *FCS_cfg, *document, *component_element, *property_element, *sensor_element;
+ Element *component_element;
Element *channel_element;
- ifstream* controls_file = new ifstream();
- FGXMLParse controls_file_parser;
Components=0;
- // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
- // file or in a separate file. Set up the Element pointer as appropriate.
string separator = "/";
-#ifdef macintosh
- separator = ";";
-#endif
+
+// ToDo: The handling of name and file attributes could be improved, here,
+// considering that a name can be in the external file, as well.
name = el->GetAttributeValue("name");
if (name.empty()) {
fname = el->GetAttributeValue("file");
- file = FDMExec->GetAircraftPath() + separator + FDMExec->GetModelName() + separator + fname + ".xml";
+ if (systype == stSystem) {
+ file = FindSystemFullPathname(fname);
+ } else {
+ file = FDMExec->GetFullAircraftPath() + separator + fname + ".xml";
+ }
if (fname.empty()) {
- cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
+ cerr << "FCS, Autopilot, or system does not appear to be defined inline nor in a file" << endl;
return false;
} else {
- controls_file->open(file.c_str());
- readXML(*controls_file, controls_file_parser);
- delete controls_file;
- document = controls_file_parser.GetDocument();
+ document = LoadXMLDocument(file);
+ if (!document) {
+ cerr << "Error loading file " << file << endl;
+ return false;
+ }
+ name = document->GetAttributeValue("name");
}
} else {
document = el;
} else if (document->GetName() == "flight_control") {
Components = &FCSComponents;
Name = "FCS: " + document->GetAttributeValue("name");
+ } else if (document->GetName() == "system") {
+ Components = &Systems;
+ Name = "System: " + document->GetAttributeValue("name");
}
-
Debug(2);
- // ToDo: How do these get untied?
- // ToDo: Consider having INPUT and OUTPUT interface properties. Would then
- // have to duplicate this block of code after channel read code.
- // Input properties could be write only (nah), and output could be read
- // only.
-
if (document->GetName() == "flight_control") bindModel();
- property_element = document->FindElement("property");
- while (property_element) {
- interface_properties.push_back(new double(0));
- interface_property_string = property_element->GetDataLine();
- PropertyManager->Tie(interface_property_string, interface_properties.back());
- property_element = document->FindNextElement("property");
- }
-
- sensor_element = document->FindElement("sensor");
- while (sensor_element) {
- try {
- sensors.push_back(new FGSensor(this, sensor_element));
- } catch (string s) {
- cerr << highint << fgred << endl << " " << s << endl;
- return false;
+ FGModel::Load(document); // Load interface properties from document
+
+ // After reading interface properties in a file, read properties in the local
+ // flight_control, autopilot, or system element. This allows general-purpose
+ // systems to be defined in a file, with overrides or initial loaded constants
+ // supplied in the relevant element of the aircraft configuration file.
+
+ Element* property_element = 0;
+
+ if (!fname.empty()) {
+ property_element = el->FindElement("property");
+ if (property_element && debug_lvl > 0) cout << endl << " Overriding properties" << endl << endl;
+ while (property_element) {
+ double value=0.0;
+ if ( ! property_element->GetAttributeValue("value").empty())
+ value = property_element->GetAttributeValueAsNumber("value");
+
+ interface_property_string = property_element->GetDataLine();
+ if (PropertyManager->HasNode(interface_property_string)) {
+ FGPropertyManager* node = PropertyManager->GetNode(interface_property_string);
+ if (debug_lvl > 0)
+ cout << " " << "Overriding value for property " << interface_property_string
+ << " (old value: " << node->getDoubleValue() << " new value: " << value << ")" << endl;
+ node->setDoubleValue(value);
+ } else {
+ interface_properties.push_back(new double(value));
+ PropertyManager->Tie(interface_property_string, interface_properties.back());
+ if (debug_lvl > 0)
+ cout << " " << interface_property_string << " (initial value: " << value << ")" << endl;
+ }
+
+ property_element = el->FindNextElement("property");
}
- sensor_element = document->FindNextElement("sensor");
}
channel_element = document->FindElement("channel");
while (channel_element) {
- component_element = channel_element->FindElement("component");
- if (component_element) {
- cout << "This form of the component specification is being deprecated" << endl;
- } else {
- component_element = channel_element->GetElement();
- }
+
+ if (debug_lvl > 0)
+ cout << endl << highint << fgblue << " Channel "
+ << normint << channel_element->GetAttributeValue("name") << reset << endl;
+
+ component_element = channel_element->GetElement();
while (component_element) {
- comp_name = component_element->GetAttributeValue("type");
try {
- if ((comp_name == "LAG_FILTER") ||
- (comp_name == "LEAD_LAG_FILTER") ||
- (comp_name == "SECOND_ORDER_FILTER") ||
- (comp_name == "WASHOUT_FILTER") ||
- (comp_name == "INTEGRATOR") ||
- (component_element->GetName() == string("lag_filter")) ||
+ if ((component_element->GetName() == string("lag_filter")) ||
(component_element->GetName() == string("lead_lag_filter")) ||
(component_element->GetName() == string("washout_filter")) ||
(component_element->GetName() == string("second_order_filter")) ||
(component_element->GetName() == string("integrator")) )
{
Components->push_back(new FGFilter(this, component_element));
- } else if ((comp_name == "PURE_GAIN") ||
- (comp_name == "SCHEDULED_GAIN") ||
- (comp_name == "AEROSURFACE_SCALE") ||
- (component_element->GetName() == string("pure_gain")) ||
+ } else if ((component_element->GetName() == string("pure_gain")) ||
(component_element->GetName() == string("scheduled_gain")) ||
(component_element->GetName() == string("aerosurface_scale")))
{
Components->push_back(new FGGain(this, component_element));
- } else if ((comp_name == "SUMMER") || (component_element->GetName() == string("summer"))) {
+ } else if (component_element->GetName() == string("summer")) {
Components->push_back(new FGSummer(this, component_element));
- } else if ((comp_name == "DEADBAND") || (component_element->GetName() == string("deadband"))) {
+ } else if (component_element->GetName() == string("deadband")) {
Components->push_back(new FGDeadBand(this, component_element));
- } else if (comp_name == "GRADIENT") {
- Components->push_back(new FGGradient(this, component_element));
- } else if ((comp_name == "SWITCH") || (component_element->GetName() == string("switch"))) {
+ } else if (component_element->GetName() == string("switch")) {
Components->push_back(new FGSwitch(this, component_element));
- } else if ((comp_name == "KINEMAT") || (component_element->GetName() == string("kinematic"))) {
+ } else if (component_element->GetName() == string("kinematic")) {
Components->push_back(new FGKinemat(this, component_element));
- } else if ((comp_name == "FUNCTION") || (component_element->GetName() == string("fcs_function"))) {
+ } else if (component_element->GetName() == string("fcs_function")) {
Components->push_back(new FGFCSFunction(this, component_element));
+ } else if (component_element->GetName() == string("pid")) {
+ Components->push_back(new FGPID(this, component_element));
+ } else if (component_element->GetName() == string("actuator")) {
+ Components->push_back(new FGActuator(this, component_element));
+ } else if (component_element->GetName() == string("sensor")) {
+ Components->push_back(new FGSensor(this, component_element));
+ } else if (component_element->GetName() == string("accelerometer")) {
+ Components->push_back(new FGAccelerometer(this, component_element));
+ } else if (component_element->GetName() == string("magnetometer")) {
+ Components->push_back(new FGMagnetometer(this, component_element));
+ } else if (component_element->GetName() == string("gyro")) {
+ Components->push_back(new FGGyro(this, component_element));
} else {
- cerr << "Unknown FCS component: " << comp_name << endl;
+ cerr << "Unknown FCS component: " << component_element->GetName() << endl;
}
} catch(string s) {
cerr << highint << fgred << endl << " " << s << endl;
cerr << reset << endl;
return false;
}
- if (comp_name.empty()) { // comp_name will be empty if using new format
- component_element = channel_element->GetNextElement();
- } else {
- component_element = channel_element->FindNextElement("component");
- }
+ component_element = channel_element->GetNextElement();
}
channel_element = document->FindNextElement("channel");
}
+ ResetParser();
+
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGFCS::GetComponentStrings(string delimeter)
+string FGFCS::FindSystemFullPathname(const string& system_filename)
+{
+ string fullpath, localpath;
+ string systemPath = FDMExec->GetSystemsPath();
+ string aircraftPath = FDMExec->GetFullAircraftPath();
+ ifstream system_file;
+
+ string separator = "/";
+
+ fullpath = systemPath + separator;
+ localpath = aircraftPath + separator + "Systems" + separator;
+
+ system_file.open(string(fullpath + system_filename + ".xml").c_str());
+ if ( !system_file.is_open()) {
+ system_file.open(string(localpath + system_filename + ".xml").c_str());
+ if ( !system_file.is_open()) {
+ cerr << " Could not open system file: " << system_filename << " in path "
+ << fullpath << " or " << localpath << endl;
+ return string("");
+ } else {
+ return string(localpath + system_filename + ".xml");
+ }
+ }
+ return string(fullpath + system_filename + ".xml");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ifstream* FGFCS::FindSystemFile(const string& system_filename)
+{
+ string fullpath, localpath;
+ string systemPath = FDMExec->GetSystemsPath();
+ string aircraftPath = FDMExec->GetFullAircraftPath();
+ ifstream* system_file = new ifstream();
+
+ string separator = "/";
+
+ fullpath = systemPath + separator;
+ localpath = aircraftPath + separator + "Systems" + separator;
+
+ system_file->open(string(fullpath + system_filename + ".xml").c_str());
+ if ( !system_file->is_open()) {
+ system_file->open(string(localpath + system_filename + ".xml").c_str());
+ if ( !system_file->is_open()) {
+ cerr << " Could not open system file: " << system_filename << " in path "
+ << fullpath << " or " << localpath << endl;
+ }
+ }
+ return system_file;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGFCS::GetComponentStrings(const string& delimiter)
{
unsigned int comp;
string CompStrings = "";
bool firstime = true;
+ int total_count=0;
- for (comp = 0; comp < FCSComponents.size(); comp++) {
+ for (unsigned int i=0; i<Systems.size(); i++) {
if (firstime) firstime = false;
- else CompStrings += delimeter;
+ else CompStrings += delimiter;
- CompStrings += FCSComponents[comp]->GetName();
+ CompStrings += Systems[i]->GetName();
+ total_count++;
}
for (comp = 0; comp < APComponents.size(); comp++)
{
- CompStrings += delimeter;
+ if (firstime) firstime = false;
+ else CompStrings += delimiter;
+
CompStrings += APComponents[comp]->GetName();
+ total_count++;
+ }
+
+ for (comp = 0; comp < FCSComponents.size(); comp++) {
+ if (firstime) firstime = false;
+ else CompStrings += delimiter;
+
+ CompStrings += FCSComponents[comp]->GetName();
+ total_count++;
}
return CompStrings;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGFCS::GetComponentValues(string delimeter)
+string FGFCS::GetComponentValues(const string& delimiter)
{
+ std::ostringstream buf;
+
unsigned int comp;
- string CompValues = "";
- char buffer[12];
bool firstime = true;
+ int total_count=0;
- for (comp = 0; comp < FCSComponents.size(); comp++) {
+ for (unsigned int i=0; i<Systems.size(); i++) {
if (firstime) firstime = false;
- else CompValues += delimeter;
+ else buf << delimiter;
- sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
- CompValues += string(buffer);
+ buf << setprecision(9) << Systems[i]->GetOutput();
+ total_count++;
}
for (comp = 0; comp < APComponents.size(); comp++) {
- sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
- CompValues += string(buffer);
+ if (firstime) firstime = false;
+ else buf << delimiter;
+
+ buf << setprecision(9) << APComponents[comp]->GetOutput();
+ total_count++;
+ }
+
+ for (comp = 0; comp < FCSComponents.size(); comp++) {
+ if (firstime) firstime = false;
+ else buf << delimiter;
+
+ buf << setprecision(9) << FCSComponents[comp]->GetOutput();
+ total_count++;
}
- return CompValues;
+ return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PropFeatherCmd.push_back(false);
PropFeather.push_back(false);
- unsigned int num = ThrottleCmd.size()-1;
+ unsigned int num = (unsigned int)ThrottleCmd.size()-1;
bindThrottle(num);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+double FGFCS::GetDt(void)
+{
+ return FDMExec->GetDeltaT()*rate;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGFCS::bind(void)
{
PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
- PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
- PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
+ PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
+ PropertyManager->Tie("fcs/left-brake-cmd-norm", this, &FGFCS::GetLBrake, &FGFCS::SetLBrake);
+ PropertyManager->Tie("fcs/right-brake-cmd-norm", this, &FGFCS::GetRBrake, &FGFCS::SetRBrake);
+ PropertyManager->Tie("fcs/center-brake-cmd-norm", this, &FGFCS::GetCBrake, &FGFCS::SetCBrake);
+ PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
+
+ PropertyManager->Tie("gear/tailhook-pos-norm", this, &FGFCS::GetTailhookPos, &FGFCS::SetTailhookPos);
+ PropertyManager->Tie("fcs/wing-fold-pos-norm", this, &FGFCS::GetWingFoldPos, &FGFCS::SetWingFoldPos);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Technically, this function should probably bind propulsion type specific controls
// rather than mixture and prop-advance.
-//
void FGFCS::bindThrottle(unsigned int num)
{
- char tmp[80];
+ string tmp;
- snprintf(tmp, 80, "fcs/throttle-cmd-norm[%u]",num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottleCmd,
+ tmp = CreateIndexedPropertyName("fcs/throttle-cmd-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottleCmd,
&FGFCS::SetThrottleCmd);
- snprintf(tmp, 80, "fcs/throttle-pos-norm[%u]",num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottlePos,
+ tmp = CreateIndexedPropertyName("fcs/throttle-pos-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetThrottlePos,
&FGFCS::SetThrottlePos);
- snprintf(tmp, 80, "fcs/mixture-cmd-norm[%u]",num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixtureCmd,
+ tmp = CreateIndexedPropertyName("fcs/mixture-cmd-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixtureCmd,
&FGFCS::SetMixtureCmd);
- snprintf(tmp, 80, "fcs/mixture-pos-norm[%u]",num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixturePos,
+ tmp = CreateIndexedPropertyName("fcs/mixture-pos-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetMixturePos,
&FGFCS::SetMixturePos);
- snprintf(tmp, 80, "fcs/advance-cmd-norm[%u]",num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvanceCmd,
+ tmp = CreateIndexedPropertyName("fcs/advance-cmd-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvanceCmd,
&FGFCS::SetPropAdvanceCmd);
- snprintf(tmp, 80, "fcs/advance-pos-norm[%u]", num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvance,
+ tmp = CreateIndexedPropertyName("fcs/advance-pos-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropAdvance,
&FGFCS::SetPropAdvance);
- snprintf(tmp, 80, "fcs/feather-cmd-norm[%u]", num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetFeatherCmd,
+ tmp = CreateIndexedPropertyName("fcs/feather-cmd-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetFeatherCmd,
&FGFCS::SetFeatherCmd);
- snprintf(tmp, 80, "fcs/feather-pos-norm[%u]", num);
- PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropFeather,
+ tmp = CreateIndexedPropertyName("fcs/feather-pos-norm", num);
+ PropertyManager->Tie( tmp.c_str(), this, num, &FGFCS::GetPropFeather,
&FGFCS::SetPropFeather);
}
void FGFCS::bindModel(void)
{
unsigned int i;
- char tmp[80];
+ string tmp;
for (i=0; i<SteerPosDeg.size(); i++) {
if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
- snprintf(tmp,80,"fcs/steer-pos-deg[%u]",i);
- PropertyManager->Tie( tmp, this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFCS::unbind(FGPropertyManager *node)
-{
- int N = node->nChildren();
- for (int i=0; i<N; i++) {
- if (node->getChild(i)->nChildren() ) {
- unbind( (FGPropertyManager*)node->getChild(i) );
- } else if ( node->getChild(i)->isTied() ) {
- node->getChild(i)->untie();
+ tmp = CreateIndexedPropertyName("fcs/steer-pos-deg", i);
+ PropertyManager->Tie( tmp.c_str(), this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
}
}
}
if (debug_lvl & 1) { // Standard console startup message output
if (from == 2) { // Loader
- cout << endl << " Flight Control (" << Name << ")" << endl;
+ cout << endl << " " << Name << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification