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