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   setDirty();
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   setDirty();
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   setDirty();
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->worldToLocalMatrix * p2.getCoords();
00156       p2.setCoords(q[0], q[1], q[2]);
00157     }
00158       // fall through to next case
00159     case DualCoding::egocentric:
00160     case DualCoding::unspecified:  // assume egocentric
00161       return lookAtPoint(p2.coordX(), p2.coordY(), p2.coordZ());
00162   }
00163   cerr << "Error: HeadPointerMC::lookAtPoint given DualCoding::Point with invalid reference frame " << p2.getRefFrameType() << endl;
00164   return false; // only happens if invalid reference frame was set (compiler warning if we leave this off)
00165 }
00166 
00167 bool HeadPointerMC::lookAtPoint(const fmat::Column<3> &p) {
00168   return lookAtPoint(p[0], p[1], p[2]);
00169 }
00170 
00171 bool HeadPointerMC::lookAtPoint(float x, float y, float z, float d) {
00172 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00173   return false;
00174 #else
00175   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00176   if(kinEff==NULL) {// if that didn't work, give up
00177     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00178     return false;
00179   }
00180   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00181   std::auto_ptr<KinematicJoint> root(effector->getRoot());
00182   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00183   // effector->pullAncestorsQFromArray(state->outputs);
00184   
00185   bool conv = effector->getIK().solve(IKSolver::Point(0,0,d),*effector,IKSolver::Point(x,y,z));
00186   do {
00187     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00188       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00189     effector = effector->getParent();
00190   } while(effector!=NULL);
00191   setDirty();
00192   
00193   return conv;
00194 #endif
00195 }
00196   
00197 bool HeadPointerMC::lookInDirection(float x, float y, float z) {
00198 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00199   return false;
00200 #else
00201   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00202   if(kinEff==NULL) {// if that didn't work, give up
00203     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00204     return false;
00205   }
00206   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00207   std::auto_ptr<KinematicJoint> root(effector->getRoot());
00208   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00209   // effector->pullAncestorsQFromArray(state->outputs);
00210   
00211   bool conv = effector->getIK().solve(IKSolver::Rotation(),*effector,IKSolver::Parallel(x,y,z));
00212   do {
00213     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00214       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00215     effector = effector->getParent();
00216   } while(effector!=NULL);
00217   setDirty();
00218   
00219   return conv;
00220 #endif
00221 }
00222 
00223 bool HeadPointerMC::lookAtJoint(unsigned int j) {
00224   const fmat::Column<3> jointPos = kine->linkToBase(j).translation();
00225   return lookAtPoint(jointPos);
00226 }
00227 
00228 int HeadPointerMC::updateOutputs() {
00229   int tmp=isDirty();
00230   if(tmp || hold) {
00231     dirty=false;
00232 #ifdef TGT_HAS_HEAD
00233     for(unsigned int i=0; i<NumHeadJoints; i++) {
00234       if(maxSpeed[i]<=0) {
00235         headCmds[i].value=headTargets[i];
00236         motman->setOutput(this,i+HeadOffset,headCmds[i]);
00237       } else { // we may be trying to exceeded maxSpeed
00238         unsigned int f=0;
00239         while(headTargets[i]>headCmds[i].value+maxSpeed[i] && f<NumFrames) {
00240           headCmds[i].value+=maxSpeed[i];                                        
00241           motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00242           f++;
00243         }
00244         while(headTargets[i]<headCmds[i].value-maxSpeed[i] && f<NumFrames) {
00245           headCmds[i].value-=maxSpeed[i];
00246                                         motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00247           f++;
00248         }
00249         if(f<NumFrames) { //we reached target value, fill in rest of frames
00250           headCmds[i].value=headTargets[i];
00251           for(;f<NumFrames;f++)
00252             motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00253         } else // we didn't reach target value, still dirty
00254           dirty=true;
00255       }
00256     }
00257 #endif
00258     if(!dirty && !targetReached) {
00259       postEvent(EventBase(EventBase::motmanEGID, getID(),EventBase::statusETID));
00260       targetReached=true;
00261       targetTimestamp=get_time();
00262     }
00263   }
00264   return tmp;
00265 }
00266 
00267 int HeadPointerMC::isAlive() {
00268 #ifndef TGT_HAS_HEAD
00269   return false;
00270 #else
00271   if(dirty || !targetReached)
00272     return true;
00273   if(targetReached && (!hold || get_time()-targetTimestamp>timeout)) { //prevents a conflicted HeadPointerMC's from fighting forever
00274     if(get_time()-targetTimestamp>timeout && getAutoPrune())
00275       serr->printf("WARNING: HeadPointerMC (mcid %d) timed out - possible joint conflict or out-of-range target\n",getID());
00276     return false;
00277   }
00278   float maxdiff=0;
00279   for(unsigned int i=0; i<NumHeadJoints; i++) {
00280     float diff=fabsf(state->outputs[HeadOffset+i]-headTargets[i]);
00281     if(diff>maxdiff)
00282       maxdiff=diff;
00283   }
00284   return (maxdiff>tolerance);
00285 #endif
00286 }
00287 
00288 void HeadPointerMC::setDirty() {
00289   dirty=true;
00290   targetReached=false;
00291 #ifdef TGT_HAS_HEAD
00292   for(unsigned int i=0; i<NumHeadJoints; i++)
00293     headCmds[i].value=motman->getOutputCmd(HeadOffset+i).value; //not state->outputs[HeadOffset+i]; - see function documentation
00294 #endif
00295 }
00296 
00297 bool HeadPointerMC::ensureValidJoint(unsigned int& i) {
00298 #ifndef TGT_HAS_HEAD
00299   serr->printf("ERROR: HeadPointerMC received a joint index of %d on headless target.\n",i);
00300 #else
00301   if(i<NumHeadJoints)
00302     return true;
00303   if(i>=HeadOffset && i<HeadOffset+NumHeadJoints) {
00304     i-=HeadOffset;
00305     serr->printf("WARNING: HeadPointerMC received a joint index of %d (HeadOffset+%d).\n",i+HeadOffset,i);
00306     serr->printf("         Since all parameters are assumed to be relative to HeadOffset,\n");
00307     serr->printf("         you should just pass %d directly.\n",i);
00308     serr->printf("WARNING: Assuming you meant %d...\n",i);
00309     return true;
00310   }
00311   serr->printf("ERROR: HeadPointerMC received a joint index of %d (HeadOffset%+d).\n",i,i-HeadOffset);
00312   serr->printf("ERROR: This does not appear to be a head joint.  HeadPointerMC only controls\n");
00313   serr->printf("       head joints, and assumes its arguments are relative to HeadOffset\n");
00314 #endif
00315   return false;
00316 }
00317 
00318 /*! @file
00319  * @brief Implements HeadPointerMC, a class for various ways to control where the head is looking
00320  * @author ejt (Creator)
00321  *
00322  */

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