2002-02-24 20:54:23 +00:00
|
|
|
// JSBsim.cxx -- interface to the JSBsim flight model
|
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started February 1999.
|
|
|
|
//
|
2004-12-16 12:47:20 +00:00
|
|
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
2002-02-24 20:54:23 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
2010-07-16 09:05:59 +00:00
|
|
|
// modify it under the terms of the GNU Lesser General Public License as
|
2002-02-24 20:54:23 +00:00
|
|
|
// 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
|
2010-07-16 09:05:59 +00:00
|
|
|
// Lesser General Public License for more details.
|
2002-02-24 20:54:23 +00:00
|
|
|
//
|
2010-07-16 09:05:59 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
2002-02-24 20:54:23 +00:00
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
//
|
2010-11-28 09:58:47 +00:00
|
|
|
// $Id: JSBSim.cxx,v 1.64 2010/10/31 04:49:25 jberndt Exp $
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
|
2002-12-03 14:59:24 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
#include <simgear/compiler.h>
|
2011-02-06 21:08:46 +00:00
|
|
|
#include <simgear/sg_inlines.h>
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2008-07-10 17:23:02 +00:00
|
|
|
#include <stdio.h> // size_t
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
#include <simgear/constants.h>
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
2005-06-02 08:51:47 +00:00
|
|
|
#include <simgear/structure/commands.hxx>
|
2002-02-24 20:54:23 +00:00
|
|
|
|
From: "Jim Wilson" <jimw@kelcomaine.com>
This is a new improved patch for the previous tile manager fixes.
Rather than building dependencies between FGlocation or the viewer or fdm with
tilemgr what I ended up doing was linking the pieces together in the Mainloop
in main.cxx. You'll see what I mean...it's been commented fairly well. More
than likely we should move that chunk somewhere...just not sure where yet.
The changes seem clean now. As I get more ideas there could be some further
improvement in organizing the update in tilemgr. You'll note that I left an
override in there for the tilemgr::update() function to preserve earlier
functionality if someone needs it (e.g. usage independent of an fdm or
viewer), not to mention there are a few places in flightgear that call it
directly that have not been changed to the new interface (and may not need to be).
The code has been optimized to avoid duplicate traversals and seems to run
generally quite well. Note that there can be a short delay reloading tiles
that have been dropped from static views. We could call the tile scheduler on
a view switch, but it's not a big deal and at the moment I'd like to get this
in so people can try it and comment on it as it is.
Everything has been resycned with CVS tonight and I've included the
description submitted earlier (below).
Best,
Jim
Changes synced with CVS approx 20:30EDT 2002-05-09 (after this evenings updates).
Files:
http://www.spiderbark.com/fgfs/viewer-update-20020516.tar.gz
or
http://www.spiderbark.com/fgfs/viewer-update-20020516.diffs.gz
Description:
In a nutshell, these patches begin to take what was one value for ground
elevation and calculate ground elevation values seperately for the FDM and the
viewer (eye position). Several outstanding view related bugs have been fixed.
With the introduction of the new viewer code a lot of that Flight Gear code
broke related to use of a global variable called "scenery.cur_elev".
Therefore the ground_elevation and other associated items (like the current
tile bucket) is maintained per FDM instance and per View. Each of these has a
"point" or location that can be identified. See changes to FGLocation class
and main.cxx.
Most of the problems related to the new viewer in terms of sky, ground and
runway lights, and tower views are fixed.
There are four minor problems remaining. 1) The sun/moon spins when you pan
the "lookat" tower view only (view #3). 2) Under stress (esp. magic carpet
full speed with max visibility), there is a memory leak in the tile caching
that was not introduced with these changes. 3) I have not tested these
changes or made corrections to the ADA or External FDM interfaces. 4) The
change view function doesn't call the time/light update (not a problem unless
a tower is very far away).
Details:
FDM/flight.cxx, flight.hxx - FGInterface ties to FGAircraftModel so that it's
location data can be accessed for runway (ground elevation under aircraft)
elevation.
FDM/larsim.cxx, larcsim.hxx - gets runway elevation from FGInterface now.
Commented out function that is causing a namespace conflict, hasn't been
called with recent code anyway.
FDM/JSBSim/JSBSim.cxx, YASim/YASim.cxx - gets runway elevation from
FGInterface now.
Scenery/newcache.cxx, newcache.hxx - changed caching scheme to time based
(oldest tiles discard).
Scenery/tileentry.cxx, tileentry.hxx - added place to record time, changed
rendering to reference viewer altitude in order to fix a problem with ground
and runway lights.
Scenery/tilemgr.cxx, tilemgr.hxx - Modified update() to accept values for
multiple locations. Refresh function added in order to periodically make
the tiles current for a non-moving view (like a tower).
Main/fg_init.cxx - register event for making tiles current in a non-moving
view (like a tower).
Main/location.hxx - added support for current ground elevation data.
Main/main.cxx - added second tilemgr call for fdm, fixed places where viewer
position data was required for correct sky rendering.
Main/options.cxx - fixed segfault reported by Curtis when using --view-offset
command line parameter.
Main/viewer.cxx, viewer.hxx - removed fudging of view position. Fixed numerous
bugs that were causing eye and target values to get mixed up.
2002-05-17 17:25:28 +00:00
|
|
|
#include <FDM/flight.hxx>
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2005-11-01 13:41:49 +00:00
|
|
|
#include <Aircraft/controls.hxx>
|
2002-02-24 20:54:23 +00:00
|
|
|
#include <Main/globals.hxx>
|
|
|
|
#include <Main/fg_props.hxx>
|
|
|
|
|
2006-01-12 15:04:22 +00:00
|
|
|
#include "JSBSim.hxx"
|
2002-02-24 20:54:23 +00:00
|
|
|
#include <FDM/JSBSim/FGFDMExec.h>
|
2006-01-12 15:04:22 +00:00
|
|
|
#include <FDM/JSBSim/FGJSBBase.h>
|
|
|
|
#include <FDM/JSBSim/initialization/FGInitialCondition.h>
|
|
|
|
#include <FDM/JSBSim/initialization/FGTrim.h>
|
|
|
|
#include <FDM/JSBSim/models/FGModel.h>
|
|
|
|
#include <FDM/JSBSim/models/FGAircraft.h>
|
|
|
|
#include <FDM/JSBSim/models/FGFCS.h>
|
|
|
|
#include <FDM/JSBSim/models/FGPropagate.h>
|
|
|
|
#include <FDM/JSBSim/models/FGAuxiliary.h>
|
2008-07-10 17:23:02 +00:00
|
|
|
#include <FDM/JSBSim/models/FGInertial.h>
|
2006-01-12 15:04:22 +00:00
|
|
|
#include <FDM/JSBSim/models/FGAtmosphere.h>
|
|
|
|
#include <FDM/JSBSim/models/FGMassBalance.h>
|
|
|
|
#include <FDM/JSBSim/models/FGAerodynamics.h>
|
|
|
|
#include <FDM/JSBSim/models/FGLGear.h>
|
2010-07-16 09:05:59 +00:00
|
|
|
#include <FDM/JSBSim/models/FGGroundReactions.h>
|
|
|
|
#include <FDM/JSBSim/models/FGPropulsion.h>
|
2006-01-12 15:04:22 +00:00
|
|
|
#include <FDM/JSBSim/models/propulsion/FGEngine.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGPiston.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGTurbine.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGTurboProp.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGRocket.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGElectric.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGNozzle.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGPropeller.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGRotor.h>
|
|
|
|
#include <FDM/JSBSim/models/propulsion/FGTank.h>
|
|
|
|
#include <FDM/JSBSim/input_output/FGPropertyManager.h>
|
|
|
|
#include <FDM/JSBSim/input_output/FGGroundCallback.h>
|
|
|
|
|
|
|
|
using namespace JSBSim;
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2002-05-07 23:11:16 +00:00
|
|
|
static inline double
|
|
|
|
FMAX (double a, double b)
|
|
|
|
{
|
|
|
|
return a > b ? a : b;
|
|
|
|
}
|
|
|
|
|
2005-05-22 08:06:47 +00:00
|
|
|
class FGFSGroundCallback : public FGGroundCallback {
|
|
|
|
public:
|
2009-03-06 16:37:12 +00:00
|
|
|
FGFSGroundCallback(FGJSBsim* ifc) : mInterface(ifc) {}
|
2005-05-22 08:06:47 +00:00
|
|
|
virtual ~FGFSGroundCallback() {}
|
|
|
|
|
2009-06-01 08:52:34 +00:00
|
|
|
/** Get the altitude above sea level dependent on the location. */
|
2005-05-22 08:06:47 +00:00
|
|
|
virtual double GetAltitude(const FGLocation& l) const {
|
|
|
|
double pt[3] = { SG_FEET_TO_METER*l(eX),
|
|
|
|
SG_FEET_TO_METER*l(eY),
|
|
|
|
SG_FEET_TO_METER*l(eZ) };
|
|
|
|
double lat, lon, alt;
|
|
|
|
sgCartToGeod( pt, &lat, &lon, &alt);
|
|
|
|
return alt * SG_METER_TO_FEET;
|
|
|
|
}
|
2005-06-02 08:51:47 +00:00
|
|
|
|
2005-05-22 08:06:47 +00:00
|
|
|
/** Compute the altitude above ground. */
|
|
|
|
virtual double GetAGLevel(double t, const FGLocation& l,
|
2010-10-26 07:48:56 +00:00
|
|
|
FGLocation& cont, FGColumnVector3& n,
|
|
|
|
FGColumnVector3& v, FGColumnVector3& w) const {
|
2005-05-22 08:06:47 +00:00
|
|
|
double loc_cart[3] = { l(eX), l(eY), l(eZ) };
|
2010-10-26 07:48:56 +00:00
|
|
|
double contact[3], normal[3], vel[3], angularVel[3], agl = 0;
|
2009-03-06 16:37:12 +00:00
|
|
|
mInterface->get_agl_ft(t, loc_cart, SG_METER_TO_FEET*2, contact, normal,
|
2010-10-26 07:48:56 +00:00
|
|
|
vel, angularVel, &agl);
|
2010-07-16 09:05:59 +00:00
|
|
|
n = FGColumnVector3( normal[0], normal[1], normal[2] );
|
2009-08-20 05:33:20 +00:00
|
|
|
v = FGColumnVector3( vel[0], vel[1], vel[2] );
|
2010-10-26 07:48:56 +00:00
|
|
|
w = FGColumnVector3( angularVel[0], angularVel[1], angularVel[2] );
|
2005-05-22 08:06:47 +00:00
|
|
|
cont = FGColumnVector3( contact[0], contact[1], contact[2] );
|
|
|
|
return agl;
|
|
|
|
}
|
|
|
|
private:
|
2009-03-06 16:37:12 +00:00
|
|
|
FGJSBsim* mInterface;
|
2005-05-22 08:06:47 +00:00
|
|
|
};
|
2002-04-11 19:09:15 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2004-03-14 14:57:07 +00:00
|
|
|
FGJSBsim::FGJSBsim( double dt )
|
2008-07-10 17:23:02 +00:00
|
|
|
: FGInterface(dt), got_wire(false)
|
2002-02-24 20:54:23 +00:00
|
|
|
{
|
|
|
|
bool result;
|
2003-11-24 17:59:10 +00:00
|
|
|
// Set up the debugging level
|
|
|
|
// FIXME: this will not respond to
|
|
|
|
// runtime changes
|
|
|
|
|
|
|
|
// if flight is excluded, don't bother
|
|
|
|
if ((logbuf::get_log_classes() & SG_FLIGHT) != 0) {
|
|
|
|
|
|
|
|
// do a rough-and-ready mapping to
|
|
|
|
// the levels documented in FGFDMExec.h
|
|
|
|
switch (logbuf::get_log_priority()) {
|
|
|
|
case SG_BULK:
|
|
|
|
FGJSBBase::debug_lvl = 0x1f;
|
|
|
|
break;
|
|
|
|
case SG_DEBUG:
|
|
|
|
FGJSBBase::debug_lvl = 0x0f;
|
|
|
|
case SG_INFO:
|
|
|
|
FGJSBBase::debug_lvl = 0x01;
|
|
|
|
break;
|
|
|
|
case SG_WARN:
|
|
|
|
case SG_ALERT:
|
|
|
|
FGJSBBase::debug_lvl = 0x00;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-29 13:33:53 +00:00
|
|
|
fdmex = new FGFDMExec( (FGPropertyManager*)globals->get_props() );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2005-05-22 08:06:47 +00:00
|
|
|
// Register ground callback.
|
|
|
|
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
Atmosphere = fdmex->GetAtmosphere();
|
|
|
|
FCS = fdmex->GetFCS();
|
|
|
|
MassBalance = fdmex->GetMassBalance();
|
|
|
|
Propulsion = fdmex->GetPropulsion();
|
|
|
|
Aircraft = fdmex->GetAircraft();
|
2004-06-14 11:40:45 +00:00
|
|
|
Propagate = fdmex->GetPropagate();
|
2002-02-24 20:54:23 +00:00
|
|
|
Auxiliary = fdmex->GetAuxiliary();
|
2008-07-10 17:23:02 +00:00
|
|
|
Inertial = fdmex->GetInertial();
|
2002-02-24 20:54:23 +00:00
|
|
|
Aerodynamics = fdmex->GetAerodynamics();
|
2004-03-14 14:57:07 +00:00
|
|
|
GroundReactions = fdmex->GetGroundReactions();
|
|
|
|
|
2002-09-22 15:31:09 +00:00
|
|
|
fgic=fdmex->GetIC();
|
2002-02-24 20:54:23 +00:00
|
|
|
needTrim=true;
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
SGPath aircraft_path( fgGetString("/sim/aircraft-dir") );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
SGPath engine_path( fgGetString("/sim/aircraft-dir") );
|
2002-02-24 20:54:23 +00:00
|
|
|
engine_path.append( "Engine" );
|
2008-07-10 17:23:02 +00:00
|
|
|
|
|
|
|
SGPath systems_path( fgGetString("/sim/aircraft-dir") );
|
|
|
|
systems_path.append( "Systems" );
|
|
|
|
|
2010-07-16 09:05:59 +00:00
|
|
|
// deprecate sim-time-sec for simulation/sim-time-sec
|
|
|
|
// remove alias with increased configuration file version number (2.1 or later)
|
|
|
|
SGPropertyNode * node = fgGetNode("/fdm/jsbsim/simulation/sim-time-sec");
|
|
|
|
fgGetNode("/fdm/jsbsim/sim-time-sec", true)->alias( node );
|
|
|
|
// end of sim-time-sec deprecation patch
|
|
|
|
|
|
|
|
fdmex->Setdt( dt );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
result = fdmex->LoadModel( aircraft_path.str(),
|
|
|
|
engine_path.str(),
|
2008-07-10 17:23:02 +00:00
|
|
|
systems_path.str(),
|
2004-06-27 19:35:54 +00:00
|
|
|
fgGetString("/sim/aero"), false );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
if (result) {
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " loaded aero.");
|
|
|
|
} else {
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO,
|
|
|
|
" aero does not exist (you may have mis-typed the name).");
|
|
|
|
throw(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "" );
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "" );
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "After loading aero definition file ..." );
|
|
|
|
|
|
|
|
int Neng = Propulsion->GetNumEngines();
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "num engines = " << Neng );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
if ( GroundReactions->GetNumGearUnits() <= 0 ) {
|
|
|
|
SG_LOG( SG_FLIGHT, SG_ALERT, "num gear units = "
|
|
|
|
<< GroundReactions->GetNumGearUnits() );
|
|
|
|
SG_LOG( SG_FLIGHT, SG_ALERT, "This is a very bad thing because with 0 gear units, the ground trimming");
|
2004-06-14 11:40:45 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_ALERT, "routine (coming up later in the code) will core dump.");
|
|
|
|
SG_LOG( SG_FLIGHT, SG_ALERT, "Halting the sim now, and hoping a solution will present itself soon!");
|
|
|
|
exit(-1);
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
2004-02-14 10:19:56 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
init_gear();
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// Set initial fuel levels if provided.
|
2002-02-24 20:54:23 +00:00
|
|
|
for (unsigned int i = 0; i < Propulsion->GetNumTanks(); i++) {
|
2011-02-06 16:33:31 +00:00
|
|
|
double d;
|
2002-02-24 20:54:23 +00:00
|
|
|
SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true);
|
2011-02-06 16:33:31 +00:00
|
|
|
FGTank* tank = Propulsion->GetTank(i);
|
|
|
|
|
|
|
|
d = node->getNode( "density-ppg", true )->getDoubleValue();
|
2011-02-06 21:08:46 +00:00
|
|
|
if( d > 0.0 ) {
|
2011-02-06 16:33:31 +00:00
|
|
|
tank->SetDensity( d );
|
2011-02-06 21:08:46 +00:00
|
|
|
} else {
|
|
|
|
node->getNode( "density-ppg", true )->setDoubleValue( SG_MAX2<double>(tank->GetDensity(), 0.1) );
|
|
|
|
}
|
2011-02-06 16:33:31 +00:00
|
|
|
|
|
|
|
d = node->getNode( "level-lbs", true )->getDoubleValue();
|
2011-02-06 21:08:46 +00:00
|
|
|
if( d > 0.0 ) {
|
2011-02-06 16:33:31 +00:00
|
|
|
tank->SetContents( d );
|
2011-02-06 21:08:46 +00:00
|
|
|
} else {
|
|
|
|
node->getNode( "level-lbs", true )->setDoubleValue( tank->GetContents() );
|
|
|
|
}
|
|
|
|
/* Capacity is read-only in FGTank and can't be overwritten from FlightGear */
|
|
|
|
node->getNode("capacity-gal_us", true )->setDoubleValue( tank->GetCapacityGallons() );
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
2004-12-16 12:47:20 +00:00
|
|
|
Propulsion->SetFuelFreeze((fgGetNode("/sim/freeze/fuel",true))->getBoolValue());
|
2005-06-02 08:51:47 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
fgSetDouble("/fdm/trim/pitch-trim", FCS->GetPitchTrimCmd());
|
|
|
|
fgSetDouble("/fdm/trim/throttle", FCS->GetThrottleCmd(0));
|
|
|
|
fgSetDouble("/fdm/trim/aileron", FCS->GetDaCmd());
|
|
|
|
fgSetDouble("/fdm/trim/rudder", FCS->GetDrCmd());
|
|
|
|
|
2002-11-15 21:13:29 +00:00
|
|
|
startup_trim = fgGetNode("/sim/presets/trim", true);
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
trimmed = fgGetNode("/fdm/trim/trimmed", true);
|
|
|
|
trimmed->setBoolValue(false);
|
|
|
|
|
|
|
|
pitch_trim = fgGetNode("/fdm/trim/pitch-trim", true );
|
|
|
|
throttle_trim = fgGetNode("/fdm/trim/throttle", true );
|
|
|
|
aileron_trim = fgGetNode("/fdm/trim/aileron", true );
|
|
|
|
rudder_trim = fgGetNode("/fdm/trim/rudder", true );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-11-21 02:54:46 +00:00
|
|
|
stall_warning = fgGetNode("/sim/alarms/stall-warning",true);
|
2002-02-24 20:54:23 +00:00
|
|
|
stall_warning->setDoubleValue(0);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-03-01 12:38:37 +00:00
|
|
|
|
|
|
|
flap_pos_pct=fgGetNode("/surface-positions/flap-pos-norm",true);
|
|
|
|
elevator_pos_pct=fgGetNode("/surface-positions/elevator-pos-norm",true);
|
2002-02-28 13:32:40 +00:00
|
|
|
left_aileron_pos_pct
|
2002-03-01 12:38:37 +00:00
|
|
|
=fgGetNode("/surface-positions/left-aileron-pos-norm",true);
|
2002-02-28 13:32:40 +00:00
|
|
|
right_aileron_pos_pct
|
2002-03-01 12:38:37 +00:00
|
|
|
=fgGetNode("/surface-positions/right-aileron-pos-norm",true);
|
|
|
|
rudder_pos_pct=fgGetNode("/surface-positions/rudder-pos-norm",true);
|
2003-04-01 12:43:18 +00:00
|
|
|
speedbrake_pos_pct
|
|
|
|
=fgGetNode("/surface-positions/speedbrake-pos-norm",true);
|
|
|
|
spoilers_pos_pct=fgGetNode("/surface-positions/spoilers-pos-norm",true);
|
2008-10-23 19:04:45 +00:00
|
|
|
tailhook_pos_pct=fgGetNode("/gear/tailhook/position-norm",true);
|
|
|
|
wing_fold_pos_pct=fgGetNode("surface-positions/wing-fold-pos-norm",true);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-28 13:32:40 +00:00
|
|
|
elevator_pos_pct->setDoubleValue(0);
|
|
|
|
left_aileron_pos_pct->setDoubleValue(0);
|
|
|
|
right_aileron_pos_pct->setDoubleValue(0);
|
|
|
|
rudder_pos_pct->setDoubleValue(0);
|
|
|
|
flap_pos_pct->setDoubleValue(0);
|
2003-04-01 12:43:18 +00:00
|
|
|
speedbrake_pos_pct->setDoubleValue(0);
|
|
|
|
spoilers_pos_pct->setDoubleValue(0);
|
2002-02-28 13:32:40 +00:00
|
|
|
|
2010-07-16 09:05:59 +00:00
|
|
|
ab_brake_engaged = fgGetNode("/autopilot/autobrake/engaged", true);
|
|
|
|
ab_brake_left_pct = fgGetNode("/autopilot/autobrake/brake-left-output", true);
|
|
|
|
ab_brake_right_pct = fgGetNode("/autopilot/autobrake/brake-right-output", true);
|
|
|
|
|
2002-06-08 03:15:05 +00:00
|
|
|
temperature = fgGetNode("/environment/temperature-degc",true);
|
|
|
|
pressure = fgGetNode("/environment/pressure-inhg",true);
|
|
|
|
density = fgGetNode("/environment/density-slugft3",true);
|
2003-07-13 20:13:18 +00:00
|
|
|
turbulence_gain = fgGetNode("/environment/turbulence/magnitude-norm",true);
|
|
|
|
turbulence_rate = fgGetNode("/environment/turbulence/rate-hz",true);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-06-08 03:15:05 +00:00
|
|
|
wind_from_north= fgGetNode("/environment/wind-from-north-fps",true);
|
|
|
|
wind_from_east = fgGetNode("/environment/wind-from-east-fps" ,true);
|
|
|
|
wind_from_down = fgGetNode("/environment/wind-from-down-fps" ,true);
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2007-01-15 12:48:54 +00:00
|
|
|
slaved = fgGetNode("/sim/slaved/enabled", true);
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) {
|
|
|
|
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
2004-06-14 11:40:45 +00:00
|
|
|
Propulsion->GetEngine(i)->GetThruster()->SetRPM(node->getDoubleValue("rpm") /
|
|
|
|
Propulsion->GetEngine(i)->GetThruster()->GetGearRatio());
|
2004-01-14 22:09:39 +00:00
|
|
|
}
|
2008-07-10 17:23:02 +00:00
|
|
|
|
|
|
|
hook_root_struct = FGColumnVector3(
|
|
|
|
fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-offset-x-in", 196),
|
|
|
|
fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-offset-y-in", 0),
|
|
|
|
fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-offset-z-in", -16));
|
2011-01-25 00:26:07 +00:00
|
|
|
last_hook_tip[0] = 0; last_hook_tip[1] = 0; last_hook_tip[2] = 0;
|
|
|
|
last_hook_root[0] = 0; last_hook_root[1] = 0; last_hook_root[2] = 0;
|
2008-10-23 19:04:45 +00:00
|
|
|
|
|
|
|
crashed = false;
|
2002-02-26 22:27:42 +00:00
|
|
|
}
|
2004-01-14 22:09:39 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
/******************************************************************************/
|
2004-01-14 22:09:39 +00:00
|
|
|
FGJSBsim::~FGJSBsim(void)
|
|
|
|
{
|
|
|
|
delete fdmex;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// Initialize the JSBsim flight model, dt is the time increment for
|
|
|
|
// each subsequent iteration through the EOM
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::init()
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "Starting and initializing JSBsim" );
|
2002-06-08 03:15:05 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
// Explicitly call the superclass's
|
|
|
|
// init method first.
|
2002-06-08 03:15:05 +00:00
|
|
|
|
|
|
|
if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
|
|
|
|
Atmosphere->UseExternal();
|
|
|
|
Atmosphere->SetExTemperature(
|
|
|
|
9.0/5.0*(temperature->getDoubleValue()+273.15) );
|
|
|
|
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
|
|
|
|
Atmosphere->SetExDensity(density->getDoubleValue());
|
2008-07-24 19:50:58 +00:00
|
|
|
Atmosphere->SetTurbType(FGAtmosphere::ttCulp);
|
2008-07-10 17:23:02 +00:00
|
|
|
Atmosphere->SetTurbGain(turbulence_gain->getDoubleValue());
|
|
|
|
Atmosphere->SetTurbRate(turbulence_rate->getDoubleValue());
|
2003-07-13 20:13:18 +00:00
|
|
|
|
2002-06-08 03:15:05 +00:00
|
|
|
} else {
|
|
|
|
Atmosphere->UseInternal();
|
|
|
|
}
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2009-04-13 11:47:57 +00:00
|
|
|
fgic->SetVNorthFpsIC( -wind_from_north->getDoubleValue() );
|
|
|
|
fgic->SetVEastFpsIC( -wind_from_east->getDoubleValue() );
|
|
|
|
fgic->SetVDownFpsIC( -wind_from_down->getDoubleValue() );
|
2002-06-08 03:15:05 +00:00
|
|
|
|
|
|
|
//Atmosphere->SetExTemperature(get_Static_temperature());
|
|
|
|
//Atmosphere->SetExPressure(get_Static_pressure());
|
|
|
|
//Atmosphere->SetExDensity(get_Density());
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO,"T,p,rho: " << fdmex->GetAtmosphere()->GetTemperature()
|
2004-03-14 14:57:07 +00:00
|
|
|
<< ", " << fdmex->GetAtmosphere()->GetPressure()
|
2002-06-08 03:15:05 +00:00
|
|
|
<< ", " << fdmex->GetAtmosphere()->GetDensity() );
|
|
|
|
|
2010-07-16 09:05:59 +00:00
|
|
|
// deprecate egt_degf for egt-degf to have consistent naming
|
|
|
|
// TODO: raise log-level to ALERT in summer 2010,
|
|
|
|
// remove alias in fall 2010,
|
|
|
|
// remove this code in winter 2010
|
|
|
|
for (unsigned int i=0; i < Propulsion->GetNumEngines(); i++) {
|
|
|
|
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
|
|
|
SGPropertyNode * egtn = node->getNode( "egt_degf" );
|
|
|
|
if( egtn != NULL ) {
|
|
|
|
SG_LOG(SG_FLIGHT,SG_WARN,
|
|
|
|
"Aircraft uses deprecated node egt_degf. Please upgrade to egt-degf");
|
|
|
|
node->getNode("egt-degf", true)->alias( egtn );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// end of egt_degf deprecation patch
|
|
|
|
|
2005-06-02 08:51:47 +00:00
|
|
|
if (fgGetBool("/sim/presets/running")) {
|
2009-03-27 11:44:33 +00:00
|
|
|
for (unsigned int i=0; i < Propulsion->GetNumEngines(); i++) {
|
2005-06-02 08:51:47 +00:00
|
|
|
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
|
|
|
node->setBoolValue("running", true);
|
|
|
|
Propulsion->GetEngine(i)->SetRunning(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-10 17:23:02 +00:00
|
|
|
FCS->SetDfPos( ofNorm, globals->get_controls()->get_flaps() );
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
common_init();
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
copy_to_JSBsim();
|
|
|
|
fdmex->RunIC(); //loop JSBSim once w/o integrating
|
2002-02-24 20:54:23 +00:00
|
|
|
copy_from_JSBsim(); //update the bus
|
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Initialized JSBSim with:" );
|
|
|
|
|
|
|
|
switch(fgic->GetSpeedSet()) {
|
|
|
|
case setned:
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, " Vn,Ve,Vd= "
|
2006-01-12 15:04:22 +00:00
|
|
|
<< Propagate->GetVel(FGJSBBase::eNorth) << ", "
|
|
|
|
<< Propagate->GetVel(FGJSBBase::eEast) << ", "
|
|
|
|
<< Propagate->GetVel(FGJSBBase::eDown) << " ft/s");
|
2002-02-24 20:54:23 +00:00
|
|
|
break;
|
|
|
|
case setuvw:
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, " U,V,W= "
|
2004-06-14 11:40:45 +00:00
|
|
|
<< Propagate->GetUVW(1) << ", "
|
|
|
|
<< Propagate->GetUVW(2) << ", "
|
|
|
|
<< Propagate->GetUVW(3) << " ft/s");
|
2002-02-24 20:54:23 +00:00
|
|
|
break;
|
|
|
|
case setmach:
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, " Mach: "
|
2004-06-14 11:40:45 +00:00
|
|
|
<< Auxiliary->GetMach() );
|
2002-02-24 20:54:23 +00:00
|
|
|
break;
|
|
|
|
case setvc:
|
|
|
|
default:
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, " Indicated Airspeed: "
|
|
|
|
<< Auxiliary->GetVcalibratedKTS() << " knots" );
|
|
|
|
break;
|
|
|
|
}
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
stall_warning->setDoubleValue(0);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Bank Angle: "
|
2006-01-12 15:04:22 +00:00
|
|
|
<< Propagate->GetEuler(FGJSBBase::ePhi)*RADTODEG << " deg" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Pitch Angle: "
|
2006-01-12 15:04:22 +00:00
|
|
|
<< Propagate->GetEuler(FGJSBBase::eTht)*RADTODEG << " deg" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " True Heading: "
|
2006-01-12 15:04:22 +00:00
|
|
|
<< Propagate->GetEuler(FGJSBBase::ePsi)*RADTODEG << " deg" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Latitude: "
|
2004-06-14 11:40:45 +00:00
|
|
|
<< Propagate->GetLocation().GetLatitudeDeg() << " deg" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: "
|
2004-06-14 11:40:45 +00:00
|
|
|
<< Propagate->GetLocation().GetLongitudeDeg() << " deg" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Altitude: "
|
2009-06-01 08:52:34 +00:00
|
|
|
<< Propagate->GetAltitudeASL() << " feet" );
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " loaded initial conditions" );
|
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " set dt" );
|
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "Finished initializing JSBSim" );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "FGControls::get_gear_down()= " <<
|
2002-02-24 20:54:23 +00:00
|
|
|
globals->get_controls()->get_gear_down() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2011-01-30 10:04:37 +00:00
|
|
|
void FGJSBsim::unbind()
|
|
|
|
{
|
2011-02-06 14:16:58 +00:00
|
|
|
fdmex->Unbind();
|
2011-01-30 10:04:37 +00:00
|
|
|
FGInterface::unbind();
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
// Run an iteration of the EOM (equations of motion)
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::update( double dt )
|
|
|
|
{
|
2008-10-23 19:04:45 +00:00
|
|
|
if(crashed) {
|
|
|
|
if(!fgGetBool("/sim/crashed"))
|
|
|
|
fgSetBool("/sim/crashed", true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-11 16:28:50 +00:00
|
|
|
if (is_suspended())
|
|
|
|
return;
|
|
|
|
|
|
|
|
int multiloop = _calc_multiloop(dt);
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
int i;
|
|
|
|
|
2005-05-22 08:06:47 +00:00
|
|
|
// Compute the radius of the aircraft. That is the radius of a ball
|
|
|
|
// where all gear units are in. At the moment it is at least 10ft ...
|
|
|
|
double acrad = 10.0;
|
|
|
|
int n_gears = GroundReactions->GetNumGearUnits();
|
|
|
|
for (i=0; i<n_gears; ++i) {
|
|
|
|
FGColumnVector3 bl = GroundReactions->GetGearUnit(i)->GetBodyLocation();
|
|
|
|
double r = bl.Magnitude();
|
|
|
|
if (acrad < r)
|
|
|
|
acrad = r;
|
|
|
|
}
|
2002-05-07 23:11:16 +00:00
|
|
|
|
2005-05-22 08:06:47 +00:00
|
|
|
// Compute the potential movement of this aircraft and query for the
|
|
|
|
// ground in this area.
|
|
|
|
double groundCacheRadius = acrad + 2*dt*Propagate->GetUVW().Magnitude();
|
2005-06-02 08:51:47 +00:00
|
|
|
double alt, slr, lat, lon;
|
2010-11-28 09:58:47 +00:00
|
|
|
FGLocation cart = Auxiliary->GetLocationVRP();
|
2005-05-22 08:06:47 +00:00
|
|
|
if ( needTrim && startup_trim->getBoolValue() ) {
|
2009-06-01 08:52:34 +00:00
|
|
|
alt = fgic->GetAltitudeASLFtIC();
|
2005-06-02 08:51:47 +00:00
|
|
|
slr = fgic->GetSeaLevelRadiusFtIC();
|
|
|
|
lat = fgic->GetLatitudeDegIC() * SGD_DEGREES_TO_RADIANS;
|
|
|
|
lon = fgic->GetLongitudeDegIC() * SGD_DEGREES_TO_RADIANS;
|
2005-05-22 08:06:47 +00:00
|
|
|
cart = FGLocation(lon, lat, alt+slr);
|
|
|
|
}
|
|
|
|
double cart_pos[3] = { cart(1), cart(2), cart(3) };
|
2010-07-16 09:05:59 +00:00
|
|
|
double t0 = fdmex->GetSimTime();
|
2009-03-15 11:26:31 +00:00
|
|
|
bool cache_ok = prepare_ground_cache_ft( t0, t0 + dt, cart_pos,
|
2005-05-22 08:06:47 +00:00
|
|
|
groundCacheRadius );
|
|
|
|
if (!cache_ok) {
|
|
|
|
SG_LOG(SG_FLIGHT, SG_WARN,
|
2005-06-02 08:51:47 +00:00
|
|
|
"FGInterface is being called without scenery below the aircraft!");
|
2009-03-27 11:44:33 +00:00
|
|
|
|
2009-06-01 08:52:34 +00:00
|
|
|
alt = fgic->GetAltitudeASLFtIC();
|
2009-03-27 11:44:33 +00:00
|
|
|
SG_LOG(SG_FLIGHT, SG_WARN, "altitude = " << alt);
|
|
|
|
|
|
|
|
slr = fgic->GetSeaLevelRadiusFtIC();
|
|
|
|
SG_LOG(SG_FLIGHT, SG_WARN, "sea level radius = " << slr);
|
|
|
|
|
|
|
|
lat = fgic->GetLatitudeDegIC() * SGD_DEGREES_TO_RADIANS;
|
|
|
|
SG_LOG(SG_FLIGHT, SG_WARN, "latitude = " << lat);
|
|
|
|
|
|
|
|
lon = fgic->GetLongitudeDegIC() * SGD_DEGREES_TO_RADIANS;
|
|
|
|
SG_LOG(SG_FLIGHT, SG_WARN, "longitude = " << lon);
|
2005-06-02 08:51:47 +00:00
|
|
|
//return;
|
2005-05-22 08:06:47 +00:00
|
|
|
}
|
2005-06-02 08:51:47 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
copy_to_JSBsim();
|
|
|
|
|
|
|
|
trimmed->setBoolValue(false);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
if ( needTrim ) {
|
|
|
|
if ( startup_trim->getBoolValue() ) {
|
2010-11-28 09:58:47 +00:00
|
|
|
double contact[3], d[3], vel[3], agl;
|
2010-07-16 09:05:59 +00:00
|
|
|
get_agl_ft(fdmex->GetSimTime(), cart_pos, SG_METER_TO_FEET*2, contact,
|
2010-11-28 09:58:47 +00:00
|
|
|
d, vel, d, &agl);
|
2005-05-22 08:06:47 +00:00
|
|
|
double terrain_alt = sqrt(contact[0]*contact[0] + contact[1]*contact[1]
|
|
|
|
+ contact[2]*contact[2]) - fgic->GetSeaLevelRadiusFtIC();
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT, SG_INFO,
|
2009-06-01 08:52:34 +00:00
|
|
|
"Ready to trim, terrain elevation is: "
|
2005-05-22 08:06:47 +00:00
|
|
|
<< terrain_alt * SG_METER_TO_FEET );
|
|
|
|
|
2010-11-28 09:58:47 +00:00
|
|
|
if (fgGetBool("/sim/presets/onground")) {
|
|
|
|
FGColumnVector3 gndVelNED = cart.GetTec2l()
|
|
|
|
* FGColumnVector3(vel[0], vel[1], vel[2]);
|
|
|
|
fgic->SetVNorthFpsIC(gndVelNED(1));
|
|
|
|
fgic->SetVEastFpsIC(gndVelNED(2));
|
|
|
|
fgic->SetVDownFpsIC(gndVelNED(3));
|
|
|
|
}
|
2009-06-01 08:52:34 +00:00
|
|
|
fgic->SetTerrainElevationFtIC( terrain_alt );
|
2002-02-24 20:54:23 +00:00
|
|
|
do_trim();
|
|
|
|
} else {
|
2002-09-22 15:31:09 +00:00
|
|
|
fdmex->RunIC(); //apply any changes made through the set_ functions
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
2004-03-14 14:57:07 +00:00
|
|
|
needTrim = false;
|
|
|
|
}
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
for ( i=0; i < multiloop; i++ ) {
|
2004-01-14 22:09:39 +00:00
|
|
|
fdmex->Run();
|
2010-07-16 09:05:59 +00:00
|
|
|
update_external_forces(fdmex->GetSimTime() + i * fdmex->GetDeltaT());
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGJSBBase::Message* msg;
|
2011-02-14 19:58:54 +00:00
|
|
|
while ((msg = fdmex->ProcessNextMessage()) != NULL) {
|
2009-08-16 19:36:55 +00:00
|
|
|
// msg = fdmex->ProcessNextMessage();
|
2002-02-24 20:54:23 +00:00
|
|
|
switch (msg->type) {
|
|
|
|
case FGJSBBase::Message::eText:
|
2008-10-23 19:04:45 +00:00
|
|
|
if (msg->text == "Crash Detected: Simulation FREEZE.")
|
|
|
|
crashed = true;
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, msg->messageId << ": " << msg->text );
|
|
|
|
break;
|
|
|
|
case FGJSBBase::Message::eBool:
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, msg->messageId << ": " << msg->text << " " << msg->bVal );
|
|
|
|
break;
|
|
|
|
case FGJSBBase::Message::eInteger:
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, msg->messageId << ": " << msg->text << " " << msg->iVal );
|
|
|
|
break;
|
|
|
|
case FGJSBBase::Message::eDouble:
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, msg->messageId << ": " << msg->text << " " << msg->dVal );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, "Unrecognized message type." );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// translate JSBsim back to FG structure so that the
|
|
|
|
// autopilot (and the rest of the sim can use the updated values
|
|
|
|
copy_from_JSBsim();
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2011-03-23 22:52:36 +00:00
|
|
|
void FGJSBsim::suspend()
|
|
|
|
{
|
|
|
|
fdmex->Hold();
|
|
|
|
SGSubsystem::suspend();
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
void FGJSBsim::resume()
|
|
|
|
{
|
|
|
|
fdmex->Resume();
|
|
|
|
SGSubsystem::resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
// Convert from the FGInterface struct to the JSBsim generic_ struct
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
bool FGJSBsim::copy_to_JSBsim()
|
|
|
|
{
|
2003-07-13 20:13:18 +00:00
|
|
|
double tmp;
|
2002-02-24 20:54:23 +00:00
|
|
|
unsigned int i;
|
2002-05-07 23:11:16 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
// copy control positions into the JSBsim structure
|
|
|
|
|
2002-05-07 23:11:16 +00:00
|
|
|
FCS->SetDaCmd( globals->get_controls()->get_aileron());
|
|
|
|
FCS->SetRollTrimCmd( globals->get_controls()->get_aileron_trim() );
|
|
|
|
FCS->SetDeCmd( globals->get_controls()->get_elevator());
|
|
|
|
FCS->SetPitchTrimCmd( globals->get_controls()->get_elevator_trim() );
|
|
|
|
FCS->SetDrCmd( -globals->get_controls()->get_rudder() );
|
|
|
|
FCS->SetYawTrimCmd( -globals->get_controls()->get_rudder_trim() );
|
2004-09-11 12:41:05 +00:00
|
|
|
FCS->SetDsCmd( globals->get_controls()->get_rudder() );
|
|
|
|
FCS->SetDfCmd( globals->get_controls()->get_flaps() );
|
2004-03-14 14:57:07 +00:00
|
|
|
FCS->SetDsbCmd( globals->get_controls()->get_speedbrake() );
|
|
|
|
FCS->SetDspCmd( globals->get_controls()->get_spoilers() );
|
2002-05-07 23:11:16 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// Parking brake sets minimum braking
|
|
|
|
// level for mains.
|
2004-01-12 17:39:41 +00:00
|
|
|
double parking_brake = globals->get_controls()->get_brake_parking();
|
2009-10-16 08:05:50 +00:00
|
|
|
double left_brake = globals->get_controls()->get_brake_left();
|
|
|
|
double right_brake = globals->get_controls()->get_brake_right();
|
2010-07-16 09:05:59 +00:00
|
|
|
|
|
|
|
if (ab_brake_engaged->getBoolValue()) {
|
|
|
|
left_brake = ab_brake_left_pct->getDoubleValue();
|
|
|
|
right_brake = ab_brake_right_pct->getDoubleValue();
|
|
|
|
}
|
|
|
|
|
2009-10-16 08:05:50 +00:00
|
|
|
FCS->SetLBrake(FMAX(left_brake, parking_brake));
|
|
|
|
FCS->SetRBrake(FMAX(right_brake, parking_brake));
|
|
|
|
|
|
|
|
|
2004-01-12 17:39:41 +00:00
|
|
|
FCS->SetCBrake( 0.0 );
|
2004-01-14 22:09:39 +00:00
|
|
|
// FCS->SetCBrake( globals->get_controls()->get_brake(2) );
|
2002-05-07 23:11:16 +00:00
|
|
|
|
|
|
|
FCS->SetGearCmd( globals->get_controls()->get_gear_down());
|
|
|
|
for (i = 0; i < Propulsion->GetNumEngines(); i++) {
|
|
|
|
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
2004-01-14 22:09:39 +00:00
|
|
|
|
2002-05-07 23:11:16 +00:00
|
|
|
FCS->SetThrottleCmd(i, globals->get_controls()->get_throttle(i));
|
|
|
|
FCS->SetMixtureCmd(i, globals->get_controls()->get_mixture(i));
|
|
|
|
FCS->SetPropAdvanceCmd(i, globals->get_controls()->get_prop_advance(i));
|
2006-01-12 15:04:22 +00:00
|
|
|
FCS->SetFeatherCmd(i, globals->get_controls()->get_feather(i));
|
2004-01-14 22:09:39 +00:00
|
|
|
|
|
|
|
switch (Propulsion->GetEngine(i)->GetType()) {
|
|
|
|
case FGEngine::etPiston:
|
|
|
|
{ // FGPiston code block
|
|
|
|
FGPiston* eng = (FGPiston*)Propulsion->GetEngine(i);
|
|
|
|
eng->SetMagnetos( globals->get_controls()->get_magnetos(i) );
|
|
|
|
break;
|
|
|
|
} // end FGPiston code block
|
2004-06-14 11:40:45 +00:00
|
|
|
case FGEngine::etTurbine:
|
|
|
|
{ // FGTurbine code block
|
|
|
|
FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
|
2004-01-14 22:09:39 +00:00
|
|
|
eng->SetAugmentation( globals->get_controls()->get_augmentation(i) );
|
|
|
|
eng->SetReverse( globals->get_controls()->get_reverser(i) );
|
2008-07-10 17:23:02 +00:00
|
|
|
//eng->SetInjection( globals->get_controls()->get_water_injection(i) );
|
2004-01-14 22:09:39 +00:00
|
|
|
eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
|
|
|
|
eng->SetIgnition( globals->get_controls()->get_ignition(i) );
|
|
|
|
break;
|
2004-06-14 11:40:45 +00:00
|
|
|
} // end FGTurbine code block
|
2004-01-14 22:09:39 +00:00
|
|
|
case FGEngine::etRocket:
|
|
|
|
{ // FGRocket code block
|
2011-02-14 19:58:54 +00:00
|
|
|
// FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
|
2004-01-14 22:09:39 +00:00
|
|
|
break;
|
|
|
|
} // end FGRocket code block
|
2006-01-12 15:04:22 +00:00
|
|
|
case FGEngine::etTurboprop:
|
|
|
|
{ // FGTurboProp code block
|
|
|
|
FGTurboProp* eng = (FGTurboProp*)Propulsion->GetEngine(i);
|
|
|
|
eng->SetReverse( globals->get_controls()->get_reverser(i) );
|
|
|
|
eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
|
|
|
|
eng->SetIgnition( globals->get_controls()->get_ignition(i) );
|
|
|
|
|
2008-07-10 17:23:02 +00:00
|
|
|
eng->SetGeneratorPower( globals->get_controls()->get_generator_breaker(i) );
|
|
|
|
eng->SetCondition( globals->get_controls()->get_condition(i) );
|
2006-01-12 15:04:22 +00:00
|
|
|
break;
|
|
|
|
} // end FGTurboProp code block
|
2009-03-27 11:44:33 +00:00
|
|
|
default:
|
|
|
|
break;
|
2004-01-14 22:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // FGEngine code block
|
|
|
|
FGEngine* eng = Propulsion->GetEngine(i);
|
|
|
|
|
2002-05-07 23:11:16 +00:00
|
|
|
eng->SetStarter( globals->get_controls()->get_starter(i) );
|
David Culp:
Here's a new FGSimTurbine module. Changes are:
1. Adds starting and stopping functionality
2. Calculate() now calls other functions, based on the engine's state, which gives more readable code.
Until now turbine engines were always running as long as fuel was available. With this new module the engine defaults to OFF. To start with the engine running, the variable FGEngine::Running must be set to true at sim startup. In FlightGear this is done with --prop:/engines/engine[n]/running=true.
To start the engine (on the ground), first set the starter to ON, i.e. FGEngine::Starter is set to true. In FlightGear this is done by toggling /controls/engines/engine[n]/starter to TRUE. Note that the current FlightGear key binding will not work, as it causes the starter to quit when the key is released. A new key binding is needed, without the mod-up.
When N2 reaches 15% or greater, place the fuel cutoff control to FALSE. This is FGEngine::Cutoff. In FlightGear this is done with /controls/engines/engine[n]/cutoff set to FALSE. The engine will then accelerate to idle. Upon reaching idle, the starter is automatically turned off, and the engine is running. There is presently no FlightGear key binding for the fuel cutoff switch.
To shut off the engine, place the fuel cutoff control to TRUE.
If you shut down the engine in flight it will windmill. To airstart you will need at least 15% N2, just as with a ground start. When you have enough N2, place the cutoff control to FALSE and the engine will restart. Note that if you can't get enough N2 by speeding up, you can get it by using the starter.
The reverser still works, and is controlled in FlightGear with /controls/engines/engine[n]/reverser. With the reverser control on (TRUE), the engine will produce negative thrust in proportion to throttle position, i.e. to get more reverse
thrust, increase throttle.
2003-09-23 09:25:24 +00:00
|
|
|
eng->SetRunning( node->getBoolValue("running") );
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGEngine code block
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2005-06-02 08:51:47 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2002-06-08 03:15:05 +00:00
|
|
|
Atmosphere->SetExTemperature(
|
|
|
|
9.0/5.0*(temperature->getDoubleValue()+273.15) );
|
|
|
|
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
|
|
|
|
Atmosphere->SetExDensity(density->getDoubleValue());
|
2003-07-13 20:13:18 +00:00
|
|
|
|
|
|
|
tmp = turbulence_gain->getDoubleValue();
|
2008-07-10 17:23:02 +00:00
|
|
|
//Atmosphere->SetTurbGain(tmp * tmp * 100.0);
|
2003-07-13 20:13:18 +00:00
|
|
|
|
2003-10-19 09:48:44 +00:00
|
|
|
tmp = turbulence_rate->getDoubleValue();
|
2008-07-10 17:23:02 +00:00
|
|
|
//Atmosphere->SetTurbRate(tmp);
|
2002-06-08 03:15:05 +00:00
|
|
|
|
2009-04-13 11:47:57 +00:00
|
|
|
Atmosphere->SetWindNED( -wind_from_north->getDoubleValue(),
|
|
|
|
-wind_from_east->getDoubleValue(),
|
|
|
|
-wind_from_down->getDoubleValue() );
|
2002-05-07 23:11:16 +00:00
|
|
|
// SG_LOG(SG_FLIGHT,SG_INFO, "Wind NED: "
|
|
|
|
// << get_V_north_airmass() << ", "
|
|
|
|
// << get_V_east_airmass() << ", "
|
|
|
|
// << get_V_down_airmass() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2002-05-07 23:11:16 +00:00
|
|
|
for (i = 0; i < Propulsion->GetNumTanks(); i++) {
|
|
|
|
SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true);
|
|
|
|
FGTank * tank = Propulsion->GetTank(i);
|
2011-02-06 16:33:31 +00:00
|
|
|
double fuelDensity = node->getDoubleValue("density-ppg");
|
|
|
|
|
|
|
|
if (fuelDensity < 0.1)
|
|
|
|
fuelDensity = 6.0; // Use average fuel value
|
|
|
|
|
|
|
|
tank->SetDensity(fuelDensity);
|
|
|
|
tank->SetContents(node->getDoubleValue("level-lbs"));
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
2008-07-10 17:23:02 +00:00
|
|
|
|
2004-12-16 12:47:20 +00:00
|
|
|
Propulsion->SetFuelFreeze((fgGetNode("/sim/freeze/fuel",true))->getBoolValue());
|
2009-06-01 08:52:34 +00:00
|
|
|
fdmex->SetChild(slaved->getBoolValue());
|
2005-06-02 08:51:47 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// Convert from the JSBsim generic_ struct to the FGInterface struct
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
bool FGJSBsim::copy_from_JSBsim()
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
unsigned int i, j;
|
2004-03-14 14:57:07 +00:00
|
|
|
/*
|
2002-02-24 20:54:23 +00:00
|
|
|
_set_Inertias( MassBalance->GetMass(),
|
|
|
|
MassBalance->GetIxx(),
|
|
|
|
MassBalance->GetIyy(),
|
|
|
|
MassBalance->GetIzz(),
|
|
|
|
MassBalance->GetIxz() );
|
2004-03-14 14:57:07 +00:00
|
|
|
*/
|
2002-02-24 20:54:23 +00:00
|
|
|
_set_CG_Position( MassBalance->GetXYZcg(1),
|
|
|
|
MassBalance->GetXYZcg(2),
|
|
|
|
MassBalance->GetXYZcg(3) );
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
_set_Accels_Body( Aircraft->GetBodyAccel(1),
|
|
|
|
Aircraft->GetBodyAccel(2),
|
|
|
|
Aircraft->GetBodyAccel(3) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
_set_Accels_CG_Body_N ( Aircraft->GetNcg(1),
|
|
|
|
Aircraft->GetNcg(2),
|
|
|
|
Aircraft->GetNcg(3) );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
_set_Accels_Pilot_Body( Auxiliary->GetPilotAccel(1),
|
|
|
|
Auxiliary->GetPilotAccel(2),
|
|
|
|
Auxiliary->GetPilotAccel(3) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
_set_Nlf( Aircraft->GetNlf() );
|
|
|
|
|
|
|
|
// Velocities
|
|
|
|
|
2006-01-12 15:04:22 +00:00
|
|
|
_set_Velocities_Local( Propagate->GetVel(FGJSBBase::eNorth),
|
|
|
|
Propagate->GetVel(FGJSBBase::eEast),
|
|
|
|
Propagate->GetVel(FGJSBBase::eDown) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Velocities_Wind_Body( Propagate->GetUVW(1),
|
|
|
|
Propagate->GetUVW(2),
|
|
|
|
Propagate->GetUVW(3) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-03-14 14:57:07 +00:00
|
|
|
// Make the HUD work ...
|
2006-01-12 15:04:22 +00:00
|
|
|
_set_Velocities_Ground( Propagate->GetVel(FGJSBBase::eNorth),
|
|
|
|
Propagate->GetVel(FGJSBBase::eEast),
|
|
|
|
-Propagate->GetVel(FGJSBBase::eDown) );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_V_rel_wind( Auxiliary->GetVt() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
_set_V_equiv_kts( Auxiliary->GetVequivalentKTS() );
|
|
|
|
|
|
|
|
_set_V_calibrated_kts( Auxiliary->GetVcalibratedKTS() );
|
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_V_ground_speed( Auxiliary->GetVground() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2006-01-12 15:04:22 +00:00
|
|
|
_set_Omega_Body( Propagate->GetPQR(FGJSBBase::eP),
|
|
|
|
Propagate->GetPQR(FGJSBBase::eQ),
|
|
|
|
Propagate->GetPQR(FGJSBBase::eR) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2006-01-12 15:04:22 +00:00
|
|
|
_set_Euler_Rates( Auxiliary->GetEulerRates(FGJSBBase::ePhi),
|
|
|
|
Auxiliary->GetEulerRates(FGJSBBase::eTht),
|
|
|
|
Auxiliary->GetEulerRates(FGJSBBase::ePsi) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Mach_number( Auxiliary->GetMach() );
|
2004-01-14 22:09:39 +00:00
|
|
|
|
|
|
|
// Positions of Visual Reference Point
|
2005-05-22 08:06:47 +00:00
|
|
|
FGLocation l = Auxiliary->GetLocationVRP();
|
|
|
|
_updateGeocentricPosition( l.GetLatitude(), l.GetLongitude(),
|
|
|
|
l.GetRadius() - get_Sea_level_radius() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Altitude_AGL( Propagate->GetDistanceAGL() );
|
2005-05-22 08:06:47 +00:00
|
|
|
{
|
2006-01-12 15:04:22 +00:00
|
|
|
double loc_cart[3] = { l(FGJSBBase::eX), l(FGJSBBase::eY), l(FGJSBBase::eZ) };
|
2005-05-22 08:06:47 +00:00
|
|
|
double contact[3], d[3], sd, t;
|
|
|
|
is_valid_m(&t, d, &sd);
|
2010-10-26 07:48:56 +00:00
|
|
|
get_agl_ft(t, loc_cart, SG_METER_TO_FEET*2, contact, d, d, d, &sd);
|
2005-05-22 08:06:47 +00:00
|
|
|
double rwrad
|
|
|
|
= FGColumnVector3( contact[0], contact[1], contact[2] ).Magnitude();
|
|
|
|
_set_Runway_altitude( rwrad - get_Sea_level_radius() );
|
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2006-01-12 15:04:22 +00:00
|
|
|
_set_Euler_Angles( Propagate->GetEuler(FGJSBBase::ePhi),
|
|
|
|
Propagate->GetEuler(FGJSBBase::eTht),
|
|
|
|
Propagate->GetEuler(FGJSBBase::ePsi) );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Alpha( Auxiliary->Getalpha() );
|
|
|
|
_set_Beta( Auxiliary->Getbeta() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Gamma_vert_rad( Auxiliary->GetGamma() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2008-07-10 17:23:02 +00:00
|
|
|
_set_Earth_position_angle( Inertial->GetEarthPositionAngle() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_Climb_Rate( Propagate->Gethdot() );
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-06-14 11:40:45 +00:00
|
|
|
const FGMatrix33& Tl2b = Propagate->GetTl2b();
|
2002-02-24 20:54:23 +00:00
|
|
|
for ( i = 1; i <= 3; i++ ) {
|
|
|
|
for ( j = 1; j <= 3; j++ ) {
|
2004-06-14 11:40:45 +00:00
|
|
|
_set_T_Local_to_Body( i, j, Tl2b(i,j) );
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// Copy the engine values from JSBSim.
|
|
|
|
for ( i=0; i < Propulsion->GetNumEngines(); i++ ) {
|
2002-05-07 23:11:16 +00:00
|
|
|
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
|
2009-10-26 13:29:58 +00:00
|
|
|
SGPropertyNode * tnode = node->getChild("thruster", 0, true);
|
2004-06-14 11:40:45 +00:00
|
|
|
FGThruster * thruster = Propulsion->GetEngine(i)->GetThruster();
|
2004-01-14 22:09:39 +00:00
|
|
|
|
|
|
|
switch (Propulsion->GetEngine(i)->GetType()) {
|
|
|
|
case FGEngine::etPiston:
|
|
|
|
{ // FGPiston code block
|
|
|
|
FGPiston* eng = (FGPiston*)Propulsion->GetEngine(i);
|
|
|
|
node->setDoubleValue("egt-degf", eng->getExhaustGasTemp_degF());
|
|
|
|
node->setDoubleValue("oil-temperature-degf", eng->getOilTemp_degF());
|
|
|
|
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
|
|
|
|
node->setDoubleValue("mp-osi", eng->getManifoldPressure_inHg());
|
2008-11-30 10:44:29 +00:00
|
|
|
// NOTE: mp-osi is not in ounces per square inch.
|
|
|
|
// This error is left for reasons of backwards compatibility with
|
|
|
|
// existing FlightGear sound and instrument configurations.
|
|
|
|
node->setDoubleValue("mp-inhg", eng->getManifoldPressure_inHg());
|
2004-01-14 22:09:39 +00:00
|
|
|
node->setDoubleValue("cht-degf", eng->getCylinderHeadTemp_degF());
|
|
|
|
node->setDoubleValue("rpm", eng->getRPM());
|
|
|
|
} // end FGPiston code block
|
|
|
|
break;
|
|
|
|
case FGEngine::etRocket:
|
|
|
|
{ // FGRocket code block
|
2011-02-14 19:58:54 +00:00
|
|
|
// FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGRocket code block
|
|
|
|
break;
|
2004-06-14 11:40:45 +00:00
|
|
|
case FGEngine::etTurbine:
|
|
|
|
{ // FGTurbine code block
|
|
|
|
FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
|
2004-02-17 09:07:27 +00:00
|
|
|
node->setDoubleValue("n1", eng->GetN1());
|
|
|
|
node->setDoubleValue("n2", eng->GetN2());
|
2010-07-16 09:05:59 +00:00
|
|
|
node->setDoubleValue("egt-degf", 32 + eng->GetEGT()*9/5);
|
2004-01-14 22:09:39 +00:00
|
|
|
node->setBoolValue("augmentation", eng->GetAugmentation());
|
|
|
|
node->setBoolValue("water-injection", eng->GetInjection());
|
2011-02-14 21:11:56 +00:00
|
|
|
node->setBoolValue("ignition", eng->GetIgnition() != 0);
|
2004-01-14 22:09:39 +00:00
|
|
|
node->setDoubleValue("nozzle-pos-norm", eng->GetNozzle());
|
|
|
|
node->setDoubleValue("inlet-pos-norm", eng->GetInlet());
|
2004-03-14 14:57:07 +00:00
|
|
|
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
|
2004-01-14 22:09:39 +00:00
|
|
|
node->setBoolValue("reversed", eng->GetReversed());
|
|
|
|
node->setBoolValue("cutoff", eng->GetCutoff());
|
2004-06-14 11:40:45 +00:00
|
|
|
node->setDoubleValue("epr", eng->GetEPR());
|
2004-01-14 22:09:39 +00:00
|
|
|
globals->get_controls()->set_reverser(i, eng->GetReversed() );
|
|
|
|
globals->get_controls()->set_cutoff(i, eng->GetCutoff() );
|
|
|
|
globals->get_controls()->set_water_injection(i, eng->GetInjection() );
|
|
|
|
globals->get_controls()->set_augmentation(i, eng->GetAugmentation() );
|
2004-06-14 11:40:45 +00:00
|
|
|
} // end FGTurbine code block
|
|
|
|
break;
|
2006-01-12 15:04:22 +00:00
|
|
|
case FGEngine::etTurboprop:
|
|
|
|
{ // FGTurboProp code block
|
|
|
|
FGTurboProp* eng = (FGTurboProp*)Propulsion->GetEngine(i);
|
|
|
|
node->setDoubleValue("n1", eng->GetN1());
|
|
|
|
//node->setDoubleValue("n2", eng->GetN2());
|
|
|
|
node->setDoubleValue("itt_degf", 32 + eng->GetITT()*9/5);
|
2011-02-14 21:11:56 +00:00
|
|
|
node->setBoolValue("ignition", eng->GetIgnition() != 0);
|
2006-01-12 15:04:22 +00:00
|
|
|
node->setDoubleValue("nozzle-pos-norm", eng->GetNozzle());
|
|
|
|
node->setDoubleValue("inlet-pos-norm", eng->GetInlet());
|
|
|
|
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
|
|
|
|
node->setBoolValue("reversed", eng->GetReversed());
|
|
|
|
node->setBoolValue("cutoff", eng->GetCutoff());
|
|
|
|
node->setBoolValue("starting", eng->GetEngStarting());
|
|
|
|
node->setBoolValue("generator-power", eng->GetGeneratorPower());
|
2011-02-14 21:11:56 +00:00
|
|
|
node->setBoolValue("damaged", eng->GetCondition() != 0);
|
2006-01-12 15:04:22 +00:00
|
|
|
node->setBoolValue("ielu-intervent", eng->GetIeluIntervent());
|
|
|
|
node->setDoubleValue("oil-temperature-degf", eng->getOilTemp_degF());
|
|
|
|
// node->setBoolValue("onfire", eng->GetFire());
|
|
|
|
globals->get_controls()->set_reverser(i, eng->GetReversed() );
|
|
|
|
globals->get_controls()->set_cutoff(i, eng->GetCutoff() );
|
|
|
|
} // end FGTurboProp code block
|
|
|
|
break;
|
2004-06-14 11:40:45 +00:00
|
|
|
case FGEngine::etElectric:
|
|
|
|
{ // FGElectric code block
|
|
|
|
FGElectric* eng = (FGElectric*)Propulsion->GetEngine(i);
|
|
|
|
node->setDoubleValue("rpm", eng->getRPM());
|
|
|
|
} // end FGElectric code block
|
2004-01-14 22:09:39 +00:00
|
|
|
break;
|
2010-07-16 09:05:59 +00:00
|
|
|
case FGEngine::etUnknown:
|
|
|
|
break;
|
2004-01-14 22:09:39 +00:00
|
|
|
}
|
2002-05-07 23:11:16 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
{ // FGEngine code block
|
|
|
|
FGEngine* eng = Propulsion->GetEngine(i);
|
2002-05-07 23:11:16 +00:00
|
|
|
node->setDoubleValue("fuel-flow-gph", eng->getFuelFlow_gph());
|
2004-01-14 22:09:39 +00:00
|
|
|
node->setDoubleValue("thrust_lb", thruster->GetThrust());
|
2003-04-01 12:43:18 +00:00
|
|
|
node->setDoubleValue("fuel-flow_pph", eng->getFuelFlow_pph());
|
2002-05-07 23:11:16 +00:00
|
|
|
node->setBoolValue("running", eng->GetRunning());
|
David Culp:
Here's a new FGSimTurbine module. Changes are:
1. Adds starting and stopping functionality
2. Calculate() now calls other functions, based on the engine's state, which gives more readable code.
Until now turbine engines were always running as long as fuel was available. With this new module the engine defaults to OFF. To start with the engine running, the variable FGEngine::Running must be set to true at sim startup. In FlightGear this is done with --prop:/engines/engine[n]/running=true.
To start the engine (on the ground), first set the starter to ON, i.e. FGEngine::Starter is set to true. In FlightGear this is done by toggling /controls/engines/engine[n]/starter to TRUE. Note that the current FlightGear key binding will not work, as it causes the starter to quit when the key is released. A new key binding is needed, without the mod-up.
When N2 reaches 15% or greater, place the fuel cutoff control to FALSE. This is FGEngine::Cutoff. In FlightGear this is done with /controls/engines/engine[n]/cutoff set to FALSE. The engine will then accelerate to idle. Upon reaching idle, the starter is automatically turned off, and the engine is running. There is presently no FlightGear key binding for the fuel cutoff switch.
To shut off the engine, place the fuel cutoff control to TRUE.
If you shut down the engine in flight it will windmill. To airstart you will need at least 15% N2, just as with a ground start. When you have enough N2, place the cutoff control to FALSE and the engine will restart. Note that if you can't get enough N2 by speeding up, you can get it by using the starter.
The reverser still works, and is controlled in FlightGear with /controls/engines/engine[n]/reverser. With the reverser control on (TRUE), the engine will produce negative thrust in proportion to throttle position, i.e. to get more reverse
thrust, increase throttle.
2003-09-23 09:25:24 +00:00
|
|
|
node->setBoolValue("starter", eng->GetStarter());
|
2002-05-07 23:11:16 +00:00
|
|
|
node->setBoolValue("cranking", eng->GetCranking());
|
David Culp:
Here's a new FGSimTurbine module. Changes are:
1. Adds starting and stopping functionality
2. Calculate() now calls other functions, based on the engine's state, which gives more readable code.
Until now turbine engines were always running as long as fuel was available. With this new module the engine defaults to OFF. To start with the engine running, the variable FGEngine::Running must be set to true at sim startup. In FlightGear this is done with --prop:/engines/engine[n]/running=true.
To start the engine (on the ground), first set the starter to ON, i.e. FGEngine::Starter is set to true. In FlightGear this is done by toggling /controls/engines/engine[n]/starter to TRUE. Note that the current FlightGear key binding will not work, as it causes the starter to quit when the key is released. A new key binding is needed, without the mod-up.
When N2 reaches 15% or greater, place the fuel cutoff control to FALSE. This is FGEngine::Cutoff. In FlightGear this is done with /controls/engines/engine[n]/cutoff set to FALSE. The engine will then accelerate to idle. Upon reaching idle, the starter is automatically turned off, and the engine is running. There is presently no FlightGear key binding for the fuel cutoff switch.
To shut off the engine, place the fuel cutoff control to TRUE.
If you shut down the engine in flight it will windmill. To airstart you will need at least 15% N2, just as with a ground start. When you have enough N2, place the cutoff control to FALSE and the engine will restart. Note that if you can't get enough N2 by speeding up, you can get it by using the starter.
The reverser still works, and is controlled in FlightGear with /controls/engines/engine[n]/reverser. With the reverser control on (TRUE), the engine will produce negative thrust in proportion to throttle position, i.e. to get more reverse
thrust, increase throttle.
2003-09-23 09:25:24 +00:00
|
|
|
globals->get_controls()->set_starter(i, eng->GetStarter() );
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGEngine code block
|
|
|
|
|
|
|
|
switch (thruster->GetType()) {
|
|
|
|
case FGThruster::ttNozzle:
|
|
|
|
{ // FGNozzle code block
|
2011-02-14 19:58:54 +00:00
|
|
|
// FGNozzle* noz = (FGNozzle*)thruster;
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGNozzle code block
|
|
|
|
break;
|
|
|
|
case FGThruster::ttPropeller:
|
|
|
|
{ // FGPropeller code block
|
|
|
|
FGPropeller* prop = (FGPropeller*)thruster;
|
|
|
|
tnode->setDoubleValue("rpm", thruster->GetRPM());
|
|
|
|
tnode->setDoubleValue("pitch", prop->GetPitch());
|
2004-03-14 14:57:07 +00:00
|
|
|
tnode->setDoubleValue("torque", prop->GetTorque());
|
2006-01-12 15:04:22 +00:00
|
|
|
tnode->setBoolValue("feathered", prop->GetFeather());
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGPropeller code block
|
|
|
|
break;
|
|
|
|
case FGThruster::ttRotor:
|
|
|
|
{ // FGRotor code block
|
2011-02-14 19:58:54 +00:00
|
|
|
// FGRotor* rotor = (FGRotor*)thruster;
|
2004-01-14 22:09:39 +00:00
|
|
|
} // end FGRotor code block
|
|
|
|
break;
|
|
|
|
case FGThruster::ttDirect:
|
|
|
|
{ // Direct code block
|
|
|
|
} // end Direct code block
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// Copy the fuel levels from JSBSim if fuel
|
|
|
|
// freeze not enabled.
|
2004-12-16 12:47:20 +00:00
|
|
|
if ( ! Propulsion->GetFuelFreeze() ) {
|
2004-01-14 22:09:39 +00:00
|
|
|
for (i = 0; i < Propulsion->GetNumTanks(); i++) {
|
|
|
|
SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true);
|
2004-06-14 11:40:45 +00:00
|
|
|
FGTank* tank = Propulsion->GetTank(i);
|
|
|
|
double contents = tank->GetContents();
|
|
|
|
double temp = tank->GetTemperature_degC();
|
2011-02-06 16:33:31 +00:00
|
|
|
double fuelDensity = tank->GetDensity();
|
|
|
|
|
|
|
|
if (fuelDensity < 0.1)
|
|
|
|
fuelDensity = 6.0; // Use average fuel value
|
|
|
|
|
|
|
|
node->setDoubleValue("density-ppg" , fuelDensity);
|
2009-02-06 19:53:51 +00:00
|
|
|
node->setDoubleValue("level-lbs", contents);
|
2004-06-14 11:40:45 +00:00
|
|
|
if (temp != -9999.0) node->setDoubleValue("temperature_degC", temp);
|
2004-01-14 22:09:39 +00:00
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
update_gear();
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-06-08 03:20:37 +00:00
|
|
|
stall_warning->setDoubleValue( Aerodynamics->GetStallWarn() );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-03-20 12:45:02 +00:00
|
|
|
elevator_pos_pct->setDoubleValue( FCS->GetDePos(ofNorm) );
|
|
|
|
left_aileron_pos_pct->setDoubleValue( FCS->GetDaLPos(ofNorm) );
|
2004-03-14 14:57:07 +00:00
|
|
|
right_aileron_pos_pct->setDoubleValue( FCS->GetDaRPos(ofNorm) );
|
2002-05-28 13:50:51 +00:00
|
|
|
rudder_pos_pct->setDoubleValue( -1*FCS->GetDrPos(ofNorm) );
|
2002-03-23 00:27:16 +00:00
|
|
|
flap_pos_pct->setDoubleValue( FCS->GetDfPos(ofNorm) );
|
2003-04-01 12:43:18 +00:00
|
|
|
speedbrake_pos_pct->setDoubleValue( FCS->GetDsbPos(ofNorm) );
|
|
|
|
spoilers_pos_pct->setDoubleValue( FCS->GetDspPos(ofNorm) );
|
2008-10-23 19:04:45 +00:00
|
|
|
tailhook_pos_pct->setDoubleValue( FCS->GetTailhookPos() );
|
|
|
|
wing_fold_pos_pct->setDoubleValue( FCS->GetWingFoldPos() );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2008-10-23 19:04:45 +00:00
|
|
|
// force a sim crashed if crashed (altitude AGL < 0)
|
2006-02-02 09:35:25 +00:00
|
|
|
if (get_Altitude_AGL() < -100.0) {
|
2010-07-16 09:05:59 +00:00
|
|
|
fdmex->SuspendIntegration();
|
2008-10-23 19:04:45 +00:00
|
|
|
crashed = true;
|
2006-01-12 15:04:22 +00:00
|
|
|
}
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
|
|
|
|
bool FGJSBsim::ToggleDataLogging(void)
|
|
|
|
{
|
2006-01-12 15:04:22 +00:00
|
|
|
// ToDo: handle this properly
|
|
|
|
fdmex->DisableOutput();
|
|
|
|
return false;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
bool FGJSBsim::ToggleDataLogging(bool state)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
if (state) {
|
2006-01-12 15:04:22 +00:00
|
|
|
fdmex->EnableOutput();
|
2002-02-24 20:54:23 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
2006-01-12 15:04:22 +00:00
|
|
|
fdmex->DisableOutput();
|
2002-02-24 20:54:23 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Positions
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Latitude(double lat)
|
|
|
|
{
|
2007-03-19 16:37:36 +00:00
|
|
|
static SGConstPropertyNode_ptr altitude = fgGetNode("/position/altitude-ft");
|
2002-02-24 20:54:23 +00:00
|
|
|
double alt;
|
|
|
|
double sea_level_radius_meters, lat_geoc;
|
2003-04-04 22:44:32 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Latitude(lat);
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
if ( altitude->getDoubleValue() > -9990 ) {
|
|
|
|
alt = altitude->getDoubleValue();
|
|
|
|
} else {
|
|
|
|
alt = 0.0;
|
|
|
|
}
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::set_Latitude: " << lat );
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO," cur alt (ft) = " << alt );
|
|
|
|
|
2004-03-14 14:57:07 +00:00
|
|
|
sgGeodToGeoc( lat, alt * SG_FEET_TO_METER,
|
2002-02-24 20:54:23 +00:00
|
|
|
&sea_level_radius_meters, &lat_geoc );
|
|
|
|
_set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET );
|
2004-03-14 14:57:07 +00:00
|
|
|
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
|
2002-02-24 20:54:23 +00:00
|
|
|
fgic->SetLatitudeRadIC( lat_geoc );
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Longitude(double lon)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO,"FGJSBsim::set_Longitude: " << lon );
|
2003-04-04 22:44:32 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Longitude(lon);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
fgic->SetLongitudeRadIC( lon );
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2009-06-01 08:52:34 +00:00
|
|
|
// Sets the altitude above sea level.
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Altitude(double alt)
|
|
|
|
{
|
2007-03-19 16:37:36 +00:00
|
|
|
static SGConstPropertyNode_ptr latitude = fgGetNode("/position/latitude-deg");
|
2002-02-24 20:54:23 +00:00
|
|
|
|
|
|
|
double sea_level_radius_meters,lat_geoc;
|
|
|
|
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Altitude: " << alt );
|
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, " lat (deg) = " << latitude->getDoubleValue() );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Altitude(alt);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
sgGeodToGeoc( latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, alt,
|
|
|
|
&sea_level_radius_meters, &lat_geoc);
|
|
|
|
_set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET );
|
|
|
|
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
|
|
|
|
SG_LOG(SG_FLIGHT, SG_INFO,
|
2010-06-16 07:31:59 +00:00
|
|
|
"Terrain elevation: " << FGInterface::get_Runway_altitude() * SG_METER_TO_FEET );
|
2002-02-24 20:54:23 +00:00
|
|
|
fgic->SetLatitudeRadIC( lat_geoc );
|
2009-06-01 08:52:34 +00:00
|
|
|
fgic->SetAltitudeASLFtIC(alt);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_V_calibrated_kts(double vc)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_V_calibrated_kts: " << vc );
|
2003-04-04 22:44:32 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_V_calibrated_kts(vc);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
fgic->SetVcalibratedKtsIC(vc);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Mach_number(double mach)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Mach_number: " << mach );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Mach_number(mach);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
fgic->SetMachIC(mach);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Velocities_Local( double north, double east, double down )
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Velocities_Local: "
|
|
|
|
<< north << ", " << east << ", " << down );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Velocities_Local(north, east, down);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
2008-07-10 17:23:02 +00:00
|
|
|
fgic->SetVNorthFpsIC(north);
|
|
|
|
fgic->SetVEastFpsIC(east);
|
|
|
|
fgic->SetVDownFpsIC(down);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Velocities_Wind_Body: "
|
|
|
|
<< u << ", " << v << ", " << w );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Velocities_Wind_Body(u, v, w);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
fgic->SetUBodyFpsIC(u);
|
|
|
|
fgic->SetVBodyFpsIC(v);
|
|
|
|
fgic->SetWBodyFpsIC(w);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Euler angles
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Euler_Angles( double phi, double theta, double psi )
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Euler_Angles: "
|
|
|
|
<< phi << ", " << theta << ", " << psi );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Euler_Angles(phi, theta, psi);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
2006-02-02 09:35:25 +00:00
|
|
|
fgic->SetThetaRadIC(theta);
|
|
|
|
fgic->SetPhiRadIC(phi);
|
|
|
|
fgic->SetPsiRadIC(psi);
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Flight Path
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Climb_Rate( double roc)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Climb_Rate: " << roc );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
// In case we're not trimming
|
2003-04-04 22:44:32 +00:00
|
|
|
FGInterface::set_Climb_Rate(roc);
|
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
//since both climb rate and flight path angle are set in the FG
|
|
|
|
//startup sequence, something is needed to keep one from cancelling
|
|
|
|
//out the other.
|
|
|
|
if( !(fabs(roc) > 1 && fabs(fgic->GetFlightPathAngleRadIC()) < 0.01) ) {
|
|
|
|
fgic->SetClimbRateFpsIC(roc);
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::set_Gamma_vert_rad( double gamma)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
SG_LOG(SG_FLIGHT,SG_INFO, "FGJSBsim::set_Gamma_vert_rad: " << gamma );
|
2004-03-14 14:57:07 +00:00
|
|
|
|
2002-02-24 20:54:23 +00:00
|
|
|
update_ic();
|
|
|
|
if( !(fabs(gamma) < 0.01 && fabs(fgic->GetClimbRateFpsIC()) > 1) ) {
|
|
|
|
fgic->SetFlightPathAngleRadIC(gamma);
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2011-03-23 22:52:36 +00:00
|
|
|
|
|
|
|
if (!fdmex->Holding())
|
|
|
|
needTrim=true;
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::init_gear(void )
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
FGGroundReactions* gr=fdmex->GetGroundReactions();
|
|
|
|
int Ngear=GroundReactions->GetNumGearUnits();
|
|
|
|
for (int i=0;i<Ngear;i++) {
|
2004-09-11 12:41:05 +00:00
|
|
|
FGLGear *gear = gr->GetGearUnit(i);
|
2002-02-24 20:54:23 +00:00
|
|
|
SGPropertyNode * node = fgGetNode("gear/gear", i, true);
|
2004-09-11 12:41:05 +00:00
|
|
|
node->setDoubleValue("xoffset-in", gear->GetBodyLocation()(1));
|
|
|
|
node->setDoubleValue("yoffset-in", gear->GetBodyLocation()(2));
|
|
|
|
node->setDoubleValue("zoffset-in", gear->GetBodyLocation()(3));
|
|
|
|
node->setBoolValue("wow", gear->GetWOW());
|
2009-04-13 11:47:57 +00:00
|
|
|
node->setDoubleValue("rollspeed-ms", gear->GetWheelRollVel()*0.3043);
|
2004-09-11 12:41:05 +00:00
|
|
|
node->setBoolValue("has-brake", gear->GetBrakeGroup() > 0);
|
2008-07-10 17:23:02 +00:00
|
|
|
node->setDoubleValue("position-norm", gear->GetGearUnitPos());
|
2004-09-11 12:41:05 +00:00
|
|
|
node->setDoubleValue("tire-pressure-norm", gear->GetTirePressure());
|
2005-11-10 10:04:33 +00:00
|
|
|
node->setDoubleValue("compression-norm", gear->GetCompLen());
|
2008-10-23 19:04:45 +00:00
|
|
|
node->setDoubleValue("compression-ft", gear->GetCompLen());
|
2004-09-11 12:41:05 +00:00
|
|
|
if ( gear->GetSteerable() )
|
|
|
|
node->setDoubleValue("steering-norm", gear->GetSteerNorm());
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::update_gear(void)
|
|
|
|
{
|
2002-02-24 20:54:23 +00:00
|
|
|
FGGroundReactions* gr=fdmex->GetGroundReactions();
|
|
|
|
int Ngear=GroundReactions->GetNumGearUnits();
|
2002-05-07 23:11:16 +00:00
|
|
|
for (int i=0;i<Ngear;i++) {
|
2004-09-11 12:41:05 +00:00
|
|
|
FGLGear *gear = gr->GetGearUnit(i);
|
2002-05-07 23:11:16 +00:00
|
|
|
SGPropertyNode * node = fgGetNode("gear/gear", i, true);
|
2004-09-11 12:41:05 +00:00
|
|
|
node->getChild("wow", 0, true)->setBoolValue( gear->GetWOW());
|
2009-04-13 11:47:57 +00:00
|
|
|
node->getChild("rollspeed-ms", 0, true)->setDoubleValue(gear->GetWheelRollVel()*0.3043);
|
2008-07-10 17:23:02 +00:00
|
|
|
node->getChild("position-norm", 0, true)->setDoubleValue(gear->GetGearUnitPos());
|
2004-09-11 12:41:05 +00:00
|
|
|
gear->SetTirePressure(node->getDoubleValue("tire-pressure-norm"));
|
2005-11-10 10:04:33 +00:00
|
|
|
node->setDoubleValue("compression-norm", gear->GetCompLen());
|
2008-10-23 19:04:45 +00:00
|
|
|
node->setDoubleValue("compression-ft", gear->GetCompLen());
|
2004-09-11 12:41:05 +00:00
|
|
|
if ( gear->GetSteerable() )
|
|
|
|
node->setDoubleValue("steering-norm", gear->GetSteerNorm());
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::do_trim(void)
|
|
|
|
{
|
|
|
|
FGTrim *fgtrim;
|
|
|
|
|
|
|
|
if ( fgGetBool("/sim/presets/onground") )
|
|
|
|
{
|
|
|
|
fgtrim = new FGTrim(fdmex,tGround);
|
|
|
|
} else {
|
|
|
|
fgtrim = new FGTrim(fdmex,tLongitudinal);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !fgtrim->DoTrim() ) {
|
|
|
|
fgtrim->Report();
|
|
|
|
fgtrim->TrimStats();
|
|
|
|
} else {
|
|
|
|
trimmed->setBoolValue(true);
|
|
|
|
}
|
|
|
|
delete fgtrim;
|
|
|
|
|
|
|
|
pitch_trim->setDoubleValue( FCS->GetPitchTrimCmd() );
|
|
|
|
throttle_trim->setDoubleValue( FCS->GetThrottleCmd(0) );
|
|
|
|
aileron_trim->setDoubleValue( FCS->GetDaCmd() );
|
|
|
|
rudder_trim->setDoubleValue( FCS->GetDrCmd() );
|
|
|
|
|
|
|
|
globals->get_controls()->set_elevator_trim(FCS->GetPitchTrimCmd());
|
|
|
|
globals->get_controls()->set_elevator(FCS->GetDeCmd());
|
2011-02-14 20:01:48 +00:00
|
|
|
for( unsigned i = 0; i < Propulsion->GetNumEngines(); i++ )
|
|
|
|
globals->get_controls()->set_throttle(i, FCS->GetThrottleCmd(i));
|
2004-01-14 22:09:39 +00:00
|
|
|
|
|
|
|
globals->get_controls()->set_aileron(FCS->GetDaCmd());
|
|
|
|
globals->get_controls()->set_rudder( FCS->GetDrCmd());
|
|
|
|
|
|
|
|
SG_LOG( SG_FLIGHT, SG_INFO, " Trim complete" );
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
|
2004-01-14 22:09:39 +00:00
|
|
|
void FGJSBsim::update_ic(void)
|
|
|
|
{
|
|
|
|
if ( !needTrim ) {
|
2004-03-14 14:57:07 +00:00
|
|
|
fgic->SetLatitudeRadIC(get_Lat_geocentric() );
|
|
|
|
fgic->SetLongitudeRadIC( get_Longitude() );
|
2009-06-01 08:52:34 +00:00
|
|
|
fgic->SetAltitudeASLFtIC( get_Altitude() );
|
2004-03-14 14:57:07 +00:00
|
|
|
fgic->SetVcalibratedKtsIC( get_V_calibrated_kts() );
|
2006-02-02 09:35:25 +00:00
|
|
|
fgic->SetThetaRadIC( get_Theta() );
|
|
|
|
fgic->SetPhiRadIC( get_Phi() );
|
|
|
|
fgic->SetPsiRadIC( get_Psi() );
|
2002-02-24 20:54:23 +00:00
|
|
|
fgic->SetClimbRateFpsIC( get_Climb_Rate() );
|
2004-03-14 14:57:07 +00:00
|
|
|
}
|
2002-02-24 20:54:23 +00:00
|
|
|
}
|
2003-01-24 12:55:28 +00:00
|
|
|
|
2009-03-06 16:37:12 +00:00
|
|
|
bool
|
|
|
|
FGJSBsim::get_agl_ft(double t, const double pt[3], double alt_off,
|
|
|
|
double contact[3], double normal[3], double vel[3],
|
2010-10-26 07:48:56 +00:00
|
|
|
double angularVel[3], double *agl)
|
2009-03-06 16:37:12 +00:00
|
|
|
{
|
|
|
|
const SGMaterial* material;
|
|
|
|
simgear::BVHNode::Id id;
|
|
|
|
if (!FGInterface::get_agl_ft(t, pt, alt_off, contact, normal, vel,
|
|
|
|
angularVel, material, id))
|
|
|
|
return false;
|
|
|
|
SGGeod geodPt = SGGeod::fromCart(SG_FEET_TO_METER*SGVec3d(pt));
|
|
|
|
SGQuatd hlToEc = SGQuatd::fromLonLat(geodPt);
|
|
|
|
*agl = dot(hlToEc.rotate(SGVec3d(0, 0, 1)), SGVec3d(contact) - SGVec3d(pt));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-10 17:23:02 +00:00
|
|
|
inline static double dot3(const FGColumnVector3& a, const FGColumnVector3& b)
|
|
|
|
{
|
|
|
|
return a(1) * b(1) + a(2) * b(2) + a(3) * b(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static double sqr(double x)
|
|
|
|
{
|
|
|
|
return x * x;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double angle_diff(double a, double b)
|
|
|
|
{
|
|
|
|
double diff = fabs(a - b);
|
|
|
|
if (diff > 180) diff = 360 - diff;
|
|
|
|
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_hook_solution(const FGColumnVector3& ground_normal_body, double E, double hook_length, double sin_fi_guess, double cos_fi_guess, double* sin_fis, double* cos_fis, double* fis, int* points)
|
|
|
|
{
|
|
|
|
FGColumnVector3 tip(-hook_length * cos_fi_guess, 0, hook_length * sin_fi_guess);
|
|
|
|
double dist = dot3(tip, ground_normal_body);
|
|
|
|
if (fabs(dist + E) < 0.0001) {
|
|
|
|
sin_fis[*points] = sin_fi_guess;
|
|
|
|
cos_fis[*points] = cos_fi_guess;
|
|
|
|
fis[*points] = atan2(sin_fi_guess, cos_fi_guess) * SG_RADIANS_TO_DEGREES;
|
|
|
|
(*points)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void check_hook_solution(const FGColumnVector3& ground_normal_body, double E, double hook_length, double sin_fi_guess, double* sin_fis, double* cos_fis, double* fis, int* points)
|
|
|
|
{
|
|
|
|
if (sin_fi_guess >= -1 && sin_fi_guess <= 1) {
|
|
|
|
double cos_fi_guess = sqrt(1 - sqr(sin_fi_guess));
|
|
|
|
check_hook_solution(ground_normal_body, E, hook_length, sin_fi_guess, cos_fi_guess, sin_fis, cos_fis, fis, points);
|
|
|
|
if (fabs(cos_fi_guess) > SG_EPSILON) {
|
|
|
|
check_hook_solution(ground_normal_body, E, hook_length, sin_fi_guess, -cos_fi_guess, sin_fis, cos_fis, fis, points);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGJSBsim::update_external_forces(double t_off)
|
|
|
|
{
|
|
|
|
const FGMatrix33& Tb2l = Propagate->GetTb2l();
|
|
|
|
const FGMatrix33& Tl2b = Propagate->GetTl2b();
|
|
|
|
const FGLocation& Location = Propagate->GetLocation();
|
|
|
|
const FGMatrix33& Tec2l = Location.GetTec2l();
|
|
|
|
|
|
|
|
double hook_area[4][3];
|
|
|
|
|
|
|
|
FGColumnVector3 hook_root_body = MassBalance->StructuralToBody(hook_root_struct);
|
|
|
|
FGColumnVector3 hook_root = Location.LocalToLocation(Tb2l * hook_root_body);
|
|
|
|
hook_area[1][0] = hook_root(1);
|
|
|
|
hook_area[1][1] = hook_root(2);
|
|
|
|
hook_area[1][2] = hook_root(3);
|
|
|
|
|
|
|
|
hook_length = fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-length-ft", 6.75);
|
|
|
|
double fi_min = fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-pos-min-deg", -18);
|
|
|
|
double fi_max = fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-pos-max-deg", 30);
|
|
|
|
double fi = fgGetDouble("/fdm/jsbsim/systems/hook/tailhook-pos-norm") * (fi_max - fi_min) + fi_min;
|
|
|
|
double cos_fi = cos(fi * SG_DEGREES_TO_RADIANS);
|
|
|
|
double sin_fi = sin(fi * SG_DEGREES_TO_RADIANS);
|
|
|
|
|
|
|
|
FGColumnVector3 hook_tip_body = hook_root_body;
|
|
|
|
hook_tip_body(1) -= hook_length * cos_fi;
|
|
|
|
hook_tip_body(3) += hook_length * sin_fi;
|
|
|
|
|
|
|
|
double contact[3];
|
|
|
|
double ground_normal[3];
|
|
|
|
double ground_vel[3];
|
2010-10-26 07:48:56 +00:00
|
|
|
double ground_angular_vel[3];
|
2008-07-10 17:23:02 +00:00
|
|
|
double root_agl_ft;
|
|
|
|
|
|
|
|
if (!got_wire) {
|
2010-10-26 07:48:56 +00:00
|
|
|
bool got = get_agl_ft(t_off, hook_area[1], 0, contact, ground_normal,
|
|
|
|
ground_vel, ground_angular_vel, &root_agl_ft);
|
2008-07-10 17:23:02 +00:00
|
|
|
if (got && root_agl_ft > 0 && root_agl_ft < hook_length) {
|
|
|
|
FGColumnVector3 ground_normal_body = Tl2b * (Tec2l * FGColumnVector3(ground_normal[0], ground_normal[1], ground_normal[2]));
|
|
|
|
FGColumnVector3 contact_body = Tl2b * Location.LocationToLocal(FGColumnVector3(contact[0], contact[1], contact[2]));
|
|
|
|
double D = -dot3(contact_body, ground_normal_body);
|
|
|
|
|
|
|
|
// check hook tip agl against same ground plane
|
|
|
|
double hook_tip_agl_ft = dot3(hook_tip_body, ground_normal_body) + D;
|
|
|
|
if (hook_tip_agl_ft < 0) {
|
|
|
|
|
|
|
|
// hook tip: hx - l cos, hy, hz + l sin
|
|
|
|
// on ground: - n0 l cos + n2 l sin + E = 0
|
|
|
|
|
|
|
|
double E = D + dot3(hook_root_body, ground_normal_body);
|
|
|
|
|
|
|
|
// substitue x = sin fi, cos fi = sqrt(1 - x * x)
|
|
|
|
// and rearrange to get a quadratic with coeffs:
|
|
|
|
double a = sqr(hook_length) * (sqr(ground_normal_body(1)) + sqr(ground_normal_body(3)));
|
|
|
|
double b = 2 * E * ground_normal_body(3) * hook_length;
|
|
|
|
double c = sqr(E) - sqr(ground_normal_body(1) * hook_length);
|
|
|
|
|
|
|
|
double disc = sqr(b) - 4 * a * c;
|
|
|
|
if (disc >= 0) {
|
|
|
|
double delta = sqrt(disc) / (2 * a);
|
|
|
|
|
|
|
|
// allow 4 solutions for safety, should never happen
|
|
|
|
double sin_fis[4];
|
|
|
|
double cos_fis[4];
|
|
|
|
double fis[4];
|
|
|
|
int points = 0;
|
|
|
|
|
|
|
|
double sin_fi_guess = -b / (2 * a) - delta;
|
|
|
|
check_hook_solution(ground_normal_body, E, hook_length, sin_fi_guess, sin_fis, cos_fis, fis, &points);
|
|
|
|
check_hook_solution(ground_normal_body, E, hook_length, sin_fi_guess + 2 * delta, sin_fis, cos_fis, fis, &points);
|
|
|
|
|
|
|
|
if (points == 2) {
|
|
|
|
double diff1 = angle_diff(fi, fis[0]);
|
|
|
|
double diff2 = angle_diff(fi, fis[1]);
|
|
|
|
int point = diff1 < diff2 ? 0 : 1;
|
|
|
|
fi = fis[point];
|
|
|
|
sin_fi = sin_fis[point];
|
|
|
|
cos_fi = cos_fis[point];
|
|
|
|
hook_tip_body(1) = hook_root_body(1) - hook_length * cos_fi;
|
|
|
|
hook_tip_body(3) = hook_root_body(3) + hook_length * sin_fi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FGColumnVector3 hook_root_vel = Propagate->GetVel() + (Tb2l * (Propagate->GetPQR() * hook_root_body));
|
|
|
|
double wire_ends_ec[2][3];
|
|
|
|
double wire_vel_ec[2][3];
|
|
|
|
get_wire_ends_ft(t_off, wire_ends_ec, wire_vel_ec);
|
|
|
|
FGColumnVector3 wire_vel_1 = Tec2l * FGColumnVector3(wire_vel_ec[0][0], wire_vel_ec[0][1], wire_vel_ec[0][2]);
|
|
|
|
FGColumnVector3 wire_vel_2 = Tec2l * FGColumnVector3(wire_vel_ec[1][0], wire_vel_ec[1][1], wire_vel_ec[1][2]);
|
|
|
|
FGColumnVector3 rel_vel = hook_root_vel - (wire_vel_1 + wire_vel_2) / 2;
|
|
|
|
if (rel_vel.Magnitude() < 3) {
|
|
|
|
got_wire = false;
|
|
|
|
release_wire();
|
|
|
|
fgSetDouble("/fdm/jsbsim/external_reactions/hook/magnitude", 0.0);
|
|
|
|
} else {
|
|
|
|
FGColumnVector3 wire_end1_body = Tl2b * Location.LocationToLocal(FGColumnVector3(wire_ends_ec[0][0], wire_ends_ec[0][1], wire_ends_ec[0][2])) - hook_root_body;
|
|
|
|
FGColumnVector3 wire_end2_body = Tl2b * Location.LocationToLocal(FGColumnVector3(wire_ends_ec[1][0], wire_ends_ec[1][1], wire_ends_ec[1][2])) - hook_root_body;
|
|
|
|
FGColumnVector3 force_plane_normal = wire_end1_body * wire_end2_body;
|
|
|
|
force_plane_normal.Normalize();
|
|
|
|
cos_fi = dot3(force_plane_normal, FGColumnVector3(0, 0, 1));
|
|
|
|
if (cos_fi < 0) cos_fi = -cos_fi;
|
|
|
|
sin_fi = sqrt(1 - sqr(cos_fi));
|
|
|
|
fi = atan2(sin_fi, cos_fi) * SG_RADIANS_TO_DEGREES;
|
|
|
|
|
|
|
|
fgSetDouble("/fdm/jsbsim/external_reactions/hook/x", -cos_fi);
|
|
|
|
fgSetDouble("/fdm/jsbsim/external_reactions/hook/y", 0);
|
|
|
|
fgSetDouble("/fdm/jsbsim/external_reactions/hook/z", sin_fi);
|
|
|
|
fgSetDouble("/fdm/jsbsim/external_reactions/hook/magnitude", fgGetDouble("/fdm/jsbsim/systems/hook/force"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FGColumnVector3 hook_tip = Location.LocalToLocation(Tb2l * hook_tip_body);
|
|
|
|
|
|
|
|
hook_area[0][0] = hook_tip(1);
|
|
|
|
hook_area[0][1] = hook_tip(2);
|
|
|
|
hook_area[0][2] = hook_tip(3);
|
|
|
|
|
|
|
|
if (!got_wire) {
|
|
|
|
// The previous positions.
|
|
|
|
hook_area[2][0] = last_hook_root[0];
|
|
|
|
hook_area[2][1] = last_hook_root[1];
|
|
|
|
hook_area[2][2] = last_hook_root[2];
|
|
|
|
hook_area[3][0] = last_hook_tip[0];
|
|
|
|
hook_area[3][1] = last_hook_tip[1];
|
|
|
|
hook_area[3][2] = last_hook_tip[2];
|
|
|
|
|
|
|
|
// Check if we caught a wire.
|
|
|
|
// Returns true if we caught one.
|
|
|
|
if (caught_wire_ft(t_off, hook_area)) {
|
|
|
|
got_wire = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// save actual position as old position ...
|
|
|
|
last_hook_tip[0] = hook_area[0][0];
|
|
|
|
last_hook_tip[1] = hook_area[0][1];
|
|
|
|
last_hook_tip[2] = hook_area[0][2];
|
|
|
|
last_hook_root[0] = hook_area[1][0];
|
|
|
|
last_hook_root[1] = hook_area[1][1];
|
|
|
|
last_hook_root[2] = hook_area[1][2];
|
|
|
|
|
|
|
|
fgSetDouble("/fdm/jsbsim/systems/hook/tailhook-pos-deg", fi);
|
|
|
|
}
|
|
|
|
|