frames.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                         frames.cxx -  description
00003                        -------------------------
00004     begin                : June 2006
00005     copyright            : (C) 2006 Erwin Aertbelien
00006     email                : firstname.lastname@mech.kuleuven.ac.be
00007 
00008  History (only major changes)( AUTHOR-Description ) :
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place,                                    *
00024  *   Suite 330, Boston, MA  02111-1307  USA                                *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #include "frames.hpp"
00029 
00030 #define _USE_MATH_DEFINES  // For MSVC
00031 #include <math.h>
00032 #include <algorithm>
00033 
00034 namespace KDL {
00035 
00036 #ifndef KDL_INLINE
00037 #include "frames.inl"
00038 #endif
00039 
00040     void Frame::Make4x4(double * d)
00041     {
00042         int i;
00043         int j;
00044         for (i=0;i<3;i++) {
00045             for (j=0;j<3;j++)
00046                 d[i*4+j]=M(i,j);
00047             d[i*4+3] = p(i);
00048         }
00049         for (j=0;j<3;j++)
00050             d[12+j] = 0.;
00051         d[15] = 1;
00052     }
00053 
00054     Frame Frame::DH_Craig1989(double a,double alpha,double d,double theta)
00055     // returns Modified Denavit-Hartenberg parameters (According to Craig)
00056     {
00057         double ct,st,ca,sa;
00058         ct = cos(theta);
00059         st = sin(theta);
00060         sa = sin(alpha);
00061         ca = cos(alpha);
00062         return Frame(Rotation(
00063                               ct,       -st,     0,
00064                               st*ca,  ct*ca,   -sa,
00065                               st*sa,  ct*sa,    ca   ),
00066                      Vector(
00067                             a,      -sa*d,  ca*d   )
00068                      );
00069     }
00070 
00071     Frame Frame::DH(double a,double alpha,double d,double theta)
00072     // returns Denavit-Hartenberg parameters (Non-Modified DH)
00073     {
00074         double ct,st,ca,sa;
00075         ct = cos(theta);
00076         st = sin(theta);
00077         sa = sin(alpha);
00078         ca = cos(alpha);
00079         return Frame(Rotation(
00080                               ct,    -st*ca,   st*sa,
00081                               st,     ct*ca,  -ct*sa,
00082                               0,        sa,      ca   ),
00083                      Vector(
00084                             a*ct,      a*st,  d   )
00085                      );
00086     }
00087 
00088     double Vector2::Norm() const
00089     {
00090         double tmp1 = fabs(data[0]);
00091         double tmp2 = fabs(data[1]);
00092         
00093         if (tmp1 == 0.0 && tmp2 == 0.0)
00094             return 0.0;
00095 
00096         if (tmp1 > tmp2) {
00097             return tmp1*sqrt(1+sqr(data[1]/data[0]));
00098         } else {
00099             return tmp2*sqrt(1+sqr(data[0]/data[1]));
00100         }
00101     }
00102     // makes v a unitvector and returns the norm of v.
00103     // if v is smaller than eps, Vector(1,0,0) is returned with norm 0.
00104     // if this is not good, check the return value of this method.
00105     double Vector2::Normalize(double eps) {
00106         double v = this->Norm();
00107         if (v < eps) {
00108             *this = Vector2(1,0);
00109             return v;
00110         } else {
00111             *this = (*this)/v;
00112             return v;
00113         }
00114     }
00115 
00116 
00117     // do some effort not to lose precision
00118     double Vector::Norm() const
00119     {
00120         double tmp1;
00121         double tmp2;
00122         tmp1 = fabs(data[0]);
00123         tmp2 = fabs(data[1]);
00124         if (tmp1 >= tmp2) {
00125             tmp2=fabs(data[2]);
00126             if (tmp1 >= tmp2) {
00127                 if (tmp1 == 0) {
00128                     // only to everything exactly zero case, all other are handled correctly
00129                     return 0;
00130                 }
00131                 return tmp1*sqrt(1+sqr(data[1]/data[0])+sqr(data[2]/data[0]));
00132             } else {
00133                 return tmp2*sqrt(1+sqr(data[0]/data[2])+sqr(data[1]/data[2]));
00134             }
00135         } else {
00136             tmp1=fabs(data[2]);
00137             if (tmp2 > tmp1) {
00138                 return tmp2*sqrt(1+sqr(data[0]/data[1])+sqr(data[2]/data[1]));
00139             } else {
00140                 return tmp1*sqrt(1+sqr(data[0]/data[2])+sqr(data[1]/data[2]));
00141             }
00142         }
00143     }
00144 
00145     // makes v a unitvector and returns the norm of v.
00146     // if v is smaller than eps, Vector(1,0,0) is returned with norm 0.
00147     // if this is not good, check the return value of this method.
00148     double Vector::Normalize(double eps) {
00149         double v = this->Norm();
00150         if (v < eps) {
00151             *this = Vector(1,0,0);
00152             return v;
00153         } else {
00154             *this = (*this)/v;
00155             return v;
00156         }
00157     }
00158 
00159 
00160     bool Equal(const Rotation& a,const Rotation& b,double eps) {
00161         return (Equal(a.data[0],b.data[0],eps) &&
00162                 Equal(a.data[1],b.data[1],eps) &&
00163                 Equal(a.data[2],b.data[2],eps) &&
00164                 Equal(a.data[3],b.data[3],eps) &&
00165                 Equal(a.data[4],b.data[4],eps) &&
00166                 Equal(a.data[5],b.data[5],eps) &&
00167                 Equal(a.data[6],b.data[6],eps) &&
00168                 Equal(a.data[7],b.data[7],eps) &&
00169                 Equal(a.data[8],b.data[8],eps)    );
00170     }
00171 
00172 
00173 
00174     Rotation operator *(const Rotation& lhs,const Rotation& rhs)
00175     // Complexity : 27M+27A
00176     {
00177         return Rotation(
00178                         lhs.data[0]*rhs.data[0]+lhs.data[1]*rhs.data[3]+lhs.data[2]*rhs.data[6],
00179                         lhs.data[0]*rhs.data[1]+lhs.data[1]*rhs.data[4]+lhs.data[2]*rhs.data[7],
00180                         lhs.data[0]*rhs.data[2]+lhs.data[1]*rhs.data[5]+lhs.data[2]*rhs.data[8],
00181                         lhs.data[3]*rhs.data[0]+lhs.data[4]*rhs.data[3]+lhs.data[5]*rhs.data[6],
00182                         lhs.data[3]*rhs.data[1]+lhs.data[4]*rhs.data[4]+lhs.data[5]*rhs.data[7],
00183                         lhs.data[3]*rhs.data[2]+lhs.data[4]*rhs.data[5]+lhs.data[5]*rhs.data[8],
00184                         lhs.data[6]*rhs.data[0]+lhs.data[7]*rhs.data[3]+lhs.data[8]*rhs.data[6],
00185                         lhs.data[6]*rhs.data[1]+lhs.data[7]*rhs.data[4]+lhs.data[8]*rhs.data[7],
00186                         lhs.data[6]*rhs.data[2]+lhs.data[7]*rhs.data[5]+lhs.data[8]*rhs.data[8]
00187                         );
00188 
00189     }
00190 
00191     Rotation Rotation::Quaternion(double x,double y,double z, double w)
00192     {
00193         double x2, y2, z2, w2;
00194         x2 = x*x;  y2 = y*y; z2 = z*z;  w2 = w*w;
00195         return Rotation(w2+x2-y2-z2, 2*x*y-2*w*z, 2*x*z+2*w*y,
00196                         2*x*y+2*w*z, w2-x2+y2-z2, 2*y*z-2*w*x,
00197                         2*x*z-2*w*y, 2*y*z+2*w*x, w2-x2-y2+z2);
00198     }
00199 
00200     /* From the following sources:
00201        http://web.archive.org/web/20041029003853/http:/www.j3d.org/matrix_faq/matrfaq_latest.html
00202        http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
00203        RobOOP::quaternion.cpp
00204     */
00205     void Rotation::GetQuaternion(double& x,double& y,double& z, double& w) const
00206     {
00207         double trace = (*this)(0,0) + (*this)(1,1) + (*this)(2,2);
00208         double epsilon=1E-12;
00209         if( trace > epsilon ){
00210             double s = 0.5 / sqrt(trace + 1.0);
00211             w = 0.25 / s;
00212             x = ( (*this)(2,1) - (*this)(1,2) ) * s;
00213             y = ( (*this)(0,2) - (*this)(2,0) ) * s;
00214             z = ( (*this)(1,0) - (*this)(0,1) ) * s;
00215         }else{
00216             if ( (*this)(0,0) > (*this)(1,1) && (*this)(0,0) > (*this)(2,2) ){
00217                 double s = 2.0 * sqrt( 1.0 + (*this)(0,0) - (*this)(1,1) - (*this)(2,2));
00218                 w = ((*this)(2,1) - (*this)(1,2) ) / s;
00219                 x = 0.25 * s;
00220                 y = ((*this)(0,1) + (*this)(1,0) ) / s;
00221                 z = ((*this)(0,2) + (*this)(2,0) ) / s;
00222             } else if ((*this)(1,1) > (*this)(2,2)) {
00223                 double s = 2.0 * sqrt( 1.0 + (*this)(1,1) - (*this)(0,0) - (*this)(2,2));
00224                 w = ((*this)(0,2) - (*this)(2,0) ) / s;
00225                 x = ((*this)(0,1) + (*this)(1,0) ) / s;
00226                 y = 0.25 * s;
00227                 z = ((*this)(1,2) + (*this)(2,1) ) / s;
00228             }else {
00229                 double s = 2.0 * sqrt( 1.0 + (*this)(2,2) - (*this)(0,0) - (*this)(1,1) );
00230                 w = ((*this)(1,0) - (*this)(0,1) ) / s;
00231                 x = ((*this)(0,2) + (*this)(2,0) ) / s;
00232                 y = ((*this)(1,2) + (*this)(2,1) ) / s;
00233                 z = 0.25 * s;
00234             }
00235         }    
00236     }
00237 
00238 Rotation Rotation::RPY(double roll,double pitch,double yaw)
00239     {
00240         double ca1,cb1,cc1,sa1,sb1,sc1;
00241         ca1 = cos(yaw); sa1 = sin(yaw);
00242         cb1 = cos(pitch);sb1 = sin(pitch);
00243         cc1 = cos(roll);sc1 = sin(roll);
00244         return Rotation(ca1*cb1,ca1*sb1*sc1 - sa1*cc1,ca1*sb1*cc1 + sa1*sc1,
00245                    sa1*cb1,sa1*sb1*sc1 + ca1*cc1,sa1*sb1*cc1 - ca1*sc1,
00246                    -sb1,cb1*sc1,cb1*cc1);
00247     }
00248 
00249 // Gives back a rotation matrix specified with RPY convention
00250 void Rotation::GetRPY(double& roll,double& pitch,double& yaw) const
00251     {
00252                 double epsilon=1E-12;
00253                 pitch = atan2(-data[6], sqrt( sqr(data[0]) +sqr(data[3]) )  );
00254         if ( fabs(pitch) > (M_PI/2.0-epsilon) ) {
00255             yaw = atan2(        -data[1], data[4]);
00256             roll  = 0.0 ;
00257         } else {
00258             roll  = atan2(data[7], data[8]);
00259             yaw   = atan2(data[3], data[0]);
00260         }
00261     }
00262 
00263 Rotation Rotation::EulerZYZ(double Alfa,double Beta,double Gamma) {
00264         double sa,ca,sb,cb,sg,cg;
00265         sa  = sin(Alfa);ca = cos(Alfa);
00266         sb  = sin(Beta);cb = cos(Beta);
00267         sg  = sin(Gamma);cg = cos(Gamma);
00268         return Rotation( ca*cb*cg-sa*sg,     -ca*cb*sg-sa*cg,        ca*sb,
00269                  sa*cb*cg+ca*sg,     -sa*cb*sg+ca*cg,        sa*sb,
00270                  -sb*cg ,                sb*sg,              cb
00271                 );
00272 
00273      }
00274 
00275 
00276 void Rotation::GetEulerZYZ(double& alpha,double& beta,double& gamma) const {
00277                 double epsilon = 1E-12;
00278         if (fabs(data[8]) > 1-epsilon  ) {
00279             gamma=0.0;
00280             if (data[8]>0) {
00281                 beta = 0.0;
00282                 alpha= atan2(data[3],data[0]);
00283             } else {
00284                 beta = PI;
00285                 alpha= atan2(-data[3],-data[0]);
00286             }
00287         } else {
00288             alpha=atan2(data[5], data[2]);
00289             beta=atan2(sqrt( sqr(data[6]) +sqr(data[7]) ),data[8]);
00290             gamma=atan2(data[7], -data[6]);
00291         }
00292  }
00293 
00294 Rotation Rotation::Rot(const Vector& rotaxis,double angle) {
00295     // The formula is
00296     // V.(V.tr) + st*[V x] + ct*(I-V.(V.tr))
00297     // can be found by multiplying it with an arbitrary vector p
00298     // and noting that this vector is rotated.
00299     Vector rotvec = rotaxis;
00300         rotvec.Normalize();
00301         return Rotation::Rot2(rotvec,angle);
00302 }
00303 
00304 Rotation Rotation::Rot2(const Vector& rotvec,double angle) {
00305     // rotvec should be normalized !
00306     // The formula is
00307     // V.(V.tr) + st*[V x] + ct*(I-V.(V.tr))
00308     // can be found by multiplying it with an arbitrary vector p
00309     // and noting that this vector is rotated.
00310     double ct = cos(angle);
00311     double st = sin(angle);
00312     double vt = 1-ct;
00313     double m_vt_0=vt*rotvec(0);
00314     double m_vt_1=vt*rotvec(1);
00315     double m_vt_2=vt*rotvec(2);
00316     double m_st_0=rotvec(0)*st;
00317     double m_st_1=rotvec(1)*st;
00318     double m_st_2=rotvec(2)*st;
00319     double m_vt_0_1=m_vt_0*rotvec(1);
00320     double m_vt_0_2=m_vt_0*rotvec(2);
00321     double m_vt_1_2=m_vt_1*rotvec(2);
00322     return Rotation(
00323         ct      +  m_vt_0*rotvec(0),
00324         -m_st_2 +  m_vt_0_1,
00325         m_st_1  +  m_vt_0_2,
00326         m_st_2  +  m_vt_0_1,
00327         ct      +  m_vt_1*rotvec(1),
00328         -m_st_0 +  m_vt_1_2,
00329         -m_st_1 +  m_vt_0_2,
00330         m_st_0  +  m_vt_1_2,
00331         ct      +  m_vt_2*rotvec(2)
00332         );
00333 }
00334 
00335 
00336 
00337 Vector Rotation::GetRot() const
00338          // Returns a vector with the direction of the equiv. axis
00339          // and its norm is angle
00340      {
00341        Vector axis;
00342        double angle;
00343        angle = Rotation::GetRotAngle(axis,epsilon);
00344        return axis * angle;
00345      }
00346 
00347 
00348 
00359 double Rotation::GetRotAngle(Vector& axis,double eps) const {
00360     double angle,x,y,z; // variables for result
00361     double epsilon = eps; // margin to allow for rounding errors
00362     double epsilon2 = eps*10; // margin to distinguish between 0 and 180 degrees
00363 
00364     // optional check that input is pure rotation, 'isRotationMatrix' is defined at:
00365     // http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/
00366 
00367     if ((std::abs(data[1] - data[3]) < epsilon)
00368         && (std::abs(data[2] - data[6])< epsilon)
00369         && (std::abs(data[5] - data[7]) < epsilon))
00370     {
00371         // singularity found
00372         // first check for identity matrix which must have +1 for all terms
00373         //  in leading diagonal and zero in other terms
00374         if ((std::abs(data[1] + data[3]) < epsilon2)
00375             && (std::abs(data[2] + data[6]) < epsilon2)
00376             && (std::abs(data[5] + data[7]) < epsilon2)
00377             && (std::abs(data[0] + data[4] + data[8]-3) < epsilon2))
00378         {
00379             // this singularity is identity matrix so angle = 0, axis is arbitrary
00380             // Choose 0, 0, 1 to pass orocos tests
00381             axis = KDL::Vector(0,0,1);
00382             angle = 0.0;
00383             return angle;
00384         }
00385 
00386         // otherwise this singularity is angle = 180
00387         angle = M_PI;
00388         double xx = (data[0] + 1) / 2;
00389         double yy = (data[4] + 1) / 2;
00390         double zz = (data[8] + 1) / 2;
00391         double xy = (data[1] + data[3]) / 4;
00392         double xz = (data[2] + data[6]) / 4;
00393         double yz = (data[5] + data[7]) / 4;
00394 
00395         if ((xx > yy) && (xx > zz))
00396         {
00397             // data[0] is the largest diagonal term
00398             x = sqrt(xx);
00399             y = xy/x;
00400             z = xz/x;
00401         }
00402         else if (yy > zz)
00403         {
00404             // data[4] is the largest diagonal term
00405             y = sqrt(yy);
00406             x = xy/y;
00407             z = yz/y;
00408         }
00409         else
00410         {
00411             // data[8] is the largest diagonal term so base result on this
00412             z = sqrt(zz);
00413             x = xz/z;
00414             y = yz/z;
00415         }
00416         axis = KDL::Vector(x, y, z);
00417         return angle; // return 180 deg rotation
00418     }
00419 
00420     // If the matrix is slightly non-orthogonal, `f` may be out of the (-1, +1) range.
00421     // Therefore, clamp it between those values to avoid NaNs.
00422     double f = (data[0] + data[4] + data[8] - 1) / 2;
00423     angle = acos(std::max(-1.0, std::min(1.0, f)));
00424 
00425     x = (data[7] - data[5]);
00426     y = (data[2] - data[6]);
00427     z = (data[3] - data[1]);
00428     axis = KDL::Vector(x, y, z);
00429     axis.Normalize();
00430     return angle;
00431 }
00432 
00433 bool operator==(const Rotation& a,const Rotation& b) {
00434 #ifdef KDL_USE_EQUAL
00435     return Equal(a,b);
00436 #else
00437     return ( a.data[0]==b.data[0] &&
00438              a.data[1]==b.data[1] &&
00439              a.data[2]==b.data[2] &&
00440              a.data[3]==b.data[3] &&
00441              a.data[4]==b.data[4] &&
00442              a.data[5]==b.data[5] &&
00443              a.data[6]==b.data[6] &&
00444              a.data[7]==b.data[7] &&
00445              a.data[8]==b.data[8]  );
00446 #endif
00447 }
00448 }


orocos_kdl
Author(s):
autogenerated on Fri Jun 14 2019 19:33:22