EAIK 0.0.1__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/sp.cpp +1 -6
  2. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/CMakeLists.txt +3 -3
  3. eaik-1.0.0/CPP/src/EAIK.cpp +241 -0
  4. eaik-1.0.0/CPP/src/EAIK.h +46 -0
  5. eaik-1.0.0/CPP/src/IK/3R_IK.cpp +150 -0
  6. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/IK/CMakeLists.txt +1 -1
  7. eaik-1.0.0/CPP/src/IK/General_IK.cpp +308 -0
  8. eaik-1.0.0/CPP/src/IK/IKS.h +84 -0
  9. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/IK/Spherical_IK.cpp +20 -29
  10. eaik-1.0.0/CPP/src/IK/utils/kinematic_utils.cpp +64 -0
  11. eaik-1.0.0/CPP/src/IK/utils/kinematic_utils.h +13 -0
  12. eaik-1.0.0/CPP/src/utils/kinematic_remodelling.cpp +165 -0
  13. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/utils/kinematic_remodelling.h +3 -0
  14. eaik-1.0.0/MANIFEST.in +6 -0
  15. eaik-1.0.0/PKG-INFO +801 -0
  16. eaik-1.0.0/README.md +106 -0
  17. {eaik-0.0.1 → eaik-1.0.0}/pyproject.toml +4 -4
  18. eaik-1.0.0/setup.py +22 -0
  19. eaik-1.0.0/src/EAIK.egg-info/PKG-INFO +801 -0
  20. eaik-1.0.0/src/EAIK.egg-info/SOURCES.txt +36 -0
  21. eaik-1.0.0/src/eaik/IK_DH.py +62 -0
  22. eaik-1.0.0/src/eaik/IK_Homogeneous.py +72 -0
  23. eaik-1.0.0/src/eaik/IK_URDF.py +70 -0
  24. eaik-1.0.0/src/eaik/pybindings/eaik_pybindings.cpp +81 -0
  25. eaik-1.0.0/src/eaik/utils/__init__.py +3 -0
  26. eaik-1.0.0/src/eaik/utils/frame_trafo_helpers.py +14 -0
  27. eaik-1.0.0/src/eaik/utils/generate_spherical_wrist.py +199 -0
  28. eaik-1.0.0/src/eaik/utils/remodel_kinematics.py +74 -0
  29. eaik-1.0.0/src/eaik/utils/spatial.py +69 -0
  30. eaik-1.0.0/src/eaik/utils/spherical_wrist_checks.py +127 -0
  31. eaik-0.0.1/MANIFEST.in +0 -1
  32. eaik-0.0.1/PKG-INFO +0 -108
  33. eaik-0.0.1/README.md +0 -89
  34. eaik-0.0.1/external/EAIK/.git +0 -1
  35. eaik-0.0.1/external/EAIK/.gitignore +0 -8
  36. eaik-0.0.1/external/EAIK/.gitmodules +0 -3
  37. eaik-0.0.1/external/EAIK/README.md +0 -2
  38. eaik-0.0.1/external/EAIK/Tests/CMakeLists.txt +0 -24
  39. eaik-0.0.1/external/EAIK/Tests/IK_system_tests.cpp +0 -252
  40. eaik-0.0.1/external/EAIK/Tests/IK_unit_tests.cpp +0 -369
  41. eaik-0.0.1/external/EAIK/external/ik-geo/.git +0 -1
  42. eaik-0.0.1/external/EAIK/external/ik-geo/.gitignore +0 -43
  43. eaik-0.0.1/external/EAIK/external/ik-geo/LICENSE +0 -29
  44. eaik-0.0.1/external/EAIK/external/ik-geo/README.md +0 -60
  45. eaik-0.0.1/external/EAIK/src/EAIK.cpp +0 -50
  46. eaik-0.0.1/external/EAIK/src/EAIK.h +0 -28
  47. eaik-0.0.1/external/EAIK/src/IK/General_IK.cpp +0 -155
  48. eaik-0.0.1/external/EAIK/src/IK/IKS.h +0 -41
  49. eaik-0.0.1/external/EAIK/src/utils/kinematic_remodelling.cpp +0 -105
  50. eaik-0.0.1/setup.py +0 -20
  51. eaik-0.0.1/src/EAIK.egg-info/PKG-INFO +0 -108
  52. eaik-0.0.1/src/EAIK.egg-info/SOURCES.txt +0 -44
  53. eaik-0.0.1/src/eaik/IK_CSV.py +0 -97
  54. eaik-0.0.1/src/eaik/IK_URDF.py +0 -47
  55. eaik-0.0.1/src/eaik/cpp/eaik_pybindings.cpp +0 -56
  56. eaik-0.0.1/src/eaik/examples/evaluate_ik.py +0 -49
  57. eaik-0.0.1/src/eaik/examples/load_urdf.py +0 -52
  58. eaik-0.0.1/src/eaik/examples/robot_csv.py +0 -79
  59. eaik-0.0.1/tests/test_axis_convention_trafo.py +0 -115
  60. eaik-0.0.1/tests/test_sphericalwrist_first_intersection.py +0 -123
  61. eaik-0.0.1/tests/test_sphericalwrist_generation.py +0 -28
  62. eaik-0.0.1/tests/test_sphericalwrist_second_intersection.py +0 -199
  63. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/CMakeLists.txt +0 -0
  64. {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/sp.h +0 -0
  65. {eaik-0.0.1/external/EAIK → eaik-1.0.0}/LICENSE +0 -0
  66. {eaik-0.0.1 → eaik-1.0.0}/setup.cfg +0 -0
  67. {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/dependency_links.txt +0 -0
  68. {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/requires.txt +0 -0
  69. {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/top_level.txt +0 -0
  70. {eaik-0.0.1 → eaik-1.0.0}/src/eaik/__init__.py +0 -0
@@ -1,8 +1,3 @@
1
- //---------------------------------------------------------------//
2
- // Name: sp_1.cpp
3
- // Author: Runbin Chen and Amar Maksumic
4
- // Purpose: Port of the subproblem files functionality
5
- //---------------------------------------------------------------//
6
1
  #include "sp.h"
7
2
  #include <math.h>
8
3
  #include <vector>
@@ -401,7 +396,7 @@ namespace IKS
401
396
  {
402
397
  const Eigen::Vector3d kxp = k.cross(p1);
403
398
  Eigen::Matrix<double, 3, 2> a_1;
404
- if(kxp.isZero(ZERO_THRESH))
399
+ if(kxp.isZero(ZERO_THRESH) || k.cross(p2).isZero(ZERO_THRESH))
405
400
  {
406
401
  // Minimization is independent of theta -> probably redundant!
407
402
  //std::cout<<"Warning! - minimization of subproblem 3 is indipendent of theta. This may indicate redundancy"<<std::endl;
@@ -1,7 +1,7 @@
1
1
  cmake_minimum_required(VERSION 3.9)
2
2
  project(EAIK_Cpp)
3
3
 
4
- add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../src/IK build_IK)
4
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/IK build_IK)
5
5
 
6
6
  if(NOT CMAKE_BUILD_TYPE)
7
7
  set(CMAKE_BUILD_TYPE Release)
@@ -9,8 +9,8 @@ endif()
9
9
  set(CMAKE_CXX_STANDARD 17)
10
10
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
11
11
 
12
- set(sources EAIK.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils/kinematic_remodelling.cpp)
12
+ set(sources EAIK.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils/kinematic_remodelling.cpp ${CMAKE_CURRENT_SOURCE_DIR}/IK/utils/kinematic_utils.cpp)
13
13
 
14
14
  add_library(EAIK ${sources})
15
- target_include_directories(EAIK PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/IK)
15
+ target_include_directories(EAIK PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/IK ${CMAKE_CURRENT_SOURCE_DIR}/IK/utils)
16
16
  target_link_libraries(EAIK EAIK_Kinematics)
@@ -0,0 +1,241 @@
1
+ #include <iostream>
2
+ #include <eigen3/Eigen/Dense>
3
+ #include <thread>
4
+ #include <mutex>
5
+
6
+ #include "kinematic_remodelling.h"
7
+ #include "kinematic_utils.h"
8
+ #include "EAIK.h"
9
+
10
+ namespace EAIK
11
+ {
12
+ Robot::Robot(const Eigen::VectorXd& dh_alpha, const Eigen::VectorXd& dh_a, const Eigen::VectorXd& dh_d, const Eigen::Matrix<double, 3, 3> &R6T, const std::vector<std::pair<int, double>>& fixed_axes, bool is_double_precision)
13
+ {
14
+ const auto&[H, P, R6T_dh] = IKS::dh_to_H_P(dh_alpha, dh_a, dh_d);
15
+ this->R6T = R6T*R6T_dh;
16
+ init(H, P, fixed_axes, is_double_precision);
17
+ }
18
+
19
+ Robot::Robot(const Eigen::MatrixXd &H, const Eigen::MatrixXd &P, const Eigen::Matrix<double, 3, 3> &R6T, const std::vector<std::pair<int, double>>& fixed_axes, bool is_double_precision) : R6T(R6T)
20
+ {
21
+ init(H, P, fixed_axes, is_double_precision);
22
+ }
23
+
24
+ void Robot::init(const Eigen::MatrixXd &H, const Eigen::MatrixXd &P, const std::vector<std::pair<int, double>>& fixed_axes, bool is_double_precision)
25
+ {
26
+ if(is_double_precision)
27
+ {
28
+ ZERO_THRESHOLD = 1e-13;
29
+ AXIS_INTERSECT_THRESHOLD = 1e-9;
30
+ }
31
+
32
+ if(P.cols() != H.cols() + 1)
33
+ {
34
+ throw std::runtime_error("Wrong input dimensions for H and P. Note that #P = #H+1.");
35
+ }
36
+
37
+ Eigen::MatrixXd P_remodelled;
38
+ Eigen::MatrixXd H_remodelled;
39
+
40
+ // Insert fixed axes (e.g., to cope with >6DOF manipulators) into the kinematic chain
41
+ if(fixed_axes.size()>0)
42
+ {
43
+ this->fixed_axes = fixed_axes;
44
+ std::sort(this->fixed_axes.begin(), this->fixed_axes.end(), [](const std::pair<int, double>& a, const std::pair<int, double>& b) {return a.first < b.first;});
45
+
46
+ const auto&[H_part, P_part, R6T_part] = partial_joint_parametrization(H, P, fixed_axes, R6T);
47
+ P_remodelled = remodel_kinematics(H_part, P_part, ZERO_THRESHOLD, AXIS_INTERSECT_THRESHOLD);
48
+ H_remodelled = H_part;
49
+ this->R6T_partial = R6T_part;
50
+ }
51
+ else
52
+ {
53
+ P_remodelled = remodel_kinematics(H, P, ZERO_THRESHOLD, AXIS_INTERSECT_THRESHOLD);
54
+ H_remodelled = H;
55
+ this->R6T_partial = R6T;
56
+ }
57
+ switch (H_remodelled.cols())
58
+ {
59
+ case 6:
60
+ // Check if last three axes intersect
61
+ if (P_remodelled.col(P_remodelled.cols()-3).norm() < ZERO_THRESHOLD && P_remodelled.col(P_remodelled.cols()-2).norm() < ZERO_THRESHOLD)
62
+ {
63
+ spherical_wrist = true;
64
+ bot_kinematics = std::make_unique<IKS::Spherical_Wrist_Robot>(H_remodelled, P_remodelled);
65
+ original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
66
+ }
67
+ else if(P_remodelled.col(1).norm() < ZERO_THRESHOLD && P_remodelled.col(2).norm() < ZERO_THRESHOLD)
68
+ {
69
+ // Spherical wrist is located at the base of the robot
70
+ spherical_wrist = true;
71
+ const auto&[H_reversed, P_reversed] = IKS::reverse_kinematic_chain(H_remodelled, P_remodelled);
72
+ bot_kinematics = std::make_unique<IKS::Spherical_Wrist_Robot>(H_reversed, P_reversed, true);
73
+ original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
74
+ }
75
+ else
76
+ {
77
+ bot_kinematics = std::make_unique<IKS::General_6R>(H_remodelled, P_remodelled);
78
+ original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
79
+ }
80
+ break;
81
+
82
+ case 3:
83
+ bot_kinematics = std::make_unique<IKS::General_3R>(H_remodelled, P_remodelled);
84
+ original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
85
+ break;
86
+ default:
87
+ throw std::runtime_error("Currently, only 6R and 3R Robots are solvable with EAIK.");
88
+ break;
89
+ }
90
+ }
91
+
92
+
93
+ IKS::IK_Solution Robot::calculate_IK(const IKS::Homogeneous_T &ee_position_orientation) const
94
+ {
95
+ IKS::Homogeneous_T ee_06_rot = ee_position_orientation;
96
+ ee_06_rot.block<3,3>(0,0) *= R6T_partial.transpose();
97
+ IKS::IK_Solution solution = bot_kinematics->calculate_IK(ee_06_rot);
98
+
99
+ // TODO: Find alternative to this costly insert operation
100
+ for(const auto&[joint_index, value] : fixed_axes)
101
+ {
102
+ for(auto& Qs : solution.Q)
103
+ {
104
+ Qs.insert(Qs.begin()+joint_index, value);
105
+ }
106
+ }
107
+
108
+ return solution;
109
+ }
110
+
111
+ std::vector<IKS::IK_Solution> Robot::calculate_IK_batched(std::vector<IKS::Homogeneous_T> EE_pose_batch, const unsigned worker_threads) const
112
+ {
113
+ std::vector<IKS::IK_Solution> solutions(EE_pose_batch.size());
114
+ std::vector<std::thread> thread_pool;
115
+ thread_pool.reserve(worker_threads);
116
+
117
+ std::mutex pose_mutex;
118
+
119
+ auto kernel =
120
+ [this, &pose_mutex, &solutions, &EE_pose_batch]{
121
+ pose_mutex.lock();
122
+ int solution_index = EE_pose_batch.size()-1;
123
+
124
+ while(solution_index >= 0)
125
+ {
126
+ const IKS::Homogeneous_T& pose = EE_pose_batch.back();
127
+ EE_pose_batch.pop_back();
128
+ pose_mutex.unlock();
129
+
130
+ solutions.at(solution_index) = calculate_IK(pose);
131
+
132
+ pose_mutex.lock();
133
+ solution_index = EE_pose_batch.size()-1;
134
+ }
135
+ pose_mutex.unlock();
136
+ };
137
+
138
+ for(unsigned i = 0; i < worker_threads; i++)
139
+ {
140
+ thread_pool.push_back(std::thread(kernel));
141
+ }
142
+
143
+ for(unsigned i = 0; i < worker_threads; i++)
144
+ {
145
+ thread_pool.at(i).join();
146
+ }
147
+
148
+ return solutions;
149
+ }
150
+
151
+ // Eigen matrices as solutions for the pybindings
152
+ IKS::IK_Eigen_Solution Robot::calculate_Eigen_IK(const IKS::Homogeneous_T &ee_position_orientation) const
153
+ {
154
+ IKS::IK_Solution vector_solution = calculate_IK(ee_position_orientation);
155
+ IKS::IK_Eigen_Solution eigen_solution;
156
+
157
+ if(vector_solution.Q.size() > 0)
158
+ {
159
+ eigen_solution.is_LS_vec.resize(vector_solution.is_LS_vec.size());
160
+
161
+ // TODO: Find a way to avoid slow loop in future releases
162
+ for(unsigned i = 0; i < vector_solution.is_LS_vec.size(); ++i)
163
+ {
164
+ eigen_solution.is_LS_vec(i) = vector_solution.is_LS_vec.at(i);
165
+ }
166
+
167
+ eigen_solution.Q = Eigen::MatrixXd(vector_solution.Q.size(), vector_solution.Q.at(0).size());
168
+ for (unsigned i = 0; i < vector_solution.Q.size(); i++)
169
+ {
170
+ eigen_solution.Q.row(i) = Eigen::VectorXd::Map(vector_solution.Q.at(i).data(),vector_solution.Q.at(0).size());
171
+ }
172
+ }
173
+ return eigen_solution;
174
+ }
175
+
176
+ std::vector<IKS::IK_Eigen_Solution> Robot::calculate_Eigen_IK_batched(std::vector<IKS::Homogeneous_T> EE_pose_batch, const unsigned worker_threads) const
177
+ {
178
+ std::vector<IKS::IK_Eigen_Solution> solutions(EE_pose_batch.size());
179
+ std::vector<std::thread> thread_pool;
180
+ thread_pool.reserve(worker_threads);
181
+
182
+ std::mutex pose_mutex;
183
+
184
+ auto kernel =
185
+ [this, &pose_mutex, &solutions, &EE_pose_batch]{
186
+ pose_mutex.lock();
187
+ int solution_index = EE_pose_batch.size()-1;
188
+
189
+ while(solution_index >= 0)
190
+ {
191
+ const IKS::Homogeneous_T& pose = EE_pose_batch.back();
192
+ EE_pose_batch.pop_back();
193
+ pose_mutex.unlock();
194
+
195
+ solutions.at(solution_index) = calculate_Eigen_IK(pose);
196
+
197
+ pose_mutex.lock();
198
+ solution_index = EE_pose_batch.size()-1;
199
+ }
200
+ pose_mutex.unlock();
201
+ };
202
+
203
+ for(unsigned i = 0; i < worker_threads; i++)
204
+ {
205
+ thread_pool.push_back(std::thread(kernel));
206
+ }
207
+
208
+ for(unsigned i = 0; i < worker_threads; i++)
209
+ {
210
+ thread_pool.at(i).join();
211
+ }
212
+
213
+ return solutions;
214
+ }
215
+
216
+ IKS::Homogeneous_T Robot::fwdkin(const std::vector<double> &Q) const
217
+ {
218
+ IKS::Homogeneous_T sol_r06 = original_kinematics->fwdkin(Q);
219
+ sol_r06.block<3,3>(0,0) *= R6T;
220
+ return sol_r06;
221
+ }
222
+
223
+ // Function for use with pybindings and the corresponding numpy arrays
224
+ IKS::Homogeneous_T Robot::fwdkin_Eigen(const Eigen::VectorXd &Q) const
225
+ {
226
+ std::vector<double> Q_stdVector(Q.data(), Q.data() + Q.size());
227
+ IKS::Homogeneous_T sol_r06 = original_kinematics->fwdkin(Q_stdVector);
228
+ sol_r06.block<3,3>(0,0) *= R6T;
229
+ return sol_r06;
230
+ }
231
+
232
+ bool Robot::is_spherical() const
233
+ {
234
+ return spherical_wrist;
235
+ }
236
+
237
+ bool Robot::has_known_decomposition() const
238
+ {
239
+ return this->bot_kinematics->has_known_decomposition();
240
+ }
241
+ } // namespace EAIK
@@ -0,0 +1,46 @@
1
+ #ifndef EAIK_IMPL
2
+ #define EAIK_IMPL
3
+
4
+ #include <eigen3/Eigen/Dense>
5
+ #include <memory>
6
+ #include <tuple>
7
+
8
+ #include "IKS.h"
9
+
10
+ namespace EAIK
11
+ {
12
+ class Robot
13
+ {
14
+ public:
15
+ Robot(const Eigen::MatrixXd &H, const Eigen::MatrixXd &P, const Eigen::Matrix<double, 3, 3> &R6T=Eigen::Matrix<double, 3, 3>::Identity(), const std::vector<std::pair<int, double>>& fixed_axes={}, bool is_double_precision=true);
16
+ Robot(const Eigen::VectorXd& dh_alpha, const Eigen::VectorXd& dh_a, const Eigen::VectorXd& dh_d, const Eigen::Matrix<double, 3, 3> &R6T=Eigen::Matrix<double, 3, 3>::Identity(), const std::vector<std::pair<int, double>>& fixed_axes={}, bool is_double_precision=true);
17
+
18
+ IKS::IK_Solution calculate_IK(const IKS::Homogeneous_T &ee_position_orientation) const;
19
+ std::vector<IKS::IK_Solution> calculate_IK_batched(std::vector<IKS::Homogeneous_T> EE_pose_batch, const unsigned worker_threads) const;
20
+
21
+ IKS::IK_Eigen_Solution calculate_Eigen_IK(const IKS::Homogeneous_T &ee_position_orientation) const;
22
+ std::vector<IKS::IK_Eigen_Solution> calculate_Eigen_IK_batched(std::vector<IKS::Homogeneous_T> EE_pose_batch, const unsigned worker_threads) const;
23
+
24
+ IKS::Homogeneous_T fwdkin(const std::vector<double> &Q) const;
25
+ IKS::Homogeneous_T fwdkin_Eigen(const Eigen::VectorXd &Q) const;
26
+
27
+ bool is_spherical() const;
28
+ bool has_known_decomposition() const;
29
+ private:
30
+ // Init function to allow nice constructor overloading
31
+ void init(const Eigen::MatrixXd &H, const Eigen::MatrixXd &P, const std::vector<std::pair<int, double>>& fixed_axes={}, bool is_double_precision=true);
32
+ std::unique_ptr<IKS::General_Robot> bot_kinematics;
33
+ std::unique_ptr<IKS::General_Robot> original_kinematics; // Forward Kinematics calculated by original kinematics
34
+
35
+ bool spherical_wrist{false};
36
+
37
+ // single precision default thresholds
38
+ double ZERO_THRESHOLD = 1e-7;
39
+ double AXIS_INTERSECT_THRESHOLD = 1e-6;
40
+
41
+ Eigen::Matrix<double, 3, 3> R6T;
42
+ Eigen::Matrix<double, 3, 3> R6T_partial;
43
+ std::vector<std::pair<int, double>> fixed_axes; // Locked axes sorted by rising indices (!)
44
+ };
45
+ } // namespace EAIK
46
+ #endif
@@ -0,0 +1,150 @@
1
+ #include <eigen3/Eigen/Dense>
2
+ #include <vector>
3
+ #include <iostream>
4
+ #include <math.h>
5
+
6
+ #include "sp.h"
7
+ #include "IKS.h"
8
+ #include "utils/kinematic_utils.h"
9
+
10
+ namespace IKS
11
+ {
12
+ General_3R::General_3R(const Eigen::Matrix<double, 3, 3> &H, const Eigen::Matrix<double, 3, 4> &P)
13
+ : General_Robot(H,P), H(H), P(P)
14
+ {
15
+ }
16
+
17
+ IK_Solution General_3R::calculate_IK(const Homogeneous_T &ee_position_orientation) const
18
+ {
19
+ IK_Solution solution;
20
+ IK_Solution solution_t_12;
21
+ const Eigen::Vector3d p_0t = ee_position_orientation.block<3, 1>(0, 3);
22
+ const Eigen::Matrix3d r_03 = ee_position_orientation.block<3, 3>(0, 0);
23
+ const Eigen::Vector3d p_13 = p_0t - this->P.col(0) - r_03*this->P.col(3);
24
+
25
+ // Checking for intersecting/parallel Axes
26
+ if (std::fabs(this->H.col(1).cross(this->H.col(2)).transpose() * this->P.col(2)) < ZERO_THRESH && !this->H.col(1).cross(this->H.col(2)).isZero(ZERO_THRESH))
27
+ {
28
+ // (h2 x h3)(p23)==0) -> h2 intersects h3 - make sure they are not parallel!
29
+
30
+ if(this->P.col(1).isZero(ZERO_THRESH) && this->P.col(2).isZero())
31
+ {
32
+ // Spherical-Wrist case with three intersecting axes
33
+ SP4 sp4(this->H.col(0), this->H.col(2), this->H.col(1), this->H.col(0).transpose()*r_03*this->H.col(2));
34
+ sp4.solve();
35
+
36
+ for(const auto& q2 : sp4.get_theta())
37
+ {
38
+ const Eigen::Matrix3d r12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
39
+ SP1 sp1_q1(r_03*this->H.col(2), r12*this->H.col(2), -this->H.col(0));
40
+ sp1_q1.solve();
41
+
42
+ const Eigen::Matrix3d r01 = Eigen::AngleAxisd(sp1_q1.get_theta(), this->H.col(0).normalized()).toRotationMatrix();
43
+ const Eigen::Vector3d hn = create_normal_vector(this->H.col(2));
44
+
45
+ SP1 sp1_q3(hn, r12.transpose()*r01.transpose()*r_03*hn, this->H.col(2));
46
+ sp1_q3.solve();
47
+ solution.Q.push_back({sp1_q1.get_theta(), q2, sp1_q3.get_theta()});
48
+ solution.is_LS_vec.push_back(sp1_q1.solution_is_ls()||sp4.solution_is_ls()||sp1_q3.solution_is_ls());
49
+ }
50
+
51
+ // All angles calculated in this case
52
+ return solution;
53
+ }
54
+ SP1 sp1_q1(this->P.col(1), p_13, this->H.col(0));
55
+ sp1_q1.solve();
56
+
57
+ const double q1 = sp1_q1.get_theta();
58
+ const Eigen::Matrix3d r01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
59
+
60
+ // Solve Theta 2 via orientation kinematics
61
+ SP1 sp1_q2(this->H.col(2),r01.transpose()*r_03*this->H.col(2),this->H.col(1));
62
+ sp1_q2.solve();
63
+ solution_t_12.Q.push_back({q1,sp1_q2.get_theta()});
64
+ solution_t_12.is_LS_vec.push_back(sp1_q1.solution_is_ls()||sp1_q2.solution_is_ls());
65
+ }
66
+ else if (this->H.col(0).cross(this->H.col(1)).norm() < ZERO_THRESH)
67
+ {
68
+ // Axis 1 || Axis 2
69
+ SP3 sp3(this->P.col(2), -this->P.col(1), this->H.col(1), p_13.norm());
70
+ sp3.solve();
71
+
72
+ const std::vector<double> &theta_2 = sp3.get_theta();
73
+
74
+ for (const auto &q2 : theta_2)
75
+ {
76
+ const Eigen::Matrix3d r12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
77
+ SP1 sp1(p_13, this->P.col(1)+r12*this->P.col(2), -this->H.col(0));
78
+ sp1.solve();
79
+
80
+ solution_t_12.Q.push_back({sp1.get_theta(), q2});
81
+ solution_t_12.is_LS_vec.push_back(sp3.solution_is_ls()||sp1.solution_is_ls());
82
+ }
83
+ }
84
+ else if (std::fabs(this->H.col(0).cross(this->H.col(1)).transpose() * this->P.col(1)) < ZERO_THRESH)
85
+ {
86
+ // (h1 x h2)(p12)==0) -> h1 intersects h2
87
+ SP2 sp2(p_13, this->P.col(2), -this->H.col(0), this->H.col(1));
88
+ sp2.solve();
89
+
90
+ for(unsigned i = 0; i < sp2.get_theta_1().size(); i++)
91
+ {
92
+ const double q1 = sp2.get_theta_1().at(i);
93
+ const double q2 = sp2.get_theta_2().at(i);
94
+ solution_t_12.Q.push_back({q1, q2});
95
+ solution_t_12.is_LS_vec.push_back(sp2.solution_is_ls());
96
+ }
97
+ }
98
+ else
99
+ {
100
+ double d = this->H.col(0).transpose()*(p_13-this->P.col(1));
101
+ SP4 sp4(this->H.col(0), this->P.col(2), this->H.col(1), d);
102
+ sp4.solve();
103
+
104
+ const std::vector<double> &theta_2 = sp4.get_theta();
105
+
106
+ for (const auto &q2 : theta_2)
107
+ {
108
+ const Eigen::Matrix3d r12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
109
+ SP1 sp1(p_13, this->P.col(1)+r12*this->P.col(2), -this->H.col(0));
110
+ sp1.solve();
111
+
112
+ solution_t_12.Q.push_back({sp1.get_theta(), q2});
113
+ solution_t_12.is_LS_vec.push_back(sp4.solution_is_ls()||sp1.solution_is_ls());
114
+ }
115
+ }
116
+
117
+ for(unsigned i = 0; i < solution_t_12.Q.size(); i++)
118
+ {
119
+ const double q1 = solution_t_12.Q.at(i).at(0);
120
+ const double q2 = solution_t_12.Q.at(i).at(1);
121
+
122
+ const Eigen::Matrix3d r12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
123
+ const Eigen::Matrix3d r01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
124
+
125
+ // hn must not be collinear to H3!
126
+ const Eigen::Vector3d hn = create_normal_vector(this->H.col(2));
127
+
128
+ SP1 sp1(hn, r12.transpose()*r01.transpose()*r_03*hn, this->H.col(2));
129
+ sp1.solve();
130
+ solution.Q.push_back({q1, q2, sp1.get_theta()});
131
+ solution.is_LS_vec.push_back(solution_t_12.is_LS_vec.at(i)|sp1.solution_is_ls());
132
+ }
133
+
134
+ // Finding 6DOF Problem for 3R is overconstrained -> "Throw away" extraneous orientation solutions
135
+ for(unsigned i = 0; i < solution.Q.size(); i++)
136
+ {
137
+ if(!solution.is_LS_vec.at(i))
138
+ {
139
+ IKS::Homogeneous_T result = fwdkin(solution.Q.at(i));
140
+ double error = (result - ee_position_orientation).norm();
141
+
142
+ if(error > ZERO_THRESH)
143
+ {
144
+ solution.is_LS_vec.at(i) = true;
145
+ }
146
+ }
147
+ }
148
+ return solution;
149
+ }
150
+ };
@@ -9,7 +9,7 @@ endif()
9
9
  set(CMAKE_CXX_STANDARD 17)
10
10
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
11
11
 
12
- set(sources Spherical_IK.cpp General_IK.cpp)
12
+ set(sources Spherical_IK.cpp General_IK.cpp 3R_IK.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils/kinematic_utils.cpp)
13
13
 
14
14
  add_library(EAIK_Kinematics ${sources})
15
15
  target_include_directories(EAIK_Kinematics PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../external/ik-geo/cpp/subproblems)