1
0
Fork 0

Attempt to handle NaNs more elegantly

Check for NaNs after each FDM iteration, and freeze the sim if found.
Report this condition to the user and to the reporting backend, along
with the last valid position.

Probably needs some refinement, this is just a first guess.

Sentry-Id: FLIGHTGEAR-AM
This commit is contained in:
James Turner 2020-12-18 13:58:33 +00:00
parent 4f7d84ed73
commit 0e545d711c
4 changed files with 62 additions and 6 deletions

View file

@ -173,7 +173,7 @@ if(ENABLE_LARCSIM)
endforeach() endforeach()
endif() endif()
flightgear_component(FDM "${SOURCES}") flightgear_component(FDM "${SOURCES}" "${HEADERS}")
if(ENABLE_YASIM) if(ENABLE_YASIM)
add_subdirectory(YASim) add_subdirectory(YASim)

View file

@ -63,11 +63,12 @@
#include <FDM/YASim/YASim.hxx> #include <FDM/YASim/YASim.hxx>
#endif #endif
#include <GUI/MessageBox.hxx>
#include <Main/sentryIntegration.hxx>
using std::string; using std::string;
FDMShell::FDMShell() : FDMShell::FDMShell() : _tankProperties(fgGetNode("/consumables/fuel", true))
_tankProperties( fgGetNode("/consumables/fuel", true) ),
_dataLogging(false)
{ {
} }
@ -94,6 +95,10 @@ void FDMShell::init()
_max_radius_nm = _props->getNode("fdm/ai-wake/max-radius-nm", true); _max_radius_nm = _props->getNode("fdm/ai-wake/max-radius-nm", true);
_ai_wake_enabled = _props->getNode("fdm/ai-wake/enabled", true); _ai_wake_enabled = _props->getNode("fdm/ai-wake/enabled", true);
_nanCheckFailed = false;
fgSetBool("/sim/fdm-nan-failure", false);
_lastValidPos = SGGeod::invalid();
createImplementation(); createImplementation();
} }
@ -171,6 +176,10 @@ void FDMShell::update(double dt)
return; return;
} }
if (_nanCheckFailed) {
return;
}
if (!_impl->get_inited()) { if (!_impl->get_inited()) {
// Check for scenery around the aircraft. // Check for scenery around the aircraft.
double lon = fgGetDouble("/sim/presets/longitude-deg"); double lon = fgGetDouble("/sim/presets/longitude-deg");
@ -263,6 +272,8 @@ void FDMShell::update(double dt)
// replay is active // replay is active
break; break;
} }
validateOutputProperties();
} }
FGInterface* FDMShell::getInterface() const FGInterface* FDMShell::getInterface() const
@ -390,6 +401,36 @@ void FDMShell::createImplementation()
} }
} }
void FDMShell::validateOutputProperties()
{
if (_nanCheckFailed)
return;
const auto p = globals->get_aircraft_position();
if (SGMisc<double>::isNaN(p.getLatitudeDeg()) ||
SGMisc<double>::isNaN(p.getLongitudeDeg()) ||
SGMisc<double>::isNaN(p.getElevationFt())) {
SG_LOG(SG_FLIGHT, SG_ALERT, "FDM position became invalid. Last valid position was:" << _lastValidPos);
_nanCheckFailed = true;
} else {
_lastValidPos = p;
}
if (SGMisc<double>::isNaN(_impl->get_V_true_kts())) {
SG_LOG(SG_FLIGHT, SG_ALERT, "FDM velocity became invalid");
_nanCheckFailed = true;
}
if (_nanCheckFailed) {
flightgear::sentryReportException("FDM NaN check failed");
flightgear::modalMessageBox("Flight dynamics error",
"The flight dynamics model (FDM) has become invalid. The simulation will be stopped, so you can restart at a new location.");
fgSetBool("/sim/fdm-nan-failure", true);
fgSetBool("/sim/freeze/master", true);
fgSetBool("/sim/freeze/clock", true);
}
}
// Register the subsystem. // Register the subsystem.
SGSubsystemMgr::Registrant<FDMShell> registrantFDMShell( SGSubsystemMgr::Registrant<FDMShell> registrantFDMShell(

View file

@ -23,7 +23,9 @@
#ifndef FG_FDM_SHELL_HXX #ifndef FG_FDM_SHELL_HXX
#define FG_FDM_SHELL_HXX #define FG_FDM_SHELL_HXX
#include <simgear/math/SGGeod.hxx>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include "TankProperties.hxx" #include "TankProperties.hxx"
// forward decls // forward decls
@ -61,10 +63,16 @@ public:
private: private:
void createImplementation(); void createImplementation();
void validateOutputProperties();
private:
TankPropertiesList _tankProperties; TankPropertiesList _tankProperties;
SGSharedPtr<FGInterface> _impl; SGSharedPtr<FGInterface> _impl;
SGPropertyNode_ptr _props; // root property tree for this FDM instance SGPropertyNode_ptr _props; // root property tree for this FDM instance
bool _dataLogging; bool _dataLogging = false;
bool _nanCheckFailed = false; ///< set when we detect NaN output from the impl
SGGeod _lastValidPos;
SGPropertyNode_ptr _wind_north, _wind_east,_wind_down; SGPropertyNode_ptr _wind_north, _wind_east,_wind_down;
SGPropertyNode_ptr _control_fdm_atmo,_temp_degc,_pressure_inhg; SGPropertyNode_ptr _control_fdm_atmo,_temp_degc,_pressure_inhg;

View file

@ -68,6 +68,9 @@ auto XML_messageWhitelist = {
"syntax error (from 'SimGear XML Parser')" "syntax error (from 'SimGear XML Parser')"
}; };
auto exception_messageWhitelist = {
"position is invalid, NaNs"};
// we don't want sentry enabled for the test suite // we don't want sentry enabled for the test suite
#if defined(HAVE_SENTRY) && !defined(BUILDING_TESTSUITE) #if defined(HAVE_SENTRY) && !defined(BUILDING_TESTSUITE)
@ -94,6 +97,10 @@ void sentryTraceSimgearThrow(const std::string& msg, const std::string& origin,
return; return;
} }
if (doesStringMatchPrefixes(msg, exception_messageWhitelist)) {
return;
}
sentry_value_t exc = sentry_value_new_object(); sentry_value_t exc = sentry_value_new_object();
sentry_value_set_by_key(exc, "type", sentry_value_new_string("Exception")); sentry_value_set_by_key(exc, "type", sentry_value_new_string("Exception"));