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