00001 #include "stage.hh"
00002 using namespace Stg;
00003
00004 const bool verbose = false;
00005
00006
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
00051
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
00071
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
00086
00087 assert( laser );
00088 assert( source );
00089 assert( sink );
00090
00091
00092
00093
00094 pos->AddCallback( Model::CB_UPDATE, (model_callback_t)PositionUpdate, this );
00095 pos->Subscribe();
00096
00097
00098
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
00106
00107
00108
00109
00110
00111
00112
00113 }
00114
00115 void Dock()
00116 {
00117
00118
00119
00120
00121
00122
00123
00124
00125 if( charger_ahoy )
00126 {
00127 double a_goal = normalize( charger_bearing );
00128
00129
00130
00131
00132
00133
00134
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 );
00148
00149 if( charger_range < 0.08 )
00150 pos->Stop();
00151
00152 if( pos->Stalled() )
00153 pos->SetXSpeed( -0.01 );
00154
00155 }
00156 }
00157 else
00158 {
00159
00160 pos->Stop();
00161 mode = MODE_WORK;
00162 }
00163
00164
00165 if( Full() )
00166 {
00167
00168 mode = MODE_UNDOCK;
00169 }
00170 }
00171
00172
00173 void UnDock()
00174 {
00175
00176 const meters_t back_off_distance = 0.3;
00177 const meters_t back_off_speed = -0.05;
00178
00179
00180 if( charger_range < back_off_distance )
00181 pos->SetXSpeed( back_off_speed );
00182 else
00183 pos->SetXSpeed( 0.0 );
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 if(
00197
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
00208
00209 double minleft = 1e6;
00210 double minright = 1e6;
00211
00212
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
00255
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;
00276 }
00277
00278 return false;
00279 }
00280
00281
00282 void Work()
00283 {
00284 if( ! ObstacleAvoid() )
00285 {
00286 if( verbose ) puts( "Cruise" );
00287
00288
00289
00290
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
00299
00300
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
00310 if( Hungry() )
00311 {
00312
00313
00314
00315 a_goal = dtor( refuel[y][x] );
00316
00317 if( charger_ahoy )
00318 mode = MODE_DOCK;
00319 }
00320 else
00321 {
00322 if( ! at_dest )
00323 {
00324
00325
00326 }
00327 }
00328
00329 double a_error = normalize( a_goal - pose.a );
00330 pos->SetTurnSpeed( a_error );
00331 }
00332 }
00333
00334
00335
00336 static int LaserUpdate( ModelRanger* laser, Robot* robot )
00337 {
00338
00339
00340
00341
00342
00343
00344 switch( robot->mode )
00345 {
00346 case MODE_DOCK:
00347
00348 robot->Dock();
00349 break;
00350
00351 case MODE_WORK:
00352
00353 robot->Work();
00354 break;
00355
00356 case MODE_UNDOCK:
00357
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
00383
00384
00385
00386
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
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
00406
00407 if( ++robot->work_put > workduration )
00408 {
00409
00410
00411 robot->sink->PushFlag( pos->PopFlag() );
00412 robot->work_put = 0;
00413 }
00414 }
00415
00416
00417
00418
00419 return 0;
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
00433
00434
00435 if( fids[i].id == 2 )
00436 {
00437
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
00444 break;
00445 }
00446 }
00447
00448 return 0;
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 };
00493
00494
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;
00502 }
00503
00504
00505