Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

WaypointEngine.cc

Go to the documentation of this file.
00001 #include "WaypointEngine.h"
00002 #include "Shared/mathutils.h"
00003 
00004 void WaypointEngine::go() {
00005   isRunning=true;
00006   for(unsigned int i=0; i<3; i++) {
00007     curVel[i]=0;
00008     pathStartPos[i]=sourcePos[i]=curPos[i];
00009   }
00010   curWaypoint=waypoints.begin();
00011   if ( waypoints.empty() )
00012     return;
00013   Waypoint target(curPos[0],curPos[1],Waypoint::POSTYPE_ABSOLUTE,curPos[2],false,0,isTracking,defaultTurnSpeed);
00014   target.apply(waypoints.front(),eps);
00015   targetPos[0]=target.x;
00016   targetPos[1]=target.y;
00017   targetPos[2]=target.angle;
00018   lastUpdateTime=get_time();
00019   setTargetWaypoint(curWaypoint);
00020 }
00021 
00022 void WaypointEngine::pause() {
00023   // cout<<"Pausing"<<endl;
00024   isRunning=false;
00025 }
00026 
00027 void WaypointEngine::unpause() {
00028   if(curWaypoint==waypoints.end())
00029     go();
00030   isRunning=true;
00031   for(unsigned int i=0; i<3; i++)
00032     curVel[i]=0;
00033   lastUpdateTime=get_time();
00034 }
00035 
00036 bool WaypointEngine::cycle() {
00037   if(!isRunning)
00038     return false;
00039   
00040   unsigned int curtime=get_time();
00041   if(curWaypoint!=waypoints.end()) {
00042     computeCurrentPosition(curtime);
00043     checkNextWaypoint(curtime);
00044   }
00045   if(curWaypoint!=waypoints.end()) {
00046     computeIdeal(curtime);
00047     computeNewVelocity(curtime);
00048   }
00049   
00050   return true;
00051 }
00052 
00053 
00054 void WaypointEngine::setTargetWaypoint(WaypointListIter_t iter) {
00055   //cout << "Moving to waypoint " << iter << endl;
00056   bool isLoop=false;
00057   if(iter==waypoints.end()) {
00058     if(isLooping && waypoints.size()>0) { //restart at beginning
00059       iter=waypoints.begin();
00060       for(unsigned int i=0; i<3; i++)
00061         pathStartPos[i]=curPos[i];
00062       isLoop=true;
00063     } else { //not looping, halt
00064       isRunning=false;
00065       curWaypoint=iter;
00066       for(unsigned int i=0; i<3; i++) {
00067         sourcePos[i]=targetPos[i];
00068         targetPos[i]=curPos[i];
00069         curVel[i]=0;
00070       }       
00071       return;
00072     }
00073   }
00074   if(iter== (iter+1) || isLoop)
00075     for(unsigned int i=0; i<3; i++)
00076       sourcePos[i]=targetPos[i];
00077   else
00078     for(unsigned int i=0; i<3; i++)
00079       sourcePos[i]=curPos[i];
00080   
00081   Waypoint target;
00082   if(isLoop)
00083     target=calcAbsoluteCoords(iter,pathStartPos[0],pathStartPos[1],pathStartPos[2]);
00084   else
00085     target=calcAbsoluteCoords(iter);
00086   targetPos[0]=target.x;
00087   targetPos[1]=target.y;
00088   targetPos[2]=target.angle;
00089   
00090   float dx=targetPos[0]-sourcePos[0];
00091   float dy=targetPos[1]-sourcePos[1];
00092   waypointDistance=std::sqrt(dx*dx+dy*dy);
00093   waypointTime=get_time();
00094   curWaypoint=iter;
00095   float radiusRatio=std::sin(target.arc/2);
00096   arcRadius = (radiusRatio==0) ? 0 : (waypointDistance/2)/radiusRatio;
00097   pathLength = arcRadius!=0 ? arcRadius*target.arc : waypointDistance;
00098   //
00099   
00100   // std::cout << "Target is now: ("<<targetPos[0]<<','<<targetPos[1]<<"  hdg" <<targetPos[2]<<")" << std::endl;
00101 }
00102 
00103 
00104 unsigned int WaypointEngine::getBinSize() const {
00105   unsigned int numPrecision=9;
00106   unsigned int wpSize=0;
00107   unsigned int boilerplateSize=0;
00108   boilerplateSize+=strlen("#WyP\n");
00109   boilerplateSize+=strlen("#add_{point|arc} {ego|off|abs} x_val y_val {hold|follow} angle_val speed_val arc_val\n");
00110   wpSize+=strlen("max_turn_speed ")+numPrecision+1;
00111   wpSize+=strlen("track_path false\n");
00112   wpSize+=strlen("add_point ")+4+numPrecision*5+1*5+strlen("follow");
00113   boilerplateSize+=strlen("#END\n");
00114   return wpSize*waypoints.size()+boilerplateSize;
00115 }
00116 
00117 unsigned int WaypointEngine::loadBuffer(const char buf[], unsigned int len, const char* filename) {
00118   unsigned int origlen=len;
00119   waypoints.clear();
00120   if(strncmp("#WyP\n",buf,5)!=0 && strncmp("#WyP\r",buf,5)!=0) {
00121     return 0;
00122   }
00123   
00124   float turn=defaultTurnSpeed; //init to current mode, in case file doesn't specify
00125   bool track=isTracking;
00126   char cmd[40];
00127   char posType[40];
00128   float x_val=0;
00129   float y_val=0;
00130   char angType[40];
00131   bool ang_val=0;
00132   float angle_val=0;
00133   float speed_val=0;
00134   float arc_val=0;
00135   unsigned int linenum=1;
00136   while(len<=origlen && len>0) {
00137     //    printf("%d %.9s\n",linenum+1,buf);
00138     if(buf[0]=='\r') {
00139       buf++; len--;
00140       if(buf[0]=='\n') {
00141         buf++; len--;
00142       }
00143       linenum++;
00144       continue;
00145     }
00146     if(buf[0]=='\n') {
00147       buf++; len--;
00148       linenum++;
00149       continue;
00150     }
00151     if(buf[0]=='#') {
00152       if(strncmp("#END\n",buf,5)==0 || strncmp("#END\r",buf,5)==0) {
00153         return origlen-len+5;
00154       } else if(strncmp("#END\r\n",buf,6)==0) {
00155         return origlen-len+6;
00156       } else {
00157         while(len>0 && *buf!='\n' && *buf!='\r') {len--;buf++;}
00158         if(*buf=='\n') { //in case of \r\n
00159           buf++;
00160           len--;
00161         }
00162         linenum++;
00163         continue;
00164       }
00165     }
00166     int used=-1U;
00167     sscanf(buf,"%40s%n",cmd,&used);
00168     if(!checkInc(used,buf,len,"*** ERROR Waypoint list load corrupted - ran out of room line %d\n",linenum)) return 0;
00169     if(strncasecmp(cmd,"add_point",9)==0 || strncasecmp(cmd,"add_arc",7)==0) {
00170       sscanf(buf,"%40s %g %g %40s %g %g %g%n",posType,&x_val,&y_val,angType,&angle_val,&speed_val,&arc_val,&used);
00171       if(!checkInc(used,buf,len,"*** ERROR Waypoint list load corrupted - bad read on add at line %d\n",linenum)) return 0;
00172       if(strncasecmp(angType,"hold",4)==0)
00173         ang_val=false;
00174       else if(strncasecmp(angType,"follow",6)==0)
00175         ang_val=true;
00176       else {
00177         printf("*** ERROR WaypointEngine: Invalid angle value type %s\n",angType);
00178         return 0;
00179       }
00180       if(strncasecmp(cmd,"add_point",9)==0) {
00181         if(strncasecmp(posType,"ego",3)==0)
00182           addEgocentricWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00183         else if(strncasecmp(posType,"off",3)==0)
00184           addOffsetWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00185         else if(strncasecmp(posType,"abs",3)==0)
00186           addAbsoluteWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00187         else {
00188           printf("*** ERROR WaypointEngine: Invalid position type %s\n",posType);
00189           return 0;
00190         }           
00191         waypoints.back().arc=arc_val;
00192       } else {
00193         if(strncasecmp(posType,"ego",3)==0)
00194           addEgocentricArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00195         else if(strncasecmp(posType,"off",3)==0)
00196           addOffsetArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00197         else if(strncasecmp(posType,"abs",3)==0)
00198           addAbsoluteArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00199         else {
00200           printf("*** ERROR WaypointEngine: Invalid position type %s\n",posType);
00201           return 0;
00202         }
00203       }
00204       waypoints.back().trackPath=track;
00205       waypoints.back().turnSpeed=turn;
00206     } else if(strncasecmp(cmd,"track_path",10)==0) {
00207       int track_tmp;
00208       sscanf(buf,"%d%n",&track_tmp,&used);
00209       track=track_tmp;
00210       if(!checkInc(used,buf,len,"*** ERROR Waypoint load corrupted - bad read on track_path line %d\n",linenum)) return 0;
00211     } else if(strncasecmp(cmd,"max_turn_speed",14)==0) {
00212       sscanf(buf,"%g%n",&turn,&used);
00213       if(!checkInc(used,buf,len,"*** ERROR Waypoint load corrupted - bad read on max_turn_speed line %d\n",linenum)) return 0;
00214     } else {
00215       printf("*** ERROR WaypointEngine: Invalid command %s\n",cmd);
00216       return 0;
00217     }
00218     
00219     linenum++;
00220   }
00221   std::cout << "*** WARNING WaypointEngine: load missing #END" << std::endl;
00222   return origlen-len;
00223 }
00224 
00225 unsigned int WaypointEngine::saveBuffer(char buf[], unsigned int len) const {
00226   unsigned int origLen=len;
00227   unsigned int used;
00228   unsigned int cnt=0;
00229   
00230   used=snprintf(buf,len,"#WyP\n");
00231   if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on header\n")) return 0;
00232   
00233   used=snprintf(buf,len,"#add_{point|arc} {ego|off|abs} x_val y_val {hold|follow} angle_val speed_val arc_val\n");
00234   if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on header\n")) return 0;
00235   
00236   //set our state variables so we'll be forced to output the first set
00237   float turn=waypoints.front().turnSpeed-1;
00238   bool track=!waypoints.front().trackPath;
00239   
00240   for(WaypointListConstIter_t it=waypoints.begin(); it!=waypoints.end(); it++) {
00241     if(it->turnSpeed!=turn) {
00242       turn=it->turnSpeed;
00243       used=snprintf(buf,len,"max_turn_speed %g\n",turn);
00244       if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d turnSpeed\n",cnt)) return 0;
00245     }
00246     if(it->trackPath!=track) {
00247       track=it->trackPath;
00248       used=snprintf(buf,len,"track_path %d\n",track);
00249       if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d\n trackPath",cnt)) return 0;
00250     }
00251     const char * posType=NULL;
00252     switch(it->posType) {
00253       case Waypoint::POSTYPE_EGOCENTRIC:
00254         posType="EGO"; break;
00255       case Waypoint::POSTYPE_OFFSET:
00256         posType="OFF"; break;
00257       case Waypoint::POSTYPE_ABSOLUTE:
00258         posType="ABS"; break;
00259     }
00260     if(it->arc!=0)
00261       used=snprintf(buf,len,"add_point %s %g %g %s %g %g %g\n",posType,it->x,it->y,(it->angleIsRelative?"FOLLOW":"HOLD"),it->angle,it->speed,it->arc);
00262     else //todo - store center of circle
00263       used=snprintf(buf,len,"add_point %s %g %g %s %g %g %g\n",posType,it->x,it->y,(it->angleIsRelative?"FOLLOW":"HOLD"),it->angle,it->speed,it->arc);
00264     if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d\n",cnt)) return 0;
00265     cnt++;
00266   }
00267   
00268   used=snprintf(buf,len,"#END\n");
00269   if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on footer\n")) return 0;
00270   
00271   return origLen-len;
00272 }
00273 
00274 void WaypointEngine::init() {
00275   eps[0]=eps[1]= 5.0f; //5 mm
00276   eps[2]=0.0175f; //1 degree
00277   for(unsigned int i=0; i<3; i++)
00278     pathStartPos[i]=targetPos[i]=sourcePos[i]=curPos[i]=curVel[i]=0;
00279   for(unsigned int i=0; i<4; i++)
00280     idealPos[i]=0;
00281 }
00282 
00283 /*! This is replicated in WaypointList, so any updates should be made there as well */
00284 void WaypointEngine::fixArc(float arc) {
00285   Waypoint& center=waypoints.back();
00286   float cdx=center.x; //center delta
00287   float cdy=center.y; //center delta
00288   if(center.posType==Waypoint::POSTYPE_ABSOLUTE) {
00289     //have to find location of waypoint before last one
00290     if(waypoints.size()<=1) {
00291       cdx-=pathStartPos[0];
00292       cdy-=pathStartPos[1];
00293     } else {
00294       Waypoint start=calcAbsoluteCoords(waypoints.end()-2);
00295       cdx-=start.x;
00296       cdy-=start.y;
00297     }
00298   }
00299   float r=std::sqrt(cdx*cdx+cdy*cdy); //radius of circle
00300   float ca=std::atan2(cdy,cdx); //angle to center of circle
00301   center.x-=r*std::cos(ca-arc); //now x is the endpoint
00302   center.y-=r*std::sin(ca-arc); //now y is the endpoint
00303   center.arc=arc;
00304 }
00305 
00306 void WaypointEngine::computeCurrentPosition(unsigned int t) {
00307   float dt=(t-lastUpdateTime)/1000.f;
00308   float df=dt*curVel[0];
00309   float ds=dt*curVel[1];
00310   float da=dt*curVel[2];
00311   
00312   float avgAngle=curPos[2]+da/2;
00313   float ca=std::cos(avgAngle);
00314   float sa=std::sin(avgAngle);
00315   
00316   curPos[0]+=df*ca-ds*sa;
00317   curPos[1]+=df*sa+ds*ca;
00318   curPos[2]+=da;
00319   curPos[2]=mathutils::normalizeAngle(curPos[2]);
00320   
00321   lastUpdateTime=t;
00322 }
00323 
00324 void WaypointEngine::checkNextWaypoint(unsigned int /*t*/) {
00325   float rx=targetPos[0]-curPos[0];
00326   float ry=targetPos[1]-curPos[1];
00327   float ra=targetPos[2]-curPos[2];
00328   if(fabs(rx)<eps[0] && fabs(ry)<eps[1] && fabs(ra)<eps[2]) {
00329     setTargetWaypoint(curWaypoint+1);
00330   }
00331 }
00332 
00333 void WaypointEngine::computeIdeal(unsigned int t) {
00334   Waypoint& cur=(*curWaypoint);
00335   if(cur.trackPath) {
00336     float dx=targetPos[0]-sourcePos[0];
00337     float dy=targetPos[1]-sourcePos[1];
00338     //--------------- here
00339     float dt=(t-waypointTime)/1000.f; //time we've been traveling towards current waypoint
00340     float ideal_travel=dt*cur.speed; //distance we should have covered
00341     float p=1; //will be set to percentage of path length to waypoint we have covered
00342     if(pathLength!=0) {
00343       p=ideal_travel/pathLength;
00344       if(p>1)
00345         p=1;
00346     }
00347     if(arcRadius==0) { //radius is "infinite" - straight line solution
00348       idealPos[0]=sourcePos[0]+dx*p;
00349       idealPos[1]=sourcePos[1]+dy*p;
00350       idealPos[2]=targetPos[2];
00351       idealPos[3]=std::atan2(dy,dx);
00352     } else {
00353       // have to find center of arc's circle
00354       float bearing=std::atan2(dy,dx); //bearing of target from source
00355       float center_bearing=bearing+((float)M_PI-cur.arc)/2; //bearing of center from source
00356       float cx=sourcePos[0]+arcRadius*std::cos(center_bearing); //x pos of center
00357       float cy=sourcePos[1]+arcRadius*std::sin(center_bearing); //y pos of center
00358       float arc_bearing=center_bearing-(float)M_PI+cur.arc*p; //bearing from center to current ideal location
00359       //sout->printf("%g %g (%g,%g) %g\n",center_bearing,arcRadius,cx,cy,arc_bearing);
00360       idealPos[0]=cx+arcRadius*std::cos(arc_bearing);
00361       idealPos[1]=cy+arcRadius*std::sin(arc_bearing);
00362       idealPos[3]=arc_bearing+(float)M_PI/2;
00363       idealPos[2]=cur.angle;
00364       if(cur.angleIsRelative)
00365         idealPos[2]+=idealPos[3];
00366       idealPos[2]=mathutils::normalizeAngle(idealPos[2]);
00367       idealPos[3]=mathutils::normalizeAngle(idealPos[3]);
00368     }
00369   } else {
00370     idealPos[0]=curPos[0];
00371     idealPos[1]=curPos[1];
00372     float rx=targetPos[0]-curPos[0];
00373     float ry=targetPos[1]-curPos[1];
00374     if(std::abs(rx)<eps[0] && std::abs(ry)<eps[1]) {
00375       idealPos[2]=targetPos[2];
00376     } else {
00377       idealPos[2]=cur.angle;
00378       if(cur.angleIsRelative) {
00379         float dx=targetPos[0]-curPos[0];
00380         float dy=targetPos[1]-curPos[1];
00381         idealPos[2]+=std::atan2(dy,dx);
00382       }
00383       idealPos[2]=mathutils::normalizeAngle(idealPos[2]);
00384     }
00385     idealPos[3]=std::atan2(ry,rx);
00386     if(arcRadius!=0) {
00387       //---------------here
00388       float dt=(t-waypointTime)/1000.f; //time we've been traveling towards current waypoint
00389       float ideal_travel=dt*cur.speed; //distance we should have covered
00390       float p=1; //will be set to percentage of path length to waypoint we have covered
00391       if(pathLength!=0) {
00392         p=ideal_travel/pathLength;
00393         if(p>1)
00394           p=1;
00395       }
00396       float arc=cur.arc*(1-p)/2;
00397       idealPos[2]=mathutils::normalizeAngle(idealPos[2]-arc);
00398       idealPos[3]=mathutils::normalizeAngle(idealPos[3]-arc);
00399     }
00400   }
00401 }
00402   
00403 void WaypointEngine::computeNewVelocity(unsigned int /*t*/) {
00404   Waypoint& cur=(*curWaypoint);
00405   
00406   //first we'll start with the velocity we would use if we were on path
00407   //determine distance remaining (only an approximation for arcing paths)
00408   float dx=targetPos[0]-idealPos[0];
00409   float dy=targetPos[1]-idealPos[1];
00410   float spd=std::sqrt(dx*dx+dy*dy)/(FrameTime*NumFrames)*1000.f;
00411   if(spd>cur.speed) {
00412     //we're far away - go at full speed
00413     curVel[0]=cur.speed*std::cos(idealPos[3]-curPos[2]);
00414     curVel[1]=cur.speed*std::sin(idealPos[3]-curPos[2]);
00415   } else {
00416     //we're about to overshoot... just go fast enough to get on target
00417     curVel[0]=spd*std::cos(idealPos[3]-curPos[2]);
00418     curVel[1]=spd*std::sin(idealPos[3]-curPos[2]);
00419   }
00420   if(arcRadius==0)
00421     curVel[2]=0;
00422   else
00423     curVel[2]=cur.speed/arcRadius;
00424   
00425   //sout->printf("ideal vel: %g %g %g\n",curVel[0],curVel[1],curVel[2]);
00426   
00427   // then we'll add the errors
00428   float ex=idealPos[0]-curPos[0];
00429   float ey=idealPos[1]-curPos[1];
00430   float ed=std::sqrt(ex*ex+ey*ey);
00431   float ehead=std::atan2(ey,ex)-curPos[2];
00432   float ea=mathutils::normalizeAngle(idealPos[2]-curPos[2]);
00433   float easpd=ea/(FrameTime*NumFrames)*1000.f;
00434   easpd=mathutils::limitRange(easpd,-cur.turnSpeed,cur.turnSpeed);
00435   curVel[0]+=Pcorr*ed*std::cos(ehead);
00436   curVel[1]+=Pcorr*ed*std::sin(ehead);
00437   curVel[2]+=easpd;
00438 }
00439 
00440 /*! @file
00441  * @brief Defines WaypointEngine, which provides computation and management of a desired path through a series of waypoints
00442  * @author ejt (Creator)
00443  */

Tekkotsu v5.1CVS
Generated Fri Mar 16 05:26:54 2012 by Doxygen 1.6.3