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