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

Tekkotsu v5.1CVS
Generated Fri Mar 16 05:26:43 2012 by Doxygen 1.6.3