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 pan, float tilt) {
00075   headTargets[PanOffset]=clipAngularRange(HeadOffset+PanOffset,pan);
00076   headTargets[TiltOffset]=clipAngularRange(HeadOffset+TiltOffset,tilt);
00077 }
00078 
00079 void HeadPointerMC::setJoints(float tilt1, float pan, float tilt2) {
00080 #ifdef TGT_HAS_HEAD
00081 #ifdef TGT_IS_AIBO
00082   headTargets[TiltOffset]=clipAngularRange(HeadOffset+TiltOffset,tilt1);
00083   headTargets[PanOffset]=clipAngularRange(HeadOffset+PanOffset,pan);
00084   headTargets[NodOffset]=clipAngularRange(HeadOffset+NodOffset,tilt2);
00085 #else
00086   const char* n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::TiltOffset];
00087   unsigned int i = capabilities.findOutputOffset(n);
00088   if(i!=-1U)
00089     headTargets[i-HeadOffset]=clipAngularRange(i,tilt1);
00090   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::PanOffset];
00091   i = capabilities.findOutputOffset(n);
00092   if(i!=-1U)
00093     headTargets[i-HeadOffset]=clipAngularRange(i,pan);
00094   n = ERS7Info::outputNames[ERS7Info::HeadOffset+ERS7Info::NodOffset];
00095   i = capabilities.findOutputOffset(n);
00096   if(i!=-1U)
00097     headTargets[i-HeadOffset]=clipAngularRange(i,tilt2);
00098 #endif
00099   setDirty();
00100 #endif
00101 }
00102 
00103 void HeadPointerMC::setJoints(float pan, float shoulder, float elbow, float pitch) {
00104         setMaxSpeed(0, 0.2f);
00105         setMaxSpeed(1, 0.2f);
00106         setMaxSpeed(2, 0.2f);
00107         setMaxSpeed(3, 0.2f);
00108         setJointValue(0, pan);  
00109   setJointValue(1, shoulder); 
00110   setJointValue(2, elbow);  
00111   setJointValue(3, pitch);  
00112 }
00113 
00114 #include <iostream>
00115 using namespace std;
00116 
00117 bool HeadPointerMC::lookAtPoint(float x, float y, float z) {
00118 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00119   return false;
00120 #else
00121   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00122   if(kinEff==NULL) {// if that didn't work, give up
00123     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00124     return false;
00125   }
00126   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00127   std::unique_ptr<KinematicJoint> root(effector->getRoot()); // auto-free the cloned branch when leaving scope
00128   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00129   // effector->pullAncestorsQFromArray(state->outputs);
00130   
00131   // make the camera into a mobile prismatic joint
00132   effector->qmax = std::numeric_limits<float>::infinity();
00133   
00134   bool conv = effector->getIK().solve(IKSolver::Point(),*effector,IKSolver::Point(x,y,z));
00135   do {
00136     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00137       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00138     effector = effector->getParent();
00139   } while(effector!=NULL);
00140   setDirty();
00141   
00142   return conv;
00143 #endif
00144 
00145 }
00146 
00147 bool HeadPointerMC::lookAtPoint(const DualCoding::Point &p) {
00148   DualCoding::Point p2 = p;
00149   switch ( p2.getRefFrameType() ) {
00150     case DualCoding::camcentric:
00151       // technically we could probably do something here based on aligning camera z with ray through the specified point...
00152       cout << "Error:  HeadPointerMC::lookAtPoint cannot accept point " << p2 << " in camera-centric coordinates\n";
00153       return false;
00154     case DualCoding::allocentric: {
00155       if ( DualCoding::VRmixin::mapBuilder == NULL ) {
00156         cout << "Error: HeadPointerMC:lookAtPoint can't convert allocentric point " << p2
00157         << " to egocentric because MapBuilder is not running\n";
00158         return false;
00159       }
00160       fmat::Column<3> q = DualCoding::VRmixin::mapBuilder->worldToLocalMatrix * p2.getCoords();
00161       p2.setCoords(q[0], q[1], q[2]);
00162     }
00163       // fall through to next case
00164     case DualCoding::egocentric:
00165     case DualCoding::unspecified:  // assume egocentric
00166       return lookAtPoint(p2.coordX(), p2.coordY(), p2.coordZ());
00167   }
00168   cerr << "Error: HeadPointerMC::lookAtPoint given DualCoding::Point with invalid reference frame " << p2.getRefFrameType() << endl;
00169   return false; // only happens if invalid reference frame was set (compiler warning if we leave this off)
00170 }
00171 
00172 bool HeadPointerMC::lookAtPoint(const fmat::Column<3> &p) {
00173   return lookAtPoint(p[0], p[1], p[2]);
00174 }
00175 
00176 bool HeadPointerMC::lookAtPoint(float x, float y, float z, float d) {
00177 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00178   return false;
00179 #else
00180   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00181   if(kinEff==NULL) {// if that didn't work, give up
00182     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00183     return false;
00184   }
00185   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00186   std::unique_ptr<KinematicJoint> root(effector->getRoot());
00187   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00188   // effector->pullAncestorsQFromArray(state->outputs);
00189   
00190   bool conv = effector->getIK().solve(IKSolver::Point(0,0,d),*effector,IKSolver::Point(x,y,z));
00191   do {
00192     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00193       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00194     effector = effector->getParent();
00195   } while(effector!=NULL);
00196   setDirty();
00197   
00198   return conv;
00199 #endif
00200 }
00201   
00202 bool HeadPointerMC::lookInDirection(float x, float y, float z) {
00203 #if !defined(TGT_HAS_HEAD) || !defined(TGT_HAS_CAMERA)
00204   return false;
00205 #else
00206   const KinematicJoint * kinEff = kine->getKinematicJoint(CameraFrameOffset);
00207   if(kinEff==NULL) {// if that didn't work, give up
00208     cout<<"HeadPointerMC: Could not find CameraFrameOffset"<<endl;
00209     return false;
00210   }
00211   KinematicJoint * effector = kinEff->cloneBranch(); // make a local copy so we can do thread-safe IK
00212   std::unique_ptr<KinematicJoint> root(effector->getRoot());
00213   // kine already updated KinematicJoint positions during getKinematicJoint call, otherwise we'd need this:
00214   // effector->pullAncestorsQFromArray(state->outputs);
00215   
00216   bool conv = effector->getIK().solve(IKSolver::Rotation(),*effector,IKSolver::Parallel(x,y,z));
00217   do {
00218     if(effector->outputOffset>=HeadOffset && effector->outputOffset<HeadOffset+NumHeadJoints)
00219       headTargets[effector->outputOffset - HeadOffset] = effector->getQ();
00220     effector = effector->getParent();
00221   } while(effector!=NULL);
00222   setDirty();
00223   
00224   return conv;
00225 #endif
00226 }
00227 
00228 bool HeadPointerMC::lookAtJoint(unsigned int j) {
00229   const fmat::Column<3> jointPos = kine->linkToBase(j).translation();
00230   return lookAtPoint(jointPos);
00231 }
00232 
00233 int HeadPointerMC::updateOutputs() {
00234   int tmp=isDirty();
00235   if(tmp || hold) {
00236     dirty=false;
00237 #ifdef TGT_HAS_HEAD
00238     for(unsigned int i=0; i<NumHeadJoints; i++) {
00239       if(maxSpeed[i]<=0) {
00240         headCmds[i].value=headTargets[i];
00241         motman->setOutput(this,i+HeadOffset,headCmds[i]);
00242       } else { // we may be trying to exceeded maxSpeed
00243         unsigned int f=0;
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         while(headTargets[i]<headCmds[i].value-maxSpeed[i] && f<NumFrames) {
00250           headCmds[i].value-=maxSpeed[i];
00251                                         motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00252           f++;
00253         }
00254         if(f<NumFrames) { //we reached target value, fill in rest of frames
00255           headCmds[i].value=headTargets[i];
00256           for(;f<NumFrames;f++)
00257             motman->setOutput(this,i+HeadOffset,headCmds[i],f);
00258         } else // we didn't reach target value, still dirty
00259           dirty=true;
00260       }
00261     }
00262 #endif
00263     if(!dirty && !targetReached) {
00264       postEvent(EventBase(EventBase::motmanEGID, getID(),EventBase::statusETID));
00265       targetReached=true;
00266       targetTimestamp=get_time();
00267     }
00268   }
00269   return tmp;
00270 }
00271 
00272 int HeadPointerMC::isAlive() {
00273 #ifndef TGT_HAS_HEAD
00274   return false;
00275 #else
00276   if(dirty || !targetReached)
00277     return true;
00278   if(targetReached && (!hold || get_time()-targetTimestamp>timeout)) { //prevents a conflicted HeadPointerMC's from fighting forever
00279     if(get_time()-targetTimestamp>timeout && getAutoPrune())
00280       serr->printf("WARNING: HeadPointerMC (mcid %d) timed out - possible joint conflict or out-of-range target\n",getID());
00281     return false;
00282   }
00283   float maxdiff=0;
00284   for(unsigned int i=0; i<NumHeadJoints; i++) {
00285     float diff=fabsf(state->outputs[HeadOffset+i]-headTargets[i]);
00286     if(diff>maxdiff)
00287       maxdiff=diff;
00288   }
00289   return (maxdiff>tolerance);
00290 #endif
00291 }
00292 
00293 void HeadPointerMC::setDirty() {
00294   dirty=true;
00295   targetReached=false;
00296 #ifdef TGT_HAS_HEAD
00297   for(unsigned int i=0; i<NumHeadJoints; i++)
00298     headCmds[i].value=motman->getOutputCmd(HeadOffset+i).value; //not state->outputs[HeadOffset+i]; - see function documentation
00299 #endif
00300 }
00301 
00302 bool HeadPointerMC::ensureValidJoint(unsigned int& i) {
00303 #ifndef TGT_HAS_HEAD
00304   serr->printf("ERROR: HeadPointerMC received a joint index of %d on headless target.\n",i);
00305 #else
00306   if(i<NumHeadJoints)
00307     return true;
00308   if(i>=HeadOffset && i<HeadOffset+NumHeadJoints) {
00309     i-=HeadOffset;
00310     serr->printf("WARNING: HeadPointerMC received a joint index of %d (HeadOffset+%d).\n",i+HeadOffset,i);
00311     serr->printf("         Since all parameters are assumed to be relative to HeadOffset,\n");
00312     serr->printf("         you should just pass %d directly.\n",i);
00313     serr->printf("WARNING: Assuming you meant %d...\n",i);
00314     return true;
00315   }
00316   serr->printf("ERROR: HeadPointerMC received a joint index of %d (HeadOffset%+d).\n",i,i-HeadOffset);
00317   serr->printf("ERROR: This does not appear to be a head joint.  HeadPointerMC only controls\n");
00318   serr->printf("       head joints, and assumes its arguments are relative to HeadOffset\n");
00319 #endif
00320   return false;
00321 }
00322 
00323 /*! @file
00324  * @brief Implements HeadPointerMC, a class for various ways to control where the head is looking
00325  * @author ejt (Creator)
00326  *
00327  */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:41 2016 by Doxygen 1.6.3