Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

HeadPointerMC.cc

Go to the documentation of this file.
00001 #include "HeadPointerMC.h"
00002 #include "Kinematics.h"
00003 #include "Shared/debuget.h"
00004 #include "Shared/WorldState.h"
00005 #include "MotionManager.h"
00006 #include "Shared/Config.h"
00007 #include "Wireless/Socket.h"
00008 #include "Shared/ERS7Info.h"
00009 #include "Shared/ERS210Info.h"
00010 #include "Motion/IKSolver.h"
00011 #include "Shared/get_time.h"
00012 #include "Events/EventBase.h"
00013 #include "DualCoding/VRmixin.h"
00014 #include "Crew/MapBuilder.h"
00015 #include "DualCoding/Point.h"
00016 
00017 #include <memory>
00018 #include <cmath>
00019 
00020 HeadPointerMC::HeadPointerMC()
00021   : MotionCommand(), dirty(true), hold(true), tolerance(.05f), // if change default tolerance, update documentation in header
00022     targetReached(true), targetTimestamp(0), timeout(2000)
00023 {
00024   setWeight(1);
00025   defaultMaxSpeed();
00026   takeSnapshot();
00027 }
00028 
00029 void HeadPointerMC::freezeMotion() {
00030 #ifdef TGT_HAS_HEAD
00031   for(unsigned int i=0; i<NumHeadJoints; i++)
00032     headTargets[i]=headCmds[i].value;
00033   dirty=false;
00034 #endif
00035 }
00036 
00037 void HeadPointerMC::takeSnapshot() {
00038 #ifdef TGT_HAS_HEAD
00039   for(unsigned int i=0; i<NumHeadJoints; i++)
00040     headTargets[i]=headCmds[i].value=state->outputs[HeadOffset+i];
00041   dirty=true;
00042 #endif
00043 }
00044 
00045 void HeadPointerMC::defaultMaxSpeed(float x/*=1*/) {
00046 #ifdef TGT_HAS_HEAD
00047   const char* n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::TiltOffset];
00048   unsigned int i = capabilities.findOutputOffset(n);
00049   if(i!=-1U)
00050     maxSpeed[i-HeadOffset]=config->motion.max_head_tilt_speed*FrameTime*x/1000;
00051   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::PanOffset];
00052   i = capabilities.findOutputOffset(n);
00053   if(i!=-1U)
00054     maxSpeed[i-HeadOffset]=config->motion.max_head_pan_speed*FrameTime*x/1000;
00055   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::NodOffset];
00056   i = capabilities.findOutputOffset(n);
00057   if(i!=-1U)
00058     maxSpeed[i-HeadOffset]=config->motion.max_head_roll_speed*FrameTime*x/1000;
00059   n = ERS210Info::outputNames[ERS210Info::HeadOffset+ERS210Info::RollOffset];
00060   i = capabilities.findOutputOffset(n);
00061   if(i!=-1U)
00062     maxSpeed[i-HeadOffset]=config->motion.max_head_roll_speed*FrameTime*x/1000;
00063 #endif
00064 }
00065 
00066 void HeadPointerMC::setWeight(float w) {
00067 #ifdef TGT_HAS_HEAD
00068   for(unsigned int x=0; x<NumHeadJoints; x++)
00069     headCmds[x].weight=w;
00070   markDirty();
00071 #endif
00072 }
00073 
00074 void HeadPointerMC::setJoints(float tilt1, float pan, float tilt2) {
00075 #ifdef TGT_HAS_HEAD
00076 #ifdef TGT_IS_AIBO
00077   headTargets[TiltOffset]=clipAngularRange(HeadOffset+TiltOffset,tilt1);
00078   headTargets[PanOffset]=clipAngularRange(HeadOffset+PanOffset,pan);
00079   headTargets[NodOffset]=clipAngularRange(HeadOffset+NodOffset,tilt2);
00080 #else
00081   const char* n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::TiltOffset];
00082   unsigned int i = capabilities.findOutputOffset(n);
00083   if(i!=-1U)
00084     headTargets[i-HeadOffset]=clipAngularRange(i,tilt1);
00085   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::PanOffset];
00086   i = capabilities.findOutputOffset(n);
00087   if(i!=-1U)
00088     headTargets[i-HeadOffset]=clipAngularRange(i,pan);
00089   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::NodOffset];
00090   i = capabilities.findOutputOffset(n);
00091   if(i!=-1U)
00092     headTargets[i-HeadOffset]=clipAngularRange(i,tilt2);
00093 #endif
00094   markDirty();
00095 #endif
00096 }
00097 
00098 void HeadPointerMC::setJoints(float pan, float shoulder, float elbow, float pitch) {
00099         setMaxSpeed(0, 0.2f);
00100         setMaxSpeed(1, 0.2f);
00101         setMaxSpeed(2, 0.2f);
00102         setMaxSpeed(3, 0.2f);
00103         setJointValue(0, pan);  
00104   setJointValue(1, shoulder); 
00105   setJointValue(2, elbow);  
00106   setJointValue(3, pitch);  
00107 }
00108 
00109 #include <iostream>
00110 using namespace std;
00111 
00112 bool HeadPointerMC::lookAtPoint(float x, float y, float z) {
00113 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00114   return false;
00115 #else
00116   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00117   if(kinEff==NULL) {// if that didn't work, give up
00118     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00119     return false;
00120   }
00121   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00122   std::auto_ptr<KinematicJoint> root(effector->getRoot()); // auto-free the cloned branch when leaving scope
00123   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00124   // effector->pullAncestorsQFromArray(state->outputs);
00125   
00126   // make the camera into a mobile prismatic joint
00127   effector->qmax = std::numeric_limits<float>::infinity();
00128   
00129   bool conv = effector->getIK().solve(IKSolver::Point(),*effector,IKSolver::Point(x,y,z));
00130   do {
00131     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00132       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00133     effector = effector->getParent();
00134   } while(effector!=NULL);
00135   markDirty();
00136   
00137   return conv;
00138 #endif
00139 
00140 }
00141 
00142 bool HeadPointerMC::lookAtPoint(const DualCoding::Point &p) {
00143   DualCoding::Point p2 = p;
00144   switch ( p2.getRefFrameType() ) {
00145     case DualCoding::camcentric:
00146       // technically we could probably do something here based on aligning camera z with ray through the specified point...
00147       cout << "Error:  HeadPointerMC::lookAtPoint cannot accept point " << p2 << " in camera-centric coordinates\n";
00148       return false;
00149     case DualCoding::allocentric: {
00150       if ( DualCoding::VRmixin::mapBuilder == NULL ) {
00151         cout << "Error: HeadPointerMC:lookAtPoint can't convert allocentric point " << p2
00152         << " to egocentric because MapBuilder is not running\n";
00153         return false;
00154       }
00155       fmat::Column<3> q = DualCoding::VRmixin::mapBuilder->worldToLocalRotateMatrix
00156       * (DualCoding::VRmixin::mapBuilder->worldToLocalTranslateMatrix * p2.getCoords());
00157       p2.setCoords(q[0], q[1], q[2]);
00158     }
00159       // fall through to next case
00160     case DualCoding::egocentric:
00161     case DualCoding::unspecified:  // assume egocentric
00162       return lookAtPoint(p2.coordX(), p2.coordY(), p2.coordZ());
00163   }
00164   cerr << "Error: HeadPointerMC::lookAtPoint given DualCoding::Point with invalid reference frame " << p2.getRefFrameType() << endl;
00165   return false; // only happens if invalid reference frame was set (compiler warning if we leave this off)
00166 }
00167 
00168 bool HeadPointerMC::lookAtPoint(float x, float y, float z, float d) {
00169 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00170   return false;
00171 #else
00172   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00173   if(kinEff==NULL) {// if that didn't work, give up
00174     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00175     return false;
00176   }
00177   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00178   std::auto_ptr<KinematicJoint> root(effector->getRoot());
00179   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00180   // effector->pullAncestorsQFromArray(state->outputs);
00181   
00182   bool conv = effector->getIK().solve(IKSolver::Point(0,0,d),*effector,IKSolver::Point(x,y,z));
00183   do {
00184     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00185       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00186     effector = effector->getParent();
00187   } while(effector!=NULL);
00188   markDirty();
00189   
00190   return conv;
00191 #endif
00192 }
00193   
00194 bool HeadPointerMC::lookInDirection(float x, float y, float z) {
00195 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00196   return false;
00197 #else
00198   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00199   if(kinEff==NULL) {// if that didn't work, give up
00200     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00201     return false;
00202   }
00203   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00204   std::auto_ptr<KinematicJoint> root(effector->getRoot());
00205   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00206   // effector->pullAncestorsQFromArray(state->outputs);
00207   
00208   bool conv = effector->getIK().solve(IKSolver::Rotation(),*effector,IKSolver::Parallel(x,y,z));
00209   do {
00210     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00211       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00212     effector = effector->getParent();
00213   } while(effector!=NULL);
00214   markDirty();
00215   
00216   return conv;
00217 #endif
00218 }
00219 
00220 
00221 int HeadPointerMC::updateOutputs() {
00222   int tmp=isDirty();
00223   if(tmp || hold) {
00224     dirty=false;
00225 #ifdef TGT_HAS_HEAD
00226     for(unsigned int i=0; i<NumHeadJoints; i++) {
00227       if(maxSpeed[i]<=0) {
00228         headCmds[i].value=headTargets[i];
00229         motman->setOutput(this,i+HeadOffset,headCmds[i]);
00230       } else { // we may be trying to exceeded maxSpeed
00231         unsigned int f=0;
00232         while(headTargets[i]>headCmds[i].value+maxSpeed[i] && f<NumFrames) {
00233           headCmds[i].value+=maxSpeed[i];                                        
00234           motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00235           f++;
00236         }
00237         while(headTargets[i]<headCmds[i].value-maxSpeed[i] && f<NumFrames) {
00238           headCmds[i].value-=maxSpeed[i];
00239                                         motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00240           f++;
00241         }
00242         if(f<NumFrames) { //we reached target value, fill in rest of frames
00243           headCmds[i].value=headTargets[i];
00244           for(;f<NumFrames;f++)
00245             motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00246         } else // we didn't reach target value, still dirty
00247           dirty=true;
00248       }
00249     }
00250 #endif
00251     if(!dirty && !targetReached) {
00252       postEvent(EventBase(EventBase::motmanEGID, getID(),EventBase::statusETID));
00253       targetReached=true;
00254       targetTimestamp=get_time();
00255     }
00256   }
00257   return tmp;
00258 }
00259 
00260 int HeadPointerMC::isAlive() {
00261 #ifndef TGT_HAS_HEAD
00262   return false;
00263 #else
00264   if(dirty || !targetReached)
00265     return true;
00266   if(targetReached && (!hold || get_time()-targetTimestamp>timeout)) { //prevents a conflicted HeadPointerMC's from fighting forever
00267     if(get_time()-targetTimestamp>timeout && getAutoPrune())
00268       serr->printf("WARNING: HeadPointerMC (mcid %d) timed out - possible joint conflict or out-of-range target\n",getID());
00269     return false;
00270   }
00271   float maxdiff=0;
00272   for(unsigned int i=0; i<NumHeadJoints; i++) {
00273     float diff=fabsf(state->outputs[HeadOffset+i]-headTargets[i]);
00274     if(diff>maxdiff)
00275       maxdiff=diff;
00276   }
00277   return (maxdiff>tolerance);
00278 #endif
00279 }
00280 
00281 void HeadPointerMC::markDirty() {
00282   dirty=true;
00283   targetReached=false;
00284 #ifdef TGT_HAS_HEAD
00285   for(unsigned int i=0; i<NumHeadJoints; i++)
00286     headCmds[i].value=motman->getOutputCmd(HeadOffset+i).value; //not state->outputs[HeadOffset+i]; - see function documentation
00287 #endif
00288 }
00289 
00290 bool HeadPointerMC::ensureValidJoint(unsigned int& i) {
00291 #ifndef TGT_HAS_HEAD
00292   serr->printf("ERROR: HeadPointerMC received a joint index of %d on headless target.\n",i);
00293 #else
00294   if(i<NumHeadJoints)
00295     return true;
00296   if(i>=HeadOffset && i<HeadOffset+NumHeadJoints) {
00297     i-=HeadOffset;
00298     serr->printf("WARNING: HeadPointerMC received a joint index of %d (HeadOffset+%d).\n",i+HeadOffset,i);
00299     serr->printf("         Since all parameters are assumed to be relative to HeadOffset,\n");
00300     serr->printf("         you should just pass %d directly.\n",i);
00301     serr->printf("WARNING: Assuming you meant %d...\n",i);
00302     return true;
00303   }
00304   serr->printf("ERROR: HeadPointerMC received a joint index of %d (HeadOffset%+d).\n",i,i-HeadOffset);
00305   serr->printf("ERROR: This does not appear to be a head joint.  HeadPointerMC only controls\n");
00306   serr->printf("       head joints, and assumes its arguments are relative to HeadOffset\n");
00307 #endif
00308   return false;
00309 }
00310 
00311 /*! @file
00312  * @brief Implements HeadPointerMC, a class for various ways to control where the head is looking
00313  * @author ejt (Creator)
00314  *
00315  */

Tekkotsu v5.1CVS
Generated Tue Jan 31 04:31:54 2012 by Doxygen 1.6.3