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