Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

WheeledWalkMC.cc

Go to the documentation of this file.
00001 #include "Shared/RobotInfo.h"
00002 #ifdef TGT_HAS_WHEELS
00003 
00004 #include "WheeledWalkMC.h"
00005 #include "Kinematics.h"
00006 #include "Events/LocomotionEvent.h"
00007 #include "Shared/Config.h"
00008 #include <sys/stat.h>
00009 
00010 using namespace std; 
00011 
00012 static const float EPSILON=1e-4f;
00013 
00014 void WheeledWalkMC::resetConfig() {
00015   updateWheelInfo();
00016   // default to going half maximum speed
00017   preferredXVel = getMaxXVel() / 2;
00018   preferredYVel = getMaxYVel() / 2;
00019   preferredAngVel = getMaxAVel() / 2;
00020   // check if a config file is available
00021   std::string file = config->motion.makePath("wheeledwalk.plist");
00022   struct stat statbuf;
00023   if(::stat(file.c_str(),&statbuf)==0)
00024     loadFile(file.c_str()); // override with settings from file
00025 }
00026 
00027 int WheeledWalkMC::updateOutputs() {
00028   unsigned int t = get_time();
00029   unsigned int dur = t - travelTime;
00030   if(!dirty) {
00031     if(displacementMode && dur>=travelDur) {
00032       // Must use zeroVelocities() here, not
00033       // setTargetVelocity, because we must post a
00034       // locomotionEvent to let Mirage know we're stopping.
00035         zeroVelocities();
00036       postEvent(EventBase(EventBase::motmanEGID, getID(), EventBase::statusETID, dur));
00037     }
00038     if(targetVel[0]==0 && targetVel[1]==0 && targetAngVel==0)
00039       return 0;
00040   }
00041   if(dirty) {
00042     LocomotionEvent e(EventBase::locomotionEGID, getID(), EventBase::statusETID, dur);
00043     e.setXYA(targetVel[0], targetVel[1], targetAngVel);
00044     travelTime = t;
00045     postEvent(e);
00046   }
00047   for(unsigned int i=0; i<NumWheels; ++i) {
00048     if(wheels[i].valid) {
00049       motman->setOutput(this, WheelOffset+i, wheels[i].targetVel);
00050     }
00051   }
00052   dirty=false;
00053   return NumWheels;
00054 }
00055 
00056 void WheeledWalkMC::start() {
00057   dirty=true;
00058   travelTime=get_time();
00059 }
00060 
00061 void WheeledWalkMC::stop() {
00062   zeroVelocities();
00063   MotionCommand::stop();
00064 }
00065 
00066 void WheeledWalkMC::zeroVelocities() {
00067   if(targetVel[0]==0 && targetVel[1]==0 && targetAngVel==0)
00068     return;
00069   unsigned int t = getTravelTime(); // cache because travelTime is about to be reset
00070   setTargetVelocity(0, 0, 0);
00071   for (unsigned int i = WheelOffset; i < WheelOffset + NumWheels; i++)
00072     motman->setOutput(this, i, 0.0f);
00073   postEvent(LocomotionEvent(EventBase::locomotionEGID, getID(), EventBase::statusETID, t));
00074 }
00075 
00076 void WheeledWalkMC::setTargetVelocity(float xvel, float yvel, float avel) {
00077   displacementMode=false;
00078   if(std::abs(targetVel[0]-xvel)<0.01f && std::abs(targetVel[1]-yvel)<0.01f && std::abs(targetAngVel-avel)<0.001f)
00079     return; // don't bother with updates (and in particular, associated LocomotionEvents) from small rounding errors
00080   targetVel[0] = xvel;
00081   targetVel[1] = yvel;
00082   targetAngVel = avel;
00083   updateWheelVels();
00084 }
00085 
00086 void WheeledWalkMC::setTargetVelocity(float xvel, float yvel, float avel, float time) {
00087   displacementMode=true;
00088   if(time<=0 || (xvel==0 && yvel==0 && avel==0) ) {
00089     targetVel[0] = targetVel[1] = targetAngVel = 0;
00090     travelDur = 0;
00091   } else {
00092     targetVel[0] = xvel;
00093     targetVel[1] = yvel;
00094     targetAngVel = avel;
00095     travelDur = static_cast<unsigned int>(time*1000 + 0.5);
00096   }
00097   updateWheelVels();
00098 }
00099 
00100 void WheeledWalkMC::setTargetDisplacement(float xdisp, float ydisp, float adisp, float time) {
00101   // std::cout << (void*)(this) << ":id=" << getID() <<"   setTargetDisplacement(" << xdisp << ", " << ydisp << ", " << adisp << ")" << std::endl;
00102   if ( xdisp == 0 && ydisp == 0 && adisp == 0 ) {
00103     setTargetVelocity(0, 0, 0, 0);
00104     return;
00105   }
00106   
00107   // select preferred velocity if time==0, otherwise cap at maximum
00108   float xCap=getMaxXVel(), yCap=getMaxYVel(), aCap=getMaxAVel();
00109   if(time==0) {
00110     if(xCap>preferredXVel) xCap = preferredXVel;
00111     if(yCap>preferredYVel) yCap = preferredYVel;
00112     if(aCap>preferredAngVel) aCap = preferredAngVel;
00113   }
00114   
00115   // test each cap, may be constrained - set to 0
00116   const float tx = xCap>0 ? std::abs(xdisp/xCap) : 0;
00117   const float ty = yCap>0 ? std::abs(ydisp/yCap) : 0;
00118   const float ta = aCap>0 ? std::abs(adisp/aCap) : 0;
00119   float maxTime =  std::max(time,std::max(tx,std::max(ty,ta)));
00120   
00121   // round up to closest FrameTime * NumFrames multiple for even better precision
00122   maxTime = std::ceil(maxTime * 1000 / (FrameTime*NumFrames)) * (FrameTime*NumFrames) / 1000.f;
00123   
00124   setTargetVelocity(xdisp/maxTime, ydisp/maxTime, adisp/maxTime, maxTime);
00125 }
00126 
00127 void WheeledWalkMC::updateWheelInfo() {
00128   fmat::Column<2> wheelSum;
00129   unsigned int avail=0;
00130   
00131   // find position and orientation of each joint
00132   for(unsigned int i=0; i<NumWheels; ++i) {
00133     fmat::Transform t = kine->linkToBase(WheelOffset+i);
00134     wheels[i].direction = fmat::pack(t(1,2),-t(0,2));
00135     fmat::fmatReal dm=wheels[i].direction.norm();
00136     if(dm<std::numeric_limits<float>::epsilon()*10) {
00137       std::cerr << "WARNING: " << outputNames[WheelOffset+i] << " has a vertical axle, ignoring it" << std::endl;
00138       wheels[i].direction=0.f;
00139       continue; // wheel is on its side, does not contribute
00140     } else if(dm<1-std::numeric_limits<float>::epsilon()*10) {
00141       // this could be supported, just need to compute position at contact with ground
00142       std::cerr << "WARNING: " << outputNames[WheelOffset+i] << " has a non-planar axle, this may affect motion accuracy" << std::endl;
00143     }
00144     wheels[i].direction/=dm;
00145     wheels[i].position = fmat::SubVector<2>(t.translation());
00146     wheelSum+=wheels[i].position;
00147     ++avail;
00148     wheels[i].valid=true;
00149   }
00150   center = wheelSum / avail;
00151   
00152   maxVel = (NumWheels==0) ? 0 : std::numeric_limits<fmat::fmatReal>::infinity();
00153   maxAngVel=0.f;
00154   for(unsigned int i=0; i<NumWheels; ++i) {
00155     if(!wheels[i].valid)
00156       continue;
00157     
00158     // maximum velocity is the minimum full-power wheel contribution
00159     float v = std::min(std::abs(outputRanges[WheelOffset+i][0]),std::abs(outputRanges[WheelOffset+i][1]));
00160     fmat::Column<2> d = wheels[i].direction*v;
00161     maxVel[0] = std::min(maxVel[0],d[0]);
00162     maxVel[1] = std::min(maxVel[1],d[1]);
00163     
00164     // maximum rotation is sum of contributions
00165     fmat::Column<2> curCof = (wheelSum - wheels[i].position) / (avail-1);
00166     fmat::Column<2> norm = (wheels[i].position - curCof);
00167     norm -= fmat::dotProduct(wheels[i].direction,norm) * wheels[i].direction;
00168     float base = norm.norm();
00169     const float MAX_ROT = M_PI*3; // limit crazy rotational speeds in case of short base
00170     float av = (base*MAX_ROT > v ) ? v / base : 0; // send limit to zero because centrally applied instead of inf. rotation
00171     maxAngVel += av;
00172   }
00173   
00174   if(targetVel[0]!=0 || targetVel[1]!=0 || targetAngVel!=0)
00175     updateWheelVels();
00176   
00177   /*
00178   for(unsigned int i=0; i<NumWheels; ++i)
00179     std::cout << "Wheel " << i << " at " << wheels[i].position << " facing " << wheels[i].direction << std::endl;
00180   std::cout << "Max velocity: " << maxVel[0] << ' ' << maxVel[1] << ' ' << maxAngVel << std::endl;
00181   */
00182 }
00183 
00184 void WheeledWalkMC::updateWheelVels() {
00185   if (std::abs(targetAngVel) <= targetVel.norm()*EPSILON) {
00186     // straight line motion
00187     for(unsigned int i=0; i<NumWheels; ++i) {
00188       if(!wheels[i].valid)
00189         continue;
00190       wheels[i].targetVel = fmat::dotProduct(wheels[i].direction,targetVel);
00191     }
00192   } else {
00193     // arcing motion, rotate target point about the previously determined center of rotation
00194     fmat::Column<2> rotationCenter = fmat::pack(-targetVel[1],targetVel[0]) / targetAngVel + center;
00195     for(unsigned int i=0; i<NumWheels; ++i) {
00196       if(!wheels[i].valid)
00197         continue;
00198       fmat::Column<2> p = wheels[i].position - rotationCenter;
00199       wheels[i].targetVel = fmat::dotProduct(wheels[i].direction,fmat::pack(-p[1],p[0])) * targetAngVel;
00200     }
00201   }
00202   dirty = true;
00203 } 
00204 
00205 /*! @file
00206  * @brief Impliments WheeledWalkMC, which provides a 'WalkMC' implementation for wheeled robots (diff-drive or theoretically holonomic configurations as well)
00207  * @author Ethan Tira-Thompson (ejt) (Creator)
00208  */
00209 
00210 #endif

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