GistSal_Navigation.C

00001 /*!@file Robots2/Beobot2/Navigation/GistSal_Navigation/GistSal_Navigation.C */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Chin-Kai Chang <chinkaic@usc.edu>
00033 // $HeadURL: svn://ilab.usc.edu/trunk/saliency/src/Robots/Beobot2/GistSal_Navigation.C
00034 // $ $Id: GistSal_Navigation.C 13126 2010-04-02 03:42:30Z beobot $
00035 //
00036 //////////////////////////////////////////////////////////////////////////
00037 
00038 #include "Robots/Beobot2/Navigation/GistSal_Navigation/GistSal_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 "Image/ColorOps.H"   // for luminance()
00046 #include "Image/ShapeOps.H"   // for rescale()
00047 #include "Image/MathOps.H"    // for stdev()
00048 #include "Image/MatrixOps.H"  // for matrixMult()
00049 #include "Image/CutPaste.H"   // for inplacePaste()
00050 
00051 #include "Util/Timer.H"
00052 
00053 #include "SIFT/Keypoint.H"
00054 #include "SIFT/VisualObject.H"
00055 #include "SIFT/VisualObjectMatch.H"
00056 #include "Transport/FrameInfo.H"
00057 
00058 #include "Ice/IceImageUtils.H"
00059 
00060 #include "Component/ModelParam.H"
00061 #include "Component/ModelOptionDef.H"
00062 
00063 #define IMAX                      1.0
00064 #define IMIN                      0.0
00065 #define LOST_TIME_LIMIT            6500000
00066 #define ROT_TIME_LIMIT             3000000
00067 #define JUNCTION_START_DIST       8.0
00068 #define REVERSE_COUNT_MAX         10
00069 #define INVALID_ANGLE             -100.0
00070 #define INVALID_DISTANCE          -200.0
00071 
00072 #define C_PROCEDURE_INACTIVE      0
00073 #define C_PROCEDURE_ACTIVE        1
00074 #define C_PROCEDURE_CONCLUDING    2
00075 
00076 // ######################################################################
00077 GistSal_Navigation::GistSal_Navigation(OptionManager& mgr,
00078                                        const std::string& descrName,
00079                                        const std::string& tagName)
00080   :
00081   RobotBrainComponent(mgr, descrName, tagName),
00082   itsOfs(new OutputFrameSeries(mgr)),
00083   itsTimer(1000000),
00084   itsCurrImgID(-1),
00085   itsPrevProcImgID(-1),
00086   itsTransSpeed(0.0),
00087   itsRotSpeed(0.0),
00088   itsDir(0),
00089   itsIState(0.0),
00090   itsDState(0.0),
00091   itsPGain(1.0),
00092   itsIGain(0.01),
00093   itsDGain(0.0),
00094   itsReverseCount(0),
00095   itsReverseDir(false),
00096   itsDistToGoal(-1.0),
00097   itsLastFoundTimer(1000000),
00098   itsSearchTracker(new SalientRegionTracker(mgr)),
00099   itsNewMovementTracker(new SalientRegionTracker(mgr)),
00100   itsCurrMovementTracker(new SalientRegionTracker(mgr))
00101 {
00102   addSubComponent(itsOfs);
00103 
00104   // tracker
00105   addSubComponent(itsSearchTracker);
00106   addSubComponent(itsNewMovementTracker);
00107   addSubComponent(itsCurrMovementTracker);
00108   itsResetSearchTracker = true;
00109 
00110   // assume the robot is not moving
00111   // until after a landmark is recognized
00112   itsTurnAngle    = 0.0;
00113   itsJunctionDist = -1.0;
00114   itsLastFoundTimer.reset();
00115 
00116   // FIX: HACK IT FIRST TO JUST GO HOME
00117   itsDesiredSegmentLocation       = 3;
00118   itsDesiredSegmentLengthTraveled = 0.95;
00119   itsInGoal = false;
00120 
00121   // this initialization is meaningless
00122   itsCurrentSegmentLocation       = 0;
00123   itsCurrentSegmentLengthTraveled = 0.0;
00124 
00125   itsCornerProcStatus = C_PROCEDURE_INACTIVE;
00126 }
00127 
00128 // ######################################################################
00129 void GistSal_Navigation::setEnvironment
00130 (rutz::shared_ptr<Environment> env)
00131 {
00132   itsEnvironment = env;
00133 
00134   // from its environment: topological map
00135   itsTopologicalMap = env->getTopologicalMap();
00136 
00137   // from its environment: visual landmark database
00138   itsLandmarkDB = env->getLandmarkDB();
00139 }
00140 
00141 // ######################################################################
00142 GistSal_Navigation::~GistSal_Navigation()
00143 { }
00144 
00145 // ######################################################################
00146 void GistSal_Navigation::start1()
00147 { }
00148 
00149 // ######################################################################
00150 void GistSal_Navigation::registerTopics()
00151 {
00152   // subscribe to gist, saliency, localizer result, and motor topics
00153   this->registerSubscription("LandmarkTrackMessageTopic");
00154   this->registerSubscription("LandmarkDBSearchResultMessageTopic");
00155   this->registerSubscription("CurrentLocationMessageTopic");
00156   this->registerSubscription("MotorMessageTopic");
00157   this->registerSubscription("CornerMotorRequestTopic");
00158 
00159   this->registerPublisher("CornerLocationMessageTopic");
00160   this->registerPublisher("MotorRequestTopic");
00161 }
00162 
00163 // ######################################################################
00164 void GistSal_Navigation::updateMessage
00165 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&)
00166 {
00167   Timer timer(1000000);
00168 
00169   // input image, saliency, and gist features message
00170   if(eMsg->ice_isA("::BeobotEvents::LandmarkTrackMessage"))
00171     {
00172       // store the image
00173       BeobotEvents::LandmarkTrackMessagePtr lTrackMsg =
00174         BeobotEvents::LandmarkTrackMessagePtr::dynamicCast(eMsg);
00175 
00176       int currRequestID = lTrackMsg->RequestID;
00177       Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> >(lTrackMsg->currIma);
00178 
00179       LINFO("Got an lTrackMessage with Request ID = %d", currRequestID);
00180 
00181       // get the recieved message
00182       its_input_mutex.lock();
00183       itsCurrImg   = img;
00184       itsCurrImgID = currRequestID;
00185 
00186       // get the salient region information
00187       uint inputSize = lTrackMsg->salientRegions.size();
00188       itsCurrSalPoints.clear();
00189       itsCurrSalRects.clear();
00190       for(uint i = 0; i < inputSize; i++)
00191         {
00192           BeobotEvents::SalientRegion salReg = lTrackMsg->salientRegions[i];
00193           LINFO("M[%4d] sp[%4d,%4d] rect[%4d,%4d,%4d,%4d]",
00194                 i, salReg.salpt.i, salReg.salpt.j,
00195                 salReg.objRect.tl.i, salReg.objRect.tl.j,
00196                 salReg.objRect.br.i, salReg.objRect.br.j);
00197 
00198           Point2D<int> salpt(salReg.salpt.i, salReg.salpt.j);
00199           itsCurrSalPoints.push_back(salpt);
00200 
00201           Rectangle rect = Rectangle::tlbrO
00202               (salReg.objRect.tl.j, salReg.objRect.tl.i,
00203                salReg.objRect.br.j, salReg.objRect.br.i);
00204           itsCurrSalRects.push_back(rect);
00205        }
00206 
00207       // get the conspicuity maps
00208       itsCurrCmap.clear();
00209       itsCurrCmap.reset(NUM_CHANNELS);
00210       for(uint i = 0; i < NUM_CHANNELS; i++)
00211         itsCurrCmap[i] = Ice2Image<float>(lTrackMsg->conspicuityMaps[i]);
00212 
00213       its_input_mutex.unlock();
00214 
00215       LINFO("[input time: %f ms]\n\n", timer.get()/1000.0f);
00216     }
00217 
00218   // landmark database match found to be tracked
00219   else if(eMsg->ice_isA("::BeobotEvents::LandmarkDBSearchResultMessage"))
00220     {
00221       BeobotEvents::LandmarkDBSearchResultMessagePtr dbrMsg =
00222         BeobotEvents::LandmarkDBSearchResultMessagePtr::dynamicCast(eMsg);
00223 
00224       int currRequestID = dbrMsg->RequestID;
00225 
00226       LINFO("Got a LandmarkDBSearchResultMessage with Request ID = %d",
00227             currRequestID);
00228 
00229       its_tracker_mutex.lock();
00230       its_Curr_Dbr_mutex.lock();
00231       itsCurrImgID = currRequestID;
00232 
00233       // make sure there is at least 1 to be tracked
00234       uint numRecognized = dbrMsg->matches.size();
00235 
00236       // check for asynchrony
00237       if(numRecognized > 0)
00238         {
00239           uint mIndex = dbrMsg->matches[numRecognized - 1].inputSalRegID;
00240           if(mIndex >= itsSearchTracker->getNumTrackedPoints())
00241             {
00242               LINFO("\n\n\nASYNCHRONIZATION HAS OCCURED: %d %d\n\n",
00243                     mIndex, itsSearchTracker->getNumTrackedPoints());
00244               numRecognized = 0;
00245 
00246               // NOTE: need better solution to fix this problem
00247             }
00248         }
00249 
00250       // if we have a new recognized salient region
00251       if(numRecognized > 0)
00252         {
00253           itsNewMovementTracker->clear();
00254 
00255           itsNewMovementTracker->reset(numRecognized);
00256           itsNewMovementTracker->setCurrInputImage
00257             (itsSearchTracker->getCurrInputImage());
00258           itsNewMovementTracker->setOriginalInputImage
00259             (itsSearchTracker->getOriginalInputImage());
00260 
00261           // MOVE found Landmark from  SearchTracker to NewTracker
00262           itsNewLandmarkDBMatches.clear();
00263           for(uint i = 0; i < dbrMsg->matches.size(); i++)
00264             {
00265               uint index = dbrMsg->matches[i].inputSalRegID;
00266               itsNewMovementTracker->move(itsSearchTracker, index);
00267 
00268               // get the salient region of the landmark
00269               // that are just identified
00270               rutz::shared_ptr<LandmarkDBMatch> ldbm(new LandmarkDBMatch());
00271               GSlocJobData dbmi(index,
00272                                 dbrMsg->matches[i].dbSegNum,
00273                                 dbrMsg->matches[i].dbLmkNum,
00274                                 dbrMsg->matches[i].dbVOStart,
00275                                 dbrMsg->matches[i].dbVOEnd);
00276               ldbm->dbi = dbmi;
00277               itsNewLandmarkDBMatches.push_back(ldbm);
00278 
00279               LINFO("DB Match sent: %d: (%d %d - %d %d)",
00280                     itsNewLandmarkDBMatches[i]->dbi.objNum,
00281                     itsNewLandmarkDBMatches[i]->dbi.segNum,
00282                     itsNewLandmarkDBMatches[i]->dbi.lmkNum,
00283                     itsNewLandmarkDBMatches[i]->dbi.voStartNum,
00284                     itsNewLandmarkDBMatches[i]->dbi.voEndNum);
00285             }
00286         }
00287 
00288       // we can now reset the search tracker
00289       itsResetSearchTracker = true;
00290 
00291       its_Curr_Dbr_mutex.unlock();
00292       its_tracker_mutex.unlock();
00293       LINFO("Found %d new landmarks in %f ms \n\n",
00294             numRecognized, timer.get()/1000.0f);
00295     }
00296 
00297   // current location message
00298   else if(eMsg->ice_isA("::BeobotEvents::CurrentLocationMessage"))
00299     {
00300       BeobotEvents::CurrentLocationMessagePtr clMsg =
00301         BeobotEvents::CurrentLocationMessagePtr::dynamicCast(eMsg);
00302       LDEBUG("Got a CurrentLocationMessage with Request ID = %d"
00303              ": loc(%d, %f)",
00304              clMsg->RequestID, clMsg->segNum, clMsg->lenTrav);
00305       its_Curr_Loc_mutex.lock();
00306       itsCurrentSegmentLocation = clMsg->segNum;
00307       itsCurrentSegmentLengthTraveled = clMsg->lenTrav;
00308       its_Curr_Loc_mutex.unlock();
00309     }
00310 
00311   // motor message
00312   else if(eMsg->ice_isA("::BeobotEvents::MotorMessage"))
00313     {
00314       BeobotEvents::MotorMessagePtr mtrMsg =
00315         BeobotEvents::MotorMessagePtr::dynamicCast(eMsg);
00316       its_Curr_Mtr_mutex.lock();
00317       itsRemoteMode = mtrMsg->rcMode;
00318       itsRcTransSpeed = mtrMsg->rcTransVel;
00319       itsRcRotSpeed = mtrMsg->rcRotVel;
00320       its_Curr_Mtr_mutex.unlock();
00321 
00322       LDEBUG("Got a MotorMessage with Request ID = %d: RC Trans %f, Rot %f",
00323              mtrMsg->RequestID, itsRcTransSpeed, itsRcRotSpeed);
00324     }
00325 
00326   // corner message
00327   else if(eMsg->ice_isA("::BeobotEvents::CornerMotorRequest"))
00328     {
00329       BeobotEvents::CornerMotorRequestPtr cmtrMsg =
00330         BeobotEvents::CornerMotorRequestPtr::dynamicCast(eMsg);
00331 
00332       its_Curr_CornerMtr_mutex.lock();
00333       itsCornerTransSpeed  = cmtrMsg->transVel;
00334       itsCornerRotSpeed    = cmtrMsg->rotVel;
00335 
00336       if(cmtrMsg->status      == C_PROCEDURE_INACTIVE)
00337         itsCornerProcStatus   = C_PROCEDURE_INACTIVE;
00338       else if(cmtrMsg->status == C_PROCEDURE_ACTIVE)
00339         itsCornerProcStatus   = C_PROCEDURE_ACTIVE;
00340       else if(cmtrMsg->status == C_PROCEDURE_CONCLUDING)
00341         itsCornerProcStatus   = C_PROCEDURE_CONCLUDING;
00342 
00343       its_Curr_CornerMtr_mutex.unlock();
00344       LINFO("Got a CornerMotorRequest Trans %f, Rot %f",
00345             itsCornerTransSpeed, itsCornerRotSpeed);
00346     }
00347 }
00348 
00349 // ######################################################################
00350 void GistSal_Navigation::evolve()
00351 {
00352   // check if the current image is updated
00353   its_input_mutex.lock();
00354   bool newInputFlag = (itsPrevProcImgID < itsCurrImgID);
00355   its_input_mutex.unlock();
00356 
00357   // if so, process
00358   if(newInputFlag)
00359     {
00360       itsTimer.reset();
00361 
00362       its_tracker_mutex.lock();
00363       its_Curr_Dbr_mutex.lock();
00364       its_Curr_CornerMtr_mutex.lock();
00365 
00366       its_input_mutex.lock();
00367       itsProcImg = itsCurrImg;
00368       itsPrevProcImgID = itsCurrImgID;
00369       std::vector<Point2D<int> > salPoints = itsCurrSalPoints;
00370       ImageSet<float> cmap = itsCurrCmap;
00371       std::vector<Rectangle> rects = itsCurrSalRects;
00372       its_input_mutex.unlock();
00373 
00374       // feed conspicuity maps to the trackers
00375       LINFO("\n search tracker: reset: %d ", itsResetSearchTracker);
00376       // FIX !!!
00377       std::vector<rutz::shared_ptr<VisualObject> > fakeVO;
00378       itsSearchTracker->input
00379         (itsProcImg, cmap, itsResetSearchTracker,
00380          salPoints, rects, fakeVO);
00381       LINFO("\n movement tracker");
00382       itsCurrMovementTracker->input
00383         (itsProcImg, cmap, false,
00384          salPoints, rects, fakeVO);
00385       itsNewMovementTracker->input
00386         (itsProcImg, cmap, false,
00387          salPoints, rects, fakeVO);
00388 
00389       // so that we only reset once per request
00390       itsResetSearchTracker = false;
00391 
00392       // FOR MOVEMENT
00393 
00394       // check for nearness to junctions/intersections
00395       bool nearJunction = estimateProgressToDestination();
00396 
00397       // NOTE: BIAS IGNORED
00398 
00399       // if near junction && not in corner procedure
00400       if(nearJunction &&
00401          itsCornerProcStatus == C_PROCEDURE_INACTIVE)
00402         {
00403           // start the turning procedure
00404           // send out which corner to cue from
00405           BeobotEvents::CornerLocationMessagePtr msg =
00406             new BeobotEvents::CornerLocationMessage;
00407           msg->cornerLocation = itsCurrentSegmentLocation;
00408           this->publish("CornerLocationMessageTopic", msg);
00409           LINFO("Publishing corner location %d", msg->cornerLocation);
00410         }
00411 
00412       // if in the middle of corner procedure
00413       if(itsCornerProcStatus == C_PROCEDURE_ACTIVE)
00414         {
00415           itsTransSpeed = itsCornerTransSpeed;
00416           itsRotSpeed   = itsCornerRotSpeed;
00417 
00418           itsLastFoundTimer.reset();
00419         }
00420 
00421       if(itsCornerProcStatus == C_PROCEDURE_CONCLUDING ||
00422          itsCornerProcStatus == C_PROCEDURE_INACTIVE     )
00423         {
00424           // get the recognized salient regions
00425           uint64 kpst = itsTimer.get();
00426           bool foundSomething = (getKeypointMatches() != 0);
00427           //if(foundSomething) itsLastFoundTimer.reset();
00428 
00429           LINFO("[KP time: %f]\n\n", (itsTimer.get() - kpst)/1000.0f);
00430           if(itsCurrLandmarkDBMatches.size() != 0)
00431             {
00432               // extract the error difference
00433               computeErrorDifference();
00434 
00435               // last found timer can be reset
00436               itsLastFoundTimer.reset();
00437               itsReverseCount = 0;
00438               //itsReverseDir = false;
00439 
00440               itsCornerProcStatus = C_PROCEDURE_INACTIVE;
00441             }
00442           else
00443             {
00444               if(itsCornerProcStatus == C_PROCEDURE_CONCLUDING)
00445                 {
00446                   itsTransSpeed = itsCornerTransSpeed;
00447                   itsRotSpeed   = itsCornerRotSpeed;
00448 
00449                   itsLastFoundTimer.reset();
00450                 }
00451               else
00452                 {
00453                   // slow down - hope we find new regions
00454                   itsTransSpeed = 0.6;
00455 
00456                   //if(itsLastFoundTimer.get() > ROT_TIME_LIMIT
00457                   //   && !itsReverseDir)
00458                   //  {
00459                   //    itsRotSpeed = -1.0 * itsRotSpeed;
00460                   //    itsReverseDir = true;
00461                   //  }
00462                   //itsDistToGoal = -1.0;
00463                 }
00464             }
00465 
00466           // if we have not found anything for some time
00467           if(itsLastFoundTimer.get() > LOST_TIME_LIMIT)
00468             recover(foundSomething);
00469         }
00470 
00471       // use the error difference to drive
00472       navigation();
00473 
00474       its_Curr_CornerMtr_mutex.unlock();
00475       its_Curr_Dbr_mutex.unlock();
00476       its_tracker_mutex.unlock();
00477 
00478       // draw the state of the surroundings
00479       drawState();
00480       itsOfs->writeRGB(itsDispImg, " ><\" GistSal_nav",
00481                        FrameInfo("GistSal_nav",SRC_POS));
00482 
00483       LINFO("[time: %f]\n\n\n\n", itsTimer.get()/1000.0f);
00484     }
00485 }
00486 
00487 // ######################################################################
00488 // computing visual error difference
00489 uint GistSal_Navigation::getKeypointMatches()
00490 {
00491   Timer tim(1000000);
00492   uint nCount, cCount;
00493 
00494   // check if there are new DBmatches
00495   //uint oldNcount = itsNewLandmarkDBMatches.size();
00496   //uint oldCcount = itsCurrLandmarkDBMatches.size();
00497 
00498   // check if the new regions can be projected forward
00499   nCount = projectForward(itsNewLandmarkDBMatches,
00500                           itsNewMovementTracker);
00501   if(nCount == 0)
00502     {
00503       // No
00504 
00505       // stick with the old ones
00506       cCount = projectForward(itsCurrLandmarkDBMatches,
00507                               itsCurrMovementTracker);
00508     }
00509   else
00510     {
00511       // project forward succeed
00512       // move new regions to become current ones
00513       itsCurrLandmarkDBMatches = itsNewLandmarkDBMatches;
00514 
00515       itsCurrMovementTracker->clear();
00516       itsCurrMovementTracker->reset(nCount);
00517       itsCurrMovementTracker->setCurrInputImage
00518         (itsNewMovementTracker->getCurrInputImage());
00519       itsCurrMovementTracker->setOriginalInputImage
00520         (itsNewMovementTracker->getOriginalInputImage());
00521       for(uint i = 0; i < nCount; i++)
00522         itsCurrMovementTracker->move(itsNewMovementTracker, i);
00523     }
00524   cCount = itsCurrLandmarkDBMatches.size();
00525   LINFO("\n\n\n Project forward: %d time: %f\n\n\n",
00526         cCount, tim.get()/1000.0f);
00527 
00528   // DON'T STOP ON THE WRONG SCALE
00529 
00530   // check if there are new DBmatches
00531   uint count = itsNewLandmarkDBMatches.size();
00532 
00533 
00534   // if not keep the old DBmatches
00535   if (count == 0)
00536     {
00537       count = itsCurrLandmarkDBMatches.size();
00538       // for(uint i = 0; i < itsCurrLandmarkDBMatches.size(); i++)
00539       //   {
00540 
00541       //     int index = itsLandmarkDB->getLandmark
00542       //       (itsCurrLandmarkDBMatches[i]->dbi.segNum,
00543       //        itsCurrLandmarkDBMatches[i]->dbi.lmkNum)->match
00544       //       (vo, cmatch,
00545       //        itsCurrLandmarkDBMatches[i]->dbi.voStartNum,
00546       //        -1, 10.0F, .75F, 2.5F, 4, M_PI/4, 1.25F);
00547 
00548 
00549       //     SIFTaffine aff =
00550       //       (itsCurrLandmarkDBMatches[i])->matchRes->getSIFTaffine();
00551       //     float theta, sx, sy, str;
00552       //     aff.decompose(theta, sx, sy, str);
00553       //     if(sx > 1.25F || sx < 0.8F)
00554       //       if(count > 0) count--;
00555       //   }
00556     }
00557 
00558 // int index = itsLandmarkDB->getLandmark
00559 //         (landmarkDBMatches[i]->dbi.segNum,
00560 //          landmarkDBMatches[i]->dbi.lmkNum)->match
00561 //         (vo, cmatch, landmarkDBMatches[i]->dbi.voStartNum,
00562 //          -1, 10.0F, .75F, 2.5F, 4, M_PI/4, 1.25F);
00563 
00564 
00565 
00566 
00567 
00568   return count;
00569 }
00570 
00571 // ######################################################################
00572 uint GistSal_Navigation::projectForward
00573 (std::vector<rutz::shared_ptr<LandmarkDBMatch> > &landmarkDBMatches,
00574  nub::soft_ref<SalientRegionTracker> tracker)
00575 {
00576   // get the found database matches
00577   std::vector<rutz::shared_ptr<LandmarkDBMatch> > tempLandmarkDBMatches;
00578 
00579   LINFO("start: %"ZU, landmarkDBMatches.size());
00580 
00581   for(uint i = 0; i < landmarkDBMatches.size(); i++)
00582     {
00583       // get the tracked salient region rectangle
00584       Rectangle rect = tracker->getCurrTrackedROI(i);
00585 
00586       // create a Visual Object
00587       Point2D<int> offset= rect.topLeft();
00588       Image<PixRGB<byte> > objImg = crop(itsCurrImg, rect);
00589       std::string iName("iName");
00590       std::string ifName = iName + std::string(".png");
00591       rutz::shared_ptr<VisualObject>
00592         vo(new VisualObject(iName, ifName, objImg));
00593       //vo(new VisualObject(iName, ifName, objImg, salpt - offset));
00594 
00595       // project forward with the database found
00596       LINFO("DB Match sent: %d: (%d %d - %d %d)",
00597             landmarkDBMatches[i]->dbi.objNum,
00598             landmarkDBMatches[i]->dbi.segNum,
00599             landmarkDBMatches[i]->dbi.lmkNum,
00600             landmarkDBMatches[i]->dbi.voStartNum,
00601             landmarkDBMatches[i]->dbi.voEndNum);
00602 
00603       rutz::shared_ptr<VisualObjectMatch> cmatch;
00604       int index = itsLandmarkDB->getLandmark
00605         (landmarkDBMatches[i]->dbi.segNum,
00606          landmarkDBMatches[i]->dbi.lmkNum)->match
00607         (vo, cmatch, landmarkDBMatches[i]->dbi.voStartNum,
00608          -1, 10.0F, .75F, 2.5F, 4, M_PI/4, 1.25F);
00609       landmarkDBMatches[i]->dbi.voStartNum = index;
00610       landmarkDBMatches[i]->dbi.voEndNum   = index;
00611 
00612       // set successful projected forward landmarks
00613       if(index != -1)
00614         {
00615           LINFO("\nProject Forward succeed: %d\n\n", index);
00616 
00617           landmarkDBMatches[i]->vo = vo;
00618 
00619           // need to store this to release mutex during drawState()
00620           Point2D<int> pt =
00621             itsLandmarkDB->getLandmark
00622             (landmarkDBMatches[i]->dbi.segNum,
00623              landmarkDBMatches[i]->dbi.lmkNum)
00624             ->getOffsetCoords
00625             (landmarkDBMatches[i]->dbi.voStartNum);
00626 
00627           landmarkDBMatches[i]->voOffset = offset;
00628           landmarkDBMatches[i]->dbOffset = pt;
00629           landmarkDBMatches[i]->matchRes = cmatch;
00630 
00631           tempLandmarkDBMatches.push_back(landmarkDBMatches[i]);
00632 
00633           LINFO("project success %d", i);
00634         }
00635       else
00636         LINFO("\nProject Forward fail: %d\n\n", index);
00637     }
00638 
00639   // only switch when there is a new
00640   //if(tempFoundDBmatches.size() != 0)
00641   landmarkDBMatches = tempLandmarkDBMatches;
00642 
00643   return uint(landmarkDBMatches.size());
00644 }
00645 
00646 // ######################################################################
00647 // computing visual error difference
00648 void GistSal_Navigation::computeErrorDifference()
00649 {
00650   // boundary condition
00651   //if((teachID-5) < TEACH_START_NUMBER) teachID = TEACH_START_NUMBER+2;
00652 
00653   // looking 10 frame ahead to find best match frame
00654   //for(int id = teachID-2; id < teachID+10; id++)
00655   // =========================
00656   //   find the best Keyframe
00657   //   float theta = 2.0, sx = 2.0, sy = 2.0, str = 0;
00658   //   match->getSIFTaffine().decompose(theta, sx, sy, str);
00659 
00660   int dirF = 0,dirL = 0,dirR = 0;
00661 
00662   uint w = itsProcImg.getWidth();
00663   uint h = itsProcImg.getHeight();
00664 
00665   // mean and standard error
00666   //double stdx  = 0.0, stdy  = 0.0;
00667   double avgdx = 0.0, avgdy = 0.0;
00668 
00669   uint nLDBMatch = itsCurrLandmarkDBMatches.size();
00670   uint totalMatchSize = 0;
00671 
00672   for(uint i = 0; i < nLDBMatch; i++)
00673     totalMatchSize += itsCurrLandmarkDBMatches[i]->matchRes->size();
00674 
00675   // go through each identified landmark
00676   for(uint i = 0; i < nLDBMatch; i++)
00677     {
00678       int dirGain = 1;
00679 
00680       rutz::shared_ptr<LandmarkDBMatch> ldbm =
00681         itsCurrLandmarkDBMatches[i];
00682       rutz::shared_ptr<VisualObjectMatch> matchRes =
00683         ldbm->matchRes;
00684 
00685       Point2D<int> obOffset = ldbm->voOffset;
00686       Point2D<int> dbOffset = ldbm->dbOffset;
00687 
00688       bool isODmatch =
00689         (ldbm->vo == matchRes->getVoRef());
00690 
00691       // compute the direction and find mean of error
00692       for (uint j = 0; j < matchRes->size(); j++)
00693         {
00694           rutz::shared_ptr<Keypoint> obkp; // input    visual object
00695           rutz::shared_ptr<Keypoint> dbkp; // database visual object
00696           if(isODmatch)
00697             {
00698               obkp = matchRes->getKeypointMatch(j).refkp;
00699               dbkp = matchRes->getKeypointMatch(j).tstkp;
00700             }
00701           else
00702             {
00703               obkp = matchRes->getKeypointMatch(j).tstkp;
00704               dbkp = matchRes->getKeypointMatch(j).refkp;
00705             }
00706 
00707           // to shift origin to the middle of the image
00708           double ud = dbkp->getX() + dbOffset.i - w/2;
00709           double ut = obkp->getX() + obOffset.i - w/2;
00710 
00711           double vd = dbkp->getY() + dbOffset.j - h/2;
00712           double vt = obkp->getY() + obOffset.j - h/2;
00713 
00714           double dx = fabs(ut - ud);
00715           double dy = fabs(vt - vd);
00716 
00717           // calculate standard deviation and average
00718           //double stdx  = 0.0;
00719           //double stdy  = 0.0;
00720           avgdx += dx;
00721           avgdy += dy;
00722 
00723           // calculate direction
00724           if(ut > 0.0 && ud < 0.0)
00725             {
00726               dirR += dirGain;
00727             }
00728           else if(ut < 0.0 && ud > 0.0)
00729             {
00730               dirL += dirGain;
00731             }
00732           else if(ut > 0.0 && ut > ud)
00733             {
00734               dirR += dirGain;
00735             }
00736           else if(ut < 0.0 && ut < ud)
00737             {
00738               dirL += dirGain;
00739             }
00740           else
00741             {
00742               dirF +=dirGain;
00743             }
00744         }
00745     }
00746   LINFO("dirL: %4d dirF: %4d dirR: %4d", dirL, dirF, dirR);
00747   avgdx /= totalMatchSize;
00748   avgdy /= totalMatchSize;
00749   LINFO("avgdx %f avgdy %f", avgdx, avgdy);
00750 
00751   // calculating standard deviation
00752   // in the loop above-> stdx += dx * dx;
00753   // after loop -> stdx -= (avgdx*avgdx);
00754   //               stdx /= bestMatchSize;
00755   //               stdx  = sqrt(stdx);
00756 
00757   itsXError = avgdx;
00758   itsYError = avgdy;
00759   itsError  = sqrt(avgdx*avgdx + avgdy*avgdy);
00760 
00761   // compute the forward speed based on scale
00762   // if it's much smaller than the one on DB: drive fast
00763   //  bestMatch->getSIFTaffine().decompose(theta, sx, sy, str);
00764   //
00765   //  //if the size difference is large(sx/sy << 1.0),we can speed up
00766   //  double rms = 1.0 -(sqrt(sx*sx+sy*sy)/sqrt(2));
00767 
00768   // double gain = 1.0;
00769   //    if(rms > 0.0)
00770   //     itsTransSpeed = 0.8 + rms * gain;
00771   //   if(itsTransSpeed > 1.0)itsTransSpeed = 1.0;
00772   //   if(itsTransSpeed < 0.0)itsTransSpeed = 0.0;
00773 
00774   // just use the same speed, for now
00775   itsTransSpeed = 0.8;
00776 
00777   // compute turning speed
00778   if(dirF >= abs(dirR + dirL))
00779     { itsRotSpeed = 0.0; itsDir = 0; }
00780   else if(dirR > dirL)
00781     {
00782       //itsXError -= 55.0;
00783       //if(itsXError < 0.0) itsXError = 0;
00784 
00785       if(itsXError > 50.0)
00786         itsRotSpeed = -0.40;
00787       else
00788         itsRotSpeed = -0.20 + itsXError/50.0 * -0.20;
00789 
00790       itsDir = 1.0;
00791     }
00792   else
00793     {
00794       //itsXError += 25.0;
00795       //if(itsXError < 0.0) itsXError = 0;
00796 
00797       if(itsXError > 50.0)
00798         itsRotSpeed = 0.60;
00799       else
00800         itsRotSpeed = 0.30 + itsXError/50.0 * 0.30;
00801 
00802       itsDir = -1.0;
00803     }
00804 
00805   LINFO("Speed: [trans: %7.3f, rot: %7.3f] Error: %f",
00806         itsTransSpeed, itsRotSpeed, itsError);
00807 }
00808 
00809 // ######################################################################
00810 bool GistSal_Navigation::estimateProgressToDestination()
00811 {
00812   bool nearJunction = false;
00813 
00814   its_Curr_Loc_mutex.lock();
00815   uint  currSegNum  = itsCurrentSegmentLocation;
00816   float currLenTrav = itsCurrentSegmentLengthTraveled;
00817   uint  desSegNum   = itsDesiredSegmentLocation;
00818   float desLenTrav  = itsDesiredSegmentLengthTraveled;
00819   its_Curr_Loc_mutex.unlock();
00820 
00821   // check the moves for the robot to go to the goal location
00822   float dist =
00823     itsTopologicalMap->getPath
00824     (currSegNum, currLenTrav, desSegNum, desLenTrav, itsMoves);
00825   // real distance in ft.
00826   dist *= itsTopologicalMap->getMapScale();
00827   itsDistToGoal = dist;
00828 
00829   // have a turn around command (if necessary) as well
00830   uint msize = itsMoves.size();
00831   for(uint i = 0; i < msize; i++)
00832     LINFO("Moves[%d]: %d", i, itsMoves[i]);
00833 
00834   itsJunctionDist = INVALID_DISTANCE;
00835 
00836   // if we are at goal location
00837   if(dist < 3.5 || msize == 0)
00838     {
00839       // tell the robot to stop
00840       itsInGoal     = true;
00841       itsTransSpeed = 0.0;
00842       itsRotSpeed   = 0.0;
00843       return false;
00844     }
00845   else itsInGoal = false;
00846 
00847   // we actually only need to look one step ahead
00848   if(itsMoves[0] == TOPOMAP_TURN_AROUND)
00849     {
00850       // turn around
00851       itsTurnAngle = M_PI;
00852       LINFO("1 Move: TURN AROUND");
00853 
00854       // this is probably a blocking open-loop operation
00855 
00856       // but also need to be careful about
00857       // not overcommitting too quickly
00858 
00859     }
00860   else if(itsMoves[0] == TOPOMAP_MOVE_FORWARD)
00861     {
00862       // if the goal is in the current and the next edge
00863       if(msize == 1)
00864         {
00865           LINFO("1 Move: almost there just MOVE FORWARD");
00866 
00867           // calculate speed according to distance left
00868           double speed = 0.8;
00869           if(dist < 10.0 && dist > 0.0) speed *= dist/10.0;
00870           itsTransSpeed = speed;
00871 
00872           itsTurnAngle    = 0.0;
00873           itsJunctionDist = -1111.0;
00874         }
00875       // else we need to figure out how far the next node is
00876       else
00877         {
00878           // get the current edge
00879           float ds, de;
00880           rutz::shared_ptr<Edge> e1 =
00881             itsTopologicalMap->getEdge(currSegNum, currLenTrav, ds, de);
00882 
00883           // distance to junction in ft.
00884           float jdist = de * itsTopologicalMap->getMapScale();
00885           itsJunctionDist = jdist;
00886           LINFO("JDIST: %f", jdist );
00887 
00888           // if we are far from the junction
00889           if(jdist > JUNCTION_START_DIST)
00890             {
00891               // move with speed according to how far from junction
00892               // calculate speed according to distance left
00893               //float speed = 0.8;
00894               //if(jdist > 5.0 && jdist > 0.0)
00895               //  speed = speed - .6*(5.0 - jdist)/5.0;
00896               //              itsTransSpeed = speed;
00897 
00898               itsTurnAngle = 0.0;
00899             }
00900           else
00901             {
00902               // get the next edge
00903               rutz::shared_ptr<Edge> e2 =
00904                 itsTopologicalMap->getEdge(itsMoves[1]);
00905 
00906               // calculate the degree amount for the turn as well
00907               float angle  = itsTopologicalMap->getAngle(e1,e2);
00908               float dangle = angle*180.0/M_PI;
00909               LINFO("ANGLE: %f or %f", angle, dangle);
00910 
00911               itsTurnAngle   = angle;
00912               double addRot  = 0.0;
00913               double fdangle = fabs(dangle);
00914 
00915               // don't add rotation if the angle is less than 30 degrees
00916               // keep going with the visual feedback
00917               if(fdangle < 30.0)
00918                 addRot = 0.0;
00919               // else if within  30 to 150 (to the right)
00920               else if(dangle >  30.0 && dangle <  150.0)
00921                 addRot = -0.3;
00922               // else if going hard right
00923               else if(dangle >= 150.0)
00924                 addRot = -0.6;
00925               // else if within  -30 to -150 (to the left)
00926               else if(dangle < -30.0 && dangle > -150.0)
00927                 addRot = 0.3;
00928               // else if going hard left
00929               else if(dangle <= -150.0)
00930                 addRot = 0.6;
00931 
00932               LINFO("\n\n\naddRot: %f dangle: %f\n\n\n\n", addRot, dangle);
00933 
00934               // IMPORTANT: need more visual feedback here!!!
00935               // check with the inputs that are matched
00936               // see if they are from the next segment
00937 
00938               // MOTOR COMMAND
00939               itsTransSpeed = 0.8;
00940               itsRotSpeed  += addRot;
00941 
00942               nearJunction = true;
00943             }
00944         }
00945     }
00946 
00947   return nearJunction;
00948 
00949   // QUESTION: how do we infuse this with other motor command
00950 
00951   // train gist for distance to junction
00952   // -> recognizing intersection
00953 
00954   // NOTE: put all these information to the display
00955 }
00956 
00957 // ######################################################################
00958 // The main function for recovery
00959 void GistSal_Navigation::recover(bool foundSomething)
00960 {
00961   itsTurnAngle    = INVALID_ANGLE;
00962   itsJunctionDist = INVALID_DISTANCE;
00963 
00964   // pan around
00965   itsTransSpeed = 0.0;
00966 
00967   //uint64 time = itsLastFoundTimer.get();
00968   //if(((time/8000000)%2) == 1)
00969   //itsRotSpeed   = -0.45;
00970   //else
00971 
00972   if(foundSomething && itsReverseCount != 0)
00973     {
00974       itsRotSpeed = 0.0;
00975       if(itsReverseCount > 0) itsReverseCount--;
00976     }
00977   else if(foundSomething || itsReverseCount > 0)
00978     {
00979       itsRotSpeed = -0.6;
00980 
00981       itsReverseCount++;
00982       if(itsReverseCount > REVERSE_COUNT_MAX)
00983         itsReverseCount = 0;
00984     }
00985   else
00986     itsRotSpeed   = 0.6; // spin LEFT
00987 }
00988 
00989 // ######################################################################
00990 // The main function of navigation
00991 void GistSal_Navigation::navigation()
00992 {
00993   // update motor command
00994   //updateMotorPID(itsTransSpeed, itsRotSpeed);
00995 
00996   // FIX !!!!!!!!!!!!!!!!!! BYPASS FOR NOW !!!!!!!!!!!!!!!!!!!!!!!!
00997   //updateMotor(itsCornerTransSpeed, itsCornerRotSpeed);
00998   updateMotor(itsTransSpeed, itsRotSpeed);
00999 }
01000 
01001 // ######################################################################
01002 void GistSal_Navigation::drawState()
01003 {
01004   uint w = itsProcImg.getWidth();
01005   uint h = itsProcImg.getHeight();
01006 
01007   itsDispImg.resize(5*w, 3*h, NO_INIT);
01008 
01009   for(uint i = 0; i < itsCurrLandmarkDBMatches.size(); i++)
01010     {
01011       //Image< PixRGB<byte> > mImg = itsMatchRes[i]->getMatchImage(1.0F);
01012       //inplacePaste(itsDispImg, mImg, Point2D<int>(w*i, 0));
01013 
01014       rutz::shared_ptr<LandmarkDBMatch> ldbm =
01015         itsCurrLandmarkDBMatches[i];
01016 
01017       rutz::shared_ptr<VisualObjectMatch> matchRes =
01018         ldbm->matchRes;
01019 
01020       Dims d(w,h);
01021       Point2D<int> objOffset1 = ldbm->voOffset;
01022       Point2D<int> objOffset2 = ldbm->dbOffset;
01023 
01024       bool isODmatch = (ldbm->vo ==  matchRes->getVoRef());
01025       bool isDOmatch = (ldbm->vo ==  matchRes->getVoTest());
01026 
01027       Image< PixRGB<byte> > result;
01028       if(isODmatch)
01029         {
01030           // LINFO("[%d %d]    O[%d %d wh: %d %d] D[%d %d wh: %d %d]",
01031           //       d.w(), d.h(),
01032           //       objOffset1.i, objOffset1.j,
01033           //       itsMatchRes[i]->getVoRef()->getImage().getWidth(),
01034           //       itsMatchRes[i]->getVoRef()->getImage().getHeight(),
01035           //       objOffset2.i, objOffset2.j,
01036           //       itsMatchRes[i]->getVoTest()->getImage().getWidth(),
01037           //       itsMatchRes[i]->getVoTest()->getImage().getHeight()  );
01038 
01039           result = matchRes->getMatchImage(d, objOffset1, objOffset2);
01040         }
01041       else if(isDOmatch)
01042         {
01043           // LINFO("[%d %d]2   O[%d %d wh: %d %d] D[%d %d wh: %d %d]",
01044           //       d.w(), d.h(),
01045           //       objOffset1.i, objOffset1.j,
01046           //       itsMatchRes[i]->getVoTest()->getImage().getWidth(),
01047           //       itsMatchRes[i]->getVoTest()->getImage().getHeight(),
01048           //       objOffset2.i, objOffset2.j,
01049           //       itsMatchRes[i]->getVoRef()->getImage().getWidth(),
01050           //       itsMatchRes[i]->getVoRef()->getImage().getHeight()  );
01051 
01052           result = matchRes->getMatchImage(d, objOffset2, objOffset1);
01053         }
01054       else{LFATAL("boom. Object neither ref nor tst."); }
01055 
01056       std::string ntext(sformat("[%d]", i));
01057       if(isODmatch) ntext += std::string("OD");
01058       else ntext += std::string("OD");
01059       inplacePaste(itsDispImg, result, Point2D<int>(i*w,0));
01060       writeText(itsDispImg, Point2D<int>(w*i,0), ntext.c_str());
01061 
01062       SIFTaffine aff = matchRes->getSIFTaffine();
01063       float theta, sx, sy, str;
01064       aff.decompose(theta, sx, sy, str);
01065       std::string ntext2(sformat("[%6.3f, %6.3f", sx, sy));
01066       writeText(itsDispImg, Point2D<int>(w*i,20), ntext2.c_str());
01067     }
01068 
01069   inplacePaste(itsDispImg, drawInfoImg(), Point2D<int>(0, 2*h));
01070 }
01071 
01072 // ######################################################################
01073 // display current heading information
01074 Image<PixRGB<byte> > GistSal_Navigation::drawInfoImg()
01075 {
01076   uint w = itsProcImg.getWidth();
01077   uint h = itsProcImg.getHeight();
01078 
01079   Image<PixRGB<byte> > dirImg(5*w, h,ZEROS);
01080 
01081   std::string text;
01082   if(itsDir == 0)     { text = sformat("Dir: |||  "); }
01083   else if(itsDir > 0) { text = sformat("Dir: -->  "); }
01084   else                { text = sformat("Dir: <--  "); }
01085 
01086   uint totalMatchSize = 0;
01087   uint nLDBMatch = itsCurrLandmarkDBMatches.size();
01088   for(uint i = 0; i < nLDBMatch; i++)
01089     totalMatchSize += itsCurrLandmarkDBMatches[i]->matchRes->size();
01090   text += sformat("#kp[%4d]", totalMatchSize);
01091 
01092   text += sformat("lDiff:[%8.3f] X:[%8.3f] Y:[%8.3f] ",
01093                   itsError, itsXError, itsYError);
01094 
01095   text += sformat("Trans[%8.3f] Rot[%8.3f]",
01096                   itsTransSpeed, itsRotSpeed);
01097 
01098   writeText(dirImg, Point2D<int>(0,0), text.c_str(),
01099             PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01100             SimpleFont::FIXED(8));
01101 
01102   std::string text2;
01103   its_Curr_Loc_mutex.lock();
01104   uint  currSegNum  = itsCurrentSegmentLocation;
01105   float currLenTrav = itsCurrentSegmentLengthTraveled;
01106   uint  desSegNum   = itsDesiredSegmentLocation;
01107   float desLenTrav  = itsDesiredSegmentLengthTraveled;
01108   its_Curr_Loc_mutex.unlock();
01109 
01110   text2 += sformat("C[%3d, %6.3f] -> ", currSegNum, currLenTrav);
01111   text2 += sformat("D[%3d, %6.3f]: ",  desSegNum,  desLenTrav);
01112   text2 += sformat("dist:[%8.3f]: ",  itsDistToGoal);
01113   text2 += sformat("M:[%"ZU"]: [", itsMoves.size());
01114   for(uint i = 0; i < itsMoves.size(); i++)
01115     text2 += sformat(" %d", itsMoves[i]);
01116 
01117   if(itsTurnAngle == INVALID_ANGLE)
01118     text2 += sformat("] tAng: \">< ");
01119   else
01120     text2 += sformat("] tAng: %7.3f ", itsTurnAngle*180.0/M_PI);
01121   text2 += sformat("jDist: %8.3f", itsJunctionDist);
01122 
01123   writeText(dirImg, Point2D<int>(0,20), text2.c_str(),
01124             PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01125             SimpleFont::FIXED(8));
01126 
01127   std::string text3;
01128   if(itsInGoal) text3 += sformat("IN GOAL     ");
01129   else          text3 += sformat("NOT IN GOAL ");
01130   uint64 tim =  itsLastFoundTimer.get();
01131   float lftime = tim/1000.0;
01132   text3 += sformat("%f ", lftime);
01133   if(tim > LOST_TIME_LIMIT)
01134     text3 += sformat("- OVER LOST TIME LIMIT. ");
01135   text3 += sformat("STATUS: %3d", itsCornerProcStatus);
01136 
01137   writeText(dirImg, Point2D<int>(0,40), text3.c_str(),
01138             PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01139             SimpleFont::FIXED(8));
01140 
01141   return dirImg;
01142 }
01143 
01144 // ######################################################################
01145 void GistSal_Navigation::updateMotorPID(double tran, double rot,double error)
01146 {
01147   error/=100.0;
01148   if(itsDir == 1)
01149     error *= -1.0;
01150   double pTerm,iTerm,dTerm;
01151   pTerm = itsPGain * error;
01152   itsIState += error;
01153   if(itsIState > IMAX)
01154     itsIState = IMAX;
01155   else if(itsIState < IMIN)
01156     itsIState = IMIN;
01157   iTerm = itsIGain * itsIState;
01158   dTerm = itsDGain * (rot - itsDState);
01159   itsDState = rot;
01160   double pid = pTerm + iTerm - dTerm;
01161 
01162   LINFO("P[%1.2f] I[%1.2f] D[%1.2f], Istate[%1.2f] DState[%1.2f]",
01163         pTerm,iTerm,dTerm,itsIState,itsDState);
01164   LINFO("pid[%1.2f],rot[%1.2f]",pid,rot);
01165   updateMotor(tran,pid);
01166 }
01167 
01168 // ######################################################################
01169 void GistSal_Navigation::updateMotor(double tran, double rot)
01170 {
01171   BeobotEvents::MotorRequestPtr msg = new BeobotEvents::MotorRequest;
01172   msg->transVel = tran;
01173   msg->rotVel   = rot;
01174   this->publish("MotorRequestTopic", msg);
01175   LINFO("[%d] Publish motor request Trans %f Rotation %f",
01176         itsPrevProcImgID,tran,rot);
01177 }
01178 
01179 // ######################################################################
01180 /* So things look consistent in everyone's emacs... */
01181 /* Local Variables: */
01182 /* indent-tabs-mode: nil */
01183 /* End: */
Generated on Sun May 8 08:41:19 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3