00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 #include <p2os_driver/kinecalc.h>
00026 
00027 #include <math.h>
00028 
00029 #include <stdio.h>
00030 
00031 KineCalc::KineCalc (void)
00032 {
00033   link1 = 0.06875f;
00034   link2 = 0.16f;
00035   link3 = 0.0f;
00036   link4 = 0.13775f;
00037   link5 = 0.11321f;
00038 
00039   endEffector.p.x = 0.0f; endEffector.p.y = 0.0f; endEffector.p.z = 0.0f;
00040   endEffector.n.x = 0.0f; endEffector.n.y = 0.0f; endEffector.n.z = 0.0f;
00041   endEffector.o.x = 0.0f; endEffector.o.y = -1.0f; endEffector.o.z = 1.0f;
00042   endEffector.a.x = 1.0f; endEffector.a.y = 0.0f; endEffector.a.z = 0.0f;
00043 
00044   for (int ii = 0; ii < 5; ii++)
00045   {
00046     joints[ii] = 0.0f;
00047     jointOffsets[ii] = 0.0f;
00048     jointMin[ii] = 0.0f;
00049     jointMax[ii] = 0.0f;
00050   }
00051 }
00052 
00053 
00055 
00057 
00058 void KineCalc::SetP (double newPX, double newPY, double newPZ)
00059 {
00060   endEffector.p.x = newPX;
00061   endEffector.p.y = newPY;
00062   endEffector.p.z = newPZ;
00063 }
00064 
00065 void KineCalc::SetN (double newNX, double newNY, double newNZ)
00066 {
00067   endEffector.n.x = newNX;
00068   endEffector.n.y = newNY;
00069   endEffector.n.z = newNZ;
00070 }
00071 
00072 void KineCalc::SetO (double newOX, double newOY, double newOZ)
00073 {
00074   endEffector.o.x = newOX;
00075   endEffector.o.y = newOY;
00076   endEffector.o.z = newOZ;
00077 }
00078 
00079 void KineCalc::SetA (double newAX, double newAY, double newAZ)
00080 {
00081   endEffector.a.x = newAX;
00082   endEffector.a.y = newAY;
00083   endEffector.a.z = newAZ;
00084 }
00085 
00086 double KineCalc::GetTheta (unsigned int index)
00087 {
00088   return joints[index];
00089 }
00090 
00091 void KineCalc::SetTheta (unsigned int index, double newVal)
00092 {
00093   joints[index] = newVal;
00094 }
00095 
00096 void KineCalc::SetLinkLengths (double newLink1, double newLink2, double newLink3, double newLink4, double newLink5)
00097 {
00098   link1 = newLink1;
00099   link2 = newLink2;
00100   link3 = newLink3;
00101   link4 = newLink4;
00102   link5 = newLink5;
00103 }
00104 
00105 void KineCalc::SetOffset (unsigned int joint, double newOffset)
00106 {
00107   jointOffsets[joint] = newOffset;
00108 }
00109 
00110 void KineCalc::SetJointRange (unsigned int joint, double min, double max)
00111 {
00112   jointMin[joint] = fmin(min, max);   
00113   jointMax[joint] = fmax(min, max);
00114 }
00115 
00116 
00117 
00119 
00121 
00122 KineVector KineCalc::Normalise (const KineVector &vector)
00123 {
00124   KineVector result;
00125   double length = sqrt (vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
00126   if (length != 0)
00127   {
00128     result.x = vector.x / length;
00129     result.y = vector.y / length;
00130     result.z = vector.z / length;
00131   }
00132   else
00133   {
00134     printf ("P2OS: Tried to normalise a vector of zero length.");
00135     result.x = 0;
00136     result.y = 0;
00137     result.z = 0;
00138   }
00139   return result;
00140 }
00141 
00142 KineVector KineCalc::CalculateN (const EndEffector &pose)
00143 {
00144   KineVector result;
00145   result.x = pose.o.y * pose.a.z - pose.a.y * pose.o.z;
00146   result.y = pose.o.z * pose.a.x - pose.a.z * pose.o.x;
00147   result.z = pose.o.x * pose.a.y - pose.a.x * pose.o.y;
00148   if (result.x == 0 && result.y == 0 && result.z == 0)
00149   {
00150     printf ("P2OS: Approach and orientation cannot be the same vector - their cross product cannot be zero.");
00151     
00152     KineVector orient;
00153     if (pose.a.y == 0 && pose.a.z == 0)
00154     {
00155       orient.x = 0;
00156       orient.y = 1;
00157       orient.z = 0;
00158     }
00159     else
00160     {
00161       orient.x = 1;
00162       orient.y = 0;
00163       orient.z = 0;
00164     }
00165     result.x = orient.y * pose.a.z - pose.a.y * orient.z;
00166     result.y = orient.z * pose.a.x - pose.a.z * orient.x;
00167     result.z = orient.x * pose.a.y - pose.a.x * orient.y;
00168   }
00169   return Normalise (result);
00170 }
00171 
00172 void KineCalc::PrintEndEffector (const EndEffector &endEffector)
00173 {
00174   printf ("P: (%f, %f, %f)\tA: (%f, %f, %f)\tO: (%f, %f, %f)\tN: (%f, %f, %f)\n",
00175           endEffector.p.x, endEffector.p.y, endEffector.p.z,
00176           endEffector.a.x, endEffector.a.y, endEffector.a.z,
00177           endEffector.o.x, endEffector.o.y, endEffector.o.z,
00178           endEffector.n.x, endEffector.n.y, endEffector.n.z);
00179 }
00180 
00181 
00183 
00185 
00186 
00187 
00188 
00189 void KineCalc::CalculateFK (const double fromJoints[])
00190 {
00191   double adjustedJoints[5];
00192 
00193   adjustedJoints[0] = (fromJoints[0] - jointOffsets[0]) * -1;
00194   adjustedJoints[1] = fromJoints[1] - jointOffsets[1];
00195   adjustedJoints[2] = fromJoints[2] - jointOffsets[2];
00196   adjustedJoints[3] = (fromJoints[3] - jointOffsets[3]) * -1;;
00197   adjustedJoints[4] = (fromJoints[4] - jointOffsets[4]) * -1;;
00198 
00199   endEffector = CalcFKForJoints (adjustedJoints);
00200 
00201 
00202 }
00203 
00204 
00205 
00206 
00207 
00208 bool KineCalc::CalculateIK (const EndEffector &fromPosition)
00209 {
00210   
00211   const KineVector &p = fromPosition.p;
00212   const KineVector &a = fromPosition.a;
00213   
00214   
00215   
00216   
00217   
00218   double solutions[4][5];
00219   double temp = 0.0f;
00220 
00221   
00222   temp = atan2 (p.y - link5 * a.y, p.x - link5 * a.x);
00223   solutions[0][0] = solutions[1][0] = temp;
00224   temp = atan2 (link5 * a.y - p.y, link5 * a.x - p.x);
00225   solutions[2][0] = solutions[3][0] = temp;
00226 
00227   
00228   
00229   double r = 0.0f, rz = 0.0f;
00230   if (sin (solutions[0][0]) < 0.1f && sin(solutions[0][0]) > -0.1f)
00231   {
00232     r = ((p.x - (link5 * a.x)) / cos (solutions[0][0])) - link1;
00233   }
00234   else
00235   {
00236     r = ((p.y - (link5 * a.y)) / sin (solutions[0][0])) - link1;
00237   }
00238   rz = p.z - (link5 * a.z);
00239   
00240   temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt (r * r + rz * rz));
00241   temp = fmin (fmax (temp, -1.0f), 1.0f);
00242   temp = atan2 (rz, r) - acos (temp);
00243   int m1 = -1;
00244   do
00245   {
00246     if (m1 > 1)
00247     {
00248       printf ("m1 > 1!\n");
00249       break;
00250     }
00251     solutions[0][1] = temp + 2 * m1 * M_PI;
00252     m1 += 1;  
00253   } 
00254   while ((solutions[0][1] < -(M_PI) || solutions[0][1] > M_PI));
00255   temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
00256   temp = fmin (fmax (temp, -1.0f), 1.0f);
00257   solutions[0][2] = M_PI - acos (temp);
00258   
00259   temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt (r * r + rz * rz));
00260   temp = fmin (fmax (temp, -1.0f), 1.0f);
00261   temp = atan2 (rz, r) + acos (temp);
00262   m1 = -1;
00263   do
00264   {
00265     if (m1 > 1)
00266     {
00267       break;
00268     }
00269     solutions[1][1] = temp + 2 * m1 * M_PI;
00270     m1 += 1;  
00271   }
00272   while ((solutions[1][1] < -(M_PI) || solutions[1][1] > M_PI));
00273   temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
00274   temp = fmin (fmax (temp, -1.0f), 1.0f);
00275   solutions[1][2] = -(M_PI) + acos (temp);
00276 
00277   
00278   CalcTheta4and5 (solutions[0], fromPosition);
00279   
00280   CalcTheta4and5 (solutions[1], fromPosition);
00281 
00282   
00283   
00284   r = 0.0f;
00285   rz = 0.0f;
00286   if (sin (solutions[2][0]) < 0.1f && sin(solutions[2][0]) > -0.1f)
00287   {
00288     r = (p.x - link5 * a.x) / cos (solutions[2][0]) - link1;
00289   }
00290   else
00291   {
00292     r = (p.y - link5 * a.y) / sin (solutions[2][0]) - link1;
00293   }
00294   rz = p.z - (link5 * a.z);
00295   
00296   temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt (r * r + rz * rz));
00297   temp = fmin (fmax (temp, -1.0f), 1.0f);
00298   temp = atan2 (rz, r) - acos (temp);
00299   m1 = -1;
00300   do
00301   {
00302     if (m1 > 1)
00303     {
00304       break;
00305     }
00306     solutions[2][1] = temp + 2 * m1 * M_PI;
00307     m1 += 1;  
00308   } 
00309   while ((solutions[2][1] < -(M_PI) || solutions[2][1] > M_PI));
00310   temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
00311   temp = fmin (fmax (temp, -1.0f), 1.0f);
00312   solutions[2][2] = M_PI - acos (temp);
00313   
00314   temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt (r * r + rz * rz));
00315   temp = fmin (fmax (temp, -1.0f), 1.0f);
00316   temp = atan2 (rz, r) + acos (temp);
00317   m1 = -1;
00318   do
00319   {
00320     if (m1 > 1)
00321     {
00322       break;
00323     }
00324     solutions[3][1] = temp + 2 * m1 * M_PI;
00325     m1 += 1;  
00326   }
00327   while ((solutions[3][1] < -(M_PI) || solutions[3][1] > M_PI));
00328   temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
00329   temp = fmin (fmax (temp, -1.0f), 1.0f);
00330   solutions[3][2] = -(M_PI) + acos (temp);
00331 
00332   
00333   CalcTheta4and5 (solutions[2], fromPosition);
00334   
00335   CalcTheta4and5 (solutions[3], fromPosition);
00336 
00337   
00338   int chosenSolution = ChooseSolution (fromPosition, solutions);
00339   if (chosenSolution == -1)
00340     
00341     return false;
00342 
00343   
00344   joints[0] = (solutions[chosenSolution][0] * -1) + jointOffsets[0];
00345   joints[1] = solutions[chosenSolution][1] + jointOffsets[1];
00346   joints[2] = solutions[chosenSolution][2] + jointOffsets[2];
00347   joints[3] = (solutions[chosenSolution][3] * -1) + jointOffsets[3];
00348   joints[4] = (solutions[chosenSolution][4] * -1) + jointOffsets[4];
00349 
00350   return true;
00351 }
00352 
00353 
00354 
00355 
00356 void KineCalc::CalcTheta4and5 (double angles[], const EndEffector &fromPosition)
00357 {
00358   const KineVector &n = fromPosition.n;
00359   const KineVector &o = fromPosition.o;
00360   const KineVector &a = fromPosition.a;
00361 
00362   double cos1 = cos (angles[0]);
00363   double cos23 = cos (angles[1] + angles[2]);
00364   double sin1 = sin (angles[0]);
00365   double sin23 = sin (angles[1] + angles[2]);
00366 
00367   if (cos23 != 0.0f)
00368   {
00369     if (sin1 < -0.1f || sin1 > 0.1f)
00370     {
00371       angles[3] = atan2 (n.z / cos23, -(n.x + ((n.z * cos1 * sin23) / cos23)) / sin1);
00372     }
00373     else
00374     {
00375       angles[3] = atan2 (n.z / cos23, (n.y + ((n.z * sin1 * sin23) / cos23)) / cos1);
00376     }
00377 
00378     double cos4 = cos (angles[3]);
00379     double sin4 = sin (angles[3]);
00380     if (cos4 != 0 || sin23 != 0)
00381     {
00382       angles[4] = atan2 (a.z * cos23 * cos4 - o.z * sin23, o.z * cos23 * cos4 + a.z * sin23);
00383     }
00384     else
00385     {
00386       angles[4] = atan2 (-(o.x * cos1 + o.y * sin1) / cos23, (o.x * sin1 - o.y * cos1) / sin4);
00387     }
00388   }
00389   else
00390   {
00391     angles[4] = atan2 (-o.z / sin23, a.z / sin23);
00392 
00393     double cos5 = cos (angles[4]);
00394     double sin5 = sin (angles[4]);
00395     if (cos5 > -0.1f || cos5 < 0.1f)
00396     {
00397       angles[3] = atan2 ((a.x * sin1 - a.y * cos1) / sin5, -(n.x * sin1) + n.y * cos1);
00398     }
00399     else
00400     {
00401       angles[3] = atan2 ((o.x * sin1 - o.y * cos1) / cos5, -(n.x * sin1) + n.y * cos1);
00402     }
00403   }
00404 }
00405 
00406 
00407 
00408 
00409 int KineCalc::ChooseSolution (const EndEffector &fromPosition, const double solutions[][5])
00410 {
00411   double errors[4];
00412   int order[4], jj;
00413 
00414   
00415   errors[0] = CalcSolutionError (solutions[0], fromPosition);
00416   errors[1] = CalcSolutionError (solutions[1], fromPosition);
00417   errors[2] = CalcSolutionError (solutions[2], fromPosition);
00418   errors[3] = CalcSolutionError (solutions[3], fromPosition);
00419 
00420   for (int ii = 0; ii < 4; ii++)
00421   {
00422     double min = fmin (errors[0], fmin (errors[1], fmin(errors[2], errors[3])));
00423     for (jj = 0; min != errors[jj]; jj++);  
00424     errors[jj] = 999999;
00425     order[ii] = jj;
00426   }
00427 
00428   for (int ii = 0; ii < 4; ii++)
00429   {
00430     if (SolutionInRange (solutions[order[ii]]))
00431     {
00432       return order[ii];
00433     }
00434   }
00435 
00436   return -1;
00437 }
00438 
00439 
00440 
00441 
00442 double KineCalc::CalcSolutionError (const double solution[], const EndEffector &fromPosition)
00443 {
00444   EndEffector solutionPos;
00445   double error = 0.0f;
00446 
00447   
00448   solutionPos = CalcFKForJoints (solution);
00449   
00450   double xOffset = solutionPos.p.x - fromPosition.p.x;
00451   double yOffset = solutionPos.p.y - fromPosition.p.y;
00452   double zOffset = solutionPos.p.z - fromPosition.p.z;
00453 
00454   error = sqrt (xOffset * xOffset + yOffset * yOffset + zOffset * zOffset);
00455   if (isnan (error))
00456     error = 9999;
00457 
00458   return error;
00459 }
00460 
00461 
00462 
00463 EndEffector KineCalc::CalcFKForJoints (const double angles[])
00464 {
00465   EndEffector result;
00466 
00467   double cos1 = cos (angles[0]);
00468   double cos2 = cos (angles[1]);
00469   double cos23 = cos (angles[1] + angles[2]);
00470   double cos4 = cos (angles[3]);
00471   double cos5 = cos (angles[4]);
00472   double sin1 = sin (angles[0]);
00473   double sin2 = sin (angles[1]);
00474   double sin23 = sin (angles[1] + angles[2]);
00475   double sin4 = sin (angles[3]);
00476   double sin5 = sin (angles[4]);
00477 
00478   result.p.x = link5 * ((cos1 * cos23 * cos5) + (sin1 * sin4 * sin5) - (cos1 * sin23 * cos4 * sin5)) +
00479       cos1 * ((link4 * cos23) + (link2 * cos2) + link1);
00480   result.p.y = link5 * ((sin1 * cos23 * cos5) + (cos1 * sin4 * sin5) - (sin1 * sin23 * cos4 * sin5)) +
00481       sin1 * ((link4 * cos23) + (link2 * cos2) + link1);
00482   result.p.z = link5 * ((sin23 * cos5) + (cos23 * cos4 * sin5)) + (link4 * sin23) + (link2 * sin2);
00483 
00484   result.n.x = -(sin1 * cos4) - (cos1 * sin23 * sin4);
00485   result.n.y = (cos1 * cos4) - (sin1 * sin23 * sin4);
00486   result.n.z = (cos23 * sin4);
00487 
00488   result.o.x = -(cos1 * cos23 * sin5) + (sin1 * sin4 * cos5) - (cos1 * sin23 * cos4 * cos5);
00489   result.o.y = -(sin1 * cos23 * sin5) - (cos1 * sin4 * cos5) - (sin1 * sin23 * cos4 * cos5);
00490   result.o.z = -(sin23 * sin5) + (cos23 * cos4 * cos5);
00491 
00492   result.a.x = (cos1 * cos23 * cos5) + (sin1 * sin4 * sin5) - (cos1 * sin23 * cos4 * sin5);
00493   result.a.y = (sin1 * cos23 * cos5) + (cos1 * sin4 * sin5) - (sin1 * sin23 * cos4 * sin5);
00494   result.a.z = (sin23 * cos5) + (cos23 * cos4 * sin5);
00495 
00496   return result;
00497 }
00498 
00499 
00500 
00501 bool KineCalc::SolutionInRange (const double angles[])
00502 {
00503   for (int ii = 0; ii < 5; ii++)
00504   {
00505     if (angles[ii] < jointMin[ii] || angles[ii] > jointMax[ii] || isnan(angles[ii]))
00506       return false;
00507   }
00508 
00509   return true;
00510 }