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
00017 preferredXVel = getMaxXVel() / 2;
00018 preferredYVel = getMaxYVel() / 2;
00019 preferredAngVel = getMaxAVel() / 2;
00020
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());
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
00033
00034
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();
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;
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
00102 if ( xdisp == 0 && ydisp == 0 && adisp == 0 ) {
00103 setTargetVelocity(0, 0, 0, 0);
00104 return;
00105 }
00106
00107
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
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
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
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;
00140 } else if(dm<1-std::numeric_limits<float>::epsilon()*10) {
00141
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
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
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;
00170 float av = (base*MAX_ROT > v ) ? v / base : 0;
00171 maxAngVel += av;
00172 }
00173
00174 if(targetVel[0]!=0 || targetVel[1]!=0 || targetAngVel!=0)
00175 updateWheelVels();
00176
00177
00178
00179
00180
00181
00182 }
00183
00184 void WheeledWalkMC::updateWheelVels() {
00185 if (std::abs(targetAngVel) <= targetVel.norm()*EPSILON) {
00186
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
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
00206
00207
00208
00209
00210 #endif