Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

invkine.cpp

Go to the documentation of this file.
00001 /*
00002 ROBOOP -- A robotics object oriented package in C++
00003 Copyright (C) 2004  Etienne Lachance
00004 
00005 This library is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU Lesser General Public License as
00007 published by the Free Software Foundation; either version 2.1 of the
00008 License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 Report problems and direct all questions to:
00020 
00021 Richard Gourdeau
00022 Professeur Agrege
00023 Departement de genie electrique
00024 Ecole Polytechnique de Montreal
00025 C.P. 6079, Succ. Centre-Ville
00026 Montreal, Quebec, H3C 3A7
00027 
00028 email: richard.gourdeau@polymtl.ca
00029 -------------------------------------------------------------------------------
00030 Revision_history:
00031 
00032 2004/04/19: Vincent Drolet
00033    -Added Robot::inv_kin_rhino and Robot::inv_kin_puma member functions.
00034 
00035 2004/04/20: Etienne Lachance
00036    -Added try, throw, catch statement in Robot::inv_kin_rhino and 
00037     Robot::inv_kin_puma in order to avoid singularity.
00038 
00039 2004/05/21: Etienne Lachance
00040    -Added Doxygen documentation.
00041 
00042 2004/07/01: Ethan Tira-Thompson
00043     -Added support for newmat's use_namespace #define, using ROBOOP namespace
00044     -Fixed warnings regarding atan2 when using float as Real type
00045 
00046 2004/07/16: Ethan Tira-Thompson
00047     -If USING_FLOAT is set from newmat's include.h, ITOL is 1e-4 instead of 1e-6
00048      Motivation was occasional failures to converge when requiring 1e-6
00049      precision from floats using prismatic joints with ranges to 100's
00050     -A few modifications to support only solving for mobile joints in chain
00051     -Can now do inverse kinematics for frames other than end effector
00052 
00053 2004/07/21: Ethan Tira-Thompson
00054     -Added inv_kin_pos() for times when you only care about position
00055     -Added inv_kin_orientation() for times when you only care about orientation
00056 -------------------------------------------------------------------------------
00057 */
00058 
00059 /*!
00060   @file invkine.cpp
00061   @brief Inverse kinematics solutions.
00062 */
00063 
00064 #include "robot.h"
00065 #include <sstream>
00066 
00067 using namespace std;
00068 
00069 #ifdef use_namespace
00070 namespace ROBOOP {
00071   using namespace NEWMAT;
00072 #endif
00073   //! @brief RCS/CVS version.
00074   static const char rcsid[] __UNUSED__ = "$Id: invkine.cpp,v 1.29 2007/11/16 16:46:45 ejt Exp $";
00075 
00076 #define NITMAX 1000  //!< def maximum number of iterations in inv_kin 
00077 #ifdef USING_FLOAT //from newmat's include.h
00078 #  define ITOL   1e-4f //!< def tolerance for the end of iterations in inv_kin 
00079 #else
00080 #  define ITOL   1e-6  //!< def tolerance for the end of iterations in inv_kin 
00081 #endif
00082 
00083 ReturnMatrix Robot_basic::inv_kin(const Matrix & Tobj, const int mj)
00084 //!  @brief Overload inv_kin function.
00085 {
00086    bool converge = false;
00087    return inv_kin(Tobj, mj, dof, converge);
00088 }
00089 
00090 
00091 ReturnMatrix Robot_basic::inv_kin(const Matrix & Tobj, const int mj, const int endlink, bool & converge)
00092 /*!
00093   @brief Numerical inverse kinematics.
00094 
00095   @param Tobj: Transformation matrix expressing the desired end effector pose.
00096   @param mj: Select algorithm type, 0: based on Jacobian, 1: based on derivative of T.
00097   @param endlink: the link to pretend is the end effector 
00098   @param converge: Indicate if the algorithm converge.
00099 
00100   The joint position vector before the inverse kinematics is returned if the 
00101   algorithm does not converge.
00102 */
00103 {
00104    ColumnVector qout, dq, q_tmp;
00105    UpperTriangularMatrix U;
00106 
00107    qout = get_available_q();
00108    if(qout.nrows()==0) {
00109       converge=true;
00110       return qout;
00111    }
00112    q_tmp = qout;
00113 
00114    converge = false;
00115    if(mj == 0) {  // Jacobian based
00116       Matrix Ipd, A, B(6,1), M;
00117       for(int j = 1; j <= NITMAX; j++) {
00118          Ipd = (kine(endlink)).i()*Tobj;
00119          B(1,1) = Ipd(1,4);
00120          B(2,1) = Ipd(2,4);
00121          B(3,1) = Ipd(3,4);
00122          B(4,1) = Ipd(3,2);
00123          B(5,1) = Ipd(1,3);
00124          B(6,1) = Ipd(2,1);
00125          A = jacobian(endlink,endlink);
00126          QRZ(A,U);
00127          QRZ(A,B,M);
00128          dq = U.i()*M;
00129 
00130          while(dq.MaximumAbsoluteValue() > 1)
00131             dq /= 10;
00132 
00133          for(int k = 1; k<= dq.nrows(); k++)
00134             qout(k)+=dq(k);
00135          set_q(qout);
00136 
00137          if (dq.MaximumAbsoluteValue() < ITOL)
00138          {
00139             converge = true;
00140             break;
00141          }
00142       }
00143    } else {  // using partial derivative of T
00144       int adof=get_available_dof(endlink);
00145       Matrix A(12,adof),B,M;
00146       for(int j = 1; j <= NITMAX; j++) {
00147          B = (Tobj-kine(endlink)).SubMatrix(1,3,1,4).AsColumn();
00148          int k=1;
00149          for(int i = 1; i<=dof && k<=adof; i++) {
00150             if(links[i].immobile)
00151                continue;
00152             A.SubMatrix(1,12,k,k) = dTdqi(i,endlink).SubMatrix(1,3,1,4).AsColumn();
00153             k++;
00154          }
00155          if(A.ncols()==0) {
00156             converge=true;
00157             break;
00158          }
00159          QRZ(A,U);
00160          QRZ(A,B,M);
00161          dq = U.i()*M;
00162 
00163          while(dq.MaximumAbsoluteValue() > 1)
00164             dq /= 10;
00165 
00166          for(k = 1; k<=adof; k++)
00167             qout(k)+=dq(k);
00168          set_q(qout);
00169          if (dq.MaximumAbsoluteValue() < ITOL)
00170          {
00171             converge = true;
00172             break;
00173          }
00174       }
00175    }
00176 
00177    if(converge)
00178    {
00179       // Make sure that: -pi < qout <= pi for revolute joints
00180       int j=1;
00181       for(int i = 1; i <= dof; i++)
00182       {
00183          if(links[i].immobile)
00184             continue;
00185          if(links[i].get_joint_type() == 0) {
00186             while(qout(j) >= M_PI)
00187                qout(j) -= 2*M_PI;
00188             while(qout(j) <= -M_PI)
00189                qout(j) += 2*M_PI;
00190          }
00191          j++;
00192       }
00193       set_q(qout);
00194       qout.Release();
00195       return qout;
00196    }
00197    else
00198    {
00199       set_q(q_tmp);
00200       q_tmp.Release();
00201       return q_tmp;
00202    }
00203 }
00204 
00205 
00206 //void serrprintf(const char *, int a, int b, int c);
00207 //#define DEBUG_ET { int debl=deb++; for(int a=0; a<50; a++) serrprintf("%d: %d %d\n",a,debl,__LINE__); }
00208 #define DEBUG_ET ;
00209 
00210 //cerr << a << ": " << debl << ' ' << __LINE__ << endl; }
00211 
00212 ReturnMatrix Robot_basic::inv_kin_pos(const ColumnVector & Pobj, const int mj, const int endlink, const ColumnVector& /*Plink*/, bool & converge)
00213 /*!
00214   @brief Numerical inverse kinematics.
00215 
00216   @param Pobj: Vector expressing the desired end effector position; can be homogenous
00217   @param mj: Select algorithm type, 0: based on Jacobian, 1: based on derivative of T.
00218   @param endlink: the link to pretend is the end effector 
00219   @param Plink: ignored for now
00220   @param converge: Indicate if the algorithm converge.
00221 
00222   The joint position vector before the inverse kinematics is returned if the 
00223   algorithm does not converge.
00224 */
00225 { 
00226    ColumnVector qout, dq, q_tmp;
00227    UpperTriangularMatrix U;
00228    //int deb=0;
00229    DEBUG_ET;
00230 
00231    qout = get_available_q();
00232    if(qout.nrows()==0) {
00233       converge=true;
00234       return qout;
00235    }
00236    q_tmp = qout;
00237 
00238    ColumnVector PHobj(4);
00239    if(Pobj.nrows()!=4) {
00240       PHobj.SubMatrix(1,Pobj.nrows(),1,1)=Pobj;
00241       PHobj.SubMatrix(Pobj.nrows()+1,4,1,1)=1;
00242    } else {
00243       PHobj=Pobj;
00244    }
00245 
00246    DEBUG_ET;
00247    converge = false;
00248    if(mj == 0) {  // Jacobian based
00249    DEBUG_ET;
00250       Matrix Ipd, A, B(3,1),M;
00251       for(int j = 1; j <= NITMAX; j++) {
00252          Ipd = (kine(endlink)).i()*PHobj;
00253          B(1,1) = Ipd(1,1);
00254          B(2,1) = Ipd(2,1);
00255          B(3,1) = Ipd(3,1);
00256          A = jacobian(endlink,endlink);
00257          A = A.SubMatrix(1,3,1,A.ncols());
00258          //need to remove any joints which do not affect position
00259          //otherwise those joints's q go nuts
00260          int removeCount=0;
00261          for(int k=1; k<= A.ncols(); k++)
00262             if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()<ITOL)
00263                removeCount++;
00264          Matrix A2(3,A.ncols()-removeCount);
00265          if(removeCount==0)
00266             A2=A;
00267          else
00268             for(int k=1,m=1; k<= A.ncols(); k++) {
00269                if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()<ITOL)
00270                   continue;
00271                A2.SubMatrix(1,3,m,m)=A.SubMatrix(1,3,k,k);
00272                m++;
00273             }
00274          //ok... on with the show, using A2 now
00275          if(A2.ncols()==0) {
00276             converge=true;
00277             break;
00278          }
00279          {
00280            stringstream ss;
00281            ss << "A2-pre:\n";
00282            for(int r=1; r<=A2.nrows(); r++) {
00283              for(int c=1; c<=A2.ncols(); c++) {
00284                ss << A2(r,c) << ' ';
00285              }
00286              ss << '\n';
00287            }
00288          QRZ(A2,U);
00289          /*  ss << "A2-mid:\n";
00290    for(int r=1; r<=A2.nrows(); r++) {
00291      for(int c=1; c<=A2.ncols(); c++) {
00292        ss << A2(r,c) << ' ';
00293      }
00294      ss << '\n';
00295      }*/
00296          QRZ(A2,B,M);
00297          //serrprintf(ss.str().c_str(),0,0,0);
00298       }
00299    DEBUG_ET;
00300    /*stringstream ss;
00301    ss << "A2-post:\n";
00302    for(int r=1; r<=A2.nrows(); r++) {
00303      for(int c=1; c<=A2.ncols(); c++) {
00304        ss << A2(r,c) << ' ';
00305      }
00306      ss << '\n';
00307    }
00308    ss << "U:\n";
00309    for(int r=1; r<=4; r++) {
00310      for(int c=r; c<=4; c++) {
00311        ss << U(r,c) << ' ';
00312      }
00313      ss << '\n';
00314    }
00315    ss << "M: ";
00316    for(int r=1; r<=M.nrows(); r++) {
00317      ss << M(r,1) << ' ';
00318    }
00319    ss << '\n';*/
00320    //serrprintf(ss.str().c_str(),0,0,0);
00321 
00322    DEBUG_ET;
00323          dq = U.i()*M;
00324 
00325    DEBUG_ET;
00326          while(dq.MaximumAbsoluteValue() > 1)
00327             dq /= 10;
00328 
00329          for(int k = 1,m=1; m<= dq.nrows(); k++)
00330             if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()>=ITOL)
00331                qout(k)+=dq(m++);
00332          set_q(qout);
00333 
00334          if (dq.MaximumAbsoluteValue() < ITOL)
00335          {
00336             converge = true;
00337             break;
00338          }
00339       }
00340    } else {  // using partial derivative of T
00341       int adof=get_available_dof(endlink);
00342       Matrix A(3,adof),Rcur,B,M;
00343       ColumnVector pcur;
00344       bool used[adof];
00345       for(int j = 1; j <= NITMAX; j++) {
00346          kine(Rcur,pcur,endlink);
00347          B = (PHobj.SubMatrix(1,3,1,1)-pcur);
00348          int k=1,m=1;
00349          for(int i = 1; m<=adof; i++) {
00350             if(links[i].immobile)
00351                continue;
00352             Matrix Atmp=dTdqi(i,endlink).SubMatrix(1,3,4,4);
00353             used[m]=(Atmp.MaximumAbsoluteValue()>=ITOL);
00354             if(!used[m++])
00355                continue;
00356             A.SubMatrix(1,3,k,k) = Atmp;
00357             k++;
00358          }
00359          Matrix A2=A.SubMatrix(1,3,1,k-1);
00360          if(A2.ncols()==0) {
00361             converge=true;
00362             break;
00363          }
00364          QRZ(A2,U);
00365          QRZ(A2,B,M);
00366          dq = U.i()*M;
00367 
00368          while(dq.MaximumAbsoluteValue() > 1)
00369             dq /= 10;
00370 
00371          for(k = m = 1; k<=adof; k++)
00372             if(used[k])
00373                qout(k)+=dq(m++);
00374          set_q(qout);
00375 
00376          if (dq.MaximumAbsoluteValue() < ITOL)
00377          {
00378             converge = true;
00379             break;
00380          }
00381       }
00382    }
00383    DEBUG_ET;
00384 
00385    if(converge)
00386    {
00387    DEBUG_ET;
00388       // Make sure that: -pi < qout <= pi for revolute joints
00389       int j=1;
00390       for(int i = 1; i <= dof; i++)
00391       {
00392          if(links[i].immobile)
00393             continue;
00394          unsigned int * test=(unsigned int*)&qout(j);
00395          if(((*test)&(255U<<23))==(255U<<23)) {
00396            //serrprintf("qout %d is not-finite\n",j,0,0);
00397            set_q(q_tmp);
00398            q_tmp.Release();
00399            return q_tmp;
00400          }
00401          /*
00402          if(links[i].get_joint_type() == 0 && finite(qout(j))) {
00403             while(qout(j) >= M_PI)
00404                qout(j) -= 2*M_PI;
00405             while(qout(j) <= -M_PI)
00406                qout(j) += 2*M_PI;
00407          }
00408          */
00409          j++;
00410       }
00411    DEBUG_ET;
00412       set_q(qout);
00413       qout.Release();
00414    DEBUG_ET;
00415       return qout;
00416    }
00417    else
00418    {
00419    DEBUG_ET;
00420       set_q(q_tmp);
00421       q_tmp.Release();
00422    DEBUG_ET;
00423       return q_tmp;
00424    }
00425 }
00426 
00427 ReturnMatrix Robot_basic::inv_kin_orientation(const Matrix & Robj, const int mj, const int endlink, bool & converge)
00428 /*!
00429   @brief Numerical inverse kinematics.
00430 
00431   @param Robj: Rotation matrix expressing the desired end effector orientation w.r.t base frame
00432   @param mj: Select algorithm type, 0: based on Jacobian, 1: based on derivative of T.
00433   @param endlink: the link to pretend is the end effector 
00434   @param converge: Indicate if the algorithm converge.
00435 
00436   The joint position vector before the inverse kinematics is returned if the 
00437   algorithm does not converge.
00438 */
00439 {
00440    ColumnVector qout, dq, q_tmp;
00441    UpperTriangularMatrix U;
00442 
00443    qout = get_available_q();
00444    if(qout.nrows()==0) {
00445       converge=true;
00446       return qout;
00447    }
00448    q_tmp = qout;
00449 
00450    Matrix RHobj(4,3);
00451    RHobj.SubMatrix(1,3,1,3)=Robj;
00452    RHobj.SubMatrix(4,4,1,3)=0;
00453 
00454    converge = false;
00455    if(mj == 0) {  // Jacobian based
00456       Matrix Ipd, A, B(3,1),M;
00457       for(int j = 1; j <= NITMAX; j++) {
00458          Ipd = kine(endlink).i()*RHobj;
00459          B(1,1) = Ipd(3,2);
00460          B(2,1) = Ipd(1,3);
00461          B(3,1) = Ipd(2,1);
00462          A = jacobian(endlink,endlink);
00463          A = A.SubMatrix(4,6,1,A.ncols());
00464          //need to remove any joints which do not affect position
00465          //otherwise those joints's q go nuts
00466          int removeCount=0;
00467          for(int k=1; k<= A.ncols(); k++)
00468             if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()<ITOL)
00469                removeCount++;
00470          Matrix A2(3,A.ncols()-removeCount);
00471          if(removeCount==0)
00472             A2=A;
00473          else
00474             for(int k=1,m=1; k<= A.ncols(); k++) {
00475                if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()<ITOL)
00476                   continue;
00477                A2.SubMatrix(1,3,m,m)=A.SubMatrix(1,3,k,k);
00478                m++;
00479             }
00480          //ok... on with the show, using A2 now
00481          if(A2.ncols()==0) {
00482             converge=true;
00483             break;
00484          }
00485          QRZ(A2,U);
00486          QRZ(A2,B,M);
00487          dq = U.i()*M;
00488 
00489          while(dq.MaximumAbsoluteValue() > 1)
00490             dq /= 10;
00491 
00492          for(int k = 1,m=1; m<= dq.nrows(); k++)
00493             if(A.SubMatrix(1,3,k,k).MaximumAbsoluteValue()>=ITOL)
00494                qout(k)+=dq(m++);
00495          set_q(qout);
00496 
00497          if (dq.MaximumAbsoluteValue() < ITOL)
00498          {
00499             converge = true;
00500             break;
00501          }
00502       }
00503    } else {  // using partial derivative of T
00504       int adof=get_available_dof(endlink);
00505       Matrix A(9,adof),Rcur,B,M;
00506       ColumnVector pcur;
00507       bool used[adof];
00508       for(int j = 1; j <= NITMAX; j++) {
00509          kine(Rcur,pcur,endlink);
00510          B = (Robj-Rcur).AsColumn();
00511          int k=1,m=1;
00512          for(int i = 1; m<=adof; i++) {
00513             if(links[i].immobile)
00514                continue;
00515             Matrix Atmp=dTdqi(i,endlink).SubMatrix(1,3,1,3).AsColumn();
00516             used[m]=(Atmp.MaximumAbsoluteValue()>=ITOL);
00517             if(!used[m++])
00518                continue;
00519             A.SubMatrix(1,9,k,k) = Atmp;
00520             k++;
00521          }
00522          Matrix A2=A.SubMatrix(1,9,1,k-1);
00523          if(A2.ncols()==0) {
00524             converge=true;
00525             break;
00526          }
00527          QRZ(A2,U);
00528          QRZ(A2,B,M);
00529          dq = U.i()*M;
00530 
00531          while(dq.MaximumAbsoluteValue() > 1)
00532             dq /= 10;
00533 
00534          for(k = m = 1; k<=adof; k++)
00535             if(used[k])
00536                qout(k)+=dq(m++);
00537          set_q(qout);
00538          
00539          if (dq.MaximumAbsoluteValue() < ITOL)
00540          {
00541             converge = true;
00542             break;
00543          }
00544       }
00545    }
00546 
00547    if(converge)
00548    {
00549       // Make sure that: -pi < qout <= pi for revolute joints
00550       int j=1;
00551       for(int i = 1; i <= dof; i++)
00552       {
00553          if(links[i].immobile)
00554             continue;
00555          if(links[i].get_joint_type() == 0) {
00556             while(qout(j) >= M_PI)
00557                qout(j) -= 2*M_PI;
00558             while(qout(j) <= -M_PI)
00559                qout(j) += 2*M_PI;
00560          }
00561          j++;
00562       }
00563       set_q(qout);
00564       qout.Release();
00565       return qout;
00566    }
00567    else
00568    {
00569       set_q(q_tmp);
00570       q_tmp.Release();
00571       return q_tmp;
00572    }
00573 }
00574 
00575 // ---------------------  R O B O T   DH   N O T A T I O N  --------------------------
00576 
00577 ReturnMatrix Robot::inv_kin(const Matrix & Tobj, const int mj)
00578 //!  @brief Overload inv_kin function.
00579 {
00580    bool converge = false;
00581    return inv_kin(Tobj, mj, dof, converge);
00582 }
00583 
00584 
00585 ReturnMatrix Robot::inv_kin(const Matrix & Tobj, const int mj, const int endlink, bool & converge)
00586 /*!
00587   @brief Inverse kinematics solutions.
00588 
00589   The solution is based on the analytic inverse kinematics if robot type (familly)
00590   is Rhino or Puma, otherwise used the numerical algoritm defined in Robot_basic
00591   class.
00592 */
00593 {
00594    switch (robotType) {
00595       case RHINO:
00596          return inv_kin_rhino(Tobj, converge);
00597       case PUMA:
00598          return inv_kin_puma(Tobj, converge);
00599       case ERS_LEG:
00600       case ERS2XX_HEAD:
00601       case ERS7_HEAD:
00602          //no specializations yet... :(
00603       case PANTILT:
00604       case GOOSENECK:
00605         return inv_kin_goose_neck(Tobj);
00606       case CRABARM:
00607       default:
00608          return Robot_basic::inv_kin(Tobj, mj, endlink, converge);
00609    }
00610 }
00611 
00612 ReturnMatrix Robot::inv_kin_pos(const ColumnVector & Pobj, const int mj, const int endlink, const ColumnVector& Plink, bool & converge)
00613 /*!
00614   @brief Inverse kinematics solutions.
00615 
00616   The solution is based on the analytic inverse kinematics if robot type (familly)
00617   is Rhino or Puma, otherwise used the numerical algoritm defined in Robot_basic
00618   class.
00619 */
00620 {
00621    switch (robotType) {
00622       case ERS_LEG:
00623       case ERS2XX_HEAD:
00624       case ERS7_HEAD:
00625          return inv_kin_ers_pos(Pobj, endlink, Plink, converge);
00626       case RHINO:
00627       case PUMA:
00628          //no specializations yet... :(
00629        case PANTILT:
00630          return inv_kin_pan_tilt(Pobj, converge);
00631       case GOOSENECK:
00632         return inv_kin_goose_neck_pos(Pobj);
00633       case CRABARM:
00634       default:
00635          return Robot_basic::inv_kin_pos(Pobj, mj, endlink, Plink, converge);
00636    }
00637 }
00638 
00639 ReturnMatrix Robot::inv_kin_orientation(const Matrix & Robj, const int mj, const int endlink, bool & converge)
00640 /*!
00641   @brief Inverse kinematics solutions.
00642 
00643   The solution is based on the analytic inverse kinematics if robot type (familly)
00644   is Rhino or Puma, otherwise used the numerical algoritm defined in Robot_basic
00645   class.
00646 */
00647 {
00648    switch (robotType) {
00649       case ERS_LEG:
00650       case ERS2XX_HEAD:
00651       case ERS7_HEAD:
00652       case RHINO:
00653       case PUMA:
00654          //no specializations yet... :(
00655       case PANTILT:
00656       case GOOSENECK:
00657 //       return inv_kin_goose_neck_orientation(Robj)
00658     case CRABARM:
00659       default:
00660          return Robot_basic::inv_kin_orientation(Robj, mj, endlink, converge);
00661    }
00662 }
00663 
00664 ReturnMatrix Robot::inv_kin_rhino(const Matrix & Tobj, bool & converge)
00665 /*!
00666   @brief Analytic Rhino inverse kinematics.
00667 
00668   converge will be false if the desired end effector pose is outside robot range.
00669 */
00670 {
00671     ColumnVector qout(5), q_actual;    
00672     q_actual = get_q();
00673 
00674     try
00675     {
00676   Real theta[6] , diff1, diff2, tmp,
00677        angle , L=0.0 , M=0.0 , K=0.0 , H=0.0 , Gl=0.0 ;
00678     
00679   // Calcul les deux angles possibles
00680   theta[0] = atan2(Tobj(2,4),
00681        Tobj(1,4));
00682   
00683   theta[1] = atan2(-Tobj(2,4),
00684        -Tobj(1,4))  ;
00685   
00686   diff1 = fabs(q_actual(1)-theta[0]) ;    
00687   if (diff1 > M_PI)
00688       diff1 = 2*M_PI - diff1;
00689   
00690   diff2 = fabs(q_actual(1)-theta[1]);
00691   if (diff2 > M_PI)
00692       diff1 = 2*M_PI - diff2 ;
00693   
00694   // Prend l'angle le plus proche de sa position actuel
00695   if (diff1 < diff2)       
00696       theta[1] = theta[0] ;
00697   
00698   theta[5] = atan2(sin(theta[1])*Tobj(1,1) - cos(theta[1])*Tobj(2,1), 
00699        sin(theta[1])*Tobj(1,2) - cos(theta[1])*Tobj(2,2));
00700   
00701   // angle = theta1 +theta2 + theta3
00702   angle = atan2(-1*cos(theta[1])*Tobj(1,3) - sin(theta[1])*Tobj(2,3),
00703           -1*Tobj(3,3));
00704   
00705   L = cos(theta[1])*Tobj(1,4) + 
00706       sin(theta[1])*Tobj(2,4) + 
00707       links[5].d*sin(angle) - 
00708       links[4].a*cos(angle);
00709   M = links[1].d - 
00710       Tobj(3,4) - 
00711       links[5].d*cos(angle) - 
00712       links[4].a*sin(angle);
00713   K = (L*L + M*M - links[3].a*links[3].a - 
00714        links[2].a*links[2].a) / 
00715       (2 * links[3].a * links[2].a);
00716   
00717   tmp = 1-K*K;
00718   if (tmp < 0)
00719       throw std::out_of_range("sqrt of negative number not allowed.");
00720 
00721   theta[0] = atan2( sqrt(tmp) , K );
00722   theta[3] = atan2( -sqrt(tmp) , K ); 
00723   
00724   diff1 = fabs(q_actual(3)-theta[0]) ;
00725   if (diff1 > M_PI)
00726       diff1 = 2*M_PI - diff1 ;
00727   
00728   diff2 = fabs(q_actual(3)-theta[3]);
00729   if (diff2 > M_PI)
00730       diff1 = 2*M_PI - diff2 ;
00731   
00732   if (diff1 < diff2)
00733       theta[3] = theta[0] ;
00734   
00735   H = cos(theta[3]) * links[3].a + links[2].a;
00736   Gl = sin(theta[3]) * links[3].a;
00737   
00738   theta[2] = atan2( M , L ) - atan2( Gl , H );
00739   theta[4] = atan2( -1*cos(theta[1])*Tobj(1,3) - sin(theta[1])*Tobj(2,3) , 
00740         -1*Tobj(3,3)) - theta[2] - theta[3] ;
00741   
00742   qout(1) = theta[1];
00743   qout(2) = theta[2];
00744   qout(3) = theta[3];
00745   qout(4) = theta[4];
00746   qout(5) = theta[5];
00747   set_q(qout);
00748   
00749   converge = true;
00750     }
00751     catch(std::out_of_range & e)
00752     {
00753   converge = false; 
00754   set_q(q_actual);
00755   qout = q_actual;
00756     }
00757 
00758     qout.Release();
00759     return qout;
00760 }
00761 
00762 
00763 ReturnMatrix Robot::inv_kin_puma(const Matrix & Tobj, bool & converge)
00764 /*!
00765   @brief Analytic Puma inverse kinematics.
00766 
00767   converge will be false if the desired end effector pose is outside robot range.
00768 */
00769 {
00770     ColumnVector qout(6), q_actual;
00771     q_actual = get_q();
00772 
00773     try
00774     {  
00775   Real theta[7] , diff1, diff2, tmp,
00776        A = 0.0 , B = 0.0 , Cl = 0.0 , D =0.0, Ro = 0.0,
00777        H = 0.0 , L = 0.0 , M = 0.0;
00778   
00779 // Removed d6 component because in the Puma inverse kinematics solution 
00780 // d6 = 0. 
00781   if (links[6].d)
00782   {
00783       ColumnVector tmpd6(3);
00784       tmpd6(1)=0; tmpd6(2)=0; tmpd6(3)=links[6].d;
00785       tmpd6 = Tobj.SubMatrix(1,3,1,3)*tmpd6;
00786       Tobj.SubMatrix(1,3,4,4) = Tobj.SubMatrix(1,3,4,4) - tmpd6;
00787   }
00788 
00789   tmp = Tobj(2,4)*Tobj(2,4) + Tobj(1,4)*Tobj(1,4);
00790   if (tmp < 0)
00791       throw std::out_of_range("sqrt of negative number not allowed.");
00792 
00793   Ro = sqrt(tmp);
00794   D = (links[2].d+links[3].d) / Ro;
00795   
00796   tmp = 1-D*D;
00797   if (tmp < 0)
00798       throw std::out_of_range("sqrt of negative number not allowed.");
00799   
00800   //Calcul les deux angles possibles
00801   theta[0] =  atan2(Tobj(2,4),Tobj(1,4)) - atan2(D, sqrt(tmp));  
00802   //Calcul les deux angles possibles
00803   theta[1] =  atan2(Tobj(2,4),Tobj(1,4)) - atan2(D , -sqrt(tmp));
00804   
00805   diff1 = fabs(q_actual(1)-theta[0]);
00806   if (diff1 > M_PI)
00807       diff1 = 2*M_PI - diff1;
00808   
00809   diff2 = fabs(q_actual(1)-theta[1]);
00810   if (diff2 > M_PI)
00811       diff1 = 2*M_PI - diff2;
00812   
00813   // Prend l'angle le plus proche de sa position actuel
00814   if (diff1 < diff2)
00815       theta[1] = theta[0];
00816   
00817   tmp = links[3].a*links[3].a + links[4].d*links[4].d;
00818   if (tmp < 0)
00819       throw std::out_of_range("sqrt of negative number not allowed.");
00820   
00821   Ro = sqrt(tmp);
00822   B = atan2(links[4].d,links[3].a);
00823   Cl = Tobj(1,4)*Tobj(1,4) + 
00824        Tobj(2,4)*Tobj(2,4) + 
00825        Tobj(3,4)*Tobj(3,4) - 
00826        (links[2].d + links[3].d)*(links[2].d + links[3].d) - 
00827        links[2].a*links[2].a - 
00828        links[3].a*links[3].a - 
00829        links[4].d*links[4].d; 
00830   A = Cl / (2*links[2].a);
00831   
00832   tmp = 1-A/Ro*A/Ro;
00833   if (tmp < 0)
00834       throw std::out_of_range("sqrt of negative number not allowed.");
00835   
00836   theta[0] = atan2(sqrt(tmp) , A/Ro) + B;
00837   theta[3] = atan2(-sqrt(tmp) , A/Ro) + B;
00838   
00839   diff1 = fabs(q_actual(3)-theta[0]);
00840   if (diff1 > M_PI)
00841       diff1 = 2*M_PI - diff1 ;
00842   
00843   diff2 = fabs(q_actual(3)-theta[3]);
00844   if (diff2 > M_PI)
00845       diff1 = 2*M_PI - diff2;
00846   
00847   //Prend l'angle le plus proche de sa position actuel
00848   if (diff1 < diff2)
00849       theta[3] = theta[0];
00850   
00851   H = cos(theta[1])*Tobj(1,4) + sin(theta[1])*Tobj(2,4);
00852   L = sin(theta[3])*links[4].d + cos(theta[3])*links[3].a + links[2].a;
00853   M = cos(theta[3])*links[4].d - sin(theta[3])*links[3].a;
00854   
00855   theta[2] = atan2( M , L ) - atan2(Tobj(3,4) , H );
00856   
00857   theta[0] = atan2( -sin(theta[1])*Tobj(1,3) + cos(theta[1])*Tobj(2,3) , 
00858         cos(theta[2] + theta[3]) * 
00859         (cos(theta[1]) * Tobj(1,3) + sin(theta[1])*Tobj(2,3)) 
00860         - (sin(theta[2]+theta[3])*Tobj(3,3)) );
00861   
00862   theta[4] = atan2(-1*(-sin(theta[1])*Tobj(1,3) + cos(theta[1])*Tobj(2,3)), 
00863        -cos(theta[2] + theta[3]) * 
00864        (cos(theta[1]) * Tobj(1,3) + sin(theta[1])*Tobj(2,3)) 
00865        + (sin(theta[2]+theta[3])*Tobj(3,3)) );
00866   
00867   diff1 = fabs(q_actual(4)-theta[0]);
00868   if (diff1 > M_PI)
00869       diff1 = 2*M_PI - diff1;
00870   
00871   diff2 = fabs(q_actual(4)-theta[4]);
00872   if (diff2 > M_PI)
00873       diff1 = 2*M_PI - diff2;
00874   
00875   // Prend l'angle le plus proche de sa position actuel
00876   if (diff1 < diff2)
00877       theta[4] = theta[0];
00878   
00879   theta[5] = atan2( cos(theta[4]) * 
00880         ( cos(theta[2] + theta[3]) * 
00881           (cos(theta[1]) * Tobj(1,3) 
00882            + sin(theta[1])*Tobj(2,3)) 
00883           - (sin(theta[2]+theta[3])*Tobj(3,3)) ) + 
00884         sin(theta[4])*(-sin(theta[1])*Tobj(1,3) 
00885            + cos(theta[1])*Tobj(2,3)) , 
00886         sin(theta[2]+theta[3]) * (cos(theta[1]) * Tobj(1,3) 
00887                 + sin(theta[1])*Tobj(2,3) ) 
00888         + (cos(theta[2]+theta[3])*Tobj(3,3)) );
00889   
00890   theta[6] = atan2( -sin(theta[4]) 
00891         * ( cos(theta[2] + theta[3]) * 
00892             (cos(theta[1]) * Tobj(1,1) 
00893              + sin(theta[1])*Tobj(2,1)) 
00894             - (sin(theta[2]+theta[3])*Tobj(3,1))) + 
00895         cos(theta[4])*(-sin(theta[1])*Tobj(1,1) 
00896            + cos(theta[1])*Tobj(2,1)), 
00897         -sin(theta[4]) * ( cos(theta[2] + theta[3]) * 
00898                (cos(theta[1]) * Tobj(1,2) 
00899                 + sin(theta[1])*Tobj(2,2)) 
00900                - (sin(theta[2]+theta[3])*Tobj(3,2))) +
00901         cos(theta[4])*(-sin(theta[1])*Tobj(1,2) 
00902            + cos(theta[1])*Tobj(2,2)) );
00903   
00904   qout(1) = theta[1];
00905   qout(2) = theta[2];
00906   qout(3) = theta[3];
00907   qout(4) = theta[4];
00908   qout(5) = theta[5];
00909   qout(6) = theta[6];
00910   set_q(qout);
00911   
00912   converge = true; 
00913     }
00914     catch(std::out_of_range & e)
00915     {
00916   converge = false; 
00917   set_q(q_actual);
00918   qout = q_actual;
00919     }
00920 
00921     qout.Release();
00922     return qout;
00923 }
00924 
00925 ReturnMatrix Robot::inv_kin_pan_tilt(const ColumnVector & Pobj, bool & converge)
00926 /*
00927   @brief Inverse Kinematics of Pan Tilt Robot
00928   @param Pobj: Vector expressing the desired end effector position
00929   @param converge: Indicate if the algorithm converge.
00930 */
00931 {
00932   //std::cout << "Inv_Kine Pan Tilt!" << std::endl;
00933   ColumnVector qout, qtmp,  /* Joint angle vectors */
00934          xyz1, xyz2,  /* Frame 1 and 2 coordinates */
00935          xyz0 = Pobj; /* Base frame coordinates */
00936   Matrix  M01, /* Matrix to convert coordinates from base (frame 0) to frame 1 */
00937       M12; /* Matrix to convert coordinates from frame 1 to frame 2 */
00938 
00939   qtmp = get_q();
00940   M01 = convertFrame(1,2);
00941   //std::cout << "Matrix M01" << std::endl << setw(5) << M01 << std::endl;
00942   xyz1 = M01*xyz0;
00943   //std::cout << xyz1(1) << " " << xyz1(2) << " " << xyz1(3) << std::endl;
00944   qtmp(2)=atan2(xyz1(2),xyz1(1));
00945   set_q(qtmp);
00946   M12 = convertFrame(2,3);
00947   //std::cout << "Matrix M12" << std::endl << setw(5) << M12 << std::endl;
00948   xyz2 = M12*xyz1;
00949   //std::cout << xyz2(1) << " " << xyz2(2) << " " << xyz2(3) << std::endl;
00950   qtmp(3)=atan2(xyz2(2),xyz2(1));
00951   set_q(qtmp);
00952 
00953 //Now I have to check to see if the angles lie within the ranges of the pan and tilt  
00954 //If not, set angles to closest min/max value.
00955   if( qtmp(2) < links[2].get_theta_min() )
00956     qtmp(2) = links[2].get_theta_min();
00957   if( qtmp(2) > links[2].get_theta_max() )
00958     qtmp(2) = links[2].get_theta_max();
00959   if( qtmp(3) < links[3].get_theta_min() )
00960     qtmp(3) = links[3].get_theta_min();
00961   if( qtmp(3) > links[3].get_theta_max() )
00962     qtmp(3) = links[3].get_theta_max();
00963   //std::cout << "inv_kin_pan_tilt computed the values:" << endl; 
00964   //std::cout << "Pan: "<< qtmp(2) << " Tilt: " << qtmp(3) << std::endl;
00965   qout = qtmp;
00966   converge=true;
00967   return qout;
00968 }
00969 
00970 ReturnMatrix Robot::inv_kin_goose_neck(const Matrix & Tobj)
00971 /*
00972 */
00973 {
00974   //std::cout << "inv_kin_goose_neck was called!" << std::endl;
00975   ColumnVector qout, Pobj(3);
00976   Real phi;
00977   Pobj(1) = Tobj(1,4);
00978   Pobj(2) = Tobj(2,4);
00979   Pobj(3) = Tobj(3,4);
00980   phi = atan2(Tobj(3,3),Tobj(1,3));
00981   qout = goose_neck_angles(Pobj, phi);
00982   return qout;
00983 }
00984 
00985 ReturnMatrix Robot::inv_kin_goose_neck_pos(const ColumnVector & Pobj)
00986 /*
00987 */
00988 {
00989     //std::cout << "inv_kin_goose_neck_pos was called!" << std::endl;
00990   ColumnVector qout;
00991   qout = goose_neck_angles(Pobj, -1.57079632679);
00992   return qout;
00993 }
00994 
00995 /*ReturnMatrix Robot::inv_kin_goose_neck_orientation(const Matrix & Robj)
00996 {
00997   
00998 }
00999 */
01000 
01001 ReturnMatrix Robot::goose_neck_angles(const ColumnVector & Pobj, Real phi)
01002 /*
01003 */
01004 {
01005   Real  c2, 
01006       qp, q1, q2, q3, //phi=-1.57079632679, //phi is the Tool Orientation
01007                                           //this phi puts the tool above the target
01008       K1, K2,
01009       L1=links[2].get_a(),//Planar Link Lengths
01010       L2=links[3].get_a(),