Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Lookout.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 
00003 #include "Events/EventRouter.h"
00004 #include "Events/LocomotionEvent.h"
00005 #include "Events/LookoutEvents.h"
00006 #include "Events/VisionObjectEvent.h"
00007 #include "IPC/SharedObject.h"
00008 #include "Motion/MMAccessor.h"
00009 #include "Motion/MotionSequenceMC.h"
00010 #include "Motion/PostureMC.h"
00011 #include "Shared/Config.h"
00012 #include "Shared/ProjectInterface.h"
00013 #include "Shared/mathutils.h"
00014 #include "Shared/WorldState.h"
00015 #include "Vision/RegionGenerator.h"
00016 #include "Vision/SegmentedColorGenerator.h"
00017 
00018 #include "DualCoding/VRmixin.h"
00019 #include "Crew/LookoutRequests.h"
00020 #include "Crew/Lookout.h"
00021 #include "Crew/MapBuilder.h"
00022 #include "DualCoding/ShapeBlob.h"
00023 #include "DualCoding/ShapeLine.h"
00024 #include "DualCoding/ShapePolygon.h"
00025 
00026 using namespace mathutils;
00027 using namespace std;
00028 
00029 namespace DualCoding {
00030 
00031 Lookout::Lookout()
00032   : BehaviorBase("Lookout"),
00033     idCounter(0),
00034     pixelHistograms(VRmixin::camSkS.getNumPixels()), distanceSamples(),
00035     pointer_id(MotionManager::invalid_MC_ID),
00036     posture_id(MotionManager::invalid_MC_ID),
00037     sequence_id(MotionManager::invalid_MC_ID),
00038     requests(), curReq(NULL), curPAR(NULL), successSave(false),
00039     trackerState(inactive)
00040 {}
00041 
00042 void Lookout::doStart() {
00043   BehaviorBase::doStart();
00044   SharedObject<HeadPointerMC> head_mc;
00045   SharedObject<PostureMC> posture_mc;
00046   SharedObject<MediumMotionSequenceMC> mseq_mc;
00047   pointer_id = motman->addPersistentMotion(head_mc,MotionManager::kIgnoredPriority);
00048   posture_id = motman->addPersistentMotion(posture_mc,MotionManager::kIgnoredPriority);
00049   sequence_id = motman->addPersistentMotion(mseq_mc,MotionManager::kIgnoredPriority);
00050   cout << "Lookout starting up: pointer_id=" << pointer_id
00051        << " posture_id=" << posture_id
00052        << " sequence_id=" << sequence_id << endl;
00053   erouter->addListener(this,EventBase::motmanEGID,pointer_id,EventBase::statusETID);
00054   erouter->addListener(this,EventBase::motmanEGID,posture_id,EventBase::statusETID);
00055   erouter->addListener(this,EventBase::motmanEGID,sequence_id,EventBase::statusETID);
00056 }
00057 
00058 void Lookout::doStop() {
00059   motman->removeMotion(pointer_id);
00060   pointer_id = MotionManager::invalid_MC_ID;
00061   motman->removeMotion(posture_id);
00062   posture_id = MotionManager::invalid_MC_ID;
00063   motman->removeMotion(sequence_id);
00064   sequence_id = MotionManager::invalid_MC_ID;
00065   curReq = NULL;
00066   curPAR = NULL;
00067   while (!requests.empty()) {
00068     delete requests.front();
00069     requests.pop();
00070   }
00071   BehaviorBase::doStop();
00072 }
00073 
00074 vector<DualCoding::Point> Lookout::groundSearchPoints() {
00075   vector<Point> gazePts;
00076 #ifdef TGT_HAS_WHEELS
00077   int ground_frame_offset = 0;
00078 #else
00079   int ground_frame_offset = -100;
00080 #endif
00081   gazePts.push_back(Point( 200, -250, ground_frame_offset, egocentric));
00082   gazePts.push_back(Point( 800,-1000, ground_frame_offset, egocentric));
00083   gazePts.push_back(Point(1200,    0, ground_frame_offset, egocentric));
00084   gazePts.push_back(Point( 800, 1000, ground_frame_offset, egocentric));
00085   gazePts.push_back(Point( 200,  250, ground_frame_offset, egocentric));
00086 #ifdef TGT_QBOTPLUS  //QBotPlus has a higher camera so it see much closer to its body
00087   gazePts.push_back(Point( 100,    0, ground_frame_offset, egocentric));
00088 #endif
00089   gazePts.push_back(Point( 200,    0, ground_frame_offset, egocentric));
00090   gazePts.push_back(Point( 400,    0, ground_frame_offset, egocentric));
00091   gazePts.push_back(Point( 800,    0, ground_frame_offset, egocentric));
00092   return gazePts;
00093 }
00094 
00095 unsigned int Lookout::executeRequest(BehaviorBase* requestingBehavior, const LookoutRequestBase& req) {
00096   const unsigned int reqID = ++idCounter;
00097   executeRequest(req);
00098   return reqID;
00099 }
00100 
00101 
00102 unsigned int Lookout::executeRequest(const LookoutRequestBase &req) {
00103   switch (req.getHeadMotionType()) {
00104   case LookoutRequestBase::noMotion:
00105   case LookoutRequestBase::pointAt:
00106     pushRequest<LookoutPointRequest>(req);
00107     break;
00108   case LookoutRequestBase::scan:
00109     pushRequest<LookoutScanRequest>(req);
00110     break;
00111   case LookoutRequestBase::track:
00112     pushRequest<LookoutTrackRequest>(req); 
00113     break;
00114   case LookoutRequestBase::search:
00115     pushRequest<LookoutSearchRequest>(req); 
00116     break;
00117   default:
00118     cout << "Lookout::executeRequest: unknown request type " << req.getHeadMotionType() << endl;
00119   };
00120   const unsigned int reqid = requests.back()->requestID = ++idCounter;  
00121   executeRequest();
00122   return reqid;
00123 }
00124 
00125 void Lookout::executeRequest() {
00126   if ( curReq != NULL || requests.empty() )
00127     return;
00128   curReq = requests.front();
00129   // cout << "Lookout executing " << LookoutRequestBase::headMotionTypeNames[curReq->getHeadMotionType()] 
00130   //   << " request, id=" << curReq->requestID << endl;
00131   curPAR = dynamic_cast<LookoutPointRequest*>(curReq);
00132 
00133   // If we're going to be computing pixel or distance modes, clear the bins first
00134   if ( curPAR != NULL && curPAR->numSamples > 1 )
00135     switch ( curPAR->getResultType() ) {
00136     case LookoutRequestBase::imageResult:
00137       for ( unsigned int i=0; i<pixelHistograms.size(); i++ )
00138   pixelHistograms[i].clear();
00139       break;
00140 #ifdef TGT_HAS_IR_DISTANCE
00141     case LookoutRequestBase::distanceResult:
00142       while ( distanceSamples.size() > 0) distanceSamples.pop();
00143       break;
00144 #endif
00145     default:
00146       break;
00147     }
00148 
00149   // now dispatch on the head motion type
00150   trackerState = inactive;
00151   switch (curReq->getHeadMotionType()) {
00152   case LookoutRequestBase::noMotion:
00153     erouter->addTimer(this, settle_timer, curPAR->motionSettleTime, false);
00154     break;
00155   case LookoutRequestBase::pointAt:
00156     moveHeadToPoint();
00157     break;
00158   case LookoutRequestBase::scan:
00159     setupScan();
00160     break;
00161   case LookoutRequestBase::track:
00162     setupTrack();
00163     break;
00164   case LookoutRequestBase::search:
00165     setupSearch();
00166     break;
00167   default:
00168     cout << "Lookout::executeRequest(): unknown request " << curReq->getHeadMotionType() << endl;
00169     break;
00170   };
00171 }
00172 
00173 void Lookout::relax() {
00174   motman->setPriority(pointer_id,MotionManager::kIgnoredPriority);
00175   motman->setPriority(posture_id,MotionManager::kIgnoredPriority);
00176   motman->setPriority(sequence_id,MotionManager::kIgnoredPriority);
00177 }
00178 
00179 void Lookout::moveHeadToPoint() {
00180   Point pt = curPAR->gazePt;
00181   switch ( pt.getRefFrameType() ) {
00182   case unspecified:
00183   case camcentric:
00184     cout << "Warning: Lookout gaze point " << curPAR->gazePt << " reference frame must be egocentric or allocentric" << endl;
00185     pt.setRefFrameType(egocentric);
00186   case egocentric:
00187     break;
00188   case allocentric:
00189     pt.applyTransform(VRmixin::mapBuilder->worldToLocalMatrix, egocentric);
00190   }
00191   // point head based on Camera or IR reference frame
00192   switch ( curPAR->getResultType() ) {
00193   case LookoutRequestBase::noResult:
00194   case LookoutRequestBase::imageResult: {
00195     successSave = MMAccessor<HeadPointerMC>(pointer_id)->lookAtPoint(pt.coordX(),pt.coordY(),pt.coordZ());
00196     motman->setPriority(pointer_id,MotionManager::kStdPriority);
00197     motman->setPriority(posture_id,MotionManager::kIgnoredPriority);
00198     motman->setPriority(sequence_id,MotionManager::kIgnoredPriority);
00199   }
00200     break;
00201   case LookoutRequestBase::distanceResult: {
00202 #ifdef TGT_HAS_IR_DISTANCE
00203     successSave = MMAccessor<PostureMC>(posture_id)->solveLinkVector(pt.coords,IRFrameOffset,Kinematics::pack(0,0,1));
00204     motman->setPriority(posture_id,MotionManager::kStdPriority);
00205     motman->setPriority(pointer_id,MotionManager::kIgnoredPriority);
00206     motman->setPriority(sequence_id,MotionManager::kIgnoredPriority);
00207 #endif
00208     }
00209     break;
00210   case LookoutRequestBase::interestPoints:
00211     cout << "Lookout error: this scan type cannot return interest points." << endl;
00212     return;
00213   }
00214 }
00215 
00216 void Lookout::doEvent() {
00217   if ( curReq == NULL ) {
00218     if ( event->getGeneratorID() == EventBase::motmanEGID &&
00219    event->getTypeID() == EventBase::statusETID )
00220       return; // harmless motman status event from startup
00221     else {
00222       cout << "Error:  Lookout received an event when not executing a request:\n";
00223       cout << "    " << event->getDescription(true,3) << endl;
00224       return;
00225     }
00226   }
00227 
00228   switch (curReq->getHeadMotionType()) {
00229   case LookoutRequestBase::noMotion:
00230   case LookoutRequestBase::pointAt:
00231     processPointAtEvent(*event);
00232     break;
00233   case LookoutRequestBase::scan:
00234     processScanEvent(*event);
00235     break;
00236   case LookoutRequestBase::track:
00237     processTrackEvent(*event);
00238     break;
00239   case LookoutRequestBase::search:
00240     processSearchEvent(*event);
00241     break;
00242   default:
00243     cout << "Lookout::doEvent: unknown head motion request type: "
00244    << curReq->getHeadMotionType() << ", event: " << event->getDescription() << endl;
00245     break;
00246   };
00247 }
00248 
00249 void Lookout::processPointAtEvent(const EventBase& ev) {
00250   switch (ev.getGeneratorID()) {
00251   case EventBase::motmanEGID:
00252     if ( ev.getSourceID() == pointer_id || ev.getSourceID() == posture_id ) {
00253       // head motion complete, now wait for head to settle
00254       motman->setPriority(ev.getSourceID(), MotionManager::kBackgroundPriority);
00255       erouter->addTimer(this, settle_timer, curPAR->motionSettleTime, false);
00256     }
00257     break;
00258 
00259   case EventBase::timerEGID:
00260     if (ev.getSourceID() == settle_timer || ev.getSourceID() == sample_timer) {
00261       switch (curReq->getResultType()) {
00262       case LookoutRequestBase::imageResult:
00263   erouter->addListener(this, EventBase::visRegionEGID,
00264            ProjectInterface::visRegionSID,EventBase::statusETID);
00265   break;
00266 #ifdef TGT_HAS_IR_DISTANCE
00267       case LookoutRequestBase::distanceResult:
00268   erouter->addListener(this, EventBase::sensorEGID, SensorSrcID::UpdatedSID);
00269   break;
00270 #endif
00271       case LookoutRequestBase::noResult:
00272       default:
00273   requestComplete(successSave);
00274   break;
00275       };
00276     }
00277     break;
00278 
00279   case EventBase::visRegionEGID:
00280     erouter->removeListener(this, EventBase::visRegionEGID);
00281     curPAR->image.bind((curPAR->sketchFunc)());
00282     ++curPAR->sampleCounter;
00283     if ( curPAR->numSamples == 1 || findPixelModes() == true ) {
00284       curPAR->toBaseMatrix = kine->linkToBase(curPAR->joint);
00285       requestComplete(successSave);
00286     }
00287     else
00288       erouter->addTimer(this, sample_timer, curPAR->sampleInterval, false);
00289     break;
00290 
00291   case EventBase::sensorEGID:
00292     erouter->removeListener(this, EventBase::sensorEGID);
00293 #ifdef TGT_HAS_IR_DISTANCE
00294     if ( findDistanceMode() == true ) {
00295       curPAR->toBaseMatrix = kine->linkToBase(curPAR->joint);
00296       requestComplete(successSave);
00297     } else
00298 #endif
00299       erouter->addTimer(this, sample_timer, curPAR->sampleInterval, false);
00300     break;
00301 
00302   default:
00303     cout << "Lookout::processPointAtEvent: unknown event " << ev.getDescription() << endl;
00304     break;
00305   };
00306 }
00307 
00308 bool Lookout::findPixelModes() {
00309   // update our counts using the new sammple
00310   for (size_t i = 0; i<pixelHistograms.size(); i++)
00311     pixelHistograms[i][curPAR->image[i]]++;
00312   if ( curPAR->sampleCounter < curPAR->numSamples )
00313     return false;
00314   // we have enough samples; compute the mode
00315   for (size_t i = 0; i<pixelHistograms.size(); i++) {
00316     unsigned int maxCount = 0;
00317     uchar maxChar = 0;
00318     for (map<uchar, unsigned int>::const_iterator it = pixelHistograms[i].begin();
00319    it != pixelHistograms[i].end(); it++)
00320       if (it->second > maxCount) {
00321   maxCount = it->second;
00322   maxChar = it->first;
00323       }
00324     curPAR->image[i] = maxChar;
00325   }
00326   return true;
00327 }
00328 
00329 #ifdef TGT_HAS_IR_DISTANCE
00330 float Lookout::getDistanceModeValue() {
00331   int const npops = distanceSamples.size() / 2;
00332   for ( int i=0; i<npops; i++ ) distanceSamples.pop();
00333   return distanceSamples.top();
00334 }
00335 
00336 inline float getIR() {
00337 #ifdef TGT_ERS7 
00338   if ( state->sensors[FarIRDistOffset] > 400 )  // far IR goes 200-1500; near IR goes 50-500
00339     return state->sensors[FarIRDistOffset];
00340   else
00341     return state->sensors[NearIRDistOffset];
00342 #else 
00343   return state->sensors[IRDistOffset];
00344 #endif
00345 }
00346 
00347 bool Lookout::findDistanceMode() {
00348   distanceSamples.push(getIR());
00349   return (int)distanceSamples.size() < curPAR->numSamples;
00350 }
00351 #endif // TGT_HAS_IR_DISTANCE
00352 
00353 void Lookout::requestComplete(bool success) {
00354   // cout << "Lookout request " << curReq->requestID << " complete." << endl;
00355   erouter->removeTimer(this);
00356   erouter->removeListener(this,EventBase::sensorEGID);
00357   erouter->removeListener(this,EventBase::visSegmentEGID);
00358   erouter->removeListener(this,EventBase::visRegionEGID);
00359   erouter->removeListener(this,EventBase::visObjEGID);
00360   LookoutRequestBase *saveReq = curReq;
00361   Sketch<uchar> image;
00362   fmat::Transform toBaseMatrix;
00363   switch ( saveReq->getHeadMotionType() ) {
00364   case LookoutRequestBase::noMotion:
00365   case LookoutRequestBase::pointAt:
00366     image = curPAR->image;
00367     toBaseMatrix = curPAR->toBaseMatrix;
00368     break;
00369   case LookoutRequestBase::search: {
00370     LookoutSearchRequest *curSR = static_cast<LookoutSearchRequest*>(curReq);
00371     image = curSR->image;
00372     toBaseMatrix = curSR->toBaseMatrix;
00373     break;
00374   }
00375   default:
00376     break;
00377   }
00378   curReq = NULL;
00379   curPAR = NULL;
00380   requests.pop();
00381   switch ( saveReq->getHeadMotionType() ) {
00382   case LookoutRequestBase::noMotion:
00383   case LookoutRequestBase::pointAt:
00384     switch ( saveReq->getResultType() ) {
00385     case LookoutRequestBase::noResult:
00386       erouter->postEvent(LookoutPointAtEvent(success,static_cast<LookoutPointRequest*>(saveReq)->toBaseMatrix,
00387                EventBase::lookoutEGID, saveReq->requestID, EventBase::deactivateETID));
00388       break;
00389     case LookoutRequestBase::imageResult:
00390       erouter->postEvent(LookoutSketchEvent(success,static_cast<LookoutPointRequest*>(saveReq)->image,
00391               static_cast<LookoutPointRequest*>(saveReq)->toBaseMatrix,
00392               EventBase::lookoutEGID, saveReq->requestID, EventBase::deactivateETID));
00393       break;
00394 #ifdef TGT_HAS_IR_DISTANCE
00395     case LookoutRequestBase::distanceResult:
00396       erouter->postEvent(LookoutIREvent(success,getDistanceModeValue(), static_cast<LookoutPointRequest*>(saveReq)->toBaseMatrix,
00397           EventBase::lookoutEGID, saveReq->requestID, EventBase::deactivateETID));
00398       break;
00399 #endif
00400     default:
00401       cout << "Lookout::requestComplete(): Unknown type returned by getResultType()\n";
00402     }
00403     break;
00404 
00405   case LookoutRequestBase::scan:
00406     erouter->postEvent(LookoutScanEvent(static_cast<LookoutScanRequest*>(saveReq)->tasks,
00407           EventBase::lookoutEGID,saveReq->requestID, EventBase::deactivateETID));
00408     break;
00409 
00410   case LookoutRequestBase::track:
00411     erouter->postEvent(EventBase(EventBase::lookoutEGID,saveReq->requestID, EventBase::deactivateETID));
00412     break;
00413 
00414   case LookoutRequestBase::search: {
00415     //    Sketch<uchar> image(VRmixin::sketchFromSeg());
00416     //#ifdef TGT_HAS_CAMERA
00417     //    const fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
00418     //#else
00419     //    fmat::Transform camToBase = fmat::Transform::identity();
00420     //#endif
00421     erouter->postEvent(LookoutSketchEvent(success, image, toBaseMatrix,
00422             EventBase::lookoutEGID, saveReq->requestID, EventBase::deactivateETID));
00423     break;
00424   }
00425 
00426   default:
00427     cout << "Lookout::requestComplete(): Unknown head motion type\n";
00428   }
00429 
00430   // The postEvent above may have led to a series of functions
00431   // returning and eventually shutting down the Lookout or starting
00432   // another request, so make sure we're still in the same state
00433   // before proceeding.
00434   delete saveReq;
00435   if ( curReq == NULL && !requests.empty() )
00436     executeRequest();
00437 }
00438 
00439 Point Lookout::findLocationFor(const CMVision::region* reg) {
00440   return findLocationFor( float(2*reg->cen_x - VRmixin::camSkS.getWidth())/VRmixin::camSkS.getWidth(),
00441     float(2*reg->cen_y - VRmixin::camSkS.getHeight())/VRmixin::camSkS.getWidth());
00442 }
00443   
00444 typedef SegmentedColorGenerator::color_class_state color_class_state;
00445 
00446 void Lookout::storeVisionRegionDataTo(vector<Point>& data, const set<color_index>& colors, int minArea) {
00447   const unsigned char *img = 
00448     ProjectInterface::defRegionGenerator->getImage(ProjectInterface::fullLayer,0);
00449   const color_class_state *regions = reinterpret_cast<const color_class_state*> (img);
00450   for (set<color_index>::const_iterator it = colors.begin();
00451        it != colors.end(); it++)
00452     for (int i = 0; i < regions[*it].num; i++)
00453       if ((regions[*it].list+i)->area > minArea) {
00454   data.push_back(findLocationFor(regions[*it].list));
00455   cout << regions[*it].name  << " at " << data.back() << endl;
00456       }
00457       else break;
00458 }
00459   
00460 #ifdef TGT_HAS_IR_DISTANCE
00461 void Lookout::storeIRDataTo(vector<Point>& data) {
00462   fmat::Column<3> ray = Kinematics::pack(0,0,getIR());
00463   cout << "dist= " << ray[2] << ", in base frame= ";
00464   fmat::Column<3> baseCoords = kine->linkToBase(IRFrameOffset)*ray;
00465   data.push_back(Point(baseCoords[0],baseCoords[1],baseCoords[2]));
00466   cout << data.back() << endl;
00467 }
00468 #endif
00469 
00470 
00471 //================ Scan Request ================
00472 
00473 void Lookout::processScanEvent(const EventBase& ev) {
00474   //  cout << "Lookout::processScan: " << ev.getName() << endl;
00475   static bool listeningObjEGID = false;
00476   const LookoutScanRequest* curScanReq = dynamic_cast<LookoutScanRequest*>(curReq);
00477 
00478   switch (ev.getGeneratorID()) {
00479   case EventBase::motmanEGID:
00480     // head arrived at the start of motion sequence, add listeners and start scan sequence
00481     if (ev.getSourceID() == pointer_id) {
00482       erouter->addTimer(this,settle_timer,curScanReq->motionSettleTime,false);
00483     }
00484     else if (ev.getSourceID() == sequence_id) {
00485       motman->setPriority(sequence_id,MotionManager::kBackgroundPriority);
00486       requestComplete(successSave);
00487     }
00488     break;
00489 
00490   case EventBase::timerEGID: // time to take some measurements
00491     if ( ev.getSourceID() == settle_timer )
00492       triggerScanMotionSequence();
00493     else if ( ev.getSourceID() >= scan_timer && ev.getSourceID()-scan_timer < curScanReq->tasks.size() ) {
00494       LookoutRequestBase::Task* task = curScanReq->tasks[ev.getSourceID()-scan_timer];
00495       if (task->getTaskType() == LookoutRequestBase::Task::visRegTask) {
00496   LookoutRequestBase::VisionRegionTask* vrt = dynamic_cast<LookoutRequestBase::VisionRegionTask*>(task);
00497   storeVisionRegionDataTo(vrt->data,vrt->index,vrt->minArea);
00498       }
00499       else if (task->getTaskType() == LookoutRequestBase::Task::visObjTask) {
00500   erouter->addListener(this, EventBase::visSegmentEGID,
00501            ProjectInterface::visSegmentSID,EventBase::statusETID);
00502   listeningObjEGID = true;
00503       }
00504 #ifdef TGT_HAS_IR_DISTANCE
00505       else if (task->getTaskType() == LookoutRequestBase::Task::irTask) 
00506   storeIRDataTo(task->data);
00507 #endif
00508     }
00509     break;
00510 
00511   case EventBase::visSegmentEGID:
00512     if (listeningObjEGID)
00513       listeningObjEGID = false;
00514     else
00515       erouter->removeListener(this, EventBase::visSegmentEGID);
00516     break;
00517 
00518   case EventBase::visObjEGID:
00519     if (listeningObjEGID) {
00520       const VisionObjectEvent &voe = static_cast<const VisionObjectEvent&>(ev);    
00521       for (vector<LookoutRequestBase::Task*>::const_iterator it = curScanReq->tasks.begin();
00522      it != curScanReq->tasks.end(); it++)
00523   if ((*it)->getTaskType() == LookoutRequestBase::Task::visObjTask) {
00524     LookoutRequestBase::VisionTask& vTask = *dynamic_cast<LookoutRequestBase::VisionTask*>(*it);
00525     if (vTask.index.find(ev.getSourceID()) != vTask.index.end()) {
00526       vTask.data.push_back(findLocationFor(voe));
00527       cout << "VisionObject at " << vTask.data.back() << endl;
00528       break;
00529     }
00530   }
00531     }
00532     break;
00533   default:
00534     cout << "Lookout::processScan: unknown event " << ev.getName() << endl;
00535     break;
00536   };
00537 }
00538 
00539 void Lookout::setupScan() {
00540   const LookoutScanRequest *curScan = dynamic_cast<const LookoutScanRequest*>(curReq);
00541   cout << "scan speed: " << curScan->scanSpeed 
00542        << "  (rad / millisec)\n";
00543   if ( !curScan->searchArea.isValid() ) {
00544     cout << "Invalid search area in LookoutScanRequest" << endl;
00545     return;
00546   }
00547   switch ( curScan->searchArea->getType() ) {
00548   case lineDataType: {
00549     const Shape<LineData> &line = ShapeRootTypeConst(curScan->searchArea,LineData);
00550     scanAlongLine(line->firstPt(), line->secondPt());
00551     break;
00552   }
00553   case polygonDataType:{
00554     const Shape<PolygonData> &poly = ShapeRootTypeConst(curScan->searchArea,PolygonData);
00555     scanAlongPolygon(poly->getVertices());
00556     break;
00557   }
00558   default:
00559     cout << "Invalid shape type for LookoutRequestBase searchArea: must be line or polygon" << endl;
00560   }
00561 }
00562 
00563 void Lookout::triggerScanMotionSequence() {
00564   const LookoutScanRequest* curScanReq = dynamic_cast<LookoutScanRequest*>(curReq);
00565   for (unsigned int i = 0; i < curScanReq->tasks.size(); i++) {
00566     const LookoutRequestBase::Task* task = curScanReq->tasks[i];
00567     if (task->getTaskType() == LookoutRequestBase::Task::visObjTask) {
00568       const LookoutRequestBase::VisionTask& vTask = *dynamic_cast<const LookoutRequestBase::VisionTask*>(task);
00569       for(set<color_index>::const_iterator color_it = vTask.index.begin();
00570     color_it != vTask.index.end(); color_it++)
00571   erouter->addListener(this,EventBase::visObjEGID, *color_it);
00572     }
00573     erouter->addTimer(this,scan_timer+i,0,false); // for initial measurements
00574     int snap_interval = (int)((float)task->dTheta / (float)curScanReq->scanSpeed);
00575     cout << "Lookout scan snap_interval = " << snap_interval << endl;
00576     erouter->addTimer(this, scan_timer+i, snap_interval, true);
00577   }
00578   motman->setPriority(pointer_id,MotionManager::kIgnoredPriority);
00579   motman->setPriority(posture_id,MotionManager::kIgnoredPriority);
00580   motman->setPriority(sequence_id,MotionManager::kStdPriority);
00581   MMAccessor<MediumMotionSequenceMC>(sequence_id)->play();
00582 }
00583 
00584 void Lookout::scanAlongLine(const Point& startPt, const Point& endPt) {
00585   motman->setPriority(pointer_id,MotionManager::kIgnoredPriority); // just to be safe
00586   MMAccessor<HeadPointerMC> pointer_acc(pointer_id);
00587 
00588   // first compute joint angles for final point
00589   pointer_acc->lookAtPoint(endPt.coordX(),endPt.coordY(),endPt.coordZ());
00590   std::vector<float> anglesA(NumHeadJoints);
00591   for(unsigned int i=0; i<NumHeadJoints; ++i)
00592     anglesA[i]=pointer_acc->getJointValue(i);
00593   
00594   // now compute angles for initial point, so when the motion command is executed we'll start there
00595   pointer_acc->lookAtPoint(startPt.coordX(),startPt.coordY(),startPt.coordZ());
00596   std::vector<float> anglesB(NumHeadJoints);
00597   for(unsigned int i=0; i<NumHeadJoints; ++i)
00598     anglesB[i]=pointer_acc->getJointValue(i);
00599   
00600   float total_joint_distance=0;
00601   for(unsigned int i=0; i<NumHeadJoints; ++i) {
00602     float diff = anglesA[i] - anglesB[i];
00603     total_joint_distance += diff*diff;
00604   }
00605   const unsigned int movement_time = (unsigned int)(sqrt(total_joint_distance) / dynamic_cast<const LookoutScanRequest*>(curReq)->scanSpeed);
00606   
00607   // begin at start point (the HeadPointerMC will have brought us there) and move smoothly to end point
00608   motman->setPriority(sequence_id,MotionManager::kIgnoredPriority); // just to be safe
00609   MMAccessor<MediumMotionSequenceMC> mseq_acc(sequence_id);
00610   mseq_acc->clear();
00611   mseq_acc->pause();
00612 #ifdef TGT_HAS_HEAD
00613   for(unsigned int i=0; i<NumHeadJoints; ++i)
00614     mseq_acc->setOutputCmd(HeadOffset+i,anglesA[i]);
00615 #endif
00616   mseq_acc->advanceTime(movement_time);
00617 #ifdef TGT_HAS_HEAD
00618   for(unsigned int i=0; i<NumHeadJoints; ++i)
00619     mseq_acc->setOutputCmd(HeadOffset+i,anglesB[i]);
00620 #endif
00621   motman->setPriority(posture_id,MotionManager::kIgnoredPriority); // just to be safe
00622   motman->setPriority(pointer_id,MotionManager::kStdPriority); // start head moving to where scan begins; completion will trigger the scan
00623 }
00624 
00625 void Lookout::scanAlongPolygon(vector<Point> const &vertices, const bool closed) {
00626   if ( vertices.size() == 0 )
00627     requestComplete();
00628   vector<Point> vertices_copy(vertices);
00629   const Point startPt = vertices_copy[0];
00630   if ( closed )
00631     vertices_copy.push_back(startPt);
00632   motman->setPriority(pointer_id,MotionManager::kBackgroundPriority); // just to be safe
00633   motman->setPriority(sequence_id,MotionManager::kBackgroundPriority); // just to be safe
00634   MMAccessor<HeadPointerMC> pointer_acc(pointer_id);
00635   MMAccessor<MediumMotionSequenceMC> mseq_acc(sequence_id);
00636   mseq_acc->pause();
00637   mseq_acc->clear();
00638   float const speed = dynamic_cast<const LookoutScanRequest*>(curReq)->scanSpeed;
00639   std::vector<float> anglesA(NumHeadJoints,0), anglesB(NumHeadJoints,0);
00640   for ( vector<Point>::const_iterator it = vertices_copy.begin(); it != vertices_copy.end(); ++it ) {
00641     pointer_acc->lookAtPoint((*it).coordX(),(*it).coordY(),(*it).coordZ());
00642     for(unsigned int i=0; i<NumHeadJoints; ++i)
00643       anglesB[i]=pointer_acc->getJointValue(i);
00644     if ( it != vertices_copy.begin() ) {
00645       float total_joint_distance=0;
00646       for(unsigned int i=0; i<NumHeadJoints; ++i) {
00647         float diff = anglesA[i] - anglesB[i];
00648         total_joint_distance += diff*diff;
00649       }
00650       const unsigned int movement_time = (unsigned int)(sqrt(total_joint_distance) /speed + 200);
00651       // cout << "Movement time " << movement_time << "msec to " << *it << endl;
00652       mseq_acc->advanceTime(movement_time);
00653     }
00654 #ifdef TGT_HAS_HEAD
00655     for(unsigned int i=0; i<NumHeadJoints; ++i)
00656       mseq_acc->setOutputCmd(HeadOffset+i,anglesB[i]);
00657     mseq_acc->advanceTime(200);
00658     for(unsigned int i=0; i<NumHeadJoints; ++i)
00659       mseq_acc->setOutputCmd(HeadOffset+i,anglesB[i]);
00660 #endif
00661     anglesA.swap(anglesB);
00662   }
00663   
00664   cout << "Lookout:scanAlongPolygon lookAtPoint " << startPt.coordX() <<  " "
00665        << startPt.coordY() << " " << startPt.coordZ() << endl;
00666   pointer_acc->lookAtPoint(startPt.coordX(),startPt.coordY(),startPt.coordZ());
00667   motman->setPriority(pointer_id,MotionManager::kStdPriority); // start head moving to where scan begins; completion will trigger the scan
00668 }
00669   
00670 //================ Track Requests ================
00671 
00672 void Lookout::setupTrack() {
00673   // point the head at the object, then start tracking it and posting status events
00674   LookoutTrackRequest *curTR = static_cast<LookoutTrackRequest*>(curReq);
00675   const ShapeRoot &target = curTR->targetShape;
00676   curTR->cindex = ProjectInterface::getColorIndex(target->getColor());
00677   Point egoLoc = target->getCentroid();
00678   if ( target->getRefFrameType() == camcentric ) {
00679 #ifndef TGT_HAS_CAMERA
00680     std::cerr << "Lookout::setupTrack target has camcentric reference frame, but target model doesn't have a camera" << std::endl;
00681 #else
00682     const fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
00683     egoLoc.projectToGround(camToBase,kine->calculateGroundPlane()); // assume head hasn't moved, or we're screwed
00684 #endif
00685   }
00686   trackerState = moveToAcquire;
00687   erouter->addListener(this, EventBase::visRegionEGID, ProjectInterface::visRegionSID, EventBase::deactivateETID);
00688   motman->setPriority(posture_id,MotionManager::kIgnoredPriority);
00689   motman->setPriority(sequence_id,MotionManager::kIgnoredPriority);
00690   motman->setPriority(pointer_id,MotionManager::kStdPriority);
00691   successSave = MMAccessor<HeadPointerMC>(pointer_id)->lookAtPoint(egoLoc.coordX(), egoLoc.coordY(), egoLoc.coordZ());
00692 }
00693 
00694 void Lookout::processTrackEvent(const EventBase &ev) {
00695   const LookoutTrackRequest *curTR = static_cast<const LookoutTrackRequest*>(curReq);
00696   switch ( ev.getGeneratorID() ) {
00697 
00698   case EventBase::visRegionEGID: {
00699     if ( trackerState == moveToAcquire ) return; // ignore vision events while slewing head to initial position
00700     const color_class_state *ccs = reinterpret_cast<const CMVision::color_class_state*>
00701       (ProjectInterface::defRegionGenerator->getImage(ProjectInterface::fullLayer,0));
00702     const color_class_state &col = ccs[curTR->cindex];
00703     if ( col.list == NULL || col.list->area <= curTR->minBlobArea ) {
00704       if ( trackerState != lost ) {
00705   trackerState = lost;
00706   erouter->addTimer(this,lost_timer,2000,false);  // wait for object to reappear
00707       }
00708       return;
00709     }
00710     // test succeeded
00711     erouter->removeTimer(this,lost_timer);
00712     trackerState = tracking;
00713     Point target = findLocationFor(col.list);
00714     MMAccessor<HeadPointerMC>(pointer_id)->lookAtPoint(target.coordX(),target.coordY(),target.coordZ());
00715   }
00716     break;
00717 
00718 
00719   case EventBase::motmanEGID:
00720     switch ( trackerState ) {
00721     case inactive:
00722       break;
00723     case moveToAcquire:
00724       trackerState = tracking;
00725       break;
00726     case tracking:
00727     case searching:
00728     case centering:
00729     case lost:
00730       break;
00731     }
00732     break;
00733     
00734   case EventBase::timerEGID:
00735     if ( ev.getSourceID() == lost_timer )   // object out of sight for too long: give up? Or search?
00736       stopTrack();
00737     break;
00738 
00739   default:
00740     break;
00741   }
00742 }
00743 
00744 void Lookout::stopTrack() {
00745   if ( curReq != NULL && curReq->getHeadMotionType() == LookoutRequestBase::track )
00746     requestComplete(false);
00747 }
00748 
00749 Point Lookout::findLocationFor(const float normX, const float normY) {
00750   fmat::Column<3> cameraPt;
00751   config->vision.computeRay(normX, normY, cameraPt[0],cameraPt[1],cameraPt[2]);
00752 #ifdef TGT_HAS_IR_DISTANCE
00753   cameraPt *= getIR();
00754 #else
00755   cameraPt *= 400;
00756 #endif
00757   // groundPt = kine->projectToPlane(CameraFrameOffset, cameraPt, 
00758   //          BaseFrameOffset, ground_plane, BaseFrameOffset);
00759 #ifndef TGT_HAS_CAMERA
00760   const fmat::Column<3> groundPt = cameraPt;
00761 #else
00762   const fmat::Transform camToBase(kine->linkToBase(CameraFrameOffset));
00763   const fmat::Column<3> groundPt = camToBase * cameraPt;
00764 #endif
00765   return Point(groundPt,egocentric);
00766 }
00767 
00768   /*
00769 void Lookout::processTrackVision(float normX, float normY, bool isCurrentlyVisible) {
00770   if (!isCurrentlyVisible && landmarkInView) { // landmark just lost
00771     cout << "landmark just lost" << endl;
00772     erouter->addTimer(this,start_pan,500,false); // wait 0.5 sec before starting to look for landmark
00773     erouter->removeTimer(this,reset_pan);
00774   }
00775   else if (!landmarkInView && isCurrentlyVisible) { // landmark just found
00776     cout << "found landmark" << endl;
00777     erouter->removeTimer(this,start_pan);
00778     erouter->addTimer(this,reset_pan,1000,false);
00779   }
00780   else if (isCurrentlyVisible) { // continue tracking landmark
00781     trackObjectAt(normX,normY);
00782   }
00783   landmarkInView = isCurrentlyVisible;
00784   lm_location = findLocationFor(normX,normY);
00785   erouter->postEvent(EventBase::lookoutEGID, curReq->getRequestID(), EventBase::statusETID,0);
00786 }
00787 
00788 void Lookout::processTrackEvent(const EventBase& event) {
00789   switch (event.getGeneratorID()) {
00790   case EventBase::visObjEGID:
00791     if (event.getTypeID()==EventBase::statusETID) {
00792       const VisionObjectEvent *voe = (static_cast<const VisionObjectEvent*>(&event));
00793       const float area = voe->getBoundaryArea();
00794       processTrackVision(voe->getCenterX(), voe->getCenterY(), area > 0.03);
00795     }
00796     break;
00797   case EventBase::visSegmentEGID:
00798     if (event.getTypeID() == EventBase::statusETID) {
00799       vector<Point> pts = getRegionData();
00800       if (pts.empty()) processTrackVision(0,0,false);
00801       else processTrackVision(pts.front().coordX(),pts.front().coordY(),true);
00802     }
00803     break;
00804   case EventBase::timerEGID:
00805     switch (event.getSourceID()) {
00806     case start_pan: //! enough time passed after landmark lost
00807       cout << "landmark not seen for 0.5 sec\n";
00808       if (curReq->isSticky())
00809   lookForLandmark();
00810       else
00811   requestComplete();
00812       break;
00813     case reset_pan:
00814       cout << "reset pan motion" << endl;
00815       { MMAccessor<SmallMotionSequenceMC> (sequence_id)->setTime(0); }
00816       break;
00817     default:
00818       cout << "unknown source timer evenet" << endl;
00819       break;
00820     }
00821   case EventBase::motmanEGID:
00822     if (event.getSourceID() == sequence_id && curReq->isSticky()) { // lookForLandmark() failed
00823       cout << "Lookout::processTrack: track failed\n";
00824       requestComplete();
00825     }
00826     break;
00827   default:
00828     cout << "Lookout::processTrack: unknown event" << endl;
00829     break;
00830   };
00831 }
00832   */
00833 
00834 
00835   /*
00836 void Lookout::trackObjectAt(float horiz, float vert) {
00837   setPanPrior(false);
00838 //  findLandmarkLocation(voe);
00839 //  erouter->postEvent(EventBase::lookoutEGID, curReq->getRequestID(), EventBase::statusETID,0);
00840   double tilt=state->outputs[HeadOffset+TiltOffset]-vert*M_PI/7.5;
00841   double pan=state->outputs[HeadOffset+PanOffset]-horiz*M_PI/6;
00842   if(tilt<mathutils::deg2rad(-20.0))
00843     tilt=mathutils::deg2rad(-20.0);
00844   if(tilt>mathutils::deg2rad(40.0))
00845     tilt=mathutils::deg2rad(40.0);
00846   if(pan>mathutils::deg2rad(80.0))
00847     pan=mathutils::deg2rad(80.0);
00848   if(pan<mathutils::deg2rad(-80.0))
00849     pan=mathutils::deg2rad(-80.0);
00850 
00851 #ifdef TGT_ERS7
00852   //  cout << "tilt: " << state->outputs[HeadOffset+TiltOffset] << ", nod: " << state->outputs[HeadOffset+NodOffset] << endl;
00853   if (tilt < -0.5)
00854     MMAccessor<HeadPointerMC> (pointer_id)->setJoints(tilt,pan,outputRanges[HeadOffset+NodOffset][MinRange]);
00855   else {
00856     const float act_tilt = state->outputs[HeadOffset+TiltOffset];
00857     const float nod_fact = act_tilt*act_tilt*4.0;
00858     MMAccessor<HeadPointerMC> (pointer_id)->setJoints(tilt,pan,outputRanges[HeadOffset+NodOffset][MinRange]*nod_fact);
00859   }
00860 #else
00861   MMAccessor<HeadPointerMC> (pointer_id)->setJoints(tilt,pan,0);
00862 #endif
00863 }
00864   */
00865 
00866 // ================ Search Requests ================
00867 
00868 /* Move head to the target shape.  If we encounter the desired color
00869 region along the way, stop moving.  Otherwise, upon reaching the
00870 target, begin a spiral search sequence.  If the sequence completes
00871 without finding the color region, return failure.  Else find the
00872 center of the color region, move the head there, wait for the camera
00873 to settle, take a picture, and return success. */
00874 
00875 void Lookout::setupSearch() {
00876   // point the head at expected object location, then start a spiral search
00877   LookoutSearchRequest *curSR = static_cast<LookoutSearchRequest*>(curReq);
00878   const ShapeRoot &target = curSR->targetShape;
00879   curSR->cindex = ProjectInterface::getColorIndex(target->getColor());
00880   Point egoLoc = target->getCentroid();
00881   if ( target->getRefFrameType() == allocentric ) {
00882     egoLoc.applyTransform(VRmixin::mapBuilder->worldToLocalMatrix, egocentric);
00883   }
00884   cout << "Lookout: search target estimated at " << egoLoc << ", color=" << curSR->cindex << endl;
00885   erouter->addListener(this, EventBase::visRegionEGID,ProjectInterface::visRegionSID,EventBase::deactivateETID);
00886   successSave = MMAccessor<HeadPointerMC>(pointer_id)->lookAtPoint(egoLoc.coordX(), egoLoc.coordY(), egoLoc.coordZ());
00887   motman->setPriority(pointer_id,MotionManager::kStdPriority);
00888   trackerState = moveToAcquire;
00889 }
00890 
00891 void Lookout::processSearchEvent(const EventBase &ev) {
00892   //  cout << "Lookout::processSearchEvent: " << ev.getDescription() << endl;
00893   LookoutSearchRequest *curSR = static_cast<LookoutSearchRequest*>(curReq);
00894   switch ( ev.getGeneratorID() ) {
00895 
00896   case EventBase::motmanEGID:
00897     if ( ev.getSourceID() == pointer_id || ev.getSourceID() == sequence_id )
00898       erouter->addTimer(this, settle_timer, 500, false);
00899     else
00900       return;
00901     break;
00902 
00903   case EventBase::visRegionEGID: {
00904     if ( trackerState == centering ) {
00905       curSR->image.bind(VRmixin::sketchFromSeg());
00906       curSR->toBaseMatrix = kine->linkToBase(curSR->joint);
00907       requestComplete(successSave);
00908       return;
00909     }
00910     const color_class_state *ccs = reinterpret_cast<const CMVision::color_class_state*>
00911       (ProjectInterface::defRegionGenerator->getImage(ProjectInterface::fullLayer,0));
00912     const color_class_state &col = ccs[curSR->cindex];
00913     // insert test to see if desired object has been seen:
00914     if ( col.list != NULL && col.list->area >= curSR->minBlobArea ) 
00915       erouter->removeListener(this,EventBase::visRegionEGID);
00916     else
00917       return;
00918     // test succeeded
00919     const Point center = findLocationFor(col.list);
00920     cout << "Lookout: search result groundpoint = " << center
00921    << "   area = " << col.list->area << "  color = " << curSR->cindex << endl;
00922     MMAccessor<HeadPointerMC>(pointer_id)->lookAtPoint(center.coordX(),center.coordY(),center.coordZ());
00923     motman->setPriority(pointer_id,MotionManager::kStdPriority);
00924     // motman->setPriority(pointer_id,MotionManager::kIgnoredPriority);
00925     motman->setPriority(posture_id,MotionManager::kIgnoredPriority);
00926     motman->setPriority(sequence_id,MotionManager::kIgnoredPriority);
00927     trackerState = centering;
00928     erouter->removeListener(this, EventBase::visRegionEGID);
00929     erouter->addTimer(this, settle_timer, 500, false);
00930     break;
00931   }
00932 
00933   case EventBase::timerEGID:
00934     switch ( trackerState ) {
00935     case moveToAcquire:  // camera has settled, so start the search
00936       triggerSearchMotionSequence();
00937       break;
00938     case searching:
00939     case centering:      // camera has settled, so grab a picture and return
00940       erouter->addListener(this, EventBase::visRegionEGID,
00941          ProjectInterface::visRegionSID,EventBase::statusETID);
00942       break;
00943     default:
00944       break;
00945     }
00946 
00947   default:
00948     break;
00949   }
00950 }
00951 
00952 void Lookout::triggerSearchMotionSequence() {
00953   cout << "Lookout: beginning search motion sequence" << endl;
00954   const LookoutSearchRequest *curSR = static_cast<const LookoutSearchRequest*>(curReq);
00955   const ShapeRoot &target = curSR->targetShape;
00956   Point egoLoc = target->getCentroid();
00957   if ( target->getRefFrameType() == allocentric ) {
00958     egoLoc.applyTransform(VRmixin::mapBuilder->worldToLocalMatrix, egocentric);
00959   }
00960   int const nspirals = 5;
00961   float const xstep=50, ystep=100;
00962   HeadPointerMC hpmc_temp;
00963   std::vector<float> jointvals(0);
00964   jointvals.reserve(nspirals*4*NumHeadJoints);
00965   for (int i=1; i<=nspirals; i++) {
00966     searchAt(hpmc_temp,jointvals,egoLoc+Point(-i*xstep,        0));
00967     searchAt(hpmc_temp,jointvals,egoLoc+Point(      0,   i*ystep));
00968     searchAt(hpmc_temp,jointvals,egoLoc+Point( i*xstep,        0));
00969     searchAt(hpmc_temp,jointvals,egoLoc+Point(       0, -i*ystep));
00970   }
00971   // Calculate all the joint positions first (above), then lock the
00972   // motionsequence command and quickly copy them over.
00973   MMAccessor<MediumMotionSequenceMC> mseq_acc(sequence_id);
00974   mseq_acc->clear();
00975 #ifdef TGT_HAS_HEAD
00976   for ( std::vector<float>::const_iterator it = jointvals.begin(); it != jointvals.end(); ) {
00977     mseq_acc->advanceTime(800);
00978     for(unsigned int i=0; i<NumHeadJoints; ++i)
00979       mseq_acc->setOutputCmd(HeadOffset+i,*(it++));
00980   }
00981   mseq_acc->advanceTime(800);
00982 #endif
00983   mseq_acc->play();
00984   motman->setPriority(sequence_id,MotionManager::kStdPriority);
00985   trackerState = searching;
00986 }
00987 
00988 void Lookout::searchAt(HeadPointerMC &hpmc_temp,
00989            std::vector<float> &jointvals,
00990            const Point &target) {
00991   hpmc_temp.lookAtPoint(target.coordX() ,target.coordY() ,target.coordZ());
00992   for(unsigned int i=0; i<NumHeadJoints; ++i)
00993     jointvals.push_back(hpmc_temp.getJointValue(i));
00994 }
00995 
00996 } // namespace

Tekkotsu v5.1CVS
Generated Sat May 4 06:32:52 2013 by Doxygen 1.6.3