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.
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/sp.cpp +1 -6
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/CMakeLists.txt +3 -3
- eaik-1.0.0/CPP/src/EAIK.cpp +241 -0
- eaik-1.0.0/CPP/src/EAIK.h +46 -0
- eaik-1.0.0/CPP/src/IK/3R_IK.cpp +150 -0
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/IK/CMakeLists.txt +1 -1
- eaik-1.0.0/CPP/src/IK/General_IK.cpp +308 -0
- eaik-1.0.0/CPP/src/IK/IKS.h +84 -0
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/IK/Spherical_IK.cpp +20 -29
- eaik-1.0.0/CPP/src/IK/utils/kinematic_utils.cpp +64 -0
- eaik-1.0.0/CPP/src/IK/utils/kinematic_utils.h +13 -0
- eaik-1.0.0/CPP/src/utils/kinematic_remodelling.cpp +165 -0
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/src/utils/kinematic_remodelling.h +3 -0
- eaik-1.0.0/MANIFEST.in +6 -0
- eaik-1.0.0/PKG-INFO +801 -0
- eaik-1.0.0/README.md +106 -0
- {eaik-0.0.1 → eaik-1.0.0}/pyproject.toml +4 -4
- eaik-1.0.0/setup.py +22 -0
- eaik-1.0.0/src/EAIK.egg-info/PKG-INFO +801 -0
- eaik-1.0.0/src/EAIK.egg-info/SOURCES.txt +36 -0
- eaik-1.0.0/src/eaik/IK_DH.py +62 -0
- eaik-1.0.0/src/eaik/IK_Homogeneous.py +72 -0
- eaik-1.0.0/src/eaik/IK_URDF.py +70 -0
- eaik-1.0.0/src/eaik/pybindings/eaik_pybindings.cpp +81 -0
- eaik-1.0.0/src/eaik/utils/__init__.py +3 -0
- eaik-1.0.0/src/eaik/utils/frame_trafo_helpers.py +14 -0
- eaik-1.0.0/src/eaik/utils/generate_spherical_wrist.py +199 -0
- eaik-1.0.0/src/eaik/utils/remodel_kinematics.py +74 -0
- eaik-1.0.0/src/eaik/utils/spatial.py +69 -0
- eaik-1.0.0/src/eaik/utils/spherical_wrist_checks.py +127 -0
- eaik-0.0.1/MANIFEST.in +0 -1
- eaik-0.0.1/PKG-INFO +0 -108
- eaik-0.0.1/README.md +0 -89
- eaik-0.0.1/external/EAIK/.git +0 -1
- eaik-0.0.1/external/EAIK/.gitignore +0 -8
- eaik-0.0.1/external/EAIK/.gitmodules +0 -3
- eaik-0.0.1/external/EAIK/README.md +0 -2
- eaik-0.0.1/external/EAIK/Tests/CMakeLists.txt +0 -24
- eaik-0.0.1/external/EAIK/Tests/IK_system_tests.cpp +0 -252
- eaik-0.0.1/external/EAIK/Tests/IK_unit_tests.cpp +0 -369
- eaik-0.0.1/external/EAIK/external/ik-geo/.git +0 -1
- eaik-0.0.1/external/EAIK/external/ik-geo/.gitignore +0 -43
- eaik-0.0.1/external/EAIK/external/ik-geo/LICENSE +0 -29
- eaik-0.0.1/external/EAIK/external/ik-geo/README.md +0 -60
- eaik-0.0.1/external/EAIK/src/EAIK.cpp +0 -50
- eaik-0.0.1/external/EAIK/src/EAIK.h +0 -28
- eaik-0.0.1/external/EAIK/src/IK/General_IK.cpp +0 -155
- eaik-0.0.1/external/EAIK/src/IK/IKS.h +0 -41
- eaik-0.0.1/external/EAIK/src/utils/kinematic_remodelling.cpp +0 -105
- eaik-0.0.1/setup.py +0 -20
- eaik-0.0.1/src/EAIK.egg-info/PKG-INFO +0 -108
- eaik-0.0.1/src/EAIK.egg-info/SOURCES.txt +0 -44
- eaik-0.0.1/src/eaik/IK_CSV.py +0 -97
- eaik-0.0.1/src/eaik/IK_URDF.py +0 -47
- eaik-0.0.1/src/eaik/cpp/eaik_pybindings.cpp +0 -56
- eaik-0.0.1/src/eaik/examples/evaluate_ik.py +0 -49
- eaik-0.0.1/src/eaik/examples/load_urdf.py +0 -52
- eaik-0.0.1/src/eaik/examples/robot_csv.py +0 -79
- eaik-0.0.1/tests/test_axis_convention_trafo.py +0 -115
- eaik-0.0.1/tests/test_sphericalwrist_first_intersection.py +0 -123
- eaik-0.0.1/tests/test_sphericalwrist_generation.py +0 -28
- eaik-0.0.1/tests/test_sphericalwrist_second_intersection.py +0 -199
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/CMakeLists.txt +0 -0
- {eaik-0.0.1/external/EAIK → eaik-1.0.0/CPP}/external/ik-geo/cpp/subproblems/sp.h +0 -0
- {eaik-0.0.1/external/EAIK → eaik-1.0.0}/LICENSE +0 -0
- {eaik-0.0.1 → eaik-1.0.0}/setup.cfg +0 -0
- {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/dependency_links.txt +0 -0
- {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/requires.txt +0 -0
- {eaik-0.0.1 → eaik-1.0.0}/src/EAIK.egg-info/top_level.txt +0 -0
- {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}
|
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)
|