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 std::cout << "axis " << x << ' ' << y << " angle " << std::asin(s) << ' ' << std::acos(c) << std::endl;
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 std::cout << fmat::Transform(v) << std::endl;
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 #ifdef TGT_HAS_LEGS
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 #else // NO LEGS -- constant ground plane
00314
00315 PlaneEquation Kinematics::calculateGroundPlane() {
00316 return PlaneEquation(0,0,1,0);
00317 }
00318
00319 PlaneEquation
00320 Kinematics::calculateGroundPlane(const fmat::Column<3>& down) {
00321 return PlaneEquation(-down, 0);
00322 }
00323
00324 #endif
00325
00326 fmat::Column<4>
00327 Kinematics::projectToPlane(
00328 unsigned int j, const fmat::Column<3>& r_j,
00329 unsigned int b, const PlaneEquation& p_b,
00330 unsigned int f,
00331 float objCentroidHeight)
00332 {
00333 update();
00334 if((j!=b && (jointMaps[j]==NULL || jointMaps[b]==NULL)) || (f!=b && (jointMaps[f]==NULL || jointMaps[b]==NULL)) )
00335 return fmat::Column<4>(0.f);
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 fmat::Column<3> ro_b, rv_b;
00368 if(j==b)
00369 rv_b=r_j;
00370 else {
00371 fmat::Transform tr = jointMaps[j]->getT(*jointMaps[b]);
00372 ro_b = tr.translation();
00373 rv_b = tr.rotation() * r_j;
00374 }
00375
00376
00377
00378 float dist = p_b.getDisplacement() - fmat::dotProduct(p_b.getDirection(),ro_b);
00379
00380
00381 dist += signbit(dist) ? objCentroidHeight : -objCentroidHeight;
00382
00383 float align = fmat::dotProduct(p_b.getDirection(),rv_b);
00384
00385
00386
00387
00388 fmat::Column<4> hit;
00389 if(std::abs(align)>numeric_limits<float>::epsilon())
00390 hit = fmat::pack(rv_b*(dist/align)+ro_b,1.f);
00391 else if(align!=0 && dist!=0 && signbit(align)!=signbit(dist))
00392 hit = fmat::pack(-rv_b,std::abs(align));
00393 else
00394 hit = fmat::pack(rv_b,std::abs(align));
00395
00396
00397 return (f==b) ? hit : jointMaps[b]->getT(*jointMaps[f]) * hit;
00398 }
00399
00400 fmat::Column<4>
00401 Kinematics::projectToGround(const VisionObjectEvent& visObj, const PlaneEquation& gndPlane, float objCentroidHeight) {
00402 #ifndef TGT_HAS_CAMERA
00403 return fmat::Column<4>();
00404 #else
00405 fmat::Column<3> imgRay_c;
00406 config->vision.computeRay(visObj.getCenterX(),visObj.getCenterY(), imgRay_c[0],imgRay_c[1],imgRay_c[2]);
00407 return projectToPlane(CameraFrameOffset, imgRay_c, BaseFrameOffset, calculateGroundPlane(), BaseFrameOffset, objCentroidHeight);
00408 #endif
00409 }
00410
00411
00412 void
00413 Kinematics::update() const {
00414 if(lastUpdateTime == state->lastSensorUpdateTime)
00415 return;
00416 for(unsigned int j=0; j<NumOutputs; j++) {
00417 if(jointMaps[j]!=NULL)
00418 jointMaps[j]->setQ(state->outputs[j]);
00419 }
00420 lastUpdateTime = state->lastSensorUpdateTime;
00421 }
00422
00423
00424
00425
00426
00427
00428