fasr2.cc
Go to the documentation of this file.
00001 #include <pthread.h>
00002 
00003 #include "stage.hh"
00004 using namespace Stg;
00005 
00006 // generic planner implementation
00007 #include "astar/astar.h"
00008 
00009 static const bool verbose = false;
00010 
00011 // navigation control params
00012 static const double cruisespeed = 0.4; 
00013 static const double avoidspeed = 0.05; 
00014 static const double avoidturn = 0.5;
00015 static const double minfrontdistance = 0.7;  
00016 static const double stopdist = 0.5;
00017 static const unsigned int avoidduration = 10;
00018 static const unsigned int PAYLOAD = 1;
00019 
00020 
00021 static unsigned int 
00022 MetersToCell( meters_t m,  meters_t size_m, unsigned int size_c )
00023 {
00024   m += size_m / 2.0; // shift to local coords
00025   m /= size_m / (float)size_c; // scale
00026   return (unsigned int)floor(m); // quantize 
00027 }
00028 
00029 static meters_t 
00030 CellToMeters( unsigned int c,  meters_t size_m, unsigned int size_c )
00031 {
00032   meters_t cell_size = size_m/(float)size_c; 
00033   meters_t m = c * cell_size; // scale
00034   m -= size_m / 2.0; // shift to local coords
00035 
00036   return m + cell_size/2.0; // offset to cell center
00037 }
00038 
00039 
00040 class Robot
00041 {
00042 public: 
00043         class Task
00044         {
00045         public:
00046                 Model* source;
00047                 Model* sink;
00048                 unsigned int participants;
00049                 
00050                 Task( Model* source, Model* sink ) 
00051                         : source(source), sink(sink), participants(0) 
00052                 {}
00053         };
00054         
00055   static std::vector<Task> tasks;
00056 
00057 private:
00058         class Node;
00059         
00060         class Edge
00061         {
00062         public:
00063                 Node* to;
00064                 double cost;
00065                 
00066                 Edge( Node* to, double cost=1.0 ) 
00067                         : to(to), cost(cost) {}  
00068         };
00069         
00070         class Node
00071         {
00072         public:
00073                 Pose pose;
00074                 double value;  
00075                 std::vector<Edge*> edges;
00076                 
00077                 Node( Pose pose, double value=0 )
00078                         : pose(pose), value(value), edges() {}
00079                 
00080                 ~Node() 
00081                 { 
00082                         FOR_EACH( it, edges )
00083                                 { delete *it; }
00084                 }
00085                 
00086                 void AddEdge( Edge* edge ) 
00087                 { 
00088                         assert(edge);
00089                         edges.push_back( edge );         
00090                 }   
00091                 
00092                 void Draw() const;
00093         }; 
00094         
00095         class Graph
00096         {
00097         public:
00098                 std::vector<Node*> nodes;
00099                 
00100                 Graph(){}
00101                 ~Graph() { FOR_EACH( it, nodes ){ delete *it; }}
00102                 
00103                 void AddNode( Node* node ){ nodes.push_back( node ); }
00104   
00105                 void PopFront()
00106                 {
00107                         const std::vector<Node*>::iterator& it = nodes.begin();
00108                         delete *it;
00109                         nodes.erase( it );
00110                 }
00111                 
00112                 void Draw() const
00113                 { 
00114                         glPointSize(3);
00115                         FOR_EACH( it, nodes ){ (*it)->Draw(); }
00116                 }
00117                 
00118                 bool GoodDirection( const Pose& pose, meters_t range, radians_t& heading_result )
00119                 {
00120                         // find the node with the lowest value within range of the given
00121                         // pose and return the absolute heading from pose to that node 
00122                         
00123                         if( nodes.empty() )
00124                                 return 0; // a null guess
00125                         
00126                         
00127                         Node* best_node = NULL;
00128                         
00129                         // find the closest node
00130                         FOR_EACH( it, nodes )
00131                                 {
00132                                         Node* node = *it;
00133                                         double dist = hypot( node->pose.x - pose.x, node->pose.y - pose.y );
00134                   
00135                                         // if it's in range, and either its the first we have found,
00136                                         // or it has a lower value than the current best
00137                                         if( dist < range &&
00138                                                         ( best_node == NULL || node->value < best_node->value ))
00139                                                 {
00140                                                         best_node = node;
00141                                                 }
00142                                 }
00143          
00144                         if( best_node == NULL )
00145                                 {
00146                                         fprintf( stderr, "FASR warning: no nodes in range" );
00147                                         return false;
00148                                 }
00149 
00150                         //else
00151                         heading_result = atan2( best_node->pose.y - pose.y,
00152                                                                                                                         best_node->pose.x - pose.x );
00153                         
00154                         // add a little bias to one side (the left) - creates two lanes
00155                         // of robot traffic
00156                         heading_result = normalize( heading_result + 0.25 );
00157 
00158                         return true;
00159                 }
00160         };
00161 
00162         class GraphVis : public Visualizer
00163         {
00164         public:
00165                 Graph** graphpp;
00166                 
00167                 GraphVis( Graph** graphpp ) 
00168                         : Visualizer( "graph", "vis_graph" ), graphpp(graphpp) {}
00169                 virtual ~GraphVis(){}
00170                 
00171                 virtual void Visualize( Model* mod, Camera* cam )
00172                 {
00173                         if( *graphpp == NULL )
00174                                 return;
00175                         
00176                         glPushMatrix();
00177                         
00178                         Gl::pose_inverse_shift( mod->GetGlobalPose() );
00179                         
00180                         //mod->PushColor( 1,0,0,1 );
00181                         
00182                         Color c = mod->GetColor();
00183                         c.a = 0.4;
00184                         
00185                         mod->PushColor( c );
00186                         (*graphpp)->Draw();
00187                         mod->PopColor();
00188                         
00189                         glPopMatrix();
00190                 }
00191         };
00192         
00193 
00194 private:
00195   long int wait_started_at;
00196   
00197   ModelPosition* pos;
00198   ModelRanger* laser;
00199   ModelRanger* sonar;
00200   ModelFiducial* fiducial;
00201   
00202   unsigned int task;
00203 
00204   Model* fuel_zone;
00205   Model* pool_zone;
00206   int avoidcount, randcount;
00207   int work_get, work_put;
00208   bool charger_ahoy;
00209   double charger_bearing;
00210   double charger_range;
00211   double charger_heading;
00212         
00213         enum {
00214                 MODE_WORK=0,
00215                 MODE_DOCK,
00216                 MODE_UNDOCK,
00217                 MODE_QUEUE
00218         } mode;
00219         
00220   radians_t docked_angle;
00221 
00222   static pthread_mutex_t planner_mutex;
00223 
00224   Model* goal;
00225   Pose cached_goal_pose;
00226 
00227   Graph* graphp;
00228   GraphVis graphvis;
00229   unsigned int node_interval;
00230   unsigned int node_interval_countdown;
00231   
00232   static const unsigned int map_width;
00233   static const unsigned int map_height;
00234   static uint8_t* map_data;
00235   static Model* map_model;
00236          
00237   bool fiducial_sub;
00238   bool laser_sub;
00239   bool sonar_sub;
00240 
00241   bool force_recharge;
00242 
00243 public:  
00244 
00245   Robot( ModelPosition* pos, 
00246                                  Model* fuel,
00247                                  Model* pool ) 
00248                 : 
00249                 wait_started_at(-1),
00250                 pos(pos), 
00251                 laser( (ModelRanger*)pos->GetChild( "ranger:1" )),
00252                 sonar( (ModelRanger*)pos->GetChild( "ranger:0" )),
00253                 fiducial( (ModelFiducial*)pos->GetUnusedModelOfType( "fiducial" )),     
00254                 task(random() % tasks.size() ), // choose a task at random
00255                 fuel_zone(fuel),
00256                 pool_zone(pool),
00257                 avoidcount(0), 
00258                 randcount(0), 
00259                 work_get(0), 
00260                 work_put(0),
00261                 charger_ahoy(false),
00262                 charger_bearing(0),
00263                 charger_range(0),
00264                 charger_heading(0),
00265                 mode(MODE_WORK),
00266                 docked_angle(0),
00267                 goal(tasks[task].source),
00268                 cached_goal_pose(),
00269                 graphp(NULL),
00270                 graphvis( &graphp ),
00271                 node_interval( 20 ),
00272                 node_interval_countdown( node_interval ),
00273                 fiducial_sub(false),            
00274                 laser_sub(false),
00275                 sonar_sub(false),
00276                 force_recharge( false )
00277   {
00278                 // need at least these models to get any work done
00279                 // (pos must be good, as we used it in the initialization list)
00280                 assert( laser );
00281                 assert( fiducial );
00282                 assert( sonar );
00283                 assert( goal );
00284 
00285                 // match the color of my destination
00286                 pos->SetColor( tasks[task].source->GetColor() );
00287                 
00288                 tasks[task].participants++;
00289                 
00290                 EnableLaser(true);
00291 
00292                 // we access all other data from the position callback
00293                 pos->AddCallback(  Model::CB_UPDATE, (model_callback_t)UpdateCallback, this );
00294                 pos->Subscribe();
00295 
00296                 pos->AddVisualizer( &graphvis, true );
00297          
00298                 if( map_data == NULL )
00299                         {
00300                                 map_data = new uint8_t[map_width*map_height*2];
00301                   
00302                                 // MUST clear the data, since Model::Rasterize() only enters
00303                                 // non-zero pixels
00304                                 memset( map_data, 0, sizeof(uint8_t) * map_width * map_height);
00305                   
00306                                 // get the map
00307                                 map_model = pos->GetWorld()->GetModel( "cave" );
00308                                 assert(map_model);
00309                                 Geom g = map_model->GetGeom();
00310                   
00311                                 map_model->Rasterize( map_data, 
00312                                                                                                                         map_width, 
00313                                                                                                                         map_height, 
00314                                                                                                                         g.size.x/(float)map_width, 
00315                                                                                                                         g.size.y/(float)map_height );
00316                   
00317                                 // fix the node costs for astar: 0=>1, 1=>9
00318                   
00319                                 unsigned int sz = map_width * map_height;        
00320                                 for( unsigned int i=0; i<sz; i++ )
00321                                         {
00322                                                 if( map_data[i] == 0 )
00323                                                         map_data[i] = 1;
00324                                                 else if( map_data[i] == 1 )
00325                                                         map_data[i] = 9;
00326                                                 else
00327                                                         printf( "FASR: bad value %d in map at index %d\n", (int)map_data[i], (int)i );
00328                                 
00329                                                 assert( (map_data[i] == 1) || (map_data[i] == 9) );               
00330                                         }        
00331                         }
00332          
00333                 //( goal );
00334                 //puts("");
00335   }
00336  
00337         
00338         void Enable( Stg::Model* model, bool& sub, bool on )
00339         {
00340                 if( on && !sub )
00341                         { 
00342                                 sub = true;
00343                                 model->Subscribe();
00344                         }
00345                 
00346                 if( !on && sub )
00347                         {
00348                                 sub = false;
00349                                 model->Unsubscribe();
00350                         }
00351         }
00352         
00353   void EnableSonar( bool on )
00354   { 
00355                 Enable( sonar, sonar_sub, on );
00356   }
00357 
00358   void EnableLaser( bool on )
00359   { 
00360                 Enable( laser, laser_sub, on );
00361   }
00362 
00363   void EnableFiducial( bool on )
00364   { 
00365                 Enable( fiducial, fiducial_sub, on );
00366   }
00367 
00368         static std::map< std::pair<uint64_t,uint64_t>, Graph*> plancache;
00369         
00370 
00371         uint64_t Pt64( const ast::point_t& pt)
00372         {
00373                 // quantize the position a bit to reduce planning frequency
00374                 uint64_t x = pt.x / 1;
00375                 uint64_t y = pt.y / 1;
00376                 
00377                 return (x<<32) + y;
00378         }
00379         
00380         void CachePlan( const ast::point_t& start, const ast::point_t& goal, Graph* graph )
00381         {
00382                 std::pair<uint64_t,uint64_t> key( Pt64(start),Pt64(goal));
00383                 plancache[key] = graph;
00384         }
00385         
00386         Graph* LookupPlan( const ast::point_t& start, const ast::point_t& goal )
00387         {
00388                 std::pair<uint64_t,uint64_t> key(Pt64(start),Pt64(goal));
00389                 return plancache[key];          
00390         }
00391 
00392 
00393  void Plan( Pose sp )
00394   {
00395                 static float hits = 0;
00396                 static float misses = 0;
00397 
00398                 // change my color to that of my destination
00399                 //pos->SetColor( dest->GetColor() );
00400                 
00401                 Pose pose = pos->GetPose();
00402                 Geom g = map_model->GetGeom();
00403                 
00404                 ast::point_t start( MetersToCell(pose.x, g.size.x, map_width), 
00405                                                                          MetersToCell(pose.y, g.size.y, map_height) );
00406                 ast::point_t goal( MetersToCell(sp.x, g.size.x, map_width),
00407                                                                         MetersToCell(sp.y, g.size.y, map_height) );
00408                 
00409                 //printf( "searching from (%.2f, %.2f) [%d, %d]\n", pose.x, pose.y, start.x, start.y );
00410                 //printf( "searching to   (%.2f, %.2f) [%d, %d]\n", sp.x, sp.y, goal.x, goal.y );
00411                 
00412                 // astar() is not reentrant, so we protect it thus
00413                 
00414                 //graph.nodes.clear(); // whatever happens, we clear the old plan
00415                 
00416 
00417                 //pthread_mutex_lock( &planner_mutex );
00418                 
00419                 // check to see if we have a path planned for these positions already
00420                 //printf( "plancache @ %p size %d\n", &plancache, (int)plancache.size() );
00421                 
00422                 //if( graphp )
00423                 //delete graphp;
00424 
00425                 graphp = LookupPlan( start, goal );
00426 
00427                 if( ! graphp ) // no plan cached
00428                         {
00429                                 misses++;
00430                                 
00431                                 std::vector<ast::point_t> path;
00432                                 bool result = ast::astar( map_data, 
00433                                                                                                                                                 map_width, 
00434                                                                                                                                                 map_height, 
00435                                                                                                                                                 start,
00436                                                                                                                                                 goal,
00437                                                                                                                                                 path );                         
00438                                 
00439                                 if( ! result )
00440                                         printf( "FASR2 warning: plan failed to find path from (%.2f,%.2f) to (%.2f,%.2f)\n",
00441                                                                         pose.x, pose.y, sp.x, sp.y );                           
00442                                 
00443                                 graphp = new Graph();
00444                                 
00445                                 unsigned int dist = 0;
00446                                 
00447                                 Node* last_node = NULL;
00448 
00449                                 for( std::vector<ast::point_t>::reverse_iterator rit = path.rbegin();
00450                                                  rit != path.rend();
00451                                                  ++rit )                        
00452                                         {       
00453                                                 //printf( "%d, %d\n", it->x, it->y );
00454                                                 
00455                                                 Node* node = new Node( Pose( CellToMeters(rit->x, g.size.x, map_width ),
00456                                                                                                                                                                  CellToMeters(rit->y, g.size.y, map_height),
00457                                                                                                                                                                  0, 0 ),
00458                                                                                                                                          dist++ ); // value stored at node
00459                                                 
00460                                                 graphp->AddNode( node );
00461                                                 
00462                                                 if( last_node )
00463                                                         last_node->AddEdge( new Edge( node ) );
00464                                                 
00465                                                 last_node = node;
00466                                         }        
00467                                 
00468                                 CachePlan( start, goal, graphp );
00469                         }
00470                 else
00471                         {
00472                                 hits++;
00473                                 //puts( "FOUND CACHED PLAN" );
00474                         }
00475                                 
00476                 //printf( "hits/misses %.2f\n", hits/misses );
00477                 //pthread_mutex_unlock( &planner_mutex );
00478         }
00479         
00480                 
00481   void Dock()
00482   {
00483                 const meters_t creep_distance = 0.5;
00484          
00485                 if( charger_ahoy )
00486                         {
00487                                 // drive toward the charger
00488                                 // orient term helps to align with the way the charger is pointing
00489                                 const double orient = normalize( M_PI - (charger_bearing - charger_heading) );
00490                                 const double a_goal = normalize( charger_bearing - 2.0 * orient );
00491                                   
00492                                 if( charger_range > creep_distance )
00493                                         {
00494                                                 if( !ObstacleAvoid() )
00495                                                         {
00496                                                                 pos->SetXSpeed( cruisespeed );                                           
00497                                                                 pos->SetTurnSpeed( a_goal );
00498                                                         }
00499                                         }
00500                                 else    // we are very close!
00501                                         {                       
00502                                                 pos->SetTurnSpeed( a_goal );
00503                                                 pos->SetXSpeed( 0.02 ); // creep towards it                              
00504                                 
00505                                                 if( charger_range < 0.08 ) // close enough
00506                                                         {
00507                                                                 pos->Stop();
00508                                                                 docked_angle = pos->GetPose().a;
00509                                                                 EnableLaser( false );
00510                                                         }
00511                                 
00512                                                 if( pos->Stalled() ) // touching
00513                                                         pos->SetXSpeed( -0.01 ); // back off a bit                                                      
00514                                         }                        
00515                         }                         
00516                 else
00517                         {
00518                                 //printf( "FASR: %s docking but can't see a charger\n", pos->Token() );
00519                                 pos->Stop();
00520                                 EnableFiducial( false );
00521                                 mode = MODE_WORK; // should get us back on track eventually
00522                         }
00523 
00524                 // if the battery is charged, go back to work
00525                 if( Full() )
00526                         {
00527                                 //printf( "fully charged, now back to work\n" );                  
00528                                 mode = MODE_UNDOCK;
00529                                 EnableSonar(true); // enable the sonar to see behind us
00530                                 EnableLaser(true);
00531                                 EnableFiducial(true);
00532                                 force_recharge = false;           
00533                         }        
00534   }
00535 
00536   void SetTask( unsigned int t )
00537   {
00538                 task = t;
00539                 tasks[task].participants++;
00540   }
00541 
00542   void UnDock()
00543   {
00544                 const meters_t back_off_distance = 0.2;
00545                 const meters_t back_off_speed = -0.02;
00546                 const radians_t undock_rotate_speed = 0.3;
00547                 const meters_t wait_distance = 0.2;
00548                 const unsigned int BACK_SENSOR_FIRST = 10;
00549                 const unsigned int BACK_SENSOR_LAST = 13;
00550          
00551                 // make sure the required sensors are running
00552                 assert( sonar_sub );
00553                 assert( fiducial_sub );
00554 
00555                 if( charger_range < back_off_distance )
00556                         {
00557                                 pos->SetXSpeed( back_off_speed );
00558 
00559                                 pos->Say( "" );
00560                   
00561                                 // stay put while anything is close behind 
00562                                 const std::vector<ModelRanger::Sensor>& sensors = sonar->GetSensors();
00563 
00564                                 for( unsigned int s = BACK_SENSOR_FIRST; s <= BACK_SENSOR_LAST; ++s )
00565                                         if( sensors[s].ranges.size() < 1 || sensors[s].ranges[0] < wait_distance) 
00566                                                 {
00567                                                         pos->Say( "Waiting..." );
00568                                                         pos->SetXSpeed( 0.0 );
00569                                                         return;
00570                                                 }       
00571                         }
00572                 else
00573                         { // we've backed up enough
00574                   
00575                                 double heading_error = normalize( pos->GetPose().a - (docked_angle + M_PI ) );
00576                   
00577                                 if( fabs( heading_error ) > 0.05 ) 
00578                                         {
00579                                                 // turn
00580                                                 pos->SetXSpeed( 0 );
00581                                                 pos->SetTurnSpeed( undock_rotate_speed * sgn(-heading_error) );
00582                                         }
00583                                 else
00584                                         {
00585                                                 // we're pointing the right way, so we're done
00586                                                 mode = MODE_WORK;  
00587                                 
00588                                                 // if we're not working on a drop-off
00589                                                 if( pos->GetFlagCount() == 0 )
00590                                                         {
00591                                                                 // pick a new task at random
00592                                                                 SetTask( random() % tasks.size() );
00593                                                                 SetGoal( tasks[task].source );
00594                                                         }
00595                                                 else
00596                                                         SetGoal( tasks[task].sink );
00597 
00598                                 
00599                                                 EnableFiducial(false);
00600                                                 EnableSonar(false);
00601                                         }
00602                         }
00603   }
00604         
00605   bool ObstacleAvoid()
00606   {
00607                 bool obstruction = false;
00608                 bool stop = false;
00609   
00610                 // find the closest distance to the left and right and check if
00611                 // there's anything in front
00612                 double minleft = 1e6;
00613                 double minright = 1e6;
00614   
00615                 // Get the data
00616                 //const std::vector<ModelLaser::Sample>& scan = laser->GetSamples();
00617 
00618                 const std::vector<meters_t>& scan = laser->GetSensors()[0].ranges;
00619 
00620     uint32_t sample_count = scan.size();
00621 
00622 
00623                 for (uint32_t i = 0; i < sample_count; i++)
00624                         {               
00625                                 if( verbose ) printf( "%.3f ", scan[i] );
00626                 
00627                                 if( (i > (sample_count/4)) 
00628                                                 && (i < (sample_count - (sample_count/4))) 
00629                                                 && scan[i] < minfrontdistance)
00630                                         {
00631                                                 if( verbose ) puts( "  obstruction!" );
00632                                                 obstruction = true;
00633                                         }
00634                 
00635                                 if( scan[i] < stopdist )
00636                                         {
00637                                                 if( verbose ) puts( "  stopping!" );
00638                                                 stop = true;
00639                                         }
00640                 
00641                                 if( i > sample_count/2 )
00642                                         minleft = std::min( minleft, scan[i] );
00643                                 else      
00644                                         minright = std::min( minright, scan[i] );
00645                         }
00646   
00647                 if( verbose ) 
00648                         {
00649                                 puts( "" );
00650                                 printf( "minleft %.3f \n", minleft );
00651                                 printf( "minright %.3f\n ", minright );
00652                         }
00653   
00654                 if( obstruction || stop || (avoidcount>0) )
00655                         {
00656                                 if( verbose ) printf( "Avoid %d\n", avoidcount );
00657                 
00658                                 pos->SetXSpeed( stop ? 0.0 : avoidspeed );      
00659                 
00660                                 /* once we start avoiding, select a turn direction and stick
00661                                          with it for a few iterations */
00662                                 if( avoidcount < 1 )
00663                                         {
00664                                                 if( verbose ) puts( "Avoid START" );
00665                                                 avoidcount = random() % avoidduration + avoidduration;
00666                          
00667                                                 if( minleft < minright  )
00668                                                         {
00669                                                                 pos->SetTurnSpeed( -avoidturn );
00670                                                                 if( verbose ) printf( "turning right %.2f\n", -avoidturn );
00671                                                         }
00672                                                 else
00673                                                         {
00674                                                                 pos->SetTurnSpeed( +avoidturn );
00675                                                                 if( verbose ) printf( "turning left %2f\n", +avoidturn );
00676                                                         }
00677                                         }                         
00678                 
00679                                 avoidcount--;
00680 
00681                                 return true; // busy avoding obstacles
00682                         }
00683   
00684                 return false; // didn't have to avoid anything
00685   }
00686 
00687   
00688   void SetGoal( Model* goal )
00689   {     
00690                 if( goal != this->goal )
00691                         {
00692                                 this->goal = goal;
00693                                 Plan( goal->GetPose() );
00694                                 pos->SetColor( goal->GetColor() );
00695                         }
00696   }
00697          
00698   void Work()
00699   {
00700                 if( ! ObstacleAvoid() )
00701                         {
00702                                 if( verbose ) 
00703                                         puts( "Cruise" );
00704                                 
00705                                 if( Hungry() )
00706                                         SetGoal( fuel_zone );
00707                                 
00708                                 const Pose pose = pos->GetPose();               
00709                                 double a_goal = 0;
00710                                 
00711                                 // if the graph fails to offer advice or the goal has moved a
00712                                 // ways since last time we planned
00713                                 if( graphp == NULL || 
00714                                                 (graphp->GoodDirection( pose, 5.0, a_goal ) == 0) || 
00715                                                 (goal->GetPose().Distance2D( cached_goal_pose ) > 0.5) )
00716                                         {
00717                                                 //printf( "%s replanning from (%.2f,%.2f) to %s at (%.2f,%.2f) in Work()\n", 
00718                                                 //        pos->Token(),
00719                                                 //        pose.x, pose.y,
00720                                                 //        goal->Token(),
00721                                                 //        goal->GetPose().x,
00722                                                 //        goal->GetPose().y );
00723                                                 Plan( goal->GetPose() );
00724                                                 cached_goal_pose = goal->GetPose();                             
00725                                         }
00726                   
00727                                 // if we are low on juice - find the direction to the recharger instead
00728                                 if( Hungry() )           
00729                                         { 
00730                                                 EnableFiducial(true);
00731                                 
00732                                                 while( graphp->GoodDirection( pose, 5.0, a_goal ) == 0 )
00733                                                         {
00734                                                                 printf( "%s replanning in Work()\n", pos->Token() );
00735                                                         }
00736                                 
00737                                 
00738                                                 if( charger_ahoy ) // I see a charger while hungry!
00739                                                         mode = MODE_DOCK;
00740                                         }
00741                                 
00742                                 const double a_error = normalize( a_goal - pose.a );
00743                                 pos->SetTurnSpeed(  a_error );                  
00744                                 pos->SetXSpeed( cruisespeed );
00745                         }  
00746   }
00747 
00748 
00749   bool Hungry()
00750   {
00751                 return( force_recharge || pos->FindPowerPack()->ProportionRemaining() < 0.2 );
00752   }      
00753 
00754   bool Full()
00755   {
00756                 return( pos->FindPowerPack()->ProportionRemaining() > 0.95 );
00757   }      
00758   
00759   // static callback wrapper
00760   static int UpdateCallback( ModelRanger* laser, Robot* robot )
00761   {  
00762                 return robot->Update();
00763   }
00764   
00765   int Update( void )
00766   {
00767                 if( strcmp( pos->Token(), "position:0") == 0 )
00768                         {
00769                                 static int seconds = 0;
00770                   
00771                                 int timenow = pos->GetWorld()->SimTimeNow() / 1e6;
00772                   
00773                                 if( timenow - seconds > 5 )
00774                                         {
00775                                                 seconds = timenow;
00776                                 
00777                                                 // report the task participation                  
00778                                                 //                                              printf( "time: %d sec\n", seconds ); 
00779                                                   
00780 //                                              unsigned int sz = tasks.size(); 
00781 //                                              for( unsigned int i=0; i<sz; ++i )
00782 //                                                      printf( "\t task[%u] %3u (%s)\n", 
00783 //                                                                                      i, tasks[i].participants, tasks[i].source->Token() );                                                   
00784                                         }
00785                         }
00786          
00787                 Pose pose = pos->GetPose();
00788 
00789          
00790                 // assume we can't see the charger
00791                 charger_ahoy = false;
00792          
00793                 // if the fiducial is enabled
00794                 if( fiducial_sub ) 
00795                         {        
00796                                 std::vector<ModelFiducial::Fiducial>& fids = fiducial->GetFiducials();
00797                   
00798                                 if( fids.size() > 0 )
00799                                         {
00800                                                 ModelFiducial::Fiducial* closest = NULL;                
00801                                 
00802                                                 for( unsigned int i = 0; i < fids.size(); i++ )
00803                                                         {                               
00804                                                                 //printf( "fiducial %d is %d at %.2f m %.2f radians\n",
00805                                                                 //        i, f->id, f->range, f->bearing );             
00806                                          
00807                                                                 ModelFiducial::Fiducial* f = &fids[i];
00808                                          
00809                                                                 // find the closest 
00810                                                                 if( f->id == 2 && ( closest == NULL || f->range < closest->range )) // I see a charging station
00811                                                                         closest = f; 
00812                                                         }                                                 
00813                   
00814                                                 if( closest )
00815                                                         {                        // record that I've seen it and where it is
00816                                                                 charger_ahoy = true;
00817                                          
00818                                                                 //printf( "AHOY %s\n", pos->Token() );
00819                                          
00820                                                                 charger_bearing = closest->bearing;
00821                                                                 charger_range = closest->range;
00822                                                                 charger_heading = closest->geom.a;                       
00823                                                         }
00824                                         }
00825                         }
00826 
00827 
00828                 //printf( "Pose: [%.2f %.2f %.2f %.2f]\n",
00829                 //  pose.x, pose.y, pose.z, pose.a );
00830   
00831                 //pose.z += 0.0001;
00832                 //pos->SetPose( pose );
00833          
00834                 if( goal == tasks[task].source )
00835                         {
00836                                 // if we're close to the source we get a flag
00837                                 Pose sourcepose = goal->GetPose();
00838                                 Geom sourcegeom = goal->GetGeom();
00839                   
00840                                 meters_t dest_dist = hypot( sourcepose.x-pose.x, sourcepose.y-pose.y );
00841                   
00842                                 // when we get close enough, we start waiting
00843                                 if( dest_dist < sourcegeom.size.x/2.0 ) // nearby
00844                                         if( wait_started_at < 0 && pos->GetFlagCount() == 0 ) 
00845                                                 {
00846                                                         wait_started_at = pos->GetWorld()->SimTimeNow() / 1e6; // usec to seconds
00847                                                         //printf( "%s begain waiting at %ld seconds\n", pos->Token(), wait_started_at );
00848                                                 }
00849                   
00850                                 if( wait_started_at > 0 )
00851                                         {
00852                                                 //long int waited = (pos->GetWorld()->SimTimeNow() / 1e6) - wait_started_at;
00853                                 
00854                                                 // leave with small probability
00855                                                 if( drand48() < 0.0005 )
00856                                                         {
00857                                                                 //printf( "%s abandoning task %s after waiting %ld seconds\n",
00858                                                                 //              pos->Token(), goal->Token(), waited );
00859                                          
00860                                                                 force_recharge = true; // forces hungry to return true
00861                                                                 tasks[task].participants--;
00862                                                                 wait_started_at = -1;
00863                                                                 return 0;
00864                                                         }
00865                                         }
00866 
00867                                 // when we get onto the square
00868                                 if( dest_dist < sourcegeom.size.x/2.0 &&                                
00869                                                 pos->GetFlagCount() < PAYLOAD )
00870                                         {
00871                                 
00872                                                 // transfer a chunk from source to robot
00873                                                 pos->PushFlag( goal->PopFlag() );
00874 
00875                                                 if( pos->GetFlagCount() == 1 && wait_started_at > 0 )
00876                                                         {
00877                                                                 // stop waiting, since we have received our first flag
00878                                                                 wait_started_at = -1;
00879                                                         }                        
00880 
00881                                                 if( pos->GetFlagCount() == PAYLOAD )
00882                                                         SetGoal( tasks[task].sink ); // we're done working
00883                                         }
00884                         }        
00885                 else if( goal == tasks[task].sink )
00886                         {                        
00887                                 // if we're close to the sink we lose a flag
00888                                 Pose sinkpose = goal->GetPose();
00889                                 Geom sinkgeom = goal->GetGeom();
00890                   
00891                                 if( hypot( sinkpose.x-pose.x, sinkpose.y-pose.y ) < sinkgeom.size.x/2.0 && 
00892                                                 pos->GetFlagCount() > 0 )
00893                                         {
00894                                                 //puts( "dropping" );
00895                                                 // transfer a chunk between robot and goal
00896 
00897                                                 Model::Flag* f = pos->PopFlag();
00898                                                 f->SetColor( Color(0,1,0) ); // delivered flags are green
00899                                                 goal->PushFlag( f );              
00900                                 
00901                                                 if( pos->GetFlagCount() == 0 ) 
00902                                                         SetGoal( tasks[task].source ); // we're done dropping off
00903                                         }
00904                         }
00905                 else
00906                         {
00907                                 assert( goal == fuel_zone || goal == pool_zone );
00908                         }
00909                   
00910                 switch( mode )
00911                         {
00912                         case MODE_DOCK:
00913                                 //puts( "DOCK" );
00914                                 Dock();
00915                                 break;
00916                 
00917                         case MODE_WORK:
00918                                 //puts( "WORK" );
00919                                 Work();
00920                                 break;
00921 
00922                         case MODE_UNDOCK:
00923                                 //puts( "UNDOCK" );
00924                                 UnDock();
00925                                 break;
00926                 
00927                         default:
00928                                 printf( "unrecognized mode %u\n", mode );               
00929                         }
00930   
00931   
00932                 return 0; // run again
00933   }
00934   
00935   static int FlagIncr( Model* mod, Robot* robot )
00936         {
00937                 printf( "model %s collected flag\n", mod->Token() );
00938                 return 0;
00939   }
00940 
00941   static int FlagDecr( Model* mod, Robot* robot )
00942   {
00943                 printf( "model %s dropped flag\n", mod->Token() );
00944                 return 0;
00945   }
00946 };
00947 
00948 
00949 void Robot::Node::Draw() const
00950 {
00951   // print value
00952   //char buf[32];
00953   //snprintf( buf, 32, "%.0f", value );
00954   //Gl::draw_string( pose.x, pose.y+0.2, 0.1, buf );
00955 
00956   //glBegin( GL_POINTS );
00957   //glVertex2f( pose.x, pose.y );
00958   //glEnd();
00959 
00960         glBegin( GL_LINES );
00961         FOR_EACH( it, edges )
00962                 { 
00963                         glVertex2f( pose.x, pose.y );
00964                         glVertex2f( (*it)->to->pose.x, (*it)->to->pose.y );
00965                 }
00966         glEnd();
00967 }
00968 
00969 
00970 // STATIC VARS
00971 pthread_mutex_t Robot::planner_mutex = PTHREAD_MUTEX_INITIALIZER;
00972 const unsigned int Robot::map_width( 32 );
00973 const unsigned int Robot::map_height( 32 );
00974 uint8_t* Robot::map_data( NULL );
00975 Model* Robot::map_model( NULL );
00976 
00977 std::map< std::pair<uint64_t,uint64_t>, Robot::Graph*> Robot::plancache;
00978 
00979 std::vector<Robot::Task> Robot::tasks;
00980 
00981 void split( const std::string& text, const std::string& separators, std::vector<std::string>& words)
00982 {
00983   const int n = text.length();
00984   int start, stop;
00985   start = text.find_first_not_of(separators);
00986   while ((start >= 0) && (start < n))
00987                 {
00988                         stop = text.find_first_of(separators, start);
00989                         if ((stop < 0) || (stop > n)) stop = n;
00990                         words.push_back(text.substr(start, stop - start));
00991                         start = text.find_first_not_of(separators, stop+1);
00992                 }
00993 }
00994 
00995 
00996 // Stage calls this when the model starts up
00997 extern "C" int Init( ModelPosition* mod, CtrlArgs* args )
00998 {  
00999   // some init for only the first controller
01000   if( Robot::tasks.size() == 0 )
01001                 {
01002                         srandom( time(NULL) );
01003                         
01004                         // tokenize the worldfile ctrl argument string into words
01005                         std::vector<std::string> words;
01006                         split( args->worldfile, std::string(" \t"), words );                    
01007                         // expecting at least one task color name 
01008                         assert( words.size() > 1 );
01009                         
01010                         const World* w = mod->GetWorld();
01011                         
01012                         // make an array of tasks by reading the controller arguments
01013                         for( unsigned int s=1; s<words.size(); s++ )
01014                                 Robot::tasks.push_back( Robot::Task( w->GetModel( words[s] + "_source"),
01015                                                                                                                                                                                  w->GetModel( words[s] + "_sink") ) );                   
01016                 }
01017         
01018   new Robot( mod,
01019                                                  mod->GetWorld()->GetModel( "fuel_zone" ),
01020                                                  mod->GetWorld()->GetModel( "pool_zone" ) );
01021         
01022   return 0; //ok
01023 }
01024 
01025 
01026 


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Thu Aug 27 2015 15:20:57