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

robot/JFKengine.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 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: JFKengine.cpp 1039 2004-02-11 20:50:52Z jungd $
00019   $Revision: 1.5 $
00020   $Date: 2004-02-11 15:50:52 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022 
00023 ****************************************************************************/
00024 
00025 #include <robot/JFKengine>
00026 #include <base/base>
00027 
00028 #include <base/Time>
00029 
00030 using robot::JFKengine;
00031 using robot::KinematicChain;
00032 
00033 using base::Math;
00034 using base::Time;
00035 using base::Vector;
00036 using base::Vector3;
00037 using base::Matrix;
00038 using base::Expression;
00039 using base::ExpressionMatrix;
00040 
00041 
00042 JFKengine::JFKengine() 
00043   : forwardKinematicsCached(false), A(0), T(0), 
00044     JCached(false), J(1,1)
00045 {
00046 }
00047 
00048 
00049 ExpressionMatrix JFKengine::getForwardKinematics(const KinematicChain& chain) const
00050 { 
00051   const Int n = chain.size(); // no. of links in the chain
00052 
00053   const Real trigEpsilon = 1.0e-5; // if sin or cos of angles are smaller, set sin=0 or cos=0
00054 
00055   if (n < 1) { // no links, return identity
00056     ExpressionMatrix I(4,4);
00057     I(0,0)=I(1,1)=I(2,2)=I(3,3)=1;
00058     return I;
00059   }
00060 
00061   if ( A.size() != n ) {
00062     // array resize is non-descructive (except the the elements truncated when resizing smaller)
00063     A.resize(n);
00064     T.resize(n);
00065     chain_AT.resize(n);
00066   }
00067 
00068   Expression zero = 0;
00069   Expression one = 1;
00070 
00071   // form A[i], the position and orientation matrix of frame for this link, relative to last one
00072   Int dof = 0;
00073   for ( Int l = 0; l < n; l++ ) {
00074     const KinematicChain::Link& link( chain[l] );
00075     //Debugcln(JFKE, "\n=====getForwardKinematics loop, joint " << (i+1) << ": " << joint);
00076 
00077     // determine if we're already computed and cached the A[l], the transform between
00078     //  the last link and this one 
00079     if (forwardKinematicsCached) { // something is cached, see if it is what we want
00080       if ( chain_AT[l] != link ) 
00081         forwardKinematicsCached = false;  // must recompute A & T from this link on, since link is different
00082     }
00083 
00084 
00085     if (!forwardKinematicsCached) {
00086 
00087       A[l].resize(4,4); T[l].resize(4,4);
00088       chain_AT.setLink(l, link);  // for caching, save parameters used to compute A & T
00089       //Debugcln(JFKE,"JFKEngine(): FK link " << l << "(dof=" << dof << "):" << link);
00090 
00091       Expression theta, d; // used to set variables for Denavit-Hartenberg notation
00092       if (link.isDHType()) {    // D-H type joints (Revolute, Prismatic)
00093 
00094         // determine what is constant and what is variable to set expressions for theta and d
00095         if (link.type() == KinematicChain::Link::Revolute) {
00096           if (link.isActive())
00097             theta = Expression::p[dof];
00098           else
00099             theta = link.getTheta(); // inactive joints are considered to be fixed in the home position
00100           d = link.getD();
00101         }
00102         else { // Prismatic
00103           theta = link.getTheta();
00104           if (link.isActive())
00105             d = Expression::p[dof];
00106           else
00107             d = link.getD();        // inactive joints are considered to be fixed in the home position
00108         }
00109 
00110         Real sinAlpha = Math::zeroIfNeighbour( Math::sin(link.getAlpha()), trigEpsilon );
00111         Real cosAlpha = Math::zeroIfNeighbour( Math::cos(link.getAlpha()), trigEpsilon );
00112         Expression sinTheta = sin(theta);
00113         Expression cosTheta = cos(theta);
00114         
00115         // form A[i], which represents the position and orientation of frame i relative to frame i-1
00116         A[l](0,0)=cosTheta; A[l](0,1)=-sinTheta*cosAlpha; A[l](0,2)=sinTheta*sinAlpha;  A[l](0,3)=link.getA()*cosTheta;
00117         A[l](1,0)=sinTheta; A[l](1,1)=cosTheta*cosAlpha;  A[l](1,2)=-cosTheta*sinAlpha; A[l](1,3)=link.getA()*sinTheta;
00118         A[l](2,0)=zero;     A[l](2,1)=sinAlpha;           A[l](2,2)=cosAlpha;           A[l](2,3)=d;
00119         A[l](3,0)=zero;     A[l](3,1)=zero;               A[l](3,2)=zero;               A[l](3,3)=one;
00120 
00121       } 
00122       else { // non-D-H type joint
00123 
00124         if (link.type() == KinematicChain::Link::Translating) {
00125 
00126           Expression t = Expression::p[dof]; // translation distance variable
00127           Assert(link.getDirection().length() > 0);
00128           Vector3 dir( link.getDirection() ); dir.normalize(); // make unit length
00129           
00130           // simple translation by t*dir
00131           A[l](0,0)=one;  A[l](0,1)=zero; A[l](0,2)=zero; A[l](0,3)=dir.x*t;
00132           A[l](1,0)=zero; A[l](1,1)=one;  A[l](1,2)=zero; A[l](1,3)=dir.y*t;
00133           A[l](2,0)=zero; A[l](2,1)=zero; A[l](2,2)=one;  A[l](2,3)=dir.z*t;
00134           A[l](3,0)=zero; A[l](3,1)=zero; A[l](3,2)=zero; A[l](3,3)=one;
00135 
00136         } // end Translating
00137         else if (link.type() == KinematicChain::Link::FixedTransform) {
00138 
00139           // this is a 0-dof transforming link
00140           A[l] = base::toExpressionMatrix(base::fromMatrix4(link.getTransform()));
00141 
00142 
00143         } // end FixedTransform
00144         else
00145           throw std::runtime_error(Exception("unsupported joint type in chain - can't calculate forward kinematic transform"));
00146 
00147       }
00148 
00149       simplify( A[l] );
00150 
00151       if ( l < 1 )
00152         T[l] = A[l];
00153       else {
00154         T[l] = T[l-1] * A[l];
00155         simplify( T[l] );
00156       }
00157    
00158       //Debugcln(JFKE, "\nA[" << (i+1) << "] matrix after simplification:\n" << A[i]);
00159       //Debugcln(JFKE, "\nT[" << (i+1) << "] matrix after simplification:\n" << T[i]);
00160     }
00161 
00162     dof += link.dof();
00163     // end single link contribution
00164 
00165   } // for l
00166 
00167   
00168   //Debugc( JFKE, "Homogeneous transformation matrix T[" << n << "]:");
00169  
00170   /*
00171   for (Int iRow=0; iRow<4; iRow++) {
00172     Debugc( JFKE, "\n");
00173     for (Int iCol=0; iCol<4; iCol++) {
00174       Debugcln( JFKE, "  (" << iRow << "," << iCol << ")=" << T[n-1](iRow,iCol));
00175     }
00176   }
00177   */
00178   
00179   forwardKinematicsCached = true;
00180 
00181   //Debugcln(KF, "\n" << chain_AT.size() << " Cached JointParamters in chain_AT\n" << chain_AT);
00182   return T[n-1];
00183 }
00184 
00185 
00186 
00187 ExpressionMatrix JFKengine::getJacobian(const KinematicChain& chain, bool includeOrientation) const
00188 {
00189   const Int n = chain.size(); 
00190   const Int chain_dof = chain.dof(); // no. of variables / degrees-of-freedom
00191 
00192   if (chain.dof() < 1) { // no joints, return zero/empty matrix
00193     ExpressionMatrix Z(includeOrientation?6:3,0);
00194     return Z;
00195   }
00196  
00197   //Debugln(JFKE, "\n");
00198 
00199   // see if cached J can be used
00200   if ( chain_J.dof() != chain_dof ) {
00201     JCached = false;  // must recompute J because not same number of joints as what is cached
00202   }
00203   else {
00204     if (chain_J.hashCode() != chain.hashCode())
00205       JCached = false;  // must recompute J because joints are not the same as what is cached
00206     else {
00207       if (includeOrientation) {
00208         if (J.size1() != 6)
00209           JCached = false; // orientation components weren't cached
00210       }
00211       else {
00212         // if cached J includes orientation components we don't need, discard them
00213         ExpressionMatrix cachedJ(J); // make copy
00214         J.resize(3,cachedJ.size2()); // destructive resize
00215         // copy position components back
00216         for(Int r=0; r<3; r++)
00217           for(Int c=0; c<J.size2(); c++)
00218             J(r,c) = cachedJ(r,c);
00219       }
00220     }
00221   }
00222   
00223 
00224   if (!JCached) { // recompute
00225     #ifdef DEBUG
00226     base::Time start( Time::now() );
00227     #endif
00228 
00229     chain_J = chain;
00230     J.resize(includeOrientation?6:3, chain_dof);
00231 
00232     getForwardKinematics( chain );  // ensure manipulator arm expression T is cached
00233  
00234     Expression zero = 0;
00235     Expression one = 1;
00236 
00237     for (Int dof=0, l=0; l < n; l++) { // for each link
00238       const KinematicChain::Link& link( chain[l] );
00239 
00240       if (link.dof() > 0) { 
00241 
00242         // Jacobian rows 1,2,3:  differentiate x,y,z: fourth column of T
00243         for (Int iVar=0; iVar < 3; iVar++) {
00244           //Debugcln(KF, "J(" << iVar << "," << iJoint << ") Before differentiating, expression= " << T[n-1](iVar,3) );
00245           J(iVar,dof) = T[n-1](iVar,3).differentiate( Expression::p[dof] );
00246           J(iVar,dof).simplify();
00247           //Debugcln(KF, "J(" << iVar << "," << iJoint << ") after differentiating =" << J(iVar,iJoint) );
00248         }
00249         
00250         if (includeOrientation) {
00251           // Jacobian rows 4,5,6: 
00252           const  KinematicChain::Link::LinkType linkType( (chain[l]).type() );
00253           switch (linkType) {
00254           case KinematicChain::Link::Revolute:  
00255             if (dof < 1) {
00256               J(3,0) = J(4,0) = zero; // [0,0,1] for first column, by definition
00257               J(5,0) = one;
00258             }
00259             else {
00260               J(3,dof) = T[l-1](0,2); // from position in cumulative transformation matrix T
00261               J(4,dof) = T[l-1](1,2);
00262               J(5,dof) = T[l-1](2,2);
00263             }
00264             break;
00265             
00266           case KinematicChain::Link::Prismatic:
00267           case KinematicChain::Link::Translating:
00268             for (Int i=3; i< 6; i++) {
00269               J(i,dof) = zero;  // no angular velocity contribution for prismatic or translating joints
00270             }
00271             break;
00272           default:
00273             throw std::runtime_error(Exception("unsupported joint type in chain - can't compute Jacobian"));
00274           }
00275         } // end if(includeOrientation)
00276 
00277       } // if link.dof() > 0
00278 
00279       dof += link.dof();
00280 
00281     } // for each link
00282     
00283     /*
00284     Debugcln( JFKE, "Jacobian matrix: \n");
00285     for (Int iJoint = 0; iJoint<n; iJoint++) {
00286       Debugcln( JFKE, "J[" << (iJoint+1) << "]=");
00287       for (Int iRow=0; iRow<(includeOrientation?6:3); iRow++) {
00288         Debugcln( JFKE, "\t" << J(iRow,iJoint) << "\n");
00289       }
00290     }
00291     */
00292 
00293     JCached = true;
00294     //Debugcln(KF, "\n" << chain_J.size() << " Cached JointParamters in chain_J\n" << chain_J);
00295     #ifdef DEBUG
00296     Debugln( JFKE, "Symbolic Jacobian computation for " << chain.size() 
00297                  << " link manipulator took " << (Time::now()-start).seconds() << "s");
00298     #endif
00299   }  // end JCached else
00300   return J;
00301 }
00302 
00303 
00304 
00305 Matrix JFKengine::getForwardKinematics(const KinematicChain& chain, const Vector& q) const
00306 {
00307   ExpressionMatrix F( getForwardKinematics(chain) );
00308   return evaluate(F,q);
00309 }
00310 
00311 
00312 Matrix JFKengine::getJacobian(const KinematicChain& chain, const Vector& q, bool includeOrientation) const
00313 {
00314   ExpressionMatrix J( getJacobian(chain, includeOrientation) );
00315   return evaluate(J,q);
00316 }
00317 
00318 
00319 
00320 
00321 array<Vector> JFKengine::getJointOrigins(const KinematicChain& chain, const Vector& q ) const
00322 {
00323   if ( chain.dof() < 1 )
00324     return array<Vector>(0); // no joints
00325 
00326   Assert(q.size() == chain.dof() );
00327 
00328   // NB: assumes no joints with dof > 1 !  i.e. 1<->1  joints<->dofs
00329   
00330   const Int chain_dof = chain.dof();
00331 
00332   array<Vector> locs(chain_dof); 
00333   getForwardKinematics(chain); // cache T
00334 
00335   for (Int v=0; v < chain_dof; v++ ) {
00336     locs[v].resize(3);
00337     Int li = chain.linkIndexOfVariable(v);
00338     for ( Int iDimension=0; iDimension < 3; iDimension++ ) {
00339       locs[v][iDimension] = T[li](iDimension,3).evaluate( q ); 
00340     }
00341   }
00342  
00343   return locs;
00344 }
00345 
00346 
00347 array<Vector> JFKengine::getLinkOrigins(const KinematicChain& chain, const Vector& q ) const
00348 {
00349   if ( chain.size() < 1 )
00350     return array<Vector>(0); // no links
00351 
00352   Assert(q.size() == chain.dof() );
00353 
00354   const Int chain_size = chain.size();
00355 
00356   array<Vector> locs(chain_size); 
00357   getForwardKinematics(chain); // cache T
00358 
00359   for (Int li=0; li < chain_size; li++ ) {
00360     locs[li].resize(3);
00361     for ( Int iDimension=0; iDimension < 3; iDimension++ ) {
00362       locs[li][iDimension] = T[li](iDimension,3).evaluate( q );  
00363     }
00364   }
00365  
00366   //Debugln(JFKE, "\ngetLinkOrigins :" << chain );
00367   //for ( Int i=0; i<chain_size; i++ ) {
00368   //  Debugcln(JFKE, "link " << i << " location relative to first link: [" << locs[i][0] << ", " << locs[i][1] << ", " << locs[i][2] << "]");
00369   //}
00370 
00371   return locs;
00372 }

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