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 // OrbitTask.cpp: implementation of the COrbitTask class. 00032 // 00034 #ifdef _WIN32 00035 #pragma warning(disable : 4786) 00036 #endif 00037 00038 #include "MOOSTaskDefaults.h" 00039 #include "OrbitTask.h" 00040 #include "math.h" 00041 00042 #include <vector> 00043 #include <sstream> 00044 #include <iostream> 00045 using namespace std; 00046 00047 00048 00050 // Construction/Destruction 00052 00053 COrbitTask::COrbitTask() 00054 { 00055 00056 m_nPriority = 3; 00057 00058 m_bInitialised = false; 00059 00060 m_dfVicinityRadius = 10; 00061 00062 m_bPositionSet = true; 00063 00064 m_bThrustSet = false; 00065 00066 m_dfThrust = 0; 00067 00068 m_nTotalPositions = ORBIT_DEFAULT_TOTAL_POSITIONS; 00069 00070 m_nOrbitDirection = CCW; 00071 00072 m_nTotalRepetitions = 0; 00073 00074 m_nRepCounter = 0; 00075 00076 m_dfPositionRadius = 2.0; 00077 } 00078 00079 COrbitTask::~COrbitTask() 00080 { 00081 m_XYPoints.clear(); 00082 } 00083 00084 00085 bool COrbitTask::OnNewMail(MOOSMSG_LIST &NewMail) 00086 { 00087 00088 CMOOSMsg Msg; 00089 if(PeekMail(NewMail,"NAV_X",Msg)) 00090 { 00091 if(!Msg.IsSkewed(GetTimeNow())) 00092 { 00093 m_XDOF.SetCurrent(Msg.m_dfVal,Msg.m_dfTime); 00094 } 00095 } 00096 if(PeekMail(NewMail,"NAV_Y",Msg)) 00097 { 00098 if(!Msg.IsSkewed(GetTimeNow())) 00099 { 00100 m_YDOF.SetCurrent(Msg.m_dfVal,Msg.m_dfTime); 00101 } 00102 } 00103 00104 if(PeekMail(NewMail,"NAV_YAW",Msg)) 00105 { 00106 if(!Msg.IsSkewed(GetTimeNow())) 00107 { 00108 00109 double dfVal = Msg.m_dfVal; 00110 00111 if(dfVal>PI) 00112 { 00113 dfVal-=2*PI; 00114 } 00115 // MOOSTrace("%s gets yaw = %f@ %f\n",m_sName.c_str(),dfVal,Msg.m_dfTime); 00116 m_YawDOF.SetCurrent(dfVal,Msg.m_dfTime); 00117 } 00118 00119 } 00120 00121 //always call base class version 00122 CMOOSBehaviour::OnNewMail(NewMail); 00123 00124 return true; 00125 } 00126 00127 bool COrbitTask::GetRegistrations(STRING_LIST &List) 00128 { 00129 List.push_front("NAV_X"); 00130 List.push_front("NAV_Y"); 00131 List.push_front("NAV_YAW"); 00132 00133 //always call base class version 00134 CMOOSBehaviour::GetRegistrations(List); 00135 00136 return true; 00137 } 00138 00139 00140 00141 //returns false if we haven't received data in a while..bad news! 00142 bool COrbitTask::RegularMailDelivery(double dfTimeNow) 00143 { 00144 if(m_YawDOF.IsStale(dfTimeNow,GetStartTime())) 00145 return false; 00146 00147 if(m_XDOF.IsStale(dfTimeNow,GetStartTime())) 00148 return false; 00149 00150 if(m_YDOF.IsStale(dfTimeNow,GetStartTime())) 00151 return false; 00152 00153 return true; 00154 } 00155 00156 00157 00158 bool COrbitTask::Run(CPathAction &DesiredAction) 00159 { 00160 if(!m_bPositionSet) 00161 { 00162 MOOSTrace("Orbit position not set\n");; 00163 return false; 00164 } 00165 00166 if(!m_bInitialised) 00167 { 00168 Initialise(); 00169 } 00170 00171 if(ShouldRun()) 00172 { 00173 00174 if(ValidData()) 00175 { 00176 00177 double dfDistanceToGo = sqrt(pow(m_YDOF.GetError(),2)+pow(m_XDOF.GetError(),2)); 00178 00179 00180 if(dfDistanceToGo<m_dfPositionRadius) 00181 { 00182 if(m_nRepCounter < m_nTotalRepetitions) 00183 { 00184 SetNextPointInOrbit(); 00185 } 00186 else 00187 { 00188 OnComplete(); 00189 } 00190 } 00191 else 00192 { 00193 00194 //calculate vector heading angle to goal 00195 double dfDesiredYaw = -atan2(m_XDOF.GetError(),m_YDOF.GetError()); 00196 00197 m_YawDOF.SetDesired(dfDesiredYaw); 00198 00199 double dfError = m_YawDOF.GetError(); 00200 00201 if(dfError<-PI) 00202 { 00203 dfError+=2*PI; 00204 } 00205 else if(dfError>PI) 00206 { 00207 dfError-=2*PI; 00208 } 00209 00210 double dfCmd = 0; 00211 00212 //this is for logging purposes only 00213 m_YawPID.SetGoal(m_YawDOF.GetDesired()); 00214 00215 if(m_YawPID.Run(dfError,m_YawDOF.GetErrorTime(),dfCmd)) 00216 { 00217 //OK we need to change something 00218 00219 DesiredAction.Set( ACTUATOR_RUDDER, 00220 -dfCmd, 00221 m_nPriority, 00222 GetName().c_str()); 00223 00224 00225 //set the thrust 00226 if(m_bThrustSet) 00227 { 00228 DesiredAction.Set( ACTUATOR_THRUST, 00229 m_dfThrust, 00230 m_nPriority, 00231 GetName().c_str()); 00232 } 00233 00234 00235 } 00236 } 00237 } 00238 } 00239 return true; 00240 } 00241 00242 bool COrbitTask::Initialise() 00243 { 00244 00245 m_YawDOF.SetDesired(0); 00246 m_YawDOF.SetTolerance(0.00); 00247 00248 //begin the loop-d-loop of points for this orbit 00249 SetNextPointInOrbit(); 00250 00251 m_bInitialised = true; 00252 00253 return m_bInitialised; 00254 } 00255 00256 bool COrbitTask::ValidData() 00257 { 00258 return m_XDOF.IsValid() && 00259 m_YDOF.IsValid() && 00260 m_YawDOF.IsValid(); 00261 } 00262 00263 00264 00265 bool COrbitTask::SetParam(string sParam, string sVal) 00266 { 00267 MOOSToUpper(sParam); 00268 MOOSToUpper(sVal); 00269 00270 00271 if(!CMOOSBehaviour::SetParam(sParam,sVal)) 00272 { 00273 //this is for us... 00274 if(sParam=="RADIUS") 00275 { 00276 m_dfVicinityRadius=atof(sVal.c_str()); 00277 } 00278 else if(sParam=="POSRADIUS") 00279 { 00280 m_dfPositionRadius=atof(sVal.c_str()); 00281 } 00282 00283 else if(sParam=="THRUST") 00284 { 00285 m_dfThrust=atof(sVal.c_str()); 00286 m_bThrustSet = true; 00287 } 00288 else if(sParam=="LOCATION") 00289 { 00290 //useful for later... 00291 m_sLocation = sVal; 00292 00293 string sTmpX = MOOSChomp(sVal,","); 00294 string sTmpY = MOOSChomp(sVal,","); 00295 string sTmpZ = MOOSChomp(sVal,","); 00296 00297 if(sTmpX.empty()||sTmpY.empty()||sTmpZ.empty()) 00298 { 00299 MOOSTrace("error in reading orbit location from file\n"); 00300 return false; 00301 } 00302 00303 //instead of setting this as the X,Y point to go to, 00304 //this information is actually the center of the circle 00305 //that we want to orbit 00306 double dfX = atof(sTmpX.c_str()); 00307 m_XOrbitCenter.SetDesired(dfX); 00308 00309 double dfY = atof(sTmpY.c_str()); 00310 m_YOrbitCenter.SetDesired(dfY); 00311 00312 } 00313 else if((sParam=="DIRECTION")) 00314 { 00315 //default is CCW, which is +1 for the multiplier 00316 if(sVal == "CW") 00317 { 00318 m_nOrbitDirection = CW; 00319 } 00320 else if(sVal == "CCW") 00321 { 00322 m_nOrbitDirection = CCW; 00323 } 00324 00325 } 00326 else if((sParam == "REPEAT")) 00327 { 00328 int nTotal = atoi(sVal.c_str()); 00329 //only accept positive values 00330 if((nTotal > 0) && (nTotal < ORBIT_MAX_TOTAL_REPETITION)) 00331 { 00332 m_nTotalRepetitions = nTotal; 00333 } 00334 else if((nTotal > 0) && (nTotal > ORBIT_MAX_TOTAL_REPETITION)) 00335 { 00336 m_nTotalRepetitions = ORBIT_MAX_TOTAL_REPETITION; 00337 } 00338 else 00339 { 00340 //default 00341 m_nTotalRepetitions = ORBIT_DEFAULT_TOTAL_REPETITION; 00342 } 00343 00344 } 00345 else if((sParam == "TOTALPOS") || (sParam == "SIDES")) 00346 { 00347 int nTotal = atoi(sVal.c_str()); 00348 //only accept positive values 00349 if((nTotal > 0) && (nTotal < ORBIT_MAX_TOTAL_POSITIONS)) 00350 { 00351 m_nTotalPositions = nTotal; 00352 } 00353 else if((nTotal > 0) && (nTotal > ORBIT_MAX_TOTAL_POSITIONS)) 00354 { 00355 m_nTotalPositions = ORBIT_MAX_TOTAL_POSITIONS; 00356 } 00357 else 00358 { 00359 //default 00360 m_nTotalPositions = ORBIT_DEFAULT_TOTAL_POSITIONS; 00361 } 00362 00363 } 00364 else 00365 { 00366 //hmmm - it wasn't for us at all: base class didn't understand either 00367 MOOSTrace("Param \"%s\" not understood!\n",sParam.c_str()); 00368 return false; 00369 } 00370 } 00371 00372 return true; 00373 } 00374 00375 00376 void COrbitTask::SetNextPointInOrbit() 00377 { 00378 //first time through, we need to make some calculations 00379 if(!m_bInitialised) 00380 { 00381 //always start by heading to the first position around the center 00382 m_nCurrentPosition = 0; 00383 //note the direction 00384 int nD = m_nOrbitDirection; 00385 //how many degrees are the points offset by 00386 int nDegSeparation = 360 / m_nTotalPositions; 00387 //note the radius here is the Vicinity, as this is how close to the 00388 //orbit center we will rotate around 00389 //m_dfPositionRadius defines how close we need to get to positions 00390 //to qualify our having been at a particular position 00391 double dfR = m_dfVicinityRadius; 00392 double dfXCenter= m_XOrbitCenter.GetDesired(); 00393 double dfYCenter= m_YOrbitCenter.GetDesired(); 00394 00395 //guarantee enough space 00396 m_XYPoints.clear(); 00397 m_XYPoints.resize(m_nTotalPositions + 1); 00398 00399 for(int i = 0; i < m_nTotalPositions; i++) 00400 { 00401 //CCW is default to rotate, represented by nD = 1 00402 int nTheta = 360 - (nD * (nDegSeparation * i)); 00403 double dfRad = nTheta * PI/180; 00404 00405 CXYPoint Position; 00406 00407 Position.SetX((dfXCenter + dfR*cos(dfRad))); 00408 Position.SetY((dfYCenter + dfR*sin(dfRad))); 00409 00410 m_XYPoints[i] = Position; 00411 00412 } 00413 00414 } 00415 else 00416 { 00417 //augment our current point we are heading to 00418 m_nCurrentPosition++; 00419 //make sure we go in a circle 00420 m_nCurrentPosition %= m_nTotalPositions; 00421 00422 //augment the reps 00423 if(m_nCurrentPosition == 0) 00424 { 00425 m_nRepCounter++; 00426 } 00427 00428 } 00429 00430 //announce where we are going to 00431 ostringstream os; 00432 00433 os<<"ORBIT - transiting to: pos["<<m_nCurrentPosition<<"]"<< 00434 " -> "<<m_XYPoints[m_nCurrentPosition].GetX()<<","<< 00435 m_XYPoints[m_nCurrentPosition].GetY()<<" - [REP : "<< 00436 m_nRepCounter<<"]"<<endl<<ends; 00437 00438 DebugNotify(os.str()); 00439 00440 //now set the point we are heading to 00441 m_XDOF.SetDesired(m_XYPoints[m_nCurrentPosition].GetX()); 00442 m_YDOF.SetDesired(m_XYPoints[m_nCurrentPosition].GetY()); 00443 00444 return; 00445 }