00001 #include <pthread.h>
00002
00003 #include "stage.hh"
00004 using namespace Stg;
00005
00006
00007 #include "astar/astar.h"
00008
00009 static const bool verbose = false;
00010
00011
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;
00025 m /= size_m / (float)size_c;
00026 return (unsigned int)floor(m);
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;
00034 m -= size_m / 2.0;
00035
00036 return m + cell_size/2.0;
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
00121
00122
00123 if( nodes.empty() )
00124 return 0;
00125
00126
00127 Node* best_node = NULL;
00128
00129
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
00136
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
00151 heading_result = atan2( best_node->pose.y - pose.y,
00152 best_node->pose.x - pose.x );
00153
00154
00155
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
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() ),
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
00279
00280 assert( laser );
00281 assert( fiducial );
00282 assert( sonar );
00283 assert( goal );
00284
00285
00286 pos->SetColor( tasks[task].source->GetColor() );
00287
00288 tasks[task].participants++;
00289
00290 EnableLaser(true);
00291
00292
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
00303
00304 memset( map_data, 0, sizeof(uint8_t) * map_width * map_height);
00305
00306
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
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
00334
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
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
00399
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
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 graphp = LookupPlan( start, goal );
00426
00427 if( ! graphp )
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
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++ );
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
00474 }
00475
00476
00477
00478 }
00479
00480
00481 void Dock()
00482 {
00483 const meters_t creep_distance = 0.5;
00484
00485 if( charger_ahoy )
00486 {
00487
00488
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
00501 {
00502 pos->SetTurnSpeed( a_goal );
00503 pos->SetXSpeed( 0.02 );
00504
00505 if( charger_range < 0.08 )
00506 {
00507 pos->Stop();
00508 docked_angle = pos->GetPose().a;
00509 EnableLaser( false );
00510 }
00511
00512 if( pos->Stalled() )
00513 pos->SetXSpeed( -0.01 );
00514 }
00515 }
00516 else
00517 {
00518
00519 pos->Stop();
00520 EnableFiducial( false );
00521 mode = MODE_WORK;
00522 }
00523
00524
00525 if( Full() )
00526 {
00527
00528 mode = MODE_UNDOCK;
00529 EnableSonar(true);
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
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
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 {
00574
00575 double heading_error = normalize( pos->GetPose().a - (docked_angle + M_PI ) );
00576
00577 if( fabs( heading_error ) > 0.05 )
00578 {
00579
00580 pos->SetXSpeed( 0 );
00581 pos->SetTurnSpeed( undock_rotate_speed * sgn(-heading_error) );
00582 }
00583 else
00584 {
00585
00586 mode = MODE_WORK;
00587
00588
00589 if( pos->GetFlagCount() == 0 )
00590 {
00591
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
00611
00612 double minleft = 1e6;
00613 double minright = 1e6;
00614
00615
00616
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
00661
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;
00682 }
00683
00684 return false;
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
00712
00713 if( graphp == NULL ||
00714 (graphp->GoodDirection( pose, 5.0, a_goal ) == 0) ||
00715 (goal->GetPose().Distance2D( cached_goal_pose ) > 0.5) )
00716 {
00717
00718
00719
00720
00721
00722
00723 Plan( goal->GetPose() );
00724 cached_goal_pose = goal->GetPose();
00725 }
00726
00727
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 )
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
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
00778
00779
00780
00781
00782
00783
00784 }
00785 }
00786
00787 Pose pose = pos->GetPose();
00788
00789
00790
00791 charger_ahoy = false;
00792
00793
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
00805
00806
00807 ModelFiducial::Fiducial* f = &fids[i];
00808
00809
00810 if( f->id == 2 && ( closest == NULL || f->range < closest->range ))
00811 closest = f;
00812 }
00813
00814 if( closest )
00815 {
00816 charger_ahoy = true;
00817
00818
00819
00820 charger_bearing = closest->bearing;
00821 charger_range = closest->range;
00822 charger_heading = closest->geom.a;
00823 }
00824 }
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834 if( goal == tasks[task].source )
00835 {
00836
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
00843 if( dest_dist < sourcegeom.size.x/2.0 )
00844 if( wait_started_at < 0 && pos->GetFlagCount() == 0 )
00845 {
00846 wait_started_at = pos->GetWorld()->SimTimeNow() / 1e6;
00847
00848 }
00849
00850 if( wait_started_at > 0 )
00851 {
00852
00853
00854
00855 if( drand48() < 0.0005 )
00856 {
00857
00858
00859
00860 force_recharge = true;
00861 tasks[task].participants--;
00862 wait_started_at = -1;
00863 return 0;
00864 }
00865 }
00866
00867
00868 if( dest_dist < sourcegeom.size.x/2.0 &&
00869 pos->GetFlagCount() < PAYLOAD )
00870 {
00871
00872
00873 pos->PushFlag( goal->PopFlag() );
00874
00875 if( pos->GetFlagCount() == 1 && wait_started_at > 0 )
00876 {
00877
00878 wait_started_at = -1;
00879 }
00880
00881 if( pos->GetFlagCount() == PAYLOAD )
00882 SetGoal( tasks[task].sink );
00883 }
00884 }
00885 else if( goal == tasks[task].sink )
00886 {
00887
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
00895
00896
00897 Model::Flag* f = pos->PopFlag();
00898 f->SetColor( Color(0,1,0) );
00899 goal->PushFlag( f );
00900
00901 if( pos->GetFlagCount() == 0 )
00902 SetGoal( tasks[task].source );
00903 }
00904 }
00905 else
00906 {
00907 assert( goal == fuel_zone || goal == pool_zone );
00908 }
00909
00910 switch( mode )
00911 {
00912 case MODE_DOCK:
00913
00914 Dock();
00915 break;
00916
00917 case MODE_WORK:
00918
00919 Work();
00920 break;
00921
00922 case MODE_UNDOCK:
00923
00924 UnDock();
00925 break;
00926
00927 default:
00928 printf( "unrecognized mode %u\n", mode );
00929 }
00930
00931
00932 return 0;
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
00952
00953
00954
00955
00956
00957
00958
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
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
00997 extern "C" int Init( ModelPosition* mod, CtrlArgs* args )
00998 {
00999
01000 if( Robot::tasks.size() == 0 )
01001 {
01002 srandom( time(NULL) );
01003
01004
01005 std::vector<std::string> words;
01006 split( args->worldfile, std::string(" \t"), words );
01007
01008 assert( words.size() > 1 );
01009
01010 const World* w = mod->GetWorld();
01011
01012
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;
01023 }
01024
01025
01026