00001 #include "Kinematics.h"
00002 #include "Shared/Config.h"
00003 #include "Shared/WorldState.h"
00004 #include "Events/VisionObjectEvent.h"
00005 #include "Shared/string_util.h"
00006 #include <sstream>
00007 #include <iostream>
00008 #include <limits>
00009 #include <cmath>
00010 
00011 #ifdef PLATFORM_APERIOS
00012 
00013 template<typename T> static inline int signbit(T x) { return x<0; }
00014 #endif
00015 
00016 using namespace std;
00017 
00018 Kinematics * kine = NULL;
00019 Kinematics::InterestPointMap Kinematics::ips;
00020 bool Kinematics::staticsInited=false;
00021 
00022 void
00023 Kinematics::init() {
00024   checkStatics();
00025   for(unsigned int i=0; i<NumReferenceFrames; ++i)
00026     jointMaps[i]=NULL;
00027   if(!root.loadFile(config->makePath(config->motion.kinematics).c_str())) {
00028     std::cerr << "Could not load " << config->motion.makePath(config->motion.kinematics) << ", forward and inverse kinematics unavailable." << std::endl;
00029     return;
00030   }
00031   root.buildChildMap(jointMaps,0,NumReferenceFrames);
00032 }
00033 
00034 void Kinematics::initStatics() {
00035   if(!staticsInited) {
00036     staticsInited=true;
00037   }
00038 }
00039 
00040 Kinematics::~Kinematics() {
00041 }
00042 
00043 fmat::Transform
00044 Kinematics::baseToLocal(const PlaneEquation& plane) {
00045   std::cout << "plane " << plane.getDirection() << ' ' << plane.getDisplacement() << std::endl;
00046   fmat::Column<3> p = plane.getDirection() / plane.getDirection().norm();
00047   float s = hypotf(p[0],p[1]); 
00048   if(std::abs(s)<std::numeric_limits<float>::epsilon()*100) 
00049     return fmat::Transform::IDENTITY;
00050   
00051   
00052   float x = -p[1]/s;
00053   float y = p[0]/s;
00054   
00055   
00056   float d = -plane.getDisplacement();
00057   
00058   float c = -p[2]; 
00059   float t = 1 - c;
00060   
00061   float v[fmat::Transform::CAP] = { t*x*x + c, t*x*y, -y*s, t*x*y, t*y*y + c, x*s, y*s, -x*s, c, p[0]*d, p[1]*d, p[2]*d };
00062   
00063   return fmat::Transform(v);
00064 }
00065 
00066 void 
00067 Kinematics::getInterestPoint(const std::string& name, unsigned int& link, fmat::Column<3>& ip, bool convertToJoint) {
00068   link=-1U;
00069   ip=fmat::Column<3>();
00070   for(unsigned int i=0; i<NumReferenceFrames; ++i) {
00071     if(strcmp(outputNames[i],name.c_str())==0) {
00072       link = i;
00073       ip=pack(0,0,0);
00074     }
00075   }
00076   if(convertToJoint && NumOutputs<=link && link<NumReferenceFrames) {
00077     KinematicJoint * kj = jointMaps[link];
00078     while(kj!=NULL) {
00079       if(kj->outputOffset < NumOutputs) {
00080         ip = jointMaps[link]->getT(*kj) * ip;
00081         link = kj->outputOffset;
00082         return;
00083       }
00084     }
00085   }
00086 }
00087 
00088 fmat::Column<3>
00089 Kinematics::getInterestPoint(unsigned int link, const std::string& name) {
00090   vector<string> ipNames = string_util::tokenize(name,",");
00091   fmat::Column<3> ans = pack(0,0,0);
00092   unsigned int cnt=0;
00093   for(vector<string>::const_iterator it=ipNames.begin(); it!=ipNames.end(); ++it) {
00094     string srcName = string_util::trim(*it);
00095     if(srcName.size()==0)
00096       continue;
00097     unsigned int srcLink=-1U;
00098     fmat::Column<3> srcPos;
00099     getInterestPoint(srcName,srcLink,srcPos);
00100     if(srcLink==-1U)
00101       throw std::runtime_error(std::string("Kinematics::getLinkInterestPoint: interest point unknown ").append(name));
00102     if(link!=srcLink)
00103       srcPos = linkToLink(srcLink,link)*srcPos;
00104     ans+=srcPos;
00105     ++cnt;
00106   }
00107   if(cnt==0)
00108     throw std::runtime_error(std::string("Kinematics::getLinkInterestPoint called with empty string"));
00109   return ans/cnt;
00110 }
00111 
00112 
00113 #if defined(TGT_HAS_LEGS) && !defined(TGT_IS_MANTIS) 
00114 void
00115 Kinematics::calcLegHeights(const fmat::Column<3>& down, float heights[NumLegs]) {
00116   update();
00117   
00118   for(unsigned int i=0; i<NumLegs; i++) {
00119     if(jointMaps[FootFrameOffset+i]==NULL) {
00120       heights[i]=std::numeric_limits<typeof(heights[0])>::max();
00121     } else {
00122       fmat::Column<3> ip_b=jointMaps[FootFrameOffset+i]->getWorldPosition();
00123       float h = -fmat::dotProduct(ip_b,down);
00124       h-=BallOfFootRadius; 
00125       heights[i]=h;
00126     }
00127   }
00128   
00129   for(InterestPointMap::const_iterator it=ips.begin(); it!=ips.end(); ++it) {
00130     unsigned int leg;
00131     if(jointMaps[it->second.output]==NULL)
00132       continue;
00133     else if(it->second.output>=LegOffset || it->second.output<LegOffset+NumLegJoints)
00134       leg = (it->second.output - LegOffset) / JointsPerLeg;
00135     else if(it->second.output>=FootFrameOffset || it->second.output<FootFrameOffset+NumLegs)
00136       leg = (it->second.output - FootFrameOffset);
00137     else
00138       continue;
00139     fmat::Column<3> ip_b=jointMaps[it->second.output]->getFullT() * it->second.p;
00140     float h = -fmat::dotProduct(ip_b,down);
00141     if(h<heights[leg])
00142       heights[leg]=h;
00143   }
00144 }
00145 
00146 LegOrder_t
00147 Kinematics::findUnusedLeg(const fmat::Column<3>& down) {
00148   float heights[NumLegs];
00149   calcLegHeights(down,heights);
00150   
00151   unsigned int highleg=0;
00152   for(unsigned int i=1; i<NumLegs; i++)
00153     if(heights[i]>heights[highleg])
00154       highleg=i;
00155   
00156   return static_cast<LegOrder_t>(highleg);
00157 }
00158 
00159 PlaneEquation Kinematics::calculateGroundPlane() {
00160 #ifdef TGT_HAS_ACCELEROMETERS
00161   fmat::Column<3> down=fmat::pack(state->sensors[BAccelOffset],-state->sensors[LAccelOffset],state->sensors[DAccelOffset]);
00162   if(down.sumSq()<0.01)
00163     down=fmat::pack(0,0,-1); 
00164   return calculateGroundPlane(down);
00165 #else
00166   return calculateGroundPlane(fmat::pack(0,0,-1));
00167 #endif
00168 }
00169 
00170 
00171 #include "PostureEngine.h"
00172 PlaneEquation
00173 Kinematics::calculateGroundPlane(const fmat::Column<3>& down) {
00174   update();
00175   fmat::Matrix<3,3> lowip; 
00176   float heights[3];
00177   unsigned int legs[3];
00178   std::string names[3];
00179   
00180   for(unsigned int i=0; i<3; i++) {
00181     heights[i]=std::numeric_limits<typeof(heights[0])>::max();;
00182     legs[i]=-1U;
00183   }
00184   
00185   for(unsigned int i=0; i<NumLegs; i++) {
00186     if(jointMaps[FootFrameOffset+i]==NULL)
00187       continue;
00188     fmat::Column<3> ip_b=jointMaps[FootFrameOffset+i]->getWorldPosition();
00189     float h = -fmat::dotProduct(ip_b,down);
00190     h-=BallOfFootRadius; 
00191     if(h<heights[0]) {
00192       if(h<heights[1]) {
00193         heights[0]=heights[1];
00194         lowip.column(0)=lowip.column(1);
00195         legs[0]=legs[1];
00196         names[0]=names[1];
00197         if(h<heights[2]) {
00198           heights[1]=heights[2];
00199           lowip.column(1)=lowip.column(2);
00200           legs[1]=legs[2];
00201           names[1]=names[2];
00202           
00203           heights[2]=h;
00204           lowip.column(2)=ip_b;
00205           legs[2]=i;
00206           names[2]="paw"; names[2]+=(char)('0'+i);
00207         } else {
00208           heights[1]=h;
00209           lowip.column(1)=ip_b;
00210           legs[1]=i;
00211           names[1]="paw"; names[1]+=(char)('0'+i);
00212         }
00213       } else {
00214         heights[0]=h;
00215         lowip.column(0)=ip_b;
00216         legs[0]=i;
00217         names[0]="paw"; names[0]+=(char)('0'+i);
00218       }
00219     }
00220   }
00221   
00222   
00223   
00224   for(InterestPointMap::const_iterator it=ips.begin(); it!=ips.end(); ++it) {
00225 #ifdef TGT_IS_AIBO
00226     if(it->first.substr(0,3)=="Toe")
00227       continue;
00228 #endif
00229     if(jointMaps[it->second.output]==NULL)
00230       continue;
00231     fmat::Column<3> ip_b=jointMaps[it->second.output]->getFullT() * it->second.p;
00232     float h = -fmat::dotProduct(ip_b,down);
00233     if(h<heights[0]) {
00234       unsigned int leg;
00235       if(it->second.output>=LegOffset && it->second.output<LegOffset+NumLegJoints)
00236         leg = (it->second.output - LegOffset) / JointsPerLeg;
00237       else if(it->second.output>=FootFrameOffset && it->second.output<FootFrameOffset+NumLegs)
00238         leg = (it->second.output - FootFrameOffset);
00239       else
00240         leg=-1U;
00241       
00242       if(h<heights[1]) {
00243         if(h<heights[2]) {
00244           if(leg==-1U || (legs[1]!=leg && legs[2]!=leg)) {
00245             heights[0]=heights[1];
00246             lowip.column(0)=lowip.column(1);
00247             legs[0]=legs[1];
00248             names[0]=names[1];
00249           }
00250           if(leg==-1U || legs[2]!=leg) {
00251             heights[1]=heights[2];
00252             lowip.column(1)=lowip.column(2);
00253             if(legs[2]!=leg)
00254               legs[1]=legs[2];
00255             names[1]=names[2];
00256           }
00257           
00258           heights[2]=h;
00259           lowip.column(2)=ip_b;
00260           legs[2]=leg;
00261           names[2]=(*it).first;
00262         } else {
00263           if(leg!=-1U && legs[2]==leg)
00264             continue;
00265           if(leg==-1U || legs[1]!=leg) {
00266             heights[0]=heights[1];
00267             lowip.column(0)=lowip.column(1);
00268             legs[0]=legs[1];
00269             names[0]=names[1];
00270           }
00271           heights[1]=h;
00272           lowip.column(1)=ip_b;
00273           legs[1]=leg;
00274           names[1]=(*it).first;
00275         }
00276       } else {
00277         if(leg!=-1U && (legs[1]==leg || legs[2]==leg))
00278           continue;
00279         heights[0]=h;
00280         lowip.column(0)=ip_b;
00281         legs[0]=leg;
00282         names[0]=(*it).first;
00283       }
00284     }
00285   }
00286   
00287   
00288   fmat::Column<3> ones(1.f);
00289   fmat::Column<3> dir;
00290   try {
00291     dir = invert(lowip.transpose())*ones;
00292   } catch(...) {
00293     std::cout << "Exception during ground plane processing, saving current posture..." << std::flush;
00294     if(PostureEngine * tpose=dynamic_cast<PostureEngine*>(this)) {
00295       tpose->setSaveFormat(true,state);
00296       tpose->saveFile("/error.pos");
00297     } else {
00298       PostureEngine pose;
00299       pose.takeSnapshot();
00300       pose.setWeights(1);
00301       pose.setSaveFormat(true,state);
00302       pose.saveFile("/error.pos");
00303     }
00304     std::cout << "Wrote current sensor info \"error.pos\" on memstick" << std::endl;
00305     cout << "Ground plane was using " << names[0] <<" ("<<heights[0]<<") " << names[1] << " ("<<heights[1]<<") " << names[2] << " ("<<heights[2]<<")"<< endl;
00306     cout << lowip;
00307     throw;
00308   }
00309   
00310   return PlaneEquation(dir, 1);
00311 }
00312 
00313 #elif defined(TGT_IS_MANTIS)
00314 
00315 
00316 PlaneEquation Kinematics::calculateGroundPlane() {
00317 #ifdef TGT_HAS_ACCELEROMETERS
00318         fmat::Column<3> down=fmat::pack(state->sensors[BAccelOffset],-state->sensors[LAccelOffset],state->sensors[DAccelOffset]);
00319         if(down.sumSq()<0.01)
00320                 down=fmat::pack(0,0,-1); 
00321         return calculateGroundPlane(down);
00322 #else
00323         return calculateGroundPlane(fmat::pack(0,0,-1));
00324 #endif
00325 }
00326 
00327 #include "PostureEngine.h"
00328 #include <utility>
00329 PlaneEquation
00330 Kinematics::calculateGroundPlane(const fmat::Column<3>& down) {
00331         update();
00332         fmat::Matrix<3,3> lowip; 
00333         float heights[3];float arr[6];
00334         unsigned int idx[NumLegs];
00335         for (unsigned int i=0; i<NumLegs; i++) {  idx[i] = i; }
00336         unsigned int legs[3];
00337         std::string names[3];
00338         for(unsigned int i=0; i<NumLegs; i++) {
00339                 if(jointMaps[FootFrameOffset+i]==NULL)
00340                         continue;
00341                 fmat::Column<3> ip_b=jointMaps[FootFrameOffset+i]->getWorldPosition();
00342                 float h = -fmat::dotProduct(ip_b,down);
00343                 h-=BallOfFootRadius; 
00344                 arr[i]=h;
00345                 
00346         }
00347         for(unsigned int i=0; i<NumLegs; i++) {
00348                  for(unsigned int j=i+1; j<NumLegs; j++) {
00349                         if (arr[idx[i]] > arr[idx[j]])
00350                         {
00351                            std::swap(idx[i], idx[j]);
00352                         }
00353                }
00354         }
00355         for(unsigned int i=0; i<3; i++) {
00356                 legs[i] = idx[i];
00357                 heights[i] = arr[idx[i]];
00358                 lowip.column(i) = jointMaps[FootFrameOffset+idx[i]]->getWorldPosition();
00359                 names[i]="paw"; names[i]+=(char)('0'+idx[i]);
00360                 
00361         }
00362 
00363 
00364         
00365 
00366 
00367         for(InterestPointMap::const_iterator it=ips.begin(); it!=ips.end(); ++it) {
00368                 if(jointMaps[it->second.output]==NULL)
00369                         continue;
00370                 fmat::Column<3> ip_b=jointMaps[it->second.output]->getFullT() * it->second.p;
00371                 float h = -fmat::dotProduct(ip_b,down);
00372                 if(h<heights[0]) {
00373                         unsigned int leg;
00374                         if(it->second.output>=LegOffset && it->second.output<LegOffset+NumFrLegJoints)
00375                                 leg = (it->second.output - LegOffset) / JointsPerFrLeg;
00376                         else if(it->second.output>=LMdLegOffset && it->second.output<LMdLegOffset+NumPosLegJoints)
00377                                 leg = (it->second.output - LMdLegOffset) / JointsPerPosLeg;
00378                         else if(it->second.output>=FootFrameOffset && it->second.output<FootFrameOffset+NumLegs)
00379                                 leg = (it->second.output - FootFrameOffset);
00380                         else
00381                                 leg=-1U;
00382 
00383                         if(h<heights[1]) {
00384                                 if(h<heights[2]) {
00385                                         if(leg==-1U || (legs[1]!=leg && legs[2]!=leg)) {
00386                                                 heights[0]=heights[1];
00387                                                 lowip.column(0)=lowip.column(1);
00388                                                 legs[0]=legs[1];
00389                                                 names[0]=names[1];
00390                                         }
00391                                         if(leg==-1U || legs[2]!=leg) {
00392                                                 heights[1]=heights[2];
00393                                                 lowip.column(1)=lowip.column(2);
00394                                                 if(legs[2]!=leg)
00395                                                         legs[1]=legs[2];
00396                                                 names[1]=names[2];
00397                                         }
00398 
00399                                         heights[2]=h;
00400                                         lowip.column(2)=ip_b;
00401                                         legs[2]=leg;
00402                                         names[2]=(*it).first;
00403                                 } else {
00404                                         if(leg!=-1U && legs[2]==leg)
00405                                                 continue;
00406                                         if(leg==-1U || legs[1]!=leg) {
00407                                                 heights[0]=heights[1];
00408                                                 lowip.column(0)=lowip.column(1);
00409                                                 legs[0]=legs[1];
00410                                                 names[0]=names[1];
00411                                         }
00412                                         heights[1]=h;
00413                                         lowip.column(1)=ip_b;
00414                                         legs[1]=leg;
00415                                         names[1]=(*it).first;
00416                                 }
00417                         } else {
00418                                 if(leg!=-1U && (legs[1]==leg || legs[2]==leg))
00419                                         continue;
00420                                 heights[0]=h;
00421                                 lowip.column(0)=ip_b;
00422                                 legs[0]=leg;
00423                                 names[0]=(*it).first;
00424                         }
00425                 }
00426         }
00427 
00428         
00429         fmat::Column<3> ones(1.f);
00430         fmat::Column<3> dir;
00431         try {
00432                 dir = invert(lowip.transpose())*ones;
00433         } catch(...) {
00434                 std::cout << "Exception during ground plane processing, saving current posture..." << std::flush;
00435                 if(PostureEngine * tpose=dynamic_cast<PostureEngine*>(this)) {
00436                         tpose->setSaveFormat(true,state);
00437                         tpose->saveFile("/error.pos");
00438                 } else {
00439                         PostureEngine pose;
00440                         pose.takeSnapshot();
00441                         pose.setWeights(1);
00442                         pose.setSaveFormat(true,state);
00443                         pose.saveFile("/error.pos");
00444                 }
00445                 std::cout << "Wrote current sensor info \"error.pos\" on memstick" << std::endl;
00446                 cout << "Ground plane was using " << names[0] <<" ("<<heights[0]<<") " << names[1] << " ("<<heights[1]<<") " << names[2] << " ("<<heights[2]<<")"<< endl;
00447                 cout << lowip;
00448                 throw;
00449         }
00450         
00451         return PlaneEquation(dir, 1);
00452 }
00453 
00454 #else // NO LEGS -- constant ground plane
00455 
00456 PlaneEquation Kinematics::calculateGroundPlane() {
00457   return PlaneEquation(0,0,1,0);
00458 }
00459 
00460 PlaneEquation
00461 Kinematics::calculateGroundPlane(const fmat::Column<3>& down) {
00462   return PlaneEquation(-down, 0); 
00463 }
00464 
00465 #endif
00466 
00467 fmat::Column<4> 
00468 Kinematics::projectToPlane(
00469       unsigned int j, const fmat::Column<3>& r_j,
00470       unsigned int b, const PlaneEquation& p_b,
00471       unsigned int f,
00472       float objCentroidHeight)
00473 {
00474   update();
00475   if((j!=b && (jointMaps[j]==NULL || jointMaps[b]==NULL)) || (f!=b && (jointMaps[f]==NULL || jointMaps[b]==NULL)) )
00476     return fmat::Column<4>(0.f);
00477   
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486    
00487   
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497    
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00508   fmat::Column<3> ro_b, rv_b;
00509   if(j==b)
00510     rv_b=r_j;
00511   else {
00512     fmat::Transform tr = jointMaps[j]->getT(*jointMaps[b]);
00513     ro_b = tr.translation();
00514     rv_b = tr.rotation() * r_j;
00515   }
00516   
00517   
00518 
00519   float dist = p_b.getDisplacement() - fmat::dotProduct(p_b.getDirection(),ro_b);
00520 
00521 
00522   dist += signbit(dist) ? objCentroidHeight : -objCentroidHeight;
00523 
00524   float align = fmat::dotProduct(p_b.getDirection(),rv_b);
00525   
00526   
00527 
00528 
00529   fmat::Column<4> hit;
00530   if(std::abs(align)>numeric_limits<float>::epsilon())
00531     hit = fmat::pack(rv_b*(dist/align)+ro_b,1.f);
00532   else if(align!=0 && dist!=0 && signbit(align)!=signbit(dist))
00533     hit = fmat::pack(-rv_b,std::abs(align));
00534   else
00535     hit = fmat::pack(rv_b,std::abs(align));
00536   
00537   
00538   return (f==b) ? hit : jointMaps[b]->getT(*jointMaps[f]) * hit;
00539 }
00540 
00541 fmat::Column<4>
00542 Kinematics::projectToGround(const VisionObjectEvent& visObj, const PlaneEquation& gndPlane, float objCentroidHeight) {
00543 #ifndef TGT_HAS_CAMERA
00544   return fmat::Column<4>();
00545 #else
00546   fmat::Column<3> imgRay_c;
00547   config->vision.computeRay(visObj.getCenterX(),visObj.getCenterY(), imgRay_c[0],imgRay_c[1],imgRay_c[2]);
00548   return projectToPlane(CameraFrameOffset, imgRay_c, BaseFrameOffset, calculateGroundPlane(), BaseFrameOffset, objCentroidHeight);
00549 #endif
00550 }
00551 
00552 
00553 void
00554 Kinematics::update() const {
00555   if(lastUpdateTime == state->lastSensorUpdateTime)
00556      return;
00557   for(unsigned int j=0; j<NumOutputs; j++) {
00558     if(jointMaps[j]!=NULL)
00559       jointMaps[j]->setQ(state->outputs[j]);
00560   }
00561   lastUpdateTime = state->lastSensorUpdateTime;
00562 }
00563 
00564 
00565 
00566 
00567 
00568 
00569