MOOS 0.2375
|
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