fasr.cc
Go to the documentation of this file.
1 #include "stage.hh"
2 using namespace Stg;
3 
4 const bool verbose = false;
5 
6 // navigation control params
7 const double cruisespeed = 0.4;
8 const double avoidspeed = 0.05;
9 const double avoidturn = 0.5;
10 const double minfrontdistance = 0.7;
11 const double stopdist = 0.5;
12 const int avoidduration = 10;
13 const int workduration = 20;
14 const unsigned int payload = 1;
15 
16 double have[4][4] = {
17  { 90, 180, 180, 180 },
18  { 90, -90, 180, 90 },
19  { 90, 90, 180, 90 },
20  { 0, 45, 0, 0}
21 };
22 
23 double need[4][4] = {
24  { -120, -180, 180, 180 },
25  { -90, -120, 180, 90 },
26  { -90, -90, 180, 180 },
27  { -90, -180, -90, -90 }
28 };
29 
30 double refuel[4][4] = {
31  { 0, 0, 45, 120 },
32  { 0,-90, -60, -160 },
33  { -90, -90, 180, 180 },
34  { -90, -180, -90, -90 }
35 };
36 
37 typedef enum {
41 } nav_mode_t;
42 
43 class Robot
44 {
45 private:
50  //ModelBlobfinder* blobfinder;
51  //ModelGripper* gripper;
52  Model *source, *sink;
53  int avoidcount, randcount;
54  int work_get, work_put;
57  double charger_range;
60  bool at_dest;
61 
62 public:
64  Model* source,
65  Model* sink )
66  : pos(pos),
67  laser( (ModelRanger*)pos->GetChild( "ranger:1" )),
68  ranger( (ModelRanger*)pos->GetChild( "ranger:0" )),
69  fiducial( (ModelFiducial*)pos->GetUnusedModelOfType( "fiducial" )),
70  //blobfinder( (ModelBlobfinder*)pos->GetUnusedModelOfType( "blobfinder" )),
71  //gripper( (ModelGripper*)pos->GetUnusedModelOfType( "gripper" )),
72  source(source),
73  sink(sink),
74  avoidcount(0),
75  randcount(0),
76  work_get(0),
77  work_put(0),
78  charger_ahoy(false),
79  charger_bearing(0),
80  charger_range(0),
81  charger_heading(0),
82  mode(MODE_WORK),
83  at_dest( false )
84  {
85  // need at least these models to get any work done
86  // (pos must be good, as we used it in the initialization list)
87  assert( laser );
88  assert( source );
89  assert( sink );
90 
91  // pos->GetUnusedModelOfType( "laser" );
92 
93  // PositionUpdate() checks to see if we reached source or sink
95  pos->Subscribe();
96 
97  // LaserUpdate() controls the robot, by reading from laser and
98  // writing to position
100  laser->Subscribe();
101 
103  fiducial->Subscribe();
104 
105  //gripper->AddUpdateCallback( (model_callback_t)GripperUpdate, this );
106  //gripper->Subscribe();
107 
108  //blobfinder->AddUpdateCallback( (model_callback_t)BlobFinderUpdate, this );
109  //blobfinder->Subscribe();
110 
111  //pos->AddFlagIncrCallback( (model_callback_t)FlagIncr, NULL );
112  //pos->AddFlagDecrCallback( (model_callback_t)FlagDecr, NULL );
113 }
114 
115  void Dock()
116  {
117  // close the grippers so they can be pushed into the charger
118  //ModelGripper::config_t gripper_data = gripper->GetConfig();
119 
120 // if( gripper_data.paddles != ModelGripper::PADDLE_CLOSED )
121 // gripper->CommandClose();
122 // else if( gripper_data.lift != ModelGripper::LIFT_UP )
123 // gripper->CommandUp();
124 
125  if( charger_ahoy )
126  {
127  double a_goal = normalize( charger_bearing );
128 
129  // if( pos->Stalled() )
130  // {
131  // puts( "stalled. stopping" );
132  // pos->Stop();
133  // }
134  // else
135 
136  if( charger_range > 0.5 )
137  {
138  if( !ObstacleAvoid() )
139  {
140  pos->SetXSpeed( cruisespeed );
141  pos->SetTurnSpeed( a_goal );
142  }
143  }
144  else
145  {
146  pos->SetTurnSpeed( a_goal );
147  pos->SetXSpeed( 0.02 ); // creep towards it
148 
149  if( charger_range < 0.08 ) // close enough
150  pos->Stop();
151 
152  if( pos->Stalled() ) // touching
153  pos->SetXSpeed( -0.01 ); // back off a bit
154 
155  }
156  }
157  else
158  {
159  //printf( "docking but can't see a charger\n" );
160  pos->Stop();
161  mode = MODE_WORK; // should get us back on track eventually
162  }
163 
164  // if the battery is charged, go back to work
165  if( Full() )
166  {
167  //printf( "fully charged, now back to work\n" );
168  mode = MODE_UNDOCK;
169  }
170  }
171 
172 
173  void UnDock()
174  {
175  //const meters_t gripper_distance = 0.2;
176  const meters_t back_off_distance = 0.3;
177  const meters_t back_off_speed = -0.05;
178 
179  // back up a bit
180  if( charger_range < back_off_distance )
181  pos->SetXSpeed( back_off_speed );
182  else
183  pos->SetXSpeed( 0.0 );
184 
185  // once we have backed off a bit, open and lower the gripper
186 // ModelGripper::config_t gripper_data = gripper->GetConfig();
187 // if( charger_range > gripper_distance )
188 // {
189 // if( gripper_data.paddles != ModelGripper::PADDLE_OPEN )
190 // gripper->CommandOpen();
191 // else if( gripper_data.lift != ModelGripper::LIFT_DOWN )
192 // gripper->CommandDown();
193 // }
194 
195  // if the gripper is down and open and we're away from the charger, undock is finished
196  if( //gripper_data.paddles == ModelGripper::PADDLE_OPEN &&
197  //gripper_data.lift == ModelGripper::LIFT_DOWN &&
198  charger_range > back_off_distance )
199  mode = MODE_WORK;
200  }
201 
203  {
204  bool obstruction = false;
205  bool stop = false;
206 
207  // find the closest distance to the left and right and check if
208  // there's anything in front
209  double minleft = 1e6;
210  double minright = 1e6;
211 
212  // Get the data from the first sensor of the laser
213  const std::vector<meters_t>& scan = laser->GetSensors()[0].ranges;
214 
215  uint32_t sample_count = scan.size();
216 
217  for (uint32_t i = 0; i < sample_count; i++)
218  {
219  if( verbose ) printf( "%.3f ", scan[i] );
220 
221  if( (i > (sample_count/4))
222  && (i < (sample_count - (sample_count/4)))
223  && scan[i] < minfrontdistance)
224  {
225  if( verbose ) puts( " obstruction!" );
226  obstruction = true;
227  }
228 
229  if( scan[i] < stopdist )
230  {
231  if( verbose ) puts( " stopping!" );
232  stop = true;
233  }
234 
235  if( i > sample_count/2 )
236  minleft = std::min( minleft, scan[i] );
237  else
238  minright = std::min( minright, scan[i] );
239  }
240 
241  if( verbose )
242  {
243  puts( "" );
244  printf( "minleft %.3f \n", minleft );
245  printf( "minright %.3f\n ", minright );
246  }
247 
248  if( obstruction || stop || (avoidcount>0) )
249  {
250  if( verbose ) printf( "Avoid %d\n", avoidcount );
251 
252  pos->SetXSpeed( stop ? 0.0 : avoidspeed );
253 
254  /* once we start avoiding, select a turn direction and stick
255  with it for a few iterations */
256  if( avoidcount < 1 )
257  {
258  if( verbose ) puts( "Avoid START" );
259  avoidcount = random() % avoidduration + avoidduration;
260 
261  if( minleft < minright )
262  {
263  pos->SetTurnSpeed( -avoidturn );
264  if( verbose ) printf( "turning right %.2f\n", -avoidturn );
265  }
266  else
267  {
268  pos->SetTurnSpeed( +avoidturn );
269  if( verbose ) printf( "turning left %2f\n", +avoidturn );
270  }
271  }
272 
273  avoidcount--;
274 
275  return true; // busy avoding obstacles
276  }
277 
278  return false; // didn't have to avoid anything
279  }
280 
281 
282  void Work()
283  {
284  if( ! ObstacleAvoid() )
285  {
286  if( verbose ) puts( "Cruise" );
287 
288  //ModelGripper::config_t gdata = gripper->GetConfig();
289 
290  //avoidcount = 0;
291  pos->SetXSpeed( cruisespeed );
292 
293  Pose pose = pos->GetPose();
294 
295  int x = (pose.x + 8) / 4;
296  int y = (pose.y + 8) / 4;
297 
298  // oh what an awful bug - 5 hours to track this down. When using
299  // this controller in a world larger than 8*8 meters, a_goal can
300  // sometimes be NAN. Causing trouble WAY upstream.
301  if( x > 3 ) x = 3;
302  if( y > 3 ) y = 3;
303  if( x < 0 ) x = 0;
304  if( y < 0 ) y = 0;
305 
306  double a_goal =
307  dtor( ( pos->GetFlagCount() ) ? have[y][x] : need[y][x] );
308 
309  // if we are low on juice - find the direction to the recharger instead
310  if( Hungry() )
311  {
312  //puts( "hungry - using refuel map" );
313 
314  // use the refuel map
315  a_goal = dtor( refuel[y][x] );
316 
317  if( charger_ahoy ) // I see a charger while hungry!
318  mode = MODE_DOCK;
319  }
320  else
321  {
322  if( ! at_dest )
323  {
324  //if( gdata.beam[0] ) // inner break beam broken
325  //gripper->CommandClose();
326  }
327  }
328 
329  double a_error = normalize( a_goal - pose.a );
330  pos->SetTurnSpeed( a_error );
331  }
332  }
333 
334 
335  // inspect the laser data and decide what to do
336  static int LaserUpdate( ModelRanger* laser, Robot* robot )
337  {
338  // if( laser->power_pack && laser->power_pack->charging )
339  // printf( "model %s power pack @%p is charging\n",
340  // laser->Token(), laser->power_pack );
341 
342  //assert( laser->GetSamples().size() > 0 );
343 
344  switch( robot->mode )
345  {
346  case MODE_DOCK:
347  //puts( "DOCK" );
348  robot->Dock();
349  break;
350 
351  case MODE_WORK:
352  //puts( "WORK" );
353  robot->Work();
354  break;
355 
356  case MODE_UNDOCK:
357  //puts( "UNDOCK" );
358  robot->UnDock();
359  break;
360 
361  default:
362  printf( "unrecognized mode %u\n", robot->mode );
363  }
364 
365  return 0;
366  }
367 
368  bool Hungry()
369  {
370  return( pos->FindPowerPack()->ProportionRemaining() < 0.25 );
371  }
372 
373  bool Full()
374  {
375  return( pos->FindPowerPack()->ProportionRemaining() > 0.95 );
376  }
377 
378  static int PositionUpdate( ModelPosition* pos, Robot* robot )
379  {
380  Pose pose = pos->GetPose();
381 
382  //printf( "Pose: [%.2f %.2f %.2f %.2f]\n",
383  // pose.x, pose.y, pose.z, pose.a );
384 
385  //pose.z += 0.0001;
386  //robot->pos->SetPose( pose );
387 
388  if( pos->GetFlagCount() < payload &&
389  hypot( -7-pose.x, -7-pose.y ) < 2.0 )
390  {
391  if( ++robot->work_get > workduration )
392  {
393  // transfer a chunk from source to robot
394  pos->PushFlag( robot->source->PopFlag() );
395  robot->work_get = 0;
396  }
397  }
398 
399  robot->at_dest = false;
400 
401  if( hypot( 7-pose.x, 7-pose.y ) < 1.0 )
402  {
403  robot->at_dest = true;
404 
405  //robot->gripper->CommandOpen();
406 
407  if( ++robot->work_put > workduration )
408  {
409  //puts( "dropping" );
410  // transfer a chunk between robot and goal
411  robot->sink->PushFlag( pos->PopFlag() );
412  robot->work_put = 0;
413  }
414  }
415 
416 
417  //printf( "diss: %.2f\n", pos->FindPowerPack()->GetDissipated() );
418 
419  return 0; // run again
420  }
421 
422 
423 
424  static int FiducialUpdate( ModelFiducial* mod, Robot* robot )
425  {
426  robot->charger_ahoy = false;
427 
428  std::vector<ModelFiducial::Fiducial>& fids = mod->GetFiducials();
429 
430  for( unsigned int i = 0; i < fids.size(); i++ )
431  {
432  //printf( "fiducial %d is %d at %.2f m %.2f radians\n",
433  // i, f->id, f->range, f->bearing );
434 
435  if( fids[i].id == 2 ) // I see a charging station
436  {
437  // record that I've seen it and where it is
438  robot->charger_ahoy = true;
439  robot->charger_bearing = fids[i].bearing;
440  robot->charger_range = fids[i].range;
441  robot->charger_heading = fids[i].geom.a;
442 
443  //printf( "charger at %.2f radians\n", robot->charger_bearing );
444  break;
445  }
446  }
447 
448  return 0; // run again
449  }
450 
451 // static int BlobFinderUpdate( ModelBlobfinder* blobmod, Robot* robot )
452 // {
453 // unsigned int blob_count = 0;
454 // const ModelBlobfinder::Blob* blobs = blobmod->GetBlobs( &blob_count );
455 
456 // if( blobs && (blob_count>0) )
457 // {
458 // printf( "%s sees %u blobs\n", blobmod->Token(), blob_count );
459 // }
460 
461 // return 0;
462 // }
463 
464 // static int GripperUpdate( ModelGripper* grip, Robot* robot )
465 // {
466 // ModelGripper::config_t gdata = grip->GetConfig();
467 
468 // printf( "BREAKBEAMS %s %s\n",
469 // gdata.beam[0] ? gdata.beam[0]->Token() : "<null>",
470 // gdata.beam[1] ? gdata.beam[1]->Token() : "<null>" );
471 
472 // printf( "CONTACTS %s %s\n",
473 // gdata.contact[0] ? gdata.contact[0]->Token() : "<null>",
474 // gdata.contact[1] ? gdata.contact[1]->Token() : "<null>");
475 
476 
477 // return 0;
478 // }
479 
480 // static int FlagIncr( Model* mod, Robot* robot )
481 // {
482 // printf( "model %s collected flag\n", mod->Token() );
483 // return 0;
484 // }
485 
486 // static int FlagDecr( Model* mod, Robot* robot )
487 // {
488 // printf( "model %s dropped flag\n", mod->Token() );
489 // return 0;
490 // }
491 
492 };
493 
494 // Stage calls this when the model starts up
495 extern "C" int Init( Model* mod, CtrlArgs* args )
496 {
497  new Robot( (ModelPosition*)mod,
498  mod->GetWorld()->GetModel( "source" ),
499  mod->GetWorld()->GetModel( "sink" ) );
500 
501  return 0; //ok
502 }
503 
504 
505 
void SetTurnSpeed(double a)
Model class
Definition: stage.hh:1742
const double avoidturn
Definition: fasr.cc:9
void UnDock()
Definition: fasr.cc:173
unsigned int GetFlagCount() const
Definition: stage.hh:2261
double dtor(double d)
Definition: stage.hh:151
Definition: fasr.cc:43
The Stage library uses its own namespace.
Definition: canvas.hh:8
std::vector< Fiducial > & GetFiducials()
Definition: stage.hh:2733
Model * sink
Definition: fasr.cc:52
static int LaserUpdate(ModelRanger *laser, Robot *robot)
Definition: fasr.cc:336
bool Full()
Definition: fasr.cc:373
ModelRanger * ranger
Definition: fasr.cc:48
const double stopdist
Definition: fasr.cc:11
double need[4][4]
Definition: fasr.cc:23
static int PositionUpdate(ModelPosition *pos, Robot *robot)
Definition: fasr.cc:378
void Init(int *argc, char **argv[])
Definition: stage.cc:18
const double avoidspeed
Definition: fasr.cc:8
double charger_heading
Definition: fasr.cc:58
int randcount
Definition: fasr.cc:53
const double minfrontdistance
Definition: fasr.cc:10
ModelFiducial * fiducial
Definition: fasr.cc:49
int(* model_callback_t)(Model *mod, void *user)
Definition: stage.hh:568
bool ObstacleAvoid()
Definition: fasr.cc:202
Model * source
Definition: fasr.cc:52
int FiducialUpdate(ModelFiducial *fid, robot_t *robot)
const int workduration
Definition: fasr.cc:13
double ProportionRemaining() const
Definition: stage.hh:1708
nav_mode_t mode
Definition: fasr.cc:59
static int FiducialUpdate(ModelFiducial *mod, Robot *robot)
Definition: fasr.cc:424
int work_put
Definition: fasr.cc:54
World * GetWorld() const
Definition: stage.hh:2302
meters_t y
Definition: stage.hh:251
ModelPosition class
Definition: stage.hh:2927
const double cruisespeed
Definition: fasr.cc:7
Robot(ModelPosition *pos, Model *source, Model *sink)
Definition: fasr.cc:63
bool charger_ahoy
Definition: fasr.cc:55
double normalize(double a)
Definition: stage.hh:154
int LaserUpdate(Model *mod, robot_t *robot)
Definition: wander.cc:54
const int avoidduration
Definition: fasr.cc:12
void SetXSpeed(double x)
Flag * PopFlag()
Definition: model.cc:408
void AddCallback(callback_type_t type, model_callback_t cb, void *user)
int PositionUpdate(Model *mod, robot_t *robot)
Definition: wander.cc:147
ModelRanger * laser
Definition: fasr.cc:47
void Work()
Definition: fasr.cc:282
void PushFlag(Flag *flag)
Definition: model.cc:399
bool Stalled() const
Definition: stage.hh:2457
double meters_t
Definition: stage.hh:174
const std::vector< Sensor > & GetSensors() const
Definition: stage.hh:2804
double charger_range
Definition: fasr.cc:57
double refuel[4][4]
Definition: fasr.cc:30
void Subscribe()
Definition: model.cc:646
ModelFiducial class
Definition: stage.hh:2687
ModelRanger class
Definition: stage.hh:2747
bool Hungry()
Definition: fasr.cc:368
int work_get
Definition: fasr.cc:54
const bool verbose
Definition: fasr.cc:4
Model * GetModel(const std::string &name) const
Definition: world.cc:707
nav_mode_t
Definition: fasr.cc:37
PowerPack * FindPowerPack() const
Definition: model.cc:985
bool at_dest
Definition: fasr.cc:60
Pose GetPose() const
Definition: stage.hh:2382
radians_t a
rotation about the z axis.
Definition: stage.hh:252
ModelPosition * pos
Definition: fasr.cc:46
void Dock()
Definition: fasr.cc:115
double have[4][4]
Definition: fasr.cc:16
double charger_bearing
Definition: fasr.cc:56
meters_t x
Definition: stage.hh:251
const unsigned int payload
Definition: fasr.cc:14


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