00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Robots/Beobot2/Navigation/ND_Navigation/ND_Navigation.H"
00039 #include "Ice/BeobotEvents.ice.H"
00040
00041 #include "Raster/Raster.H"
00042 #include "Util/sformat.H"
00043 #include "Image/Image.H"
00044 #include "Image/DrawOps.H"
00045 #include "Transport/FrameInfo.H"
00046
00047 #include "Ice/IceImageUtils.H"
00048
00049 #define SecurityNearnessRad 1000.0
00050
00051
00052 ND_Navigation::ND_Navigation(OptionManager& mgr,
00053 const std::string& descrName, const std::string& tagName) :
00054 RobotBrainComponent(mgr, descrName, tagName),
00055 itsOfs(new OutputFrameSeries(mgr)),
00056 itsDispImg(512, 512, ZEROS),
00057 itsTimer(1000000)
00058 {
00059 addSubComponent(itsOfs);
00060
00061
00062
00063 itsGoalSector = 141;
00064
00065 itsPrevDirection = 141;
00066 itsBigJumpCount = 0;
00067 }
00068
00069
00070 ND_Navigation::~ND_Navigation()
00071 { }
00072
00073
00074 void ND_Navigation::start1()
00075 {
00076 }
00077
00078
00079 void ND_Navigation::registerTopics()
00080 {
00081
00082 this->registerSubscription("LRFMessageTopic");
00083 this->registerPublisher("MotorRequestTopic");
00084 }
00085
00086
00087 void ND_Navigation::evolve()
00088 { }
00089
00090
00091 Beobot2::MotorCommand ND_Navigation::computeND_Navigation()
00092 {
00093
00094 findGapsAndRegions();
00095
00096
00097 findGoalRegion();
00098
00099 biasForSafety();
00100
00101
00102 LINFO("Jump detected: %d %d", itsPrevDirection, itsNextDirection);
00103
00104 if((abs(int(itsPrevDirection) - int(itsNextDirection)) > 90)
00105 && itsBigJumpCount < 3)
00106 {
00107 LINFO("BIG JUMP\n\n\n");
00108 itsNextDirection = itsPrevDirection;
00109 itsBigJumpCount++;
00110 }
00111 else itsBigJumpCount = 0;
00112
00113 if(abs(int(itsPrevDirection) - int(itsNextDirection)) > 15)
00114 {
00115 LINFO("JUMP\n\n\n");
00116 if(itsPrevDirection > itsNextDirection)
00117 itsNextDirection = itsPrevDirection - 15;
00118 else itsNextDirection = itsPrevDirection + 15;
00119 }
00120 LINFO("Jump detected: %d %d", itsPrevDirection, itsNextDirection);
00121
00122
00123 float frontIndex = 141.0; float maxAngle = 141.0;
00124 float rot = (itsNextDirection - frontIndex)/maxAngle * 2.0;
00125 if(rot > 1.0) rot = 1.0;
00126 if(rot < -1.0) rot = -1.0;
00127 if(itsNextDirection < frontIndex)
00128 {
00129 LINFO("Go RIGHT: %f", rot);
00130 }
00131 else
00132 {
00133 LINFO("Go LEFT : %f", rot);
00134 }
00135
00136
00137 drawSituation();
00138
00139
00140
00141
00142 Beobot2::MotorCommand cmd;
00143
00144 cmd.rotation = rot;
00145
00146 float dist = itsDistances[120];
00147 for(uint i = 121; i < 160; i++)
00148 {
00149 if(dist < itsDistances[i]) dist = itsDistances[i];
00150 }
00151
00152 if(dist < 600.0)
00153 cmd.translation = 0.0;
00154 else
00155 {
00156 float trans = 1.0 - 1.5 * abs(rot);
00157 if(trans < 0) trans = 0.0;
00158 trans += 0.1;
00159
00160 if(trans > 1.0) trans = 1.0;
00161
00162
00163 cmd.translation = trans;
00164 }
00165
00166 std::string ntext(sformat("T: %10.6f R: %10.6f",
00167 cmd.translation, cmd.rotation));
00168 writeText(itsDispImg, Point2D<int>(0,400), ntext.c_str());
00169
00170 itsOfs->writeRGB(itsDispImg, "ND_nav", FrameInfo("ND_nav",SRC_POS));
00171
00172 itsPrevDirection = itsNextDirection;
00173 return cmd;
00174 }
00175
00176
00177 void ND_Navigation::findGapsAndRegions()
00178 {
00179 itsGaps.clear();
00180 itsRegions.clear();
00181
00182 uint nSectors = itsDistances.size();
00183 uint prevEnd = 0;
00184
00185
00186 double discThres = 1000.0;
00187
00188
00189 for(uint i = 1; i < nSectors; i++)
00190 {
00191
00192 if(itsDistances[i-1] == -1.0 || itsDistances[i] == -1.0)
00193 continue;
00194
00195
00196 if(i >= 25 && i <= 36) continue;
00197 if(i >= 243 && i <= 253) continue;
00198
00199 if(abs(itsDistances[i-1] - itsDistances[i]) > discThres)
00200 {
00201 itsGaps.push_back(i);
00202 RegionInformation r;
00203 r.start = prevEnd;
00204 r.end = i-1;
00205 itsRegions.push_back(r);
00206 prevEnd = i;
00207 }
00208 }
00209 RegionInformation r;
00210 r.start = prevEnd;
00211 r.end = nSectors-1;
00212 itsRegions.push_back(r);
00213
00214
00215 setMinimumDistances();
00216 }
00217
00218
00219 void ND_Navigation::drawSituation()
00220 {
00221
00222 float max = itsDistances[0]; float min = itsDistances[0];
00223 for(uint i = 1; i < itsDistances.size(); i++)
00224 {
00225 if(min > itsDistances[i]) min = itsDistances[i];
00226 if(max < itsDistances[i]) max = itsDistances[i];
00227 }
00228 if (min == max) max += 1.0;
00229 itsMinDistance = min;
00230 itsMaxDistance = max;
00231
00232 itsDispImg.clear(PixRGB<byte>(0, 0, 0));
00233 for(uint i = 0; i < itsRegions.size(); i++)
00234 {
00235 PixRGB<byte> c((byte)rand()/2, (byte)rand()/2, (byte)rand()/2);
00236
00237 for(uint j = itsRegions[i].start; j <= itsRegions[i].end; j++)
00238 {
00239 float dist = itsDistances[j];
00240 int angle = itsAngles[j];
00241
00242
00243 float rad = dist; rad = ((rad - min)/(max-min))*256;
00244 if (rad < 0) rad = 1.0;
00245
00246 Point2D<int> pt;
00247 pt.i = 256 - int(rad*sin((double)angle*M_PI/180.0));
00248 pt.j = 256 - int(rad*cos((double)angle*M_PI/180.0));
00249
00250 drawCircle(itsDispImg, pt, 2, PixRGB<byte>(255,0,0));
00251 drawLine(itsDispImg, Point2D<int>(256,256), pt, c);
00252
00253 LDEBUG("[%4d][%4d] <%4d>: %10.1f mm", i, j, angle, dist);
00254 }
00255 }
00256
00257 for(uint i = 0; i < itsRegions.size(); i++)
00258 {
00259 float dist = itsDistances[itsRegions[i].minIndex];
00260 int angle = itsAngles[itsRegions[i].minIndex];
00261
00262
00263 PixRGB<byte> c((byte)rand()/2, (byte)rand()/2, (byte)rand()/2);
00264 dist = itsDistances[itsRegions[i].start];
00265 angle = itsAngles[itsRegions[i].start];
00266
00267
00268 dist = itsDistances[itsRegions[i].end];
00269 angle = itsAngles[itsRegions[i].end];
00270
00271
00272 uint midInd = (itsRegions[i].start+ itsRegions[i].end) /2;
00273 dist = itsDistances[midInd] + 1000.0;
00274 angle = itsAngles[midInd];
00275
00276
00277 float rad = dist; rad = ((rad - min)/(max-min))*256;
00278 if (rad < 0) rad = 1.0;
00279 Point2D<int> pt;
00280 pt.i = 256 - int(rad*sin((double)angle*M_PI/180.0));
00281 pt.j = 256 - int(rad*cos((double)angle*M_PI/180.0));
00282
00283 std::string ntext(sformat("%d", i));
00284 writeText(itsDispImg, pt, ntext.c_str());
00285 }
00286
00287
00288 int angle = itsAngles[itsNextDirection];
00289 drawRangeLine(itsMaxDistance, angle, PixRGB<byte>(0,0,255));
00290 angle = itsAngles[itsRegions[itsGoalRegion].start];
00291 drawRangeLine(itsMaxDistance, angle, PixRGB<byte>(255, 255, 0));
00292 angle = itsAngles[itsRegions[itsGoalRegion].end];
00293 drawRangeLine(itsMaxDistance, angle, PixRGB<byte>(255, 255, 0));
00294
00295
00296 float rad = ((SecurityNearnessRad - itsMinDistance)/
00297 (itsMaxDistance - itsMinDistance))*256;
00298 drawCircle(itsDispImg, Point2D<int>(256, 256) , rad,
00299 PixRGB<byte>(255,255,0));
00300
00301
00302
00303 drawLine(itsDispImg, Point2D<int>(256,0), Point2D<int>(256,512),
00304 PixRGB<byte>(255,255,255));
00305 drawLine(itsDispImg, Point2D<int>(0,256), Point2D<int>(512,256),
00306 PixRGB<byte>(255,255,255));
00307
00308 drawRangeLine(itsMaxDistance, itsAngles[itsLeftEnd], PixRGB<byte>(255,0,0));
00309 drawRangeLine(itsMaxDistance, itsAngles[itsRightEnd], PixRGB<byte>(255,0,0));
00310 }
00311
00312
00313 void ND_Navigation::drawRangeLine(float dist, int angle, PixRGB<byte> c)
00314 {
00315 float min = itsMinDistance;
00316 float max = itsMaxDistance;
00317
00318 float rad = ((dist - min)/(max-min))*256;
00319 if (rad < 0) rad = 1.0;
00320
00321 Point2D<int> pt;
00322 pt.i = 256 - int(rad*sin((double)angle*M_PI/180.0));
00323 pt.j = 256 - int(rad*cos((double)angle*M_PI/180.0));
00324
00325 drawLine(itsDispImg, Point2D<int>(256,256), pt, c);
00326 }
00327
00328
00329
00330 void ND_Navigation::setMinimumDistances()
00331 {
00332 for(uint i = 0; i < itsRegions.size(); i++)
00333 {
00334 float minDist = itsDistances[itsRegions[i].start];
00335 uint minIndex = itsRegions[i].start;
00336 for(uint j = itsRegions[i].start +1; j <= itsRegions[i].end; j++)
00337 {
00338
00339 if(itsDistances[j] == -1.0) continue;
00340
00341
00342 if(j >= 25 && j <= 36) continue;
00343 if(j >= 243 && j <= 253) continue;
00344
00345
00346 if(minDist > itsDistances[j])
00347 {
00348 minDist = itsDistances[j];
00349 minIndex = j;
00350 }
00351 }
00352
00353 itsRegions[i].minDistance = minDist;
00354 itsRegions[i].minIndex = minIndex;
00355 LINFO("[%4d]{%4d, %4d} minDist: %f",
00356 itsRegions[i].minIndex,
00357 itsRegions[i].start, itsRegions[i].end,
00358 itsRegions[i].minDistance);
00359 }
00360 }
00361
00362
00363 void ND_Navigation::findGoalRegion()
00364 {
00365
00366
00367
00368
00369 uint goalRegion = 0;
00370 for(uint i = 0; i < itsRegions.size(); i++)
00371 {
00372 LINFO("[%d][%d %d]",
00373 i, itsRegions[i].start,itsRegions[i].end);
00374 if(itsRegions[i].start <= itsGoalSector &&
00375 itsRegions[i].end >= itsGoalSector)
00376 {
00377 goalRegion = i;
00378 LINFO("goal: %d", i);
00379 }
00380 }
00381
00382 LINFO("initial goal region: %d", goalRegion);
00383 if(isNavigableRegion(goalRegion))
00384 LINFO("just go straight: %d", goalRegion);
00385 else
00386 {
00387 int cRegion = goalRegion + 1;
00388 while(cRegion < int(itsRegions.size()) &&
00389 !isNavigableRegion(cRegion))
00390 {
00391 cRegion++;
00392 }
00393
00394
00395 if(cRegion == int(itsRegions.size()))
00396 {
00397 cRegion = goalRegion - 1;
00398 while(cRegion >= 0 &&
00399 !isNavigableRegion(cRegion))
00400 {
00401 cRegion--;
00402 }
00403
00404 if(cRegion == -1)
00405 {
00406
00407 LINFO("get lucky");
00408 }
00409 else
00410 {
00411 goalRegion = cRegion;
00412 LINFO("to the right: %d", goalRegion);
00413 }
00414 }
00415 else
00416 {
00417 goalRegion = cRegion;
00418 LINFO("to the left: %d", goalRegion);
00419 }
00420 }
00421
00422 itsGoalRegion = goalRegion;
00423 uint start = itsRegions[goalRegion].start;
00424 uint end = itsRegions[goalRegion].end;
00425
00426 float total = 0.0;
00427 for(uint i = start; i <= end; i++)
00428 total += itsDistances[i];
00429 total /= 2.0;
00430
00431 uint index = start;
00432 while(index <= end && total > 0.0)
00433 {
00434 total -= itsDistances[index];
00435 index++;
00436 }
00437 itsNextDirection = index;
00438
00439
00440
00441
00442
00443 LINFO("Next dir: %d ", itsNextDirection);
00444
00445 }
00446
00447
00448
00449 void ND_Navigation::biasForSafety()
00450 {
00451 uint biasRange = 60;
00452
00453 if(itsNextDirection > biasRange)
00454 itsRightEnd = itsNextDirection - biasRange;
00455 else itsRightEnd = 0;
00456
00457
00458 if(itsNextDirection < itsAngles.size() - biasRange)
00459 itsLeftEnd = itsNextDirection + biasRange;
00460 else itsLeftEnd = itsAngles.size() - 1;
00461
00462
00463
00464 if(itsRightEnd < 50) itsRightEnd = 50;
00465 if(itsLeftEnd > 230) itsLeftEnd = 230;
00466
00467 if(itsNextDirection < 50) itsNextDirection = 50;
00468 if(itsNextDirection > 230) itsNextDirection = 230;
00469
00470 if(itsRightEnd > itsLeftEnd) return;
00471
00472 float rightDist = SecurityNearnessRad;
00473 int rightIndex = -1;
00474 for(uint i = itsRightEnd; i < itsNextDirection; i++)
00475 {
00476
00477 if(itsDistances[i] == -1.0) continue;
00478
00479
00480 if(i >= 25 && i <= 36) continue;
00481 if(i >= 243 && i <= 253) continue;
00482
00483 if(itsDistances[i] < SecurityNearnessRad)
00484 {
00485 rightDist = itsDistances[i];
00486 rightIndex = i;
00487 }
00488 }
00489
00490 float leftDist = SecurityNearnessRad;
00491 int leftIndex = -1;
00492 for(uint i = itsNextDirection; i < itsLeftEnd; i++)
00493 {
00494
00495 if(itsDistances[i] == -1.0) continue;
00496
00497
00498 if(i >= 25 && i <= 36) continue;
00499 if(i >= 243 && i <= 253) continue;
00500
00501 if(itsDistances[i] < SecurityNearnessRad)
00502 {
00503 leftDist = itsDistances[i];
00504 leftIndex = i;
00505 }
00506 }
00507
00508 LINFO("safety [%f %f]",
00509 itsAngles[itsRightEnd], itsAngles[itsLeftEnd]);
00510
00511
00512 if(rightIndex == -1 && leftIndex == -1)
00513 {
00514 LINFO("good to go");
00515 return;
00516 }
00517
00518
00519 if(rightIndex != -1 && leftIndex == -1)
00520 {
00521 itsNextDirection = itsNextDirection + 30;
00522 if(itsNextDirection >= itsAngles.size())
00523 itsNextDirection = itsAngles.size() - 1;
00524
00525 LINFO("right obstacle: [%d] %f: -> %d",
00526 rightIndex, rightDist, itsNextDirection);
00527 return;
00528 }
00529
00530
00531 if(rightIndex == -1 && leftIndex != -1)
00532 {
00533 if(itsNextDirection < 30)
00534 itsNextDirection = 0;
00535 else
00536 itsNextDirection -= 30;
00537
00538 LINFO("left obstacle: [%d] %f -> %d",
00539 leftIndex, leftDist, itsNextDirection);
00540 return;
00541 }
00542
00543
00544 if(rightIndex != -1 && leftIndex != -1)
00545 {
00546 int bias = int((leftDist - rightDist)/SecurityNearnessRad * 10.0);
00547 if (bias > 10.0) bias = 10.0;
00548 if (bias < -10.0) bias = -10.0;
00549
00550 int temp = itsNextDirection + bias;
00551 if(temp < 0) temp = 0;
00552 if(temp >= int(itsAngles.size())) temp = itsAngles.size() - 1;
00553
00554 LINFO("hopefully nothing bad happens: %d -> %d", itsNextDirection, temp);
00555 itsNextDirection = temp;
00556
00557 return;
00558 }
00559 return;
00560 }
00561
00562
00563 bool ND_Navigation::isNavigableRegion(uint index)
00564 {
00565 bool extreme = false;
00566 uint size = itsRegions[index].end - itsRegions[index].start;
00567 uint count = 0;
00568 for(uint i = itsRegions[index].start; i <= itsRegions[index].end; i++)
00569 {
00570 if(i > 230 || i < 50) count++;
00571 }
00572 if(count > size/2) extreme = true;
00573
00574 uint nSector = itsRegions[index].end - itsRegions[index].start;
00575 float minDist = itsRegions[index].minDistance;
00576
00577 bool isNav = (((nSector >= 6 && minDist > 1250.0) ||
00578 ((nSector >= 4 && nSector <= 5) && minDist >= 2000.0))
00579 && !extreme);
00580
00581 if(!isNav) LINFO("not Nav: %d %d %f extreme: %d", index,
00582 nSector, minDist, extreme);
00583
00584 return isNav;
00585 }
00586
00587
00588 void ND_Navigation::updateMessage
00589 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&)
00590 {
00591
00592 if(eMsg->ice_isA("::BeobotEvents::LRFMessage"))
00593 {
00594
00595 BeobotEvents::LRFMessagePtr lrfMsg =
00596 BeobotEvents::LRFMessagePtr::dynamicCast(eMsg);
00597
00598 itsDistances = lrfMsg->distances;
00599 itsAngles = lrfMsg->angles;
00600
00601
00602 Beobot2::MotorCommand cmd = computeND_Navigation();
00603
00604
00605 updateMotor(cmd.translation,cmd.rotation);
00606 }
00607 }
00608
00609
00610 void ND_Navigation::updateMotor(double tran,double rot)
00611 {
00612 BeobotEvents::MotorRequestPtr msg = new BeobotEvents::MotorRequest;
00613 msg->transVel = tran;
00614 msg->rotVel = rot;
00615 this->publish("MotorRequestTopic", msg);
00616
00617 }
00618
00619
00620
00621
00622
00623