EAIK 1.1.0__tar.gz → 1.2.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-1.1.0 → eaik-1.2.0}/CPP/external/ik-geo/cpp/subproblems/sp.cpp +5 -5
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/EAIK.cpp +19 -4
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/EAIK.h +1 -1
- eaik-1.2.0/CPP/src/IK/1R_IK.cpp +48 -0
- eaik-1.2.0/CPP/src/IK/2R_IK.cpp +89 -0
- eaik-1.2.0/CPP/src/IK/4R_IK.cpp +391 -0
- eaik-1.2.0/CPP/src/IK/5R_IK.cpp +714 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/IK/6R_IK.cpp +63 -2
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/IK/CMakeLists.txt +1 -1
- eaik-1.2.0/CPP/src/IK/IKS.h +218 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/IK/utils/kinematic_utils.h +1 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/utils/kinematic_remodeling.cpp +20 -20
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/utils/kinematic_remodeling.h +1 -1
- eaik-1.2.0/LICENSE +28 -0
- eaik-1.2.0/PKG-INFO +155 -0
- eaik-1.2.0/README.md +132 -0
- {eaik-1.1.0 → eaik-1.2.0}/pyproject.toml +6 -4
- {eaik-1.1.0 → eaik-1.2.0}/setup.py +5 -2
- eaik-1.2.0/src/EAIK.egg-info/PKG-INFO +155 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/EAIK.egg-info/SOURCES.txt +6 -0
- eaik-1.2.0/src/eaik/IK_HP.py +24 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/IK_Robot.py +10 -10
- eaik-1.2.0/src/eaik/pybindings/__init__.py +3 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/pybindings/eaik_pybindings.cpp +5 -5
- eaik-1.1.0/CPP/src/IK/IKS.h +0 -101
- eaik-1.1.0/LICENSE +0 -674
- eaik-1.1.0/PKG-INFO +0 -811
- eaik-1.1.0/README.md +0 -116
- eaik-1.1.0/src/EAIK.egg-info/PKG-INFO +0 -811
- {eaik-1.1.0 → eaik-1.2.0}/CPP/external/ik-geo/cpp/subproblems/CMakeLists.txt +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/external/ik-geo/cpp/subproblems/sp.h +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/CMakeLists.txt +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/IK/3R_IK.cpp +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/CPP/src/IK/utils/kinematic_utils.cpp +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/MANIFEST.in +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/setup.cfg +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/EAIK.egg-info/dependency_links.txt +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/EAIK.egg-info/requires.txt +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/EAIK.egg-info/top_level.txt +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/IK_DH.py +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/IK_Homogeneous.py +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/IK_URDF.py +0 -0
- {eaik-1.1.0 → eaik-1.2.0}/src/eaik/__init__.py +0 -0
@@ -546,7 +546,7 @@ namespace IKS
|
|
546
546
|
|
547
547
|
void SP5::solve()
|
548
548
|
{
|
549
|
-
const double EPSILON =
|
549
|
+
const double EPSILON = 1e-6; // Should this be different?
|
550
550
|
std::vector<double> theta;
|
551
551
|
theta.reserve(8);
|
552
552
|
|
@@ -646,8 +646,8 @@ namespace IKS
|
|
646
646
|
Eigen::Vector3d v1 = a_1 * sc_1 + p1_s;
|
647
647
|
Eigen::Vector3d v3 = a_3 * sc_3 + p3_s;
|
648
648
|
|
649
|
-
const double norm_equation_error = std::fabs(
|
650
|
-
if (norm_equation_error <
|
649
|
+
const double norm_equation_error = std::fabs(v1.norm() - v3.norm());
|
650
|
+
if (norm_equation_error < 1e-3)
|
651
651
|
{
|
652
652
|
SP1 sp(v3, v1, k2);
|
653
653
|
sp.solve();
|
@@ -675,8 +675,7 @@ namespace IKS
|
|
675
675
|
|
676
676
|
theta_2.push_back(sp.get_theta());
|
677
677
|
}
|
678
|
-
|
679
|
-
else if (theta_1.size()==0)
|
678
|
+
else
|
680
679
|
{
|
681
680
|
SP1 sp(v3, v1, k2);
|
682
681
|
sp.solve();
|
@@ -698,6 +697,7 @@ namespace IKS
|
|
698
697
|
approx_t2 = sp.get_theta();
|
699
698
|
|
700
699
|
norm_errors_angles.push_back({norm_equation_error, approx_t1, approx_t2, approx_t3});
|
700
|
+
_solution_is_ls = true;
|
701
701
|
}
|
702
702
|
}
|
703
703
|
}
|
@@ -60,13 +60,28 @@ namespace EAIK
|
|
60
60
|
bot_kinematics = std::make_unique<IKS::General_6R>(H_remodeled, P_remodeled);
|
61
61
|
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
62
62
|
break;
|
63
|
-
|
63
|
+
case 5:
|
64
|
+
bot_kinematics = std::make_unique<IKS::General_5R>(H_remodeled, P_remodeled);
|
65
|
+
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
66
|
+
break;
|
67
|
+
case 4:
|
68
|
+
bot_kinematics = std::make_unique<IKS::General_4R>(H_remodeled, P_remodeled);
|
69
|
+
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
70
|
+
break;
|
64
71
|
case 3:
|
65
|
-
|
66
|
-
|
72
|
+
bot_kinematics = std::make_unique<IKS::General_3R>(H_remodeled, P_remodeled);
|
73
|
+
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
74
|
+
break;
|
75
|
+
case 2:
|
76
|
+
bot_kinematics = std::make_unique<IKS::General_2R>(H_remodeled, P_remodeled);
|
77
|
+
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
78
|
+
break;
|
79
|
+
case 1:
|
80
|
+
bot_kinematics = std::make_unique<IKS::General_1R>(H_remodeled, P_remodeled);
|
81
|
+
original_kinematics = std::make_unique<IKS::General_Robot>(H, P);
|
67
82
|
break;
|
68
83
|
default:
|
69
|
-
throw std::runtime_error("Currently, only 6R
|
84
|
+
throw std::runtime_error("Currently, only 1-6R robots are solvable with EAIK. Consider locking redundant joints.");
|
70
85
|
break;
|
71
86
|
}
|
72
87
|
}
|
@@ -34,7 +34,7 @@ namespace EAIK
|
|
34
34
|
Eigen::MatrixXd get_original_P() const;
|
35
35
|
|
36
36
|
std::string get_kinematic_family() const;
|
37
|
-
|
37
|
+
|
38
38
|
private:
|
39
39
|
// Init function to allow nice constructor overloading
|
40
40
|
void init(const Eigen::MatrixXd &H, const Eigen::MatrixXd &P, const std::vector<std::pair<int, double>>& fixed_axes={}, bool is_double_precision=true);
|
@@ -0,0 +1,48 @@
|
|
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_1R::General_1R(const Eigen::Matrix<double, 3, 1> &H, const Eigen::Matrix<double, 3, 2> &P)
|
13
|
+
: General_Robot(H,P), H(H), P(P)
|
14
|
+
{
|
15
|
+
}
|
16
|
+
|
17
|
+
IK_Solution General_1R::calculate_IK(const Homogeneous_T &ee_position_orientation) const
|
18
|
+
{
|
19
|
+
IK_Solution solution = calculate_position_IK(ee_position_orientation.block<3, 1>(0, 3));
|
20
|
+
|
21
|
+
// 6DOF Problem for 1R is overconstrained -> "Throw away" extraneous orientation solutions
|
22
|
+
return enforce_solution_consistency(solution, ee_position_orientation);
|
23
|
+
}
|
24
|
+
|
25
|
+
IK_Solution General_1R::calculate_position_IK(const Eigen::Vector3d &ee_position) const
|
26
|
+
{
|
27
|
+
IK_Solution sol;
|
28
|
+
const Eigen::Vector3d p_1t = ee_position - this->P.col(0);
|
29
|
+
SP1 sp1(this->P.col(1), p_1t, this->H.col(0));
|
30
|
+
sp1.solve();
|
31
|
+
sol.Q.push_back({sp1.get_theta()});
|
32
|
+
sol.is_LS_vec.push_back(sp1.solution_is_ls());
|
33
|
+
|
34
|
+
return sol;
|
35
|
+
}
|
36
|
+
|
37
|
+
IK_Solution General_1R::calculate_orientation_IK(const Eigen::Matrix3d &ee_orientation) const
|
38
|
+
{
|
39
|
+
IK_Solution sol;
|
40
|
+
const Eigen::Vector3d h_n = create_normal_vector(this->H.col(0));
|
41
|
+
SP1 sp1(h_n, ee_orientation*h_n, this->H.col(0));
|
42
|
+
sp1.solve();
|
43
|
+
sol.Q.push_back({sp1.get_theta()});
|
44
|
+
sol.is_LS_vec.push_back(sp1.solution_is_ls());
|
45
|
+
|
46
|
+
return sol;
|
47
|
+
}
|
48
|
+
};
|
@@ -0,0 +1,89 @@
|
|
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
|
+
#include "kinematic_remodeling.h"
|
10
|
+
|
11
|
+
namespace IKS
|
12
|
+
{
|
13
|
+
General_2R::General_2R(const Eigen::Matrix<double, 3, 2> &H, const Eigen::Matrix<double, 3, 3> &P)
|
14
|
+
: General_Robot(H, P), H(H), P(P)
|
15
|
+
{
|
16
|
+
}
|
17
|
+
|
18
|
+
IK_Solution General_2R::calculate_IK(const Homogeneous_T &ee_position_orientation) const
|
19
|
+
{
|
20
|
+
IK_Solution solution = calculate_position_IK(ee_position_orientation.block<3, 1>(0, 3));
|
21
|
+
|
22
|
+
// 6DOF Problem for 2R is overconstrained -> "Throw away" extraneous orientation solutions
|
23
|
+
return enforce_solution_consistency(solution, ee_position_orientation);
|
24
|
+
}
|
25
|
+
|
26
|
+
IK_Solution General_2R::calculate_position_IK(const Eigen::Vector3d &ee_position) const
|
27
|
+
{
|
28
|
+
IK_Solution solution;
|
29
|
+
const Eigen::Vector3d p_1ee = ee_position - this->P.col(0);
|
30
|
+
|
31
|
+
if (EAIK::do_axes_intersect(this->H.col(0), this->H.col(1), this->P.col(1), ZERO_THRESH, ZERO_THRESH))
|
32
|
+
{
|
33
|
+
// (h1 x h2)(p12)==0) -> h1 intersects h2
|
34
|
+
SP2 sp2(p_1ee, this->P.col(2), -this->H.col(0), this->H.col(1));
|
35
|
+
sp2.solve();
|
36
|
+
const std::vector<double>& theta_1 = sp2.get_theta_1();
|
37
|
+
const std::vector<double>& theta_2 = sp2.get_theta_2();
|
38
|
+
|
39
|
+
for(unsigned i = 0; i < theta_1.size(); i++)
|
40
|
+
{
|
41
|
+
solution.Q.push_back({theta_1.at(i), theta_2.at(i)});
|
42
|
+
solution.is_LS_vec.push_back(sp2.solution_is_ls());
|
43
|
+
}
|
44
|
+
}
|
45
|
+
else
|
46
|
+
{
|
47
|
+
SP3 sp3(this->P.col(2), -this->P.col(1), this->H.col(1), p_1ee.norm());
|
48
|
+
sp3.solve();
|
49
|
+
|
50
|
+
for (const auto &q2 : sp3.get_theta())
|
51
|
+
{
|
52
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
|
53
|
+
SP1 sp1(this->P.col(1) + r_12 * this->P.col(2), p_1ee, this->H.col(0));
|
54
|
+
sp1.solve();
|
55
|
+
solution.Q.push_back({sp1.get_theta(), q2});
|
56
|
+
solution.is_LS_vec.push_back(sp1.solution_is_ls() || sp3.solution_is_ls());
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
return enforce_solution_consistency(solution, ee_position);
|
61
|
+
}
|
62
|
+
|
63
|
+
IK_Solution General_2R::calculate_orientation_IK(const Eigen::Matrix3d &ee_orientation) const
|
64
|
+
{
|
65
|
+
IK_Solution solution;
|
66
|
+
if (this->H.col(0).cross(this->H.col(1)).norm() > ZERO_THRESH)
|
67
|
+
{
|
68
|
+
const Eigen::Vector3d h_n = this->H.col(0).cross(this->H.col(1));
|
69
|
+
SP2 sp2(ee_orientation*h_n, h_n, -this->H.col(0), this->H.col(1));
|
70
|
+
sp2.solve();
|
71
|
+
|
72
|
+
const std::vector<double> &theta_1 = sp2.get_theta_1();
|
73
|
+
const std::vector<double> &theta_2 = sp2.get_theta_2();
|
74
|
+
|
75
|
+
for (unsigned i = 0; i < theta_1.size(); i++)
|
76
|
+
{
|
77
|
+
solution.Q.push_back({theta_1.at(i), theta_2.at(i)});
|
78
|
+
solution.is_LS_vec.push_back(sp2.solution_is_ls());
|
79
|
+
}
|
80
|
+
}
|
81
|
+
else
|
82
|
+
{
|
83
|
+
// Implicit redundancy
|
84
|
+
throw new std::runtime_error("Can not calculate orientation IK for implicitly redundant manipulator");
|
85
|
+
}
|
86
|
+
|
87
|
+
return enforce_solution_consistency(solution, ee_orientation);
|
88
|
+
}
|
89
|
+
};
|
@@ -0,0 +1,391 @@
|
|
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
|
+
#include "kinematic_remodeling.h"
|
10
|
+
|
11
|
+
namespace IKS
|
12
|
+
{
|
13
|
+
General_4R::General_4R(const Eigen::Matrix<double, 3, 4> &H, const Eigen::Matrix<double, 3, 5> &P)
|
14
|
+
: General_Robot(H,P), H(H), P(P)
|
15
|
+
{
|
16
|
+
kinematicClass = determine_Kinematic_Class();
|
17
|
+
}
|
18
|
+
|
19
|
+
General_4R::KinematicClass General_4R::determine_Kinematic_Class()
|
20
|
+
{
|
21
|
+
if (this->H.col(0).cross(this->H.col(1)).norm() >= ZERO_THRESH &&
|
22
|
+
std::fabs(this->H.col(0).cross(this->H.col(1)).transpose() * this->P.col(1)) < ZERO_THRESH)
|
23
|
+
{
|
24
|
+
// (h1 x h2)(p12)==0) -> h1 intersects h2
|
25
|
+
// And 1 not parallel to 2 (h1 x h2 =/= 0)
|
26
|
+
const Eigen::Vector3d intersection = EAIK::calc_intersection(H.col(0), H.col(1), P.col(0), P.col(1), ZERO_THRESH);
|
27
|
+
|
28
|
+
if(EAIK::is_point_on_Axis(H.col(2), P.col(0)+P.col(1)+P.col(2), intersection, ZERO_THRESH))
|
29
|
+
{
|
30
|
+
const auto&[H_reversed, P_reversed] = reverse_kinematic_chain(this->H, this->P);
|
31
|
+
const Eigen::MatrixXd P_reversed_remodeled = EAIK::remodel_kinematics(H_reversed, P_reversed, ZERO_THRESH, ZERO_THRESH);
|
32
|
+
|
33
|
+
this->reversed_Robot_ptr = std::make_unique<General_4R>(H_reversed, P_reversed_remodeled);
|
34
|
+
// Spherical Wrist at the base of the robot
|
35
|
+
return KinematicClass::REVERSED;
|
36
|
+
}
|
37
|
+
else if(this->H.col(2).cross(this->H.col(3)).norm() >= ZERO_THRESH &&
|
38
|
+
std::fabs(this->H.col(2).cross(this->H.col(3)).transpose() * this->P.col(3)) < ZERO_THRESH)
|
39
|
+
{
|
40
|
+
// (h3 x h4)(p34)==0) -> h3 intersects h4
|
41
|
+
// And 3 not parallel to 4 (h3 x h4 =/= 0)
|
42
|
+
return KinematicClass::FIRST_TWO_LAST_TWO_INTERSECTING;
|
43
|
+
}
|
44
|
+
|
45
|
+
// Same as if h3 intersects with h4 -> Use reversed kinematics
|
46
|
+
const auto&[H_reversed, P_reversed] = reverse_kinematic_chain(this->H, this->P);
|
47
|
+
const Eigen::MatrixXd P_reversed_remodeled = EAIK::remodel_kinematics(H_reversed, P_reversed, ZERO_THRESH, ZERO_THRESH);
|
48
|
+
|
49
|
+
this->reversed_Robot_ptr = std::make_unique<General_4R>(H_reversed, P_reversed_remodeled);
|
50
|
+
return KinematicClass::REVERSED;
|
51
|
+
}
|
52
|
+
|
53
|
+
// Spherical wrist at end of manipulator
|
54
|
+
if (this->H.col(1).cross(this->H.col(2)).norm() >= ZERO_THRESH &&
|
55
|
+
std::fabs(this->H.col(1).cross(this->H.col(2)).transpose() * this->P.col(2)) < ZERO_THRESH)
|
56
|
+
{
|
57
|
+
const Eigen::Vector3d p02 = P.block<3,2>(0,0).rowwise().sum();
|
58
|
+
const Eigen::Vector3d intersection = EAIK::calc_intersection(H.col(1), H.col(2), p02,P.col(2), ZERO_THRESH);
|
59
|
+
|
60
|
+
if(EAIK::is_point_on_Axis(H.col(3), p02+P.col(2)+P.col(3), intersection, ZERO_THRESH))
|
61
|
+
{
|
62
|
+
return KinematicClass::SPHERICAL_WRIST;
|
63
|
+
}
|
64
|
+
|
65
|
+
return KinematicClass::SECOND_THIRD_INTERSECTING;
|
66
|
+
}
|
67
|
+
|
68
|
+
if(this->H.col(2).cross(this->H.col(3)).norm() >= ZERO_THRESH &&
|
69
|
+
std::fabs(this->H.col(2).cross(this->H.col(3)).transpose() * this->P.col(3)) < ZERO_THRESH)
|
70
|
+
{
|
71
|
+
// (h3 x h4)(p34)==0) -> h3 intersects h4
|
72
|
+
// And 3 not parallel to 4 (h3 x h4 =/= 0)
|
73
|
+
return KinematicClass::THIRD_FOURTH_INTERSECTING;
|
74
|
+
}
|
75
|
+
|
76
|
+
if (this->H.col(0).cross(this->H.col(1)).norm() > ZERO_THRESH)
|
77
|
+
{
|
78
|
+
// h1 =/= h2
|
79
|
+
if (this->H.col(1).cross(this->H.col(2)).norm() > ZERO_THRESH)
|
80
|
+
{
|
81
|
+
// h2 =/= h3
|
82
|
+
if (this->H.col(2).cross(this->H.col(3)).norm() < ZERO_THRESH)
|
83
|
+
{
|
84
|
+
// h3 == h4
|
85
|
+
const auto&[H_reversed, P_reversed] = reverse_kinematic_chain(this->H, this->P);
|
86
|
+
const Eigen::MatrixXd P_reversed_remodeled = EAIK::remodel_kinematics(H_reversed, P_reversed, ZERO_THRESH, ZERO_THRESH);
|
87
|
+
|
88
|
+
this->reversed_Robot_ptr = std::make_unique<General_4R>(H_reversed, P_reversed_remodeled);
|
89
|
+
return KinematicClass::REVERSED;
|
90
|
+
}
|
91
|
+
return KinematicClass::NONE_PARALLEL_NONE_INTERSECTING;
|
92
|
+
}
|
93
|
+
// h2 == h3
|
94
|
+
return KinematicClass::SECOND_THIRD_PARALLEL;
|
95
|
+
}
|
96
|
+
else if(this->H.col(1).cross(this->H.col(2)).norm() > ZERO_THRESH)
|
97
|
+
{
|
98
|
+
// h1 == h2 , h2 =/= h3
|
99
|
+
return KinematicClass::FIRST_SECOND_PARALLEL;
|
100
|
+
}
|
101
|
+
else
|
102
|
+
{
|
103
|
+
// h1 == h2 , h2 == h3 -> h3 =/= h4 for non-redundant manipulator -> reverse
|
104
|
+
const auto&[H_reversed, P_reversed] = reverse_kinematic_chain(this->H, this->P);
|
105
|
+
const Eigen::MatrixXd P_reversed_remodeled = EAIK::remodel_kinematics(H_reversed, P_reversed, ZERO_THRESH, ZERO_THRESH);
|
106
|
+
|
107
|
+
this->reversed_Robot_ptr = std::make_unique<General_4R>(H_reversed, P_reversed_remodeled);
|
108
|
+
return KinematicClass::REVERSED;
|
109
|
+
}
|
110
|
+
|
111
|
+
return KinematicClass::UNKNOWN;
|
112
|
+
}
|
113
|
+
|
114
|
+
IK_Solution General_4R::calculate_IK(const Homogeneous_T &ee_position_orientation) const
|
115
|
+
{
|
116
|
+
IK_Solution solution;
|
117
|
+
const Eigen::Vector3d p_0t = ee_position_orientation.block<3, 1>(0, 3);
|
118
|
+
const Eigen::Matrix3d r_04 = ee_position_orientation.block<3, 3>(0, 0);
|
119
|
+
const Eigen::Vector3d p_14 = p_0t - this->P.col(0) - r_04*this->P.col(4);
|
120
|
+
|
121
|
+
switch(this->kinematicClass)
|
122
|
+
{
|
123
|
+
case KinematicClass::THIRD_FOURTH_INTERSECTING:
|
124
|
+
{
|
125
|
+
// (h3 x h4)(p34)==0) -> h3 intersects h4
|
126
|
+
// And 3 not parallel to 4 (h3 x h4 =/= 0)
|
127
|
+
SP3 sp3_q1(p_14, this->P.col(1), -this->H.col(0), this->P.col(2).norm());
|
128
|
+
sp3_q1.solve();
|
129
|
+
|
130
|
+
for(const auto& q1 : sp3_q1.get_theta())
|
131
|
+
{
|
132
|
+
const Eigen::Matrix3d r_10 = Eigen::AngleAxisd(q1, -this->H.col(0).normalized()).toRotationMatrix();
|
133
|
+
SP3 sp3_q2(this->P.col(2), -this->P.col(1), this->H.col(1), p_14.norm());
|
134
|
+
sp3_q2.solve();
|
135
|
+
|
136
|
+
for(const auto& q2 : sp3_q2.get_theta())
|
137
|
+
{
|
138
|
+
const Eigen::Matrix3d r_21 = Eigen::AngleAxisd(q2, -this->H.col(1).normalized()).toRotationMatrix();
|
139
|
+
|
140
|
+
const Eigen::Vector3d hn = create_normal_vector(this->H.col(2));
|
141
|
+
SP2 sp2(r_21*r_10*r_04*hn, hn, -this->H.col(2), this->H.col(3));
|
142
|
+
sp2.solve();
|
143
|
+
|
144
|
+
const std::vector<double>& theta_3 = sp2.get_theta_1();
|
145
|
+
const std::vector<double>& theta_4 = sp2.get_theta_2();
|
146
|
+
|
147
|
+
for(unsigned i = 0; i < theta_3.size(); ++i)
|
148
|
+
{
|
149
|
+
solution.Q.push_back({q1, q2, theta_3.at(i), theta_4.at(i)});
|
150
|
+
solution.is_LS_vec.push_back(sp3_q1.solution_is_ls() || sp3_q2.solution_is_ls() || sp2.solution_is_ls());
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
break;
|
155
|
+
};
|
156
|
+
case KinematicClass::SECOND_THIRD_INTERSECTING:
|
157
|
+
{
|
158
|
+
SP3 sp3(this->P.col(1), p_14, this->H.col(0), this->P.col(3).norm());
|
159
|
+
sp3.solve();
|
160
|
+
|
161
|
+
for(const auto& q1 : sp3.get_theta())
|
162
|
+
{
|
163
|
+
const Eigen::Matrix3d r_10 = Eigen::AngleAxisd(q1, -this->H.col(0).normalized()).toRotationMatrix();
|
164
|
+
SP2 sp2(r_10*p_14 - this->P.col(1), this->P.col(3), -this->H.col(1), this->H.col(2));
|
165
|
+
sp2.solve();
|
166
|
+
|
167
|
+
const std::vector<double>& theta_2 = sp2.get_theta_1();
|
168
|
+
const std::vector<double>& theta_3 = sp2.get_theta_2();
|
169
|
+
|
170
|
+
const Eigen::Vector3d h_n = create_normal_vector(this->H.col(3));
|
171
|
+
for(unsigned i = 0; i < theta_2.size(); ++i)
|
172
|
+
{
|
173
|
+
const double& q2 = theta_2.at(i);
|
174
|
+
const double& q3 = theta_3.at(i);
|
175
|
+
|
176
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
|
177
|
+
const Eigen::Matrix3d r_23 = Eigen::AngleAxisd(q3, this->H.col(2).normalized()).toRotationMatrix();
|
178
|
+
|
179
|
+
SP1 sp1(h_n, r_04.transpose()*r_10.transpose()*r_12*r_23*h_n, -this->H.col(3));
|
180
|
+
sp1.solve();
|
181
|
+
|
182
|
+
solution.Q.push_back({q1, q2, q3, sp1.get_theta()});
|
183
|
+
solution.is_LS_vec.push_back(sp3.solution_is_ls() || sp2.solution_is_ls() || sp1.solution_is_ls());
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
break;
|
188
|
+
};
|
189
|
+
case KinematicClass::FIRST_SECOND_PARALLEL:
|
190
|
+
{
|
191
|
+
// h1 = h2; h2=/=h3
|
192
|
+
SP4 sp4_q3(this->H.col(0), this->P.col(3), this->H.col(2), this->H.col(0).transpose()*(p_14 - this->P.col(1) - this->P.col(2)));
|
193
|
+
sp4_q3.solve();
|
194
|
+
|
195
|
+
for(const auto& q3 : sp4_q3.get_theta())
|
196
|
+
{
|
197
|
+
const Eigen::Matrix3d r_23 = Eigen::AngleAxisd(q3, this->H.col(2).normalized()).toRotationMatrix();
|
198
|
+
SP3 sp3_q1(p_14, this->P.col(1), -this->H.col(0), (this->P.col(2)+r_23*this->P.col(3)).norm());
|
199
|
+
sp3_q1.solve();
|
200
|
+
|
201
|
+
for(const auto& q1 : sp3_q1.get_theta())
|
202
|
+
{
|
203
|
+
const Eigen::Matrix3d r_01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
|
204
|
+
SP1 sp1_q2(this->P.col(2)+r_23*this->P.col(3), r_01.transpose()*p_14-this->P.col(1), this->H.col(1));
|
205
|
+
sp1_q2.solve();
|
206
|
+
|
207
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(sp1_q2.get_theta(), this->H.col(1).normalized()).toRotationMatrix();
|
208
|
+
const Eigen::Vector3d hn = create_normal_vector(this->H.col(3));
|
209
|
+
SP1 sp1_q4(hn, r_04.transpose()*r_01*r_12*r_23*hn, -this->H.col(3));
|
210
|
+
sp1_q4.solve();
|
211
|
+
|
212
|
+
solution.Q.push_back({q1, sp1_q2.get_theta(), q3, sp1_q4.get_theta()});
|
213
|
+
solution.is_LS_vec.push_back(sp4_q3.solution_is_ls() || sp3_q1.solution_is_ls() || sp1_q2.solution_is_ls() || sp1_q4.solution_is_ls());
|
214
|
+
}
|
215
|
+
}
|
216
|
+
break;
|
217
|
+
};
|
218
|
+
case KinematicClass::SECOND_THIRD_PARALLEL:
|
219
|
+
{
|
220
|
+
// h1 =/= h2; h2=h3
|
221
|
+
SP4 sp4(this->H.col(1), p_14, -this->H.col(0), this->H.col(1).transpose()*(this->P.col(1) + this->P.col(2) + this->P.col(3)));
|
222
|
+
sp4.solve();
|
223
|
+
|
224
|
+
for(const auto& q1 : sp4.get_theta())
|
225
|
+
{
|
226
|
+
const Eigen::Matrix3d r_10 = Eigen::AngleAxisd(q1, -this->H.col(0).normalized()).toRotationMatrix();
|
227
|
+
SP3 sp3(this->P.col(3), -this->P.col(2), this->H.col(2), (r_10*p_14-this->P.col(1)).norm());
|
228
|
+
sp3.solve();
|
229
|
+
|
230
|
+
for(const auto& q3 : sp3.get_theta())
|
231
|
+
{
|
232
|
+
const Eigen::Matrix3d r_23 = Eigen::AngleAxisd(q3, this->H.col(2).normalized()).toRotationMatrix();
|
233
|
+
SP1 sp1_q2(this->P.col(2) + r_23*this->P.col(3), r_10*p_14-this->P.col(1), this->H.col(1));
|
234
|
+
sp1_q2.solve();
|
235
|
+
|
236
|
+
const double q2 = sp1_q2.get_theta();
|
237
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
|
238
|
+
|
239
|
+
const Eigen::Vector3d hn = create_normal_vector(this->H.col(3));
|
240
|
+
SP1 sp1_q4(hn, r_04.transpose()*r_10.transpose()*r_12*r_23*hn, -this->H.col(3));
|
241
|
+
sp1_q4.solve();
|
242
|
+
|
243
|
+
solution.Q.push_back({q1, q2, q3, sp1_q4.get_theta()});
|
244
|
+
solution.is_LS_vec.push_back(sp4.solution_is_ls() || sp3.solution_is_ls() || sp1_q2.solution_is_ls() || sp1_q4.solution_is_ls());
|
245
|
+
}
|
246
|
+
}
|
247
|
+
break;
|
248
|
+
};
|
249
|
+
case KinematicClass::NONE_PARALLEL_NONE_INTERSECTING:
|
250
|
+
{
|
251
|
+
// h1 =/= h2; h2=/=h3
|
252
|
+
SP5 sp5(-this->P.col(1), p_14, this->P.col(2), this->P.col(3), -this->H.col(0), this->H.col(1), this->H.col(2));
|
253
|
+
sp5.solve();
|
254
|
+
|
255
|
+
const std::vector<double> &theta_1 = sp5.get_theta_1();
|
256
|
+
const std::vector<double> &theta_2 = sp5.get_theta_2();
|
257
|
+
const std::vector<double> &theta_3 = sp5.get_theta_3();
|
258
|
+
|
259
|
+
const Eigen::Vector3d h_n = create_normal_vector(this->H.col(3));
|
260
|
+
for(unsigned i = 0; i < theta_1.size(); i++)
|
261
|
+
{
|
262
|
+
const double& q1 = theta_1.at(i);
|
263
|
+
const double& q2 = theta_2.at(i);
|
264
|
+
const double& q3 = theta_3.at(i);
|
265
|
+
const Eigen::Matrix3d r_01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
|
266
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
|
267
|
+
const Eigen::Matrix3d r_23 = Eigen::AngleAxisd(q3, this->H.col(2).normalized()).toRotationMatrix();
|
268
|
+
|
269
|
+
SP1 sp1(h_n, r_23.transpose()*r_12.transpose()*r_01.transpose()*r_04*h_n, this->H.col(3));
|
270
|
+
sp1.solve();
|
271
|
+
|
272
|
+
solution.Q.push_back({q1, q2, q3, sp1.get_theta()});
|
273
|
+
solution.is_LS_vec.push_back(sp5.solution_is_ls() || sp1.solution_is_ls());
|
274
|
+
}
|
275
|
+
break;
|
276
|
+
};
|
277
|
+
case KinematicClass::FIRST_TWO_LAST_TWO_INTERSECTING:
|
278
|
+
{
|
279
|
+
SP2 sp2_q12(p_14, this->P.col(2), -this->H.col(0), this->H.col(1));
|
280
|
+
sp2_q12.solve();
|
281
|
+
|
282
|
+
const std::vector<double> &theta_1 = sp2_q12.get_theta_1();
|
283
|
+
const std::vector<double> &theta_2 = sp2_q12.get_theta_2();
|
284
|
+
|
285
|
+
for(unsigned i = 0; i < theta_1.size(); ++i)
|
286
|
+
{
|
287
|
+
const double& q1 = theta_1.at(i);
|
288
|
+
const double& q2 = theta_2.at(i);
|
289
|
+
const Eigen::Matrix3d r_01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
|
290
|
+
const Eigen::Matrix3d r_12 = Eigen::AngleAxisd(q2, this->H.col(1).normalized()).toRotationMatrix();
|
291
|
+
|
292
|
+
const Eigen::Vector3d h_n = this->H.col(3).cross(r_04.transpose()*r_01*r_12*this->H.col(2));
|
293
|
+
SP2 sp2_q34(r_12.transpose()*r_01.transpose()*r_04*h_n, h_n, -this->H.col(2), this->H.col(3));
|
294
|
+
sp2_q34.solve();
|
295
|
+
|
296
|
+
const std::vector<double> &theta_3 = sp2_q34.get_theta_1();
|
297
|
+
const std::vector<double> &theta_4 = sp2_q34.get_theta_2();
|
298
|
+
|
299
|
+
for(unsigned j = 0; j < theta_3.size(); ++j)
|
300
|
+
{
|
301
|
+
const double& q3 = theta_3.at(j);
|
302
|
+
const double& q4 = theta_4.at(j);
|
303
|
+
|
304
|
+
solution.Q.push_back({q1, q2, q3, q4});
|
305
|
+
solution.is_LS_vec.push_back(sp2_q12.solution_is_ls() || sp2_q34.solution_is_ls());
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
break;
|
310
|
+
};
|
311
|
+
case KinematicClass::SPHERICAL_WRIST:
|
312
|
+
{
|
313
|
+
SP1 sp1_q1(this->P.col(1), p_14, this->H.col(0));
|
314
|
+
sp1_q1.solve();
|
315
|
+
|
316
|
+
const double& q1 = sp1_q1.get_theta();
|
317
|
+
const Eigen::Matrix3d r_01 = Eigen::AngleAxisd(q1, this->H.col(0).normalized()).toRotationMatrix();
|
318
|
+
|
319
|
+
SP2 sp2(r_01.transpose()*r_04*this->H.col(3), this->H.col(3), -this->H.col(1), this->H.col(2));
|
320
|
+
sp2.solve();
|
321
|
+
|
322
|
+
const std::vector<double> &theta_2 = sp2.get_theta_1();
|
323
|
+
const std::vector<double> &theta_3 = sp2.get_theta_2();
|
324
|
+
|
325
|
+
const Eigen::Vector3d& h_n = create_normal_vector(this->H.col(3));
|
326
|
+
for(unsigned i = 0; i < theta_2.size(); ++i)
|
327
|
+
{
|
328
|
+
const double& q2 = theta_2.at(i);
|
329
|
+
const double& q3 = theta_3.at(i);
|
330
|
+
|
331
|
+
const Eigen::Matrix3d r_21 = Eigen::AngleAxisd(q2, -this->H.col(1).normalized()).toRotationMatrix();
|
332
|
+
const Eigen::Matrix3d r_32 = Eigen::AngleAxisd(q3, -this->H.col(2).normalized()).toRotationMatrix();
|
333
|
+
|
334
|
+
SP1 sp1_q4(h_n, r_32*r_21*r_01.transpose()*r_04*h_n, this->H.col(3));
|
335
|
+
sp1_q4.solve();
|
336
|
+
|
337
|
+
solution.Q.push_back({q1, q2, q3, sp1_q4.get_theta()});
|
338
|
+
solution.is_LS_vec.push_back(sp1_q1.solution_is_ls() || sp2.solution_is_ls() || sp1_q4.solution_is_ls());
|
339
|
+
}
|
340
|
+
break;
|
341
|
+
};
|
342
|
+
case KinematicClass::REVERSED:
|
343
|
+
{
|
344
|
+
if(reversed_Robot_ptr)
|
345
|
+
{
|
346
|
+
// Use reversed kinematic chain
|
347
|
+
solution = this->reversed_Robot_ptr->calculate_IK(inverse_homogeneous_T(ee_position_orientation));
|
348
|
+
reverse_vector_second_dimension(solution.Q);
|
349
|
+
}
|
350
|
+
else
|
351
|
+
{
|
352
|
+
throw std::runtime_error("Reversed kinematic chain was not initialized! Please open an issue on our GitHub repository.");
|
353
|
+
}
|
354
|
+
|
355
|
+
break;
|
356
|
+
};
|
357
|
+
|
358
|
+
default:
|
359
|
+
std::cerr<< "The choosen manipulator has no known subproblem decomposition! The resulting solutions will be empty."<<std::endl;
|
360
|
+
}
|
361
|
+
|
362
|
+
return enforce_solution_consistency(solution, ee_position_orientation);
|
363
|
+
}
|
364
|
+
|
365
|
+
|
366
|
+
std::string General_4R::get_kinematic_family() const
|
367
|
+
{
|
368
|
+
switch (kinematicClass)
|
369
|
+
{
|
370
|
+
case KinematicClass::THIRD_FOURTH_INTERSECTING:
|
371
|
+
return std::string("4R-THIRD_FOURTH_INTERSECTING");
|
372
|
+
case KinematicClass::SECOND_THIRD_INTERSECTING:
|
373
|
+
return std::string("4R-SECOND_THIRD_INTERSECTING");
|
374
|
+
case KinematicClass::FIRST_SECOND_PARALLEL:
|
375
|
+
return std::string("4R-FIRST_SECOND_PARALLEL");
|
376
|
+
case KinematicClass::SECOND_THIRD_PARALLEL:
|
377
|
+
return std::string("4R-SECOND_THIRD_PARALLEL");
|
378
|
+
case KinematicClass::NONE_PARALLEL_NONE_INTERSECTING:
|
379
|
+
return std::string("4R-NONE_PARALLEL_NONE_INTERSECTING");
|
380
|
+
case KinematicClass::FIRST_TWO_LAST_TWO_INTERSECTING:
|
381
|
+
return std::string("4R-FIRST_TWO_LAST_TWO_INTERSECTING");
|
382
|
+
case KinematicClass::SPHERICAL_WRIST:
|
383
|
+
return std::string("4R-SPHERICAL_WRIST");
|
384
|
+
case KinematicClass::REVERSED:
|
385
|
+
return reversed_Robot_ptr ? reversed_Robot_ptr->get_kinematic_family() : "4R-Unknown Kinematic Class";
|
386
|
+
default:
|
387
|
+
return std::string("4R-Unknown Kinematic Class");
|
388
|
+
}
|
389
|
+
}
|
390
|
+
|
391
|
+
};
|