1
0
Fork 0

Make the GPS drive the autopilot directly (if configured), also update external course (OBS) source, and init at the current airport.

This commit is contained in:
jmt 2009-10-13 22:02:08 +00:00 committed by Tim Moore
parent 5aa51e5780
commit 879531ce63
3 changed files with 147 additions and 55 deletions

View file

@ -97,11 +97,12 @@ void FGRouteMgr::init() {
_apAltitudeLock = fgGetNode( "/autopilot/locks/altitude", true ); _apAltitudeLock = fgGetNode( "/autopilot/locks/altitude", true );
_apTrueHeading = fgGetNode( "/autopilot/settings/true-heading-deg", true ); _apTrueHeading = fgGetNode( "/autopilot/settings/true-heading-deg", true );
rm->tie("drive-autopilot", SGRawValuePointer<bool>(&_driveAutopilot)); rm->tie("drive-autopilot", SGRawValuePointer<bool>(&_driveAutopilot));
_driveAutopilot = false;
departure = fgGetNode(RM "departure", true); departure = fgGetNode(RM "departure", true);
// init departure information from current location // init departure information from current location
SGGeod pos = SGGeod::fromDegFt(lon->getDoubleValue(), lat->getDoubleValue(), alt->getDoubleValue()); SGGeod pos = SGGeod::fromDegFt(lon->getDoubleValue(), lat->getDoubleValue(), alt->getDoubleValue());
FGAirport* apt = FGAirport::findClosest(pos, 10.0); FGAirport* apt = FGAirport::findClosest(pos, 20.0);
if (apt) { if (apt) {
departure->setStringValue("airport", apt->ident().c_str()); departure->setStringValue("airport", apt->ident().c_str());
FGRunway* active = apt->getActiveRunwayForUsage(); FGRunway* active = apt->getActiveRunwayForUsage();

View file

@ -205,13 +205,14 @@ GPS::Config::Config() :
_turnRate(3.0), // degrees-per-second, so 180 degree turn takes 60 seconds _turnRate(3.0), // degrees-per-second, so 180 degree turn takes 60 seconds
_overflightArmDistance(0.5), _overflightArmDistance(0.5),
_waypointAlertTime(30.0), _waypointAlertTime(30.0),
_tuneRadio1ToRefVor(true), _tuneRadio1ToRefVor(false),
_minRunwayLengthFt(0.0), _minRunwayLengthFt(0.0),
_requireHardSurface(true), _requireHardSurface(true),
_cdiMaxDeflectionNm(-1) // default to angular mode _cdiMaxDeflectionNm(-1), // default to angular mode
_driveAutopilot(true)
{ {
_enableTurnAnticipation = false; _enableTurnAnticipation = false;
_obsCourseSource = fgGetNode("/instrumentation/nav[0]/radials/selected-deg", true); _extCourseSource = fgGetNode("/instrumentation/nav[0]/radials/selected-deg", true);
} }
void GPS::Config::init(SGPropertyNode* aCfgNode) void GPS::Config::init(SGPropertyNode* aCfgNode)
@ -223,44 +224,55 @@ void GPS::Config::init(SGPropertyNode* aCfgNode)
aCfgNode->tie("min-runway-length-ft", SGRawValuePointer<double>(&_minRunwayLengthFt)); aCfgNode->tie("min-runway-length-ft", SGRawValuePointer<double>(&_minRunwayLengthFt));
aCfgNode->tie("hard-surface-runways-only", SGRawValuePointer<bool>(&_requireHardSurface)); aCfgNode->tie("hard-surface-runways-only", SGRawValuePointer<bool>(&_requireHardSurface));
aCfgNode->tie("obs-course-source", SGRawValueMethods<GPS::Config, const char*> aCfgNode->tie("course-source", SGRawValueMethods<GPS::Config, const char*>
(*this, &GPS::Config::getOBSCourseSource, &GPS::Config::setOBSCourseSource)); (*this, &GPS::Config::getCourseSource, &GPS::Config::setCourseSource));
aCfgNode->tie("cdi-max-deflection-nm", SGRawValuePointer<double>(&_cdiMaxDeflectionNm)); aCfgNode->tie("cdi-max-deflection-nm", SGRawValuePointer<double>(&_cdiMaxDeflectionNm));
aCfgNode->tie("drive-autopilot", SGRawValuePointer<bool>(&_driveAutopilot));
} }
const char* const char*
GPS::Config::getOBSCourseSource() const GPS::Config::getCourseSource() const
{ {
if (!_obsCourseSource) { if (!_extCourseSource) {
return ""; return "";
} }
return _obsCourseSource->getPath(true); return _extCourseSource->getPath(true);
} }
void void
GPS::Config::setOBSCourseSource(const char* aPath) GPS::Config::setCourseSource(const char* aPath)
{ {
SGPropertyNode* nd = fgGetNode(aPath, false); SGPropertyNode* nd = fgGetNode(aPath, false);
if (!nd) { if (!nd) {
SG_LOG(SG_INSTR, SG_WARN, "couldn't find OBS course source at:" << aPath); SG_LOG(SG_INSTR, SG_WARN, "couldn't find course source at:" << aPath);
_obsCourseSource = NULL; _extCourseSource = NULL;
} }
_obsCourseSource = nd; _extCourseSource = nd;
} }
double double
GPS::Config::getOBSCourse() const GPS::Config::getExternalCourse() const
{ {
if (!_obsCourseSource) { if (!_extCourseSource) {
return 0.0; return 0.0;
} }
return _obsCourseSource->getDoubleValue(); return _extCourseSource->getDoubleValue();
} }
void
GPS::Config::setExternalCourse(double aCourseDeg)
{
if (!_extCourseSource) {
return;
}
_extCourseSource->setDoubleValue(aCourseDeg);
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
GPS::GPS ( SGPropertyNode *node) : GPS::GPS ( SGPropertyNode *node) :
@ -374,7 +386,9 @@ GPS::init ()
(*this, &GPS::getWP1CourseErrorNm, NULL)); (*this, &GPS::getWP1CourseErrorNm, NULL));
wp1_node->tie("to-flag", SGRawValueMethods<GPS, bool> wp1_node->tie("to-flag", SGRawValueMethods<GPS, bool>
(*this, &GPS::getWP1ToFlag, NULL)); (*this, &GPS::getWP1ToFlag, NULL));
wp1_node->tie("from-flag", SGRawValueMethods<GPS, bool>
(*this, &GPS::getWP1FromFlag, NULL));
_tracking_bug_node = node->getChild("tracking-bug", 0, true); _tracking_bug_node = node->getChild("tracking-bug", 0, true);
// leg properties (only valid in DTO/LEG modes, not OBS) // leg properties (only valid in DTO/LEG modes, not OBS)
@ -410,20 +424,38 @@ GPS::init ()
_route_current_wp_node->addChangeListener(_listener); _route_current_wp_node->addChangeListener(_listener);
_route_active_node = fgGetNode("/autopilot/route-manager/active", true); _route_active_node = fgGetNode("/autopilot/route-manager/active", true);
_route_active_node->addChangeListener(_listener); _route_active_node->addChangeListener(_listener);
_ref_navaid_id_node->addChangeListener(_listener); _ref_navaid_id_node->addChangeListener(_listener);
// navradio slaving properties // navradio slaving properties
node->tie("cdi-deflection", SGRawValueMethods<GPS,double> node->tie("cdi-deflection", SGRawValueMethods<GPS,double>
(*this, &GPS::getCDIDeflection)); (*this, &GPS::getCDIDeflection));
SGPropertyNode* toFlag = node->getChild("to-flag", 0, true); SGPropertyNode* toFlag = node->getChild("to-flag", 0, true);
toFlag->alias(wp1_node->getChild("to-flag")); toFlag->alias(wp1_node->getChild("to-flag"));
// autopilot drive properties
_apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
_apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
_apAltitudeLock = fgGetNode("/autopilot/locks/altitude", true);
_fromFlagNode = node->getChild("from-flag", 0, true); // realism prop[s]
_realismSimpleGps = fgGetNode("/sim/realism/simple-gps", true);
if (!_realismSimpleGps->hasValue()) {
_realismSimpleGps->setBoolValue(true);
}
// last thing, add the deprecated prop watcher // last thing, add the deprecated prop watcher
new DeprecatedPropListener(node); new DeprecatedPropListener(node);
// initialise in OBS mode, with waypt set to the nearest airport.
// keep in mind at this point, _last_valid is not set
auto_ptr<FGPositioned::Filter> f(createFilter(FGPositioned::AIRPORT));
FGPositionedRef apt = FGPositioned::findClosest(_position.get(), 20.0, f.get());
if (apt) {
setScratchFromPositioned(apt, 0);
selectOBSMode();
}
} }
void void
@ -436,7 +468,7 @@ GPS::clearOutput()
_last_vertical_speed = 0.0; _last_vertical_speed = 0.0;
_last_true_track = 0.0; _last_true_track = 0.0;
_raim_node->setDoubleValue(false); _raim_node->setDoubleValue(0.0);
_indicated_pos = SGGeod(); _indicated_pos = SGGeod();
_wp1DistanceM = 0.0; _wp1DistanceM = 0.0;
_wp1TrueBearing = 0.0; _wp1TrueBearing = 0.0;
@ -446,19 +478,19 @@ GPS::clearOutput()
_tracking_bug_node->setDoubleValue(0); _tracking_bug_node->setDoubleValue(0);
_true_bug_error_node->setDoubleValue(0); _true_bug_error_node->setDoubleValue(0);
_magnetic_bug_error_node->setDoubleValue(0); _magnetic_bug_error_node->setDoubleValue(0);
_fromFlagNode->setBoolValue(false);
} }
void void
GPS::update (double delta_time_sec) GPS::update (double delta_time_sec)
{ {
// If it's off, don't bother. if (!_realismSimpleGps->getBoolValue()) {
if (!_serviceable_node->getBoolValue() || !_electrical_node->getBoolValue()) { // If it's off, don't bother.
clearOutput(); if (!_serviceable_node->getBoolValue() || !_electrical_node->getBoolValue()) {
return; clearOutput();
return;
}
} }
if (delta_time_sec <= 0.0) { if (delta_time_sec <= 0.0) {
return; // paused, don't bother return; // paused, don't bother
} }
@ -504,7 +536,7 @@ GPS::update (double delta_time_sec)
printf("%f %f \n", error_length, error_angle); printf("%f %f \n", error_length, error_angle);
*/ */
_raim_node->setBoolValue(true); _raim_node->setDoubleValue(1.0);
_indicated_pos = _position.get(); _indicated_pos = _position.get();
if (_last_valid) { if (_last_valid) {
@ -512,14 +544,14 @@ GPS::update (double delta_time_sec)
} else { } else {
_last_valid = true; _last_valid = true;
if (_route_active_node->getBoolValue()) { if (_route_active_node->getBoolValue()) {
// GPS init with active route // GPS init with active route
SG_LOG(SG_INSTR, SG_INFO, "GPS init with active route"); SG_LOG(SG_INSTR, SG_INFO, "GPS init with active route");
_listener->setGuard(true); _listener->setGuard(true);
routeActivated(); routeActivated();
routeManagerSequenced(); routeManagerSequenced();
_listener->setGuard(false); _listener->setGuard(false);
} }
} }
_last_pos = _indicated_pos; _last_pos = _indicated_pos;
@ -533,7 +565,7 @@ GPS::updateWithValid(double dt)
updateBasicData(dt); updateBasicData(dt);
if (_mode == "obs") { if (_mode == "obs") {
_selectedCourse = _config.getOBSCourse(); _selectedCourse = _config.getExternalCourse();
} else { } else {
updateTurn(); updateTurn();
} }
@ -542,6 +574,7 @@ GPS::updateWithValid(double dt)
updateTrackingBug(); updateTrackingBug();
updateReferenceNavaid(dt); updateReferenceNavaid(dt);
updateRouteData(); updateRouteData();
driveAutopilot();
} }
void void
@ -584,8 +617,6 @@ GPS::updateWaypoints()
{ {
double az2; double az2;
SGGeodesy::inverse(_indicated_pos, _wp1_position, _wp1TrueBearing, az2,_wp1DistanceM); SGGeodesy::inverse(_indicated_pos, _wp1_position, _wp1TrueBearing, az2,_wp1DistanceM);
bool toWp = getWP1ToFlag();
_fromFlagNode->setBoolValue(!toWp);
} }
void GPS::updateReferenceNavaid(double dt) void GPS::updateReferenceNavaid(double dt)
@ -679,11 +710,10 @@ void GPS::routeActivated()
{ {
if (_route_active_node->getBoolValue()) { if (_route_active_node->getBoolValue()) {
SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, switching to LEG mode"); SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, switching to LEG mode");
_mode = "leg"; selectLegMode();
_computeTurnData = true;
} else if (_mode == "leg") { } else if (_mode == "leg") {
SG_LOG(SG_INSTR, SG_INFO, "GPS::route deactivated, switching to OBS mode"); SG_LOG(SG_INSTR, SG_INFO, "GPS::route deactivated, switching to OBS mode");
_mode = "obs"; selectOBSMode();
} }
} }
@ -714,6 +744,7 @@ void GPS::routeManagerSequenced()
_wp1_position = wp1.get_target(); _wp1_position = wp1.get_target();
_selectedCourse = getLegMagCourse(); _selectedCourse = getLegMagCourse();
wp1Changed();
} }
void GPS::updateTurn() void GPS::updateTurn()
@ -924,6 +955,35 @@ void GPS::updateRouteData()
} }
} }
void GPS::driveAutopilot()
{
if (!_config.driveAutopilot() || !_realismSimpleGps->getBoolValue()) {
return;
}
// FIXME: we want to set desired track, not heading, here
_apTrueHeading->setDoubleValue(getWP1Bearing());
}
void GPS::wp1Changed()
{
// update external HSI/CDI/NavDisplay/PFD/etc
_config.setExternalCourse(getLegMagCourse());
if (!_config.driveAutopilot()) {
return;
}
double altFt = _wp1_position.getElevationFt();
if (altFt < -9990.0) {
_apTargetAltitudeFt->setDoubleValue(0.0);
_apAltitudeLock->setBoolValue(false);
} else {
_apTargetAltitudeFt->setDoubleValue(altFt);
_apAltitudeLock->setBoolValue(true);
}
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// property getter/setters // property getter/setters
@ -1120,7 +1180,7 @@ double GPS::getWP1CourseErrorNm() const
bool GPS::getWP1ToFlag() const bool GPS::getWP1ToFlag() const
{ {
if (!_last_valid) { if (!_last_valid) {
return 0.0; return false;
} }
double dev = getWP1MagBearing() - _selectedCourse; double dev = getWP1MagBearing() - _selectedCourse;
@ -1129,6 +1189,15 @@ bool GPS::getWP1ToFlag() const
return (fabs(dev) < 90.0); return (fabs(dev) < 90.0);
} }
bool GPS::getWP1FromFlag() const
{
if (!_last_valid) {
return false;
}
return !getWP1ToFlag();
}
double GPS::getScratchDistance() const double GPS::getScratchDistance() const
{ {
if (!_scratchValid) { if (!_scratchValid) {
@ -1225,6 +1294,8 @@ void GPS::directTo()
_mode = "dto"; _mode = "dto";
_selectedCourse = getLegMagCourse(); _selectedCourse = getLegMagCourse();
clearScratch(); clearScratch();
wp1Changed();
} }
void GPS::loadRouteWaypoint() void GPS::loadRouteWaypoint()
@ -1494,6 +1565,7 @@ void GPS::selectOBSMode()
_wp1Name = _scratchNode->getStringValue("name"); _wp1Name = _scratchNode->getStringValue("name");
_wp1_position = _scratchPos; _wp1_position = _scratchPos;
_wp0_position = _indicated_pos; _wp0_position = _indicated_pos;
wp1Changed();
} }
void GPS::selectLegMode() void GPS::selectLegMode()

View file

@ -130,7 +130,9 @@ private:
double minRunwayLengthFt() const double minRunwayLengthFt() const
{ return _minRunwayLengthFt; } { return _minRunwayLengthFt; }
double getOBSCourse() const; double getExternalCourse() const;
void setExternalCourse(double aCourseDeg);
bool cdiDeflectionIsAngular() const bool cdiDeflectionIsAngular() const
{ return (_cdiMaxDeflectionNm <= 0.0); } { return (_cdiMaxDeflectionNm <= 0.0); }
@ -140,6 +142,9 @@ private:
assert(_cdiMaxDeflectionNm > 0.0); assert(_cdiMaxDeflectionNm > 0.0);
return _cdiMaxDeflectionNm; return _cdiMaxDeflectionNm;
} }
bool driveAutopilot() const
{ return _driveAutopilot; }
private: private:
bool _enableTurnAnticipation; bool _enableTurnAnticipation;
@ -162,14 +167,16 @@ private:
// should we require a hard-surfaced runway when filtering? // should we require a hard-surfaced runway when filtering?
bool _requireHardSurface; bool _requireHardSurface;
// helpers to tie obs-course-source property // helpers to tie course-source property
const char* getOBSCourseSource() const; const char* getCourseSource() const;
void setOBSCourseSource(const char* aPropPath); void setCourseSource(const char* aPropPath);
// property to retrieve the OBS course from // property to retrieve the external course from
SGPropertyNode_ptr _obsCourseSource; SGPropertyNode_ptr _extCourseSource;
double _cdiMaxDeflectionNm; double _cdiMaxDeflectionNm;
bool _driveAutopilot;
}; };
class SearchFilter : public FGPositioned::Filter class SearchFilter : public FGPositioned::Filter
@ -195,6 +202,7 @@ private:
void referenceNavaidSet(const std::string& aNavaid); void referenceNavaidSet(const std::string& aNavaid);
void tuneNavRadios(); void tuneNavRadios();
void updateRouteData(); void updateRouteData();
void driveAutopilot();
void routeActivated(); void routeActivated();
void routeManagerSequenced(); void routeManagerSequenced();
@ -208,8 +216,12 @@ private:
void computeTurnData(); void computeTurnData();
void updateTurnData(); void updateTurnData();
double computeTurnRadiusNm(double aGroundSpeedKts) const; double computeTurnRadiusNm(double aGroundSpeedKts) const;
/**
* Update one-shot things when WP1 / leg data change
*/
void wp1Changed();
// scratch maintenence utilities // scratch maintenence utilities
void setScratchFromPositioned(FGPositioned* aPos, int aIndex); void setScratchFromPositioned(FGPositioned* aPos, int aIndex);
void setScratchFromCachedSearchResult(); void setScratchFromCachedSearchResult();
@ -288,6 +300,8 @@ private:
double getWP1CourseDeviation() const; double getWP1CourseDeviation() const;
double getWP1CourseErrorNm() const; double getWP1CourseErrorNm() const;
bool getWP1ToFlag() const; bool getWP1ToFlag() const;
bool getWP1FromFlag() const;
// true-bearing-error and mag-bearing-error // true-bearing-error and mag-bearing-error
@ -315,9 +329,7 @@ private:
SGPropertyNode_ptr _route_current_wp_node; SGPropertyNode_ptr _route_current_wp_node;
SGPropertyNode_ptr _routeDistanceNm; SGPropertyNode_ptr _routeDistanceNm;
SGPropertyNode_ptr _routeETE; SGPropertyNode_ptr _routeETE;
SGPropertyNode_ptr _fromFlagNode;
double _selectedCourse; double _selectedCourse;
bool _last_valid; bool _last_valid;
@ -372,6 +384,13 @@ private:
double _turnRadius; // radius of turn in nm double _turnRadius; // radius of turn in nm
SGGeod _turnPt; SGGeod _turnPt;
SGGeod _turnCentre; SGGeod _turnCentre;
SGPropertyNode_ptr _realismSimpleGps; ///< should the GPS be simple or realistic?
// autopilot drive properties
SGPropertyNode_ptr _apTrueHeading;
SGPropertyNode_ptr _apTargetAltitudeFt;
SGPropertyNode_ptr _apAltitudeLock;
}; };