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 // 00031 // MOOSNavTopDownCalEngine.cpp: implementation of the CMOOSNavTopDownCalEngine class. 00032 // 00034 #ifdef _WIN32 00035 #pragma warning(disable : 4786) 00036 #endif 00037 00038 #include "MOOSNavLibGlobalHelper.h" 00039 #include "MOOSNavObsStore.h" 00040 #include "MOOSNavBeacon.h" 00041 #include "MOOSNavVehicle.h" 00042 #define FAILED_CONVERGENCE_LIMIT 4 00043 #define DEFAULT_MANUAL_PATH_LENGTH 100.0 00044 #include "MOOSNavTopDownCalEngine.h" 00045 00047 // Construction/Destruction 00049 00050 CMOOSNavTopDownCalEngine::CMOOSNavTopDownCalEngine() 00051 { 00052 m_nSelectedChan = 3; 00053 m_eState = OFFLINE; 00054 m_sJobName = "TOPDOWNCALIBRATION"; 00055 m_nNoConvergenceCounter = 0; 00056 m_dfCalPathLength = DEFAULT_MANUAL_PATH_LENGTH; 00057 00058 m_dfTide = 0; 00059 00060 m_sName = "TopDown"; 00061 00062 m_dfLastSolveAttempt = -1; 00063 00064 m_bInitialOnline = false; 00065 00066 //how often do we try to solve? 00067 m_dfTrialRate = 4.0; 00068 00069 m_dfSpacing = 1.0; 00070 } 00071 00072 CMOOSNavTopDownCalEngine::~CMOOSNavTopDownCalEngine() 00073 { 00074 00075 } 00076 00077 bool CMOOSNavTopDownCalEngine::Initialise(STRING_LIST sParams) 00078 { 00079 00080 00081 if(CMOOSNavLSQEngine::Initialise(sParams)) 00082 { 00083 m_pStore->SetSpan(200); 00084 } 00085 00086 //we never use heading bias state in TDC 00087 m_bEstimateHeadingBias = false; 00088 00089 00090 00091 string sVal; 00092 00093 if(MOOSGetValueFromToken(sParams,"TDC_TIDE",sVal)) 00094 { 00095 double dfVal = atof(sVal.c_str()); 00096 m_dfTide = dfVal; 00097 00098 } 00099 00100 if(MOOSGetValueFromToken(sParams,"TDC_SPACING",sVal)) 00101 { 00102 double dfVal = atof(sVal.c_str()); 00103 if(dfVal>0) 00104 { 00105 m_dfSpacing = dfVal; 00106 } 00107 } 00108 00109 if(MOOSGetValueFromToken(sParams,"TDC_TRIAL_RATE",sVal)) 00110 { 00111 double dfVal = atof(sVal.c_str()); 00112 if(dfVal>0) 00113 { 00114 m_dfTrialRate = dfVal; 00115 } 00116 } 00117 00118 //initial guesses for top down 00119 if(MOOSGetValueFromToken(sParams,"TDC_GUESS_DEPTHS",sVal)) 00120 { 00121 //TDC_GUESS_DEPTHS = 3@2.4 , 4@5.4 etc 00122 while(!sVal.empty()) 00123 { 00124 string sBlock = MOOSChomp(sVal,","); 00125 string sChan = MOOSChomp(sBlock,"@"); 00126 //store this guess depth... 00127 m_GuessedDepths[atoi(sChan.c_str())] = atoi(sBlock.c_str()); 00128 } 00129 } 00130 else 00131 { 00132 AddToOutput("Warning now beacons guess depths specified\n"); 00133 } 00134 00135 return true; 00136 } 00137 00138 00139 bool CMOOSNavTopDownCalEngine::AddData(const CMOOSMsg &Msg) 00140 { 00141 //crack all messages for control commands... 00142 if(Msg.m_sKey=="TOP_DOWN_CAL_CONTROL") 00143 { 00144 return OnRxTopDownControl(Msg.m_sVal); 00145 } 00146 else if(m_eState!=OFFLINE) 00147 { 00148 bool bBaseSuccess = CMOOSNavLSQEngine::AddData(Msg); 00149 00150 return bBaseSuccess; 00151 } 00152 return true; 00153 } 00154 00155 bool CMOOSNavTopDownCalEngine::Iterate(double dfTimeNow) 00156 { 00157 if(!IsOnline()) 00158 return false; 00159 00160 //a fresh start on each iteration 00161 Clean(); 00162 00163 if(dfTimeNow-m_dfLastSolveAttempt>m_dfTrialRate) 00164 { 00165 m_dfLastSolveAttempt = dfTimeNow; 00166 00167 if(MakeVantagePoints()) 00168 { 00169 //is we got to here then we are in a fit state to try and calculate... 00170 if(Calculate(dfTimeNow)) 00171 { 00172 } 00173 } 00174 OnIterateDone(); 00175 } 00176 00177 return true; 00178 } 00179 00180 00181 00182 bool CMOOSNavTopDownCalEngine::OnSolved() 00183 { 00184 00185 if(m_pTracked->RefreshState()) 00186 { 00187 00188 AddToOutput("Bcn(C%d)->[%7.1f,%7.1f,%7.1f]", 00189 m_nSelectedChan, 00190 m_pTracked->m_State.m_dfX, 00191 m_pTracked->m_State.m_dfY, 00192 m_pTracked->m_State.m_dfZ); 00193 } 00194 if(m_pTracked->RefreshStateCovariance()) 00195 { 00196 AddToOutput("Bcn std: %7.1f,%7.1f,%7.1f", 00197 sqrt(m_pTracked->m_State.m_dfPX), 00198 sqrt(m_pTracked->m_State.m_dfPY), 00199 sqrt(m_pTracked->m_State.m_dfPZ)); 00200 00201 00202 00203 } 00204 00205 return true; 00206 00207 } 00208 00209 00210 bool CMOOSNavTopDownCalEngine::OnIterateDone() 00211 { 00212 00213 BEACONLIST::iterator p,q; 00214 00215 for(p = m_Beacons.begin();p!=m_Beacons.end();p++) 00216 { 00217 CMOOSNavBeacon * pBcn = *p; 00218 00219 if(pBcn->m_bPseudo) 00220 { 00221 delete pBcn; 00222 q=p; 00223 p++; 00224 m_Beacons.erase(q); 00225 } 00226 } 00227 00228 return true; 00229 } 00230 00231 00232 bool CMOOSNavTopDownCalEngine::GetXYZ(double &dfX, 00233 double &dfY, 00234 double &dfZ, 00235 double dfTime, 00236 double dfTolerance) 00237 { 00238 dfZ = 0; 00239 00240 OBSLIST * pGPSX = m_pStore->GetListByType(CMOOSObservation::X); 00241 OBSLIST * pGPSY = m_pStore->GetListByType(CMOOSObservation::Y); 00242 00243 if(pGPSX==NULL || pGPSY==NULL) 00244 { 00245 AddToOutput("TDC: Cannot locate GPS data..is iGPS running?"); 00246 MOOSPause(2000); 00247 return false; 00248 } 00249 00250 if(pGPSX->empty() || pGPSY->empty()) 00251 return false; 00252 00253 OBSLIST::iterator q,w; 00254 w = pGPSX->end(); 00255 double dfMinDT = 1e9; 00256 for(q = pGPSX->begin();q!=pGPSX->end();q++) 00257 { 00258 double dfDT =fabs((*q).m_dfTime -dfTime); 00259 if( dfDT<dfTolerance && dfDT<dfMinDT) 00260 { 00261 w = q; 00262 dfMinDT = dfDT; 00263 } 00264 } 00265 if(w == pGPSX->end()) 00266 { 00267 return false; 00268 } 00269 dfX = (*w).m_dfData; 00270 00271 00272 00273 dfMinDT = 1e9; 00274 w = pGPSY->end(); 00275 for(q = pGPSY->begin();q!=pGPSY->end();q++) 00276 { 00277 double dfDT =fabs((*q).m_dfTime -dfTime); 00278 if( dfDT<dfTolerance && dfDT<dfMinDT) 00279 { 00280 w = q; 00281 dfMinDT = dfDT; 00282 } 00283 } 00284 00285 if(w == pGPSY->end()) 00286 { 00287 return false; 00288 } 00289 dfY = (*w).m_dfData; 00290 00291 00292 return true; 00293 } 00294 00295 00296 double CMOOSNavTopDownCalEngine::GetPathLength() 00297 { 00298 00299 if(m_VantagePoints.size()<2) 00300 return 0; 00301 00302 double dfXLast = m_VantagePoints.front().m_dfX; 00303 double dfYLast = m_VantagePoints.front().m_dfY; 00304 double dfXNow = 0; 00305 double dfYNow = 0; 00306 double dfS = 0; 00307 00308 VANTAGEPOINT_LIST::iterator p; 00309 00310 for(p = m_VantagePoints.begin();p!=m_VantagePoints.end();p++) 00311 { 00312 CVantagePoint & rVP = *p; 00313 00314 dfXNow = p->m_dfX; 00315 dfYNow = p->m_dfY; 00316 00317 dfS+=sqrt(pow(dfXNow-dfXLast,2)+pow(dfYNow-dfYLast,2)); 00318 00319 dfXLast = dfXNow; 00320 dfYLast = dfYNow; 00321 00322 } 00323 00324 // MOOSTrace("Paths Length = %f\n",dfS); 00325 return dfS; 00326 } 00327 00328 00329 bool CMOOSNavTopDownCalEngine::MakeVantagePoints() 00330 { 00331 OBSLIST * pAcoustic = m_pStore->GetListByType(CMOOSObservation::LBL_BEACON_2WR); 00332 00333 if(pAcoustic==NULL) 00334 return false; 00335 00336 if(pAcoustic->size()<10) 00337 return true; 00338 00339 OBSLIST::iterator p; 00340 00341 //build a list using only the observations on our selected 00342 //channel... 00343 double dfX,dfXOld=0; 00344 double dfY,dfYOld=0; 00345 double dfZ; 00346 00347 00348 for(p = pAcoustic->begin();p!=pAcoustic->end();p++) 00349 { 00350 CMOOSObservation & rObs = *p; 00351 00352 if(rObs.m_nChan==m_nSelectedChan) 00353 { 00354 00355 if(GetXYZ(dfX,dfY,dfZ,rObs.m_dfTime,0.5)) 00356 { 00357 00358 double dfS = sqrt(pow(dfX-dfXOld,2)+pow(dfY-dfYOld,2)); 00359 00360 if(dfS>m_dfSpacing || p == pAcoustic->begin() ) 00361 { 00362 CVantagePoint VP; 00363 00364 VP.m_dfX = dfX; 00365 VP.m_dfY = dfY; 00366 VP.m_dfZ = 0; 00367 00368 VP.m_dfTOF = rObs.m_dfData; 00369 VP.m_dfTOFStd = rObs.m_dfDataStd; 00370 VP.m_dfTime = rObs.m_dfTime; 00371 VP.m_pInterrogateSensor = rObs.m_pInterrogateSensor; 00372 00373 m_VantagePoints.push_back(VP); 00374 00375 dfXOld = dfX; 00376 dfYOld = dfY; 00377 } 00378 } 00379 } 00380 } 00381 00382 return !m_VantagePoints.empty(); 00383 } 00384 00385 bool CMOOSNavTopDownCalEngine::MakePseudoBeacons() 00386 { 00387 //need a certain number to be able to solve in any case.. 00388 if(m_VantagePoints.size()<3) 00389 { 00390 return false; 00391 } 00392 00393 CMOOSNavBeacon* pB = GetBeaconByChannel(m_nSelectedChan); 00394 double dfTAT = pB->m_dfTAT; 00395 00396 VANTAGEPOINT_LIST::iterator p; 00397 00398 int nBcn = 0; 00399 for(p = m_VantagePoints.begin();p!=m_VantagePoints.end();p++) 00400 { 00401 CVantagePoint & rVP = *p; 00402 00403 string sName = MOOSFormat("B%d[%7.2f,%7.2f]", 00404 nBcn++, 00405 rVP.m_dfX, 00406 rVP.m_dfY); 00407 00408 AddAcousticBeacon( sName, 00409 m_nSelectedChan, 00410 dfTAT, 00411 rVP.m_dfX, 00412 rVP.m_dfY, 00413 0); 00414 00415 //fetch newly added beacons... 00416 CMOOSNavBeacon* pNewBeacon = GetBeaconByName(sName); 00417 pNewBeacon->m_bPseudo = true; 00418 00419 if(pNewBeacon) 00420 { 00421 rVP.m_pRespondingSensor = pNewBeacon->GetSensorByType(CMOOSNavSensor::LBL); 00422 } 00423 00424 } 00425 00426 return true; 00427 } 00428 00429 bool CMOOSNavTopDownCalEngine::MakeObservations() 00430 { 00431 m_Observations.clear(); 00432 m_FixedObservations.clear(); 00433 00434 VANTAGEPOINT_LIST::iterator p; 00435 for(p = m_VantagePoints.begin();p!=m_VantagePoints.end();p++) 00436 { 00437 CVantagePoint & rVP = *p; 00438 CMOOSObservation NewObs; 00439 NewObs.m_eType=CMOOSObservation::LBL_BEACON_2WR; 00440 NewObs.m_dfTime = rVP.m_dfTime; 00441 NewObs.m_dfData = rVP.m_dfTOF; 00442 NewObs.m_dfDataStd = rVP.m_dfTOFStd; 00443 NewObs.m_pInterrogateSensor = rVP.m_pInterrogateSensor; 00444 NewObs.m_pRespondingSensor = rVP.m_pRespondingSensor; 00445 00446 m_Observations.push_back(NewObs); 00447 } 00448 00449 //finally make things observable... 00450 AddFixedObservation(CMOOSObservation::YAW,0,0.1); 00451 AddFixedObservation(CMOOSObservation::TIDE,0,0.1); 00452 00453 //guess a depth... 00454 double dfGuessDepth = -10.0; 00455 00456 map<int,int>::iterator q = m_GuessedDepths.find(m_nSelectedChan); 00457 if(q!=m_GuessedDepths.end()) 00458 { 00459 dfGuessDepth = -(q->second); 00460 } 00461 AddToOutput("Guessing Depth of %f m\n",-dfGuessDepth); 00462 00463 00464 AddFixedObservation(CMOOSObservation::DEPTH,dfGuessDepth,2.0); 00465 00466 m_Observations.insert( m_Observations.begin(), 00467 m_FixedObservations.begin(), 00468 m_FixedObservations.end()); 00469 00470 00471 return true; 00472 } 00473 00474 bool CMOOSNavTopDownCalEngine::Clean() 00475 { 00476 m_Observations.clear(); 00477 m_FixedObservations.clear(); 00478 m_VantagePoints.clear(); 00479 m_GuessedDepths.clear(); 00480 00481 return true; 00482 } 00483 00484 00485 bool CMOOSNavTopDownCalEngine::SetFocus(int nChannel) 00486 { 00487 m_nSelectedChan=nChannel; 00488 00489 return true; 00490 } 00491 00492 00493 bool CMOOSNavTopDownCalEngine::OnRxTopDownControl(string sInstruction) 00494 { 00495 MOOSToUpper(sInstruction); 00496 if(MOOSStrCmp(sInstruction,"STOP")) 00497 { 00498 SetOnline(false); 00499 SetState(OFFLINE); 00500 return true; 00501 } 00502 else if(MOOSStrCmp(sInstruction,"START")) 00503 { 00504 OnStart(); 00505 00506 return true; 00507 } 00508 else if(MOOSStrCmp(sInstruction,"CALCULATE")) 00509 { 00510 //ok try and calculate now.... 00511 return Calculate(MOOSTime()); 00512 } 00513 else if(sInstruction.find("FOCUS")!=string::npos) 00514 { 00515 MOOSChomp(sInstruction,"="); 00516 int nNew = atoi(sInstruction.c_str()); 00517 if(nNew!=0) 00518 { 00519 m_nActiveChannel = nNew; 00520 AddToOutput("Manual set of TDC focus to channel %d",nNew); 00521 SetFocus(nNew); 00522 } 00523 } 00524 else 00525 { 00526 AddToOutput("Unknown top down cal control command"); 00527 return false; 00528 } 00529 00530 return true; 00531 } 00532 00533 bool CMOOSNavTopDownCalEngine::SetState(State eState) 00534 { 00535 m_eState = eState; 00536 00537 AddToOutput("Top Down Cal is %s\n", 00538 GetStateAsString(m_eState).c_str()); 00539 00540 00541 00542 return true; 00543 00544 } 00545 00546 string CMOOSNavTopDownCalEngine::GetStateAsString(State eState) 00547 { 00548 switch(eState) 00549 { 00550 case OFFLINE: return "OFFLINE"; 00551 case GATHERING: return "GATHERING"; 00552 case THINKING: return "THINKING"; 00553 } 00554 return ""; 00555 } 00556 00557 bool CMOOSNavTopDownCalEngine::OnStart() 00558 { 00559 00560 //start with a clean slate... 00561 m_pStore->Flush(); 00562 00563 if(m_nSelectedChan==-1) 00564 { 00565 AddToOutput("TDC: no focus channel specified"); 00566 return false; 00567 } 00568 00569 //the minute we start we are gathering data... 00570 SetState(GATHERING); 00571 SetOnline(true); 00572 00573 return true; 00574 } 00575 00576 00577 bool CMOOSNavTopDownCalEngine::IndicateGatherProgress() 00578 { 00579 00580 AddToOutput("%.1f m travelled %d observations gathered", 00581 GetPathLength(), 00582 m_Observations.size()); 00583 00584 return true; 00585 } 00586 00587 bool CMOOSNavTopDownCalEngine::SeedSolution() 00588 { 00589 //we will take the mean position of the vantage points 00590 //in and y 00591 00592 VANTAGEPOINT_LIST::iterator p; 00593 00594 double dfXMean=0; 00595 double dfYMean=0; 00596 00597 for(p = m_VantagePoints.begin();p!=m_VantagePoints.end();p++) 00598 { 00599 CVantagePoint & rVP = *p; 00600 00601 dfXMean += p->m_dfX; 00602 dfYMean += p->m_dfY; 00603 } 00604 00605 dfXMean/=m_VantagePoints.size(); 00606 dfYMean/=m_VantagePoints.size(); 00607 00608 m_pTracked->m_State.m_dfX = dfXMean; 00609 m_pTracked->m_State.m_dfY = dfYMean; 00610 m_pTracked->m_State.m_dfZ = -m_dfTide; 00611 00612 00613 return m_pTracked->RefreshStateVector(); 00614 00615 } 00616 00617 00618 bool CMOOSNavTopDownCalEngine::Calculate(double dfTimeNow) 00619 { 00620 00621 AddToOutput("TDC: Attempting to calculate"); 00622 00623 if(!MakePseudoBeacons()) 00624 return false; 00625 00626 AddToOutput("TDC: Pseudo Beacons Made OK"); 00627 00628 if(!MakeObservations()) 00629 return false; 00630 00631 AddToOutput("TDC: made observations"); 00632 00633 00634 //send progress information.. 00635 IndicateGatherProgress(); 00636 00637 00638 //make an intial guess... 00639 SeedSolution(); 00640 00641 for(int nIteration = 0;nIteration<m_nLSQIterations;nIteration++) 00642 { 00643 if(MakeObsMatrices()) 00644 { 00645 switch(Solve()) 00646 { 00647 case LSQ_NO_SOLUTION: 00648 // StatusMessage("FAILED TO SOLVE TDC"); 00649 MOOSTrace("FAILED TO SOLVE TDC"); 00650 return false; 00651 00652 case LSQ_IN_PROGRESS: 00653 break; 00654 00655 case LSQ_SOLVED: 00656 if(!DoWStatistic()) 00657 { 00658 //we will have removed the observation 00659 //that is not fitting...try to iterate again.. 00660 nIteration = 0; 00661 break; 00662 } 00663 else 00664 { 00665 return OnSolved(); 00666 } 00667 } 00668 } 00669 } 00670 00671 //if we have spect ages trying to figure it out we had better bail 00672 if(m_nNoConvergenceCounter++>FAILED_CONVERGENCE_LIMIT) 00673 { 00674 AddToOutput("Could not solve for beacon (no convergence)... "); 00675 } 00676 00677 return true; 00678 00679 } 00680 00681 00682 double CMOOSNavTopDownCalEngine::GetRequiredPathLength() 00683 { 00684 return m_dfCalPathLength; 00685 }