00001
00002
00003
00004
00005 #include "Robots/BeoHawk/computer/HawkSlammer.H"
00006
00007
00008 HawkSlammer::HawkSlammer(std::string myName, int argc, char* argv[])
00009 : HawkAgent(myName, argc, argv),
00010 window(Dims(320, 240)) {
00011
00012 helpTitle = "HawkSlammer";
00013 helpDescription = "Runs an implementation of DP-SLAM for the BeoHawk.";
00014 helpOptions.push_back("\t--pause\t\t(false) Wait for keyboard input after each iteration.");
00015 helpOptions.push_back("\t--mode\t\t(simulation) Try realTimeDrop, realTimeCombine, or simulation.");
00016 helpOptions.push_back("\t--particles\t(100) Number of particles in the simulation.");
00017 helpOptions.push_back("\t--resolution\t(30) Size of each grid cell in mm.");
00018 helpOptions.push_back("\t--maxLaserDistance\t(6000) Largest distance that the laser scanner can detect.");
00019
00020
00021 pauseEachStep = loadBoolParameter("pause", false);
00022 numberOfParticles = loadIntParameter("particles", 100);
00023 mapResolution = loadIntParameter("resolution", 30);
00024 maxLaserDistance = loadIntParameter("maxLaserDistance", 6000);
00025 robotXStdDev = loadDoubleParameter("robotXStdDev", 50);
00026 robotYStdDev = loadDoubleParameter("robotYStdDev", 50);
00027 robotThetaStdDev = loadDoubleParameter("robotThetaStdDev", 0.1);
00028 scannerVariance = loadDoubleParameter("scannerVariance", 20);
00029 std::string modeIn = loadStringParameter("mode", "simulation");
00030 if(modeIn == "realTimeDrop") mode = REALTIME_DROP;
00031 else if(modeIn == "realTimeCombine") mode = REALTIME_COMBINE;
00032 else mode = SIMULATION;
00033
00034
00035 initializeSlam();
00036 }
00037
00038
00039 void HawkSlammer::registerTopics() {
00040 registerPublisher("SlamDataMessage");
00041 registerSubscription("SensorDataMessage");
00042 }
00043
00044
00045 bool HawkSlammer::scheduler() {
00046 if(sensorDataMessages.size() > 0) {
00047 slam();
00048 return true;
00049 }
00050
00051 return false;
00052 }
00053
00054
00055 void HawkSlammer::catchMessage(const HawkMessages::MessagePtr& hawkMessage, const Ice::Current&) {
00056 if(hawkMessage->ice_isA("::HawkMessages::SensorDataMessage"))
00057 {
00058
00059 HawkMessages::SensorDataMessagePtr msg = HawkMessages::SensorDataMessagePtr::dynamicCast(hawkMessage);
00060 sensorDataMessages.push_back(msg);
00061 wakeUp();
00062 }
00063 }
00064
00065
00066 void HawkSlammer::initializeSlam() {
00067
00068 int initialPixels = (int)(2 * maxLaserDistance / mapResolution);
00069 occupancyGrid = occupancyMap_t(initialPixels, initialPixels, NO_INIT);
00070
00071
00072 boost::shared_ptr<Particle> head(new Particle());
00073 head->parent.reset();
00074 head->robotPose.x = initialPixels/2;
00075 head->robotPose.y = initialPixels/2;
00076 head->robotPose.z = 0;
00077 head->robotPose.theta = 0;
00078 head->probability = 1;
00079 ancestryTree.head = head;
00080
00081
00082 ancestryTree.leaves.push_back(head);
00083 }
00084
00085
00086 void HawkSlammer::slam() {
00087 std::cout << "slam(): " << sensorDataMessages.size() << " messages in queue" << std::endl;
00088
00089
00090 SensorDataMessagePtr msg;
00091 if(mode == REALTIME_COMBINE) {
00092
00093 msg = sensorDataMessages.back();
00094 for(size_t i = 0; i < (sensorDataMessages.size()-1); i++) {
00095
00096
00097 }
00098 sensorDataMessages.clear();
00099 }
00100 else if(mode == REALTIME_DROP) {
00101
00102 msg = sensorDataMessages.front();
00103 sensorDataMessages.clear();
00104 }
00105 else {
00106
00107 msg = sensorDataMessages.front();
00108 sensorDataMessages.erase(sensorDataMessages.begin());
00109 }
00110
00111
00112 updateParticles(msg);
00113 sendSlamDataMessage();
00114 resampleParticles();
00115 std::cout << "active particles: " << 1+countDescendants(ancestryTree.head) << std::endl;
00116 if(pauseEachStep) {
00117 std::cout << "Please press enter to continue...";
00118 std::cin.get();
00119 std::cout << std::endl;
00120 }
00121 pruneParticles();
00122
00123
00124 std::cout << "active particles: " << 1+countDescendants(ancestryTree.head) << std::endl;
00125 if(pauseEachStep) {
00126 std::cout << "Please press enter to continue...";
00127 std::cin.get();
00128 std::cout << std::endl;
00129 }
00130 }
00131
00132
00133 void HawkSlammer::updateParticles(SensorDataMessagePtr msg) {
00134 std::cout << "updateParticles()" << std::endl;
00135
00136
00137 ancestryTree.mostLikely.reset();
00138 double totalProbability = 0;
00139
00140
00141 for(size_t i = 0; i < ancestryTree.leaves.size(); i++) {
00142 std::cout << "Working with leaf #" << i << ". ";
00143
00144 Pose move = msg->attemptedMove;
00145 move.x = (move.x + gaussian(robotXStdDev)) / mapResolution;
00146 move.y = (move.y + gaussian(robotYStdDev)) / mapResolution;
00147 move.theta += gaussian(robotThetaStdDev);
00148
00149
00150 double worldTheta = cleanAngle(ancestryTree.leaves.at(i)->robotPose.theta + move.theta);
00151 ancestryTree.leaves.at(i)->robotPose.theta = worldTheta;
00152 ancestryTree.leaves.at(i)->robotPose.x += move.x*cos(worldTheta) + move.y*sin(worldTheta);
00153 ancestryTree.leaves.at(i)->robotPose.y += move.y*cos(worldTheta) - move.x*sin(worldTheta);
00154
00155
00156 int offset = msg->scannerData.size()/2;
00157 std::cout << "Applying laser scan... ";
00158 for(int j = 0; j < (int)msg->scannerData.size(); j++) {
00159 addLaserCast(ancestryTree.leaves.at(i), (j-offset)*msg->angularResolution, msg->scannerData.at(j) / mapResolution);
00160 }
00161
00162
00163
00164
00165 double probabilityOfLaserScan = 0;
00166 std::cout << "Scoring laser scan... ";
00167 for(int j = 0; j < (int)msg->scannerData.size(); j++) {
00168 probabilityOfLaserScan += scoreLaserCast(ancestryTree.leaves.at(i), (j-offset)*msg->angularResolution, msg->scannerData.at(j) / mapResolution);
00169 }
00170
00171
00172 std::cout << probabilityOfLaserScan << std::endl;
00173 ancestryTree.leaves.at(i)->probability *= probabilityOfLaserScan;
00174 totalProbability += ancestryTree.leaves.at(i)->probability;
00175
00176
00177 if(!ancestryTree.mostLikely || ancestryTree.leaves.at(i)->probability > ancestryTree.mostLikely->probability) {
00178 ancestryTree.mostLikely = ancestryTree.leaves.at(i);
00179 }
00180 }
00181
00182
00183 for(size_t i = 0; i < ancestryTree.leaves.size(); i++) {
00184 if(totalProbability == 0) ancestryTree.leaves.at(i)->probability = 1 / ancestryTree.leaves.size();
00185 else ancestryTree.leaves.at(i)->probability = ancestryTree.leaves.at(i)->probability / totalProbability;
00186 }
00187 }
00188
00189
00190 double HawkSlammer::randomDouble() {
00191 return double(rand()) / (double(RAND_MAX) + 1.0);
00192 }
00193
00194
00195 double HawkSlammer::gaussian(double stdDev) {
00196 double sum = 0;
00197 for(int i = 0; i < 12; i++) {
00198 sum += randomDouble() * 2 * stdDev - stdDev;
00199 }
00200 return sum / 2;
00201 }
00202
00203
00204 double HawkSlammer::cleanAngle(double angle) {
00205 while(angle > M_PI) angle -= 2*M_PI;
00206 while(angle < -M_PI) angle += 2*M_PI;
00207 return angle;
00208 }
00209
00210
00211 void HawkSlammer::addLaserCast(boost::shared_ptr<Particle> treeLeaf, double scanAngle, double scanDistance) {
00212 if(scanDistance == 0) return;
00213
00214 double startx = treeLeaf->robotPose.x;
00215 double starty = treeLeaf->robotPose.y;
00216 double theta = cleanAngle(treeLeaf->robotPose.theta + scanAngle);
00217
00218 double overflow, slope;
00219 int x, y, incX, incY, endx, endy;
00220 int xedge, yedge;
00221 double dx, dy;
00222 double distance = scanDistance, error;
00223
00224
00225 double secant = 1.0/fabs(cos(theta));
00226 double cosecant = 1.0/fabs(sin(theta));
00227
00228
00229
00230 dx = (startx + (cos(theta) * distance));
00231 dy = (starty + (sin(theta) * distance));
00232 endx = (int) (dx);
00233 endy = (int) (dy);
00234
00235
00236
00237
00238 if (startx > dx) {
00239 incX = -1;
00240 xedge = 1;
00241 }
00242 else {
00243 incX = 1;
00244 xedge = 0;
00245 }
00246
00247 if (starty > dy) {
00248 incY = -1;
00249 yedge = 1;
00250 }
00251 else {
00252 incY = 1;
00253 yedge = 0;
00254 }
00255
00256
00257
00258 if (fabs(startx - dx) > fabs(starty - dy)) {
00259
00260
00261 y = (int)(starty);
00262 overflow = starty - y;
00263
00264
00265
00266 if(incY == 1) overflow = 1.0 - overflow;
00267
00268
00269 slope = fabs(tan(theta));
00270
00271
00272
00273
00274
00275
00276
00277 error = fabs(((int)(startx)+incX+xedge)-startx);
00278 overflow = overflow - (slope*error);
00279
00280 if (overflow < 0.0) {
00281 y = y + incY;
00282 overflow = overflow + 1.0;
00283 }
00284
00285
00286 for(x = (int)(startx) + incX; x != endx; x = x + incX) {
00287 overflow = overflow - slope;
00288
00289
00290 if(overflow < 0.0) distance = (overflow+slope)*cosecant;
00291 else distance = fabs(slope)*cosecant;
00292
00293
00294 addObservation(treeLeaf, x, y, distance, 0);
00295
00296
00297 if(overflow < 0) {
00298 y = y + incY;
00299 distance = -overflow*cosecant;
00300 overflow = overflow + 1.0;
00301 addObservation(treeLeaf, x, y, distance, 0);
00302 }
00303 }
00304
00305
00306
00307
00308 if(incX < 0) distance = fabs((x+1) - dx)*secant;
00309 else distance = fabs(dx - x)*secant;
00310 addObservation(treeLeaf, endx, endy, distance, 1);
00311
00312 }
00313
00314 else {
00315 x = (int)(startx);
00316 overflow = startx - x;
00317 if(incX == 1) overflow = 1.0 - overflow;
00318 slope = 1.0/fabs(tan(theta));
00319
00320 error = fabs(((int)(starty)+incY+yedge)-starty);
00321 overflow = overflow - (error*slope);
00322 if(overflow < 0.0) {
00323 x = x + incX;
00324 overflow = overflow + 1.0;
00325 }
00326
00327 for(y = (int)(starty) + incY; y != endy; y = y + incY) {
00328 overflow = overflow - slope;
00329 if (overflow < 0) distance = (overflow+slope)*secant;
00330 else distance = fabs(slope)*secant;
00331
00332 addObservation(treeLeaf, x, y, distance, 0);
00333
00334 if(overflow < 0.0) {
00335 x = x + incX;
00336 distance = -overflow*secant;
00337 overflow = overflow + 1.0;
00338 addObservation(treeLeaf, x, y, distance, 0);
00339 }
00340 }
00341
00342
00343 if(incY < 0) distance = fabs(((y+1) - dy)/sin(theta));
00344 else distance = fabs((dy - y)/sin(theta));
00345
00346 addObservation(treeLeaf, endx, endy, distance, 1);
00347
00348 }
00349 }
00350
00351
00352 void HawkSlammer::addObservation(boost::shared_ptr<Particle> treeLeaf, int x, int y, double distanceTraveled, int hit) {
00353
00354 boost::shared_ptr<Observation> o(new Observation());
00355 o->source = treeLeaf;
00356 o->x = x;
00357 o->y = y;
00358
00359
00360 occupancyMapPix_t treeMap;
00361 if(!occupancyGrid.getVal(x, y)) {
00362 treeMap = occupancyMapPix_t(
00363 new std::map<boost::shared_ptr<Particle>, boost::shared_ptr<Observation> >);
00364 occupancyGrid.setVal(x, y, treeMap);
00365 }
00366 else treeMap = occupancyGrid.getVal(x, y);
00367
00368
00369 boost::shared_ptr<Particle> ancestor = treeLeaf->parent;
00370 bool ancestorObservation = false;
00371 std::map< boost::shared_ptr<Particle>, boost::shared_ptr<Observation> >::const_iterator it;
00372 while(!ancestorObservation && ancestor) {
00373 it = treeMap->find(ancestor);
00374 if(it != treeMap->end()) ancestorObservation = true;
00375 else ancestor = ancestor->parent;
00376 }
00377
00378
00379 if(ancestorObservation) {
00380 o->laserTravel = it->second->laserTravel + distanceTraveled;
00381 o->laserTerminations = it->second->laserTerminations + hit;
00382 o->ancestor = it->second;
00383 }
00384 else {
00385 o->laserTravel = distanceTraveled;
00386 o->laserTerminations = hit;
00387 o->ancestor.reset();
00388 }
00389
00390
00391 treeLeaf->observations.push_back(o);
00392 treeMap->insert( std::pair<boost::shared_ptr<Particle>, boost::shared_ptr<Observation> >(treeLeaf, o) );
00393 }
00394
00395
00396 double HawkSlammer::scoreLaserCast(boost::shared_ptr<Particle> treeLeaf, double scanAngle, double scanDistance) {
00397 if(scanDistance == 0) return scoreObservation(treeLeaf, treeLeaf->robotPose.x, treeLeaf->robotPose.y, scanDistance);
00398
00399 double startx = treeLeaf->robotPose.x;
00400 double starty = treeLeaf->robotPose.y;
00401 double theta = cleanAngle(treeLeaf->robotPose.theta + scanAngle);
00402 double MeasuredDist = scanDistance;
00403
00404 double overflow, slope;
00405 int x, y, incX, incY, endx, endy;
00406 double dx, dy;
00407 double totalProb;
00408 double eval;
00409 double prob, distance, error;
00410 double secant, cosecant;
00411 double xblock, yblock;
00412 double xMotion, yMotion;
00413 double standardDist;
00414
00415
00416 eval = 0.0;
00417
00418
00419 totalProb = 1.0;
00420
00421 secant = 1.0/fabs(cos(theta));
00422 cosecant = 1.0/fabs(sin(theta));
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 distance = MeasuredDist;
00437
00438
00439 dx = (startx + (cos(theta) * distance));
00440 dy = (starty + (sin(theta) * distance));
00441 endx = (int) (dx);
00442 endy = (int) (dy);
00443
00444
00445 if(startx > dx) {
00446 incX = -1;
00447 xblock = -startx;
00448 }
00449 else {
00450 incX = 1;
00451 xblock = 1.0-startx;
00452 }
00453
00454 if(starty > dy) {
00455 incY = -1;
00456 yblock = -starty;
00457 }
00458 else {
00459 incY = 1;
00460 yblock = 1.0-starty;
00461 }
00462
00463
00464
00465 if(fabs(startx - dx) > fabs(starty - dy)) {
00466 y = (int) (starty);
00467
00468
00469
00470 overflow = starty - y;
00471
00472 if(incY == 1) overflow = 1.0 - overflow;
00473
00474 slope = fabs(tan(theta));
00475 if(slope > 1.0) slope = fabs((starty - dy) / (startx - dx));
00476
00477
00478
00479
00480
00481
00482
00483 dx = fabs((int)(startx)+xblock);
00484 dy = fabs(tan(theta)*dx);
00485
00486
00487 if (overflow - dy < 0.0) {
00488 y = y + incY;
00489 overflow = overflow - dy + 1.0;
00490 }
00491
00492
00493 else overflow = overflow - dy;
00494
00495
00496
00497 standardDist = slope*cosecant;
00498
00499
00500
00501
00502
00503
00504 xMotion = -fabs(fabs(( ((int) (startx)) +xblock) * secant) - MeasuredDist);
00505 yMotion = -fabs(fabs((y+yblock) * cosecant) - MeasuredDist);
00506
00507 for(x = (int) (startx) + incX; x != endx; x = x + incX) {
00508
00509 xMotion = xMotion + secant;
00510 overflow = overflow - slope;
00511
00512
00513
00514 if (overflow < 0.0) distance = (overflow+slope)*cosecant;
00515 else distance = standardDist;
00516
00517
00518
00519 prob = totalProb * scoreObservation(treeLeaf, x, y, distance);
00520 if(prob > 0) {
00521
00522
00523
00524 if(overflow < 0.0) error = fabs(yMotion);
00525 else error = fabs(xMotion);
00526
00527
00528
00529
00530
00531 if(error < 20.0) eval = eval + (prob * exp(-(error*error)/(2*scannerVariance)));
00532
00533
00534 totalProb = totalProb - prob;
00535 }
00536
00537
00538
00539 if(overflow < 0.0) {
00540 y += incY;
00541 yMotion = yMotion + cosecant;
00542
00543 distance = -overflow*cosecant;
00544 overflow = overflow + 1.0;
00545
00546 prob = totalProb * scoreObservation(treeLeaf, x, y, distance);
00547 if(prob > 0) {
00548
00549
00550 error = fabs(xMotion);
00551 if(error < 20.0) eval = eval + (prob * exp(-(error*error)/(2*scannerVariance)));
00552 }
00553 totalProb = totalProb - prob;
00554 }
00555
00556 }
00557 }
00558
00559
00560
00561 else {
00562 x = (int) (startx);
00563 overflow = startx - x;
00564 if(incX == 1) overflow = 1.0 - overflow;
00565 slope = 1.0/fabs(tan(theta));
00566
00567
00568 dy = fabs((int)(starty)+yblock);
00569 dx = fabs(dy/tan(theta));
00570 if(overflow - dx < 0) {
00571 x = x + incX;
00572 overflow = overflow - dx + 1.0;
00573 }
00574 else overflow = overflow - dx;
00575
00576 standardDist = slope*secant;
00577 xMotion = -fabs(fabs((x+xblock) * secant) - MeasuredDist);
00578 yMotion = -fabs(fabs(( ((int) (starty)) +yblock) * cosecant) - MeasuredDist);
00579
00580 for(y = (int) (starty) + incY; y != endy; y = y + incY) {
00581 yMotion = yMotion + cosecant;
00582 overflow = overflow - slope;
00583
00584 if(overflow < 0.0) distance = (overflow+slope)*secant;
00585 else distance = standardDist;
00586
00587 prob = totalProb * scoreObservation(treeLeaf, x, y, distance);
00588 if (prob > 0) {
00589 if(overflow < 0.0) error = fabs(xMotion);
00590 else error = fabs(yMotion);
00591 if(error < 20.0) eval = eval + (prob * exp(-(error*error)/(2*scannerVariance)));
00592 }
00593 totalProb = totalProb - prob;
00594
00595 if(overflow < 0.0) {
00596 x += incX;
00597 xMotion = xMotion + secant;
00598
00599 distance = -overflow*secant;
00600 overflow = overflow + 1.0;
00601
00602 prob = totalProb * scoreObservation(treeLeaf, x, y, distance);
00603 if(prob > 0) {
00604 error = fabs(yMotion);
00605 if(error < 20.0) eval = eval + (prob * exp(-(error*error)/(2*scannerVariance)));
00606 }
00607 totalProb = totalProb - prob;
00608 }
00609
00610 }
00611 }
00612
00613
00614
00615
00616 if(MeasuredDist >= maxLaserDistance) return (eval + totalProb);
00617
00618
00619
00620 if(totalProb == 1) return 0;
00621 return (eval / (1.0 - totalProb));
00622 }
00623
00624
00625 double HawkSlammer::scoreObservation(boost::shared_ptr<Particle> treeLeaf, int x, int y, double distanceTraveled) {
00626
00627 if(occupancyGrid.getVal(x, y)) {
00628 std::map< boost::shared_ptr<Particle>, boost::shared_ptr<Observation> >::const_iterator it = occupancyGrid.getVal(x, y)->find(treeLeaf);
00629 if(it == occupancyGrid.getVal(x, y)->end())
00630 return (1.0 - exp(-1.0/(8000 * mapResolution) * distanceTraveled));
00631 else return (1.0 - exp(-(it->second->laserTerminations / it->second->laserTravel) * distanceTraveled));
00632 }
00633 else return (1.0 - exp(-1.0/(8000 * mapResolution) * distanceTraveled));
00634 }
00635
00636
00637 void HawkSlammer::sendSlamDataMessage() {
00638 std::cout << "sendSlamDataMessage()" << std::endl;
00639
00640
00641 HawkMessages::SlamDataMessagePtr msg = new HawkMessages::SlamDataMessage;
00642 msg->hawkPose = ancestryTree.mostLikely->robotPose;
00643 Image< PixRGB<byte> > mapImage = makeMapImage(ancestryTree.mostLikely);
00644 if(ancestryTree.leaves.size() >= 3) {
00645 Image< PixRGB<byte> > topImage = concatX(mapImage, makeMapImage(ancestryTree.leaves.at(0)));
00646 Image< PixRGB<byte> > bottomImage = concatX(makeMapImage(ancestryTree.leaves.at(1)), makeMapImage(ancestryTree.leaves.at(2)));
00647 mapImage = concatY(topImage, bottomImage);
00648 }
00649
00650
00651 std::cout << "\trobotPose: (" << msg->hawkPose.x << ", " << msg->hawkPose.y << ", " << msg->hawkPose.z << ", " << msg->hawkPose.theta << ")" << std::endl;
00652 window.drawImage(mapImage, 0, 0, true);
00653
00654
00655 publish("SlamDataMessage", msg);
00656 }
00657
00658
00659 void HawkSlammer::resampleParticles() {
00660 std::cout << "resampleParticles()" << std::endl;
00661
00662
00663 std::vector<float> CDF;
00664 CDF.resize(ancestryTree.leaves.size());
00665 CDF.at(0) = ancestryTree.leaves.at(0)->probability;
00666 for(int i = 1; i < (int)CDF.size(); i++) {
00667 CDF.at(i) = CDF.at(i-1) + ancestryTree.leaves.at(i)->probability;
00668 }
00669
00670
00671 std::vector<boost::shared_ptr<Particle> > lonelyLeaves = ancestryTree.leaves;
00672 std::vector<boost::shared_ptr<Particle> > newLeaves;
00673 int i = 0;
00674 float newProb = 1.0/float(numberOfParticles);
00675 float u = randomDouble()* newProb;
00676 for(int j = 0; j < numberOfParticles; j++) {
00677
00678 while(i < (int)CDF.size() && u > CDF.at(i)) i++;
00679 u += newProb;
00680
00681
00682 boost::shared_ptr<Particle> p(new Particle());
00683 p->parent = ancestryTree.leaves.at(i);
00684 p->robotPose = ancestryTree.leaves.at(i)->robotPose;
00685 p->probability = newProb;
00686
00687
00688 ancestryTree.leaves.at(i)->children.push_back(p);
00689 newLeaves.push_back(p);
00690
00691
00692 std::vector<boost::shared_ptr<Particle> >::iterator it;
00693 it = std::find(lonelyLeaves.begin(), lonelyLeaves.end(), ancestryTree.leaves.at(i));
00694 if(it != lonelyLeaves.end()) lonelyLeaves.erase(it);
00695 }
00696
00697
00698 ancestryTree.leaves = newLeaves;
00699
00700
00701 std::cout << "before resampling, active particles: " << 1+countDescendants(ancestryTree.head) << std::endl;
00702 std::cout << "we have " << lonelyLeaves.size() << " lonely leaves to be deleted" << std::endl;
00703 for(size_t i = 0; i < lonelyLeaves.size(); i++) {
00704 std::vector<boost::shared_ptr<Particle> >::iterator it;
00705 it = find(lonelyLeaves.at(i)->parent->children.begin(), lonelyLeaves.at(i)->parent->children.end(), lonelyLeaves.at(i));
00706 lonelyLeaves.at(i)->parent->children.erase(it);
00707
00708 }
00709 std::cout << "after resampling, active particles: " << 1+countDescendants(ancestryTree.head) << std::endl;
00710 }
00711
00712
00713 void HawkSlammer::pruneParticles() {
00714 std::cout << "pruneParticles()" << std::endl;
00715
00716
00717 collapseParticle(ancestryTree.head);
00718 }
00719
00720
00721 void HawkSlammer::collapseParticle(boost::shared_ptr<Particle> particle) {
00722
00723 if(particle->children.size() == 1) {
00724 std::cout << "fouund a particle to squash!" << std::endl;
00725
00726 boost::shared_ptr<Particle> child = particle->children.at(0);
00727
00728 std::cout << "Child has " << child->observations.size() << " observations" << std::endl;
00729
00730 for(size_t j = 0; j < child->observations.size(); j++) {
00731
00732 if(child->observations.at(j)->ancestor && child->observations.at(j)->ancestor->source == particle) {
00733
00734 child->observations.at(j)->ancestor = child->observations.at(j)->ancestor->ancestor;
00735
00736
00737 std::cout << "Erasing observation with " << (*occupancyGrid.getVal(child->observations.at(j)->x, child->observations.at(j)->y))[particle].use_count() << " references" << std::endl;
00738 occupancyGrid.getVal(child->observations.at(j)->x, child->observations.at(j)->y)->erase(particle);
00739 }
00740 }
00741 std::cout << "Child now has " << child->observations.size() << " observations" << std::endl;
00742 std::cin.get();
00743
00744
00745 for(int j = 0; j < (int)particle->observations.size(); j++) {
00746 particle->observations.at(j)->source = child;
00747 child->observations.push_back(particle->observations.at(j));
00748 }
00749
00750
00751 child->parent = particle->parent;
00752
00753
00754 if(!particle->parent) {
00755
00756 ancestryTree.head = child;
00757 }
00758 else {
00759
00760 std::vector<boost::shared_ptr<Particle> >::iterator it;
00761 it = find(particle->parent->children.begin(), particle->parent->children.end(), particle);
00762 *it = child;
00763 }
00764
00765
00766 particle->parent.reset();
00767 particle->children.clear();
00768 particle->observations.clear();
00769
00770
00771 collapseParticle(child);
00772 }
00773 else {
00774
00775 for(size_t i = 0; i < particle->children.size(); i++) {
00776 collapseParticle(particle->children.at(i));
00777 }
00778 }
00779 }
00780
00781
00782 int HawkSlammer::countDescendants(boost::shared_ptr<Particle> particle) {
00783 int particles = particle->children.size();
00784
00785 for(size_t i = 0; i < particle->children.size(); i++) {
00786 particles += countDescendants(particle->children.at(i));
00787 }
00788
00789 return particles;
00790 }
00791
00792
00793 Image< PixRGB<byte> > HawkSlammer::makeMapImage(boost::shared_ptr<Particle> primaryParticle) {
00794 Image< PixRGB<byte> > mapImage(occupancyGrid.getWidth(), occupancyGrid.getHeight(), NO_INIT);
00795 PixRGB<byte> hitDot, nohitDot, notscannedDot;
00796 hitDot.set(0, 0, 0);
00797 nohitDot.set(195, 195, 195);
00798 notscannedDot.set(255, 255, 255);
00799
00800
00801 for(int i = 0; i < mapImage.getWidth(); i++) {
00802 for(int j = 0; j < mapImage.getHeight(); j++) {
00803
00804 boost::shared_ptr<Particle> particle = primaryParticle;
00805 boost::shared_ptr<Observation> observation;
00806 std::map<boost::shared_ptr<Particle>, boost::shared_ptr<Observation> >::iterator it;
00807 while(!observation && particle) {
00808 if(occupancyGrid.getVal(i, j)) {
00809 it = occupancyGrid.getVal(i, j)->find(particle);
00810 if(it != occupancyGrid.getVal(i, j)->end()) observation = it->second;
00811 else particle = particle->parent;
00812 }
00813 else particle = particle->parent;
00814 }
00815
00816
00817 if(observation) {
00818 if(observation->laserTerminations / observation->laserTravel > 0.5)
00819 mapImage.setVal(i, j, hitDot);
00820 else mapImage.setVal(i, j, nohitDot);
00821 }
00822 else mapImage.setVal(i, j, notscannedDot);
00823 }
00824 }
00825
00826 return mapImage;
00827 }
00828
00829
00830 Image< PixRGB<byte> > HawkSlammer::makeScannerImage(SensorDataMessagePtr msg) {
00831 double angularResolution = msg->angularResolution;
00832 LongSeq scannerData = msg->scannerData;
00833 Image< PixRGB<byte> > scannerImage(2*HALF_WINDOW_SIZE,2*HALF_WINDOW_SIZE,ZEROS);
00834
00835
00836 long min = maxLaserDistance, max = 0;
00837 int offset = scannerData.size()/2;
00838 for(size_t i = 0; i < scannerData.size(); i++) {
00839 if(scannerData.at(i) > max) max = scannerData.at(i);
00840 if(scannerData.at(i) < min) min = scannerData.at(i);
00841
00842 float distance = scannerData.at(i);
00843 float angle = (i-offset)*angularResolution;
00844 distance = distance/maxLaserDistance*HALF_WINDOW_SIZE;
00845 if (distance < 0) distance = 1.0;
00846
00847
00848 Point2D<int> pt;
00849 pt.i = HALF_WINDOW_SIZE - int(distance*sin(angle));
00850 pt.j = HALF_WINDOW_SIZE - int(distance*cos(angle));
00851 drawCircle(scannerImage, pt, 1, PixRGB<byte>(255,0,0));
00852
00853
00854 if(i == 0 || i == (scannerData.size() - 1)) {
00855 pt.i = HALF_WINDOW_SIZE - int(HALF_WINDOW_SIZE*sin(angle));
00856 pt.j = HALF_WINDOW_SIZE - int(HALF_WINDOW_SIZE*cos(angle));
00857 drawLine(scannerImage, Point2D<int>(HALF_WINDOW_SIZE,HALF_WINDOW_SIZE),pt,PixRGB<byte>(0,0,255));
00858 }
00859
00860
00861
00862
00863
00864 }
00865 std::cout << "min, max: " << min << ", " << max << std::endl;
00866
00867 return scannerImage;
00868 }
00869
00870
00871 int main (int argc, char* argv[]) {
00872 std::cout << "HawkSlammer: starting..." << std::endl;
00873
00874 HawkSlammer agent("HawkSlammer", argc, argv);
00875 agent.start();
00876
00877 std::cout << "HawkSlammer: all done!" << std::endl;
00878 }