Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

KinematicJoint.cc

Go to the documentation of this file.
00001 #include "KinematicJoint.h"
00002 #include "IKSolver.h"
00003 #include "Shared/RobotInfo.h"
00004 #include <cmath>
00005 #include <limits>
00006 
00007 using namespace std;
00008 
00009 const char* KinematicJoint::jointTypeNames[3] = { "revolute", "prismatic", NULL };
00010 INSTANTIATE_NAMEDENUMERATION_STATICS(KinematicJoint::JointType_t);
00011 
00012 PLIST_CLONE_IMP(LinkComponent,new LinkComponent(*this));
00013 
00014 //! for each node, if it's an array, start loading the subtree via recursive instantiation, otherwise load the KinematicJoint
00015 bool KinematicJointLoader::loadXMLNode(size_t index, xmlNode* val, const std::string& comment) {
00016   if(xNodeHasName(val,"array")) {
00017     if(index==0) {
00018       xmlChar* path=xGetNodePath(val);
00019       std::cerr << "WARNING: loading kinematic file " << xNodeGetURL(val) << ":" << xmlGetLineNo(val) << " (" << path << "), encountered branch without prior link" << std::endl;
00020       xmlFree(path);
00021     }
00022     if(skipToElement(xNodeGetChildren(val))!=NULL) { // make sure there's something to load...
00023       KinematicJoint * kj = new KinematicJoint;
00024       KinematicJointLoader(*kj,val);
00025       parent->addBranch(kj);
00026     } else {
00027       xmlChar* path=xGetNodePath(val);
00028       std::cerr << "WARNING: loading kinematic file " << xNodeGetURL(val) << ":" << xmlGetLineNo(val) << " (" << path << "), skipping empty array" << std::endl;
00029       xmlFree(path);
00030     }
00031   } else {
00032     if(!plist::ArrayOf<KinematicJoint>::loadXMLNode(index==0 ? 0 : size(),val,comment))
00033       return false;
00034     if(index>0) {
00035       parent->addBranch(&back());
00036       parent = &back();
00037       myRef.clear();
00038     }
00039   }
00040   return true;
00041 }
00042 
00043 
00044 
00045 //! saves the array of joints, prepending human-readable help text as a comment if this is a root XML node
00046 void KinematicJointSaver::saveXML(xmlNode* node) const {
00047   if(node==NULL)
00048     return;
00049   if(xNodeGetChildren(node)==NULL && (xNodeGetParent(node)==NULL || xNodeGetParent(xNodeGetParent(node))==NULL || xNodeHasName(xNodeGetParent(node),"plist"))) {
00050     std::string indentStr=getIndentationPrefix(node);
00051     std::string jointTypes;
00052     const char ** jtName = KinematicJoint::jointTypeNames;
00053     while(*jtName!=NULL && (*jtName)[0]!='\0') {
00054       if(jointTypes.size()>0)
00055         jointTypes+=" | ";
00056       jointTypes+=*jtName++;
00057     }
00058     
00059     std::string headerComment="\n"
00060     "##################################################################\n"
00061     "##################   Kinematics Configuration   ##################\n"
00062     "##################################################################\n"
00063     "\n"
00064     "This is an XML-based format using the Property List (plist) layout.\n"
00065     "\n"
00066     "Each joint is defined by a <dict> element with the keys listed below.\n"
00067     "A branch in the chain is denoted by an <array> containing the\n"
00068     "joints of the sub-chain.\n"
00069     "\n"
00070     "  JointType: Indicates the type of motion produced by the joint\n"
00071     "    One of: "+jointTypes+"\n"
00072     "\n"
00073     "  Denavit-Hartenberg parameters: (here in order of application)\n"
00074     "    d: Displacement along the previous joint's z axis\n"
00075     "    θ: Rotation about the previous joint's z axis (theta, U+03B8)\n"
00076     "    r: Displacement from prev. z along the current joint's x axis\n"
00077     "    α: Rotation about the current joint's x axis (alpha, U+03B1)\n"
00078     "  In other words, θ and d align the previous joint's x axis with\n"
00079     "  this joint's x axis, and then a displacement of r (radius of\n"
00080     "  rotation) along this x defines the current joint's origin.\n"
00081     "  α then defines the current joint's z axis (the axis of actuation).\n"
00082     "\n"
00083     "  qOffset: An additional parameter which shifts the final reference\n"
00084     "    frame to the physical joint's 0 position.  This is a rotation\n"
00085     "    about the joint's z axis for revolute joints, or translation\n"
00086     "    along z for prismatic.\n"
00087     "  Min: The minimum acceptable joint value for inverse kinematics\n"
00088     "  Max: The maximum acceptable joint value for inverse kinematics\n"
00089     "    Inverse kinematics ignores this joint if Min==Max (immobile).\n"
00090     "\n"
00091     "  Model: for 3D graphics, the name of the OGRE mesh file to render\n"
00092     "    for the link following the joint. (drop the \".mesh\" suffix)\n"
00093     "  Material: for 3D graphics, the name of the material to apply to\n"
00094     "    the model, or blank to use the model's defaults\n"
00095     "\n"
00096     "All distances are in millimeters.  Angles are radians, unless a\n"
00097     "'unit' attribute is specified, or a '°' is suffixed.  You can\n"
00098     "also specify radians as multiples of Pi, e.g. 'π/2'.\n";
00099     xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+indentStr).c_str()));
00100     xmlAddChild(node,xmlNewComment((const xmlChar*)headerComment.c_str()));
00101     xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+indentStr).c_str()));
00102   }
00103   plist::Array::saveXML(node);
00104 }
00105 
00106 void KinematicJointSaver::init(const std::set<KinematicJoint*>& joints, xmlNode* node) {
00107   const std::set<KinematicJoint*>* branches = &joints;
00108   while(branches->size()>0) {
00109     if(branches->size()==1) {
00110       addEntry(**branches->begin());
00111       branches = &(*branches->begin())->branches;
00112     } else {
00113       for(std::set<KinematicJoint*>::const_iterator it=branches->begin(); it!=branches->end(); ++it)
00114         addEntry(new KinematicJointSaver(**it));
00115       break;
00116     }
00117   }
00118   if(node!=NULL)
00119     saveXML(node);
00120 }
00121 
00122 KinematicJoint::~KinematicJoint() {
00123   removeSelfListener();
00124   clearBranches();
00125   delete branchListeners;
00126   branchListeners=NULL;
00127   delete ik;
00128   ik=NULL;
00129 }
00130 
00131 void KinematicJoint::addBranchListener(BranchListener* l) const {
00132   if(l!=NULL) {
00133     if(branchListeners==NULL)
00134       branchListeners=new std::set<BranchListener*>;
00135     branchListeners->insert(l);
00136   }
00137 }
00138 
00139 void KinematicJoint::removeBranchListener(BranchListener* l) const {
00140   if(branchListeners==NULL)
00141     return;
00142   std::set<BranchListener*>::iterator it=branchListeners->find(l);
00143   if(it!=branchListeners->end()) {
00144     branchListeners->erase(it);
00145     if(branchListeners->empty()) {
00146       delete branchListeners;
00147       branchListeners=NULL;
00148     }
00149   }
00150 }
00151 
00152 bool KinematicJoint::isBranchListener(BranchListener* l) const {
00153   if(l==NULL)
00154     return false;
00155   if(branchListeners==NULL)
00156     return false;
00157   return ( branchListeners->count(l) > 0 );
00158 }
00159 
00160 IKSolver& KinematicJoint::getIK() const {
00161   if(ik!=NULL)
00162     return *ik;
00163   ik = IKSolver::getRegistry().create(ikSolver);
00164   if(ik==NULL) {
00165     ik = IKSolver::getRegistry().create("");
00166     if(ik==NULL)
00167       throw std::runtime_error("Could not create any IKSolvers");
00168     std::cerr << "Warning: could not create any IKSolver '" << ikSolver << "' for " << outputOffset.get() << ", falling back on default generic solver" << std::endl;
00169   }
00170   ikSolver.addPrimitiveListener(const_cast<KinematicJoint*>(this));
00171   return *ik;
00172 }
00173 
00174 PLIST_CLONE_IMP(KinematicJoint,new KinematicJoint(*this));
00175 
00176 void KinematicJoint::fireBranchAdded(KinematicJoint& val) {
00177   if(branchListeners==NULL)
00178     return;
00179   // copy primitive listeners so we aren't screwed if a listener is removed during processing, particularly if it's the *last* listener
00180   std::set<BranchListener*> pls=*branchListeners;
00181   for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00182     // make sure current listener hasn't been removed
00183     if(branchListeners->count(*it)>0)
00184       (*it)->kinematicJointBranchAdded(*this,val);
00185   }
00186 }
00187 
00188 void KinematicJoint::fireBranchRemoved(KinematicJoint& val) {
00189   if(branchListeners==NULL)
00190     return;
00191   // copy primitive listeners so we aren't screwed if a listener is removed during processing, particularly if it's the *last* listener
00192   std::set<BranchListener*> pls=*branchListeners;
00193   for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00194     // make sure current listener hasn't been removed
00195     if(branchListeners->count(*it)>0)
00196       (*it)->kinematicJointBranchRemoved(*this,val);
00197   }
00198 }
00199 
00200 void KinematicJoint::fireReconfigured() {
00201   if(branchListeners==NULL)
00202     return;
00203   // copy primitive listeners so we aren't screwed if a listener is removed during processing, particularly if it's the *last* listener
00204   std::set<BranchListener*> pls=*branchListeners;
00205   for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00206     // make sure current listener hasn't been removed
00207     if(branchListeners->count(*it)>0)
00208       (*it)->kinematicJointReconfigured(*this);
00209   }
00210 }
00211 
00212 /*! returning false here can cause IK to invert solutions... for better stability,
00213     only return false if a joint limit is "significantly" exceeded. */
00214 bool KinematicJoint::tryQ(float x) {
00215   const float EPSILON = numeric_limits<float>::epsilon()*100;
00216   if(x>qmax) {
00217     if(q!=qmax) {
00218       q=qmax;
00219       updateTq();
00220     }
00221     return (x-EPSILON < qmax);
00222   } else if(x<qmin) {
00223     if(q!=qmin) {
00224       q=qmin;
00225       updateTq();
00226     }
00227     return (x+EPSILON > qmin);
00228   } else {
00229     if(x!=q) {
00230       q=x;
00231       updateTq();
00232     }
00233     return true;
00234   }
00235 }
00236 
00237 void KinematicJoint::zeroChildrenQ() {
00238   if(qmin!=qmax)
00239     setQ(0);
00240   for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00241     (*it)->zeroChildrenQ();
00242 }
00243 
00244 void KinematicJoint::zeroAncestorQ() {
00245   for(KinematicJoint* p = this; p!=NULL; p=p->getParent())
00246     if(p->qmin!=p->qmax)
00247       p->setQ(0);
00248 }
00249 
00250 
00251 fmat::Transform KinematicJoint::getFullT() const {
00252   fmat::Transform t;
00253   getFullT(t,NULL);
00254   return t;
00255 }
00256 
00257 fmat::Transform KinematicJoint::getT(const KinematicJoint& j) const {
00258   if(&j==this)
00259     return fmat::Transform::identity();
00260   fmat::Transform t;
00261   const KinematicJoint* myAnc=parent;
00262   const KinematicJoint* jAnc=j.parent;
00263   while(myAnc!=NULL || jAnc!=NULL) {
00264     if(myAnc!=NULL) {
00265       if(myAnc==&j) {
00266         getFullT(t,&j);
00267         return t;
00268       }
00269       myAnc=myAnc->parent;
00270     }
00271     if(jAnc!=NULL) {
00272       if(jAnc==this) {
00273         j.getFullT(t,this);
00274         return t.rigidInverse();
00275       }
00276       jAnc=jAnc->parent;
00277     }
00278   }
00279   getFullT(t,NULL);
00280   return j.getFullInvT() * t;
00281 }
00282 
00283 void KinematicJoint::sumCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const {
00284   fmat::Column<4> com = sumCenterOfMass();
00285   cOfM = fmat::SubVector<3>(com);
00286   if(com[3]>std::numeric_limits<fmat::fmatReal>::epsilon())
00287     cOfM/=com[3];
00288   totalMass=com[3];
00289 }
00290 
00291 fmat::Column<4> KinematicJoint::sumCenterOfMass() const { 
00292   fmat::Column<4> com = sumLinkCenterOfMass();
00293   for(branch_iterator it=branches.begin(); it!=branches.end(); ++it)
00294     com += (*it)->getTq() * (*it)->sumCenterOfMass();
00295   return com;
00296 }
00297 
00298 void LinkComponent::sumLinkCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const {
00299   fmat::Column<4> com = sumLinkCenterOfMass();
00300   cOfM = fmat::SubVector<3>(com);
00301   if(com[3]>std::numeric_limits<fmat::fmatReal>::epsilon())
00302     cOfM/=com[3];
00303   totalMass=com[3];
00304 }
00305 
00306 fmat::Column<4> KinematicJoint::sumLinkCenterOfMass() const {
00307   fmat::Column<4> com = getMassVector();
00308   for(component_iterator it=components.begin(); it!=components.end(); ++it)
00309     com += (*it)->getMassVector();
00310   return com;
00311 }
00312 
00313 bool KinematicJoint::hasMass() const {
00314   if(mass > 0)
00315     return true;
00316   for(component_iterator it=components.begin(); it!=components.end(); ++it)
00317     if((*it)->mass > 0)
00318       return true;
00319   return false;
00320 }
00321 
00322 fmat::Column<6> KinematicJoint::getJointJacobian(const fmat::Column<3>& p) const {
00323   fmat::Column<6> j;
00324   if(outputOffset>=NumOutputs)
00325     return j;
00326   fmat::Transform t = fmat::Transform::identity();
00327   getFullT(t,NULL);
00328   //std::cout << "Joint " << depth << "\nTq\n" << Tq << "Tfull\n" << t << std::endl;
00329   switch(jointType) {
00330     case REVOLUTE: {
00331       fmat::Column<3> z(t.column(2));
00332       fmat::Column<3> v(t.column(3));
00333       v = p - v;
00334       fmat::SubVector<3>(j,0) = fmat::crossProduct(z,v);
00335       fmat::SubVector<3>(j,3) = &t.column(2)[0];
00336     } break;
00337     case PRISMATIC: {
00338       j=0.f;
00339       fmat::SubVector<3>(j,0) = &t.column(2)[0];
00340     } break;
00341   }
00342   return j;
00343 }
00344 
00345 fmat::Column<3> KinematicJoint::getParentPosition() const {
00346   fmat::Column<3> p = -Tq.column(3);
00347   return fmat::pack(fmat::dotProduct(Tq.column(0),p), fmat::dotProduct(Tq.column(1),p), fmat::dotProduct(Tq.column(2),p));  
00348 }
00349 
00350 fmat::Quaternion KinematicJoint::getWorldQuaternion() const {
00351   fmat::Quaternion quat;
00352   getQuaternion(quat,NULL);
00353   return quat;
00354 }
00355 
00356 fmat::Quaternion KinematicJoint::getQuaternion(const KinematicJoint& j) const {
00357   if(&j==this)
00358     return fmat::Quaternion::identity();
00359   fmat::Quaternion quat;
00360   const KinematicJoint* myAnc=parent;
00361   const KinematicJoint* jAnc=j.parent;
00362   while(myAnc!=NULL || jAnc!=NULL) {
00363     if(myAnc!=NULL) {
00364       if(myAnc==&j) {
00365         getQuaternion(quat,&j);
00366         return quat;
00367       }
00368       myAnc=myAnc->parent;
00369     }
00370     if(jAnc!=NULL) {
00371       if(jAnc==this) {
00372         j.getQuaternion(quat,this);
00373         return quat.inverse();
00374       }
00375       jAnc=jAnc->parent;
00376     }
00377   }
00378   getQuaternion(quat,NULL);
00379   fmat::Quaternion jq;
00380   j.getQuaternion(jq,NULL);
00381   return jq.inverse() * quat;
00382 }
00383 
00384 void KinematicJoint::loadXML(xmlNode* node) {
00385   removeSelfListener();
00386   clearBranches();
00387   if(xNodeHasName(node,"array")) {
00388     try {
00389       KinematicJointLoader(*this,node);
00390     } catch(...) {
00391       addSelfListener();
00392       throw;
00393     }
00394   } else {
00395     try {
00396       LinkComponent::loadXML(node);
00397     } catch(...) {
00398       addSelfListener();
00399       throw;
00400     }
00401   }
00402   addSelfListener();
00403 }
00404 
00405 void KinematicJoint::saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const {
00406   if(node==NULL)
00407     return;
00408   if(xNodeGetParent(node)==NULL || xNodeGetParent(xNodeGetParent(node))==NULL || xNodeHasName(xNodeGetParent(node),"plist")) {
00409     KinematicJointSaver(*this,node);
00410   } else {
00411     if(xNodeGetChildren(node)==NULL && seen.size()==0) {
00412       // a bit of customization to put things in a more friendly order (not alphabetical)
00413       std::string indentStr=getIndentationPrefix(node);
00414       size_t longestKeyLen = getLongestKeyLen(NULL,1);
00415       doSaveXMLNode(seen, node, "Name", indentStr, longestKeyLen);
00416       doSaveXMLNode(seen, node, "JointType", indentStr, longestKeyLen);
00417       doSaveXMLNode(seen, node, "d", indentStr, longestKeyLen);
00418       doSaveXMLNode(seen, node, "θ", indentStr, longestKeyLen); // theta
00419       doSaveXMLNode(seen, node, "r", indentStr, longestKeyLen);
00420       doSaveXMLNode(seen, node, "α", indentStr, longestKeyLen); // alpha
00421       doSaveXMLNode(seen, node, "qOffset", indentStr, longestKeyLen);
00422       doSaveXMLNode(seen, node, "Min", indentStr, longestKeyLen);
00423       doSaveXMLNode(seen, node, "Max", indentStr, longestKeyLen);
00424       std::string parentIndent;
00425       if(indentStr.size()>=perIndent().size())
00426         parentIndent=indentStr.substr(perIndent().size());
00427       xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+parentIndent).c_str()));
00428     }
00429     // save anything else we didn't already cover
00430     LinkComponent::saveXML(node,onlyOverwrite,seen);
00431   }
00432 }
00433 
00434 void KinematicJoint::plistValueChanged(const plist::PrimitiveBase& pl) {
00435   updateTo();
00436   if(&pl==&jointType) {
00437     switch(*jointType) {
00438       case REVOLUTE: {
00439         qOffset.setFormat(plist::Angle::FORMAT_SAME);
00440         qmin.setFormat(plist::Angle::FORMAT_SAME);
00441         qmax.setFormat(plist::Angle::FORMAT_SAME);
00442       } break;
00443       case PRISMATIC: {
00444         qOffset.setFormat(plist::Angle::FORMAT_NONE);
00445         qmin.setFormat(plist::Angle::FORMAT_NONE);
00446         qmax.setFormat(plist::Angle::FORMAT_NONE);
00447       } break;
00448     }
00449   } else if(&pl==&ikSolver) {
00450     delete ik;
00451     ik=NULL;
00452     ikSolver.removePrimitiveListener(this);
00453   }
00454   fireReconfigured();
00455 }
00456 
00457 void KinematicJoint::addSelfListener() {
00458   jointType.addPrimitiveListener(this);
00459   theta.addPrimitiveListener(this);
00460   d.addPrimitiveListener(this);
00461   alpha.addPrimitiveListener(this);
00462   r.addPrimitiveListener(this);
00463   qOffset.addPrimitiveListener(this);
00464   plistValueChanged(jointType); // update values, may have changed
00465 }
00466 
00467 void KinematicJoint::removeSelfListener() {
00468   jointType.removePrimitiveListener(this);
00469   theta.removePrimitiveListener(this);
00470   d.removePrimitiveListener(this);
00471   alpha.removePrimitiveListener(this);
00472   r.removePrimitiveListener(this);
00473   qOffset.removePrimitiveListener(this);
00474 }
00475 
00476 void KinematicJoint::updateTo() {
00477   fmat::fmatReal ct = std::cos(static_cast<fmat::fmatReal>(theta));
00478   fmat::fmatReal st = std::sin(static_cast<fmat::fmatReal>(theta));
00479   fmat::fmatReal ca = std::cos(static_cast<fmat::fmatReal>(alpha));
00480   fmat::fmatReal sa = std::sin(static_cast<fmat::fmatReal>(alpha));
00481   // no final q:
00482   // fmat is column-major, transpose this array...
00483   /*fmat::fmatReal mat[16] = {
00484     ct, -st*ca, st*sa, r*ct,
00485     st, ct*ca, -ct*sa, r*st,
00486     0, sa, ca, d,
00487     0, 0, 0, 1
00488   };*/
00489   fmat::fmatReal mat[16] = {
00490     ct, st, 0, 
00491     -st*ca, ct*ca, sa, 
00492     st*sa, -ct*sa, ca, 
00493     r*ct, r*st, d
00494   };
00495   To = mat;
00496   // with final q:
00497   /*fmat::fmatReal mat[16] = {
00498    cq*ct + sq*(-st*ca), -sq*ct + cq*(-st*ca), st*sa, d*ct,
00499    cq*st + sq*(ct*ca), -sq*st + cq*(ct*ca), -ct*sa, d*sa,
00500    sq*sa, cq*sa, ca, a,
00501    0, 0, 0, 1
00502    };*/
00503   Tq = mat; updateTq();
00504 }
00505 
00506 void KinematicJoint::updateTq() {
00507   const fmat::fmatReal qv = static_cast<fmat::fmatReal>(q+qOffset);
00508   switch(jointType) {
00509     case REVOLUTE: {
00510       const fmat::fmatReal cq = std::cos(qv);
00511       const fmat::fmatReal sq = std::sin(qv);
00512       const fmat::fmatReal t11=To(0,0), t12=To(0,1), t21=To(1,0), t22=To(1,1), t32=To(2,1);
00513       Tq(0,0) = cq*t11 + sq*t12;
00514       Tq(1,0) = cq*t21 + sq*t22;
00515       Tq(2,0) = /*t31 is 0*/ sq*t32;
00516       Tq(0,1) = -sq*t11 + cq*t12;
00517       Tq(1,1) = -sq*t21 + cq*t22;
00518       Tq(2,1) = /*t31 is 0*/ cq*t32;
00519     } break;
00520     case PRISMATIC: {
00521       Tq(0,3) = To(0,2)*qv + To(0,3);
00522       Tq(1,3) = To(1,2)*qv + To(1,3);
00523       Tq(2,3) = To(2,2)*qv + To(2,3);
00524     } break;
00525   }
00526 }
00527 
00528 void LinkComponent::getModelTransform(fmat::Transform& tr) const {
00529   tr.rotation() = fmat::Quaternion::fromAxis(modelRotation).toMatrix();
00530   tr.translation().importFrom(modelOffset);
00531 }
00532 
00533 void LinkComponent::getCollisionModelTransform(fmat::Transform& tr) const {
00534   tr.rotation() = fmat::Quaternion::fromAxis(collisionModelRotation).toMatrix();
00535   tr.translation().importFrom(collisionModelOffset);
00536 }
00537 
00538 KinematicJoint* LinkComponent::getNextMobileAncestor() const {
00539   KinematicJoint* joint = parent;
00540   if (!joint) return NULL;
00541   while (joint->isMobile() == false) {
00542     joint = joint->getParent();
00543     if (!joint) return NULL;
00544   }
00545   return joint;
00546 }
00547 
00548 PlannerObstacle2D* LinkComponent::getObstacle(const fmat::Transform& worldT) const {
00549   if(collisionModel.empty())
00550     return NULL;
00551   bool asCirc=false;
00552   if(collisionModel=="Sphere") {
00553     asCirc = true;
00554   } else if(collisionModel=="Cylinder") {
00555     fmat::Quaternion q = fmat::Quaternion::fromAxis(collisionModelRotation);
00556     fmat::Matrix<3,3> rot = worldT.rotation() * q.toMatrix();
00557     if(std::abs(rot(2,2))>0.9) // this is just a heuristic, could be better
00558       asCirc=true;
00559   }
00560   if(asCirc) {
00561     RectangularObstacle ro;
00562     getOwnBB2D(worldT, ro);
00563     return new EllipticalObstacle(ro.getCenter(), ro.getWidth()/2, ro.getHeight()/2, ro.getOrientation());
00564   } else {
00565     RectangularObstacle * ro = new RectangularObstacle;
00566     getOwnBB2D(worldT, *ro);
00567     return ro;
00568   }
00569 }
00570 
00571 void LinkComponent::getObstacles(const fmat::Transform& worldT, HierarchicalObstacle& obs, bool /*recurse*/) const {
00572   PlannerObstacle2D * o = getObstacle(worldT);
00573   if(o!=NULL)
00574     obs.add(o);
00575 }
00576 
00577 void KinematicJoint::getObstacles(const fmat::Transform& worldT, HierarchicalObstacle& obs, bool recurse) const {
00578   fmat::Transform tr = worldT * getTq();
00579   LinkComponent::getObstacles(tr,obs,recurse);
00580   for(component_iterator it = components.begin(); it!=components.end(); ++it) {
00581     (*it)->getObstacles(tr,obs,recurse);
00582   }
00583   if(recurse) {
00584     for(branch_iterator it = branches.begin(); it!=branches.end(); ++it) {
00585       (*it)->getObstacles(tr, obs, recurse);
00586     }
00587   }
00588 }
00589 
00590 void LinkComponent::dirtyBB() {
00591   bbDirty=true;
00592   if(parent!=NULL)
00593     static_cast<LinkComponent&>(*parent).dirtyBB(); // silly cast because compiler complains about dirtyBB being protected otherwise :-P
00594 }
00595 
00596 void LinkComponent::computeOwnAABB(BoundingBox3D& bb) const {
00597   if(collisionModel.size()==0) {
00598     // no collision shape, no bounding box
00599     bb.clear();
00600     return;
00601   }
00602   fmat::Column<3> ex; // will set to extent (half dim)
00603   ex.importFrom(collisionModelScale);
00604   ex/=2; // for primitive shapes, scale is dim, if we ever support polygon collision models, this will need to be smarter
00605   fmat::Quaternion q = fmat::Quaternion::fromAxis(collisionModelRotation);
00606   
00607   // this leverages rotational symmetry, only needs to expand positive dimensions of one face
00608   fmat::Column<3> b = fmat::abs(ex);
00609   ex[0]=-ex[0]; b.maximize(fmat::abs(q*ex));
00610   ex[1]=-ex[1]; b.maximize(fmat::abs(q*ex));
00611   ex[0]=-ex[0]; b.maximize(fmat::abs(q*ex));
00612   
00613   // now apply offset 
00614   fmat::Column<3> off; off.importFrom(collisionModelOffset);
00615   bb.min = off - b;
00616   bb.max = off + b;
00617 }
00618 
00619 void LinkComponent::updateBB() const {
00620   computeOwnAABB(boundingBox);
00621   bbDirty=false;
00622 }
00623 
00624 void KinematicJoint::updateBB() const {
00625   LinkComponent::updateBB(); // clears bbDirty
00626   for(component_iterator it = components.begin(); it!=components.end(); ++it) {
00627     if((*it)->collisionModel.size()==0)
00628       continue;
00629     boundingBox.expand((*it)->getAABB());
00630   }
00631 }
00632 
00633 bool LinkComponent::getOwnBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const {
00634   if (collisionModel.empty())
00635     return false;
00636   fmat::Transform obT;
00637   getCollisionModelTransform(obT);
00638   fmat::Transform fullT = worldT * obT;
00639   computeBB2D(fullT, ro, collisionModelScale.exportTo<fmat::Column<3> >());
00640   return true;
00641 }
00642 
00643 bool LinkComponent::getOwnBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const {
00644   if (collisionModel.empty())
00645     return false;
00646   fmat::Transform obT;
00647   getCollisionModelTransform(obT);
00648   fmat::Transform fullT = worldT * obT;
00649   bo.reset(fullT.translation(),
00650        collisionModelScale.exportTo<fmat::Column<3> >()/2,
00651        fmat::SubMatrix<3,3,const fmat::fmatReal>(fullT.rotation()));
00652   return true;
00653 }
00654 
00655 bool LinkComponent::getBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const {
00656   const BoundingBox3D& bb = getAABB();
00657   if (bb.empty())
00658     return false;
00659   fmat::Transform fullT = worldT;
00660   fullT.translation()+=bb.getCenter();
00661   computeBB2D(fullT, ro, bb.getDimensions());
00662   return true;
00663 }
00664 
00665 bool LinkComponent::getBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const {
00666   const BoundingBox3D& bb = getAABB();
00667   if (bb.empty())
00668     return false;
00669   fmat::Transform fullT = worldT;
00670   fullT.translation()+=bb.getCenter();
00671   bo.reset(fullT.translation(),
00672        bb.getDimensions()/2,
00673        fmat::SubMatrix<3,3,const fmat::fmatReal>(fullT.rotation()));
00674   return true;
00675 }
00676 
00677 void LinkComponent::computeBB2D(const fmat::Transform& fullT, RectangularObstacle& ro, const fmat::Column<3>& obD) {
00678   // assume projection along Z (could tweak worldT to compensate otherwise)
00679   // Find longest dimension in XY plane, will use that to align bounding box
00680   // (is this necessarily optimal fit?  Good enough...)
00681   
00682   // columns are the directions of each collision model axis, projected on XY:
00683   fmat::Matrix<2,3> projR(fullT.rotation());
00684   
00685   // now find projected dimension of each axis:
00686   fmat::Column<3> prD;
00687   for(size_t i=0; i<3; ++i)
00688     prD[i] = std::abs(projR.column(i).norm() * obD[i]);
00689   // abs() only because we don't trust user not to use negative dimensions...
00690   
00691   // find maximum dimension, set primary to its axis
00692   fmat::Column<2> primary = projR.column(0);
00693   if(prD[2] > prD[1]) {
00694     if(prD[2] > prD[0]) {
00695       // if picking z axis, and if x is second dominant, use normal instead for
00696       // more stable corner ordering when projecting down-axis using square dimensions
00697       if(prD[0] > prD[1]) {
00698         if(fullT(2,1)>0) {
00699           primary = fmat::normalRight(projR.column(2));
00700         } else {
00701           primary = fmat::normalLeft(projR.column(2));
00702         }
00703       } else {
00704         primary = projR.column(2);
00705       }
00706       // however, above does introduce some extra flip-flopping on
00707       // some diagonal projections, could just use the axis directly:
00708       //primary = projR.column(2);
00709     }
00710   } else if(prD[1] > prD[0]) {
00711     // picking y axis, actually use normal to maintain corner ordering
00712     // fixes corner numerical instability projecting down-axis with square dimensions
00713     if(prD[0] > prD[2]) {
00714       if(fullT(2,2)>0) {
00715         primary = fmat::normalRight(projR.column(1));
00716       } else {
00717         primary = fmat::normalLeft(projR.column(1));
00718       }
00719     } else {
00720       if(fullT(2,0)>0) {
00721         primary = fmat::normalLeft(projR.column(1));
00722       } else {
00723         primary = fmat::normalRight(projR.column(1));
00724       }
00725     }
00726     // however, above does introduce some extra flip-flopping on
00727     // some diagonal projections, could just use the axis directly:
00728     //primary = projR.column(1);
00729   }
00730   fmat::fmatReal primaryNorm = primary.norm();
00731   if(primaryNorm==0) {
00732     // projecting down a line or empty collision model
00733     ro.reset(fmat::SubVector<2,const fmat::fmatReal>(fullT.translation()), fmat::pack(0,0), 0);
00734     return;
00735   }
00736   primary/=primaryNorm;
00737   
00738   // construct a (inverse) rotation matrix from this vector
00739   fmat::Matrix<2,2> boxR;
00740   boxR(0,0) = primary[0]; boxR(0,1) = primary[1];
00741   boxR(1,0) =-primary[1]; boxR(1,1) = primary[0];
00742   // projection of XY components
00743   fmat::Matrix<2,2> boxProj = boxR * fmat::SubMatrix<2,2>(projR);
00744   // offset due to Z component
00745   fmat::Column<2> off = boxR * projR.column(2) * obD[2];
00746   
00747   // because of rotational symmetry, only need to test extents of one face
00748   // (errr, I think so anyway?  Also think it doesn't matter which face?)
00749   fmat::Column<2> xyD(obD);
00750   fmat::Column<2> dim = fmat::abs(boxProj*xyD + off);
00751   xyD[0]=-xyD[0];
00752   dim.maximize(fmat::abs(boxProj*xyD + off));
00753   xyD[1]=-xyD[1];
00754   dim.maximize(fmat::abs(boxProj*xyD + off));
00755   xyD[0]=-xyD[0];
00756   dim.maximize(fmat::abs(boxProj*xyD + off));
00757   
00758   ro.reset(fmat::SubVector<2,const fmat::fmatReal>(fullT.translation()), dim/2, boxR.transpose());
00759 }
00760 
00761 KinematicJoint* KinematicJoint::addBranch(KinematicJoint* b) {
00762   if(b==NULL)
00763     throw std::runtime_error("Attempted to add NULL branch to KinematicJoint");
00764   if(b==this)
00765     throw std::runtime_error("Attempted to add KinematicJoint as its own branch (no loops!)");
00766   if(!branches.insert(b).second)
00767     return b; // already added
00768   if(b->parent!=NULL)
00769     throw std::runtime_error("KinematicJoint was told to add a branch which already has a parent.  Pass a clone instead (no loops)");
00770   if(b->depth>0) // shouldn't happen if we didn't have a parent
00771     throw std::runtime_error("KinematicJoint was told to add a branch which has a non-zero depth (but doesn't have a parent!?!?  Something's broken.)");
00772   b->parent=this;
00773   b->updateDepth();
00774   fireBranchAdded(*b);
00775   return b;
00776 }
00777 
00778 KinematicJoint* KinematicJoint::removeBranch(KinematicJoint* b) {
00779   if(branches.erase(b)==0)
00780     return NULL;
00781   b->parent=NULL;
00782   b->depth=0;
00783   fireBranchRemoved(*b);
00784   return b;
00785 }
00786 
00787 void KinematicJoint::clearBranches() {
00788   if(branchListeners==NULL) {
00789     for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00790       delete *it;
00791     branches.clear();
00792   } else {
00793     while(branches.size()>0)
00794       delete removeBranch(*branches.begin());
00795   }
00796 }
00797 
00798 KinematicJoint* KinematicJoint::cloneBranch() const {
00799   KinematicJoint * leaf=NULL, *cur = NULL;
00800   const KinematicJoint * next=this;
00801   while(next!=NULL) {
00802     KinematicJoint * tmp = new KinematicJoint;
00803     tmp->shallowCopy(*next);
00804     if(cur!=NULL)
00805       tmp->addBranch(cur);
00806     else
00807       leaf = tmp;
00808     cur=tmp;
00809     next = next->parent;
00810   }
00811   return leaf;
00812 }
00813 
00814 /*! @file
00815  * @brief Implements KinematicJoint, which manages parameters defining the position and type of motion produced by an actuator (i.e. forward kinematics)
00816  * @author Ethan Tira-Thompson (ejt) (Creator)
00817  */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:42 2016 by Doxygen 1.6.3