fasr.cc
Go to the documentation of this file.
00001 #include "stage.hh"
00002 using namespace Stg;
00003 
00004 const bool verbose = false;
00005 
00006 // navigation control params
00007 const double cruisespeed = 0.4; 
00008 const double avoidspeed = 0.05; 
00009 const double avoidturn = 0.5;
00010 const double minfrontdistance = 0.7;  
00011 const double stopdist = 0.5;
00012 const int avoidduration = 10;
00013 const int workduration = 20;
00014 const unsigned int payload = 1;
00015 
00016 double have[4][4] = { 
00017   { 90, 180, 180, 180 },
00018   { 90, -90, 180, 90 },
00019   { 90, 90, 180, 90 },
00020   { 0, 45, 0, 0} 
00021 };
00022 
00023 double need[4][4] = {
00024   { -120, -180, 180, 180 },
00025   { -90, -120, 180, 90 },
00026   { -90, -90, 180, 180 },
00027   { -90, -180, -90, -90 }
00028 };
00029 
00030 double refuel[4][4] = {
00031   {  0, 0, 45, 120 },
00032   { 0,-90, -60, -160 },
00033   { -90, -90, 180, 180 },
00034   { -90, -180, -90, -90 }
00035 };
00036 
00037 typedef enum {
00038   MODE_WORK=0,
00039   MODE_DOCK,
00040   MODE_UNDOCK
00041 } nav_mode_t;
00042 
00043 class Robot
00044 {
00045 private:
00046   ModelPosition* pos;
00047   ModelRanger* laser;
00048   ModelRanger* ranger;
00049   ModelFiducial* fiducial;
00050   //ModelBlobfinder* blobfinder;
00051   //ModelGripper* gripper;
00052   Model *source, *sink;
00053   int avoidcount, randcount;
00054   int work_get, work_put;
00055   bool charger_ahoy;
00056   double charger_bearing;
00057   double charger_range;
00058   double charger_heading;
00059   nav_mode_t mode;
00060   bool at_dest;
00061 
00062 public:
00063   Robot( ModelPosition* pos, 
00064                         Model* source,
00065                         Model* sink ) 
00066          : pos(pos), 
00067                 laser( (ModelRanger*)pos->GetChild( "ranger:1" )),
00068                 ranger( (ModelRanger*)pos->GetChild( "ranger:0" )),
00069                 fiducial( (ModelFiducial*)pos->GetUnusedModelOfType( "fiducial" )),     
00070                 //blobfinder( (ModelBlobfinder*)pos->GetUnusedModelOfType( "blobfinder" )),
00071                 //gripper( (ModelGripper*)pos->GetUnusedModelOfType( "gripper" )),
00072                 source(source), 
00073                 sink(sink), 
00074                 avoidcount(0), 
00075                 randcount(0), 
00076                 work_get(0), 
00077                 work_put(0),
00078                 charger_ahoy(false),
00079                 charger_bearing(0),
00080                 charger_range(0),
00081                 charger_heading(0),
00082                 mode(MODE_WORK),
00083                 at_dest( false )
00084   {
00085          // need at least these models to get any work done
00086          // (pos must be good, as we used it in the initialization list)
00087          assert( laser );
00088          assert( source );
00089          assert( sink );
00090 
00091          //      pos->GetUnusedModelOfType( "laser" );
00092          
00093          // PositionUpdate() checks to see if we reached source or sink
00094          pos->AddCallback( Model::CB_UPDATE, (model_callback_t)PositionUpdate, this );
00095          pos->Subscribe();
00096 
00097          // LaserUpdate() controls the robot, by reading from laser and
00098          // writing to position
00099          laser->AddCallback( Model::CB_UPDATE, (model_callback_t)LaserUpdate, this );
00100          laser->Subscribe();
00101 
00102          fiducial->AddCallback( Model::CB_UPDATE, (model_callback_t)FiducialUpdate, this );              
00103          fiducial->Subscribe();
00104          
00105          //gripper->AddUpdateCallback( (model_callback_t)GripperUpdate, this );          
00106          //gripper->Subscribe();
00107          
00108          //blobfinder->AddUpdateCallback( (model_callback_t)BlobFinderUpdate, this );
00109          //blobfinder->Subscribe();
00110 
00111          //pos->AddFlagIncrCallback( (model_callback_t)FlagIncr, NULL );
00112          //pos->AddFlagDecrCallback( (model_callback_t)FlagDecr, NULL );
00113 }
00114 
00115   void Dock()
00116   {
00117          // close the grippers so they can be pushed into the charger
00118          //ModelGripper::config_t gripper_data = gripper->GetConfig();
00119   
00120 //       if( gripper_data.paddles != ModelGripper::PADDLE_CLOSED )
00121 //              gripper->CommandClose();
00122 //       else  if( gripper_data.lift != ModelGripper::LIFT_UP )
00123 //              gripper->CommandUp();  
00124 
00125          if( charger_ahoy )
00126                 {
00127                   double a_goal = normalize( charger_bearing );                           
00128                 
00129                   //            if( pos->Stalled() )
00130                   //              {
00131                   //                     puts( "stalled. stopping" );
00132                   //                     pos->Stop();
00133                   //              }
00134                   //            else
00135 
00136                   if( charger_range > 0.5 )
00137                          {
00138                                 if( !ObstacleAvoid() )
00139                                   {
00140                                          pos->SetXSpeed( cruisespeed );                                          
00141                                          pos->SetTurnSpeed( a_goal );
00142                                   }
00143                          }
00144                   else  
00145                          {                      
00146                                 pos->SetTurnSpeed( a_goal );
00147                                 pos->SetXSpeed( 0.02 ); // creep towards it                              
00148 
00149                                 if( charger_range < 0.08 ) // close enough
00150                                   pos->Stop();
00151 
00152                                 if( pos->Stalled() ) // touching
00153                                   pos->SetXSpeed( -0.01 ); // back off a bit                     
00154 
00155                          }                       
00156                 }                         
00157          else
00158                 {
00159                   //printf( "docking but can't see a charger\n" );
00160                   pos->Stop();
00161                   mode = MODE_WORK; // should get us back on track eventually
00162                 }
00163 
00164          // if the battery is charged, go back to work
00165          if( Full() )
00166                 {
00167                   //printf( "fully charged, now back to work\n" );
00168                   mode = MODE_UNDOCK;
00169                 }
00170   }
00171 
00172 
00173   void UnDock()
00174   {
00175          //const meters_t gripper_distance = 0.2;
00176          const meters_t back_off_distance = 0.3;
00177          const meters_t back_off_speed = -0.05;
00178 
00179          // back up a bit
00180          if( charger_range < back_off_distance )
00181                 pos->SetXSpeed( back_off_speed );
00182          else
00183                 pos->SetXSpeed( 0.0 );
00184   
00185          // once we have backed off a bit, open and lower the gripper
00186 //       ModelGripper::config_t gripper_data = gripper->GetConfig();
00187 //       if( charger_range > gripper_distance )
00188 //              {
00189 //                if( gripper_data.paddles != ModelGripper::PADDLE_OPEN )
00190 //                       gripper->CommandOpen();
00191 //                else if( gripper_data.lift != ModelGripper::LIFT_DOWN )
00192 //                       gripper->CommandDown();  
00193 //              }
00194     
00195          // if the gripper is down and open and we're away from the charger, undock is finished
00196          if( //gripper_data.paddles == ModelGripper::PADDLE_OPEN &&
00197                    //gripper_data.lift == ModelGripper::LIFT_DOWN &&
00198                    charger_range > back_off_distance )   
00199                  mode = MODE_WORK;  
00200   }
00201 
00202   bool ObstacleAvoid()
00203   {
00204          bool obstruction = false;
00205          bool stop = false;
00206   
00207          // find the closest distance to the left and right and check if
00208          // there's anything in front
00209          double minleft = 1e6;
00210          double minright = 1e6;
00211          
00212          // Get the data from the first sensor of the laser 
00213          const std::vector<meters_t>& scan = laser->GetSensors()[0].ranges;
00214          
00215          uint32_t sample_count = scan.size();
00216   
00217          for (uint32_t i = 0; i < sample_count; i++)
00218                 {               
00219                   if( verbose ) printf( "%.3f ", scan[i] );
00220                 
00221                   if( (i > (sample_count/4)) 
00222                                 && (i < (sample_count - (sample_count/4))) 
00223                                 && scan[i] < minfrontdistance)
00224                          {
00225                                 if( verbose ) puts( "  obstruction!" );
00226                                 obstruction = true;
00227                          }
00228                 
00229                   if( scan[i] < stopdist )
00230                          {
00231                                 if( verbose ) puts( "  stopping!" );
00232                                 stop = true;
00233                          }
00234                 
00235                   if( i > sample_count/2 )
00236                                 minleft = std::min( minleft, scan[i] );
00237                   else      
00238                                 minright = std::min( minright, scan[i] );
00239                 }
00240   
00241          if( verbose ) 
00242                 {
00243                   puts( "" );
00244                   printf( "minleft %.3f \n", minleft );
00245                   printf( "minright %.3f\n ", minright );
00246                 }
00247   
00248          if( obstruction || stop || (avoidcount>0) )
00249                 {
00250                   if( verbose ) printf( "Avoid %d\n", avoidcount );
00251                 
00252                   pos->SetXSpeed( stop ? 0.0 : avoidspeed );      
00253                 
00254                   /* once we start avoiding, select a turn direction and stick
00255                           with it for a few iterations */
00256                   if( avoidcount < 1 )
00257                          {
00258                                 if( verbose ) puts( "Avoid START" );
00259                                 avoidcount = random() % avoidduration + avoidduration;
00260                          
00261                                 if( minleft < minright  )
00262                                   {
00263                                          pos->SetTurnSpeed( -avoidturn );
00264                                          if( verbose ) printf( "turning right %.2f\n", -avoidturn );
00265                                   }
00266                                 else
00267                                   {
00268                                          pos->SetTurnSpeed( +avoidturn );
00269                                          if( verbose ) printf( "turning left %2f\n", +avoidturn );
00270                                   }
00271                          }                        
00272                 
00273                   avoidcount--;
00274 
00275                   return true; // busy avoding obstacles
00276                 }
00277   
00278          return false; // didn't have to avoid anything
00279   }
00280 
00281 
00282   void Work()
00283   {
00284          if( ! ObstacleAvoid() )
00285                 {
00286                   if( verbose ) puts( "Cruise" );
00287                 
00288                   //ModelGripper::config_t gdata = gripper->GetConfig();
00289                                          
00290                   //avoidcount = 0;
00291                   pos->SetXSpeed( cruisespeed );          
00292                 
00293                   Pose pose = pos->GetPose();
00294                 
00295                   int x = (pose.x + 8) / 4;
00296                   int y = (pose.y + 8) / 4;
00297                 
00298                   // oh what an awful bug - 5 hours to track this down. When using
00299                   // this controller in a world larger than 8*8 meters, a_goal can
00300                   // sometimes be NAN. Causing trouble WAY upstream. 
00301                   if( x > 3 ) x = 3;
00302                   if( y > 3 ) y = 3;
00303                   if( x < 0 ) x = 0;
00304                   if( y < 0 ) y = 0;
00305                 
00306                   double a_goal = 
00307                          dtor( ( pos->GetFlagCount() ) ? have[y][x] : need[y][x] );
00308                 
00309                   // if we are low on juice - find the direction to the recharger instead
00310                   if( Hungry() )                 
00311                          { 
00312                                 //puts( "hungry - using refuel map" );
00313                          
00314                                 // use the refuel map
00315                                 a_goal = dtor( refuel[y][x] );
00316 
00317                                 if( charger_ahoy ) // I see a charger while hungry!
00318                                   mode = MODE_DOCK;
00319                          }
00320                   else
00321                          {
00322                                 if( ! at_dest )
00323                                   {
00324                                          //if( gdata.beam[0] ) // inner break beam broken
00325                                                 //gripper->CommandClose();
00326                                   }
00327                          }
00328                   
00329                   double a_error = normalize( a_goal - pose.a );
00330                   pos->SetTurnSpeed(  a_error );
00331                 }  
00332   }
00333 
00334 
00335   // inspect the laser data and decide what to do
00336   static int LaserUpdate( ModelRanger* laser, Robot* robot )
00337   {
00338          //   if( laser->power_pack && laser->power_pack->charging )
00339          //      printf( "model %s power pack @%p is charging\n",
00340          //                             laser->Token(), laser->power_pack );
00341                 
00342                 //assert( laser->GetSamples().size() > 0 );
00343                 
00344          switch( robot->mode )
00345                 {
00346                 case MODE_DOCK:
00347                   //puts( "DOCK" );
00348                   robot->Dock();
00349                   break;
00350                 
00351                 case MODE_WORK:
00352                   //puts( "WORK" );
00353                   robot->Work();
00354                   break;
00355 
00356                 case MODE_UNDOCK:
00357                   //puts( "UNDOCK" );
00358                   robot->UnDock();
00359                   break;
00360                 
00361                 default:
00362                   printf( "unrecognized mode %u\n", robot->mode );              
00363                 }
00364   
00365          return 0;
00366   }
00367 
00368   bool Hungry()
00369   {
00370          return( pos->FindPowerPack()->ProportionRemaining() < 0.25 );
00371   }      
00372 
00373   bool Full()
00374   {
00375          return( pos->FindPowerPack()->ProportionRemaining() > 0.95 );
00376   }      
00377 
00378   static int PositionUpdate( ModelPosition* pos, Robot* robot )
00379   {  
00380          Pose pose = pos->GetPose();
00381   
00382          //printf( "Pose: [%.2f %.2f %.2f %.2f]\n",
00383          //  pose.x, pose.y, pose.z, pose.a );
00384   
00385          //pose.z += 0.0001;
00386          //robot->pos->SetPose( pose );
00387          
00388          if( pos->GetFlagCount() < payload && 
00389                   hypot( -7-pose.x, -7-pose.y ) < 2.0 )
00390                 {
00391                   if( ++robot->work_get > workduration )
00392                          {
00393                                 // transfer a chunk from source to robot
00394                                 pos->PushFlag( robot->source->PopFlag() );
00395                                 robot->work_get = 0;    
00396                          }        
00397                 }
00398          
00399          robot->at_dest = false;
00400 
00401          if( hypot( 7-pose.x, 7-pose.y ) < 1.0 )
00402                 {
00403                   robot->at_dest = true;
00404 
00405                   //robot->gripper->CommandOpen();
00406 
00407                   if( ++robot->work_put > workduration )
00408                          {
00409                                 //puts( "dropping" );
00410                                 // transfer a chunk between robot and goal
00411                                 robot->sink->PushFlag( pos->PopFlag() );
00412                                 robot->work_put = 0;
00413                          }
00414                 }
00415   
00416 
00417          //printf( "diss: %.2f\n", pos->FindPowerPack()->GetDissipated() );
00418   
00419          return 0; // run again
00420   }
00421 
00422 
00423 
00424   static int FiducialUpdate( ModelFiducial* mod, Robot* robot )
00425   {    
00426                 robot->charger_ahoy = false;
00427                 
00428                 std::vector<ModelFiducial::Fiducial>& fids = mod->GetFiducials();
00429                 
00430                 for( unsigned int i = 0; i < fids.size(); i++ )
00431                         {                               
00432                   //printf( "fiducial %d is %d at %.2f m %.2f radians\n",
00433                   //      i, f->id, f->range, f->bearing );             
00434                 
00435                   if( fids[i].id == 2 ) // I see a charging station
00436                                 {
00437                                         // record that I've seen it and where it is
00438                                         robot->charger_ahoy = true;
00439                                         robot->charger_bearing = fids[i].bearing;
00440                                         robot->charger_range = fids[i].range;
00441                                         robot->charger_heading = fids[i].geom.a;
00442                                         
00443                                         //printf( "charger at %.2f radians\n", robot->charger_bearing );
00444                                         break;
00445                                 }
00446                 }                                                 
00447  
00448          return 0; // run again
00449   }
00450 
00451 //   static int BlobFinderUpdate( ModelBlobfinder* blobmod, Robot* robot )
00452 //   {  
00453 //       unsigned int blob_count = 0;
00454 //       const ModelBlobfinder::Blob* blobs = blobmod->GetBlobs( &blob_count );
00455 
00456 //       if( blobs && (blob_count>0) )
00457 //              {
00458 //                printf( "%s sees %u blobs\n", blobmod->Token(), blob_count );
00459 //              }
00460 
00461 //       return 0;
00462 //   }
00463 
00464 //   static int GripperUpdate( ModelGripper* grip, Robot* robot )
00465 //   {
00466 //       ModelGripper::config_t gdata = grip->GetConfig();
00467          
00468 //       printf( "BREAKBEAMS %s %s\n",
00469 //                              gdata.beam[0] ? gdata.beam[0]->Token() : "<null>", 
00470 //                              gdata.beam[1] ? gdata.beam[1]->Token() : "<null>" );
00471 
00472 //       printf( "CONTACTS %s %s\n",
00473 //                              gdata.contact[0] ? gdata.contact[0]->Token() : "<null>", 
00474 //                              gdata.contact[1] ? gdata.contact[1]->Token() : "<null>");
00475 
00476 
00477 //       return 0;
00478 //   }
00479   
00480 //   static int FlagIncr( Model* mod, Robot* robot )
00481 //   {
00482 //       printf( "model %s collected flag\n", mod->Token() );
00483 //       return 0;
00484 //   }
00485 
00486 //   static int FlagDecr( Model* mod, Robot* robot )
00487 //   {
00488 //       printf( "model %s dropped flag\n", mod->Token() );
00489 //       return 0;
00490 //   }
00491 
00492 };
00493 
00494 // Stage calls this when the model starts up
00495 extern "C" int Init( Model* mod, CtrlArgs* args )
00496 {  
00497   new Robot( (ModelPosition*)mod,
00498                                                  mod->GetWorld()->GetModel( "source" ),
00499                                                  mod->GetWorld()->GetModel( "sink" ) );
00500   
00501   return 0; //ok
00502 }
00503 
00504 
00505 


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 Thu Aug 27 2015 15:20:57