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


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 Feb 28 2022 23:48:55