MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/NavigationAndControl/MOOSNavLib/MOOSNavTopDownCalEngine.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 //
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines