kinecalc.cpp
Go to the documentation of this file.
1 /*
2  * P2OS for ROS
3  * Copyright (C) 2015 David Feil-Seifer, Brian Gerkey, Kasper Stoy,
4  * Richard Vaughan, & Andrew Howard
5  * Copyright (C) 2018 Hunter L. Allen
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22 #include <stdio.h>
23 #include <math.h>
24 
25 #include <p2os_driver/kinecalc.hpp>
26 
28 {
29  link1 = 0.06875f;
30  link2 = 0.16f;
31  link3 = 0.0f;
32  link4 = 0.13775f;
33  link5 = 0.11321f;
34 
35  endEffector.p.x = 0.0f; endEffector.p.y = 0.0f; endEffector.p.z = 0.0f;
36  endEffector.n.x = 0.0f; endEffector.n.y = 0.0f; endEffector.n.z = 0.0f;
37  endEffector.o.x = 0.0f; endEffector.o.y = -1.0f; endEffector.o.z = 1.0f;
38  endEffector.a.x = 1.0f; endEffector.a.y = 0.0f; endEffector.a.z = 0.0f;
39 
40  for (int ii = 0; ii < 5; ii++) {
41  joints[ii] = 0.0f;
42  jointOffsets[ii] = 0.0f;
43  jointMin[ii] = 0.0f;
44  jointMax[ii] = 0.0f;
45  }
46 }
47 
48 
50 // Accessor functions
52 
53 void KineCalc::SetP(double newPX, double newPY, double newPZ)
54 {
55  endEffector.p.x = newPX;
56  endEffector.p.y = newPY;
57  endEffector.p.z = newPZ;
58 }
59 
60 void KineCalc::SetN(double newNX, double newNY, double newNZ)
61 {
62  endEffector.n.x = newNX;
63  endEffector.n.y = newNY;
64  endEffector.n.z = newNZ;
65 }
66 
67 void KineCalc::SetO(double newOX, double newOY, double newOZ)
68 {
69  endEffector.o.x = newOX;
70  endEffector.o.y = newOY;
71  endEffector.o.z = newOZ;
72 }
73 
74 void KineCalc::SetA(double newAX, double newAY, double newAZ)
75 {
76  endEffector.a.x = newAX;
77  endEffector.a.y = newAY;
78  endEffector.a.z = newAZ;
79 }
80 
81 double KineCalc::GetTheta(unsigned int index)
82 {
83  return joints[index];
84 }
85 
86 void KineCalc::SetTheta(unsigned int index, double newVal)
87 {
88  joints[index] = newVal;
89 }
90 
92  double newLink1, double newLink2, double newLink3, double newLink4,
93  double newLink5)
94 {
95  link1 = newLink1;
96  link2 = newLink2;
97  link3 = newLink3;
98  link4 = newLink4;
99  link5 = newLink5;
100 }
101 
102 void KineCalc::SetOffset(unsigned int joint, double newOffset)
103 {
104  jointOffsets[joint] = newOffset;
105 }
106 
107 void KineCalc::SetJointRange(unsigned int joint, double min, double max)
108 {
109  jointMin[joint] = fmin(min, max); // So that if min > max we reverse them
110  jointMax[joint] = fmax(min, max);
111 }
112 
113 
115 // Utility helper functions
117 
119 {
120  KineVector result;
121  double length = sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
122  if (length != 0) {
123  result.x = vector.x / length;
124  result.y = vector.y / length;
125  result.z = vector.z / length;
126  } else {
127  printf("P2OS: Tried to normalise a vector of zero length.\n");
128  result.x = 0;
129  result.y = 0;
130  result.z = 0;
131  }
132  return result;
133 }
134 
136 {
137  KineVector result;
138  result.x = pose.o.y * pose.a.z - pose.a.y * pose.o.z;
139  result.y = pose.o.z * pose.a.x - pose.a.z * pose.o.x;
140  result.z = pose.o.x * pose.a.y - pose.a.x * pose.o.y;
141  if (result.x == 0 && result.y == 0 && result.z == 0) {
142  printf(
143  "P2OS: Approach and orientation cannot be the same vector"
144  "- their cross product cannot be zero.\n");
145  // Ensures that a different orientation vector is created
146  KineVector orient;
147  if (pose.a.y == 0 && pose.a.z == 0) {
148  orient.x = 0;
149  orient.y = 1;
150  orient.z = 0;
151  } else {
152  orient.x = 1;
153  orient.y = 0;
154  orient.z = 0;
155  }
156  result.x = orient.y * pose.a.z - pose.a.y * orient.z;
157  result.y = orient.z * pose.a.x - pose.a.z * orient.x;
158  result.z = orient.x * pose.a.y - pose.a.x * orient.y;
159  }
160  return Normalise(result);
161 }
162 
164 {
165  printf("P: (%f, %f, %f)\tA: (%f, %f, %f)\tO: (%f, %f, %f)\tN: (%f, %f, %f)\n",
166  endEffector.p.x, endEffector.p.y, endEffector.p.z,
167  endEffector.a.x, endEffector.a.y, endEffector.a.z,
168  endEffector.o.x, endEffector.o.y, endEffector.o.z,
169  endEffector.n.x, endEffector.n.y, endEffector.n.z);
170 }
171 
172 
174 // The important functions
176 
177 // Calculate the forward kinematics
178 // The result is stored in endEffector
179 // fromJoints[]: An array of 5 joint values
180 void KineCalc::CalculateFK(const double fromJoints[])
181 {
182  double adjustedJoints[5];
183 
184  adjustedJoints[0] = (fromJoints[0] - jointOffsets[0]) * -1;
185  adjustedJoints[1] = fromJoints[1] - jointOffsets[1];
186  adjustedJoints[2] = fromJoints[2] - jointOffsets[2];
187  adjustedJoints[3] = (fromJoints[3] - jointOffsets[3]) * -1;
188  adjustedJoints[4] = (fromJoints[4] - jointOffsets[4]) * -1;
189 
190  endEffector = CalcFKForJoints(adjustedJoints);
191 // printf ("Result of FK:\n");
192 // PrintEndEffector (endEffector);
193 }
194 
195 // Calculate the inverse kinematics
196 // The result is stored in joints
197 // fromPosition: An EndEffector structure describing the pose
198 // of the end effector
199 bool KineCalc::CalculateIK(const EndEffector & fromPosition)
200 {
201  // Some references to make the code neater
202  const KineVector & p = fromPosition.p;
203  const KineVector & a = fromPosition.a;
204  // These are the four possible solutions to the IK
205  // solution1 = {1a, 2a, 3a, 4a, 5a}
206  // solution2 = {1a, 2b, 3b, 4b, 5b}
207  // solution3 = {1b, 2c, 3c, 4c, 5c}
208  // solution4 = {1b, 2d, 3d, 4d, 5d}
209  double solutions[4][5];
210  double temp = 0.0f;
211 
212  // First calculate the two possible values for theta1, theta1a and theta1b
213  temp = atan2(p.y - link5 * a.y, p.x - link5 * a.x);
214  solutions[0][0] = solutions[1][0] = temp;
215  temp = atan2(link5 * a.y - p.y, link5 * a.x - p.x);
216  solutions[2][0] = solutions[3][0] = temp;
217 
218  // Next, using theta1_a, calculate thetas 2 and 3 (a and b)
219  // First up is calculating r and rz
220  double r = 0.0f, rz = 0.0f;
221  if (sin(solutions[0][0]) < 0.1f && sin(solutions[0][0]) > -0.1f) {
222  r = ((p.x - (link5 * a.x)) / cos(solutions[0][0])) - link1;
223  } else {
224  r = ((p.y - (link5 * a.y)) / sin(solutions[0][0])) - link1;
225  }
226  rz = p.z - (link5 * a.z);
227  // Then calculate theta2a and 3a
228  temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt(r * r + rz * rz));
229  temp = fmin(fmax(temp, -1.0f), 1.0f);
230  temp = atan2(rz, r) - acos(temp);
231  int m1 = -1;
232  do {
233  if (m1 > 1) {
234  printf("m1 > 1!\n");
235  break;
236  }
237  solutions[0][1] = temp + 2 * m1 * M_PI;
238  m1 += 1; // So that within the 3 iterations we get m1 = -1, 0, 1
239  } while ((solutions[0][1] < -(M_PI) || solutions[0][1] > M_PI)); // && m1 < 1);
240  // Put a catchall here to prevent infinite loops by checking if m1 has gone past 1
241  temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
242  temp = fmin(fmax(temp, -1.0f), 1.0f);
243  solutions[0][2] = M_PI - acos(temp);
244  // Followed by theta2b and 3b
245  temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt(r * r + rz * rz));
246  temp = fmin(fmax(temp, -1.0f), 1.0f);
247  temp = atan2(rz, r) + acos(temp);
248  m1 = -1;
249  do {
250  if (m1 > 1) {
251  break;
252  }
253  solutions[1][1] = temp + 2 * m1 * M_PI;
254  m1 += 1; // So that within the 3 iterations we get m1 = -1, 0, 1
255  } while ((solutions[1][1] < -(M_PI) || solutions[1][1] > M_PI)); // && m1 < 1);
256  temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
257  temp = fmin(fmax(temp, -1.0f), 1.0f);
258  solutions[1][2] = -(M_PI) + acos(temp);
259 
260  // Using theta2a and 3a, calculate 4a and 5a to complete solution1
261  CalcTheta4and5(solutions[0], fromPosition);
262  // Using theta2b and 3b, calculate 4b and 5b to complete solution2
263  CalcTheta4and5(solutions[1], fromPosition);
264 
265  // That's two of the possible solutions. To get the other two, repeat with theta1b
266  // First up is calculating r and rz
267  r = 0.0f;
268  rz = 0.0f;
269  if (sin(solutions[2][0]) < 0.1f && sin(solutions[2][0]) > -0.1f) {
270  r = (p.x - link5 * a.x) / cos(solutions[2][0]) - link1;
271  } else {
272  r = (p.y - link5 * a.y) / sin(solutions[2][0]) - link1;
273  }
274  rz = p.z - (link5 * a.z);
275  // Then calculate theta2c and 3c
276  temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt(r * r + rz * rz));
277  temp = fmin(fmax(temp, -1.0f), 1.0f);
278  temp = atan2(rz, r) - acos(temp);
279  m1 = -1;
280  do {
281  if (m1 > 1) {
282  break;
283  }
284  solutions[2][1] = temp + 2 * m1 * M_PI;
285  m1 += 1; // So that within the 3 iterations we get m1 = -1, 0, 1
286  } while ((solutions[2][1] < -(M_PI) || solutions[2][1] > M_PI)); // && m1 < 1);
287  // Put a catchall here to prevent infinite loops by checking if m1 has gone past 1
288  temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
289  temp = fmin(fmax(temp, -1.0f), 1.0f);
290  solutions[2][2] = M_PI - acos(temp);
291  // Followed by theta2d and 3d
292  temp = (r * r + rz * rz + link2 * link2 - link4 * link4) / (2 * link2 * sqrt(r * r + rz * rz));
293  temp = fmin(fmax(temp, -1.0f), 1.0f);
294  temp = atan2(rz, r) + acos(temp);
295  m1 = -1;
296  do {
297  if (m1 > 1) {
298  break;
299  }
300  solutions[3][1] = temp + 2 * m1 * M_PI;
301  m1 += 1; // So that within the 3 iterations we get m1 = -1, 0, 1
302  } while ((solutions[3][1] < -(M_PI) || solutions[3][1] > M_PI)); // && m1 < 1);
303  temp = (link2 * link2 + link4 * link4 - r * r - rz * rz) / (2 * link2 * link4);
304  temp = fmin(fmax(temp, -1.0f), 1.0f);
305  solutions[3][2] = -(M_PI) + acos(temp);
306 
307  // Using theta2c and 3c, calculate 4c and 5c to complete solution1
308  CalcTheta4and5(solutions[2], fromPosition);
309  // Using theta2d and 3d, calculate 4d and 5d to complete solution2
310  CalcTheta4and5(solutions[3], fromPosition);
311 
312  // Choose the best of the four solutions
313  int chosenSolution = ChooseSolution(fromPosition, solutions);
314  if (chosenSolution == -1) {
315  // Couldn't find a valid solution
316  return false;
317  }
318 
319  // Offsets and so forth
320  joints[0] = (solutions[chosenSolution][0] * -1) + jointOffsets[0];
321  joints[1] = solutions[chosenSolution][1] + jointOffsets[1];
322  joints[2] = solutions[chosenSolution][2] + jointOffsets[2];
323  joints[3] = (solutions[chosenSolution][3] * -1) + jointOffsets[3];
324  joints[4] = (solutions[chosenSolution][4] * -1) + jointOffsets[4];
325 
326  return true;
327 }
328 
329 // Calculates thetas 4 and 5 based on supplied thetas 1, 2 and 3 and the desired end effector pose
330 // angles[]: A 5-element array, of which elements 0, 1 and 2 should be filled already
331 // fromPosition: The desired end effector pose
332 void KineCalc::CalcTheta4and5(double angles[], const EndEffector & fromPosition)
333 {
334  const KineVector & n = fromPosition.n;
335  const KineVector & o = fromPosition.o;
336  const KineVector & a = fromPosition.a;
337 
338  double cos1 = cos(angles[0]);
339  double cos23 = cos(angles[1] + angles[2]);
340  double sin1 = sin(angles[0]);
341  double sin23 = sin(angles[1] + angles[2]);
342 
343  if (cos23 != 0.0f) {
344  if (sin1 < -0.1f || sin1 > 0.1f) {
345  angles[3] = atan2(n.z / cos23, -(n.x + ((n.z * cos1 * sin23) / cos23)) / sin1);
346  } else {
347  angles[3] = atan2(n.z / cos23, (n.y + ((n.z * sin1 * sin23) / cos23)) / cos1);
348  }
349 
350  double cos4 = cos(angles[3]);
351  double sin4 = sin(angles[3]);
352  if (cos4 != 0 || sin23 != 0) {
353  angles[4] = atan2(a.z * cos23 * cos4 - o.z * sin23, o.z * cos23 * cos4 + a.z * sin23);
354  } else {
355  angles[4] = atan2(-(o.x * cos1 + o.y * sin1) / cos23, (o.x * sin1 - o.y * cos1) / sin4);
356  }
357  } else {
358  angles[4] = atan2(-o.z / sin23, a.z / sin23);
359 
360  double cos5 = cos(angles[4]);
361  double sin5 = sin(angles[4]);
362  if (cos5 > -0.1f || cos5 < 0.1f) {
363  angles[3] = atan2((a.x * sin1 - a.y * cos1) / sin5, -(n.x * sin1) + n.y * cos1);
364  } else {
365  angles[3] = atan2((o.x * sin1 - o.y * cos1) / cos5, -(n.x * sin1) + n.y * cos1);
366  }
367  }
368 }
369 
370 // Choose the best solution from the 4 available based on error and reachability
371 // fromPosition: The desired end effector pose
372 // solutions[][]: The four solutions (each with 5 angles) in an array
373 int KineCalc::ChooseSolution(const EndEffector & fromPosition, const double solutions[][5])
374 {
375  double errors[4];
376  int order[4], jj;
377 
378  // We have 4 solutions, calculate the error for each one
379  errors[0] = CalcSolutionError(solutions[0], fromPosition);
380  errors[1] = CalcSolutionError(solutions[1], fromPosition);
381  errors[2] = CalcSolutionError(solutions[2], fromPosition);
382  errors[3] = CalcSolutionError(solutions[3], fromPosition);
383 
384  for (int ii = 0; ii < 4; ii++) {
385  double min = fmin(errors[0], fmin(errors[1], fmin(errors[2], errors[3])));
386  for (jj = 0; min != errors[jj]; jj++) { // Find the index at which the min is at
387  }
388  errors[jj] = 999999;
389  order[ii] = jj;
390  }
391 
392  for (int ii = 0; ii < 4; ii++) {
393  if (SolutionInRange(solutions[order[ii]])) {
394  return order[ii];
395  }
396  }
397 
398  return -1;
399 }
400 
401 // Calculate the error for a solution from the desired pose
402 // solution[]: An array of 5 angles
403 // fromPosition[]: The end effector pose
404 double KineCalc::CalcSolutionError(const double solution[], const EndEffector & fromPosition)
405 {
406  EndEffector solutionPos;
407  double error = 0.0f;
408 
409  // Calculate the position of the end effector this solution gives using FK
410  solutionPos = CalcFKForJoints(solution);
411  // Calculate the distance from this to the desired position
412  double xOffset = solutionPos.p.x - fromPosition.p.x;
413  double yOffset = solutionPos.p.y - fromPosition.p.y;
414  double zOffset = solutionPos.p.z - fromPosition.p.z;
415 
416  error = sqrt(xOffset * xOffset + yOffset * yOffset + zOffset * zOffset);
417  if (isnan(error)) {
418  error = 9999;
419  }
420 
421  return error;
422 }
423 
424 // Calculates the forward kinematics of a set of joint angles
425 // angles[]: The 5 angles to calculate from
427 {
428  EndEffector result;
429 
430  double cos1 = cos(angles[0]);
431  double cos2 = cos(angles[1]);
432  double cos23 = cos(angles[1] + angles[2]);
433  double cos4 = cos(angles[3]);
434  double cos5 = cos(angles[4]);
435  double sin1 = sin(angles[0]);
436  double sin2 = sin(angles[1]);
437  double sin23 = sin(angles[1] + angles[2]);
438  double sin4 = sin(angles[3]);
439  double sin5 = sin(angles[4]);
440 
441  result.p.x = link5 *
442  ((cos1 * cos23 * cos5) + (sin1 * sin4 * sin5) - (cos1 * sin23 * cos4 * sin5)) +
443  cos1 * ((link4 * cos23) + (link2 * cos2) + link1);
444  result.p.y = link5 *
445  ((sin1 * cos23 * cos5) + (cos1 * sin4 * sin5) - (sin1 * sin23 * cos4 * sin5)) +
446  sin1 * ((link4 * cos23) + (link2 * cos2) + link1);
447  result.p.z = link5 * ((sin23 * cos5) + (cos23 * cos4 * sin5)) + (link4 * sin23) + (link2 * sin2);
448 
449  result.n.x = -(sin1 * cos4) - (cos1 * sin23 * sin4);
450  result.n.y = (cos1 * cos4) - (sin1 * sin23 * sin4);
451  result.n.z = (cos23 * sin4);
452 
453  result.o.x = -(cos1 * cos23 * sin5) + (sin1 * sin4 * cos5) - (cos1 * sin23 * cos4 * cos5);
454  result.o.y = -(sin1 * cos23 * sin5) - (cos1 * sin4 * cos5) - (sin1 * sin23 * cos4 * cos5);
455  result.o.z = -(sin23 * sin5) + (cos23 * cos4 * cos5);
456 
457  result.a.x = (cos1 * cos23 * cos5) + (sin1 * sin4 * sin5) - (cos1 * sin23 * cos4 * sin5);
458  result.a.y = (sin1 * cos23 * cos5) + (cos1 * sin4 * sin5) - (sin1 * sin23 * cos4 * sin5);
459  result.a.z = (sin23 * cos5) + (cos23 * cos4 * sin5);
460 
461  return result;
462 }
463 
464 // Checks if the angles for a solution are reachable by the arm
465 // angles[]: The 5 angles to check
466 bool KineCalc::SolutionInRange(const double angles[])
467 {
468  for (int ii = 0; ii < 5; ii++) {
469  if (angles[ii] < jointMin[ii] || angles[ii] > jointMax[ii] || isnan(angles[ii])) {
470  return false;
471  }
472  }
473 
474  return true;
475 }
double jointOffsets[5]
Definition: kinecalc.hpp:112
double CalcSolutionError(const double solution[], const EndEffector &fromPosition)
Definition: kinecalc.cpp:404
void CalculateFK(const double fromJoints[])
Definition: kinecalc.cpp:180
double x
Definition: kinecalc.hpp:31
f
double joints[5]
Definition: kinecalc.hpp:110
bool CalculateIK(const EndEffector &fromPosition)
Definition: kinecalc.cpp:199
void SetO(const KineVector &newO)
Definition: kinecalc.hpp:66
bool SolutionInRange(const double angles[])
Definition: kinecalc.cpp:466
double link1
Definition: kinecalc.hpp:120
void SetJointRange(unsigned int joint, double min, double max)
Definition: kinecalc.cpp:107
void SetOffset(unsigned int joint, double newOffset)
Definition: kinecalc.cpp:102
double link4
Definition: kinecalc.hpp:120
void SetLinkLengths(double newLink1, double newLink2, double newLink3, double newLink4, double newLink5)
Definition: kinecalc.cpp:91
double link2
Definition: kinecalc.hpp:120
void SetTheta(unsigned int index, double newVal)
Definition: kinecalc.cpp:86
double jointMax[5]
Definition: kinecalc.hpp:115
KineVector p
Definition: kinecalc.hpp:38
void SetN(const KineVector &newN)
Definition: kinecalc.hpp:62
double GetTheta(unsigned int index)
Definition: kinecalc.cpp:81
KineVector n
Definition: kinecalc.hpp:39
KineVector o
Definition: kinecalc.hpp:40
KineVector CalculateN(const EndEffector &pose)
Definition: kinecalc.cpp:135
double link5
Definition: kinecalc.hpp:120
double min(double a, double b)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
void SetP(const KineVector &newP)
Definition: kinecalc.hpp:58
double y
Definition: kinecalc.hpp:31
void PrintEndEffector(const EndEffector &endEffector)
Definition: kinecalc.cpp:163
EndEffector endEffector
Definition: kinecalc.hpp:105
double jointMin[5]
Definition: kinecalc.hpp:114
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
EndEffector CalcFKForJoints(const double angles[])
Definition: kinecalc.cpp:426
double z
Definition: kinecalc.hpp:31
void CalcTheta4and5(double angles[], const EndEffector &fromPosition)
Definition: kinecalc.cpp:332
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
int ChooseSolution(const EndEffector &fromPosition, const double solutions[][5])
Definition: kinecalc.cpp:373
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
KineVector a
Definition: kinecalc.hpp:41
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
void SetA(const KineVector &newA)
Definition: kinecalc.hpp:70
double link3
Definition: kinecalc.hpp:120
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
KineCalc(void)
Definition: kinecalc.cpp:27
KineVector Normalise(const KineVector &vector)
Definition: kinecalc.cpp:118


p2os_driver
Author(s): Hunter L. Allen , David Feil-Seifer , Aris Synodinos , Brian Gerkey, Kasper Stoy, Richard Vaughan, Andrew Howard, Tucker Hermans, ActivMedia Robotics LLC, MobileRobots Inc.
autogenerated on Sat Jun 20 2020 03:29:42