fasr2.cc
Go to the documentation of this file.
1 #include <pthread.h>
2 
3 #include "stage.hh"
4 using namespace Stg;
5 
6 // generic planner implementation
7 #include "astar/astar.h"
8 
9 static const bool verbose = false;
10 
11 // navigation control params
12 static const double cruisespeed = 0.4;
13 static const double avoidspeed = 0.05;
14 static const double avoidturn = 0.5;
15 static const double minfrontdistance = 0.7;
16 static const double stopdist = 0.5;
17 static const unsigned int avoidduration = 10;
18 static const unsigned int PAYLOAD = 1;
19 
20 
21 static unsigned int
22 MetersToCell( meters_t m, meters_t size_m, unsigned int size_c )
23 {
24  m += size_m / 2.0; // shift to local coords
25  m /= size_m / (float)size_c; // scale
26  return (unsigned int)floor(m); // quantize
27 }
28 
29 static meters_t
30 CellToMeters( unsigned int c, meters_t size_m, unsigned int size_c )
31 {
32  meters_t cell_size = size_m/(float)size_c;
33  meters_t m = c * cell_size; // scale
34  m -= size_m / 2.0; // shift to local coords
35 
36  return m + cell_size/2.0; // offset to cell center
37 }
38 
39 
40 class Robot
41 {
42 public:
43  class Task
44  {
45  public:
48  unsigned int participants;
49 
50  Task( Model* source, Model* sink )
51  : source(source), sink(sink), participants(0)
52  {}
53  };
54 
55  static std::vector<Task> tasks;
56 
57 private:
58  class Node;
59 
60  class Edge
61  {
62  public:
63  Node* to;
64  double cost;
65 
66  Edge( Node* to, double cost=1.0 )
67  : to(to), cost(cost) {}
68  };
69 
70  class Node
71  {
72  public:
74  double value;
75  std::vector<Edge*> edges;
76 
77  Node( Pose pose, double value=0 )
78  : pose(pose), value(value), edges() {}
79 
80  ~Node()
81  {
82  FOR_EACH( it, edges )
83  { delete *it; }
84  }
85 
86  void AddEdge( Edge* edge )
87  {
88  assert(edge);
89  edges.push_back( edge );
90  }
91 
92  void Draw() const;
93  };
94 
95  class Graph
96  {
97  public:
98  std::vector<Node*> nodes;
99 
100  Graph(){}
101  ~Graph() { FOR_EACH( it, nodes ){ delete *it; }}
102 
103  void AddNode( Node* node ){ nodes.push_back( node ); }
104 
105  void PopFront()
106  {
107  const std::vector<Node*>::iterator& it = nodes.begin();
108  delete *it;
109  nodes.erase( it );
110  }
111 
112  void Draw() const
113  {
114  glPointSize(3);
115  FOR_EACH( it, nodes ){ (*it)->Draw(); }
116  }
117 
118  bool GoodDirection( const Pose& pose, meters_t range, radians_t& heading_result )
119  {
120  // find the node with the lowest value within range of the given
121  // pose and return the absolute heading from pose to that node
122 
123  if( nodes.empty() )
124  return 0; // a null guess
125 
126 
127  Node* best_node = NULL;
128 
129  // find the closest node
130  FOR_EACH( it, nodes )
131  {
132  Node* node = *it;
133  double dist = hypot( node->pose.x - pose.x, node->pose.y - pose.y );
134 
135  // if it's in range, and either its the first we have found,
136  // or it has a lower value than the current best
137  if( dist < range &&
138  ( best_node == NULL || node->value < best_node->value ))
139  {
140  best_node = node;
141  }
142  }
143 
144  if( best_node == NULL )
145  {
146  fprintf( stderr, "FASR warning: no nodes in range" );
147  return false;
148  }
149 
150  //else
151  heading_result = atan2( best_node->pose.y - pose.y,
152  best_node->pose.x - pose.x );
153 
154  // add a little bias to one side (the left) - creates two lanes
155  // of robot traffic
156  heading_result = normalize( heading_result + 0.25 );
157 
158  return true;
159  }
160  };
161 
162  class GraphVis : public Visualizer
163  {
164  public:
166 
167  GraphVis( Graph** graphpp )
168  : Visualizer( "graph", "vis_graph" ), graphpp(graphpp) {}
169  virtual ~GraphVis(){}
170 
171  virtual void Visualize( Model* mod, Camera* cam )
172  {
173  if( *graphpp == NULL )
174  return;
175 
176  glPushMatrix();
177 
179 
180  //mod->PushColor( 1,0,0,1 );
181 
182  Color c = mod->GetColor();
183  c.a = 0.4;
184 
185  mod->PushColor( c );
186  (*graphpp)->Draw();
187  mod->PopColor();
188 
189  glPopMatrix();
190  }
191  };
192 
193 
194 private:
195  long int wait_started_at;
196 
197  ModelPosition* pos;
198  ModelRanger* laser;
200  ModelFiducial* fiducial;
201 
202  unsigned int task;
203 
206  int avoidcount, randcount;
207  int work_get, work_put;
208  bool charger_ahoy;
209  double charger_bearing;
210  double charger_range;
211  double charger_heading;
212 
213  enum {
217  MODE_QUEUE
218  } mode;
219 
221 
222  static pthread_mutex_t planner_mutex;
223 
226 
229  unsigned int node_interval;
231 
232  static const unsigned int map_width;
233  static const unsigned int map_height;
234  static uint8_t* map_data;
235  static Model* map_model;
236 
238  bool laser_sub;
239  bool sonar_sub;
240 
242 
243 public:
244 
246  Model* fuel,
247  Model* pool )
248  :
249  wait_started_at(-1),
250  pos(pos),
251  laser( (ModelRanger*)pos->GetChild( "ranger:1" )),
252  sonar( (ModelRanger*)pos->GetChild( "ranger:0" )),
253  fiducial( (ModelFiducial*)pos->GetUnusedModelOfType( "fiducial" )),
254  task(random() % tasks.size() ), // choose a task at random
255  fuel_zone(fuel),
256  pool_zone(pool),
257  avoidcount(0),
258  randcount(0),
259  work_get(0),
260  work_put(0),
261  charger_ahoy(false),
262  charger_bearing(0),
263  charger_range(0),
264  charger_heading(0),
265  mode(MODE_WORK),
266  docked_angle(0),
267  goal(tasks[task].source),
268  cached_goal_pose(),
269  graphp(NULL),
270  graphvis( &graphp ),
271  node_interval( 20 ),
272  node_interval_countdown( node_interval ),
273  fiducial_sub(false),
274  laser_sub(false),
275  sonar_sub(false),
276  force_recharge( false )
277  {
278  // need at least these models to get any work done
279  // (pos must be good, as we used it in the initialization list)
280  assert( laser );
281  assert( fiducial );
282  assert( sonar );
283  assert( goal );
284 
285  // match the color of my destination
286  pos->SetColor( tasks[task].source->GetColor() );
287 
288  tasks[task].participants++;
289 
290  EnableLaser(true);
291 
292  // we access all other data from the position callback
294  pos->Subscribe();
295 
296  pos->AddVisualizer( &graphvis, true );
297 
298  if( map_data == NULL )
299  {
300  map_data = new uint8_t[map_width*map_height*2];
301 
302  // MUST clear the data, since Model::Rasterize() only enters
303  // non-zero pixels
304  memset( map_data, 0, sizeof(uint8_t) * map_width * map_height);
305 
306  // get the map
307  map_model = pos->GetWorld()->GetModel( "cave" );
308  assert(map_model);
309  Geom g = map_model->GetGeom();
310 
311  map_model->Rasterize( map_data,
312  map_width,
313  map_height,
314  g.size.x/(float)map_width,
315  g.size.y/(float)map_height );
316 
317  // fix the node costs for astar: 0=>1, 1=>9
318 
319  unsigned int sz = map_width * map_height;
320  for( unsigned int i=0; i<sz; i++ )
321  {
322  if( map_data[i] == 0 )
323  map_data[i] = 1;
324  else if( map_data[i] == 1 )
325  map_data[i] = 9;
326  else
327  printf( "FASR: bad value %d in map at index %d\n", (int)map_data[i], (int)i );
328 
329  assert( (map_data[i] == 1) || (map_data[i] == 9) );
330  }
331  }
332 
333  //( goal );
334  //puts("");
335  }
336 
337 
338  void Enable( Stg::Model* model, bool& sub, bool on )
339  {
340  if( on && !sub )
341  {
342  sub = true;
343  model->Subscribe();
344  }
345 
346  if( !on && sub )
347  {
348  sub = false;
349  model->Unsubscribe();
350  }
351  }
352 
353  void EnableSonar( bool on )
354  {
355  Enable( sonar, sonar_sub, on );
356  }
357 
358  void EnableLaser( bool on )
359  {
360  Enable( laser, laser_sub, on );
361  }
362 
363  void EnableFiducial( bool on )
364  {
365  Enable( fiducial, fiducial_sub, on );
366  }
367 
368  static std::map< std::pair<uint64_t,uint64_t>, Graph*> plancache;
369 
370 
371  uint64_t Pt64( const ast::point_t& pt)
372  {
373  // quantize the position a bit to reduce planning frequency
374  uint64_t x = pt.x / 1;
375  uint64_t y = pt.y / 1;
376 
377  return (x<<32) + y;
378  }
379 
380  void CachePlan( const ast::point_t& start, const ast::point_t& goal, Graph* graph )
381  {
382  std::pair<uint64_t,uint64_t> key( Pt64(start),Pt64(goal));
383  plancache[key] = graph;
384  }
385 
386  Graph* LookupPlan( const ast::point_t& start, const ast::point_t& goal )
387  {
388  std::pair<uint64_t,uint64_t> key(Pt64(start),Pt64(goal));
389  return plancache[key];
390  }
391 
392 
393  void Plan( Pose sp )
394  {
395  static float hits = 0;
396  static float misses = 0;
397 
398  // change my color to that of my destination
399  //pos->SetColor( dest->GetColor() );
400 
401  Pose pose = pos->GetPose();
402  Geom g = map_model->GetGeom();
403 
404  ast::point_t start( MetersToCell(pose.x, g.size.x, map_width),
405  MetersToCell(pose.y, g.size.y, map_height) );
406  ast::point_t goal( MetersToCell(sp.x, g.size.x, map_width),
407  MetersToCell(sp.y, g.size.y, map_height) );
408 
409  //printf( "searching from (%.2f, %.2f) [%d, %d]\n", pose.x, pose.y, start.x, start.y );
410  //printf( "searching to (%.2f, %.2f) [%d, %d]\n", sp.x, sp.y, goal.x, goal.y );
411 
412  // astar() is not reentrant, so we protect it thus
413 
414  //graph.nodes.clear(); // whatever happens, we clear the old plan
415 
416 
417  //pthread_mutex_lock( &planner_mutex );
418 
419  // check to see if we have a path planned for these positions already
420  //printf( "plancache @ %p size %d\n", &plancache, (int)plancache.size() );
421 
422  //if( graphp )
423  //delete graphp;
424 
425  graphp = LookupPlan( start, goal );
426 
427  if( ! graphp ) // no plan cached
428  {
429  misses++;
430 
431  std::vector<ast::point_t> path;
432  bool result = ast::astar( map_data,
433  map_width,
434  map_height,
435  start,
436  goal,
437  path );
438 
439  if( ! result )
440  printf( "FASR2 warning: plan failed to find path from (%.2f,%.2f) to (%.2f,%.2f)\n",
441  pose.x, pose.y, sp.x, sp.y );
442 
443  graphp = new Graph();
444 
445  unsigned int dist = 0;
446 
447  Node* last_node = NULL;
448 
449  for( std::vector<ast::point_t>::reverse_iterator rit = path.rbegin();
450  rit != path.rend();
451  ++rit )
452  {
453  //printf( "%d, %d\n", it->x, it->y );
454 
455  Node* node = new Node( Pose( CellToMeters(rit->x, g.size.x, map_width ),
456  CellToMeters(rit->y, g.size.y, map_height),
457  0, 0 ),
458  dist++ ); // value stored at node
459 
460  graphp->AddNode( node );
461 
462  if( last_node )
463  last_node->AddEdge( new Edge( node ) );
464 
465  last_node = node;
466  }
467 
468  CachePlan( start, goal, graphp );
469  }
470  else
471  {
472  hits++;
473  //puts( "FOUND CACHED PLAN" );
474  }
475 
476  //printf( "hits/misses %.2f\n", hits/misses );
477  //pthread_mutex_unlock( &planner_mutex );
478  }
479 
480 
481  void Dock()
482  {
483  const meters_t creep_distance = 0.5;
484 
485  if( charger_ahoy )
486  {
487  // drive toward the charger
488  // orient term helps to align with the way the charger is pointing
489  const double orient = normalize( M_PI - (charger_bearing - charger_heading) );
490  const double a_goal = normalize( charger_bearing - 2.0 * orient );
491 
492  if( charger_range > creep_distance )
493  {
494  if( !ObstacleAvoid() )
495  {
496  pos->SetXSpeed( cruisespeed );
497  pos->SetTurnSpeed( a_goal );
498  }
499  }
500  else // we are very close!
501  {
502  pos->SetTurnSpeed( a_goal );
503  pos->SetXSpeed( 0.02 ); // creep towards it
504 
505  if( charger_range < 0.08 ) // close enough
506  {
507  pos->Stop();
508  docked_angle = pos->GetPose().a;
509  EnableLaser( false );
510  }
511 
512  if( pos->Stalled() ) // touching
513  pos->SetXSpeed( -0.01 ); // back off a bit
514  }
515  }
516  else
517  {
518  //printf( "FASR: %s docking but can't see a charger\n", pos->Token() );
519  pos->Stop();
520  EnableFiducial( false );
521  mode = MODE_WORK; // should get us back on track eventually
522  }
523 
524  // if the battery is charged, go back to work
525  if( Full() )
526  {
527  //printf( "fully charged, now back to work\n" );
528  mode = MODE_UNDOCK;
529  EnableSonar(true); // enable the sonar to see behind us
530  EnableLaser(true);
531  EnableFiducial(true);
532  force_recharge = false;
533  }
534  }
535 
536  void SetTask( unsigned int t )
537  {
538  task = t;
539  tasks[task].participants++;
540  }
541 
542  void UnDock()
543  {
544  const meters_t back_off_distance = 0.2;
545  const meters_t back_off_speed = -0.02;
546  const radians_t undock_rotate_speed = 0.3;
547  const meters_t wait_distance = 0.2;
548  const unsigned int BACK_SENSOR_FIRST = 10;
549  const unsigned int BACK_SENSOR_LAST = 13;
550 
551  // make sure the required sensors are running
552  assert( sonar_sub );
553  assert( fiducial_sub );
554 
555  if( charger_range < back_off_distance )
556  {
557  pos->SetXSpeed( back_off_speed );
558 
559  pos->Say( "" );
560 
561  // stay put while anything is close behind
562  const std::vector<ModelRanger::Sensor>& sensors = sonar->GetSensors();
563 
564  for( unsigned int s = BACK_SENSOR_FIRST; s <= BACK_SENSOR_LAST; ++s )
565  if( sensors[s].ranges.size() < 1 || sensors[s].ranges[0] < wait_distance)
566  {
567  pos->Say( "Waiting..." );
568  pos->SetXSpeed( 0.0 );
569  return;
570  }
571  }
572  else
573  { // we've backed up enough
574 
575  double heading_error = normalize( pos->GetPose().a - (docked_angle + M_PI ) );
576 
577  if( fabs( heading_error ) > 0.05 )
578  {
579  // turn
580  pos->SetXSpeed( 0 );
581  pos->SetTurnSpeed( undock_rotate_speed * sgn(-heading_error) );
582  }
583  else
584  {
585  // we're pointing the right way, so we're done
586  mode = MODE_WORK;
587 
588  // if we're not working on a drop-off
589  if( pos->GetFlagCount() == 0 )
590  {
591  // pick a new task at random
592  SetTask( random() % tasks.size() );
593  SetGoal( tasks[task].source );
594  }
595  else
596  SetGoal( tasks[task].sink );
597 
598 
599  EnableFiducial(false);
600  EnableSonar(false);
601  }
602  }
603  }
604 
606  {
607  bool obstruction = false;
608  bool stop = false;
609 
610  // find the closest distance to the left and right and check if
611  // there's anything in front
612  double minleft = 1e6;
613  double minright = 1e6;
614 
615  // Get the data
616  //const std::vector<ModelLaser::Sample>& scan = laser->GetSamples();
617 
618  const std::vector<meters_t>& scan = laser->GetSensors()[0].ranges;
619 
620  uint32_t sample_count = scan.size();
621 
622 
623  for (uint32_t i = 0; i < sample_count; i++)
624  {
625  if( verbose ) printf( "%.3f ", scan[i] );
626 
627  if( (i > (sample_count/4))
628  && (i < (sample_count - (sample_count/4)))
629  && scan[i] < minfrontdistance)
630  {
631  if( verbose ) puts( " obstruction!" );
632  obstruction = true;
633  }
634 
635  if( scan[i] < stopdist )
636  {
637  if( verbose ) puts( " stopping!" );
638  stop = true;
639  }
640 
641  if( i > sample_count/2 )
642  minleft = std::min( minleft, scan[i] );
643  else
644  minright = std::min( minright, scan[i] );
645  }
646 
647  if( verbose )
648  {
649  puts( "" );
650  printf( "minleft %.3f \n", minleft );
651  printf( "minright %.3f\n ", minright );
652  }
653 
654  if( obstruction || stop || (avoidcount>0) )
655  {
656  if( verbose ) printf( "Avoid %d\n", avoidcount );
657 
658  pos->SetXSpeed( stop ? 0.0 : avoidspeed );
659 
660  /* once we start avoiding, select a turn direction and stick
661  with it for a few iterations */
662  if( avoidcount < 1 )
663  {
664  if( verbose ) puts( "Avoid START" );
665  avoidcount = random() % avoidduration + avoidduration;
666 
667  if( minleft < minright )
668  {
669  pos->SetTurnSpeed( -avoidturn );
670  if( verbose ) printf( "turning right %.2f\n", -avoidturn );
671  }
672  else
673  {
674  pos->SetTurnSpeed( +avoidturn );
675  if( verbose ) printf( "turning left %2f\n", +avoidturn );
676  }
677  }
678 
679  avoidcount--;
680 
681  return true; // busy avoding obstacles
682  }
683 
684  return false; // didn't have to avoid anything
685  }
686 
687 
688  void SetGoal( Model* goal )
689  {
690  if( goal != this->goal )
691  {
692  this->goal = goal;
693  Plan( goal->GetPose() );
694  pos->SetColor( goal->GetColor() );
695  }
696  }
697 
698  void Work()
699  {
700  if( ! ObstacleAvoid() )
701  {
702  if( verbose )
703  puts( "Cruise" );
704 
705  if( Hungry() )
706  SetGoal( fuel_zone );
707 
708  const Pose pose = pos->GetPose();
709  double a_goal = 0;
710 
711  // if the graph fails to offer advice or the goal has moved a
712  // ways since last time we planned
713  if( graphp == NULL ||
714  (graphp->GoodDirection( pose, 5.0, a_goal ) == 0) ||
715  (goal->GetPose().Distance2D( cached_goal_pose ) > 0.5) )
716  {
717  //printf( "%s replanning from (%.2f,%.2f) to %s at (%.2f,%.2f) in Work()\n",
718  // pos->Token(),
719  // pose.x, pose.y,
720  // goal->Token(),
721  // goal->GetPose().x,
722  // goal->GetPose().y );
723  Plan( goal->GetPose() );
724  cached_goal_pose = goal->GetPose();
725  }
726 
727  // if we are low on juice - find the direction to the recharger instead
728  if( Hungry() )
729  {
730  EnableFiducial(true);
731 
732  while( graphp->GoodDirection( pose, 5.0, a_goal ) == 0 )
733  {
734  printf( "%s replanning in Work()\n", pos->Token() );
735  }
736 
737 
738  if( charger_ahoy ) // I see a charger while hungry!
739  mode = MODE_DOCK;
740  }
741 
742  const double a_error = normalize( a_goal - pose.a );
743  pos->SetTurnSpeed( a_error );
744  pos->SetXSpeed( cruisespeed );
745  }
746  }
747 
748 
749  bool Hungry()
750  {
751  return( force_recharge || pos->FindPowerPack()->ProportionRemaining() < 0.2 );
752  }
753 
754  bool Full()
755  {
756  return( pos->FindPowerPack()->ProportionRemaining() > 0.95 );
757  }
758 
759  // static callback wrapper
760  static int UpdateCallback( ModelRanger* laser, Robot* robot )
761  {
762  return robot->Update();
763  }
764 
765  int Update( void )
766  {
767  if( strcmp( pos->Token(), "position:0") == 0 )
768  {
769  static int seconds = 0;
770 
771  int timenow = pos->GetWorld()->SimTimeNow() / 1e6;
772 
773  if( timenow - seconds > 5 )
774  {
775  seconds = timenow;
776 
777  // report the task participation
778  // printf( "time: %d sec\n", seconds );
779 
780 // unsigned int sz = tasks.size();
781 // for( unsigned int i=0; i<sz; ++i )
782 // printf( "\t task[%u] %3u (%s)\n",
783 // i, tasks[i].participants, tasks[i].source->Token() );
784  }
785  }
786 
787  Pose pose = pos->GetPose();
788 
789 
790  // assume we can't see the charger
791  charger_ahoy = false;
792 
793  // if the fiducial is enabled
794  if( fiducial_sub )
795  {
796  std::vector<ModelFiducial::Fiducial>& fids = fiducial->GetFiducials();
797 
798  if( fids.size() > 0 )
799  {
800  ModelFiducial::Fiducial* closest = NULL;
801 
802  for( unsigned int i = 0; i < fids.size(); i++ )
803  {
804  //printf( "fiducial %d is %d at %.2f m %.2f radians\n",
805  // i, f->id, f->range, f->bearing );
806 
807  ModelFiducial::Fiducial* f = &fids[i];
808 
809  // find the closest
810  if( f->id == 2 && ( closest == NULL || f->range < closest->range )) // I see a charging station
811  closest = f;
812  }
813 
814  if( closest )
815  { // record that I've seen it and where it is
816  charger_ahoy = true;
817 
818  //printf( "AHOY %s\n", pos->Token() );
819 
820  charger_bearing = closest->bearing;
821  charger_range = closest->range;
822  charger_heading = closest->geom.a;
823  }
824  }
825  }
826 
827 
828  //printf( "Pose: [%.2f %.2f %.2f %.2f]\n",
829  // pose.x, pose.y, pose.z, pose.a );
830 
831  //pose.z += 0.0001;
832  //pos->SetPose( pose );
833 
834  if( goal == tasks[task].source )
835  {
836  // if we're close to the source we get a flag
837  Pose sourcepose = goal->GetPose();
838  Geom sourcegeom = goal->GetGeom();
839 
840  meters_t dest_dist = hypot( sourcepose.x-pose.x, sourcepose.y-pose.y );
841 
842  // when we get close enough, we start waiting
843  if( dest_dist < sourcegeom.size.x/2.0 ) // nearby
844  if( wait_started_at < 0 && pos->GetFlagCount() == 0 )
845  {
846  wait_started_at = pos->GetWorld()->SimTimeNow() / 1e6; // usec to seconds
847  //printf( "%s begain waiting at %ld seconds\n", pos->Token(), wait_started_at );
848  }
849 
850  if( wait_started_at > 0 )
851  {
852  //long int waited = (pos->GetWorld()->SimTimeNow() / 1e6) - wait_started_at;
853 
854  // leave with small probability
855  if( drand48() < 0.0005 )
856  {
857  //printf( "%s abandoning task %s after waiting %ld seconds\n",
858  // pos->Token(), goal->Token(), waited );
859 
860  force_recharge = true; // forces hungry to return true
861  tasks[task].participants--;
862  wait_started_at = -1;
863  return 0;
864  }
865  }
866 
867  // when we get onto the square
868  if( dest_dist < sourcegeom.size.x/2.0 &&
869  pos->GetFlagCount() < PAYLOAD )
870  {
871 
872  // transfer a chunk from source to robot
873  pos->PushFlag( goal->PopFlag() );
874 
875  if( pos->GetFlagCount() == 1 && wait_started_at > 0 )
876  {
877  // stop waiting, since we have received our first flag
878  wait_started_at = -1;
879  }
880 
881  if( pos->GetFlagCount() == PAYLOAD )
882  SetGoal( tasks[task].sink ); // we're done working
883  }
884  }
885  else if( goal == tasks[task].sink )
886  {
887  // if we're close to the sink we lose a flag
888  Pose sinkpose = goal->GetPose();
889  Geom sinkgeom = goal->GetGeom();
890 
891  if( hypot( sinkpose.x-pose.x, sinkpose.y-pose.y ) < sinkgeom.size.x/2.0 &&
892  pos->GetFlagCount() > 0 )
893  {
894  //puts( "dropping" );
895  // transfer a chunk between robot and goal
896 
897  Model::Flag* f = pos->PopFlag();
898  f->SetColor( Color(0,1,0) ); // delivered flags are green
899  goal->PushFlag( f );
900 
901  if( pos->GetFlagCount() == 0 )
902  SetGoal( tasks[task].source ); // we're done dropping off
903  }
904  }
905  else
906  {
907  assert( goal == fuel_zone || goal == pool_zone );
908  }
909 
910  switch( mode )
911  {
912  case MODE_DOCK:
913  //puts( "DOCK" );
914  Dock();
915  break;
916 
917  case MODE_WORK:
918  //puts( "WORK" );
919  Work();
920  break;
921 
922  case MODE_UNDOCK:
923  //puts( "UNDOCK" );
924  UnDock();
925  break;
926 
927  default:
928  printf( "unrecognized mode %u\n", mode );
929  }
930 
931 
932  return 0; // run again
933  }
934 
935  static int FlagIncr( Model* mod, Robot* robot )
936  {
937  printf( "model %s collected flag\n", mod->Token() );
938  return 0;
939  }
940 
941  static int FlagDecr( Model* mod, Robot* robot )
942  {
943  printf( "model %s dropped flag\n", mod->Token() );
944  return 0;
945  }
946 };
947 
948 
949 void Robot::Node::Draw() const
950 {
951  // print value
952  //char buf[32];
953  //snprintf( buf, 32, "%.0f", value );
954  //Gl::draw_string( pose.x, pose.y+0.2, 0.1, buf );
955 
956  //glBegin( GL_POINTS );
957  //glVertex2f( pose.x, pose.y );
958  //glEnd();
959 
960  glBegin( GL_LINES );
961  FOR_EACH( it, edges )
962  {
963  glVertex2f( pose.x, pose.y );
964  glVertex2f( (*it)->to->pose.x, (*it)->to->pose.y );
965  }
966  glEnd();
967 }
968 
969 
970 // STATIC VARS
971 pthread_mutex_t Robot::planner_mutex = PTHREAD_MUTEX_INITIALIZER;
972 const unsigned int Robot::map_width( 32 );
973 const unsigned int Robot::map_height( 32 );
974 uint8_t* Robot::map_data( NULL );
975 Model* Robot::map_model( NULL );
976 
977 std::map< std::pair<uint64_t,uint64_t>, Robot::Graph*> Robot::plancache;
978 
979 std::vector<Robot::Task> Robot::tasks;
980 
981 void split( const std::string& text, const std::string& separators, std::vector<std::string>& words)
982 {
983  const int n = text.length();
984  int start, stop;
985  start = text.find_first_not_of(separators);
986  while ((start >= 0) && (start < n))
987  {
988  stop = text.find_first_of(separators, start);
989  if ((stop < 0) || (stop > n)) stop = n;
990  words.push_back(text.substr(start, stop - start));
991  start = text.find_first_not_of(separators, stop+1);
992  }
993 }
994 
995 
996 // Stage calls this when the model starts up
997 extern "C" int Init( ModelPosition* mod, CtrlArgs* args )
998 {
999  // some init for only the first controller
1000  if( Robot::tasks.size() == 0 )
1001  {
1002  srandom( time(NULL) );
1003 
1004  // tokenize the worldfile ctrl argument string into words
1005  std::vector<std::string> words;
1006  split( args->worldfile, std::string(" \t"), words );
1007  // expecting at least one task color name
1008  assert( words.size() > 1 );
1009 
1010  const World* w = mod->GetWorld();
1011 
1012  // make an array of tasks by reading the controller arguments
1013  for( unsigned int s=1; s<words.size(); s++ )
1014  Robot::tasks.push_back( Robot::Task( w->GetModel( words[s] + "_source"),
1015  w->GetModel( words[s] + "_sink") ) );
1016  }
1017 
1018  new Robot( mod,
1019  mod->GetWorld()->GetModel( "fuel_zone" ),
1020  mod->GetWorld()->GetModel( "pool_zone" ) );
1021 
1022  return 0; //ok
1023 }
1024 
1025 
1026 
void SetTurnSpeed(double a)
meters_t range
range to the target
Definition: stage.hh:2694
virtual void PushColor(Color col)
Definition: stage.hh:2189
Model class
Definition: stage.hh:1742
static meters_t CellToMeters(unsigned int c, meters_t size_m, unsigned int size_c)
Definition: fasr2.cc:30
Graph ** graphpp
Definition: fasr2.cc:165
static void UpdateCallback(WorldGui *world)
Definition: worldgui.cc:349
void AddNode(Node *node)
Definition: fasr2.cc:103
void EnableSonar(bool on)
Definition: fasr2.cc:353
Task(Model *source, Model *sink)
Definition: fasr2.cc:50
bool astar(uint8_t *map, uint32_t width, uint32_t height, const point_t start, const point_t goal, std::vector< point_t > &path)
Definition: findpath.cpp:180
void UnDock()
Definition: fasr2.cc:542
void Draw() const
Definition: fasr2.cc:112
double a
Definition: stage.hh:200
static const bool verbose
Definition: fasr2.cc:9
unsigned int task
Definition: fasr2.cc:202
unsigned int GetFlagCount() const
Definition: stage.hh:2261
double value
Definition: fasr2.cc:74
usec_t SimTimeNow(void) const
Definition: stage.hh:1119
World class
Definition: stage.hh:814
Definition: fasr.cc:43
The Stage library uses its own namespace.
Definition: canvas.hh:8
std::vector< Fiducial > & GetFiducials()
Definition: stage.hh:2733
Node(Pose pose, double value=0)
Definition: fasr2.cc:77
Node * to
Definition: fasr2.cc:63
meters_t x
Definition: stage.hh:228
bool Full()
Definition: fasr2.cc:754
static const double minfrontdistance
Definition: fasr2.cc:15
void EnableLaser(bool on)
Definition: fasr2.cc:358
void Init(int *argc, char **argv[])
Definition: stage.cc:18
std::vector< Node * > nodes
Definition: fasr2.cc:98
uint32_t x
Definition: astar.h:8
ModelRanger * sonar
Definition: fasr2.cc:199
unsigned int participants
Definition: fasr2.cc:48
int(* model_callback_t)(Model *mod, void *user)
Definition: stage.hh:568
Color GetColor() const
Definition: stage.hh:2362
Size size
extent
Definition: stage.hh:395
void Rasterize(uint8_t *data, unsigned int width, unsigned int height, meters_t cellwidth, meters_t cellheight)
Definition: model.cc:1002
bool ObstacleAvoid()
Definition: fasr2.cc:605
bool GoodDirection(const Pose &pose, meters_t range, radians_t &heading_result)
Definition: fasr2.cc:118
static const double avoidturn
Definition: fasr2.cc:14
void SetColor(const Color &col)
Definition: model.cc:1187
double ProportionRemaining() const
Definition: stage.hh:1708
static unsigned int MetersToCell(meters_t m, meters_t size_m, unsigned int size_c)
Definition: fasr2.cc:22
bool sonar_sub
Definition: fasr2.cc:239
virtual void PopColor()
Definition: stage.hh:2191
long int wait_started_at
Definition: fasr2.cc:195
void EnableFiducial(bool on)
Definition: fasr2.cc:363
void Say(const std::string &str)
Definition: model.cc:539
float s
Definition: glutgraphics.cc:58
static int FlagIncr(Model *mod, Robot *robot)
Definition: fasr2.cc:935
World * GetWorld() const
Definition: stage.hh:2302
meters_t y
Definition: stage.hh:251
double cost
Definition: fasr2.cc:64
void PopFront()
Definition: fasr2.cc:105
ModelPosition class
Definition: stage.hh:2927
static const unsigned int map_width
Definition: fasr2.cc:232
Model * source
Definition: fasr2.cc:46
Robot(ModelPosition *pos, Model *fuel, Model *pool)
Definition: fasr2.cc:245
Pose cached_goal_pose
Definition: fasr2.cc:225
void AddEdge(Edge *edge)
Definition: fasr2.cc:86
virtual ~GraphVis()
Definition: fasr2.cc:169
void pose_inverse_shift(const Pose &pose)
Definition: gl.cc:18
double normalize(double a)
Definition: stage.hh:154
void SetXSpeed(double x)
Flag * PopFlag()
Definition: model.cc:408
void AddCallback(callback_type_t type, model_callback_t cb, void *user)
void Draw() const
Definition: fasr2.cc:949
static Model * map_model
Definition: fasr2.cc:235
static const unsigned int map_height
Definition: fasr2.cc:233
void Plan(Pose sp)
Definition: fasr2.cc:393
Pose GetGlobalPose() const
Definition: model.cc:1379
radians_t bearing
bearing to the target
Definition: stage.hh:2695
void Work()
Definition: fasr2.cc:698
void PushFlag(Flag *flag)
Definition: model.cc:399
uint64_t Pt64(const ast::point_t &pt)
Definition: fasr2.cc:371
static const unsigned int avoidduration
Definition: fasr2.cc:17
bool laser_sub
Definition: fasr2.cc:238
bool Stalled() const
Definition: stage.hh:2457
void SetGoal(Model *goal)
Definition: fasr2.cc:688
uint32_t y
Definition: astar.h:8
Edge(Node *to, double cost=1.0)
Definition: fasr2.cc:66
double meters_t
Definition: stage.hh:174
int Update(void)
Definition: fasr2.cc:765
void SetTask(unsigned int t)
Definition: fasr2.cc:536
Model * pool_zone
Definition: fasr2.cc:205
meters_t y
Definition: stage.hh:228
const std::vector< Sensor > & GetSensors() const
Definition: stage.hh:2804
Model * fuel_zone
Definition: fasr2.cc:204
void AddVisualizer(Visualizer *custom_visual, bool on_by_default)
Definition: model_draw.cc:322
Graph * LookupPlan(const ast::point_t &start, const ast::point_t &goal)
Definition: fasr2.cc:386
void Subscribe()
Definition: model.cc:646
std::vector< Edge * > edges
Definition: fasr2.cc:75
static const double avoidspeed
Definition: fasr2.cc:13
static pthread_mutex_t planner_mutex
Definition: fasr2.cc:222
static std::vector< Task > tasks
Definition: fasr2.cc:55
bool fiducial_sub
Definition: fasr2.cc:237
radians_t docked_angle
Definition: fasr2.cc:220
unsigned int node_interval
Definition: fasr2.cc:229
static const double cruisespeed
Definition: fasr2.cc:12
void Unsubscribe()
Definition: model.cc:659
ModelFiducial class
Definition: stage.hh:2687
void Enable(Stg::Model *model, bool &sub, bool on)
Definition: fasr2.cc:338
meters_t Distance2D(const Pose &other) const
Definition: stage.hh:338
ModelRanger class
Definition: stage.hh:2747
Model * sink
Definition: fasr2.cc:47
bool Hungry()
Definition: fasr2.cc:749
std::string worldfile
Definition: stage.hh:805
Graph * graphp
Definition: fasr2.cc:227
Pose geom
size and relative angle of the target
Definition: stage.hh:2696
Model * GetModel(const std::string &name) const
Definition: world.cc:707
static uint8_t * map_data
Definition: fasr2.cc:234
Model * goal
Definition: fasr2.cc:224
virtual void Visualize(Model *mod, Camera *cam)
Definition: fasr2.cc:171
static int FlagDecr(Model *mod, Robot *robot)
Definition: fasr2.cc:941
bool force_recharge
Definition: fasr2.cc:241
static const unsigned int PAYLOAD
Definition: fasr2.cc:18
PowerPack * FindPowerPack() const
Definition: model.cc:985
void split(const std::string &text, const std::string &separators, std::vector< std::string > &words)
Definition: fasr2.cc:981
#define FOR_EACH(I, C)
Definition: stage.hh:616
Pose GetPose() const
Definition: stage.hh:2382
radians_t a
rotation about the z axis.
Definition: stage.hh:252
GraphVis(Graph **graphpp)
Definition: fasr2.cc:167
static int UpdateCallback(ModelRanger *laser, Robot *robot)
Definition: fasr2.cc:760
static const double stopdist
Definition: fasr2.cc:16
void Dock()
Definition: fasr2.cc:481
unsigned int node_interval_countdown
Definition: fasr2.cc:230
static std::map< std::pair< uint64_t, uint64_t >, Graph * > plancache
Definition: fasr2.cc:368
void CachePlan(const ast::point_t &start, const ast::point_t &goal, Graph *graph)
Definition: fasr2.cc:380
Pose pose
Definition: fasr2.cc:73
int id
the fiducial identifier of the target (i.e. its fiducial_return value), or -1 if none can be detected...
Definition: stage.hh:2700
void SetColor(Color col)
Definition: model.cc:1260
double radians_t
Definition: stage.hh:177
GraphVis graphvis
Definition: fasr2.cc:228
meters_t x
Definition: stage.hh:251
const char * Token() const
Definition: stage.hh:715
int sgn(int a)
Definition: stage.hh:162
Geom GetGeom() const
Definition: stage.hh:2378


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 Mon Jun 10 2019 15:06:09