Further GPS and route manager behavioural fixes
* When the nav-radio is slaved, calculated radial/target-hdg-deg (needed by some autopilot logic) * Handle editing (including deletion) of route waypoints correctly, including deleting the active waypoint * Add a signal to the route manager when the last wpt is reached, and use it in the GPS to revert to OBS mode. * Change the altitude handling to use the specified cruise altitude * Fix a bug where autopilot/locks/altitude was treated as a boolean
This commit is contained in:
parent
a865555fed
commit
afb1e7ffe9
6 changed files with 111 additions and 65 deletions
src
|
@ -139,8 +139,11 @@ void FGRouteMgr::init() {
|
||||||
airborne = fgGetNode(RM "airborne", true);
|
airborne = fgGetNode(RM "airborne", true);
|
||||||
airborne->setBoolValue(false);
|
airborne->setBoolValue(false);
|
||||||
|
|
||||||
currentWp = fgGetNode(RM "current-wp", true);
|
_edited = fgGetNode(RM "signals/edited", true);
|
||||||
currentWp->setIntValue(_route->current_index());
|
_finished = fgGetNode(RM "signals/finished", true);
|
||||||
|
|
||||||
|
rm->tie("current-wp", SGRawValueMethods<FGRouteMgr, int>
|
||||||
|
(*this, &FGRouteMgr::currentWaypoint, &FGRouteMgr::jumpToIndex));
|
||||||
|
|
||||||
// temporary distance / eta calculations, for backward-compatability
|
// temporary distance / eta calculations, for backward-compatability
|
||||||
wp0 = fgGetNode(RM "wp", 0, true);
|
wp0 = fgGetNode(RM "wp", 0, true);
|
||||||
|
@ -277,23 +280,38 @@ void FGRouteMgr::setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDi
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGRouteMgr::add_waypoint( const SGWayPoint& wp, int n ) {
|
void FGRouteMgr::add_waypoint( const SGWayPoint& wp, int n ) {
|
||||||
_route->add_waypoint( wp, n );
|
_route->add_waypoint( wp, n );
|
||||||
update_mirror();
|
|
||||||
|
if (_route->current_index() > n) {
|
||||||
|
_route->set_current(_route->current_index() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_mirror();
|
||||||
|
_edited->fireValueChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SGWayPoint FGRouteMgr::pop_waypoint( int n ) {
|
SGWayPoint FGRouteMgr::pop_waypoint( int n ) {
|
||||||
SGWayPoint wp;
|
if ( _route->size() <= 0 ) {
|
||||||
|
return SGWayPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( n < 0 ) {
|
||||||
|
n = _route->size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_route->current_index() > n) {
|
||||||
|
_route->set_current(_route->current_index() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if ( _route->size() > 0 ) {
|
SGWayPoint wp = _route->get_waypoint(n);
|
||||||
if ( n < 0 )
|
_route->delete_waypoint(n);
|
||||||
n = _route->size() - 1;
|
|
||||||
wp = _route->get_waypoint(n);
|
update_mirror();
|
||||||
_route->delete_waypoint(n);
|
_edited->fireValueChanged();
|
||||||
}
|
checkFinished();
|
||||||
|
|
||||||
update_mirror();
|
return wp;
|
||||||
return wp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -310,10 +328,6 @@ void FGRouteMgr::new_waypoint( const string& target, int n ) {
|
||||||
|
|
||||||
add_waypoint( *wp, n );
|
add_waypoint( *wp, n );
|
||||||
delete wp;
|
delete wp;
|
||||||
|
|
||||||
if ( !near_ground() ) {
|
|
||||||
fgSetString( "/autopilot/locks/heading", "true-heading-hold" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -420,20 +434,6 @@ void FGRouteMgr::update_mirror() {
|
||||||
mirror->setIntValue("num", _route->size());
|
mirror->setIntValue("num", _route->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FGRouteMgr::near_ground() {
|
|
||||||
SGPropertyNode *gear = fgGetNode( "/gear/gear/wow", false );
|
|
||||||
if ( !gear || gear->getType() == simgear::props::NONE )
|
|
||||||
return fgGetBool( "/sim/presets/onground", true );
|
|
||||||
|
|
||||||
if ( fgGetDouble("/position/altitude-agl-ft", 300.0)
|
|
||||||
< fgGetDouble("/autopilot/route-manager/min-lock-altitude-agl-ft") )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return gear->getBoolValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// command interface /autopilot/route-manager/input:
|
// command interface /autopilot/route-manager/input:
|
||||||
//
|
//
|
||||||
// @CLEAR ... clear route
|
// @CLEAR ... clear route
|
||||||
|
@ -544,10 +544,7 @@ void FGRouteMgr::sequence()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_route->current_index() == _route->size()) {
|
if (checkFinished()) {
|
||||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
|
|
||||||
// what now?
|
|
||||||
active->setBoolValue(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +552,19 @@ void FGRouteMgr::sequence()
|
||||||
currentWaypointChanged();
|
currentWaypointChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FGRouteMgr::checkFinished()
|
||||||
|
{
|
||||||
|
int lastWayptIndex = _route->size() - 1;
|
||||||
|
if (_route->current_index() < lastWayptIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
|
||||||
|
_finished->fireValueChanged();
|
||||||
|
active->setBoolValue(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void FGRouteMgr::jumpToIndex(int index)
|
void FGRouteMgr::jumpToIndex(int index)
|
||||||
{
|
{
|
||||||
if (!active->getBoolValue()) {
|
if (!active->getBoolValue()) {
|
||||||
|
@ -588,7 +598,6 @@ void FGRouteMgr::currentWaypointChanged()
|
||||||
wp1->getChild("id")->setStringValue("");
|
wp1->getChild("id")->setStringValue("");
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWp->setIntValue(_route->current_index());
|
|
||||||
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _route->current_index());
|
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _route->current_index());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +715,7 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode_ptr altProp = aWP->getChild("altitude-ft");
|
SGPropertyNode_ptr altProp = aWP->getChild("altitude-ft");
|
||||||
double alt = -9999.0;
|
double alt = cruise->getDoubleValue("altitude-ft") * SG_FEET_TO_METER;
|
||||||
if (altProp) {
|
if (altProp) {
|
||||||
alt = altProp->getDoubleValue();
|
alt = altProp->getDoubleValue();
|
||||||
}
|
}
|
||||||
|
@ -714,10 +723,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
|
||||||
string ident(aWP->getStringValue("ident"));
|
string ident(aWP->getStringValue("ident"));
|
||||||
if (aWP->hasChild("longitude-deg")) {
|
if (aWP->hasChild("longitude-deg")) {
|
||||||
// explicit longitude/latitude
|
// explicit longitude/latitude
|
||||||
if (alt < -9990.0) {
|
|
||||||
alt = 0.0; // don't export wyapoints with invalid altitude
|
|
||||||
}
|
|
||||||
|
|
||||||
SGWayPoint swp(aWP->getDoubleValue("longitude-deg"),
|
SGWayPoint swp(aWP->getDoubleValue("longitude-deg"),
|
||||||
aWP->getDoubleValue("latitude-deg"), alt,
|
aWP->getDoubleValue("latitude-deg"), alt,
|
||||||
SGWayPoint::WGS84, ident, aWP->getStringValue("name"));
|
SGWayPoint::WGS84, ident, aWP->getStringValue("name"));
|
||||||
|
@ -740,10 +745,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
|
||||||
SGGeodesy::direct(p->geod(), radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
|
SGGeodesy::direct(p->geod(), radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alt < -9990.0) {
|
|
||||||
alt = p->elevation();
|
|
||||||
}
|
|
||||||
|
|
||||||
SGWayPoint swp(pos.getLongitudeDeg(), pos.getLatitudeDeg(), alt,
|
SGWayPoint swp(pos.getLongitudeDeg(), pos.getLatitudeDeg(), alt,
|
||||||
SGWayPoint::WGS84, ident, "");
|
SGWayPoint::WGS84, ident, "");
|
||||||
add_waypoint(swp);
|
add_waypoint(swp);
|
||||||
|
@ -754,10 +755,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
|
||||||
throw sg_io_exception("bad route file, unknown waypoint:" + ident);
|
throw sg_io_exception("bad route file, unknown waypoint:" + ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alt < -9990.0) {
|
|
||||||
alt = p->elevation();
|
|
||||||
}
|
|
||||||
|
|
||||||
SGWayPoint swp(p->longitude(), p->latitude(), alt,
|
SGWayPoint swp(p->longitude(), p->latitude(), alt,
|
||||||
SGWayPoint::WGS84, p->ident(), p->name());
|
SGWayPoint::WGS84, p->ident(), p->name());
|
||||||
add_waypoint(swp);
|
add_waypoint(swp);
|
||||||
|
|
|
@ -63,7 +63,6 @@ private:
|
||||||
|
|
||||||
SGPropertyNode_ptr active;
|
SGPropertyNode_ptr active;
|
||||||
SGPropertyNode_ptr airborne;
|
SGPropertyNode_ptr airborne;
|
||||||
SGPropertyNode_ptr currentWp;
|
|
||||||
|
|
||||||
SGPropertyNode_ptr wp0;
|
SGPropertyNode_ptr wp0;
|
||||||
SGPropertyNode_ptr wp1;
|
SGPropertyNode_ptr wp1;
|
||||||
|
@ -72,6 +71,16 @@ private:
|
||||||
|
|
||||||
SGPropertyNode_ptr _pathNode;
|
SGPropertyNode_ptr _pathNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal property to notify people that the route was edited
|
||||||
|
*/
|
||||||
|
SGPropertyNode_ptr _edited;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal property to notify when the last waypoint is reached
|
||||||
|
*/
|
||||||
|
SGPropertyNode_ptr _finished;
|
||||||
|
|
||||||
void setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDistance);
|
void setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDistance);
|
||||||
|
|
||||||
class InputListener : public SGPropertyChangeListener {
|
class InputListener : public SGPropertyChangeListener {
|
||||||
|
@ -99,7 +108,6 @@ private:
|
||||||
|
|
||||||
|
|
||||||
void update_mirror();
|
void update_mirror();
|
||||||
bool near_ground();
|
|
||||||
|
|
||||||
void currentWaypointChanged();
|
void currentWaypointChanged();
|
||||||
|
|
||||||
|
@ -107,6 +115,12 @@ private:
|
||||||
* Parse a route/wp node (from a saved, property-lsit formatted route)
|
* Parse a route/wp node (from a saved, property-lsit formatted route)
|
||||||
*/
|
*/
|
||||||
void parseRouteWaypoint(SGPropertyNode* aWP);
|
void parseRouteWaypoint(SGPropertyNode* aWP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we've reached the final waypoint.
|
||||||
|
* Returns true if we have.
|
||||||
|
*/
|
||||||
|
bool checkFinished();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGRouteMgr();
|
FGRouteMgr();
|
||||||
|
|
|
@ -135,6 +135,10 @@ public:
|
||||||
_gps->routeActivated();
|
_gps->routeActivated();
|
||||||
} else if (prop == _gps->_ref_navaid_id_node) {
|
} else if (prop == _gps->_ref_navaid_id_node) {
|
||||||
_gps->referenceNavaidSet(prop->getStringValue(""));
|
_gps->referenceNavaidSet(prop->getStringValue(""));
|
||||||
|
} else if (prop == _gps->_routeEditedSignal) {
|
||||||
|
_gps->routeEdited();
|
||||||
|
} else if (prop == _gps->_routeFinishedSignal) {
|
||||||
|
_gps->routeFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
_guard = false;
|
_guard = false;
|
||||||
|
@ -412,12 +416,9 @@ GPS::init ()
|
||||||
// should these move to the route manager?
|
// should these move to the route manager?
|
||||||
_routeDistanceNm = node->getChild("route-distance-nm", 0, true);
|
_routeDistanceNm = node->getChild("route-distance-nm", 0, true);
|
||||||
_routeETE = node->getChild("ETE", 0, true);
|
_routeETE = node->getChild("ETE", 0, true);
|
||||||
|
_routeEditedSignal = fgGetNode("/autopilot/route-manager/signals/edited", true);
|
||||||
// disable auto-sequencing in the route manager; we'll deal with it
|
_routeFinishedSignal = fgGetNode("/autopilot/route-manager/signals/finished", true);
|
||||||
// ourselves using turn anticipation
|
|
||||||
SGPropertyNode_ptr autoSeq = fgGetNode("/autopilot/route-manager/auto-sequence", true);
|
|
||||||
autoSeq->setBoolValue(false);
|
|
||||||
|
|
||||||
// add listener to various things
|
// add listener to various things
|
||||||
_listener = new GPSListener(this);
|
_listener = new GPSListener(this);
|
||||||
_route_current_wp_node = fgGetNode("/autopilot/route-manager/current-wp", true);
|
_route_current_wp_node = fgGetNode("/autopilot/route-manager/current-wp", true);
|
||||||
|
@ -425,14 +426,20 @@ GPS::init ()
|
||||||
_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);
|
||||||
|
_routeEditedSignal->addChangeListener(_listener);
|
||||||
|
_routeFinishedSignal->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"));
|
||||||
|
|
||||||
|
SGPropertyNode* fromFlag = node->getChild("from-flag", 0, true);
|
||||||
|
fromFlag->alias(wp1_node->getChild("from-flag"));
|
||||||
|
|
||||||
|
|
||||||
// autopilot drive properties
|
// autopilot drive properties
|
||||||
_apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
|
_apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
|
||||||
_apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
|
_apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
|
||||||
|
@ -747,6 +754,28 @@ void GPS::routeManagerSequenced()
|
||||||
wp1Changed();
|
wp1Changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPS::routeEdited()
|
||||||
|
{
|
||||||
|
if (_mode != "leg") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_INSTR, SG_INFO, "GPS route edited while in LEG mode, updating waypoints");
|
||||||
|
routeManagerSequenced();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPS::routeFinished()
|
||||||
|
{
|
||||||
|
if (_mode != "leg") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_INSTR, SG_INFO, "GPS route finished, reverting to OBS");
|
||||||
|
_mode = "obs";
|
||||||
|
_wp0_position = _indicated_pos;
|
||||||
|
wp1Changed();
|
||||||
|
}
|
||||||
|
|
||||||
void GPS::updateTurn()
|
void GPS::updateTurn()
|
||||||
{
|
{
|
||||||
bool printProgress = false;
|
bool printProgress = false;
|
||||||
|
@ -977,10 +1006,8 @@ void GPS::wp1Changed()
|
||||||
double altFt = _wp1_position.getElevationFt();
|
double altFt = _wp1_position.getElevationFt();
|
||||||
if (altFt < -9990.0) {
|
if (altFt < -9990.0) {
|
||||||
_apTargetAltitudeFt->setDoubleValue(0.0);
|
_apTargetAltitudeFt->setDoubleValue(0.0);
|
||||||
_apAltitudeLock->setBoolValue(false);
|
|
||||||
} else {
|
} else {
|
||||||
_apTargetAltitudeFt->setDoubleValue(altFt);
|
_apTargetAltitudeFt->setDoubleValue(altFt);
|
||||||
_apAltitudeLock->setBoolValue(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,8 @@ private:
|
||||||
|
|
||||||
void routeActivated();
|
void routeActivated();
|
||||||
void routeManagerSequenced();
|
void routeManagerSequenced();
|
||||||
|
void routeEdited();
|
||||||
|
void routeFinished();
|
||||||
|
|
||||||
void updateTurn();
|
void updateTurn();
|
||||||
void updateOverflight();
|
void updateOverflight();
|
||||||
|
@ -329,7 +331,9 @@ 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 _routeEditedSignal;
|
||||||
|
SGPropertyNode_ptr _routeFinishedSignal;
|
||||||
|
|
||||||
double _selectedCourse;
|
double _selectedCourse;
|
||||||
|
|
||||||
bool _last_valid;
|
bool _last_valid;
|
||||||
|
|
|
@ -247,7 +247,8 @@ FGNavRadio::init ()
|
||||||
gps_has_gs_node = fgGetNode("/instrumentation/gps/has-gs", true);
|
gps_has_gs_node = fgGetNode("/instrumentation/gps/has-gs", true);
|
||||||
gps_course_node = fgGetNode("/instrumentation/gps/selected-course-deg", true);
|
gps_course_node = fgGetNode("/instrumentation/gps/selected-course-deg", true);
|
||||||
gps_xtrack_error_nm_node = fgGetNode("/instrumentation/gps/wp/wp[1]/course-error-nm", true);
|
gps_xtrack_error_nm_node = fgGetNode("/instrumentation/gps/wp/wp[1]/course-error-nm", true);
|
||||||
|
_magvarNode = fgGetNode("/environment/magnetic-variation-deg", true);
|
||||||
|
|
||||||
std::ostringstream temp;
|
std::ostringstream temp;
|
||||||
temp << _name << "nav-ident" << _num;
|
temp << _name << "nav-ident" << _num;
|
||||||
nav_fx_name = temp.str();
|
nav_fx_name = temp.str();
|
||||||
|
@ -621,7 +622,9 @@ void FGNavRadio::updateGPSSlaved()
|
||||||
_cdiCrossTrackErrorM = gps_xtrack_error_nm_node->getDoubleValue() * SG_NM_TO_METER;
|
_cdiCrossTrackErrorM = gps_xtrack_error_nm_node->getDoubleValue() * SG_NM_TO_METER;
|
||||||
_gsNeedleDeflection = 0.0; // FIXME, supply this
|
_gsNeedleDeflection = 0.0; // FIXME, supply this
|
||||||
|
|
||||||
//sel_radial_node->setDoubleValue(gps_course_node->getDoubleValue());
|
double trtrue = gps_course_node->getDoubleValue() + _magvarNode->getDoubleValue();
|
||||||
|
SG_NORMALIZE_RANGE(trtrue, 0.0, 360.0);
|
||||||
|
target_radial_true_node->setDoubleValue( trtrue );
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGNavRadio::updateCDI(double dt)
|
void FGNavRadio::updateCDI(double dt)
|
||||||
|
|
|
@ -115,7 +115,8 @@ class FGNavRadio : public SGSubsystem
|
||||||
SGPropertyNode_ptr gps_has_gs_node;
|
SGPropertyNode_ptr gps_has_gs_node;
|
||||||
SGPropertyNode_ptr gps_course_node;
|
SGPropertyNode_ptr gps_course_node;
|
||||||
SGPropertyNode_ptr gps_xtrack_error_nm_node;
|
SGPropertyNode_ptr gps_xtrack_error_nm_node;
|
||||||
|
SGPropertyNode_ptr _magvarNode;
|
||||||
|
|
||||||
// internal (private) values
|
// internal (private) values
|
||||||
|
|
||||||
int play_count;
|
int play_count;
|
||||||
|
|
Loading…
Add table
Reference in a new issue