00001 /*!@file Robots2/Beobot2/Navigation/GistSal_Navigation/CornerNavigation.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/CornerNavigation.C 00034 // $ $Id: CornerNavigation.C 13084 2010-03-30 02:42:00Z kai $ 00035 // 00036 ////////////////////////////////////////////////////////////////////////// 00037 00038 #include "Robots/Beobot2/Navigation/GistSal_Navigation/CornerNavigation.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 FOLDER "../data/corner" 00064 #define DBNAME "HNB" 00065 #define IMAGE_PREFIX "image_0000000000" 00066 #define IMAX 1.0 00067 #define IMIN 0.0 00068 00069 #define C_PROCEDURE_INACTIVE 0 00070 #define C_PROCEDURE_ACTIVE 1 00071 #define C_PROCEDURE_CONCLUDING 2 00072 00073 const ModelOptionCateg MOC_CornerNavigation = 00074 { MOC_SORTPRI_3, "QT Navigation Related Options" }; 00075 const ModelOptionDef OPT_RealCamera = 00076 { MODOPT_ARG(bool), "RealCamera", &MOC_CornerNavigation, OPTEXP_CORE, 00077 "Do we want use real camera from BeoCamera? Default will load from image files.", 00078 "camera", '\0', "true | false", "false" }; 00079 00080 // ###################################################################### 00081 CornerNavigation::CornerNavigation(OptionManager& mgr, 00082 const std::string& descrName, 00083 const std::string& tagName) : 00084 RobotBrainComponent(mgr, descrName, tagName), 00085 itsFftComputer(new GistEstimatorFFT(mgr)), 00086 itsOfs(new OutputFrameSeries(mgr)), 00087 itsMapImg(320,240,ZEROS), 00088 itsReplayDBnum(0), 00089 itsFfn(new FeedForwardNetwork()), 00090 itsTimer(1000000), 00091 itsCurrImgID(-1), 00092 itsPrevProcImgID(-1), 00093 itsTeachImgID(0), 00094 itsReplayImgID(0), 00095 itsTransSpeed(0.0), 00096 itsRotSpeed(0.0), 00097 itsDirVector(0.0), 00098 itsDir(0), 00099 itsMilestoneErr(999.99), 00100 itsFalseErrRate(0.0), 00101 itsDirCount(0), 00102 itsPosition(0.0, 0.0, 0.0), 00103 itsError(0.0, 0.0, 0.0), 00104 itsRealCamera(&OPT_RealCamera, this, 0), 00105 itsEstop(true), 00106 itsIState(0.0), 00107 itsDState(0.0), 00108 itsPGain(1.0), 00109 itsIGain(0.01), 00110 itsDGain(0.0) 00111 { 00112 addSubComponent(itsOfs); 00113 00114 itsStatus = C_PROCEDURE_INACTIVE; 00115 // load the teach Visual Object Database 00116 openDB(sformat("%s/%s/%s.conf",FOLDER,DBNAME,DBNAME)); 00117 } 00118 00119 // ###################################################################### 00120 void CornerNavigation::openDB(const std::string& path) 00121 { 00122 FILE *dbconf = fopen(path.c_str(),"r"); 00123 if(dbconf == NULL){ 00124 LFATAL("Can not open file: %s",path.c_str()); 00125 }else{ 00126 char line[512]; 00127 while(fgets(line,sizeof line,dbconf)!= NULL) 00128 { 00129 //Skip the line start at# 00130 if(line[0] != '#') 00131 { 00132 char subdb[256]; 00133 char type;//Teach or Replay 00134 int start,end; 00135 int ret = sscanf(line,"%s %d %d %c",subdb,&start,&end,&type); 00136 if(ret == 4){ 00137 LINFO("Got [%s],start[%d],end[%d],type[%c]",subdb,start,end,type); 00138 cornerDB tmpDB; 00139 tmpDB.path = sformat("%s/%s/%s/%s",FOLDER,DBNAME,subdb,IMAGE_PREFIX); 00140 tmpDB.start = start; 00141 tmpDB.end = end; 00142 tmpDB.type = type; 00143 loadDB(tmpDB); 00144 00145 } 00146 } 00147 00148 } 00149 00150 00151 } 00152 } 00153 00154 // ###################################################################### 00155 void CornerNavigation::initFFN() 00156 { } 00157 00158 // ###################################################################### 00159 CornerNavigation::~CornerNavigation() 00160 { } 00161 00162 // ###################################################################### 00163 void CornerNavigation::start1() 00164 { 00165 //if it runing in simulation 00166 if(!itsRealCamera.getVal()) 00167 itsDBnum = 0; 00168 else // corner location to turn: initially set none 00169 itsDBnum = -1; 00170 LINFO("itsDBNUM: %d", itsDBnum); 00171 } 00172 00173 // ###################################################################### 00174 void CornerNavigation::registerTopics() 00175 { 00176 // subscribe to all sensor data 00177 //this->registerSubscription("CameraMessageTopic"); 00178 this->registerSubscription("GistSalMessageTopic"); 00179 this->registerSubscription("MotorMessageTopic"); 00180 this->registerSubscription("CornerLocationMessageTopic"); 00181 00182 this->registerPublisher("CornerMotorRequestTopic"); 00183 //this->registerPublisher("MotorRequestTopic"); 00184 } 00185 00186 // ###################################################################### 00187 void CornerNavigation::evolve() 00188 { 00189 // check if the current image is updated 00190 its_Curr_Img_mutex.lock(); 00191 bool newImageFlag = (itsPrevProcImgID < itsCurrImgID); 00192 its_Curr_Img_mutex.unlock(); 00193 00194 // if simulation 00195 if(!itsRealCamera.getVal()) 00196 { 00197 navigation(); 00198 } 00199 00200 // if real camera 00201 else 00202 { 00203 // if so, process 00204 if(newImageFlag) 00205 { 00206 // get the input image 00207 itsTimer.reset(); 00208 its_Curr_Img_mutex.lock(); 00209 itsProcImg = itsCurrImg; 00210 itsPrevProcImgID = itsCurrImgID; 00211 its_Curr_Img_mutex.unlock(); 00212 00213 // check if we are turning a corner 00214 its_Corner_Loc_mutex.lock(); 00215 int dbNum = itsDBnum; 00216 int status = itsStatus; 00217 its_Corner_Loc_mutex.unlock(); 00218 00219 // if so navigate 00220 if(dbNum != -1 && status != C_PROCEDURE_INACTIVE) 00221 { 00222 LINFO("size: %"ZU, itsVisualObjectDBs.size() ); 00223 int cornerSize = itsVisualObjectDBs[dbNum].vdb->numObjects(); 00224 00225 if(itsTeachImgID >= cornerSize) 00226 { 00227 itsStatus = C_PROCEDURE_INACTIVE; 00228 } 00229 else if(itsTeachImgID > int(cornerSize*0.9)) 00230 { 00231 itsStatus = C_PROCEDURE_CONCLUDING; 00232 } 00233 else 00234 { 00235 itsStatus = C_PROCEDURE_ACTIVE; 00236 } 00237 LINFO("5"); 00238 navigation(); 00239 LINFO("6"); 00240 } 00241 } 00242 } 00243 00244 if(!itsRealCamera.getVal() || newImageFlag) 00245 { 00246 drawState(); 00247 itsOfs->writeRGB(itsDispImg, "CornerNav", 00248 FrameInfo("CornerNav",SRC_POS)); 00249 } 00250 00251 // if(itsEstop == false) 00252 // { 00253 // Raster::waitForKey(); 00254 // itsEstop = true; 00255 // } 00256 } 00257 00258 // ###################################################################### 00259 void CornerNavigation::recovery() 00260 { 00261 int trytimes = 0; 00262 do{ 00263 loadFrame(); 00264 std::vector< rutz::shared_ptr<VisualObjectMatch> > matches; 00265 00266 its_Corner_Loc_mutex.lock(); 00267 int dbNum = itsDBnum; 00268 its_Corner_Loc_mutex.unlock(); 00269 00270 int nmatches = 00271 itsVisualObjectDBs[dbNum].vdb->getObjectMatches 00272 (itsReplayVo,matches,VOMA_SIMPLE, 00273 10U, 00274 0.5F, //keypoint distance score default 0.5F 00275 0.5F, //affine distance score default 0.5F 00276 1.0F, //minscore default 1.0F 00277 4U, //min # of keypoint match 00278 100U, //keypoint selection thershold 00279 false //sort by preattentive 00280 ); 00281 std::string objName; 00282 int closestFrame = 999999999; 00283 int tmpFrameID = itsTeachImgID; 00284 LINFO("Searching For Nearest Key Frame in the Database"); 00285 if (nmatches > 0 ) 00286 { 00287 for(int i = 0; i < nmatches; i++) 00288 { 00289 LINFO("Found [%d] frames matches Frame[%d]", nmatches, i); 00290 00291 // so that we will have a ref to the last matches obj 00292 rutz::shared_ptr<VisualObject> obj; 00293 rutz::shared_ptr<VisualObjectMatch> vom; 00294 vom = matches[i]; 00295 obj = vom->getVoTest(); 00296 // score = vom->getScore(); 00297 // nkeyp = vom->size(); 00298 // avgScore = vom->getKeypointAvgDist(); 00299 // affineAvgDist = vom->getAffineAvgDist(); 00300 objName = obj->getName(); 00301 int tmpID = atoi(objName.c_str()); 00302 int dx = tmpID - itsTeachImgID; 00303 00304 LINFO("Dist. from current teach frame[%d]=======new ID[%d]", 00305 dx,tmpID); 00306 // find closest frame that matches 00307 //FIXX: we don't consider the match rate yet. 00308 if(dx < closestFrame) 00309 { 00310 closestFrame = dx; 00311 tmpFrameID = tmpID; 00312 } 00313 } 00314 LINFO("Recovery Found:TID[%d]RID[%d] Match[%d]", 00315 itsTeachImgID,itsReplayImgID,tmpFrameID); 00316 itsTeachImgID = tmpFrameID; 00317 itsEstop = true; 00318 itsTransSpeed = 0.8; 00319 loadFrame(); 00320 computeSIFT(); 00321 } 00322 else 00323 { 00324 LINFO("No Match Point,Try get new frame and try again"); 00325 loadFrame(); 00326 trytimes++; 00327 } 00328 } 00329 while(!itsEstop && trytimes < 10); 00330 } 00331 00332 // ###################################################################### 00333 // The main function of navigation 00334 void CornerNavigation::navigation() 00335 { 00336 // load key frame from database 00337 // compute SIFT keypoint and matching 00338 loadFrame(); 00339 //computeSIFT(); 00340 00341 // apply QT algo for direction 00342 double error = computeDirection2(itsTeachImgID); 00343 00344 //When the mean error and stderr have too much difference 00345 //Then ignore the SIFT bogus match 00346 if(error != 0.0 && itsMatchList->size()!=0 && 00347 (itsMatchList->checkSIFTaffine() || itsFalseErrRate > 1.0) 00348 ){ 00349 updateMotor(itsTransSpeed, itsRotSpeed,itsStatus); 00350 updateKeyframe(error); 00351 itsEstop = true; 00352 00353 // update keyframe when reaching milestone 00354 updateKeyframe(error); 00355 itsEstop = true; 00356 } 00357 00358 // when the mean error and stderr have too much difference 00359 // then ignore the SIFT bogus match 00360 else 00361 { 00362 itsEstop = false; 00363 LINFO("lost matching; start recover mechanism"); 00364 itsTransSpeed = 0.0; 00365 itsRotSpeed = 0.0; 00366 00367 if(itsRealCamera.getVal()) 00368 { 00369 its_Corner_Loc_mutex.lock(); 00370 itsStatus = C_PROCEDURE_INACTIVE; 00371 int status = itsStatus; 00372 itsDBnum = -1; 00373 its_Corner_Loc_mutex.unlock(); 00374 updateMotor(itsTransSpeed, itsRotSpeed, status); 00375 }else{ 00376 updateMotor(itsTransSpeed, itsRotSpeed, 0); 00377 //recovery(); 00378 //itsEstop = true; 00379 } 00380 } 00381 } 00382 00383 // ###################################################################### 00384 void CornerNavigation::loadDB(cornerDB db) 00385 { 00386 00387 //std::string path = sformat("%s/%s.sift",db.path.c_str(),IMAGE_PREFIX); 00388 00389 // load the actual VisualObjectDatabase but don't load images 00390 db.vdb.reset(new VisualObjectDB()); 00391 bool rt = db.vdb->loadFrom(sformat("%s.sift",db.path.c_str()),false); 00392 if(rt) 00393 { 00394 LINFO("Load SIFT Database"); 00395 itsVisualObjectDBs.push_back(db); 00396 00397 //Check if db is use for replay 00398 if(db.type =='R') 00399 itsReplayDBnum = int(itsVisualObjectDBs.size())-1; 00400 } 00401 else 00402 { 00403 LINFO("SIFT Database %s not exist, create new", db.path.c_str()); 00404 saveDB(db.start,db.end,db.path.c_str()); 00405 } 00406 } 00407 // ###################################################################### 00408 void CornerNavigation::saveDB(int start,int end,const std::string& path) 00409 { 00410 cornerDB tmp; 00411 tmp.vdb.reset(new VisualObjectDB()); 00412 for(int i = start; i < end; i++) 00413 { 00414 itsTimer.reset(); 00415 std::string teachFileName(sformat("%s%05d.ppm",path.c_str(),i)); 00416 Image< PixRGB<byte> > img = Raster::ReadRGB(teachFileName); 00417 rutz::shared_ptr<VisualObject> vo1 00418 (new VisualObject(sformat("%d",i), 00419 sformat("%s%05d.png",path.c_str(),i), 00420 rescale(img,img.getWidth()/2, img.getHeight()/2))); 00421 tmp.vdb->addObject(vo1); 00422 LINFO("Time[%f] Compute SIFT for Frame %d/%d", 00423 itsTimer.get()/1000.0,i-start+1,end-start+1); 00424 } 00425 std::string teachDB(sformat("%s.sift",path.c_str())); 00426 // itsVisualObjectDB->setName(); 00427 tmp.vdb->saveTo(teachDB); 00428 } 00429 00430 // ###################################################################### 00431 void CornerNavigation::loadFrame() 00432 { 00433 // load teach image data 00434 itsTimer.reset(); 00435 00436 its_Corner_Loc_mutex.lock(); 00437 int dbNum = itsDBnum; 00438 its_Corner_Loc_mutex.unlock(); 00439 00440 //Check the size of subdb 00441 if(itsTeachImgID < (int)itsVisualObjectDBs[dbNum].vdb->numObjects()) 00442 { 00443 itsTeachVo = itsVisualObjectDBs[dbNum].vdb->getObject(itsTeachImgID); 00444 itsTeachImg = itsTeachVo->getImage(); 00445 } 00446 else 00447 { 00448 LINFO("=======Teach DB End====="); 00449 itsTeachImgID = 0; 00450 //itsReplayImgID = 0; 00451 } 00452 00453 LINFO("Time for Computing SIFT on TeachImg %f", 00454 itsTimer.get()/1000.0); 00455 itsTimer.reset(); 00456 00457 // Load Current Replay image data 00458 00459 // running from image files 00460 if(!itsRealCamera.getVal()) 00461 { 00462 if(itsReplayImgID < (int)itsVisualObjectDBs[itsReplayDBnum].vdb->numObjects()) 00463 { 00464 if(itsReplayImgID <(int)itsVisualObjectDBs[itsReplayDBnum].vdb->numObjects()) 00465 { 00466 itsReplayVo = itsVisualObjectDBs[itsReplayDBnum].vdb-> getObject(itsReplayImgID); 00467 itsReplayImg = itsReplayVo->getImage(); 00468 itsProcImg = itsReplayImg; 00469 itsReplayImgID++; 00470 } 00471 } 00472 } 00473 00474 // running from real camera 00475 else 00476 { 00477 itsReplayImg = itsProcImg; 00478 itsReplayImgID = itsPrevProcImgID; 00479 rutz::shared_ptr<VisualObject> vo2 (new VisualObject ("1", "", itsReplayImg)); 00480 itsReplayVo = vo2; 00481 } 00482 LINFO("Time for Computing SIFT on ReplayImg %f", 00483 itsTimer.get()/1000.0); 00484 } 00485 00486 // ###################################################################### 00487 bool CornerNavigation::computeSIFT() 00488 { 00489 itsTimer.reset(); 00490 VisualObjectMatchAlgo voma(VOMA_SIMPLE); 00491 itsMatchList.reset(new VisualObjectMatch(itsTeachVo, itsReplayVo, voma)); 00492 LINFO("========================================="); 00493 //LINFO("Found %u matches between Teach and Replay", match.size()); 00494 00495 // let's prune the matches: 00496 //uint np = 00497 itsMatchList->prune(); 00498 //LINFO("Pruned %u outlier matches.", np); 00499 LINFO("Match size now is %u ", itsMatchList->size()); 00500 00501 // show our final affine transform: 00502 // std::cerr<<match.getSIFTaffine(); 00503 00504 //LINFO("getKeypointAvgDist = %f", match.getKeypointAvgDist()); 00505 //LINFO("getAffineAvgDist = %f", match.getAffineAvgDist()); 00506 //LINFO("getScore = %f", match.getScore()); 00507 if (itsMatchList->checkSIFTaffine() == false) 00508 LINFO("### Affine is too weird -- BOGUS MATCH"); 00509 00510 // record the time 00511 LINFO("Time for Matching SIFT %f",itsTimer.get()/1000.0); 00512 00513 // if the sift point is valid, return true 00514 return (itsMatchList->size()!=0 && itsMatchList->checkSIFTaffine()); 00515 } 00516 00517 // ###################################################################### 00518 double CornerNavigation::computeDirection2(int teachID) 00519 { 00520 int dirF = 0,dirL = 0,dirR = 0; 00521 rutz::shared_ptr<VisualObjectMatch> bestMatch; 00522 int bestMatchSize = -1; 00523 int bestID = 0; 00524 LINFO("Direction2 Start"); 00525 00526 // boundary condition 00527 if((teachID-2) < 0) teachID = 2; 00528 00529 // looking 10 frame ahead to find best match frame 00530 for(int id = teachID-2; id < teachID+10; id++) 00531 { 00532 00533 its_Corner_Loc_mutex.lock(); 00534 int dbNum = itsDBnum; 00535 its_Corner_Loc_mutex.unlock(); 00536 00537 //std::string teachFileName(sformat("%s%05d.ppm",TEACH_FOLDER,id)); 00538 rutz::shared_ptr<VisualObject> vo1; 00539 if(id < (int)itsVisualObjectDBs[dbNum].vdb->numObjects()){ 00540 vo1 = itsVisualObjectDBs[dbNum].vdb->getObject(id); 00541 } 00542 else{ 00543 LINFO("DB END"); 00544 return 0.0; 00545 } 00546 VisualObjectMatchAlgo voma(VOMA_SIMPLE); 00547 rutz::shared_ptr<VisualObjectMatch> 00548 match(new VisualObjectMatch(vo1, itsReplayVo, voma)); 00549 match->prune(); 00550 00551 // ========================= 00552 // find the best Keyframe 00553 float theta = 2.0, sx = 2.0, sy = 2.0, str = 0; 00554 00555 // check if the match is valid 00556 if (match->checkSIFTaffine()) 00557 { 00558 match->getSIFTaffine().decompose(theta, sx, sy, str); 00559 } 00560 int msize = match->size(); 00561 if((msize > bestMatchSize && sx < 1.0 && sy < 1.0) || 00562 (bestMatchSize == -1 && id==teachID)) 00563 { 00564 bestMatchSize = msize; 00565 bestMatch = match; 00566 bestID = id; 00567 } 00568 LDEBUG("Best Match Size %d,",bestMatchSize); 00569 itsMatchList = bestMatch; 00570 00571 int dirGain = 1; if(id == bestID) dirGain = 2; 00572 00573 // compute the direction and find mean of error 00574 for (int i = 0; i < msize; i ++) 00575 { 00576 rutz::shared_ptr<Keypoint> refk = match->getKeypointMatch(i).refkp; 00577 rutz::shared_ptr<Keypoint> tstk = match->getKeypointMatch(i).tstkp; 00578 00579 double ut = tstk->getX() - itsReplayVo->getImage().getWidth()/2; 00580 double ud = refk->getX() - itsTeachVo->getImage().getWidth()/2; 00581 00582 if(ut > 0.0 && ud < 0.0) 00583 { 00584 dirR += dirGain; 00585 } 00586 else if(ut < 0.0 && ud > 0.0) 00587 { 00588 dirL += dirGain; 00589 } 00590 else if(ut > 0.0 && ut > ud) 00591 { 00592 dirR += dirGain; 00593 } 00594 else if(ut < 0.0 && ut < ud) 00595 { 00596 dirL += dirGain; 00597 } 00598 else 00599 { 00600 dirF +=dirGain; 00601 } 00602 } 00603 }//end for 00604 00605 //========================= 00606 double stdx = 0.0,stdy = 0.0; 00607 double avgdx = 0.0,avgdy = 0.0; 00608 00609 // compute the std error 00610 for (int i = 0; i < bestMatchSize; i ++) 00611 { 00612 // LINFO("Loading best match point %d",i); 00613 rutz::shared_ptr<Keypoint> refk = bestMatch->getKeypointMatch(i).refkp; 00614 rutz::shared_ptr<Keypoint> tstk = bestMatch->getKeypointMatch(i).tstkp; 00615 double dx = fabs(tstk->getX() - refk->getX())+ 0.000001; 00616 stdx += dx * dx; 00617 avgdx+= dx; 00618 00619 double dy = fabs(tstk->getY() - refk->getY())+ 0.000001; 00620 stdy += dy * dy; 00621 avgdy+= dy; 00622 LDEBUG("Error! i=[%d] BestMatchSize[%d] " 00623 "avgdx[%f] avgdy[%f],dx[%f], dy[%f]", 00624 i,bestMatchSize,avgdx,avgdy,dx,dy); 00625 } 00626 if(bestMatchSize != 0) 00627 { 00628 avgdx/= bestMatchSize; 00629 avgdy/= bestMatchSize; 00630 stdx -= (avgdx*avgdx); 00631 stdy -= (avgdy*avgdy); 00632 stdx /= bestMatchSize; 00633 stdx = sqrt(stdx); 00634 stdy /= bestMatchSize; 00635 stdy = sqrt(stdy); 00636 LDEBUG("Error! BestMatchSize[%d] avgdx[%f] avgdy[%f]", 00637 bestMatchSize,avgdx,avgdy); 00638 } 00639 else 00640 { 00641 avgdx = 0; 00642 avgdy = 0; 00643 stdx = 0; 00644 stdy = 0; 00645 } 00646 00647 LDEBUG("stdx %f stdy %f",stdx,stdy); 00648 uint stdcount = 0; 00649 double newAvgX = 0.0,newAvgY = 0.0; 00650 00651 // Pick one stddev error as the new error data 00652 for (int i = 0; i < bestMatchSize; i ++) 00653 { 00654 rutz::shared_ptr<Keypoint> refk = bestMatch->getKeypointMatch(i).refkp; 00655 rutz::shared_ptr<Keypoint> tstk = bestMatch->getKeypointMatch(i).tstkp; 00656 double dx = fabs(tstk->getX() - refk->getX())+ 0.000001; 00657 double dy = fabs(tstk->getY() - refk->getY())+ 0.000001 ; 00658 double ddx = fabs(dx - avgdx); 00659 double ddy = fabs(dy - avgdy); 00660 00661 if(ddx < stdx && ddy < stdy) 00662 { 00663 newAvgX += dx; 00664 newAvgY += dy; 00665 stdcount++; 00666 } 00667 } 00668 00669 if(stdcount != 0) 00670 { 00671 newAvgX/= stdcount; 00672 newAvgY/= stdcount; 00673 } 00674 double newAvgerr = sqrt(newAvgX*newAvgX + newAvgY*newAvgY); 00675 double avgerr = sqrt(avgdx*avgdx + avgdy*avgdy); 00676 double angle = (newAvgX*(16.0/33.0)); 00677 itsError.x = newAvgX; 00678 itsError.y = newAvgY; 00679 itsError.z = newAvgerr; 00680 //FIXXX 00681 if(newAvgerr == 0.0) 00682 { 00683 //Raster::waitForKey(); 00684 newAvgerr = avgerr; 00685 itsFalseErrRate = 0; 00686 } 00687 else 00688 { 00689 itsFalseErrRate = avgerr/newAvgerr; 00690 } 00691 LDEBUG("False Error Rate %1.3f",itsFalseErrRate); 00692 if(itsFalseErrRate == 0.0) 00693 { 00694 LDEBUG("Error!!!! stdcount[%d] avgerr[%f]", 00695 stdcount,avgerr); 00696 LDEBUG("Error!!!! bestMatchSize[%d] stdx[%f] stdy[%f]", 00697 bestMatchSize,stdx,stdy); 00698 //Raster::waitForKey(); 00699 } 00700 00701 // reset target keyframe if we found better match 00702 if(bestID > itsTeachImgID && newAvgerr < 10.0) 00703 itsTeachImgID = bestID; 00704 00705 // compute the forward speed based on scale 00706 if (bestMatch->checkSIFTaffine())//Check if the match is valid 00707 { 00708 float theta = 0.0 , sx = 0.0, sy = 0.0, str = 0.0 ; 00709 bestMatch->getSIFTaffine().decompose(theta, sx, sy, str); 00710 //if the size difference is large(sx/sy << 1.0),we can speed up 00711 double rms = 1.0 -(sqrt(sx*sx+sy*sy)/sqrt(2)); 00712 00713 double gain = 1.0; 00714 if(rms > 0.0) 00715 itsTransSpeed = 0.8 + rms * gain; 00716 if(itsTransSpeed > 1.0)itsTransSpeed = 1.0; 00717 if(itsTransSpeed < 0.0)itsTransSpeed = 0.0; 00718 } 00719 else 00720 { 00721 itsTransSpeed = 0.8; 00722 } 00723 00724 // compute turning speed 00725 if(dirF >= abs(dirR + dirL)) 00726 { 00727 updatePosition(0); 00728 itsRotSpeed = 0.4; 00729 if(itsDir == 0)//same heading since last time 00730 { 00731 itsDirCount++; 00732 } 00733 else 00734 { 00735 itsDirCount = 0;//reset direction count 00736 itsDir = 0;//reset direction 00737 } 00738 } 00739 else if(dirR > dirL) 00740 { 00741 updatePosition(angle); 00742 //Average the speed 00743 itsRotSpeed -= newAvgX/100.0; 00744 itsRotSpeed /= 2.0; 00745 if(itsDir == 1)//same heading since last time 00746 { 00747 itsDirCount++; 00748 } 00749 else 00750 { 00751 itsDirCount = 0;//reset direction count 00752 itsDir = 1;//reset direction 00753 } 00754 } 00755 else 00756 { 00757 updatePosition(-1*angle); 00758 //Average the speed 00759 itsRotSpeed += newAvgX/100.0+1.0; 00760 itsRotSpeed /= 2.0; 00761 if(itsDir == -1)//same heading since last time 00762 { 00763 itsDirCount++; 00764 }else{ 00765 itsDirCount = 0;//reset direction count 00766 itsDir = -1;//reset direction 00767 } 00768 } 00769 return newAvgerr; 00770 } 00771 00772 // ###################################################################### 00773 double CornerNavigation::computeDirection() 00774 { 00775 itsTimer.reset(); 00776 int dirF = 0,dirL = 0,dirR = 0; 00777 double avgdx = 0.0,avgdy = 0.0; 00778 uint msize = itsMatchList->size(); 00779 00780 // compute the direction and find mean of error 00781 for (uint i = 0; i < msize; i ++) 00782 { 00783 rutz::shared_ptr<Keypoint> refk = 00784 itsMatchList->getKeypointMatch(i).refkp; 00785 rutz::shared_ptr<Keypoint> tstk = 00786 itsMatchList->getKeypointMatch(i).tstkp; 00787 00788 double ut = tstk->getX() - itsReplayVo->getImage().getWidth()/2; 00789 double ud = refk->getX() - itsTeachVo->getImage().getWidth()/2; 00790 double dx = fabs(ut - ud); 00791 double dy = fabs(tstk->getY() - refk->getY()); 00792 avgdx += dx; 00793 avgdy += dy; 00794 std::string dir; 00795 00796 if(ut > 0.0 && ud < 0.0) 00797 { 00798 dir = std::string("RIGHT"); 00799 dirR ++; 00800 } 00801 else if(ut < 0.0 && ud > 0.0) 00802 { 00803 dir = std::string("LEFT"); 00804 dirL ++; 00805 } 00806 else if(ut > 0.0 && ut > ud ) 00807 { 00808 dir = std::string("RIGHT"); 00809 dirR ++; 00810 } 00811 else if(ut < 0.0 && ut < ud) 00812 { 00813 dir = std::string("LEFT"); 00814 dirL ++; 00815 } 00816 else 00817 { 00818 dir = std::string("Forward"); 00819 dirF ++; 00820 } 00821 LDEBUG("MatchPoint[%d] Teach(%f,%f) Replay(%f,%f), " 00822 "ud:[%f],ut:[%f],dx:[%f],dy:[%f] Turn %s", 00823 i, 00824 (refk->getX()), 00825 (refk->getY()), 00826 (tstk->getX()), 00827 (tstk->getY()), 00828 ud,ut,dx,dy,dir.c_str() 00829 ); 00830 } 00831 avgdx/= msize; 00832 avgdy/= msize; 00833 double stdx = 0.0,stdy = 0.0; 00834 00835 // compute the std error 00836 for (uint i = 0; i < msize; i ++) 00837 { 00838 rutz::shared_ptr<Keypoint> refk = 00839 itsMatchList->getKeypointMatch(i).refkp; 00840 rutz::shared_ptr<Keypoint> tstk = 00841 itsMatchList->getKeypointMatch(i).tstkp; 00842 double ddx = fabs(tstk->getX() - refk->getX()) - avgdx; 00843 stdx += ddx * ddx; 00844 double ddy = fabs(tstk->getY() - refk->getY()) - avgdy; 00845 stdy += ddy * ddy; 00846 } 00847 stdx /= msize; 00848 //stdx = sqrt(stdx); 00849 stdy /= msize; 00850 //stdy = sqrt(stdy); 00851 uint stdcount = 0; 00852 double newAvgX = 0.0,newAvgY = 0.0; 00853 00854 // pick one std error as the new error data 00855 for (uint i = 0; i < msize; i ++) 00856 { 00857 rutz::shared_ptr<Keypoint> refk = 00858 itsMatchList->getKeypointMatch(i).refkp; 00859 rutz::shared_ptr<Keypoint> tstk = 00860 itsMatchList->getKeypointMatch(i).tstkp; 00861 double dx = fabs(tstk->getX() - refk->getX()) ; 00862 double dy = fabs(tstk->getY() - refk->getY()) ; 00863 double ddx = fabs(dx - avgdx); 00864 double ddy = fabs(dy - avgdy); 00865 00866 if(ddx < sqrt(stdx) && ddy < sqrt(stdy)) 00867 { 00868 newAvgX += dx; 00869 newAvgY += dy; 00870 stdcount++; 00871 } 00872 } 00873 if(stdcount != 0) 00874 { 00875 newAvgX/=stdcount; 00876 newAvgY/=stdcount; 00877 } 00878 00879 double stdeverr = sqrt(stdx+stdy); 00880 double avgerr = sqrt(avgdx*avgdx + avgdy*avgdy); 00881 double newAvgerr = sqrt(newAvgX*newAvgX + newAvgY*newAvgY); 00882 double df = (itsTeachImgID - itsReplayImgID ); 00883 double angle = (newAvgX*(56.0/33.0))/df; 00884 //double angle = (newAvgX*(16.0/33.0)); 00885 LDEBUG("StdError[%f],StdErrX[%f],StdErrY[%f],Frame[%1.0f]", 00886 stdeverr,sqrt(stdx),sqrt(stdy),df); 00887 LDEBUG("AvgErr[%f],AvgX[%f],AvgY[%f]",avgerr,avgdx,avgdy); 00888 LDEBUG("StdAvgErr[%f],StdAvgX[%f],StdAvgY[%f]",newAvgerr,newAvgX,newAvgY); 00889 LDEBUG("Forward[%d], Right[%d], Left[%d] Angle[%f]",dirF,dirR,dirL,angle); 00890 itsError.x = newAvgX; 00891 itsError.y = newAvgY; 00892 itsError.z = newAvgerr; 00893 //FIXXX 00894 if(newAvgerr == 0.0) 00895 { 00896 //Raster::waitForKey(); 00897 newAvgerr = avgerr; 00898 } 00899 00900 itsFalseErrRate = avgerr/newAvgerr; 00901 00902 LINFO("Time for QT Navigation %f",itsTimer.get()/1000.0); 00903 return newAvgerr; 00904 } 00905 00906 // ###################################################################### 00907 void CornerNavigation::updateKeyframe(double error) 00908 { 00909 LINFO("itsMerror %f,new error %f", itsMilestoneErr, error); 00910 00911 // check if the match is valid 00912 if (itsMatchList->checkSIFTaffine()) 00913 { 00914 float theta, sx, sy, str; 00915 itsMatchList->getSIFTaffine().decompose(theta, sx, sy, str); 00916 LDEBUG("SIFT SCALE SX[%f] SY[%f] Theta[%f] Str[%f]",sx,sy,theta,str); 00917 00918 //Check the frame reach the milestone image or not 00919 //if(itsMilestoneErr > error && (sx <1.0&&sy <1.0)) 00920 // itsMilestoneErr = error; 00921 //else 00922 //{ 00923 //FIXXX: Hack,Single threshold will not work in all environment 00924 if(((sx >=0.9 && sy >=0.9) && error <50.0 ) && itsMatchList->size()>2){ 00925 itsMilestoneErr = 999.99; 00926 itsTeachImgID += 20;//FIXXX when turning sharp,slow down the forward rate 00927 LINFO("*********=========Switch Keyframe=========**********"); 00928 } 00929 //} 00930 } 00931 } 00932 00933 //Given Current image frame,it will try to find proper keyframe for navation 00934 // 00935 // ###################################################################### 00936 int CornerNavigation::computeEntropy() 00937 { 00938 return 1; 00939 } 00940 00941 // ###################################################################### 00942 void CornerNavigation::drawState() 00943 { 00944 its_Corner_Loc_mutex.lock(); 00945 int dbNum = itsDBnum; 00946 its_Corner_Loc_mutex.unlock(); 00947 00948 uint w = itsProcImg.getWidth()*2, h = itsProcImg.getHeight()*2; 00949 //uint w = 320, h = 240; 00950 LINFO("TeachImg w=%d,h=%d, dbNum: %d", w, h, dbNum); 00951 itsDispImg.resize(w*2, 3*h, NO_INIT); 00952 char buffer[128]; 00953 00954 // original image 00955 inplacePaste(itsDispImg, itsProcImg, Point2D<int>(0, 0)); 00956 00957 if(dbNum != -1) 00958 { 00959 // replay image 00960 Image< PixRGB<byte> > replayImg = rescale(itsReplayImg,w,h); 00961 sprintf(buffer,"img%5d",itsReplayImgID); 00962 writeText(replayImg, Point2D<int>(5,5), 00963 buffer, PixRGB<byte>(255,255,255), 00964 PixRGB<byte>(0,0,0),SimpleFont::FIXED(8)); 00965 inplacePaste(itsDispImg, replayImg, Point2D<int>(0, 2*h)); 00966 00967 // teach image 00968 Image< PixRGB<byte> > teachImg = rescale(itsTeachImg,w,h); 00969 sprintf(buffer,"img%5d",itsTeachImgID); 00970 writeText(teachImg, Point2D<int>(5,5), 00971 buffer, PixRGB<byte>(255,255,255), 00972 PixRGB<byte>(0,0,0), SimpleFont::FIXED(8)); 00973 inplacePaste(itsDispImg, teachImg, Point2D<int>(0, h)); 00974 00975 // teach keypoint image 00976 //inplacePaste(itsDispImg, itsTeachVo->getKeypointImage(1.0) , 00977 // Point2D<int>(w, h)); 00978 00979 // replay keypoint image 00980 //inplacePaste(itsDispImg, itsReplayVo->getKeypointImage(1.0), 00981 // Point2D<int>(w, h*1.5)); 00982 00983 // match image 00984 if(itsEstop) 00985 { 00986 Image< PixRGB<byte> > mimg = itsMatchList->getMatchImage(1.0F); 00987 LDEBUG("itsdispImg[%d,%d] mimg[%d,%d] pt[%d,%d]", 00988 itsDispImg.getWidth(), itsDispImg.getHeight(), 00989 mimg.getWidth(), mimg.getHeight(), int(w*1.5), h); 00990 00991 inplacePaste(itsDispImg, mimg, Point2D<int>(w*1.5, h)); 00992 } 00993 00994 // visual odometry 00995 double mapScale = 0.20; 00996 Point2D<int> drawPos 00997 (int(itsPosition.x*mapScale + itsMapImg.getWidth()/2), 00998 int(itsPosition.y*mapScale + itsMapImg.getHeight()/2)); 00999 if(itsMapImg.coordsOk(drawPos)) 01000 itsMapImg.setVal(drawPos, PixRGB<byte>(0,255,0)); 01001 inplacePaste(itsDispImg, itsMapImg, Point2D<int>(w, h*2)); 01002 } 01003 01004 // information 01005 inplacePaste(itsDispImg, drawInfoImg(), Point2D<int>(w, 0)); 01006 } 01007 01008 // ###################################################################### 01009 // Only for display current heading 01010 Image<PixRGB<byte> > CornerNavigation::drawInfoImg() 01011 { 01012 char buffer[128]; 01013 Image<PixRGB<byte> > dirImg(320,240,ZEROS); 01014 01015 its_Corner_Loc_mutex.lock(); 01016 int dbNum = itsDBnum; 01017 int status = itsStatus; 01018 its_Corner_Loc_mutex.unlock(); 01019 01020 // return if currently not turning 01021 sprintf(buffer, "DB# :[%d] Status:[%d]", dbNum, status); 01022 writeText(dirImg, Point2D<int>(10,70), 01023 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01024 SimpleFont::FIXED(8)); 01025 if (dbNum == -1) return dirImg; 01026 01027 // heading direction 01028 if(itsDir == 0) { sprintf(buffer, "||| "); } 01029 else if(itsDir > 0){ sprintf(buffer, "--> "); } 01030 else { sprintf(buffer, "<-- "); } 01031 writeText(dirImg, Point2D<int>(dirImg.getWidth()/2-20, 01032 dirImg.getHeight()/2-20), 01033 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01034 SimpleFont::FIXED(20)); 01035 01036 // vote count 01037 sprintf(buffer, "[%d]",itsDirCount); 01038 writeText(dirImg, Point2D<int>(dirImg.getWidth()/2-10, 01039 dirImg.getHeight()/2+40), 01040 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01041 SimpleFont::FIXED(20)); 01042 01043 // error rate 01044 sprintf(buffer, "False Error Rate:[%1.3f]",itsFalseErrRate); 01045 writeText(dirImg, Point2D<int>(10,10), 01046 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01047 SimpleFont::FIXED(8)); 01048 if(itsEstop) 01049 { 01050 sprintf(buffer, "Match:[%d]",itsMatchList->size()); 01051 writeText(dirImg, Point2D<int>(210,10), 01052 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01053 SimpleFont::FIXED(8)); 01054 } 01055 sprintf(buffer, "Error:[%1.3f] X:[%1.3f] Y:[%1.3f]", 01056 itsError.z,itsError.x,itsError.y); 01057 writeText(dirImg, Point2D<int>(10,25), 01058 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01059 SimpleFont::FIXED(8)); 01060 01061 // check if the match is valid 01062 if (itsEstop && itsMatchList->checkSIFTaffine()) 01063 { 01064 float theta, sx, sy, str; 01065 itsMatchList->getSIFTaffine().decompose(theta, sx, sy, str); 01066 sprintf(buffer, "Affine T:[%1.3f] X:[%1.3f] Y:[%1.3f]",theta,sx,sy); 01067 writeText(dirImg, Point2D<int>(10,40), 01068 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01069 SimpleFont::FIXED(8)); 01070 } 01071 sprintf(buffer, "Motor Speed :[%1.3f] Motor Rot:[%1.3f]", 01072 itsTransSpeed, itsRotSpeed); 01073 writeText(dirImg, Point2D<int>(10,55), 01074 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0), 01075 SimpleFont::FIXED(8)); 01076 return dirImg; 01077 } 01078 01079 // ###################################################################### 01080 void CornerNavigation::updatePosition(double turn) 01081 { 01082 itsDirVector += turn; 01083 if(itsDirVector > 360.0) itsDirVector = 0.0; 01084 if(itsDirVector < 0.0) itsDirVector = 360.0; 01085 01086 itsPosition.x -= sin(itsDirVector*(M_PI/180.0)); 01087 itsPosition.y -= cos(itsDirVector*(M_PI/180.0)); 01088 } 01089 01090 // ###################################################################### 01091 void CornerNavigation::updateMessage 01092 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&) 01093 { 01094 // // camera message 01095 // if(eMsg->ice_isA("::BeobotEvents::CameraMessage")) 01096 // { 01097 // // store the image 01098 // BeobotEvents::CameraMessagePtr cameraMsg = 01099 // BeobotEvents::CameraMessagePtr::dynamicCast(eMsg); 01100 01101 // int currRequestID = cameraMsg->RequestID; 01102 // Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> >(cameraMsg->image); 01103 01104 // LDEBUG("Got a CameraMessage with Request ID = %d", currRequestID); 01105 01106 // its_Curr_Img_mutex.lock(); 01107 // itsCurrImg = img; 01108 // itsCurrImgID = cameraMsg->RequestID; 01109 // its_Curr_Img_mutex.unlock(); 01110 // } 01111 01112 // Get a gist-sal message 01113 if(eMsg->ice_isA("::BeobotEvents::GistSalMessage")) 01114 { 01115 BeobotEvents::GistSalMessagePtr gistSalMsg = 01116 BeobotEvents::GistSalMessagePtr::dynamicCast(eMsg); 01117 01118 // Get the current request ID 01119 int currRequestID = gistSalMsg->RequestID; 01120 Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> >(gistSalMsg->currIma); 01121 01122 its_Curr_Img_mutex.lock(); 01123 itsCurrImg = img; 01124 itsCurrImgID = gistSalMsg->RequestID; 01125 its_Curr_Img_mutex.unlock(); 01126 01127 LINFO("Got a GSMessage with Request ID = %d", currRequestID); 01128 } 01129 01130 // motor message 01131 else if(eMsg->ice_isA("::BeobotEvents::MotorMessage")) 01132 { 01133 BeobotEvents::MotorMessagePtr mtrMsg = 01134 BeobotEvents::MotorMessagePtr::dynamicCast(eMsg); 01135 LDEBUG("Got a MotorMessage with Request ID = %d: RC Trans %f, Rot %f", 01136 mtrMsg->RequestID, itsRcTransSpeed, itsRcRotSpeed); 01137 its_Curr_Mtr_mutex.lock(); 01138 itsRemoteMode = mtrMsg->rcMode; 01139 itsRcTransSpeed = mtrMsg->rcTransVel; 01140 itsRcRotSpeed = mtrMsg->rcRotVel; 01141 its_Curr_Mtr_mutex.unlock(); 01142 } 01143 01144 // corner location message 01145 else if(eMsg->ice_isA("::BeobotEvents::CornerLocationMessage")) 01146 { 01147 BeobotEvents::CornerLocationMessagePtr clMsg = 01148 BeobotEvents::CornerLocationMessagePtr::dynamicCast(eMsg); 01149 LINFO("Turn on on corner %d", clMsg->cornerLocation); 01150 01151 // check if the corner location exceed the maximum index 01152 int index = clMsg->cornerLocation; 01153 LINFO("Got Corner location Message Corner:[%d]",index); 01154 01155 //only take new command if corner system is not running 01156 its_Corner_Loc_mutex.lock(); 01157 int status = itsStatus; 01158 its_Corner_Loc_mutex.unlock(); 01159 01160 if(status == C_PROCEDURE_INACTIVE) 01161 { 01162 if(index >= (int)itsVisualObjectDBs.size()) index = -1; 01163 its_Corner_Loc_mutex.lock(); 01164 itsStatus = C_PROCEDURE_ACTIVE; 01165 itsTeachImgID = 0; 01166 itsDBnum = index; 01167 its_Corner_Loc_mutex.unlock(); 01168 } 01169 } 01170 } 01171 01172 // ###################################################################### 01173 void CornerNavigation::updateMotorPID(double tran, double rot,double error) 01174 { 01175 error/=100.0; 01176 if(itsDir == 1) 01177 error *= -1.0; 01178 double pTerm,iTerm,dTerm; 01179 pTerm = itsPGain * error; 01180 itsIState += error; 01181 if(itsIState > IMAX) 01182 itsIState = IMAX; 01183 else if(itsIState < IMIN) 01184 itsIState = IMIN; 01185 iTerm = itsIGain * itsIState; 01186 dTerm = itsDGain * (rot - itsDState); 01187 itsDState = rot; 01188 double pid = pTerm + iTerm - dTerm; 01189 01190 LINFO("P[%1.2f] I[%1.2f] D[%1.2f], Istate[%1.2f] DState[%1.2f]", 01191 pTerm,iTerm,dTerm,itsIState,itsDState); 01192 LINFO("pid[%1.2f],rot[%1.2f]",pid,rot); 01193 updateMotor(tran,pid,itsStatus); 01194 } 01195 01196 // // ###################################################################### 01197 // void CornerNavigation::updateMotor(double tran, double rot) 01198 // { 01199 // BeobotEvents::MotorRequestPtr msg = new BeobotEvents::MotorRequest; 01200 // msg->transVel = tran; 01201 // msg->rotVel = rot; 01202 // this->publish("MotorRequestTopic", msg); 01203 // LINFO("[%d] Publish motor request Trans %f Rotation %f", 01204 // itsPrevProcImgID,tran,rot); 01205 // } 01206 01207 // ###################################################################### 01208 void CornerNavigation::updateMotor(double tran, double rot, int status) 01209 { 01210 BeobotEvents::CornerMotorRequestPtr msg = 01211 new BeobotEvents::CornerMotorRequest; 01212 msg->transVel = tran; 01213 msg->rotVel = rot; 01214 msg->status = status; 01215 this->publish("CornerMotorRequestTopic", msg); 01216 LINFO("[%d] Publish corner motor request Trans %f Rotation %f", 01217 itsPrevProcImgID, tran, rot); 01218 } 01219 01220 // ###################################################################### 01221 /* So things look consistent in everyone's emacs... */ 01222 /* Local Variables: */ 01223 /* indent-tabs-mode: nil */ 01224 /* End: */