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