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:
parent
4f7d84ed73
commit
0e545d711c
4 changed files with 62 additions and 6 deletions
|
@ -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)
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue