Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PlanarThreeLinkArm.cc

Go to the documentation of this file.
00001 #include "Shared/RobotInfo.h"
00002 #ifdef TGT_IS_HANDEYE
00003 
00004 #include "Shared/debuget.h"
00005 #include "PlanarThreeLinkArm.h"
00006 #include "Shared/fmatSpatial.h"
00007 #include <math.h>
00008 
00009 const std::string PlanarThreeLinkArm::autoRegisterPlanarThreeLinkArm = IKSolver::getRegistry().registerType<PlanarThreeLinkArm>("PlanarThreeLinkArm");
00010 
00011 PlanarThreeLinkArm::PlanarThreeLinkArm() : L1(), L2(), L3(), jointLimits() {
00012   //    unsigned int lastOff = capabilities.findOutputOffset("ARM:wristYaw");
00013   unsigned int lastOff;
00014 #if defined(TGT_CHIARA) || defined(TGT_HANDEYE)
00015   lastOff = RobotInfo::GripperFrameOffset;
00016 #elif defined(TGT_HAS_ARMS)
00017   lastOff = ArmOffset+NumArmJoints-1;
00018 #else
00019   return;
00020 #endif
00021   
00022   const KinematicJoint* j = kine->getKinematicJoint(lastOff);
00023   if ( j == NULL )
00024     throw std::runtime_error("PlanarThreeLinkArm can't find joint for end of arm");
00025   
00026   
00027   L1 = j->getParent()->getParent()->r;
00028   L2 = j->getParent()->r;
00029   L3 = j->r;
00030   
00031 #if defined(TGT_HANDEYE)
00032   j = j->getParent();
00033 #endif
00034   
00035   jointLimits[0][0] = j->getParent()->getParent()->qmin;
00036   jointLimits[0][1] = j->getParent()->getParent()->qmax;
00037   jointLimits[1][0] = j->getParent()->qmin; 
00038   jointLimits[1][1] = j->getParent()->qmax;
00039   jointLimits[2][0] = j->qmin;
00040   jointLimits[2][1] = j->qmax;
00041     
00042   //std::cout << "L1=" << L1 << " L2=" << L2 << " L3=" << L3 << std::endl;
00043 }
00044 
00045 PlanarThreeLinkArm::PlanarThreeLinkArm(unsigned int offset) : L1(), L2(), L3(), jointLimits() {
00046   float linkLengths[3];
00047   for ( unsigned int j = offset; j < offset+3; j++) {
00048     linkLengths[j-offset] = kine->getKinematicJoint(j)->nextJoint()->r;
00049     jointLimits[j-offset][0] = kine->getKinematicJoint(j)->qmin; 
00050     jointLimits[j-offset][1] = kine->getKinematicJoint(j)->qmax;
00051   }
00052   
00053   L1 = linkLengths[0];
00054   L2 = linkLengths[1];
00055   L3 = linkLengths[2];
00056   
00057   //std::cout << "L1=" << L1 << " L2=" << L2 << " L3=" << L3 << std::endl;
00058 }
00059 
00060 
00061 void PlanarThreeLinkArm::PrintVariables() const { 
00062   std::cout << "L1: " << L1 << "\tL2: " << L2 << "\tL3 :" << L3 << std::endl;
00063   std::cout << "Shoulder joint limits:\t" << jointLimits[0][0] << "\t" << jointLimits[0][1] << std::endl;
00064   std::cout << "Elbow joint limits:   \t" << jointLimits[1][0] << "\t" << jointLimits[1][1] << std::endl;
00065   std::cout << "Wrist joint limits:   \t" << jointLimits[2][0] << "\t" << jointLimits[2][1] << std::endl;
00066 }
00067 
00068 bool PlanarThreeLinkArm::solve(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float posPri, const Orientation& oriTgt, float oriPri) const {
00069   
00070   // use const Position& pTgt as the target postion
00071   const Point& pTgtV = dynamic_cast<const Point&>(pTgt);
00072   
00073   // use const Orientation& oriTgt as target orientation
00074   const Rotation& oriTgtV = dynamic_cast<const Rotation&>(oriTgt);
00075   float ori = oriTgtV.axisComponent(fmat::UNIT3_Z);
00076   
00077   // Determine where the Gripper center should be
00078   fmat::Column<2> target = fmat::rotation2D(ori) * fmat::pack(pEff.x, pEff.y) + fmat::pack(pTgtV.x, pTgtV.y);
00079   
00080   PlanarThreeLinkArm::Solutions solutions = invKin3LinkRelaxPhi(target[0], target[1], ori);
00081   
00082   j.getParent()->setQ(solutions.angles(0,2));
00083   j.getParent()->getParent()->setQ(solutions.angles(0,1));
00084   j.getParent()->getParent()->getParent()->setQ(solutions.angles(0,0));
00085   return true;
00086 }
00087 
00088 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin3LinkRelaxPhi(float x, float y, float pref_phi) const {
00089   PlanarThreeLinkArm::Solutions solutions;
00090   float delta_phi;  
00091   if ( sqrt(x*x + y*y) > (L1+L2+L3) ) { // punt if point is out of reach
00092     return punt(x, y);
00093   }
00094   
00095   solutions = invKin3Link(x,y,pref_phi);  
00096   if( solutions.valid )
00097     return solutions;
00098   // Otherwise change last_phi by 10 degrees until achievable angles are found
00099   else {
00100     for( int i = 1; i <= 18; i++) {
00101       delta_phi = i*10*(float)M_PI/180;
00102       solutions = invKin3Link(x,y,angNorm(pref_phi + delta_phi));
00103       if( solutions.valid ) {
00104         return solutions;
00105       }
00106       solutions = invKin3Link(x,y,angNorm(pref_phi - delta_phi));
00107       if( solutions.valid ) {
00108         return solutions;
00109       }
00110     }
00111   } 
00112   solutions.noSols = 0;  solutions.valid = false;
00113   return solutions;
00114 }
00115 
00116 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::solveWithOffset(float x, float y, float pref_phi, fmat::Column<3> baseOffset) const {
00117   fmat::Column<3> basePoint = fmat::pack(x, y, 0);
00118   
00119   fmat::Column<3> offset = fmat::rotationZ(pref_phi) * baseOffset;
00120   fmat::Column<3> point = basePoint + offset;
00121   return invKin3Link(point[0], point[1], pref_phi);
00122 }
00123 
00124 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin3Link(float x,float y,float phi) const {
00125   PlanarThreeLinkArm::Solutions solutions;
00126   fmat::Matrix<1,2> d3, p2;
00127   fmat::Matrix<2,2> sols_2link;
00128   fmat::Column<2> q3; 
00129   d3(0,0) = L3 * std::cos(phi); d3(0,1) = L3 * std::sin(phi);
00130   p2(0,0) = x - d3(0,0); p2(0,1) = y - d3(0,1);
00131   float p2x = p2(0,0);    float p2y = p2(0,1);
00132   float c2 = (p2x*p2x + p2y*p2y - L1*L1 - L2*L2) / (2*L1*L2);
00133   if(c2*c2 > 1) {
00134     solutions.noSols = 0;
00135     solutions.valid = false;
00136     return solutions;
00137   }
00138   else {
00139     sols_2link = invKin2Link(p2x,p2y,L1,L2);
00140     q3[0] = phi - sols_2link(0,0) - sols_2link(0,1);
00141     q3[1] = phi - sols_2link(1,0) - sols_2link(1,1);
00142     solutions.angles(0,0) = sols_2link(0,0); solutions.angles(0,1) = sols_2link(0,1); solutions.angles(0,2) =  q3[0];
00143     solutions.angles(1,0) = sols_2link(1,0); solutions.angles(1,1) = sols_2link(1,1); solutions.angles(1,2) =  q3[1];
00144     solutions.noSols = 2;
00145     solutions = validAngles(solutions);
00146     return solutions;
00147   }
00148 }
00149 
00150 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::nearConfig(PlanarThreeLinkArm::Solutions sol, float elbow, bool valid) const{
00151   PlanarThreeLinkArm::Solutions ret_sol;  
00152   if ( (sol.angles(0,1)/fabs(sol.angles(0,1))) == (elbow/fabs(elbow)) ) {
00153     ret_sol.angles(0,0) = sol.angles(0,0); ret_sol.angles(0,1) = sol.angles(0,1); ret_sol.angles(0,2) = sol.angles(0,2);
00154     ret_sol.noSols = 1; ret_sol.valid = valid;
00155     return ret_sol;
00156   }
00157   if (sol.noSols == 2) {
00158     if ( (sol.angles(1,1)/fabs(sol.angles(1,1))) == (elbow/fabs(elbow)) ) {
00159       ret_sol.angles(0,0) = sol.angles(1,0); ret_sol.angles(0,1) = sol.angles(1,1); ret_sol.angles(0,2) = sol.angles(1,2);
00160       ret_sol.noSols = 1; ret_sol.valid = valid;
00161       return ret_sol;
00162     }
00163   } 
00164   ret_sol.noSols = 0;  ret_sol.valid = false;
00165   return ret_sol;
00166 }
00167 
00168 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::punt(float x, float y) const {
00169   PlanarThreeLinkArm::Solutions solutions;
00170   float q1 = std::atan2(y,x), q2 = 0.0f, q3 = 0.0f;
00171   q1 = std::min(std::max(q1,jointLimits[0][0]),jointLimits[0][1]);
00172   solutions.angles(0,0) = q1; solutions.angles(0,1) = q2; solutions.angles(0,2) = q3;
00173   solutions.noSols = 1;
00174   solutions.valid = false;
00175   return solutions;
00176 }
00177 
00178 fmat::Matrix<2,2> PlanarThreeLinkArm::invKin2Link(float x,float y,float link1,float link2) const {
00179   fmat::Matrix<2,2> ret;
00180   float c2 = (x*x + y*y - link1*link1 - link2*link2) / (2*link1*link2);
00181   float s2minus = std::sqrt(1-c2*c2);
00182   float s2plus = -std::sqrt(1-c2*c2);
00183   float q2minus = std::atan2(s2minus,c2);
00184   float q2plus = std::atan2(s2plus,c2); 
00185   float K1 = link1 + link2*c2;
00186   float K2plus = link2*s2plus;
00187   float K2minus = link2*s2minus;  
00188   float q1minus = std::atan2(y,x) - std::atan2(K2minus,K1);
00189   float q1plus = std::atan2(y,x) - std::atan2(K2plus,K1); 
00190   ret(0,0) = q1plus; ret(0,1) = q2plus;
00191   ret(1,0) = q1minus; ret(1,1) = q2minus; 
00192   return ret;
00193 }
00194 
00195 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::invKin2Link(float x,float y) const {
00196   PlanarThreeLinkArm::Solutions ret;
00197   float c2 = (x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2);
00198   
00199   if(c2*c2 > 1){
00200     bool noValid = true;
00201     while(noValid){
00202       if(std::fabs(x) > std::fabs(y)){
00203         if(x > 0)       
00204           x = x - 1;
00205         else 
00206           x = x + 1;
00207       }
00208       else if (std::fabs(y) > std::fabs(x)){
00209         if(y > 0)       
00210           y = y - 1;
00211         else 
00212           y = y + 1;
00213       }
00214       else{
00215         if(x > 0)
00216           x = x - 1; 
00217         else
00218           x = x + 1;
00219         if(y > 0)
00220           y = y - 1;    
00221         else 
00222           y = y + 1;
00223       }
00224       c2 = (x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2); 
00225       if(c2*c2 <= 1)
00226         noValid = false;
00227     }//end while
00228   }//end if 
00229   
00230   float s2minus = std::sqrt(1-c2*c2);
00231   float s2plus = -std::sqrt(1-c2*c2);
00232   float q2minus = std::atan2(s2minus,c2);
00233   float q2plus = std::atan2(s2plus,c2); 
00234   float K1 = L1 + L2*c2;
00235   float K2plus = L2*s2plus;
00236   float K2minus = L2*s2minus; 
00237   float q1minus = std::atan2(y,x) - std::atan2(K2minus,K1);
00238   float q1plus = std::atan2(y,x) - std::atan2(K2plus,K1); 
00239   ret.angles(0,0) = q1plus; ret.angles(0,1) = q2plus; ret.angles(0,2) = 0.0;
00240   ret.angles(1,0) = q1minus; ret.angles(1,1) = q2minus; ret.angles(1,2) = 0.0;
00241   return ret;
00242 }
00243 PlanarThreeLinkArm::Solutions PlanarThreeLinkArm::validAngles(PlanarThreeLinkArm::Solutions solutions) const {
00244   int valid_solutions[2] = {0, 0}; // assume both solutions are invalid
00245   fmat::Matrix<1,3> angles_set_1, angles_set_2;
00246   angles_set_1(0,0)=solutions.angles(0,0); angles_set_1(0,1)=solutions.angles(0,1); angles_set_1(0,2)=solutions.angles(0,2);
00247   angles_set_2(0,0)=solutions.angles(1,0); angles_set_2(0,1)=solutions.angles(1,1); angles_set_2(0,2)=solutions.angles(1,2);
00248   for( int sol_no = 0; sol_no < solutions.noSols; sol_no++ ) {
00249     // Check for joint limits, any solution with a joint outside the limits is an invalid solution
00250     int val_angles = 0;
00251     for( int joint_no = 0; joint_no < 3; joint_no++ ) {
00252       if( !(solutions.angles(sol_no,joint_no) < jointLimits[joint_no][0] || solutions.angles(sol_no,joint_no) > jointLimits[joint_no][1]) )
00253         val_angles++;
00254     }
00255     if( val_angles == 3 )
00256       valid_solutions[sol_no] = 1;
00257   } 
00258   if( valid_solutions[0]+valid_solutions[1] == 2 ) {      // both solutions were valid
00259     solutions.noSols = 2;
00260     solutions.valid = true;
00261     return solutions;
00262   }
00263   else if( valid_solutions[0]+valid_solutions[1] == 0 ) { // both solutions were invalid
00264     solutions.noSols = 0;
00265     solutions.valid = false;
00266     return solutions;
00267   }
00268   else {                                                  // one solution was invalid
00269     if( valid_solutions[0] == 0 ) {
00270       solutions.angles(0,0) = solutions.angles(1,0);
00271       solutions.angles(0,1) = solutions.angles(1,1);
00272       solutions.angles(0,2) = solutions.angles(1,2);
00273     }
00274     solutions.noSols = 1;
00275     solutions.valid = true;
00276     return solutions;
00277   }
00278 }
00279 
00280 float PlanarThreeLinkArm::angDist(float a1,float a2) const {
00281   // returns distance between two angles
00282   // answer is between 0 and pi
00283   float angle = std::fmod(std::abs(a1 - a2),float(2*M_PI));
00284   if( angle > (float)M_PI )
00285     angle = float(2*M_PI) - angle;
00286   return angle;
00287 }
00288 
00289 float PlanarThreeLinkArm::angNorm(float a) const {
00290   // Normalize an angle into the range -pi to pi
00291   float bias = (float)M_PI * (a/std::abs(a));
00292   float b = std::fmod(a+bias, float(2*M_PI)) - bias;
00293   return b;
00294 }
00295 
00296 fmat::Matrix<2,2> PlanarThreeLinkArm::rot(float t) const {
00297   // Returns a rotation matrix of t radians
00298   fmat::Matrix<2,2> r;
00299   r(0,0)=std::cos(t); r(0,1)=-std::sin(t);
00300   r(1,0)=std::sin(t); r(1,1)=std::sin(t);
00301   return r;
00302 }
00303 
00304 float PlanarThreeLinkArm::getL1() const{
00305   return (this->L1);
00306 }
00307 
00308 float PlanarThreeLinkArm::getL2() const{
00309   return (this->L2);
00310 }
00311 
00312 float PlanarThreeLinkArm::getL3() const{
00313   return (this->L3);
00314 }
00315 
00316 void PlanarThreeLinkArm::setL1(float length1, float jointMax, float jointMin){
00317   this->L1 = length1;
00318   this->jointLimits[0][0] = jointMin;
00319   this->jointLimits[0][1] = jointMax;
00320 }
00321 
00322 void PlanarThreeLinkArm::setL2(float length2, float jointMax, float jointMin){
00323   this->L2 = length2;
00324   this->jointLimits[1][0] = jointMin;
00325   this->jointLimits[1][1] = jointMax;
00326 }
00327 
00328 void PlanarThreeLinkArm::setL3(float length3, float jointMax, float jointMin){
00329   this->L3 = length3;
00330   this->jointLimits[2][0] = jointMin;
00331   this->jointLimits[2][1] = jointMax;
00332 }
00333 
00334 IKSolver::StepResult_t PlanarThreeLinkArm::step(const Point& pEff, const Rotation& oriEff, KinematicJoint& j, const Position& pTgt, float pDist, float posPri, const Orientation& oriTgt, float oriDist, float oriPri) const {
00335   // find the closest target point
00336   fmat::Transform Tj = j.getFullT();
00337   fmat::Column<3> pEffBase(Tj*pEff);
00338   fmat::Quaternion qj = j.getWorldQuaternion();
00339   Rotation oEffBase = qj*oriEff;
00340   Point de;
00341   pTgt.computeErrorGradient(pEffBase,oEffBase,de);
00342   StepResult_t res=SUCCESS;
00343   if(de.norm()>pDist) {
00344     de*=pDist/de.norm();
00345     res = PROGRESS;
00346   }
00347   Point pEffBaseP(pEffBase[1],pEffBase[2],pEffBase[3]);
00348   Point pTgtP = pEffBaseP+de;
00349   if(solve(pEff,oriEff,j,pTgtP,posPri,oriTgt,oriPri))
00350     return res;
00351   return LIMITS;
00352 }
00353 
00354 #endif //TGT_HANDEYE

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