MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/NavigationAndControl/pNav/MOOSNavigator.cpp
Go to the documentation of this file.
00001 
00002 //
00003 //   MOOS - Mission Oriented Operating Suite
00004 //
00005 //   A suit of Applications and Libraries for Mobile Robotics Research
00006 //   Copyright (C) 2001-2005 Massachusetts Institute of Technology and
00007 //   Oxford University.
00008 //
00009 //   This software was written by Paul Newman and others
00010 //   at MIT 2001-2002 and Oxford University 2003-2005.
00011 //   email: pnewman@robots.ox.ac.uk.
00012 //
00013 //   This file is part of a  MOOS Basic (Common) Application.
00014 //
00015 //   This program is free software; you can redistribute it and/or
00016 //   modify it under the terms of the GNU General Public License as
00017 //   published by the Free Software Foundation; either version 2 of the
00018 //   License, or (at your option) any later version.
00019 //
00020 //   This program is distributed in the hope that it will be useful,
00021 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00023 //   General Public License for more details.
00024 //
00025 //   You should have received a copy of the GNU General Public License
00026 //   along with this program; if not, write to the Free Software
00027 //   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00028 //   02111-1307, USA.
00029 //
00032 //                                                               //
00033 //          This file is part of MOOS Suite                      //
00034 //            Copyright Paul Newman, September 2000                //
00035 //                                                               //
00037 //
00038 //MOOSNavigator.cpp: implementation of the CMOOSNavigator class.
00039 //
00041 #include <MOOSLIB/MOOSLib.h>
00042 #include "../MOOSNavLib/MOOSNavLib.h"
00043 
00044 #include "MOOSNavigator.h"
00045 #include <sstream>
00046 #include <iomanip>
00047 #include <iostream>
00048 #include <algorithm>
00049 
00050 #include <math.h>
00051 
00053 // Construction/Destruction
00055 
00056 //no variables will be update at more than 10HZ
00057 //however we don;t want to miss stuff like two consecuative
00058 //LBL pings!!
00059 #define DEFAULT_NAV_UPDATE_PERIOD 0.0
00060 
00061 /*
00062 ProcessConfig = pNav
00063 {
00064 
00065   X        = SIM @ 5.0 GPS @ 2.0 , DVL @ 3.0 , LBL @ 5.0
00066   Y        = GPS then DVL then LBL
00067   Z        = GPS then DVL then LBL
00068   Depth    = PARA then DVL then LBL
00069   Yaw        = CROSS_BOW then DVL
00070 
00071 }*/
00072 #define DEFAULT_LSQ_TIMEOUT 30
00073 #define DEFAULT_MAX_EKF_LSQ_DEVIATION 20
00074 #define DEFAULT_MAX_POSITION_UNCERTAINTY 30
00075 #define DEFAULT_MAX_EKFLSQ_DISAGREEMENTS 6
00076 #define DEFAULT_LSQ_SAMPLE_SIZE 8
00077 #define DEFAULT_MAX_MEDIAN_LSQ_SHIFT 20
00078 
00079 CMOOSNavigator::CFilterSafety::CFilterSafety()
00080 {
00081     Initialise();
00082 }
00083 
00084 bool CMOOSNavigator::CFilterSafety::Initialise()
00085 {
00086     m_nLastEKFDisagreeIteration = 0;
00087     m_nLastLSQDisagreeIteration = 0;
00088 
00089     m_DeltaLSQHistory.clear();
00090 
00091     m_dfLSQTimeOut = DEFAULT_LSQ_TIMEOUT;
00092     m_dfMaxEKFLSQDeviation = DEFAULT_MAX_EKF_LSQ_DEVIATION;
00093     m_dfMaxEKFPositionUncertainty = DEFAULT_MAX_POSITION_UNCERTAINTY;
00094 
00095     m_nLastEKFDisagreeIteration = 0;
00096     m_nLastLSQDisagreeIteration = 0;
00097 
00098     m_nEKFLSQDisagreements = 0;
00099 
00100     m_nForceEKFAfterNDisagreements = DEFAULT_MAX_EKFLSQ_DISAGREEMENTS;
00101 
00102     m_dfLastLSQX=0;
00103     m_dfLastLSQY=0;
00104     m_dfLastLSQZ=0;
00105     m_dfLastLSQH=0;
00106 
00107     m_nLSQSampleSize = DEFAULT_LSQ_SAMPLE_SIZE;
00108     m_dfMaxMedianLSQShift = DEFAULT_MAX_MEDIAN_LSQ_SHIFT;
00109 
00110     return true;
00111 }
00112 
00113 
00114 CMOOSNavigator::CMOOSNavigator()
00115 {
00116     SetAppFreq(10);
00117     SetCommsFreq(20);
00118 
00119     m_pEKF=NULL;
00120     m_pLSQ=NULL;
00121 
00122 }
00123 
00124 CMOOSNavigator::~CMOOSNavigator()
00125 {
00126 
00127 }
00128 
00129 
00130 
00131 bool CMOOSNavigator::OnNewMail(MOOSMSG_LIST &NewMail)
00132 {
00133 
00134     //look for personal mail first.
00135     HandlePersonalMail(NewMail);
00136 
00137     CMOOSPriorityInput * Inputs[] = {&m_XInput,
00138         &m_YInput,
00139         &m_ZInput,
00140         &m_DepthInput,
00141         &m_YawInput,
00142         &m_AltitudeInput,
00143         &m_SpeedInput,
00144         &m_PitchInput,
00145         &m_PoseInput,
00146         &m_OdometryInput
00147 
00148     } ;
00149 
00150 
00151     MOOSMSG_LIST::iterator p;
00152     NAVENGINE_LIST::iterator q;
00153     for(p = NewMail.begin();p!=NewMail.end();p++)
00154     {
00155         CMOOSMsg &  rMsgIn = *p;
00156 
00157         //if we are in playback mode then don't worry about skew
00158         //this happens in the IsSkewed call
00159         if(rMsgIn.IsSkewed(MOOSTime()))
00160             continue;
00161 
00162         for(q=m_NavEngines.begin();q!=m_NavEngines.end();q++)
00163         {
00164             if((*q)->IsEnabled())
00165             {
00166                 (*q)->AddData(rMsgIn);
00167             }
00168         }
00169         double dfTimeNow = GetTimeNow();
00170         for(unsigned int i = 0;i<sizeof(Inputs)/sizeof(Inputs[0]);i++)
00171         {
00172 
00173             Inputs[i]->SetInput(rMsgIn,dfTimeNow);
00174         }
00175     }
00176 
00177 
00178 
00179 
00180     return true;
00181 }
00182 
00183 
00186 bool CMOOSNavigator::Iterate()
00187 {
00188     NAVENGINE_LIST::iterator q;
00189 
00190     for(q=m_NavEngines.begin();q!=m_NavEngines.end();q++)
00191     {
00192         CMOOSNavEngine * pEngine = *q;
00193 
00194         if(pEngine->IsEnabled())
00195         {
00196             //figure out upto what time we want to
00197             //progress
00198             double dfTimeToIterateTo = GetTimeNow();
00199 
00200             pEngine->Iterate(dfTimeToIterateTo);
00201 
00202             CMOOSMsg ResultMsg;
00203 
00204             while(pEngine->GetNextResult(ResultMsg))
00205             {
00206                 PRIORITYINPUT_LIST::iterator q;
00207 
00208                 for(q = m_InputsList.begin();q!=m_InputsList.end();q++)
00209                 {
00210                     //post to imput stacks.
00211                     //this makes it look as though data came from outside world
00212                     (*q)->SetInput(ResultMsg,ResultMsg.GetTime());
00213 
00214                 }
00215                 //also publish results of the filter.
00216                 //code in MangeInputs prevents us from
00217                 //subscribing to what we publish
00218                 m_Comms.Post(ResultMsg);
00219             }
00220         }
00221     }
00222 
00223     MonitorFilters();
00224 
00225     PublishData();
00226     return true;
00227 }
00228 
00229 
00230 bool CMOOSNavigator::OnStartUp()
00231 {
00232     Clean();
00233     return Initialise();
00234 }
00235 
00236 bool CMOOSNavigator::OnConnectToServer()
00237 {
00238     return MakeSubscriptions();
00239 }
00240 
00241 
00242 
00243 bool CMOOSNavigator::ManageInputs()
00244 {
00245     string sVal;
00246     STRING_LIST TmpList;
00247 
00248 
00249     struct InputSpec{
00250         CMOOSPriorityInput * m_pPriorityInput;
00251         const char * m_sConfigName;
00252         const char * m_sPublishName;
00253         const char* m_sStem;
00254     };
00255 
00256     InputSpec Array[] = {
00257         {&m_XInput,         "X",            "NAV_X",                    "X"},
00258         {&m_YInput,         "Y",            "NAV_Y",                    "Y"},
00259         {&m_ZInput,         "Z",            "NAV_Z",                    "Z"},
00260         {&m_YawInput,       "Yaw",          "NAV_YAW",                  "YAW"},
00261         {&m_SpeedInput,     "Speed",        "NAV_SPEED",        "SPEED"},
00262         {&m_DepthInput,     "Depth",        "NAV_DEPTH",        "DEPTH"},
00263         {&m_PitchInput,     "Pitch",        "NAV_PITCH",        "PITCH"},
00264         {&m_AltitudeInput,  "Altitude",     "NAV_ALTITUDE",     "ALTITUDE"},
00265         {&m_OdometryInput,  "Odometry",     "NAV_ODOMETRY",     "ODOMETRY"},
00266         {&m_PoseInput,          "Pose",         "NAV_POSE",             "POSE"},
00267         
00268     };
00269 
00270     for(unsigned int i = 0; i<sizeof(Array)/sizeof(Array[0]);i++)
00271     {
00272         InputSpec is = Array[i];
00273 
00274         MOOSTrace("setting up data routing table and priorities for %s\n",is.m_sPublishName);
00275 
00276         if(m_MissionReader.GetConfigurationParam(is.m_sConfigName,sVal))
00277         {
00278             is.m_pPriorityInput->Initialise(is.m_sPublishName,
00279                 sVal,
00280                 is.m_sStem,
00281                 TmpList);
00282 
00283             m_SubScriptions.splice(m_SubScriptions.begin(),TmpList);
00284         }
00285     }
00286 
00287     //sometimes sensors supply data that we want that does not map to
00288     //state coordinates - eg LBL TOF...
00289     //this field is used for such occasions and to force the navigator
00290     //to subscribe todata thgat is not decalred in the priority queues
00291     string sAlways;
00292     if(m_MissionReader.GetConfigurationParam("ALWAYS_READ",sAlways))
00293     {
00294         while(!sAlways.empty())
00295         {
00296             m_SubScriptions.push_back(MOOSChomp(sAlways,","));
00297         }
00298     }
00299 
00300 
00301     //so we have build a long list of all the variable we want to subscribe to
00302     //now we tell the server to tell us when they change.
00303     STRING_LIST::iterator p;
00304 
00305     //but don;t subscribe to things with the stems
00306     //that we will be publishing
00307     set<string> DoNotSubscribe;
00308     DoNotSubscribe.insert("LSQ");
00309     DoNotSubscribe.insert("EKF");
00310 
00311     for(p = m_SubScriptions.begin();p!=m_SubScriptions.end();p++)
00312     {
00313         set<string>::iterator q;
00314         bool bOmit = false;
00315         for(q = DoNotSubscribe.begin();q!=DoNotSubscribe.end();q++)
00316         {
00317             //if we can find a banned stem in the SubScriptions
00318             //we shall skip this potential subscription
00319             string sBanned = *q;
00320             string sSubs = *p;
00321             if(p->find(*q)!=string::npos)
00322             {
00323                 bOmit = true;
00324                 break;
00325             }
00326         }
00327 
00328         if(!bOmit)
00329         {
00330             m_Comms.Register(*p,DEFAULT_NAV_UPDATE_PERIOD);
00331         }
00332     }
00333 
00334 
00335 
00336 
00337 
00338     //keep a STL list of our inputs for future use...
00339     m_InputsList.clear();
00340     m_InputsList.push_front(&m_XInput);
00341     m_InputsList.push_front(&m_YInput);
00342     m_InputsList.push_front(&m_ZInput);
00343     m_InputsList.push_front(&m_DepthInput);
00344     m_InputsList.push_front(&m_YawInput);
00345     m_InputsList.push_front(&m_AltitudeInput);
00346     m_InputsList.push_front(&m_SpeedInput);
00347     m_InputsList.push_front(&m_PitchInput);
00348     m_InputsList.push_front(&m_OdometryInput);
00349     m_InputsList.push_front(&m_PoseInput);
00350 
00351 
00352     //some additional susbcriptions
00353     m_Comms.Register("TOP_DOWN_CAL_CONTROL",0);
00354 
00355     return true;
00356 }
00357 
00358 
00359 
00360 
00361 bool CMOOSNavigator::PublishData()
00362 {
00363 
00364 
00365     double dfTimeNow = GetTimeNow();
00366 
00367     PRIORITYINPUT_LIST::iterator q;
00368 
00369     ostringstream os;
00370 
00371     for(q = m_InputsList.begin();q!=m_InputsList.end();q++)
00372     {
00373 
00374         CMOOSMsg MsgOut;
00375 
00376         if((*q)->GetOutput(MsgOut,dfTimeNow))
00377         {
00378             m_Comms.Post(MsgOut);
00379         }
00380 
00381         double dfTime,dfVal;
00382         if((*q)->GetLastValue(dfTime,dfVal))
00383         {
00384             os<<(*q)->m_sName.c_str()<<"=";
00385             os<<dfVal;
00386             os<<"@"<<dfTime-GetAppStartTime();
00387             os<<",";
00388         }
00389 
00390     }
00391 
00392     os<<ends;
00393 
00394     //finally send a nav summary
00395     string sSummary = os.str();
00396     //   os.rdbuf()->freeze(0);
00397     if(!sSummary.empty())
00398     {
00399         m_Comms.Notify("NAV_SUMMARY",sSummary);
00400     }
00401 
00402     return true;
00403 }
00404 
00405 
00406 bool CMOOSNavigator::SetUpNavEngines()
00407 {
00408     //firstly make the nav engines....
00409 
00410     if(!MakeNavEngines())
00411         return false;
00412 
00413     if(!AddSensorsToEngines())
00414         return false;
00415 
00416     if(!AddAcousticsToEngines())
00417         return false;
00418 
00419     if(!AddFixedObservations())
00420         return false;
00421 
00422     return true;
00423 }
00424 
00425 bool CMOOSNavigator::AddSensorsToEngines()
00426 {
00427 
00428     //now Add sensors
00429     NAVENGINE_LIST::iterator p;
00430 
00431     for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
00432     {
00433         CMOOSNavEngine * pEngine = *p;
00434 
00435         STRING_LIST sList;
00436         m_MissionReader.GetConfiguration(GetAppName(),sList);
00437 
00438         STRING_LIST::iterator q;
00439 
00440         for(q = sList.begin();q!=sList.end();q++)
00441         {
00442             string sLine = *q;
00443             string sTok,sVal;
00444 
00445             if(m_MissionReader.GetTokenValPair(sLine,sTok,sVal))
00446             {
00447                 CMOOSNavSensor::Type eType=CMOOSNavSensor::INVALID;
00448 
00449                 if(MOOSStrCmp(sTok,"SENSOR_XY"))
00450                 {
00451                     eType = CMOOSNavSensor::XY;
00452                 }
00453                 else if(MOOSStrCmp(sTok,"SENSOR_ORIENTATION"))
00454                 {
00455                     eType = CMOOSNavSensor::ORIENTATION;
00456                 }
00457                 else if(MOOSStrCmp(sTok,"SENSOR_DEPTH"))
00458                 {
00459                     eType = CMOOSNavSensor::DEPTH;
00460                 }
00461                 else if(MOOSStrCmp(sTok,"SENSOR_LBL"))
00462                 {
00463                     eType = CMOOSNavSensor::LBL;
00464                 }
00465                 else if(MOOSStrCmp(sTok,"SENSOR_ALTITUDE"))
00466                 {
00467                     eType = CMOOSNavSensor::ALTITUDE;
00468                 }
00469                 else if(MOOSStrCmp(sTok,"SENSOR_BODY_VEL"))
00470                 {
00471                     eType = CMOOSNavSensor::BODY_VEL;
00472                 }
00473                 else if(MOOSStrCmp(sTok,"SENSOR_CONTROL"))
00474                 {
00475                     eType = CMOOSNavSensor::CONTROL;
00476                 }
00477 
00478                 if(eType!=CMOOSNavSensor::INVALID)
00479                 {
00480                     string sSource = MOOSChomp(sVal,"->");
00481 
00482                     string sName = MOOSChomp(sVal,"@");
00483 
00484                     double dfX = atof(MOOSChomp(sVal,",").c_str());
00485                     double dfY = atof(MOOSChomp(sVal,",").c_str());
00486                     double dfZ = atof(sVal.c_str());
00487 
00488                     //now look for noise figure
00489                     MOOSChomp(sVal,"~");
00490                     double dfNoise=-1;
00491                     if(!sVal.empty())
00492                     {
00493                         dfNoise = atof(sVal.c_str());
00494                     }
00495 
00496                     if(!pEngine->AddSensor(sSource,sName,eType,dfX,dfY,dfZ,dfNoise))
00497                     {
00498                         MOOSTrace("Sensor Not added!\n");
00499                     }
00500                 }
00501                 else
00502                 {
00503                     if(sTok.find("SENSOR_")!=string::npos)
00504                     {
00505                         MOOSTrace("Cannot add sensor of type %s - not supported\n",sTok.c_str());
00506                     }
00507                 }
00508             }
00509         }
00510     }
00511 
00512     return true;
00513 }
00514 
00515 bool CMOOSNavigator::MakeNavEngines()
00516 {
00517     m_pEKF = NULL;
00518     m_pLSQ = NULL;
00519 
00520     string sBool;
00521     if(m_MissionReader.GetConfigurationParam("USELSQ",sBool))
00522     {
00523         if(MOOSStrCmp("TRUE",sBool))
00524         {
00525             m_pLSQ = new CMOOSNavLSQEngine;
00526             m_NavEngines.push_back(m_pLSQ);
00527         }
00528     }
00529     if(m_MissionReader.GetConfigurationParam("USETOPDOWN",sBool))
00530     {
00531         if(MOOSStrCmp("TRUE",sBool))
00532         {
00533             m_NavEngines.push_back(new CMOOSNavTopDownCalEngine);
00534         }
00535     }
00536     if(m_MissionReader.GetConfigurationParam("USEEKF",sBool))
00537     {
00538         if(MOOSStrCmp("TRUE",sBool))
00539         {
00540             m_pEKF = new CMOOSNavEKFEngine;
00541             m_NavEngines.push_back(m_pEKF);
00542         }
00543     }
00544 
00545     //now initialise all the engines giving themchance to
00546     //pick out their own parameters
00547     NAVENGINE_LIST::iterator p;
00548 
00549     STRING_LIST sParams;
00550     m_MissionReader.GetConfiguration(GetAppName(),sParams);
00551 
00552 
00553     for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
00554     {
00555         CMOOSNavEngine * pEngine = *p;
00556 
00557         pEngine->SetMissionFileName(this->m_sMissionFile);
00558 
00559         pEngine->Initialise(sParams);
00560 
00561 
00562     }
00563 
00564     if(m_pLSQ!=NULL)
00565     {
00566         //the LSQ starts imediately
00567         m_pLSQ->SetTimeStarted(MOOSTime());
00568     }
00569 
00570     //now we may want to run the EKF WITHOUT LSQ
00571     if(m_pEKF!=NULL && m_pLSQ==NULL)
00572     {
00573         //we turn the EKF on!
00574         m_pEKF->SetOnline(true);
00575         m_pEKF->Enable(true);
00576     }
00577 
00578     return true;
00579 }
00580 
00581 bool CMOOSNavigator::AddAcousticsToEngines()
00582 {
00583 
00584     STRING_LIST sParams;
00585 
00586     if(!m_MissionReader.GetConfiguration("Acoustics",sParams))
00587         return true;
00588 
00589     sParams.reverse();
00590 
00591     STRING_LIST::iterator q;
00592 
00593     string sTok,sVal;
00594 
00595     for(q = sParams.begin();q!=sParams.end();q++)
00596     {
00597         string sLine = *q;
00598         MOOSToUpper(sLine);
00599         if(sLine.find("BEACON")!=string::npos)
00600         {
00601 
00602             //this is what we want to know
00603             double dfX;
00604             double dfY;
00605             double dfZ;
00606             int nChan;
00607             double dfTAT;
00608             string sName;
00609 
00610 
00611             //lets find them out...
00612             CMOOSFileReader::GetTokenValPair(sLine,sTok,sVal);
00613 
00614             CMOOSNavBeacon Beacon;
00615 
00616             sName=sVal;
00617 
00618             if(*(++q) == "[")
00619             {
00620                 while(++q!=sParams.end() && *q!="]")
00621                 {
00622                     sLine = *q;
00623                     MOOSToUpper(sLine);
00624 
00625                     CMOOSFileReader::GetTokenValPair(sLine,sTok,sVal);
00626 
00627 
00629                     //      set up location
00631 
00632                     if(sLine.find("POS")!=string::npos)
00633                     {
00634                         //we are being told location
00635                         dfX = atof(MOOSChomp(sVal,",").c_str());
00636                         dfY = atof(MOOSChomp(sVal,",").c_str());
00637                         dfZ = atof(MOOSChomp(sVal,",").c_str());
00638 
00639                         Beacon.m_State.m_dfX=dfX;
00640                         Beacon.m_State.m_dfY=dfY;
00641                         Beacon.m_State.m_dfZ=dfZ;
00642 
00643                     }
00644 
00646                     //      set up transmit
00648 
00649                     if(sLine.find("TX")!=string::npos)
00650                     {
00651                         MOOSChomp(sVal,"CH");
00652 
00653                         nChan = atoi(sVal.c_str());
00654 
00655                         if(nChan>0)
00656                         {
00657                             Beacon.m_nChan = nChan;
00658                         }
00659                         else
00660                         {
00661                             MOOSTrace("Illegal Beacon Reply Channel!\n");
00662                             return false;
00663                         }
00664 
00665                     }
00666 
00667 
00669                     //      set up TAT
00671 
00672                     if(sLine.find("TAT")!=string::npos)
00673                     {
00674                         dfTAT = atof(sVal.c_str());
00675 
00676                         if(dfTAT>0)
00677                         {
00678                             Beacon.m_dfTAT=dfTAT;
00679                         }
00680                         else
00681                         {
00682                             MOOSTrace("Illegal TAT must be >0\n");
00683                             return false;
00684                         }
00685                     }
00686                 }
00687             }//end of Beacon [.....] block
00688 
00689             //now tell all engines about this beacon
00690             NAVENGINE_LIST::iterator p;
00691             for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
00692             {
00693                 CMOOSNavEngine * pEngine = *p;
00694                 if(!pEngine->AddAcousticBeacon(sName,nChan,dfTAT,dfX,dfY,dfZ))
00695                 {
00696                     MOOSTrace("failed to add acoustic beacon\n");
00697                     return false;
00698                 }
00699             }
00700         }
00701     }
00702 
00703     return true;
00704 }
00705 
00706 
00707 
00708 
00709 
00710 bool CMOOSNavigator::AddFixedObservations()
00711 {
00712 
00713     typedef map<string,CMOOSObservation::Type> NAME_2_OBS_TYPE_MAP;
00714 
00715     NAME_2_OBS_TYPE_MAP    AllowedObs;
00716 
00717     //add new fixed observatin types here.....
00718     AllowedObs["FIXEDDEPTH"]=CMOOSObservation::DEPTH;
00719     AllowedObs["FIXEDHEADING"]=CMOOSObservation::YAW;
00720     AllowedObs["FIXEDTIDE"]=CMOOSObservation::TIDE;
00721 
00722 
00723 
00724     NAME_2_OBS_TYPE_MAP::iterator s;
00725     for(s = AllowedObs.begin();s!=AllowedObs.end();s++)
00726     {
00727         string sName = s->first;
00728         string sVal;
00729 
00730         if(m_MissionReader.GetConfigurationParam(sName,sVal))
00731         {
00732             //we know type of observation this maps to..
00733             CMOOSObservation::Type eType = s->second;
00734 
00735             //look for value
00736             double dfVal = atof(sVal.c_str());
00737 
00738             if(eType==CMOOSObservation::YAW)
00739             {
00740                 dfVal = MOOS_ANGLE_WRAP(-MOOSDeg2Rad(dfVal));
00741             }
00742 
00743             //now look for uncertainty
00744             //chomp on @ symbol
00745             MOOSChomp(sVal,"@");
00746 
00747             double dfStd = -1;
00748             if(!sVal.empty())
00749             {
00750                 dfStd = atof(sVal.c_str());
00751             }
00752 
00753 
00754             NAVENGINE_LIST::iterator p;
00755 
00756             for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
00757             {
00758                 CMOOSNavEngine * pEngine = *p;
00759                 if(!pEngine->AddFixedObservation(eType,dfVal,dfStd))
00760                     return false;
00761             }
00762 
00763         }
00764     }
00765 
00766 
00767 
00768 
00769 
00770     return true;
00771 
00772 }
00773 
00774 
00775 bool CMOOSNavigator::HandlePersonalMail(MOOSMSG_LIST &NewMail)
00776 {
00777 
00778 
00779     CMOOSMsg Msg;
00780 
00781     if(m_Comms.PeekMail(NewMail,"RESTART_NAV",Msg,true))
00782     {
00783         if(!Msg.IsSkewed(MOOSTime()))
00784         {
00785             OnNavRestart();
00786         }
00787     }
00788 
00789     if(m_Comms.PeekMail(NewMail,"NAV_SUMMARY_REQUEST",Msg,true))
00790     {
00791         if(!Msg.IsSkewed(MOOSTime()))
00792         {
00793             if(m_pEKF!=NULL)
00794             {
00795                 m_pEKF->DoObservationSummary();
00796             }
00797         }
00798     }
00799 
00800 
00801     if(m_Comms.PeekMail(NewMail,"LSQ_ENABLE",Msg,true))
00802     {
00803         if(!Msg.IsSkewed(MOOSTime()))
00804         {
00805             bool bEnable = MOOSStrCmp("TRUE",Msg.m_sVal);
00806             if(m_pLSQ!=NULL)
00807             {
00808                 m_pLSQ->Enable(bEnable);
00809             }
00810         }
00811     }
00812 
00813     if(m_Comms.PeekMail(NewMail,"EKF_ENABLE",Msg,true))
00814     {
00815         if(!Msg.IsSkewed(MOOSTime()))
00816         {
00817             bool bEnable = MOOSStrCmp("TRUE",Msg.m_sVal);
00818             if(m_pEKF!=NULL)
00819             {
00820                 m_pEKF->Enable(bEnable);
00821                 m_pEKF->SetOnline(bEnable);
00822             }
00823         }
00824     }
00825 
00826 
00827     return true;
00828 }
00829 
00830 bool CMOOSNavigator::OnNavRestart()
00831 {
00832     MOOSDebugWrite("Restarting Navigator");
00833 
00834     Clean();
00835 
00836     return Initialise();
00837 
00838 }
00839 
00840 bool CMOOSNavigator::Clean()
00841 {
00842     NAVENGINE_LIST::iterator p;
00843 
00844     for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
00845     {
00846         CMOOSNavEngine * pEngine = *p;
00847         delete pEngine;
00848     }
00849     m_NavEngines.clear();
00850     m_pEKF = NULL;
00851     m_pLSQ = NULL;
00852 
00853     //clean down inputs list..
00854 
00855     PRIORITYINPUT_LIST::iterator q;
00856 
00857     for(q = m_InputsList.begin();q!=m_InputsList.end();q++)
00858     {
00859         CMOOSPriorityInput*  pInput = *q;
00860         pInput->Clear();
00861     }
00862 
00863 
00864     return true;
00865 
00866 }
00867 
00868 bool CMOOSNavigator::OnNavFailure(const string &sReason)
00869 {
00870     if(m_pLSQ!=NULL)
00871     {
00872         m_pLSQ->SetOnline(false);
00873         m_pLSQ->Enable(false);
00874     }
00875     if(m_pEKF!=NULL)
00876     {
00877         m_pEKF->SetOnline(false);
00878         m_pEKF->Enable(false);
00879     }
00880 
00881 
00882     string sBadNews = MOOSFormat("NAVIGATION FAILURE : \"%s\" ALL FILTERS GOING DOWN. Are all the required sensors working?",sReason.c_str());
00883 
00884     MOOSDebugWrite(sBadNews);
00885 
00886     m_Comms.Notify("NAVIGATION_FAILURE",sBadNews,MOOSTime());
00887 
00888     m_Comms.Notify("EndMission","Nav Failure");
00889 
00890     return true;
00891 }
00892 
00893 bool CMOOSNavigator::MonitorFilters()
00894 {
00895     //note this is a complicated bit of logic
00896     //to show the whole piture it is written in one
00897     //oversized function. The idea is to
00898     // 1)spot divergence in the EKF
00899     // 2)spot failuer in LSQ (no updates)
00900     // 3) spot differeing solutions between EKF and LSQ
00901     // 4) if possible reset the EKF from the LSQ if the LSQ
00902     //    has been disagreeing with LSQ for a while
00903     //
00904     // note that 4) will reset the EKF continually if the LSQ is all
00905     // over the shop..
00906     double dfXEKF;
00907     double dfYEKF;
00908     double dfZEKF;
00909     double dfHEKF;
00910 
00911     double dfXLSQ;
00912     double dfYLSQ;
00913     double dfZLSQ;
00914     double dfHLSQ;
00915 
00916     double dfLastLSQUpdate;
00917     double dfLastEKFUpdate;
00918     double dfTimeSinceLSQUpdate=1e6;
00919 
00920 
00921     //is LSQ healthy?
00922     if(m_pLSQ!=NULL && m_pLSQ->IsOnline() )
00923     {
00924         //so the LSQ is meant to be working (we set it up)
00925         //and it has booted.
00926         m_pLSQ->GetTrackedPosition(dfXLSQ,dfYLSQ,dfZLSQ,dfHLSQ,dfLastLSQUpdate);
00927 
00928 
00930         //    are we getting regular updates?
00931         dfTimeSinceLSQUpdate = GetTimeNow()-dfLastLSQUpdate;
00932 
00933         if(dfTimeSinceLSQUpdate>m_FilterSafety.m_dfLSQTimeOut && m_pLSQ->GetIterations()!=0)
00934         {
00935             //this is really bad news...
00936             string sReason = MOOSFormat("No updates from LSQ Filter in %f seconds",m_FilterSafety.m_dfLSQTimeOut);
00937             return OnNavFailure(sReason);
00938         }
00939 
00941         //        have we spent too long waiting to boot?
00942         double dfTimeSinceStart = GetTimeNow()-m_pLSQ->GetTimeStarted();
00943         if(m_pLSQ->GetIterations()==0 && dfTimeSinceStart>m_FilterSafety.m_dfLSQTimeOut)
00944         {
00945             string sReason = MOOSFormat("LSQ Filter seems not to have booted in %f seconds",m_FilterSafety.m_dfLSQTimeOut);
00946             return OnNavFailure(sReason);
00947         }
00948 
00950         //        Are the LSQ fixes really noisy?
00951         m_FilterSafety.SetLSQSolution(dfXLSQ,dfYLSQ,dfZLSQ,dfHLSQ,dfLastLSQUpdate);
00952         if(m_FilterSafety.IsLSQNoisey())
00953         {
00954             string sReason = MOOSFormat("LSQ Filter is \"all over the shop\" median shift of %f m over %d solutions!",
00955                 m_FilterSafety.GetMedianLSQShift(),
00956                 m_FilterSafety.m_nLSQSampleSize);
00957 
00958             return OnNavFailure(sReason);
00959         }
00960 
00961 
00962         if(m_pEKF!=NULL && m_pEKF->IsEnabled() )
00963         {
00964             //so the EKF exists and we want to use it( Enabled)
00965             // howver it may not be booted (online)
00966             if(!m_pEKF->IsOnline())
00967             {
00968                 if(dfTimeSinceLSQUpdate<2.0)
00969                 {
00970                     //to do add boot code here!!!
00971                     MOOSDebugWrite("Booting EKF from LSQ Estimate");
00972                     m_pEKF->SetOnline(true);
00973                     m_pEKF->SetTimeStarted(MOOSTime());
00974 
00975                     //we boot with our LSQ solution...
00976                     m_pEKF->ForceTrackedPosition(dfXLSQ,dfYLSQ,dfZLSQ,dfHLSQ);
00977                 }
00978             }
00979             else
00980             {
00981                 //well the EKF and the LSQ are both in use and both
00982                 //online - we should compare then
00983 
00984                 m_pEKF->GetTrackedPosition(dfXEKF,dfYEKF,dfZEKF,dfHEKF,dfLastEKFUpdate);
00985 
00986                 double dfDistance = sqrt(
00987                     pow(dfXLSQ-dfXEKF,2)+
00988                     pow(dfYLSQ-dfYEKF,2)+
00989                     pow(dfZLSQ-dfZEKF,2));
00990 
00991                 //are we behaving?....(in agreement (roughly))
00992                 if(dfDistance>m_FilterSafety.m_dfMaxEKFLSQDeviation )
00993                 {
00994                     //no... they seem to be diverging...
00995 
00996                     //We may want to see if they disgree over a period of time
00997                     //ie not just an outlier in the LSQ!
00998                     int nEKFDisagree = m_pEKF->GetIterations();
00999                     int nLSQDisagree = m_pLSQ->GetIterations();
01000 
01001                     if(nEKFDisagree!=m_FilterSafety.m_nLastEKFDisagreeIteration
01002                         && nLSQDisagree!=m_FilterSafety.m_nLastLSQDisagreeIteration)
01003                     {
01004                         //both filters have advanced..
01005                         m_FilterSafety.m_nEKFLSQDisagreements++;
01006 
01007                         m_FilterSafety.m_nLastEKFDisagreeIteration = nEKFDisagree;
01008                         m_FilterSafety.m_nLastLSQDisagreeIteration = nLSQDisagree;
01009 
01010                     }
01011 
01012                     if(m_FilterSafety.m_nEKFLSQDisagreements>m_FilterSafety.m_nForceEKFAfterNDisagreements)
01013                     {
01014                         //we had better force the EKF to the LSQ solution...
01015                         //this has been going on for a while!
01016                         string sReason = MOOSFormat("Forcing EKF to LSQ Pose disageed for %d iterations deviation = %f ( >%f )",
01017                             m_FilterSafety.m_nEKFLSQDisagreements,
01018                             dfDistance,
01019                             m_FilterSafety.m_dfMaxEKFLSQDeviation);
01020 
01021                         MOOSDebugWrite(sReason);
01022 
01023                         //here we reset the EKF filter
01024                         m_pEKF->ForceTrackedPosition(dfXLSQ,dfYLSQ,dfZLSQ,dfHLSQ);
01025 
01026 
01027                         //reset our counts..
01028                         m_FilterSafety.m_nEKFLSQDisagreements=0;
01029                     }
01030                 }
01031                 else
01032                 {
01033                         //there is NO disagreement..
01034                         //reset our counts..
01035                         m_FilterSafety.m_nEKFLSQDisagreements=0;
01036                 }
01037             }
01038         }
01039     }
01040 
01041     //look after EKF explicit things...
01042     if(m_pEKF!=NULL && m_pEKF->IsOnline() && m_pEKF->GetIterations()>10)
01043     {
01044         //are we too uncertain?
01045         double dfPX,dfPY,dfPZ,dfPH;
01046         m_pEKF->GetTrackedUncertainty(dfPX,dfPY,dfPZ,dfPH);
01047 
01048         if(sqrt(dfPX)>m_FilterSafety.m_dfMaxEKFPositionUncertainty || sqrt(dfPY)>m_FilterSafety.m_dfMaxEKFPositionUncertainty)
01049         {
01050             //we are lost :-(
01051             m_pEKF->Reset();
01052             m_pEKF->SetOnline(false);
01053 
01054             string sReason = MOOSFormat("EKF is lost!, CEP = [%.2f,%.2f]m which is greater than %.2f limit specified in mission file\n",
01055             sqrt(dfPX),
01056             sqrt(dfPY),
01057             m_FilterSafety.m_dfMaxEKFPositionUncertainty);
01058 
01059             MOOSDebugWrite(sReason);
01060         }
01061     }
01062     return true;
01063 }
01064 
01065 double CMOOSNavigator::GetTimeNow()
01066 {
01067     if(IsMOOSPlayBack())
01068     {
01069         //we are in playback - time can be warped.
01070         //best we can do is figure out what the last time
01071         //that the engines know about is....
01072         NAVENGINE_LIST::iterator p;
01073 
01074         double dfYoungest = -1.0;
01075         for(p=m_NavEngines.begin();p!=m_NavEngines.end();p++)
01076         {
01077             CMOOSNavEngine * pEngine = *p;
01078 
01079             double dfTmp = pEngine->GetYoungestDataTime();
01080             dfYoungest = dfTmp>dfYoungest?dfTmp:dfYoungest;
01081         }
01082 
01083         return dfYoungest;
01084     }
01085     else
01086     {
01087         //we are live so we use NOW time
01088         return MOOSTime();
01089     }
01090 }
01091 
01092 bool CMOOSNavigator::MakeSubscriptions()
01093 {
01094     m_Comms.Register("RESTART_NAV",0.1);
01095     m_Comms.Register("EKF_ENABLE",0.1);
01096     m_Comms.Register("LSQ_ENABLE",0.1);
01097     m_Comms.Register("NAV_SUMMARY_REQUEST",0.1);
01098 
01099 
01100     return ManageInputs();
01101 }
01102 
01103 bool CMOOSNavigator::Initialise()
01104 {
01105     m_FilterSafety.Initialise();
01106 
01107     m_MissionReader.GetConfigurationParam("MAXLSQEKFDEVIATION",m_FilterSafety.m_dfMaxEKFLSQDeviation);
01108     m_MissionReader.GetConfigurationParam("LSQTIMEOUT",m_FilterSafety.m_dfLSQTimeOut);
01109     m_MissionReader.GetConfigurationParam("MAXEKFPOSITIONUNCERTAINTY",m_FilterSafety.m_dfMaxEKFPositionUncertainty);
01110     m_MissionReader.GetConfigurationParam("MAXMEDIANLSQSHIFT",m_FilterSafety.m_dfMaxMedianLSQShift);
01111 
01112 
01113     if(!SetUpNavEngines())
01114         return false;
01115 
01116     //this sets up subscriptions etc
01117     if(!MakeSubscriptions())
01118         return false;
01119 
01120 
01121     return true;
01122 }
01123 
01124 
01125 bool CMOOSNavigator::CFilterSafety::SetLSQSolution(double dfX, double dfY, double dfZ, double dfH, double dfTime)
01126 {
01127     if(dfTime==m_dfLastLSQUpdate)
01128         return true;
01129 
01130     double dfR =    sqrt(pow(m_dfLastLSQX-dfX,2)+
01131                     pow(m_dfLastLSQY-dfY,2)+
01132                     pow(m_dfLastLSQZ-dfZ,2));
01133 
01134     m_DeltaLSQHistory.push_front(dfR);
01135 
01136     while(static_cast<int> (m_DeltaLSQHistory.size())>m_nLSQSampleSize)
01137     {
01138         m_DeltaLSQHistory.pop_back();
01139     }
01140 
01141     m_dfLastLSQX=dfX;
01142     m_dfLastLSQY=dfY;
01143     m_dfLastLSQZ=dfZ;
01144     m_dfLastLSQH=dfH;
01145     m_dfLastLSQUpdate = dfTime;
01146 
01147     return true;
01148 }
01149 
01150 bool CMOOSNavigator::CFilterSafety::IsLSQNoisey()
01151 {
01152     return GetMedianLSQShift()>m_dfMaxMedianLSQShift;
01153 }
01154 
01155 double CMOOSNavigator::CFilterSafety::GetMedianLSQShift()
01156 {
01157 
01158     if(static_cast<int> (m_DeltaLSQHistory.size())<m_nLSQSampleSize)
01159         return 0;
01160 
01161     vector<double> LocalVec;
01162     LocalVec.resize(m_DeltaLSQHistory.size());
01163 
01164     copy(m_DeltaLSQHistory.begin(),m_DeltaLSQHistory.end(),LocalVec.begin());
01165     sort(LocalVec.begin(),LocalVec.end());
01166 
01167     double dfMedian = LocalVec[LocalVec.size()/2];
01168 
01169     return dfMedian;
01170 }
01171 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines