Maik JUSTUS: (OK'ed by Andy)
""" - ground properties (e.g. feel bumpiness and the reduced friction of grass or go swimming with the beaver) - initial load for yasim gears (to get rid of the jitter the beaver has on ground) - glider/winch/aerotow (do winch start with YASim glider or do aerotow over the net) I will place a how-to on the wiki soon, here very short: use the sgs233y (or the bocian if you have AJ (up ot now) non-GPL bocian) winch start: Ctrl-w for placing the winch, hold w to winch, press Shift-w to release the tow aerotow: Place the glider within 60m to a MP-aircraft, press Ctrl-t to tow to this aircraft. If the MP-aircraft is the J3 and the patch is installed on both sides, the J3 feels the forces, too. The J3-pilot has to taxi very slow up to the moment, the glider starts moving. Increase the throttle gently. Don't lift the J3 early, wait for the glider being lifted, lift gently. """
This commit is contained in:
parent
15754ccfc1
commit
53f09ff6a5
19 changed files with 1360 additions and 45 deletions
|
@ -7,6 +7,7 @@
|
|||
#include "Surface.hpp"
|
||||
#include "Rotorpart.hpp"
|
||||
#include "Thruster.hpp"
|
||||
#include "Hitch.hpp"
|
||||
#include "Airplane.hpp"
|
||||
|
||||
namespace yasim {
|
||||
|
@ -38,11 +39,13 @@ Airplane::Airplane()
|
|||
_cruiseT = 0;
|
||||
_cruiseSpeed = 0;
|
||||
_cruiseWeight = 0;
|
||||
_cruiseGlideAngle = 0;
|
||||
_approachP = 0;
|
||||
_approachT = 0;
|
||||
_approachSpeed = 0;
|
||||
_approachAoA = 0;
|
||||
_approachWeight = 0;
|
||||
_approachGlideAngle = 0;
|
||||
|
||||
_dragFactor = 1;
|
||||
_liftRatio = 1;
|
||||
|
@ -182,16 +185,17 @@ void Airplane::updateGearState()
|
|||
}
|
||||
}
|
||||
|
||||
void Airplane::setApproach(float speed, float altitude, float aoa, float fuel)
|
||||
void Airplane::setApproach(float speed, float altitude, float aoa, float fuel, float gla)
|
||||
{
|
||||
_approachSpeed = speed;
|
||||
_approachP = Atmosphere::getStdPressure(altitude);
|
||||
_approachT = Atmosphere::getStdTemperature(altitude);
|
||||
_approachAoA = aoa;
|
||||
_approachFuel = fuel;
|
||||
_approachGlideAngle = gla;
|
||||
}
|
||||
|
||||
void Airplane::setCruise(float speed, float altitude, float fuel)
|
||||
void Airplane::setCruise(float speed, float altitude, float fuel, float gla)
|
||||
{
|
||||
_cruiseSpeed = speed;
|
||||
_cruiseP = Atmosphere::getStdPressure(altitude);
|
||||
|
@ -199,6 +203,7 @@ void Airplane::setCruise(float speed, float altitude, float fuel)
|
|||
_cruiseAoA = 0;
|
||||
_tailIncidence = 0;
|
||||
_cruiseFuel = fuel;
|
||||
_cruiseGlideAngle = gla;
|
||||
}
|
||||
|
||||
void Airplane::setElevatorControl(int control)
|
||||
|
@ -323,6 +328,11 @@ void Airplane::addHook(Hook* hook)
|
|||
_model.addHook(hook);
|
||||
}
|
||||
|
||||
void Airplane::addHitch(Hitch* hitch)
|
||||
{
|
||||
_model.addHitch(hitch);
|
||||
}
|
||||
|
||||
void Airplane::addLaunchbar(Launchbar* launchbar)
|
||||
{
|
||||
_model.addLaunchbar(launchbar);
|
||||
|
@ -417,7 +427,7 @@ int Airplane::getSolutionIterations()
|
|||
return _solutionIterations;
|
||||
}
|
||||
|
||||
void Airplane::setupState(float aoa, float speed, State* s)
|
||||
void Airplane::setupState(float aoa, float speed, float gla, State* s)
|
||||
{
|
||||
float cosAoA = Math::cos(aoa);
|
||||
float sinAoA = Math::sin(aoa);
|
||||
|
@ -425,7 +435,7 @@ void Airplane::setupState(float aoa, float speed, State* s)
|
|||
s->orient[3] = 0; s->orient[4] = 1; s->orient[5] = 0;
|
||||
s->orient[6] = -sinAoA; s->orient[7] = 0; s->orient[8] = cosAoA;
|
||||
|
||||
s->v[0] = speed; s->v[1] = 0; s->v[2] = 0;
|
||||
s->v[0] = speed*Math::cos(gla); s->v[1] = -speed*Math::sin(gla); s->v[2] = 0;
|
||||
|
||||
int i;
|
||||
for(i=0; i<3; i++)
|
||||
|
@ -602,6 +612,7 @@ void Airplane::compileContactPoints()
|
|||
// I made these up
|
||||
g->setStaticFriction(0.6f);
|
||||
g->setDynamicFriction(0.5f);
|
||||
g->setContactPoint(1);
|
||||
|
||||
_model.addGear(g);
|
||||
}
|
||||
|
@ -709,7 +720,8 @@ void Airplane::solveGear()
|
|||
g->getPosition(pos);
|
||||
Math::sub3(cg, pos, pos);
|
||||
gr->wgt = 1.0f/(0.5f+Math::sqrt(pos[0]*pos[0] + pos[1]*pos[1]));
|
||||
total += gr->wgt;
|
||||
if (!g->getIgnoreWhileSolving())
|
||||
total += gr->wgt;
|
||||
}
|
||||
|
||||
// Renormalize so they sum to 1
|
||||
|
@ -731,7 +743,7 @@ void Airplane::solveGear()
|
|||
float e = energy * gr->wgt;
|
||||
float comp[3];
|
||||
gr->gear->getCompression(comp);
|
||||
float len = Math::mag3(comp);
|
||||
float len = Math::mag3(comp)*(1+2*gr->gear->getInitialLoad());
|
||||
|
||||
// Energy in a spring: e = 0.5 * k * len^2
|
||||
float k = 2 * e / (len*len);
|
||||
|
@ -773,7 +785,7 @@ void Airplane::setupWeights(bool isApproach)
|
|||
|
||||
void Airplane::runCruise()
|
||||
{
|
||||
setupState(_cruiseAoA, _cruiseSpeed, &_cruiseState);
|
||||
setupState(_cruiseAoA, _cruiseSpeed,_approachGlideAngle, &_cruiseState);
|
||||
_model.setState(&_cruiseState);
|
||||
_model.setAir(_cruiseP, _cruiseT,
|
||||
Atmosphere::calcStdDensity(_cruiseP, _cruiseT));
|
||||
|
@ -816,7 +828,7 @@ void Airplane::runCruise()
|
|||
|
||||
void Airplane::runApproach()
|
||||
{
|
||||
setupState(_approachAoA, _approachSpeed, &_approachState);
|
||||
setupState(_approachAoA, _approachSpeed,_approachGlideAngle, &_approachState);
|
||||
_model.setState(&_approachState);
|
||||
_model.setAir(_approachP, _approachT,
|
||||
Atmosphere::calcStdDensity(_approachP, _approachT));
|
||||
|
@ -924,7 +936,7 @@ void Airplane::solve()
|
|||
runCruise();
|
||||
|
||||
_model.getThrust(tmp);
|
||||
float thrust = tmp[0];
|
||||
float thrust = tmp[0] + _cruiseWeight * Math::sin(_cruiseGlideAngle) * 9.81;
|
||||
|
||||
_model.getBody()->getAccel(tmp);
|
||||
Math::tmul33(_cruiseState.orient, tmp, tmp);
|
||||
|
@ -1063,7 +1075,7 @@ void Airplane::solveHelicopter()
|
|||
applyDragFactor(Math::pow(15.7/1000, 1/SOLVE_TWEAK));
|
||||
applyLiftRatio(Math::pow(104, 1/SOLVE_TWEAK));
|
||||
}
|
||||
setupState(0,0, &_cruiseState);
|
||||
setupState(0,0,0, &_cruiseState);
|
||||
_model.setState(&_cruiseState);
|
||||
setupWeights(true);
|
||||
_controls.reset();
|
||||
|
|
|
@ -13,6 +13,7 @@ class Gear;
|
|||
class Hook;
|
||||
class Launchbar;
|
||||
class Thruster;
|
||||
class Hitch;
|
||||
|
||||
class Airplane {
|
||||
public:
|
||||
|
@ -45,12 +46,13 @@ public:
|
|||
void addLaunchbar(Launchbar* l);
|
||||
void addThruster(Thruster* t, float mass, float* cg);
|
||||
void addBallast(float* pos, float mass);
|
||||
void addHitch(Hitch* h);
|
||||
|
||||
int addWeight(float* pos, float size);
|
||||
void setWeight(int handle, float mass);
|
||||
|
||||
void setApproach(float speed, float altitude, float aoa, float fuel);
|
||||
void setCruise(float speed, float altitude, float fuel);
|
||||
void setApproach(float speed, float altitude, float aoa, float fuel, float gla);
|
||||
void setCruise(float speed, float altitude, float fuel, float gla);
|
||||
|
||||
void setElevatorControl(int control);
|
||||
void addApproachControl(int control, float val);
|
||||
|
@ -61,6 +63,8 @@ public:
|
|||
int numGear();
|
||||
Gear* getGear(int g);
|
||||
Hook* getHook();
|
||||
int numHitches() { return _hitches.size(); }
|
||||
Hitch* getHitch(int h);
|
||||
Rotorgear* getRotorgear();
|
||||
Launchbar* getLaunchbar();
|
||||
|
||||
|
@ -88,7 +92,7 @@ public:
|
|||
float getApproachElevator() { return _approachElevator.val; }
|
||||
char* getFailureMsg();
|
||||
|
||||
static void setupState(float aoa, float speed, State* s); // utility
|
||||
static void setupState(float aoa, float speed, float gla, State* s); // utility
|
||||
|
||||
private:
|
||||
struct Tank { float pos[3]; float cap; float fill;
|
||||
|
@ -139,6 +143,7 @@ private:
|
|||
Vector _contacts; // non-gear ground contact points
|
||||
Vector _weights;
|
||||
Vector _surfs; // NON-wing Surfaces
|
||||
Vector _hitches; //for airtow and winch
|
||||
|
||||
Vector _solveWeights;
|
||||
|
||||
|
@ -149,6 +154,7 @@ private:
|
|||
float _cruiseSpeed;
|
||||
float _cruiseWeight;
|
||||
float _cruiseFuel;
|
||||
float _cruiseGlideAngle;
|
||||
|
||||
Vector _approachControls;
|
||||
State _approachState;
|
||||
|
@ -158,6 +164,7 @@ private:
|
|||
float _approachAoA;
|
||||
float _approachWeight;
|
||||
float _approachFuel;
|
||||
float _approachGlideAngle;
|
||||
|
||||
int _solutionIterations;
|
||||
float _dragFactor;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Rotor.hpp"
|
||||
#include "Math.hpp"
|
||||
#include "Propeller.hpp"
|
||||
#include "Hitch.hpp"
|
||||
|
||||
#include "ControlMap.hpp"
|
||||
namespace yasim {
|
||||
|
@ -219,6 +220,10 @@ void ControlMap::applyControls(float dt)
|
|||
case WASTEGATE:
|
||||
((PistonEngine*)((Thruster*)obj)->getEngine())->setWastegate(lval);
|
||||
break;
|
||||
case WINCHRELSPEED: ((Hitch*)obj)->setWinchRelSpeed(lval); break;
|
||||
case HITCHOPEN: ((Hitch*)obj)->setOpen(lval!=0); break;
|
||||
case PLACEWINCH: ((Hitch*)obj)->setWinchPositionAuto(lval!=0); break;
|
||||
case FINDAITOW: ((Hitch*)obj)->findBestAIObject(lval!=0); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +238,7 @@ float ControlMap::rangeMin(int type)
|
|||
case CYCLICELE: return -1;
|
||||
case CYCLICAIL: return -1;
|
||||
case COLLECTIVE: return -1;
|
||||
case WINCHRELSPEED: return -1;
|
||||
case MAGNETOS: return 0; // [0:3]
|
||||
default: return 0; // [0:1]
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ public:
|
|||
BOOST, CASTERING, PROPPITCH, PROPFEATHER,
|
||||
COLLECTIVE, CYCLICAIL, CYCLICELE, ROTORENGINEON,
|
||||
ROTORBRAKE,
|
||||
REVERSE_THRUST, WASTEGATE };
|
||||
REVERSE_THRUST, WASTEGATE,
|
||||
WINCHRELSPEED, HITCHOPEN, PLACEWINCH, FINDAITOW};
|
||||
|
||||
enum { OPT_SPLIT = 0x01,
|
||||
OPT_INVERT = 0x02,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "TurbineEngine.hpp"
|
||||
#include "Rotor.hpp"
|
||||
#include "Rotorpart.hpp"
|
||||
#include "Hitch.hpp"
|
||||
|
||||
#include "FGFDM.hpp"
|
||||
|
||||
|
@ -158,12 +159,14 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
float spd = attrf(a, "speed") * KTS2MPS;
|
||||
float alt = attrf(a, "alt", 0) * FT2M;
|
||||
float aoa = attrf(a, "aoa", 0) * DEG2RAD;
|
||||
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2));
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2),gla);
|
||||
_cruiseCurr = false;
|
||||
} else if(eq(name, "cruise")) {
|
||||
float spd = attrf(a, "speed") * KTS2MPS;
|
||||
float alt = attrf(a, "alt") * FT2M;
|
||||
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5));
|
||||
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
|
||||
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
|
||||
_cruiseCurr = true;
|
||||
} else if(eq(name, "solve-weight")) {
|
||||
int idx = attri(a, "idx");
|
||||
|
@ -245,6 +248,46 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
er->eng = j;
|
||||
er->prefix = dup(buf);
|
||||
_thrusters.add(er);
|
||||
} else if(eq(name, "hitch")) {
|
||||
Hitch* h = new Hitch(a->getValue("name"));
|
||||
_currObj = h;
|
||||
v[0] = attrf(a, "x");
|
||||
v[1] = attrf(a, "y");
|
||||
v[2] = attrf(a, "z");
|
||||
h->setPosition(v);
|
||||
if(a->hasAttribute("force-is-calculated-by-other")) h->setForceIsCalculatedByOther(attrb(a,"force-is-calculated-by-other"));
|
||||
_airplane.addHitch(h);
|
||||
} else if(eq(name, "tow")) {
|
||||
Hitch* h = (Hitch*)_currObj;
|
||||
if(a->hasAttribute("length"))
|
||||
h->setTowLength(attrf(a, "length"));
|
||||
if(a->hasAttribute("elastic-constant"))
|
||||
h->setTowElasticConstant(attrf(a, "elastic-constant"));
|
||||
if(a->hasAttribute("break-force"))
|
||||
h->setTowBreakForce(attrf(a, "break-force"));
|
||||
if(a->hasAttribute("weight-per-meter"))
|
||||
h->setTowWeightPerM(attrf(a, "weight-per-meter"));
|
||||
if(a->hasAttribute("mp-auto-connect-period"))
|
||||
h->setMpAutoConnectPeriod(attrf(a, "mp-auto-connect-period"));
|
||||
} else if(eq(name, "winch")) {
|
||||
Hitch* h = (Hitch*)_currObj;
|
||||
double pos[3];
|
||||
pos[0] = attrd(a, "x",0);
|
||||
pos[1] = attrd(a, "y",0);
|
||||
pos[2] = attrd(a, "z",0);
|
||||
h->setWinchPosition(pos);
|
||||
if(a->hasAttribute("max-speed"))
|
||||
h->setWinchMaxSpeed(attrf(a, "max-speed"));
|
||||
if(a->hasAttribute("power"))
|
||||
h->setWinchPower(attrf(a, "power") * 1000);
|
||||
if(a->hasAttribute("max-force"))
|
||||
h->setWinchMaxForce(attrf(a, "max-force"));
|
||||
if(a->hasAttribute("initial-tow-length"))
|
||||
h->setWinchInitialTowLength(attrf(a, "initial-tow-length"));
|
||||
if(a->hasAttribute("max-tow-length"))
|
||||
h->setWinchMaxTowLength(attrf(a, "max-tow-length"));
|
||||
if(a->hasAttribute("min-tow-length"))
|
||||
h->setWinchMinTowLength(attrf(a, "min-tow-length"));
|
||||
} else if(eq(name, "gear")) {
|
||||
Gear* g = new Gear();
|
||||
_currObj = g;
|
||||
|
@ -269,10 +312,17 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
|||
v[i] *= attrf(a, "compression", 1);
|
||||
g->setCompression(v);
|
||||
g->setBrake(attrf(a, "skid", 0));
|
||||
g->setInitialLoad(attrf(a, "initial-load", 0));
|
||||
g->setStaticFriction(attrf(a, "sfric", 0.8));
|
||||
g->setDynamicFriction(attrf(a, "dfric", 0.7));
|
||||
g->setSpring(attrf(a, "spring", 1));
|
||||
g->setDamping(attrf(a, "damp", 1));
|
||||
if(a->hasAttribute("on-water")) g->setOnWater(attrb(a,"on-water"));
|
||||
if(a->hasAttribute("on-solid")) g->setOnSolid(attrb(a,"on-solid"));
|
||||
if(a->hasAttribute("ignored-by-solver")) g->setIgnoreWhileSolving(attrb(a,"ignored-by-solver"));
|
||||
g->setSpringFactorNotPlaning(attrf(a, "spring-factor-not-planing", 1));
|
||||
g->setSpeedPlaning(attrf(a, "speed-planing", 0) * KTS2MPS);
|
||||
g->setReduceFrictionByExtension(attrf(a, "reduce-friction-by-extension", 0));
|
||||
_airplane.addGear(g);
|
||||
} else if(eq(name, "hook")) {
|
||||
Hook* h = new Hook();
|
||||
|
@ -898,6 +948,11 @@ int FGFDM::parseOutput(const char* name)
|
|||
if(eq(name, "ROTORBRAKE")) return ControlMap::ROTORBRAKE;
|
||||
if(eq(name, "REVERSE_THRUST")) return ControlMap::REVERSE_THRUST;
|
||||
if(eq(name, "WASTEGATE")) return ControlMap::WASTEGATE;
|
||||
if(eq(name, "WINCHRELSPEED")) return ControlMap::WINCHRELSPEED;
|
||||
if(eq(name, "HITCHOPEN")) return ControlMap::HITCHOPEN;
|
||||
if(eq(name, "PLACEWINCH")) return ControlMap::PLACEWINCH;
|
||||
if(eq(name, "FINDAITOW")) return ControlMap::FINDAITOW;
|
||||
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"Unrecognized control type '"
|
||||
<< name << "' in YASim aircraft description.");
|
||||
exit(1);
|
||||
|
@ -972,6 +1027,23 @@ float FGFDM::attrf(XMLAttributes* atts, char* attr, float def)
|
|||
else return (float)atof(val);
|
||||
}
|
||||
|
||||
double FGFDM::attrd(XMLAttributes* atts, char* attr)
|
||||
{
|
||||
if(!atts->hasAttribute(attr)) {
|
||||
SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr <<
|
||||
"' in YASim aircraft description");
|
||||
exit(1);
|
||||
}
|
||||
return attrd(atts, attr, 0);
|
||||
}
|
||||
|
||||
double FGFDM::attrd(XMLAttributes* atts, char* attr, double def)
|
||||
{
|
||||
const char* val = atts->getValue(attr);
|
||||
if(val == 0) return def;
|
||||
else return atof(val);
|
||||
}
|
||||
|
||||
// ACK: the dreaded ambiguous string boolean. Remind me to shoot Maik
|
||||
// when I have a chance. :). Unless you have a parser that can check
|
||||
// symbol constants (we don't), this kind of coding is just a Bad
|
||||
|
|
|
@ -53,6 +53,8 @@ private:
|
|||
int attri(XMLAttributes* atts, char* attr, int def);
|
||||
float attrf(XMLAttributes* atts, char* attr);
|
||||
float attrf(XMLAttributes* atts, char* attr, float def);
|
||||
double attrd(XMLAttributes* atts, char* attr);
|
||||
double attrd(XMLAttributes* atts, char* attr, double def);
|
||||
bool attrb(XMLAttributes* atts, char* attr);
|
||||
|
||||
// The core Airplane object we manage.
|
||||
|
|
|
@ -35,6 +35,23 @@ void FGGround::getGroundPlane(const double pos[3],
|
|||
for(int i=0; i<3; i++) vel[i] = dvel[i];
|
||||
}
|
||||
|
||||
void FGGround::getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3],
|
||||
int *type, const SGMaterial **material
|
||||
)
|
||||
{
|
||||
// Return values for the callback.
|
||||
double agl;
|
||||
double cp[3], dvel[3];
|
||||
_iface->get_agl_m(_toff, pos, cp, plane, dvel,
|
||||
type, material, &agl);
|
||||
|
||||
// The plane below the actual contact point.
|
||||
plane[3] = plane[0]*cp[0] + plane[1]*cp[1] + plane[2]*cp[2];
|
||||
|
||||
for(int i=0; i<3; i++) vel[i] = dvel[i];
|
||||
}
|
||||
|
||||
bool FGGround::caughtWire(const double pos[4][3])
|
||||
{
|
||||
return _iface->caught_wire_m(_toff, pos);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Ground.hpp"
|
||||
|
||||
class FGInterface;
|
||||
class SGMaterial;
|
||||
|
||||
namespace yasim {
|
||||
|
||||
|
@ -18,6 +19,16 @@ public:
|
|||
virtual void getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3]);
|
||||
|
||||
virtual void getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3],
|
||||
int *type, const SGMaterial **material);/*
|
||||
double *frictionFactor,
|
||||
double *rollingFriction,
|
||||
double *loadCapacity,
|
||||
double *loadResistance,
|
||||
double *bumpiness,
|
||||
bool *isSolid);*/
|
||||
|
||||
virtual bool caughtWire(const double pos[4][3]);
|
||||
|
||||
virtual bool getWire(double end[2][3], float vel[2][3]);
|
||||
|
|
|
@ -2,8 +2,13 @@
|
|||
#include "BodyEnvironment.hpp"
|
||||
#include "RigidBody.hpp"
|
||||
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
#include <FDM/flight.hxx>
|
||||
#include "Gear.hpp"
|
||||
namespace yasim {
|
||||
static const float YASIM_PI = 3.14159265358979323846;
|
||||
static const float maxGroundBumpAmplitude=0.4;
|
||||
//Amplitude can be positive and negative
|
||||
|
||||
Gear::Gear()
|
||||
{
|
||||
|
@ -16,9 +21,26 @@ Gear::Gear()
|
|||
_dfric = 0.7f;
|
||||
_brake = 0;
|
||||
_rot = 0;
|
||||
_initialLoad = 0;
|
||||
_extension = 1;
|
||||
_castering = false;
|
||||
_frac = 0;
|
||||
_ground_type = 0;
|
||||
_ground_frictionFactor = 1;
|
||||
_ground_rollingFriction = 0.02;
|
||||
_ground_loadCapacity = 1e30;
|
||||
_ground_loadResistance = 1e30;
|
||||
_ground_isSolid = 1;
|
||||
_ground_bumpiness = 0;
|
||||
_onWater = 0;
|
||||
_onSolid = 1;
|
||||
_global_x = 0.0;
|
||||
_global_y = 0.0;
|
||||
_reduceFrictionByExtension = 0;
|
||||
_spring_factor_not_planing = 1;
|
||||
_speed_planing = 0;
|
||||
_isContactPoint = 0;
|
||||
_ignoreWhileSolving = 0;
|
||||
|
||||
for(i=0; i<3; i++)
|
||||
_global_ground[i] = _global_vel[i] = 0;
|
||||
|
@ -78,12 +100,99 @@ void Gear::setCastering(bool c)
|
|||
_castering = c;
|
||||
}
|
||||
|
||||
void Gear::setGlobalGround(double *global_ground, float* global_vel)
|
||||
void Gear::setContactPoint(bool c)
|
||||
{
|
||||
_isContactPoint=c;
|
||||
}
|
||||
|
||||
void Gear::setOnWater(bool c)
|
||||
{
|
||||
_onWater = c;
|
||||
}
|
||||
|
||||
void Gear::setOnSolid(bool c)
|
||||
{
|
||||
_onSolid = c;
|
||||
}
|
||||
|
||||
void Gear::setIgnoreWhileSolving(bool c)
|
||||
{
|
||||
_ignoreWhileSolving = c;
|
||||
}
|
||||
|
||||
void Gear::setSpringFactorNotPlaning(float f)
|
||||
{
|
||||
_spring_factor_not_planing = f;
|
||||
}
|
||||
|
||||
void Gear::setSpeedPlaning(float s)
|
||||
{
|
||||
_speed_planing = s;
|
||||
}
|
||||
|
||||
void Gear::setReduceFrictionByExtension(float s)
|
||||
{
|
||||
_reduceFrictionByExtension = s;
|
||||
}
|
||||
|
||||
void Gear::setInitialLoad(float l)
|
||||
{
|
||||
_initialLoad = l;
|
||||
}
|
||||
|
||||
void Gear::setGlobalGround(double *global_ground, float* global_vel,
|
||||
double globalX, double globalY,
|
||||
int type, const SGMaterial *material)
|
||||
{
|
||||
int i;
|
||||
double frictionFactor,rollingFriction,loadCapacity,loadResistance,bumpiness;
|
||||
bool isSolid;
|
||||
|
||||
for(i=0; i<4; i++) _global_ground[i] = global_ground[i];
|
||||
for(i=0; i<3; i++) _global_vel[i] = global_vel[i];
|
||||
}
|
||||
|
||||
if (material) {
|
||||
loadCapacity = (*material).get_load_resistence();
|
||||
frictionFactor =(*material).get_friction_factor();
|
||||
rollingFriction = (*material).get_rolling_friction();
|
||||
loadResistance = (*material).get_load_resistence();
|
||||
bumpiness = (*material).get_bumpiness();
|
||||
isSolid = (*material).get_solid();
|
||||
} else {
|
||||
if (type == FGInterface::Solid) {
|
||||
loadCapacity = DBL_MAX;
|
||||
frictionFactor = 1.0;
|
||||
rollingFriction = 0.02;
|
||||
loadResistance = DBL_MAX;
|
||||
bumpiness = 0.0;
|
||||
isSolid = true;
|
||||
} else if (type == FGInterface::Water) {
|
||||
loadCapacity = DBL_MAX;
|
||||
frictionFactor = 1.0;
|
||||
rollingFriction = 2;
|
||||
loadResistance = DBL_MAX;
|
||||
bumpiness = 0.8;
|
||||
isSolid = false;
|
||||
} else {
|
||||
loadCapacity = DBL_MAX;
|
||||
frictionFactor = 0.9;
|
||||
rollingFriction = 0.1;
|
||||
loadResistance = DBL_MAX;
|
||||
bumpiness = 0.2;
|
||||
isSolid = true;
|
||||
}
|
||||
}
|
||||
_ground_type = type;
|
||||
_ground_frictionFactor = frictionFactor;
|
||||
_ground_rollingFriction = rollingFriction;
|
||||
_ground_loadCapacity = loadCapacity;
|
||||
_ground_loadResistance = loadResistance;
|
||||
_ground_bumpiness = bumpiness;
|
||||
_ground_isSolid = isSolid;
|
||||
_global_x = globalX;
|
||||
_global_y = globalY;
|
||||
|
||||
}
|
||||
|
||||
void Gear::getPosition(float* out)
|
||||
{
|
||||
|
@ -159,6 +268,31 @@ bool Gear::getCastering()
|
|||
return _castering;
|
||||
}
|
||||
|
||||
bool Gear::getGroundIsSolid()
|
||||
{
|
||||
return _ground_isSolid;
|
||||
}
|
||||
|
||||
float Gear::getBumpAltitude()
|
||||
{
|
||||
if (_ground_bumpiness<0.001) return 0.0;
|
||||
double x = _global_x*0.1;
|
||||
double y = _global_y*0.1;
|
||||
x -= Math::floor(x);
|
||||
y -= Math::floor(y);
|
||||
x *= 2*YASIM_PI;
|
||||
y *= 2*YASIM_PI;
|
||||
//now x and y are in the range of 0..2pi
|
||||
//we need a function, that is periodically on 2pi and gives some
|
||||
//height. This is not very fast, but for a beginning.
|
||||
//maybe this should be done by interpolating between some precalculated
|
||||
//values
|
||||
float h = Math::sin(x)+Math::sin(7*x)+Math::sin(8*x)+Math::sin(13*x);
|
||||
h += Math::sin(2*y)+Math::sin(5*y)+Math::sin(9*y*x)+Math::sin(17*y);
|
||||
|
||||
return h*(1/8.)*_ground_bumpiness*maxGroundBumpAmplitude;
|
||||
}
|
||||
|
||||
void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
||||
{
|
||||
// Init the return values
|
||||
|
@ -169,6 +303,16 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
if(_extension < 1)
|
||||
return;
|
||||
|
||||
// Dont bother if we are in the "wrong" ground
|
||||
if (!((_onWater&&!_ground_isSolid)||(_onSolid&&_ground_isSolid))) {
|
||||
_wow = 0;
|
||||
_frac = 0;
|
||||
_compressDist = 0;
|
||||
_rollSpeed = 0;
|
||||
_casterAngle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// The ground plane transformed to the local frame.
|
||||
float ground[4];
|
||||
s->planeGlobalToLocal(_global_ground, ground);
|
||||
|
@ -180,6 +324,12 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
// First off, make sure that the gear "tip" is below the ground.
|
||||
// If it's not, there's no force.
|
||||
float a = ground[3] - Math::dot3(_pos, ground);
|
||||
float BumpAltitude=0;
|
||||
if (a<maxGroundBumpAmplitude)
|
||||
{
|
||||
BumpAltitude=getBumpAltitude();
|
||||
a+=BumpAltitude;
|
||||
}
|
||||
_compressDist = -a;
|
||||
if(a > 0) {
|
||||
_wow = 0;
|
||||
|
@ -196,7 +346,7 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
// above ground is negative.
|
||||
float tmp[3];
|
||||
Math::add3(_cmpr, _pos, tmp);
|
||||
float b = ground[3] - Math::dot3(tmp, ground);
|
||||
float b = ground[3] - Math::dot3(tmp, ground)+BumpAltitude;
|
||||
|
||||
// Calculate the point of ground _contact.
|
||||
_frac = a/(a-b);
|
||||
|
@ -218,8 +368,25 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
// Finally, we can start adding up the forces. First the spring
|
||||
// compression. (note the clamping of _frac to 1):
|
||||
_frac = (_frac > 1) ? 1 : _frac;
|
||||
float fmag = _frac*clen*_spring;
|
||||
|
||||
// Add the initial load to frac, but with continous transistion around 0
|
||||
float frac_with_initial_load;
|
||||
if (_frac>0.2 || _initialLoad==0.0)
|
||||
frac_with_initial_load = _frac+_initialLoad;
|
||||
else
|
||||
frac_with_initial_load = (_frac+_initialLoad)
|
||||
*_frac*_frac*3*25-_frac*_frac*_frac*2*125;
|
||||
|
||||
float fmag = frac_with_initial_load*clen*_spring;
|
||||
if (_speed_planing>0)
|
||||
{
|
||||
float v = Math::mag3(cv);
|
||||
if (v < _speed_planing)
|
||||
{
|
||||
float frac = v/_speed_planing;
|
||||
fmag = fmag*_spring_factor_not_planing*(1-frac)+fmag*frac;
|
||||
}
|
||||
}
|
||||
// Then the damping. Use the only the velocity into the ground
|
||||
// (projection along "ground") projected along the compression
|
||||
// axis. So Vdamp = ground*(ground dot cv) dot cmpr
|
||||
|
@ -284,11 +451,28 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
_rollSpeed = vsteer;
|
||||
_casterAngle = _rot;
|
||||
}
|
||||
|
||||
float fsteer = _brake * calcFriction(wgt, vsteer);
|
||||
float fskid = calcFriction(wgt, vskid);
|
||||
float fsteer,fskid;
|
||||
if(_ground_isSolid)
|
||||
{
|
||||
fsteer = (_brake * _ground_frictionFactor
|
||||
+(1-_brake)*_ground_rollingFriction
|
||||
)*calcFriction(wgt, vsteer);
|
||||
fskid = calcFriction(wgt, vskid)*(_ground_frictionFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
fsteer = calcFrictionFluid(wgt, vsteer)*_ground_frictionFactor;
|
||||
fskid = 10*calcFrictionFluid(wgt, vskid)*_ground_frictionFactor;
|
||||
//factor 10: floats have different drag in x and y.
|
||||
}
|
||||
if(vsteer > 0) fsteer = -fsteer;
|
||||
if(vskid > 0) fskid = -fskid;
|
||||
|
||||
//reduce friction if wanted by _reduceFrictionByExtension
|
||||
float factor = (1-_frac)*(1-_reduceFrictionByExtension)+_frac*1;
|
||||
factor = Math::clamp(factor,0,1);
|
||||
fsteer *= factor;
|
||||
fskid *= factor;
|
||||
|
||||
// Phoo! All done. Add it up and get out of here.
|
||||
Math::mul3(fsteer, steer, tmp);
|
||||
|
@ -298,7 +482,7 @@ void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
|
|||
Math::add3(tmp, _force, _force);
|
||||
}
|
||||
|
||||
float Gear::calcFriction(float wgt, float v)
|
||||
float Gear::calcFriction(float wgt, float v) //used on solid ground
|
||||
{
|
||||
// How slow is stopped? 10 cm/second?
|
||||
const float STOP = 0.1f;
|
||||
|
@ -308,5 +492,15 @@ float Gear::calcFriction(float wgt, float v)
|
|||
else return wgt * _dfric;
|
||||
}
|
||||
|
||||
float Gear::calcFrictionFluid(float wgt, float v) //used on fluid ground
|
||||
{
|
||||
// How slow is stopped? 1 cm/second?
|
||||
const float STOP = 0.01f;
|
||||
const float iSTOP = 1.0f/STOP;
|
||||
v = Math::abs(v);
|
||||
if(v < STOP) return v*iSTOP * wgt * _sfric;
|
||||
else return wgt * _dfric*v*v*0.01;
|
||||
//*0.01: to get _dfric of the same size than _dfric on solid
|
||||
}
|
||||
}; // namespace yasim
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef _GEAR_HPP
|
||||
#define _GEAR_HPP
|
||||
|
||||
class SGMaterial;
|
||||
|
||||
namespace yasim {
|
||||
|
||||
class RigidBody;
|
||||
|
@ -39,8 +41,16 @@ public:
|
|||
void setRotation(float rotation);
|
||||
void setExtension(float extension);
|
||||
void setCastering(bool castering);
|
||||
void setGlobalGround(double* global_ground, float* global_vel);
|
||||
|
||||
void setOnWater(bool c);
|
||||
void setOnSolid(bool c);
|
||||
void setSpringFactorNotPlaning(float f);
|
||||
void setSpeedPlaning(float s);
|
||||
void setReduceFrictionByExtension(float s);
|
||||
void setInitialLoad(float l);
|
||||
void setIgnoreWhileSolving(bool c);
|
||||
void setGlobalGround(double* global_ground, float* global_vel,
|
||||
double globalX, double globalY,
|
||||
int type, const SGMaterial *material);
|
||||
void getPosition(float* out);
|
||||
void getCompression(float* out);
|
||||
void getGlobalGround(double* global_ground);
|
||||
|
@ -51,9 +61,12 @@ public:
|
|||
float getBrake();
|
||||
float getRotation();
|
||||
float getExtension();
|
||||
float getInitialLoad() {return _initialLoad; }
|
||||
bool getCastering();
|
||||
float getCasterAngle() { return _casterAngle; }
|
||||
float getRollSpeed() { return _rollSpeed; }
|
||||
float getBumpAltitude();
|
||||
bool getGroundIsSolid();
|
||||
|
||||
// Takes a velocity of the aircraft relative to ground, a rotation
|
||||
// vector, and a ground plane (all specified in local coordinates)
|
||||
|
@ -67,9 +80,13 @@ public:
|
|||
float getWoW();
|
||||
float getCompressFraction();
|
||||
float getCompressDist() { return _compressDist; }
|
||||
bool getSubmergable() {return (!_ground_isSolid)&&(!_isContactPoint); }
|
||||
bool getIgnoreWhileSolving() {return _ignoreWhileSolving; }
|
||||
void setContactPoint(bool c);
|
||||
|
||||
private:
|
||||
float calcFriction(float wgt, float v);
|
||||
float calcFrictionFluid(float wgt, float v);
|
||||
|
||||
bool _castering;
|
||||
float _pos[3];
|
||||
|
@ -85,11 +102,29 @@ private:
|
|||
float _contact[3];
|
||||
float _wow;
|
||||
float _frac;
|
||||
float _initialLoad;
|
||||
float _compressDist;
|
||||
double _global_ground[4];
|
||||
float _global_vel[3];
|
||||
float _casterAngle;
|
||||
float _rollSpeed;
|
||||
bool _isContactPoint;
|
||||
bool _onWater;
|
||||
bool _onSolid;
|
||||
float _spring_factor_not_planing;
|
||||
float _speed_planing;
|
||||
float _reduceFrictionByExtension;
|
||||
bool _ignoreWhileSolving;
|
||||
|
||||
int _ground_type;
|
||||
double _ground_frictionFactor;
|
||||
double _ground_rollingFriction;
|
||||
double _ground_loadCapacity;
|
||||
double _ground_loadResistance;
|
||||
double _ground_bumpiness;
|
||||
bool _ground_isSolid;
|
||||
double _global_x;
|
||||
double _global_y;
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "Glue.hpp"
|
||||
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
#include "Ground.hpp"
|
||||
namespace yasim {
|
||||
|
||||
|
@ -28,6 +29,13 @@ void Ground::getGroundPlane(const double pos[3],
|
|||
vel[2] = 0.0;
|
||||
}
|
||||
|
||||
void Ground::getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3],
|
||||
int *type, const SGMaterial **material)
|
||||
{
|
||||
getGroundPlane(pos,plane,vel);
|
||||
}
|
||||
|
||||
bool Ground::caughtWire(const double pos[4][3])
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _GROUND_HPP
|
||||
#define _GROUND_HPP
|
||||
|
||||
class SGMaterial;
|
||||
namespace yasim {
|
||||
|
||||
class Ground {
|
||||
|
@ -11,6 +12,10 @@ public:
|
|||
virtual void getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3]);
|
||||
|
||||
virtual void getGroundPlane(const double pos[3],
|
||||
double plane[4], float vel[3],
|
||||
int *type, const SGMaterial **material);
|
||||
|
||||
virtual bool caughtWire(const double pos[4][3]);
|
||||
|
||||
virtual bool getWire(double end[2][3], float vel[2][3]);
|
||||
|
|
778
src/FDM/YASim/Hitch.cpp
Executable file
778
src/FDM/YASim/Hitch.cpp
Executable file
|
@ -0,0 +1,778 @@
|
|||
#include "Math.hpp"
|
||||
#include "BodyEnvironment.hpp"
|
||||
#include "RigidBody.hpp"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
#include "Hitch.hpp"
|
||||
namespace yasim {
|
||||
Hitch::Hitch(const char *name)
|
||||
{
|
||||
int i;
|
||||
strncpy(_name,name,128);
|
||||
_name[127]=0;
|
||||
for(i=0; i<3; i++)
|
||||
_pos[i] = _force[i] = _winchPos[i] = _mp_lpos[i]=_towEndForce[i]=_mp_force[i]=0;
|
||||
for(i=0; i<2; i++)
|
||||
_global_ground[i] = 0;
|
||||
_global_ground[2] = 1;
|
||||
_global_ground[3] = -1e5;
|
||||
_forceMagnitude=0;
|
||||
_open=true;
|
||||
_oldOpen=_open;
|
||||
_towLength=60;
|
||||
_towElasticConstant=1e5;
|
||||
_towBrakeForce=100000;
|
||||
_towWeightPerM=1;
|
||||
_winchMaxSpeed=40;
|
||||
_winchRelSpeed=0;
|
||||
_winchInitialTowLength=1000;
|
||||
_winchPower=100000;
|
||||
_winchMaxForce=10000;
|
||||
_winchActualForce=0;
|
||||
_winchMaxTowLength=1000;
|
||||
_winchMinTowLength=0;
|
||||
_dist=0;
|
||||
_towEndIsConnectedToProperty=false;
|
||||
_towEndNode=0;
|
||||
_nodeIsMultiplayer=false;
|
||||
_nodeIsAiAircraft=false;
|
||||
_forceIsCalculatedByMaster=false;
|
||||
_nodeID=0;
|
||||
//_ai_MP_callsign=0;
|
||||
_height_above_ground=0;
|
||||
_winch_height_above_ground=0;
|
||||
_loPosFrac=0;
|
||||
_lowest_tow_height=0;
|
||||
_state=new State;
|
||||
_displayed_len_lower_dist_message=false;
|
||||
_last_wish=true;
|
||||
_isSlave=false;
|
||||
_mpAutoConnectPeriod=0;
|
||||
_timeToNextAutoConnectTry=0;
|
||||
_timeToNextReConnectTry=10;
|
||||
_speed_in_tow_direction=0;
|
||||
_mp_time_lag=1;
|
||||
_mp_last_reported_dist=0;
|
||||
_mp_last_reported_v=0;
|
||||
_mp_is_slave=false;
|
||||
_mp_open_last_state=false;
|
||||
_timeLagCorrectedDist=0;
|
||||
|
||||
//tie the properties
|
||||
char text[128];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->tie("tow/length",SGRawValuePointer<float>(&_towLength));
|
||||
node->tie("tow/elastic-constant",SGRawValuePointer<float>(&_towElasticConstant));
|
||||
node->tie("tow/weight-per-m-kg-m",SGRawValuePointer<float>(&_towWeightPerM));
|
||||
node->tie("tow/brake-force",SGRawValuePointer<float>(&_towBrakeForce));
|
||||
node->tie("winch/max-speed-m-s",SGRawValuePointer<float>(&_winchMaxSpeed));
|
||||
node->tie("winch/rel-speed",SGRawValuePointer<float>(&_winchRelSpeed));
|
||||
node->tie("winch/initial-tow-length-m",SGRawValuePointer<float>(&_winchInitialTowLength));
|
||||
node->tie("winch/min-tow-length-m",SGRawValuePointer<float>(&_winchMinTowLength));
|
||||
node->tie("winch/max-tow-length-m",SGRawValuePointer<float>(&_winchMaxTowLength));
|
||||
node->tie("winch/global-pos-x",SGRawValuePointer<double>(&_winchPos[0]));
|
||||
node->tie("winch/global-pos-y",SGRawValuePointer<double>(&_winchPos[1]));
|
||||
node->tie("winch/global-pos-z",SGRawValuePointer<double>(&_winchPos[2]));
|
||||
node->tie("winch/max-power",SGRawValuePointer<float>(&_winchPower));
|
||||
node->tie("winch/max-force",SGRawValuePointer<float>(&_winchMaxForce));
|
||||
node->tie("winch/actual-force",SGRawValuePointer<float>(&_winchActualForce));
|
||||
node->tie("tow/end-force-x",SGRawValuePointer<float>(&_reportTowEndForce[0]));
|
||||
node->tie("tow/end-force-y",SGRawValuePointer<float>(&_reportTowEndForce[1]));
|
||||
node->tie("tow/end-force-z",SGRawValuePointer<float>(&_reportTowEndForce[2]));
|
||||
node->tie("force",SGRawValuePointer<float>(&_forceMagnitude));
|
||||
node->tie("open",SGRawValuePointer<bool>(&_open));
|
||||
node->tie("force-is-calculated-by-other",SGRawValuePointer<bool>(&_forceIsCalculatedByMaster));
|
||||
node->tie("local-pos-x",SGRawValuePointer<float>(&_pos[0]));
|
||||
node->tie("local-pos-y",SGRawValuePointer<float>(&_pos[1]));
|
||||
node->tie("local-pos-z",SGRawValuePointer<float>(&_pos[2]));
|
||||
node->tie("tow/dist",SGRawValuePointer<float>(&_dist));
|
||||
node->tie("tow/dist-time-lag-corrected",SGRawValuePointer<float>(&_timeLagCorrectedDist));
|
||||
node->tie("tow/connected-to-property-node",SGRawValuePointer<bool>(&_towEndIsConnectedToProperty));
|
||||
node->tie("tow/connected-to-mp-node",SGRawValuePointer<bool>(&_nodeIsMultiplayer));
|
||||
node->tie("tow/connected-to-ai-node",SGRawValuePointer<bool>(&_nodeIsAiAircraft));
|
||||
node->tie("tow/connected-to-ai-or-mp-id",SGRawValuePointer<int>(&_nodeID));
|
||||
node->tie("debug/hitch-height-above-ground",SGRawValuePointer<float>(&_height_above_ground));
|
||||
node->tie("debug/tow-end-height-above-ground",SGRawValuePointer<float>(&_winch_height_above_ground));
|
||||
node->tie("debug/tow-rel-lo-pos",SGRawValuePointer<float>(&_loPosFrac));
|
||||
node->tie("debug/tow-lowest-pos-height",SGRawValuePointer<float>(&_lowest_tow_height));
|
||||
node->tie("is-slave",SGRawValuePointer<bool>(&_isSlave));
|
||||
node->tie("speed-in-tow-direction",SGRawValuePointer<float>(&_speed_in_tow_direction));
|
||||
node->tie("mp-auto-connect-period",SGRawValuePointer<float>(&_mpAutoConnectPeriod));
|
||||
node->tie("mp-time-lag",SGRawValuePointer<float>(&_mp_time_lag));
|
||||
node->setStringValue("tow/Node","");
|
||||
node->setStringValue("tow/connectedToAIorMP-callsign");
|
||||
node->setBoolValue("broken",false);
|
||||
}
|
||||
|
||||
Hitch::~Hitch()
|
||||
{
|
||||
char text[128];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->untie("tow/length");
|
||||
node->untie("tow/elastic-constant");
|
||||
node->untie("tow/weight-per-m-kg-m");
|
||||
node->untie("tow/brake-force");
|
||||
node->untie("winch/max-speed-m-s");
|
||||
node->untie("winch/rel-speed");
|
||||
node->untie("winch/initial-tow-length-m");
|
||||
node->untie("winch/min-tow-length-m");
|
||||
node->untie("winch/max-tow-length-m");
|
||||
node->untie("winch/global-pos-x");
|
||||
node->untie("winch/global-pos-y");
|
||||
node->untie("winch/global-pos-z");
|
||||
node->untie("winch/max-power");
|
||||
node->untie("winch/max-force");
|
||||
node->untie("winch/actual-force");
|
||||
node->untie("tow/end-force-x");
|
||||
node->untie("tow/end-force-y");
|
||||
node->untie("tow/end-force-z");
|
||||
node->untie("force");
|
||||
node->untie("open");
|
||||
node->untie("force-is-calculated-by-other");
|
||||
node->untie("local-pos-x");
|
||||
node->untie("local-pos-y");
|
||||
node->untie("local-pos-z");
|
||||
node->untie("tow/dist");
|
||||
node->untie("tow/dist-time-lag-corrected");
|
||||
node->untie("tow/connected-to-property-node");
|
||||
node->untie("tow/connected-to-mp-node");
|
||||
node->untie("tow/connected-to-ai-node");
|
||||
node->untie("tow/connected-to-ai-or-mp-id");
|
||||
node->untie("debug/hitch-height-above-ground");
|
||||
node->untie("debug/tow-end-height-above-ground");
|
||||
node->untie("debug/tow-rel-lo-pos");
|
||||
node->untie("debug/tow-lowest-pos-height");
|
||||
node->untie("is-slave");
|
||||
node->untie("speed-in-tow-direction");
|
||||
node->untie("mp-auto-connect-period");
|
||||
node->untie("mp-time-lag");
|
||||
|
||||
delete _state;
|
||||
}
|
||||
|
||||
void Hitch::setPosition(float* position)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) _pos[i] = position[i];
|
||||
}
|
||||
|
||||
void Hitch::setTowLength(float length)
|
||||
{
|
||||
_towLength = length;
|
||||
}
|
||||
|
||||
void Hitch::setOpen(bool isOpen)
|
||||
{
|
||||
//test if we already processed this before
|
||||
//without this test a binded property could
|
||||
//try to close the Hitch every run
|
||||
//it will close, if we are near the end
|
||||
//e.g. if we are flying over the parked
|
||||
//tow-aircraft....
|
||||
if (isOpen==_last_wish)
|
||||
return;
|
||||
_last_wish=isOpen;
|
||||
_open=isOpen;
|
||||
}
|
||||
|
||||
void Hitch::setTowElasticConstant(float sc)
|
||||
{
|
||||
_towElasticConstant=sc;
|
||||
}
|
||||
|
||||
void Hitch::setTowBreakForce(float bf)
|
||||
{
|
||||
_towBrakeForce=bf;
|
||||
}
|
||||
|
||||
void Hitch::setWinchMaxForce(float f)
|
||||
{
|
||||
_winchMaxForce=f;
|
||||
}
|
||||
|
||||
void Hitch::setTowWeightPerM(float rw)
|
||||
{
|
||||
_towWeightPerM=rw;
|
||||
}
|
||||
|
||||
void Hitch::setWinchMaxSpeed(float mws)
|
||||
{
|
||||
_winchMaxSpeed=mws;
|
||||
}
|
||||
|
||||
void Hitch::setWinchRelSpeed(float rws)
|
||||
{
|
||||
_winchRelSpeed=rws;
|
||||
}
|
||||
|
||||
void Hitch::setWinchPosition(double *winchPosition)//in global coordinates!
|
||||
{
|
||||
for (int i=0; i<3;i++)
|
||||
_winchPos[i]=winchPosition[i];
|
||||
}
|
||||
|
||||
void Hitch::setMpAutoConnectPeriod(float dt)
|
||||
{
|
||||
_mpAutoConnectPeriod=dt;
|
||||
}
|
||||
|
||||
void Hitch::setForceIsCalculatedByOther(bool b)
|
||||
{
|
||||
_forceIsCalculatedByMaster=b;
|
||||
}
|
||||
|
||||
const char *Hitch::getConnectedPropertyNode() const
|
||||
{
|
||||
if (_towEndNode)
|
||||
return _towEndNode->getDisplayName();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Hitch::setConnectedPropertyNode(const char *nodename)
|
||||
{
|
||||
_towEndNode=fgGetNode(nodename,false);
|
||||
}
|
||||
|
||||
void Hitch::setWinchPositionAuto(bool doit)
|
||||
{
|
||||
static bool lastState=false;
|
||||
if(!_state)
|
||||
return;
|
||||
if (!doit)
|
||||
{
|
||||
lastState=false;
|
||||
return;
|
||||
}
|
||||
if(lastState)
|
||||
return;
|
||||
lastState=true;
|
||||
float lWinchPos[3];
|
||||
// The ground plane transformed to the local frame.
|
||||
float ground[4];
|
||||
_state->planeGlobalToLocal(_global_ground, ground);
|
||||
|
||||
float help[3];
|
||||
//find a normalized vector pointing forward parallel to the ground
|
||||
help[0]=0;
|
||||
help[1]=1;
|
||||
help[2]=0;
|
||||
Math::cross3(ground,help,help);
|
||||
//multiplay by initial tow length;
|
||||
//reduced by 1m to be able to close the
|
||||
//hitch either if the glider slips backwards a bit
|
||||
Math::mul3((_winchInitialTowLength-1.),help,help);
|
||||
//add to the actual pos
|
||||
Math::add3(_pos,help,lWinchPos);
|
||||
//put it onto the ground plane
|
||||
Math::mul3(ground[3],ground,help);
|
||||
Math::add3(lWinchPos,help,lWinchPos);
|
||||
|
||||
_state->posLocalToGlobal(lWinchPos,_winchPos);
|
||||
_towLength=_winchInitialTowLength;
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,"Set the winch pos to "<<_winchPos[0]<<","<<_winchPos[1]<<","<<_winchPos[2]<<endl);
|
||||
_open=false;
|
||||
|
||||
char text[512];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->setBoolValue("broken",false);
|
||||
|
||||
//set the dist value (if not, the hitch would open in the next calcforce run
|
||||
//float delta[3];
|
||||
//Math::sub3(lWinchPos,_pos,delta);
|
||||
//_dist=Math::mag3(delta);
|
||||
_dist=Math::mag3(lWinchPos); //use the aircraft center as reference for distance calculation
|
||||
//this position is transferred to the MP-Aircraft.
|
||||
//With this trick, both player in aerotow get the same length
|
||||
|
||||
}
|
||||
|
||||
void Hitch::findBestAIObject(bool doit,bool running_as_autoconnect)
|
||||
{
|
||||
static bool lastState=false;
|
||||
if(!_state)
|
||||
return;
|
||||
if (!doit)
|
||||
{
|
||||
lastState=false;
|
||||
return;
|
||||
}
|
||||
if(lastState)
|
||||
return;
|
||||
lastState=true;
|
||||
double gpos[3];
|
||||
_state->posLocalToGlobal(_pos,gpos);
|
||||
double bestdist=_towLength*_towLength;//squared!
|
||||
_towEndIsConnectedToProperty=false;
|
||||
SGPropertyNode * ainode = fgGetNode("/ai/models",false);
|
||||
if(!ainode) return;
|
||||
char myCallsign[256]="***********";
|
||||
if (running_as_autoconnect)
|
||||
{
|
||||
//get own callsign
|
||||
SGPropertyNode *cs=fgGetNode("/sim/multiplay/callsign",false);
|
||||
if (cs)
|
||||
{
|
||||
strncpy(myCallsign,cs->getStringValue(),256);
|
||||
myCallsign[255]=0;
|
||||
}
|
||||
//reset tow length for search radius. Lentgh will be later copied from master
|
||||
_towLength=_winchInitialTowLength;
|
||||
}
|
||||
bool found=false;
|
||||
vector <SGPropertyNode_ptr> nodes;//<SGPropertyNode_ptr>
|
||||
for (int i=0;i<ainode->nChildren();i++)
|
||||
{
|
||||
SGPropertyNode * n=ainode->getChild(i);
|
||||
_nodeIsMultiplayer = strncmp("multiplayer",n->getName(),11)==0;
|
||||
_nodeIsAiAircraft = strncmp("aircraft",n->getName(),8)==0;
|
||||
if (!(_nodeIsMultiplayer || _nodeIsAiAircraft))
|
||||
continue;
|
||||
if (running_as_autoconnect)
|
||||
{
|
||||
if (!_nodeIsMultiplayer)
|
||||
continue;
|
||||
if(n->getBoolValue("sim/hitches/aerotow/open",true)) continue;
|
||||
if(strncmp(myCallsign,n->getStringValue("sim/hitches/aerotow/tow/connectedToAIorMP-callsign"),255)!=0)
|
||||
continue;
|
||||
}
|
||||
double pos[3];
|
||||
pos[0]=n->getDoubleValue("position/global-x",0);
|
||||
pos[1]=n->getDoubleValue("position/global-y",0);
|
||||
pos[2]=n->getDoubleValue("position/global-z",0);
|
||||
double dist=0;
|
||||
for (int j=0;j<3;j++)
|
||||
dist+=(pos[j]-gpos[j])*(pos[j]-gpos[j]);
|
||||
if (dist<bestdist)
|
||||
{
|
||||
bestdist=dist;
|
||||
_towEndNode=n;
|
||||
_towEndIsConnectedToProperty=true;
|
||||
char text[512];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
//node->setStringValue("tow/Node",n->getPath());
|
||||
node->setStringValue("tow/Node",n->getDisplayName());
|
||||
_nodeID=n->getIntValue("id",0);
|
||||
node->setStringValue("tow/connectedToAIorMP-callsign",n->getStringValue("callsign"));
|
||||
_open=false;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
char text[512];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
//if (!running_as_autoconnect)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,"Found aircraft for aerotow: "
|
||||
<<node->getStringValue("tow/connectedToAIorMP-callsign")
|
||||
<<", distance "<<Math::sqrt(bestdist)<<"m at "
|
||||
<<node->getStringValue("tow/Node")<<endl);
|
||||
if (running_as_autoconnect)
|
||||
_isSlave=true;
|
||||
//set the dist value to some value below the tow lentgh (if not, the hitch
|
||||
//would open in the next calc force run
|
||||
_dist=_towLength*0.5;
|
||||
_mp_open_last_state=true;
|
||||
}
|
||||
else
|
||||
if (!running_as_autoconnect)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,"Found no aircraft for aerotow!"<<endl);
|
||||
}
|
||||
|
||||
void Hitch::setWinchInitialTowLength(float length)
|
||||
{
|
||||
_winchInitialTowLength=length;
|
||||
}
|
||||
|
||||
void Hitch::setWinchPower(float power)
|
||||
{
|
||||
_winchPower=power;
|
||||
}
|
||||
|
||||
void Hitch::setWinchMaxTowLength(float length)
|
||||
{
|
||||
_winchMaxTowLength=length;
|
||||
}
|
||||
|
||||
void Hitch::setWinchMinTowLength(float length)
|
||||
{
|
||||
_winchMinTowLength=length;
|
||||
}
|
||||
|
||||
void Hitch::setGlobalGround(double *global_ground, float *global_vel)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; i++) _global_ground[i] = global_ground[i];
|
||||
for(i=0; i<3; i++) _global_vel[i] = global_vel[i];
|
||||
}
|
||||
|
||||
void Hitch::getPosition(float* out)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; i++) out[i] = _pos[i];
|
||||
}
|
||||
|
||||
float Hitch::getTowLength(void)
|
||||
{
|
||||
return _towLength;
|
||||
}
|
||||
|
||||
void Hitch::calcForce(Ground *g_cb, RigidBody* body, State* s)
|
||||
{
|
||||
float lWinchPos[3],delta[3],deltaN[3];
|
||||
*_state=*s;
|
||||
s->posGlobalToLocal(_winchPos,lWinchPos);
|
||||
Math::sub3(lWinchPos,_pos,delta);
|
||||
//_dist=Math::mag3(delta);
|
||||
_dist=Math::mag3(lWinchPos); //use the aircraft center as reference for distance calculation
|
||||
//this position is transferred to the MP-Aircraft.
|
||||
//With this trick, both player in aerotow get the same length
|
||||
Math::unit3(delta,deltaN);
|
||||
float lvel[3];
|
||||
s->velGlobalToLocal(s->v,lvel);
|
||||
_speed_in_tow_direction=Math::dot3(lvel,deltaN);
|
||||
if (_towEndIsConnectedToProperty && _nodeIsMultiplayer)
|
||||
{
|
||||
float mp_delta_dist_due_to_time_lag=0.5*_mp_time_lag*(-_mp_v+_speed_in_tow_direction);
|
||||
_timeLagCorrectedDist=_dist+mp_delta_dist_due_to_time_lag;
|
||||
if(_forceIsCalculatedByMaster && !_open)
|
||||
{
|
||||
s->velGlobalToLocal(_mp_force,_force);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
_timeLagCorrectedDist=_dist;
|
||||
if (_open)
|
||||
{
|
||||
_force[0]=_force[1]=_force[2]=0;
|
||||
return;
|
||||
}
|
||||
if(_dist>_towLength)
|
||||
if(_towLength>1e-3)
|
||||
_forceMagnitude=(_dist-_towLength)/_towLength*_towElasticConstant;
|
||||
else
|
||||
_forceMagnitude=2*_towBrakeForce;
|
||||
else
|
||||
_forceMagnitude=0;
|
||||
if(_forceMagnitude>=_towBrakeForce)
|
||||
{
|
||||
_forceMagnitude=0;
|
||||
_open=true;
|
||||
char text[128];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->setBoolValue("broken",true);
|
||||
_force[0]=_force[1]=_force[2]=0;
|
||||
_towEndForce[0]=_towEndForce[1]=_towEndForce[2]=0;
|
||||
_reportTowEndForce[0]=_reportTowEndForce[1]=_reportTowEndForce[2]=0;
|
||||
return;
|
||||
}
|
||||
Math::mul3(_forceMagnitude,deltaN,_force);
|
||||
Math::mul3(-1.,_force,_towEndForce);
|
||||
_winchActualForce=_forceMagnitude; //missing: gravity on this end and friction
|
||||
//Add the gravitiy of the rope.
|
||||
//calculate some numbers:
|
||||
float grav_force=_towWeightPerM*_towLength*9.81;
|
||||
//the length of the gravity-expanded row:
|
||||
float leng=_towLength+grav_force*_towLength/_towElasticConstant;
|
||||
// The ground plane transformed to the local frame.
|
||||
float ground[4];
|
||||
s->planeGlobalToLocal(_global_ground, ground);
|
||||
|
||||
// The velocity of the contact patch transformed to local coordinates.
|
||||
//float glvel[3];
|
||||
//s->velGlobalToLocal(_global_vel, glvel);
|
||||
|
||||
_height_above_ground = ground[3] - Math::dot3(_pos, ground);
|
||||
|
||||
//the same for the winch-pos (the pos of the tow end)
|
||||
_winch_height_above_ground = ground[3] - Math::dot3(lWinchPos, ground);
|
||||
|
||||
//the frac of the grav force acting on _pos:
|
||||
float grav_frac=0.5*(1+(_height_above_ground-_winch_height_above_ground)/leng);
|
||||
grav_frac=Math::clamp(grav_frac,0,1);
|
||||
float grav_frac_tow_end=1-grav_frac;
|
||||
//reduce grav_frac, if the tow has ground contact.
|
||||
if (_height_above_ground<leng) //if not, the tow can not be on ground
|
||||
{
|
||||
float fa[3],fb[3],fg[3];
|
||||
//the grav force an the hitch position:
|
||||
Math::mul3(-grav_frac*grav_force,ground,fg);
|
||||
//the total force on hitch postion:
|
||||
Math::add3(fg,_force,fa);
|
||||
//the grav force an the tow end position:
|
||||
Math::mul3(-(1-grav_frac)*grav_force,ground,fg);
|
||||
//the total force on tow end postion:
|
||||
//note: sub: _force on tow-end is negative of force on hitch postion
|
||||
Math::sub3(fg,_force,fb);
|
||||
float fa_=Math::mag3(fa);
|
||||
float fb_=Math::mag3(fb);
|
||||
float stretchedTowLen;
|
||||
stretchedTowLen=_towLength*(1.+(fa_+fb_)/(2*_towElasticConstant));
|
||||
//the relative position of the lowest postion of the tow:
|
||||
if ((fa_+fb_)>1e-3)
|
||||
_loPosFrac=fa_/(fa_+fb_);
|
||||
else
|
||||
_loPosFrac=0.5;
|
||||
//dist to tow-end parallel to ground
|
||||
float ground_dist;
|
||||
float help[3];
|
||||
//Math::cross3(delta,ground,help);//as long as we calculate the dist without _pos, od it with lWinchpos, the dist to our center....
|
||||
Math::cross3(lWinchPos,ground,help);
|
||||
ground_dist=Math::mag3(help);
|
||||
//height of lowest tow pos (relative to _pos)
|
||||
_lowest_tow_height=_loPosFrac*Math::sqrt(Math::abs(stretchedTowLen*stretchedTowLen-ground_dist*ground_dist));
|
||||
if (_height_above_ground<_lowest_tow_height)
|
||||
{
|
||||
if (_height_above_ground>1e-3)
|
||||
grav_frac*=_height_above_ground/_lowest_tow_height;
|
||||
else
|
||||
grav_frac=0;
|
||||
}
|
||||
if (_winch_height_above_ground<(_lowest_tow_height-_height_above_ground+_winch_height_above_ground))
|
||||
{
|
||||
if (_winch_height_above_ground>1e-3)
|
||||
grav_frac_tow_end*=_winch_height_above_ground/
|
||||
(_lowest_tow_height-_height_above_ground+_winch_height_above_ground);
|
||||
else
|
||||
grav_frac_tow_end=0;
|
||||
}
|
||||
}
|
||||
else _lowest_tow_height=_loPosFrac=-1; //for debug output
|
||||
float grav_force_v[3];
|
||||
Math::mul3(grav_frac*grav_force,ground,grav_force_v);
|
||||
Math::add3(grav_force_v,_force,_force);
|
||||
_forceMagnitude=Math::mag3(_force);
|
||||
//the same for the tow end:
|
||||
Math::mul3(grav_frac_tow_end*grav_force,ground,grav_force_v);
|
||||
Math::add3(grav_force_v,_towEndForce,_towEndForce);
|
||||
s->velLocalToGlobal(_towEndForce,_towEndForce);
|
||||
|
||||
if(_forceMagnitude>=_towBrakeForce)
|
||||
{
|
||||
_forceMagnitude=0;
|
||||
_open=true;
|
||||
char text[128];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->setBoolValue("broken",true);
|
||||
_force[0]=_force[1]=_force[2]=0;
|
||||
_towEndForce[0]=_towEndForce[1]=_towEndForce[2]=0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Computed values: total force
|
||||
void Hitch::getForce(float* force, float* off)
|
||||
{
|
||||
Math::set3(_force, force);
|
||||
Math::set3(_pos, off);
|
||||
}
|
||||
|
||||
void Hitch::integrate (float dt)
|
||||
{
|
||||
//check if hitch has opened or closed, if yes: message
|
||||
if (_open !=_oldOpen)
|
||||
{
|
||||
if (_oldOpen)
|
||||
{
|
||||
if (_dist>_towLength*1.00001)
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,"Could not lock Hinch (tow length is insufficient) on hitch '"<<_name<<"' !"<<endl);
|
||||
_open=true;
|
||||
return;
|
||||
}
|
||||
char text[512];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->setBoolValue("broken",false);
|
||||
}
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,(_open?"Opened hitch (or broken tow) '":"Locked hitch '")<<_name<<"' !"<<endl);
|
||||
_oldOpen=_open;
|
||||
}
|
||||
|
||||
//check, if tow end should be searched in all MP-aircrafts
|
||||
if(_open && _mpAutoConnectPeriod)
|
||||
{
|
||||
_isSlave=false;
|
||||
_timeToNextAutoConnectTry-=dt;
|
||||
if ((_timeToNextAutoConnectTry>_mpAutoConnectPeriod) || (_timeToNextAutoConnectTry<0))
|
||||
{
|
||||
_timeToNextAutoConnectTry=_mpAutoConnectPeriod;
|
||||
//search for MP-Aircraft, which is towed with us
|
||||
findBestAIObject(true,true);
|
||||
}
|
||||
}
|
||||
//check, if tow end can be modified by property, if yes: update
|
||||
if(_towEndIsConnectedToProperty)
|
||||
{
|
||||
char text[128];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
if (node)
|
||||
{
|
||||
//_towEndNode=fgGetNode(node->getStringValue("tow/Node"), false);
|
||||
char towNode[256];
|
||||
strncpy(towNode,node->getStringValue("tow/Node"),256);
|
||||
towNode[255]=0;
|
||||
_towEndNode=fgGetNode("ai/models")->getNode(towNode, false);
|
||||
//AI and multiplayer objects seem to change node?
|
||||
//Check if we have the right one by callsign
|
||||
if (_nodeIsMultiplayer || _nodeIsAiAircraft)
|
||||
{
|
||||
char MPcallsign[256]="";
|
||||
const char *MPc;
|
||||
MPc=node->getStringValue("tow/connectedToAIorMP-callsign");
|
||||
if (MPc)
|
||||
{
|
||||
strncpy(MPcallsign,MPc,256);
|
||||
MPcallsign[255]=0;
|
||||
}
|
||||
if (((_towEndNode)&&(strncmp(_towEndNode->getStringValue("callsign"),MPcallsign,255)!=0))||!_towEndNode)
|
||||
{
|
||||
_timeToNextReConnectTry-=dt;
|
||||
if((_timeToNextReConnectTry<0)||(_timeToNextReConnectTry>10))
|
||||
{
|
||||
_timeToNextReConnectTry=10;
|
||||
SGPropertyNode * ainode = fgGetNode("/ai/models",false);
|
||||
if(ainode)
|
||||
{
|
||||
for (int i=0;i<ainode->nChildren();i++)
|
||||
{
|
||||
SGPropertyNode * n=ainode->getChild(i);
|
||||
if(_nodeIsMultiplayer?strncmp("multiplayer",n->getName(),11)==0:strncmp("aircraft",n->getName(),8))
|
||||
if (strcmp(n->getStringValue("callsign"),MPcallsign)==0)//found
|
||||
{
|
||||
_towEndNode=n;
|
||||
//node->setStringValue("tow/Node",n->getPath());
|
||||
node->setStringValue("tow/Node",n->getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(_towEndNode)
|
||||
{
|
||||
_winchPos[0]=_towEndNode->getDoubleValue("position/global-x",_winchPos[0]);
|
||||
_winchPos[1]=_towEndNode->getDoubleValue("position/global-y",_winchPos[1]);
|
||||
_winchPos[2]=_towEndNode->getDoubleValue("position/global-z",_winchPos[2]);
|
||||
_mp_lpos[0]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-x",0);
|
||||
_mp_lpos[1]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-y",0);
|
||||
_mp_lpos[2]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-z",0);
|
||||
_mp_dist=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/dist");
|
||||
_mp_v=_towEndNode->getFloatValue("sim/hitches/aerotow/speed-in-tow-direction");
|
||||
_mp_force[0]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-x",0);
|
||||
_mp_force[1]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-y",0);
|
||||
_mp_force[2]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-z",0);
|
||||
|
||||
if(_isSlave)
|
||||
{
|
||||
#define gf(a,b) a=_towEndNode->getFloatValue(b,a)
|
||||
#define gb(a,b) a=_towEndNode->getBoolValue(b,a)
|
||||
gf(_towLength,"sim/hitches/aerotow/tow/length");
|
||||
gf(_towElasticConstant,"sim/hitches/aerotow/tow/elastic-constant");
|
||||
gf(_towWeightPerM,"sim/hitches/aerotow/tow/weight-per-m-kg-m");
|
||||
gf(_towBrakeForce,"sim/hitches/aerotow/brake-force");
|
||||
gb(_open,"sim/hitches/aerotow/open");
|
||||
gb(_mp_is_slave,"sim/hitches/aerotow/is-slave");
|
||||
#undef gf
|
||||
#undef gb
|
||||
if (_mp_is_slave) _isSlave=false; //someone should be master
|
||||
}
|
||||
else
|
||||
{
|
||||
//check if other has opened hitch, but is neccessary, that it was closed before
|
||||
bool mp_open=_towEndNode->getBoolValue("sim/hitches/aerotow/open",_mp_open_last_state);
|
||||
if (mp_open != _mp_open_last_state) //state has changed
|
||||
{
|
||||
_mp_open_last_state=mp_open; //store that value
|
||||
if(!_open)
|
||||
{
|
||||
if(mp_open)
|
||||
{
|
||||
_open=true;
|
||||
char text[512];
|
||||
sprintf(text,"/sim/hitches/%s", _name);
|
||||
SGPropertyNode * node = fgGetNode(text, true);
|
||||
node->getStringValue("tow/Node","");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,"'"<<node->getStringValue("tow/Node","")<<"' has opened hitch!"<<endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//try to calculate the time lag
|
||||
if ((_mp_last_reported_dist!=_mp_dist)||(_mp_last_reported_v!=_mp_v)) //new data;
|
||||
{
|
||||
_mp_last_reported_dist=_mp_dist;
|
||||
_mp_last_reported_v=_mp_v;
|
||||
float total_v=-_mp_v+_speed_in_tow_direction;//mp has opposite tow direction
|
||||
float abs_v=Math::abs(total_v);
|
||||
if (abs_v>0.1)
|
||||
{
|
||||
float actual_time_lag_guess=(_mp_dist-_dist)/total_v;
|
||||
//check, if it sounds ok
|
||||
if((actual_time_lag_guess>0)&&(actual_time_lag_guess<5))
|
||||
{
|
||||
float frac=abs_v*0.01;
|
||||
if (frac>0.05) frac=0.05;
|
||||
// if we are slow, the guess of the lag can be rather wrong. as faster we are
|
||||
// the better the guess. Therefore frac is proportiona to the speed. Clamp it
|
||||
// at 5m/s
|
||||
_mp_time_lag=(1-frac)*_mp_time_lag+frac*actual_time_lag_guess;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//set the _reported_tow_end_force (smoothed)
|
||||
//smooth it a bit and store it
|
||||
float sc=10.*dt; //100ms
|
||||
float tmp[3];
|
||||
Math::mul3(sc,_towEndForce,tmp);
|
||||
Math::mul3(1.-sc,_reportTowEndForce,_reportTowEndForce);
|
||||
Math::add3(tmp,_reportTowEndForce,_reportTowEndForce);
|
||||
|
||||
if (_open) return;
|
||||
if (_winchRelSpeed==0) return;
|
||||
float factor=1,offset=0;
|
||||
if (_winchActualForce>_winchMaxForce)
|
||||
offset=-(_winchActualForce-_winchMaxForce)/_winchMaxForce*20;
|
||||
if (_winchRelSpeed>0.01) // to avoit div by zero
|
||||
{
|
||||
float maxForcePowerLimit=_winchPower/(_winchRelSpeed*_winchMaxSpeed);
|
||||
if (_winchActualForce>maxForcePowerLimit)
|
||||
factor-=(_winchActualForce-maxForcePowerLimit)/maxForcePowerLimit;
|
||||
}
|
||||
_towLength-=dt*(factor*_winchRelSpeed+offset)*_winchMaxSpeed;
|
||||
if (_towLength<=_winchMinTowLength)
|
||||
{
|
||||
if (_winchRelSpeed<0)
|
||||
_winchRelSpeed=0;
|
||||
_towLength=_winchMinTowLength;
|
||||
return;
|
||||
}
|
||||
if (_towLength>=_winchMaxTowLength)
|
||||
{
|
||||
if (_winchRelSpeed<0)
|
||||
_winchRelSpeed=0;
|
||||
_towLength=_winchMaxTowLength;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace yasim
|
112
src/FDM/YASim/Hitch.hpp
Executable file
112
src/FDM/YASim/Hitch.hpp
Executable file
|
@ -0,0 +1,112 @@
|
|||
#ifndef _HITCH_HPP
|
||||
#define _HITCH_HPP
|
||||
class SGPropertyNode;
|
||||
namespace yasim {
|
||||
|
||||
class Ground;
|
||||
class RigidBody;
|
||||
struct State;
|
||||
|
||||
class Hitch {
|
||||
public:
|
||||
Hitch(const char *name);
|
||||
~Hitch();
|
||||
|
||||
// Externally set values
|
||||
void setPosition(float* position);
|
||||
void setOpen(bool isOpen);
|
||||
//void setName(const char *text);
|
||||
|
||||
void setTowLength(float length);
|
||||
void setTowElasticConstant(float sc);
|
||||
void setTowBreakForce(float bf);
|
||||
void setTowWeightPerM(float rw);
|
||||
void setWinchMaxSpeed(float mws);
|
||||
void setWinchRelSpeed(float rws);
|
||||
void setWinchPosition(double *winchPosition); //in global coordinates!
|
||||
void setWinchPositionAuto(bool doit);
|
||||
void findBestAIObject(bool doit,bool running_as_autoconnect=false);
|
||||
void setWinchInitialTowLength(float length);
|
||||
void setWinchPower(float power);
|
||||
void setWinchMaxForce(float force);
|
||||
void setWinchMaxTowLength(float length);
|
||||
void setWinchMinTowLength(float length);
|
||||
void setMpAutoConnectPeriod(float dt);
|
||||
void setForceIsCalculatedByOther(bool b);
|
||||
|
||||
void setGlobalGround(double *global_ground, float *global_vel);
|
||||
|
||||
void getPosition(float* out);
|
||||
float getTowLength(void);
|
||||
|
||||
void calcForce(Ground *g_cb, RigidBody* body, State* s);
|
||||
|
||||
// Computed values: total force
|
||||
void getForce(float* force, float* off);
|
||||
|
||||
void integrate (float dt);
|
||||
|
||||
const char *getConnectedPropertyNode() const;
|
||||
void setConnectedPropertyNode(const char *nodename);
|
||||
|
||||
private:
|
||||
float _pos[3];
|
||||
bool _open;
|
||||
bool _oldOpen;
|
||||
float _towLength;
|
||||
float _towElasticConstant;
|
||||
float _towBrakeForce;
|
||||
float _towWeightPerM;
|
||||
float _winchMaxSpeed;
|
||||
float _winchRelSpeed;
|
||||
float _winchInitialTowLength;
|
||||
float _winchMaxTowLength;
|
||||
float _winchMinTowLength;
|
||||
float _winchPower;
|
||||
float _winchMaxForce;
|
||||
float _winchActualForce;
|
||||
double _winchPos[3];
|
||||
float _force[3];
|
||||
float _towEndForce[3];
|
||||
float _reportTowEndForce[3];
|
||||
float _forceMagnitude;
|
||||
double _global_ground[4];
|
||||
float _global_vel[3];
|
||||
char _name[256];
|
||||
State* _state;
|
||||
float _dist;
|
||||
float _timeLagCorrectedDist;
|
||||
SGPropertyNode *_towEndNode;
|
||||
const char *_towEndPropertyName;
|
||||
bool _towEndIsConnectedToProperty;
|
||||
bool _nodeIsMultiplayer;
|
||||
bool _nodeIsAiAircraft;
|
||||
bool _forceIsCalculatedByMaster;
|
||||
int _nodeID;
|
||||
//const char *_ai_MP_callsign;
|
||||
bool _isSlave;
|
||||
float _mpAutoConnectPeriod;
|
||||
float _timeToNextAutoConnectTry;
|
||||
float _timeToNextReConnectTry;
|
||||
float _height_above_ground;
|
||||
float _winch_height_above_ground;
|
||||
float _loPosFrac;
|
||||
float _lowest_tow_height;
|
||||
float _speed_in_tow_direction;
|
||||
float _mp_time_lag;
|
||||
float _mp_last_reported_dist;
|
||||
float _mp_last_reported_v;
|
||||
float _mp_v;
|
||||
float _mp_dist;
|
||||
float _mp_lpos[3];
|
||||
float _mp_force[3];
|
||||
bool _mp_is_slave;
|
||||
bool _mp_open_last_state;
|
||||
|
||||
bool _displayed_len_lower_dist_message;
|
||||
bool _last_wish;
|
||||
|
||||
};
|
||||
|
||||
}; // namespace yasim
|
||||
#endif // _HITCH_HPP
|
|
@ -15,6 +15,7 @@ SHARED_SOURCE_FILES = \
|
|||
Gear.cpp Gear.hpp \
|
||||
Glue.cpp Glue.hpp \
|
||||
Ground.cpp Ground.hpp \
|
||||
Hitch.cpp Hitch.hpp \
|
||||
Hook.cpp Hook.hpp \
|
||||
Launchbar.cpp Launchbar.hpp \
|
||||
Integrator.cpp Integrator.hpp \
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "Surface.hpp"
|
||||
#include "Rotor.hpp"
|
||||
#include "Rotorpart.hpp"
|
||||
#include "Hitch.hpp"
|
||||
#include "Glue.hpp"
|
||||
#include "Ground.hpp"
|
||||
|
||||
|
@ -75,6 +76,9 @@ Model::~Model()
|
|||
delete _ground_cb;
|
||||
delete _hook;
|
||||
delete _launchbar;
|
||||
for(int i=0; i<_hitches.size();i++)
|
||||
delete (Hitch*)_hitches.get(i);
|
||||
|
||||
}
|
||||
|
||||
void Model::getThrust(float* out)
|
||||
|
@ -127,6 +131,11 @@ void Model::initIteration()
|
|||
_turb->offset(toff);
|
||||
}
|
||||
|
||||
for(i=0; i<_hitches.size(); i++) {
|
||||
Hitch* h = (Hitch*)_hitches.get(i);
|
||||
h->integrate(_integrator.getInterval());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -252,6 +261,11 @@ void Model::addLaunchbar(Launchbar* launchbar)
|
|||
_launchbar = launchbar;
|
||||
}
|
||||
|
||||
int Model::addHitch(Hitch* hitch)
|
||||
{
|
||||
return _hitches.add(hitch);
|
||||
}
|
||||
|
||||
void Model::setGroundCallback(Ground* ground_cb)
|
||||
{
|
||||
delete _ground_cb;
|
||||
|
@ -307,9 +321,34 @@ void Model::updateGround(State* s)
|
|||
// Ask for the ground plane in the global coordinate system
|
||||
double global_ground[4];
|
||||
float global_vel[3];
|
||||
_ground_cb->getGroundPlane(pt, global_ground, global_vel);
|
||||
g->setGlobalGround(global_ground, global_vel);
|
||||
int type;
|
||||
const SGMaterial* material;
|
||||
_ground_cb->getGroundPlane(pt, global_ground, global_vel,
|
||||
&type,&material);
|
||||
static int h=0;
|
||||
g->setGlobalGround(global_ground, global_vel, pt[0], pt[1],
|
||||
type,material);
|
||||
}
|
||||
|
||||
for(i=0; i<_hitches.size(); i++) {
|
||||
Hitch* h = (Hitch*)_hitches.get(i);
|
||||
|
||||
// Get the point of interest
|
||||
float pos[3];
|
||||
h->getPosition(pos);
|
||||
|
||||
// Transform the local coordinates of the contact point to
|
||||
// global coordinates.
|
||||
double pt[3];
|
||||
s->posLocalToGlobal(pos, pt);
|
||||
|
||||
// Ask for the ground plane in the global coordinate system
|
||||
double global_ground[4];
|
||||
float global_vel[3];
|
||||
_ground_cb->getGroundPlane(pt, global_ground, global_vel);
|
||||
h->setGlobalGround(global_ground, global_vel);
|
||||
}
|
||||
|
||||
for(i=0; i<_rotorgear.getRotors()->size(); i++) {
|
||||
Rotor* r = (Rotor*)_rotorgear.getRotors()->get(i);
|
||||
r->findGroundEffectAltitude(_ground_cb,s);
|
||||
|
@ -468,8 +507,16 @@ void Model::calcForces(State* s)
|
|||
_body.addForce(contactlb, forcelb);
|
||||
_body.addForce(contacthb, forcehb);
|
||||
}
|
||||
}
|
||||
|
||||
// The hitches
|
||||
for(i=0; i<_hitches.size(); i++) {
|
||||
float force[3], contact[3];
|
||||
Hitch* h = (Hitch*)_hitches.get(i);
|
||||
h->calcForce(_ground_cb,&_body, s);
|
||||
h->getForce(force, contact);
|
||||
_body.addForce(contact, force);
|
||||
}
|
||||
}
|
||||
void Model::newState(State* s)
|
||||
{
|
||||
_s = s;
|
||||
|
@ -480,23 +527,26 @@ void Model::newState(State* s)
|
|||
for(i=0; i<_gears.size(); i++) {
|
||||
Gear* g = (Gear*)_gears.get(i);
|
||||
|
||||
// Get the point of ground contact
|
||||
float pos[3], cmpr[3];
|
||||
g->getPosition(pos);
|
||||
g->getCompression(cmpr);
|
||||
Math::mul3(g->getCompressFraction(), cmpr, cmpr);
|
||||
Math::add3(cmpr, pos, pos);
|
||||
if (!g->getSubmergable())
|
||||
{
|
||||
// Get the point of ground contact
|
||||
float pos[3], cmpr[3];
|
||||
g->getPosition(pos);
|
||||
g->getCompression(cmpr);
|
||||
Math::mul3(g->getCompressFraction(), cmpr, cmpr);
|
||||
Math::add3(cmpr, pos, pos);
|
||||
|
||||
// The plane transformed to local coordinates.
|
||||
double global_ground[4];
|
||||
g->getGlobalGround(global_ground);
|
||||
float ground[4];
|
||||
s->planeGlobalToLocal(global_ground, ground);
|
||||
float dist = ground[3] - Math::dot3(pos, ground);
|
||||
// The plane transformed to local coordinates.
|
||||
double global_ground[4];
|
||||
g->getGlobalGround(global_ground);
|
||||
float ground[4];
|
||||
s->planeGlobalToLocal(global_ground, ground);
|
||||
float dist = ground[3] - Math::dot3(pos, ground);
|
||||
|
||||
// Find the lowest one
|
||||
if(dist < min)
|
||||
min = dist;
|
||||
// Find the lowest one
|
||||
if(dist < min)
|
||||
min = dist;
|
||||
}
|
||||
}
|
||||
_agl = min;
|
||||
if(_agl < -1) // Allow for some integration slop
|
||||
|
|
|
@ -19,6 +19,7 @@ class Gear;
|
|||
class Ground;
|
||||
class Hook;
|
||||
class Launchbar;
|
||||
class Hitch;
|
||||
|
||||
class Model : public BodyEnvironment {
|
||||
public:
|
||||
|
@ -49,6 +50,7 @@ public:
|
|||
Rotorgear* getRotorgear(void);
|
||||
Gear* getGear(int handle);
|
||||
Hook* getHook(void);
|
||||
int addHitch(Hitch* hitch);
|
||||
Launchbar* getLaunchbar(void);
|
||||
|
||||
// Semi-private methods for use by the Airplane solver.
|
||||
|
@ -92,6 +94,7 @@ private:
|
|||
Vector _gears;
|
||||
Hook* _hook;
|
||||
Launchbar* _launchbar;
|
||||
Vector _hitches;
|
||||
|
||||
float _groundEffectSpan;
|
||||
float _groundEffect;
|
||||
|
|
|
@ -477,6 +477,7 @@ void YASim::copyFromYASim()
|
|||
node->setFloatValue("compression-m", g->getCompressDist());
|
||||
node->setFloatValue("caster-angle-deg", g->getCasterAngle() * RAD2DEG);
|
||||
node->setFloatValue("rollspeed-ms", g->getRollSpeed());
|
||||
node->setBoolValue("ground-is-solid", g->getGroundIsSolid()!=0);
|
||||
}
|
||||
|
||||
Hook* h = airplane->getHook();
|
||||
|
|
|
@ -46,7 +46,7 @@ void yasim_graph(Airplane* a, float alt, float kts)
|
|||
|
||||
for(int deg=-179; deg<=179; deg++) {
|
||||
float aoa = deg * DEG2RAD;
|
||||
Airplane::setupState(aoa, kts * KTS2MPS, &s);
|
||||
Airplane::setupState(aoa, kts * KTS2MPS, 0 ,&s);
|
||||
m->getBody()->reset();
|
||||
m->initIteration();
|
||||
m->calcForces(&s);
|
||||
|
|
Loading…
Reference in a new issue