|
From: <ric...@gm...> - 2014-04-24 00:05:20
|
On 21 Apr 2014, at 18:51, Renk Thorsten <tho...@jy...> wrote:
> The big question is why YaSim doesn't run into the same problems - I understand it may not default to zero if it can't get terrain, but it seems to be doing just fine with a correct reading. So it's not just the scenery having a discontinuity, there must be something specific for JSBSim.
Get a coffee, it's a long one ...
The common function that both YASim and JSBSim call to get altitude AGL is the FGGroundCache::get_agl function in flightgear/src/FDM/groundcache.cxx. I don't understand what it does, but it does return a variable called "found_ground", which is a strong hint.
This is called by a pair of functions in flightgear/src/FDM/flight.cxx, namely FGInterface::get_agl_m and FGInterface::get_agl_ft. If you look at these, you'll see that they do exactly the same thing, but with a scaling factor applied for metres vs feet. (We can consider them equivalent).
YASim calls the get_agl_m function (flightgear/src/FDM/YASim/FGGround.cpp):
###
void FGGround::getGroundPlane(const double pos[3],
double plane[4], float vel[3],
const simgear::BVHMaterial **material)
{
// Return values for the callback.
double cp[3], dvel[3], dangvel[3];
simgear::BVHNode::Id id;
_iface->get_agl_m(_toff, pos, 2, cp, plane, dvel, dangvel, *material, id);
// 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];
}
###
Whereas JSBSim calls the get_agl_ft function (flightgear/src/FDM/JSBSim/JSBSim.cxx):
###
bool
FGJSBsim::get_agl_ft(double t, const double pt[3], double alt_off,
double contact[3], double normal[3], double vel[3],
double angularVel[3], double *agl)
{
const simgear::BVHMaterial* 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));
static SGPropertyNode_ptr terrain = fgGetNode("/sim/fdm/surface", true);
#ifdef JSBSIM_USE_GROUNDREACTIONS
bool terrain_active = (terrain->getIntValue("override-level", -1) > 0) ? false : true;
terrain->setBoolValue("active", terrain_active);
terrain->setBoolValue("valid", (material && terrain_active) ? true : false);
if (terrain_active)
{
static bool material_valid = false;
if (material) {
GroundReactions->SetStaticFFactor((*material).get_friction_factor());
GroundReactions->SetRollingFFactor((*material).get_rolling_friction()/0.02);
// 1 Pascal = 0.00014503773800721815 lbs/in^2
double pressure = (*material).get_load_resistance(); // N/m^2 (or Pascal)
GroundReactions->SetMaximumForce(pressure*0.00014503773800721815);
GroundReactions->SetBumpiness((*material).get_bumpiness());
GroundReactions->SetSolid((*material).get_solid());
GroundReactions->SetPosition(pt);
material_valid = true;
} else {
if (material_valid) {
GroundReactions->resetValues();
material_valid = false;
}
}
}
#else
terrain->setBoolValue("valid", false);
#endif
return true;
}
###
The difference is that YASim doesn't test the return value, whereas JSBSim does. If "found_ground" is false, JSBSim just returns. But look at the comment in the function they are calling (FGGroundCache::get_agl) in the block where it returns the "found_ground" flag:
// Whenever we did not have a ground triangle for the requested point,
// take the ground level we found during the current cache build.
// This is as good as what we had before for agl.
So even though FGGroundCache::get_agl cannot find any ground, it would appear from the comment that it still tries to return something useful. YASim takes advantage of that by carrying on and doing it's thing. JSBSim gives up and doesn't use it, which results in a zero AGL because that's how it's initialized on line 107 in flightgear/src/FDM/JSBSim/JSBSim.cxx and that value remains unchanged because the FGJSBsim::get_agl_ft quits early.
That dirty fix I came up with works because the caller detects when JSBSim bails out in the function shown above and "fixes" that by plugging in a high value for altitude AGL. I didn't suspect that JSBSim had a perfectly good altitude AGL within its grasp but failed to use it. I would therefore suggest the solution is for JSBSim to just do what YASim does and use the best endeavours provided by FGGroundCache::get_agl.
So here is a patch for serious consideration. I've tested it with a couple of JSBSim aircraft and it flies over that discontinuity off the coast near EGFF with sensible altitude AGL throughout.
From c181c674542eab59fab43eaa9f7dfe3309964290 Mon Sep 17 00:00:00 2001
From: Richard Senior <ric...@gm...>
Date: Thu, 24 Apr 2014 00:31:27 +0100
Subject: [PATCH] JSBSim: Proposed fix for zero altitude AGL with scenery
discontinuities
---
src/FDM/JSBSim/JSBSim.cxx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx
index 91c4dd6..d2dcefc 100644
--- a/src/FDM/JSBSim/JSBSim.cxx
+++ b/src/FDM/JSBSim/JSBSim.cxx
@@ -1331,9 +1331,8 @@ FGJSBsim::get_agl_ft(double t, const double pt[3], double alt_off,
{
const simgear::BVHMaterial* material;
simgear::BVHNode::Id id;
- if (!FGInterface::get_agl_ft(t, pt, alt_off, contact, normal, vel,
- angularVel, material, id))
- return false;
+ FGInterface::get_agl_ft(t, pt, alt_off, contact, normal, vel,
+ angularVel, material, id);
SGGeod geodPt = SGGeod::fromCart(SG_FEET_TO_METER*SGVec3d(pt));
SGQuatd hlToEc = SGQuatd::fromLonLat(geodPt);
--
1.8.3.2
There are still white lines across the sea of course.
|