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 at MIT 2001-2002 and Oxford 00010 // University 2003-2005. email: pnewman@robots.ox.ac.uk. 00011 // 00012 // This file is part of a MOOS Utility Component. 00013 // 00014 // This program is free software; you can redistribute it and/or 00015 // modify it under the terms of the GNU General Public License as 00016 // published by the Free Software Foundation; either version 2 of the 00017 // License, or (at your option) any later version. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 // General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with this program; if not, write to the Free Software 00026 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00027 // 02111-1307, USA. 00028 // 00030 00031 // SimpleAUVSim.cpp: implementation of the CMVSim class. 00032 // 00034 #include <MOOSLIB/MOOSLib.h> 00035 #include <MOOSGenLib/MOOSGenLib.h> 00036 #include "AcousticResponder.h" 00037 #include "MVSim.h" 00038 #include "math.h" 00039 #include <iostream> 00040 #include <iomanip> 00041 using namespace std; 00042 00043 00044 #include "AcousticIntersection.h" 00045 00047 // Construction/Destruction 00049 00050 00051 00052 00053 CMVSim::CMVSim() 00054 { 00055 m_dfSimulatorTime = 0.0; 00056 m_dfLastMailed = 0.0; 00057 m_dfUpdateRate = 5.0; 00058 m_dfOldSimulatorTime = 0; 00059 00060 m_dfStartTime = MOOSTime(); 00061 00062 m_bInitialised = false; 00063 00064 m_bRealTime = true; 00065 00066 SetAppFreq(10); 00067 SetCommsFreq(20); 00068 } 00069 00070 CMVSim::~CMVSim() 00071 { 00072 00073 } 00074 00075 //this will be called for us automatically 00076 bool CMVSim::OnConnectToServer() 00077 { 00078 return DoRegistrations(); 00079 } 00080 00081 00082 bool CMVSim::DoRegistrations() 00083 { 00084 SIM_ENTITY_LIST::iterator p; 00085 00086 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00087 { 00088 CSimEntity* pEntity = *p; 00089 00090 CSixDOFAUV* pAUV = dynamic_cast<CSixDOFAUV*> (pEntity); 00091 00092 if(pAUV) 00093 { 00094 m_Comms.Register(pAUV->m_sInputPrefix+"DESIRED_THRUST",0.0); 00095 m_Comms.Register(pAUV->m_sInputPrefix+"DESIRED_ELEVATOR",0.02); 00096 m_Comms.Register(pAUV->m_sInputPrefix+"DESIRED_RUDDER",0.02); 00097 } 00098 } 00099 00100 00101 m_Comms.Register("SIM_RESET",0.02); 00102 m_Comms.Notify("SIMULATION_MODE","TRUE"); 00103 00104 return true; 00105 } 00106 00107 bool CMVSim::OnNewMail(MOOSMSG_LIST &NewMail) 00108 { 00109 //someone has changed one of the variable we were intersted in! 00110 MOOSMSG_LIST::iterator p; 00111 00112 00113 00114 for(p=NewMail.begin();p!=NewMail.end();p++) 00115 { 00116 00117 CMOOSMsg & rMsg = *p; 00118 00119 CSixDOFAUV * pAUV = GetSubscriber(rMsg.m_sKey); 00120 00121 if(pAUV) 00122 { 00123 //we now know which AUV wants this control data.. 00124 if(rMsg.m_sKey.find("DESIRED_ELEVATOR")!=string::npos) 00125 { 00126 pAUV->m_dfElevator = MOOSDeg2Rad(rMsg.m_dfVal); 00127 continue; 00128 } 00129 else if(rMsg.m_sKey.find("DESIRED_RUDDER")!=string::npos) 00130 { 00131 pAUV->m_dfRudder = MOOSDeg2Rad(rMsg.m_dfVal); 00132 continue; 00133 } 00134 else if(rMsg.m_sKey.find("DESIRED_THRUST")!=string::npos) 00135 { 00136 pAUV->m_dfThrust = rMsg.m_dfVal; 00137 continue; 00138 } 00139 } 00140 00141 if(MOOSStrCmp(rMsg.m_sKey,"SIM_RESET")) 00142 { 00143 Initialise(); 00144 } 00145 } 00146 00147 return true; 00148 } 00149 00150 00151 // who of teh AUVs want to rx this data (look at prefixes) 00152 CSixDOFAUV * CMVSim::GetSubscriber(const std::string & sName) 00153 { 00154 //index to entities... 00155 SIM_ENTITY_LIST::iterator p; 00156 00157 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00158 { 00159 CSimEntity* pEntity = *p; 00160 00161 CSixDOFAUV* pAUV = dynamic_cast<CSixDOFAUV*> (pEntity); 00162 00163 if(pAUV) 00164 { 00165 std::string sPrefix = pAUV->m_sInputPrefix; 00166 00167 if(MOOSStrCmp(sName.substr(0,sPrefix.length()),sPrefix)) 00168 { 00169 return pAUV; 00170 } 00171 } 00172 } 00173 00174 return NULL; 00175 } 00176 00177 bool CMVSim::Iterate() 00178 { 00179 00180 00181 //have we initialised? 00182 if(!m_bInitialised) 00183 { 00184 00185 Initialise(); 00186 } 00187 00188 00190 // sort timing out 00192 00193 double dfDT = 0; 00194 00195 //here we decide what the increment in time is... 00196 if(m_bRealTime) 00197 { 00198 //we will go at real world speed. 00199 dfDT = MOOSTime()-m_dfSimulatorTime; 00200 00201 00202 if(dfDT==0) 00203 { 00204 return true; 00205 } 00206 } 00207 else 00208 { 00209 //coarse DT is 0.1 seconds..good as any... 00210 dfDT = 0.1; 00211 SetAppFreq(int(1/dfDT)); 00212 } 00213 00214 00215 //the epoch ends at: 00216 double dfEndTime = m_dfSimulatorTime +dfDT; 00217 00218 00219 //but we want a fine granularity within this epoch of 00220 //better than 10 ms. 00221 //and within this we shall perform linear interpolation. 00222 double dfSmallDT = dfDT; 00223 int nDiv = 1; 00224 00225 do 00226 { 00227 00228 dfSmallDT = dfDT/(nDiv++); 00229 00230 }while(dfSmallDT>0.01); 00231 00232 00233 00235 // now propagate models..... 00237 00238 while(m_dfSimulatorTime<=dfEndTime) 00239 { 00240 00241 //index to entities... 00242 SIM_ENTITY_LIST::iterator p; 00243 00244 00245 //move all entities - Newton(1:3) still rule even in the 00246 //new millenium 00247 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00248 { 00249 CSimEntity* pEntity = *p; 00250 pEntity->Iterate(m_dfSimulatorTime,dfSmallDT); 00251 } 00252 00253 //MOOSTrace("\n\nAbout To Solve Acoustics\n"); 00254 //look for intersection with signals 00255 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00256 { 00257 CSimEntity* pEntity = *p; 00258 00259 pEntity->SolveAcoustics(m_dfSimulatorTime,dfSmallDT); 00260 00261 } 00262 00263 //move just a wee bit forward in time... 00264 m_dfSimulatorTime+=dfSmallDT; 00265 00266 }//completed epoch... 00267 00268 00269 00270 // housekeeping - remove old pings in the water column.. 00271 m_Environment.RemoveOldSignals(m_dfSimulatorTime); 00272 00273 00274 00276 // Tell the world what has happened // 00278 00279 //MOOSTrace("Posting @ %f\n",MOOSTime()); 00280 PostResults(); 00281 00282 00283 00284 return true; 00285 } 00286 00287 00288 00289 00290 00291 bool CMVSim::NeedToMail() 00292 { 00293 return m_dfSimulatorTime-m_dfLastMailed>1.0/m_dfUpdateRate; 00294 00295 } 00296 00297 00298 bool CMVSim::OnStartUp() 00299 { 00300 Initialise(); 00301 00302 DoRegistrations(); 00303 00304 return true; 00305 } 00306 00307 bool CMVSim::Initialise() 00308 { 00309 00310 00311 00312 Clean(); 00313 00314 SetAppFreq(50); 00315 00316 m_dfLastMailed = 0.0; 00317 00318 00319 if(m_bRealTime) 00320 { 00321 m_dfStartTime = MOOSTime(); 00322 m_dfSimulatorTime = m_dfStartTime; 00323 } 00324 else 00325 { 00326 m_dfAppStartTime=0.0; 00327 m_dfStartTime = 0.0; 00328 m_dfSimulatorTime = 0.0; 00329 } 00330 m_dfOldSimulatorTime = m_dfSimulatorTime; 00331 00332 m_Environment.SetStartTime(m_dfSimulatorTime); 00333 00334 //now load in terrain data 00335 string sTerrainFile= "terrain.dat"; 00336 m_MissionReader.GetValue("TerrainFile",sTerrainFile); 00337 00338 if(!m_Environment.Initialise(sTerrainFile.c_str())) 00339 { 00340 MOOSTrace("warning environment failed to build\n"); 00341 } 00342 00343 // load general parameters from process config block 00344 STRING_LIST sParams; 00345 m_MissionReader.GetConfiguration(GetAppName(),sParams); 00346 m_Params.Load(sParams); 00347 00348 //load some others in 00349 m_MissionReader.GetConfigurationParam("TideHeight",m_Environment.m_dfTideHeight); 00350 m_MissionReader.GetValue("MagneticOffset",m_Environment.m_dfMagneticOffset); 00351 00352 00353 00354 //populate with vehicles and beacons 00355 STRING_LIST::iterator p; 00356 for(p = sParams.begin();p!=sParams.end();p++) 00357 { 00358 std::string sTmp = *p; 00359 std::string sTok,sVal; 00360 CMOOSFileReader::GetTokenValPair(sTmp,sTok,sVal); 00361 if(MOOSStrCmp(sTok,"ADD_AUV")) 00362 { 00363 MakeAUV(sVal); 00364 } 00365 else if(MOOSStrCmp(sTok,"ADD_TRANSPONDER")) 00366 { 00367 MakeBeacon(sVal); 00368 } 00369 } 00370 00371 00372 //open log file 00373 OpenLogFile(); 00374 00375 //log all entities' initial state 00376 LogStartConditions(); 00377 00378 00379 m_bInitialised = true; 00380 00381 return true; 00382 } 00383 00384 00385 00386 00387 void CMVSim::PostResults() 00388 { 00389 if(NeedToMail()) 00390 { 00391 //index to entities... 00392 SIM_ENTITY_LIST::iterator p; 00393 00394 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00395 { 00396 CSimEntity* pEntity = *p; 00397 00398 CSixDOFAUV* pAUV = dynamic_cast<CSixDOFAUV*> (pEntity); 00399 00400 if(pAUV==NULL) 00401 continue; 00402 00403 double dfX = pAUV->GetX(); 00404 if(m_Params.m_bAddNoise) 00405 dfX+=MOOSWhiteNoise(m_Params.m_dfXYStd); 00406 00407 double dfY = pAUV->GetY(); 00408 if(m_Params.m_bAddNoise) 00409 dfY+=MOOSWhiteNoise(m_Params.m_dfXYStd); 00410 00411 double dfZ = pAUV->GetZ(); 00412 if(m_Params.m_bAddNoise) 00413 dfZ+=MOOSWhiteNoise(m_Params.m_dfZStd); 00414 00415 double dfYaw = pAUV->GetYaw(); 00416 if(m_Params.m_bAddNoise) 00417 { 00418 dfYaw+=MOOSWhiteNoise(m_Params.m_dfYawStd); 00419 dfYaw+=m_Params.m_dfYawBias; 00420 } 00421 00422 double dfDepth = pAUV->GetDepth(); 00423 if(m_Params.m_bAddNoise) 00424 dfDepth+=MOOSWhiteNoise(m_Params.m_dfZStd); 00425 00426 double dfBodyVelY = pAUV->GetBodyVelY(); 00427 if(m_Params.m_bAddNoise) 00428 dfBodyVelY+=MOOSWhiteNoise(m_Params.m_dfXYVelStd); 00429 00430 double dfBodyVelX = pAUV->GetBodyVelX(); 00431 if(m_Params.m_bAddNoise) 00432 dfBodyVelX+=MOOSWhiteNoise(m_Params.m_dfXYVelStd); 00433 00434 double dfSpeed = pAUV->GetSpeed(); 00435 if(m_Params.m_bAddNoise) 00436 dfSpeed=hypot(dfBodyVelY,dfBodyVelX); 00437 00438 double dfHeading = pAUV->GetHeading(); 00439 if(m_Params.m_bAddNoise) 00440 dfHeading = -MOOSRad2Deg(dfYaw); 00441 00442 std::string sP = pAUV->m_sOutputPrefix; 00443 00444 m_Comms.Notify(sP+"X",dfX); 00445 m_Comms.Notify(sP+"Y",dfY); 00446 m_Comms.Notify(sP+"Z",dfZ); 00447 m_Comms.Notify(sP+"YAW",dfYaw); 00448 m_Comms.Notify(sP+"DEPTH",dfDepth); 00449 m_Comms.Notify(sP+"SPEED",dfSpeed); 00450 m_Comms.Notify(sP+"HEADING",dfHeading); 00451 m_Comms.Notify(sP+"BODY_VEL_Y",dfBodyVelY); 00452 m_Comms.Notify(sP+"BODY_VEL_X",dfBodyVelX); 00453 m_Comms.Notify(sP+"PITCH",pAUV->GetPitch()); 00454 00455 00456 if(pAUV->GetAltitude()>=0) 00457 { 00458 m_Comms.Notify(sP+"ALTITUDE",pAUV->GetAltitude()); 00459 } 00460 00461 } 00462 00463 m_Comms.Notify("TIDE_HEIGHT",m_Environment.GetTideHeight()); 00464 m_dfLastMailed = m_dfSimulatorTime; 00465 00466 } 00467 00468 //finally get all Msg that have appeared in Environments 00469 //out box, this allows objects from anywhere to send notifications 00470 MOOSMSG_LIST::iterator q; 00471 for(q = m_Environment.m_MailOut.begin();q!=m_Environment.m_MailOut.end();q++) 00472 { 00473 //MOOSTrace("Sending Env :%s\n",q->GetString().c_str()); 00474 m_Comms.Post(*q); 00475 } 00476 00477 if(!m_Environment.m_MailOut.empty()) 00478 { 00479 // MOOSTrace("Sent %d Mesg from Environment\n",m_Environment.m_MailOut.size()); 00480 m_Environment.m_MailOut.clear(); 00481 } 00482 00483 00484 //log all entities 00485 SIM_ENTITY_LIST::iterator p; 00486 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00487 { 00488 (*p)->LogState(m_dfSimulatorTime); 00489 } 00490 00491 00492 00493 00494 } 00495 00496 00497 bool CMVSim::Clean() 00498 { 00499 SIM_ENTITY_LIST::iterator p; 00500 00501 00502 //move all entities 00503 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00504 { 00505 CSimEntity* pEntity = *p; 00506 delete pEntity; 00507 } 00508 m_Entities.clear(); 00509 00510 m_Environment.Clean(); 00511 00512 return true; 00513 } 00514 00516 bool CMVSim::MakeAUV(std::string sConfig) 00517 { 00518 00519 //ADD_AUV= pose=[3x1]{7,3,4,5},name = AUV1,InputPrefix=AUV1,OutputPrefix=AUV1 00520 CSixDOFAUV * pAUV = new CSixDOFAUV; 00521 try 00522 { 00523 //give it a parameter block 00524 pAUV->SetParams(&m_Params); 00525 00526 pAUV->Initialise(); 00527 00528 //where is it? 00529 std::vector<double> T; int nR,nC; 00530 if(MOOSValFromString(T,nR,nC,sConfig,"pose")) 00531 { 00532 if(nR !=4) 00533 { 00534 throw CMOOSException(MOOSFormat("pose must be a 4 vector %s\n",MOOSHERE)); 00535 } 00536 pAUV->SetX(T[0]); 00537 pAUV->SetY(T[1]); 00538 pAUV->SetZ(T[2]); 00539 pAUV->SetYaw(T[3]); 00540 00541 } 00542 00543 //whats it called 00544 std::string sName; 00545 if(!MOOSValFromString(sName,sConfig,"name")) 00546 throw CMOOSException(MOOSFormat("AUV has no name! %s\n",MOOSHERE)); 00547 00548 00549 pAUV->SetName(sName); 00550 00551 00552 //how will control be sent to it and positions be emmited? 00553 std::string sInputPrefix="SIM"; //this would mean it Rxs SIM_DESIRED_RUDDER 00554 std::string sOutputPrefix="SIM";//and publishes SIM_X etc... 00555 00556 if(!MOOSValFromString(sInputPrefix,sConfig,"InputPrefix")) 00557 { 00558 throw CMOOSException(MOOSFormat("No Input prefix defined - assuming %s\n",sInputPrefix.c_str())); 00559 } 00560 if(!MOOSValFromString(sOutputPrefix,sConfig,"OutputPrefix")) 00561 { 00562 throw CMOOSException(MOOSFormat("No OutputPrefix defined - assuming %s\n",sOutputPrefix.c_str())); 00563 } 00564 00565 pAUV->SetInputPrefix(sInputPrefix); 00566 pAUV->SetOutputPrefix(sOutputPrefix); 00567 00568 //tell it about teh world 00569 pAUV->SetEnvironment(&m_Environment); 00570 00571 //what channel does it reply to interrogations on? 00572 std::string sChannelResponder = "Ch2"; 00573 if(!MOOSValFromString(sChannelResponder,sConfig,"ResponderChannel")) 00574 { 00575 MOOSTrace("No ResponderChannel defined - assuming no Responder required \n"); 00576 00577 //turn it off - other parameters don't matter 00578 pAUV->ConfigureResponder(false,ACOUSTIC_CHAN_CIF,ACOUSTIC_CHAN_CIF,-1); 00579 00580 } 00581 else 00582 { 00583 AcousticChannel eCh = CAcousticSignal::ChannelFromString(sChannelResponder); 00584 00585 //what is its TAT on interrogations? 00586 double dfTAT = 0.125; 00587 if(!MOOSValFromString(dfTAT,sConfig,"TAT")) 00588 { 00589 throw CMOOSException(MOOSFormat("No TAT defined - assuming %f\n",dfTAT)); 00590 } 00591 00592 //turn it on.. 00593 pAUV->ConfigureResponder(true,ACOUSTIC_CHAN_CIF,eCh,dfTAT); 00594 } 00595 //store it 00596 m_Entities.push_front(pAUV); 00597 } 00598 catch(CMOOSException e) 00599 { 00600 delete pAUV; 00601 return MOOSFail(e.m_sReason); 00602 } 00603 00604 return true; 00605 00606 00607 } 00608 00609 00610 00611 bool CMVSim::MakeBeacon(std::string sConfig) 00612 { 00613 //"ADD_TRANSPONDER = Name = B1,pose=[3x1]{23, 45, 0},TAT = 0.125,RX = CH8 | CH9 | C10,TX = CIF 00614 00615 CAcousticBeacon * pBeacon = new CAcousticBeacon; 00616 try 00617 { 00618 00619 std::vector<double> T; int nR,nC; 00620 if(MOOSValFromString(T,nR,nC,sConfig,"pose")) 00621 { 00622 if(nR !=3) 00623 { 00624 return MOOSFail("pose must be a 3 vector %s\n",MOOSHERE); 00625 } 00626 pBeacon->m_Pos_e<<T[0] 00627 <<T[1] 00628 <<T[2] 00629 <<0 00630 <<0 00631 <<0; 00632 } 00633 00634 //whats it called 00635 std::string sName; 00636 if(!MOOSValFromString(sName,sConfig,"name")) 00637 throw CMOOSException(MOOSFormat("Beacon has no name! %s %s\n",sConfig.c_str(),MOOSHERE)); 00638 pBeacon->SetName(sName); 00639 00640 std::string sTx; 00641 if(!MOOSValFromString(sTx,sConfig,"Tx")) 00642 throw CMOOSException(MOOSFormat("Beacon has no Tx field %s %s\n",sConfig.c_str(),MOOSHERE)); 00643 00644 00645 ACOUSTIC_NODE_LIST AcousticNodes; 00646 pBeacon->GetAcousticNodes(AcousticNodes); 00647 00648 AcousticChannel eChan = CAcousticSignal::ChannelFromString(sTx); 00649 00650 if( eChan==ACOUSTIC_CHAN_ERROR || 00651 !AcousticNodes.front()->SetTxChan(eChan)) 00652 { 00653 throw CMOOSException(MOOSFormat("error setting Tx Channel on beacon %s\n",sName.c_str())); 00654 } 00655 00656 std::string sRx; 00657 if(!MOOSValFromString(sTx,sConfig,"Rx")) 00658 throw CMOOSException(MOOSFormat("Beacon has no Rx field %s %s\n",sConfig.c_str(),MOOSHERE)); 00659 00660 00661 00662 while(!sRx.empty()) 00663 { 00664 string sChan = MOOSChomp(sRx,"|"); 00665 00666 AcousticChannel eChan = CAcousticSignal::ChannelFromString(sChan); 00667 00668 if( eChan==ACOUSTIC_CHAN_ERROR || 00669 !AcousticNodes.front()->SetRxChan(eChan,true)) 00670 { 00671 MOOSTrace("error setting Rx Channel on beacon\n"); 00672 } 00673 }//for all channels 00674 00675 00677 // set up TAT 00679 00680 double dfTAT; 00681 if(!MOOSValFromString(dfTAT,sConfig,"TAT")) 00682 throw CMOOSException(MOOSFormat("Beacon has no TAT field %s %s\n",sConfig.c_str(),MOOSHERE)); 00683 00684 00685 CAcousticResponder * pResponder = dynamic_cast<CAcousticResponder*>(AcousticNodes.front()); 00686 if(pResponder!=NULL) 00687 { 00688 pResponder->SetTAT(dfTAT); 00689 } 00690 00691 //final set up of beacon... 00692 pBeacon->SetEnvironment(&m_Environment); 00693 00694 pBeacon->SetParams(&m_Params); 00695 00696 m_Entities.push_front(pBeacon); 00697 } 00698 catch (CMOOSException e) 00699 { 00700 delete pBeacon; 00701 return MOOSFail(e.m_sReason); 00702 } 00703 00704 return true; 00705 } 00706 00707 00708 00709 bool CMVSim::OpenLogFile() 00710 { 00711 //set up log file... 00712 if(!m_Params.m_sLogFileName.empty()) 00713 { 00714 //open and close ..truncates file 00715 ofstream os(m_Params.m_sLogFileName.c_str()); 00716 00717 os.close(); 00718 } 00719 return true; 00720 } 00721 00722 bool CMVSim::LogStartConditions() 00723 { 00724 SIM_ENTITY_LIST::iterator p; 00725 00726 if(!m_Params.m_sLogFileName.empty()) 00727 { 00728 //open and close ..truncates file 00729 ofstream os(m_Params.m_sLogFileName.c_str(),ios::app); 00730 00731 //start time... 00732 os.setf(ios::fixed,ios::floatfield); 00733 os<<setprecision(3); 00734 os<<"StartTime,T="<<setprecision(3)<<m_dfSimulatorTime<<endl; 00735 00736 //entity states 00737 for(p = m_Entities.begin();p!=m_Entities.end();p++) 00738 { 00739 (*p)->CSimEntity::LogState(m_dfSimulatorTime); 00740 } 00741 00742 00743 } 00744 00745 return true; 00746 }