Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

robot/KinematicChain.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2003 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: KinematicChain.cpp 1039 2004-02-11 20:50:52Z jungd $
00019   $Revision: 1.9 $
00020   $Date: 2004-02-11 15:50:52 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <robot/KinematicChain>
00026 
00027 #include <base/MD5>
00028 #include <base/Externalizer>
00029 #include <base/externalization_error>
00030 #include <robot/JFKengine>
00031 
00032 #include <cstdio>
00033 
00034 using robot::KinematicChain;
00035 
00036 using base::Byte;
00037 using base::Matrix;
00038 using base::Vector;
00039 using base::ExpressionMatrix;
00040 using base::Externalizer;
00041 using base::externalization_error;
00042 using base::dom::DOMNode;
00043 using base::dom::DOMElement;
00044 using base::MD5;
00045 using robot::KinematicEvaluator;
00046 using robot::JFKengine;
00047 
00048 
00049 
00050 const Real KinematicChain::unboundedMinAngleLimit = -consts::Pi - consts::epsilon;
00051 const Real KinematicChain::unboundedMaxAngleLimit = +consts::Pi + consts::epsilon;
00052 const Real KinematicChain::unboundedMinDistLimit  = consts::maxReal;
00053 const Real KinematicChain::unboundedMaxDistLimit  = -consts::maxReal;
00054 
00055   
00056   
00057 KinematicChain::Link& KinematicChain::Link::operator=(const KinematicChain::Link& l)
00058 {
00059   linkType=l.linkType;
00060   switch (linkType) {
00061     case Translating:
00062       direction=l.direction;
00063       t=l.t;
00064       break;
00065     case FixedTransform:
00066       transform=l.transform;
00067       break;
00068     case Prismatic: 
00069     case Revolute:
00070       alpha=l.alpha; a=l.a; d=l.d; theta=l.theta;
00071       break;
00072     default: Assertm(false,"known joint type");
00073   }
00074   jminLimit=l.jminLimit; jmaxLimit=l.jmaxLimit;
00075   jminAccel=l.jminAccel; jmaxAccel=l.jmaxAccel;
00076   active=l.active;
00077   dirtyHash(); 
00078   return *this;
00079 }
00080 
00081 
00082 bool KinematicChain::Link::operator==(const Link& l) const
00083 {
00084   if (linkType != l.linkType) return false;
00085   if (this == &l) return true;
00086   
00087   switch (linkType) {
00088     case Prismatic:
00089     case Revolute:
00090       return    Math::equals(alpha,l.alpha) && Math::equals(theta,l.theta) 
00091              && Math::equals(d,l.d) && Math::equals(a,l.a) && (active==l.active);
00092     case Translating:
00093       return direction.equals(l.direction) && (active==l.active);
00094     case FixedTransform:
00095       return transform.equals(l.transform);
00096     default:
00097       throw std::runtime_error(Exception("unhandled KinematicChain::Link type"));
00098   }
00099   
00100   return false;
00101 }
00102 
00103 
00104 base::Matrix KinematicChain::Link::kinematicTransform(const base::Vector& q) const
00105 {
00106   Assert(q.size() == dof());
00107   Matrix A(4,4);
00108   
00109   if (isDHType()) {
00110     Real d = ((linkType == Prismatic) && active)?q[0]:this->d;
00111     Real theta = ((linkType == Revolute) && active)?q[0]:this->theta;
00112     
00113     // Compute the transformation that transforms the coord. frame of
00114     //  this link into the frame of the previous one
00115     // (see a ref on Denavit-Hartenberg parameters - e.g. "Robot Manipulators" by Richard P. Paul.)
00116     Real sinAlpha = Math::sin(alpha);
00117     Real cosAlpha = Math::cos(alpha);
00118     Real sinTheta = Math::sin(theta);
00119     Real cosTheta = Math::cos(theta);
00120     
00121     A(0,0) = cosTheta; A(0,1) = -sinTheta*cosAlpha; A(0,2) = sinTheta*sinAlpha;  A(0,3) = a*cosTheta; 
00122     A(1,0) = sinTheta; A(1,1) = cosTheta*cosAlpha;  A(1,2) = -cosTheta*sinAlpha; A(1,3) = a*sinTheta;
00123     A(2,0) = 0;        A(2,1) = sinAlpha;           A(2,2) = cosAlpha;           A(2,3) = d;
00124     A(3,0) = 0;        A(3,1) = 0;                  A(3,2) = 0;                  A(3,3) = 1;
00125   }
00126   else if (linkType == Translating) {
00127     A = base::identityMatrix(4,4);
00128     Assert(direction.length() > 0);
00129     Vector3 dir(direction);
00130     dir.normalize();
00131     Real v = active?q[0]:t;
00132     A(0,3) = dir.x * v;
00133     A(1,3) = dir.y * v;
00134     A(2,3) = dir.z * v;
00135   }
00136   else if (linkType == FixedTransform) {
00137     A = base::fromMatrix4(transform);
00138   }
00139   else
00140     throw std::runtime_error(Exception("unhandled KinematicChain::Link type"));
00141   
00142   return A;
00143 }
00144 
00145 
00146 base::array<base::Byte> KinematicChain::Link::hashCode() const
00147 {
00148   if (!hashDirty) return hash;
00149   
00150   // create an MD5 hash over relevant link parameters
00151   MD5 md5;
00152   md5.update( (unsigned char *)(&linkType), sizeof(LinkType) );
00153   md5.update( (unsigned char *)(&active), sizeof(bool) );
00154   
00155   switch (linkType) {
00156     case Translating:
00157       md5.update( (unsigned char *)(&direction.x), sizeof(Real) );
00158       md5.update( (unsigned char *)(&direction.y), sizeof(Real) );
00159       md5.update( (unsigned char *)(&direction.z), sizeof(Real) );
00160       md5.update( (unsigned char *)(&t), sizeof(Real) );
00161       break;
00162     case FixedTransform:
00163       for (Int r=1; r<=4; r++)
00164         for(Int c=1; c<=4; c++) {
00165           Real e = transform(r,c);
00166           md5.update( (unsigned char *)(&e), sizeof(Real) );
00167         }
00168       break;
00169     case Prismatic: 
00170     case Revolute:
00171       md5.update( (unsigned char *)(&alpha), sizeof(Real) );
00172       md5.update( (unsigned char *)(&a), sizeof(Real) );
00173       md5.update( (unsigned char *)(&d), sizeof(Real) );
00174       md5.update( (unsigned char *)(&theta), sizeof(Real) );
00175       break;
00176     default: Assertm(false,"known joint type");
00177   }
00178   
00179   md5.finalize();
00180   hash.resize(16); // MD5 implies 16 byte hash
00181   unsigned char *digest = md5.raw_digest();
00182   for(Int b=0; b<16; b++) hash[b] = digest[b];
00183   
00184   return hash;
00185 }
00186 
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194 
00195 bool KinematicChain::isDHType() const
00196 {
00197   for(Int i=0; i<links.size(); i++)
00198     if (!links[i].isDHType()) return false;
00199   return true;
00200 }
00201 
00202   
00203 KinematicChain KinematicChain::subChain(Int first, Int count) const
00204 {
00205   Assert( first < size() );
00206   Assert( first+count <= size() );
00207   LinkArray la(count);
00208   for(Int i=0; i<count; i++) la[i]=links[first+i];
00209   return KinematicChain(la);
00210 }
00211 
00212     
00213 KinematicChain& KinematicChain::operator+=(const KinematicChain& kc)
00214 {
00215   if (kc.size() > 0) {
00216     for(Int i=0; i<kc.size(); i++)
00217       links.push_back(kc[i]);
00218     computeVariables(); 
00219   }
00220   dirtyHash();
00221   return *this;
00222 }
00223 
00224 
00225 KinematicChain& KinematicChain::insert(Int pos, const KinematicChain& kc)
00226 {
00227   Assert( pos <= size() );
00228   KinematicChain newkc( subChain(0,pos) );
00229   newkc += kc;
00230   newkc += subChain(pos,size()-pos);
00231   *this = newkc;
00232   computeVariables(); 
00233   dirtyHash();
00234   return *this;
00235 }
00236 
00237 
00238 KinematicChain& KinematicChain::insert(Int pos, const Link& l)
00239 {
00240   Assert( pos <= size() );
00241   KinematicChain newkc( subChain(0,pos) );
00242   newkc += l;
00243   newkc += subChain(pos,size()-pos);
00244   *this = newkc;
00245   computeVariables(); 
00246   dirtyHash();
00247   return *this;
00248 }  
00249 
00250 
00251 KinematicChain& KinematicChain::erase(Int pos)
00252 {
00253   Assert( pos < size() );
00254   KinematicChain newkc( size()-1);
00255   for(Int i=0; i<size(); i++)
00256     if (i!=pos) newkc.push_back(links[i]);
00257   *this = newkc;
00258   computeVariables(); 
00259   dirtyHash();
00260   return *this;
00261 }
00262 
00263 
00264 KinematicChain& KinematicChain::erase(Int first, Int last)
00265 {
00266   Assert( first <= last );
00267   Assert( first < size() );
00268   Assert( last <= size() );
00269   KinematicChain newkc( size()-(last-first) );
00270   for(Int i=0; i<size(); i++)
00271     if (!((i>=first) && (i<last))) newkc.push_back(links[i]);
00272   *this = newkc;
00273   computeVariables(); 
00274   dirtyHash();
00275   return *this;
00276 }
00277 
00278 
00279 
00280 void KinematicChain::computeVariables()
00281 {
00282   variables.clear();
00283   for(Int l=0; l<size(); l++) {
00284     const Link& link(links[l]);
00285 
00286     for(Int d=0; d<link.dof(); d++)
00287       variables.push_back( std::make_pair<Int,Int>(l,d) );
00288   } 
00289 }
00290 
00291 
00292 
00293 
00294 
00295 bool KinematicChain::KinematicEvaluatorInitialized = false;
00296 ref<KinematicEvaluator> KinematicChain::defaultKinematicEvaluator;
00297 
00298 
00299 void KinematicChain::initKinematicEvaluator() 
00300 {
00301   if (!KinematicEvaluatorInitialized) {
00302     KinematicEvaluatorInitialized = true;
00303     defaultKinematicEvaluator = ref<JFKengine>(NewObj JFKengine()); 
00304   }
00305   kinematicEvaluator = defaultKinematicEvaluator;
00306 }
00307 
00308 
00309 
00310 Matrix KinematicChain::getForwardKinematics(const Vector& q) const
00311 {
00312   return kinematicEvaluator->getForwardKinematics(*this,q);
00313 }
00314 
00315   
00316 Matrix KinematicChain::getJacobian(const Vector& q, bool includeOrientation) const
00317 {
00318   return kinematicEvaluator->getJacobian(*this, q, includeOrientation);
00319 }
00320 
00321 array<Vector> KinematicChain::getJointOrigins(const Vector& q) const
00322 {
00323   return kinematicEvaluator->getJointOrigins(*this, q);
00324 }
00325 
00326 
00327 array<Vector> KinematicChain::getLinkOrigins(const Vector& q) const
00328 {
00329   return kinematicEvaluator->getLinkOrigins(*this, q);
00330 }
00331 
00332 
00333 
00334 
00335 Vector KinematicChain::transform(Int fromLink, Int toLink, const Vector& v, const Vector& q) const
00336 {
00337   if (fromLink == toLink) return v;
00338   
00339   Int from = fromLink;
00340   Int to = toLink;
00341   
00342   if (fromLink < toLink) base::swap(from, to);
00343   
00344   KinematicChain subTo_From(subChain(toLink, fromLink-toLink)); // chain from 'to' to 'from'
00345   KinematicChain sub0_To(subChain(0, toLink)); // chain from 0 to 'to'
00346   Vector subq( vectorRange(q, Range(sub0_To.dof(), subTo_From.dof())) );
00347   
00348   Matrix4 T( base::toMatrix4(subTo_From.getForwardKinematics(subq)) );
00349     
00350   if (fromLink < toLink) T.invert();
00351   
00352   return base::fromVector3(T*base::toVector3(v));
00353 }
00354 
00355   
00356 Vector KinematicChain::transform(const String& fromFrame, const String& toFrame, const Vector& v, const Vector& q) const
00357 {
00358   const SInt NotFound = -2;
00359   const SInt InitialFrame = -1;
00360   
00361   // find link frames
00362   SInt from = NotFound;
00363   if (fromFrame == initialFrame)
00364     from=InitialFrame;
00365   else {
00366     for (Int fl=0; fl<size(); fl++) 
00367       if (links[fl].frameName == fromFrame) {
00368         from=fl;
00369         break;
00370       }
00371   }
00372     
00373   
00374   SInt to = NotFound;
00375   if (toFrame == initialFrame)
00376     to=InitialFrame;
00377   else {
00378     for (Int tl=0; tl<size(); tl++)
00379       if (links[tl].frameName == toFrame) {
00380         to=tl;
00381         break;
00382       }
00383   }
00384     
00385   if (from==NotFound)
00386     throw std::invalid_argument(Exception("unknown frame name:"+fromFrame));
00387   if (to==NotFound)
00388     throw std::invalid_argument(Exception("unknown frame name:"+toFrame));
00389 
00390   if (from == to) return v; // nothing to do
00391   
00392   
00393   if ((from != InitialFrame) && (to != InitialFrame))
00394     return transform(from, to, v, q);
00395 
00396   // special case when one frame is the initial frame
00397   Unimplemented;
00398   
00399 }
00400 
00401   
00402   
00403 
00404 void KinematicChain::externalize(base::Externalizer& e, String format, Real version)
00405 {
00406   if (format == "") format = "xml";
00407 
00408   if (!formatSupported(format,version,e.ioType()))
00409     throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00410 
00411   if (e.isOutput()) {
00412 
00413     DOMElement* chainElem = e.createElement("kinematicchain");
00414     bool allDHLinks = isDHType();
00415     e.setElementAttribute(chainElem,"type",allDHLinks?"DH":"mixed" );
00416 
00417     e.appendComment(chainElem,"Parameters describing the serial Kinematic Chain:");
00418     e.appendComment(chainElem,"  revolute , {alpha} ,     {a} ,     {d} , {theta} ,{minlimit},{maxlimit} ");
00419     e.appendComment(chainElem,"  prismatic, {alpha} ,     {a} ,     {d} , {theta} ,{minlimit},{maxlimit} ");
00420     if (!allDHLinks) {
00421       e.appendComment(chainElem,"  translating,         {dir.x} , {dir.y} , {dir.z} ,{minlimit},{maxlimit} ");
00422       // transform here!!!
00423     }
00424 
00425     e.pushContext(chainElem);
00426     for(Int l=0; l<links.size(); l++) 
00427       links[l].externalize(e, format, version);
00428     e.popContext();
00429     
00430     e.appendElement(chainElem);
00431 
00432   } else { // input
00433 
00434     DOMNode* context = e.context();
00435     
00436     DOMElement* chainElem = e.getFirstElement(context, "kinematicchain");
00437 
00438     String units = e.getDefaultedElementAttribute(chainElem, "units", "meters");
00439     if ((units != "meters") && (units != "inches"))
00440       throw externalization_error(Exception("unknown/unsupported length unit:"+units));
00441     
00442     String type = e.getDefaultedElementAttribute(chainElem, "type", "mixed");
00443     if ( (type == "mixed") || (type == "DH")) {
00444 
00445       links.clear();
00446       e.pushContext(chainElem);
00447       
00448       while (e.getFirstChildElement(chainElem, "link",false) != 0) { // more joints?
00449         Link l;
00450         l.externalize(e, format, version);
00451         if ( (!l.isDHType()) && (type == "DH"))
00452           throw externalization_error(Exception("a non D-H type joint was specified for a kinematic chain of type 'DH' (try type 'mixed')"));
00453         
00454         // convert all length measures to meters
00455         if (units != "meters") {
00456           Real scale = 1.0;
00457           if (units == "inches") scale = 0.0254;
00458           
00459           if (l.isDHType()) {
00460             l.setA( l.getA()*scale );
00461             l.setD( l.getD()*scale );
00462           }
00463           else if (l.type() == KinematicChain::Link::FixedTransform) {
00464             Logln("Warning: conversion from "+units+" to meters unsupported for fixed transform links");
00465           }
00466 
00467         }
00468         
00469         links.push_back(l);
00470       }
00471       
00472       e.popContext();
00473     
00474       if (links.size() < 1)
00475         throw externalization_error(Exception("a KinematicChain must contain at least one link (<link>...</link>)."));
00476 
00477     }
00478     else
00479       throw externalization_error(Exception(String("unknown KinematicChain type ")+type));
00480       
00481     computeVariables();
00482     dirtyHash(); 
00483   }
00484 }
00485 
00486 
00487 
00488 void KinematicChain::Link::externalize(base::Externalizer& e, String format, Real version)
00489 {
00490   if (format == "") format = "xml";
00491   
00492   if (!formatSupported(format,version,e.ioType()))
00493     throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00494   
00495   if (e.isOutput()) {
00496     DOMElement* linkElem = e.createElement("link",false);
00497     char buf[1024];
00498 
00499     if (type() == Revolute) {
00500       if (  (Math::equals(jminLimit, KinematicChain::unboundedMinAngleLimit))
00501           ||(Math::equals(jmaxLimit, KinematicChain::unboundedMaxAngleLimit)) )
00502         sprintf(buf, "revolute , %8.4f, %8.4f, %8.4f, %8.4f,    -inf ,     +inf ",
00503                 Math::radToDeg(alpha), a, d, Math::radToDeg(theta));
00504       else
00505         sprintf(buf, "revolute , %8.4f, %8.4f, %8.4f, %8.4f, %8.4f, %8.4f ",
00506                 Math::radToDeg(alpha), a, d, Math::radToDeg(theta),
00507                 Math::radToDeg(jminLimit), Math::radToDeg(jmaxLimit));
00508     }
00509     else if (type() == Prismatic) {
00510       char minBuf[32], maxBuf[32];
00511       if (Math::equals(jminLimit, KinematicChain::unboundedMinDistLimit,999))
00512         sprintf(minBuf, "%8.4f", jminLimit);
00513       else
00514         sprintf(minBuf, "%s", "-inf");
00515 
00516       if (Math::equals(jmaxLimit, KinematicChain::unboundedMaxDistLimit,999))
00517         sprintf(maxBuf, "%8.4f", jmaxLimit);
00518       else
00519         sprintf(maxBuf, "%s", "+inf");
00520 
00521       sprintf(buf, "prismatic, %8.4f, %8.4f, %8.4f, %8.4f, %s, %s ",
00522               Math::radToDeg(alpha), a, d, Math::radToDeg(theta),
00523               minBuf, maxBuf);
00524     }
00525     else if (type() == Translating) {
00526       char minBuf[32], maxBuf[32];
00527       if (Math::equals(jminLimit, KinematicChain::unboundedMinDistLimit,999))
00528         sprintf(minBuf, "%8.4f", jminLimit);
00529       else
00530         sprintf(minBuf, "%s", "-inf");
00531 
00532       if (Math::equals(jmaxLimit, KinematicChain::unboundedMaxDistLimit,999))
00533         sprintf(maxBuf, "%8.4f", jmaxLimit);
00534       else
00535         sprintf(maxBuf, "%s", "+inf");
00536 
00537       sprintf(buf, "translating,         %8.4f, %8.4f, %8.4f, %s, %s ",
00538               direction.x, direction.y, direction.z,
00539               minBuf, maxBuf);
00540     }
00541     else if (type() == FixedTransform) {
00542       Unimplemented; ///!!!
00543     } 
00544     else
00545       throw externalization_error(Exception(String("unknown link type")));
00546       
00547     e.appendText(linkElem,String(buf));
00548     e.appendElement(linkElem);
00549     e.appendBreak();
00550   }
00551   else { // input
00552     DOMNode* context = e.context();
00553     
00554     DOMElement* linkElem = e.getFirstChildElement(context, "link");
00555 
00556     String linkText = e.getContainedText(linkElem);
00557     array<String> elts = e.splitAtDelimiter(linkText,',');
00558     elts[0] = e.removeChar(elts[0],' ');
00559     if (elts[0] == "revolute")
00560       linkType = Revolute;
00561     else if (elts[0] == "prismatic")
00562       linkType = Prismatic;
00563     else if (elts[0] == "translating")
00564       linkType = Translating;
00565     else if (elts[0] == "transform")
00566       linkType = FixedTransform;
00567     else
00568       throw externalization_error(Exception(String("link type should be either 'revolute', 'prismatic', 'translating' or 'transform'; not '")+elts[0]+"'."));
00569 
00570     Vector vals( e.stringsToReals(elts) );
00571     jminLimit=jmaxLimit = 0.0;
00572     if (isDHType()) {
00573       alpha = Math::degToRad( vals[1] );
00574       a = vals[2];
00575       d = vals[3];
00576       theta = Math::degToRad( vals[4] );
00577       if (type() == Revolute) {
00578         if (vals.size() > 6) {
00579           jminLimit = Math::degToRad( vals[5] );
00580           jmaxLimit = Math::degToRad( vals[6] );
00581         }
00582         if (Math::equals(jminLimit,0) && Math::equals(jmaxLimit,0)) { // unbounded
00583           jminLimit = KinematicChain::unboundedMinAngleLimit;
00584           jmaxLimit = KinematicChain::unboundedMaxAngleLimit;
00585         }
00586         
00587       }
00588       else {
00589         if (vals.size() > 6) {
00590           jminLimit = vals[5];
00591           jmaxLimit = vals[6];
00592         }
00593         if (Math::equals(jminLimit,0) && Math::equals(jmaxLimit,0)) { // unbounded
00594           jminLimit = unboundedMinDistLimit;
00595           jmaxLimit = unboundedMaxDistLimit;
00596         }
00597       }
00598     }
00599     else if (type() == Translating) {
00600       direction.x = vals[1];
00601       direction.y = vals[2];
00602       direction.z = vals[3];
00603       if (vals.size() > 5) {
00604         jminLimit = vals[4];
00605         jmaxLimit = vals[5];
00606       }
00607       if (Math::equals(jminLimit,0) && Math::equals(jmaxLimit,0)) { // unbounded
00608         jminLimit = unboundedMinDistLimit;
00609         jmaxLimit = unboundedMaxDistLimit;
00610       }
00611     }
00612     else if (type() == FixedTransform) {
00613       Unimplemented; ///!!!
00614     }
00615     else
00616       Assertm(false,"link type not implemented");
00617 
00618     e.removeElement(linkElem);
00619     
00620     dirtyHash(); 
00621   }
00622 
00623 }
00624 
00625 
00626 base::array<base::Byte> KinematicChain::hashCode() const
00627 {
00628   if (!hashDirty) return hash;
00629   
00630   // create an MD5 hash over the link size, dof and each link's hashCode()
00631   MD5 md5;
00632   Int chainSize = size();
00633   md5.update( (unsigned char *)(&chainSize), sizeof(Int));
00634   Int chainDOF = dof();
00635   md5.update( (unsigned char *)(&chainDOF), sizeof(Int));
00636   for(Int l=0; l<size(); l++) {
00637     array<Byte> hashCode( links[l].hashCode() );
00638     md5.update( (unsigned char *)(&(hashCode[0])), hashCode.size()); // assumes array stores Bytes contigously
00639   }
00640   md5.finalize();
00641   
00642   hash.resize(16); // MD5 implies 16 byte hash
00643   unsigned char *digest = md5.raw_digest();
00644   for(Int b=0; b<16; b++) hash[b] = digest[b];
00645   
00646   return hash;
00647 }
00648 
00649 
00650 
00651 std::ostream& robot::operator<<(std::ostream& out, const robot::KinematicChain::Link& l) // Output
00652 {
00653 
00654   switch(l.type()){
00655   case KinematicChain::Link::Revolute:  
00656     if (l.isActive()) 
00657       out << "DH Revolute :" << " alpha:" << Math::radToDeg(l.getAlpha()) << ",  a:" << l.getA() << ",  d:" << l.getD() << ",  {theta}:"  << Math::radToDeg(l.getTheta()) << std::endl; 
00658     else
00659       out << "DH Revolute :" << " alpha:" << Math::radToDeg(l.getAlpha()) << ",  a:" << l.getA() << ",  d:" << l.getD() << ",  theta:"  << Math::radToDeg(l.getTheta()) << std::endl;       
00660     break;
00661   case KinematicChain::Link::Prismatic:  
00662     if (l.isActive())
00663       out << "DH Prismatic:" << " alpha:" << Math::radToDeg(l.getAlpha()) << ",  a:" << l.getA() << ",  {d}:" << l.getD() << ",  theta:"  << Math::radToDeg(l.getTheta()) << std::endl;
00664     else
00665       out << "DH Prismatic:" << " alpha:" << Math::radToDeg(l.getAlpha()) << ",  a:" << l.getA() << ",  d:" << l.getD() << ",  theta:"  << Math::radToDeg(l.getTheta()) << std::endl;
00666     break;
00667   case KinematicChain::Link::Translating:
00668     if (l.isActive())
00669       out << "Translating : direction {t}:" << l.getT() << "*" << l.getDirection() << std::endl;
00670     else
00671       out << "Translating : direction t:" << l.getT() << "*" << l.getDirection() << std::endl;
00672     break;
00673   case KinematicChain::Link::FixedTransform:
00674     out << "Transform   : translation:" << l.getTransform().column(4).toVector3() << " rotation:" << base::Orient(Matrix3(l.getTransform())).getQuat4() << std::endl;
00675     break;
00676   default: out << "unknown joint type\n";
00677   }
00678   return out;
00679 }
00680 
00681 
00682 

Generated on Thu Jul 29 15:56:36 2004 for OpenSim by doxygen 1.3.6