fk_ik_tests.cpp
Go to the documentation of this file.
1 // Author: Jeroen De Maeyer (JeroenDM @ Github)
2 // With edits by Jonathan Meyer
4 OPW_IGNORE_WARNINGS_PUSH
5 #include <array>
6 #include <chrono>
7 #include <gtest/gtest.h> // IWYU pragma: keep
8 #include <random>
9 #include <array>
10 OPW_IGNORE_WARNINGS_POP
11 
12 #include "opw_kinematics/opw_kinematics.h" // IWYU pragma: keep
15 
16 // Structure used for setting sampler parameters based on floating point type
17 template <typename T>
19 
20 template <>
21 struct TestTolerance<float>
22 {
23  static constexpr float TOLERANCE = 5e-4f;
24  static constexpr const char* const NAME = "float";
25 };
26 
27 template <>
28 struct TestTolerance<double>
29 {
30  static constexpr double TOLERANCE = 1e-7;
31  static constexpr const char* const NAME = "double";
32 };
33 
34 // Helper Functions for generating and testing random poses in cartesian/joint space
37 
38 template <typename T>
39 void comparePoses(const Transform<T>& Ta, const Transform<T>& Tb, double tolerance)
40 {
41  T translation_distance = (Ta.translation() - Tb.translation()).norm();
42  T angular_distance = Eigen::Quaternion<T>(Ta.linear()).angularDistance(Eigen::Quaternion<T>(Tb.linear()));
43 
44  EXPECT_NEAR(static_cast<double>(translation_distance), 0, tolerance);
45  EXPECT_NEAR(static_cast<double>(angular_distance), 0, tolerance);
46 }
47 
48 template <typename T>
49 void getRandomJointValues(std::array<T, 6>& q)
50 {
51  static std::default_random_engine en{ 42 }; // random engine
52  static std::uniform_real_distribution<T> rg{ T(-M_PI), T(M_PI) }; // random generator
53 
54  q[0] = rg(en);
55  q[1] = rg(en);
56  q[2] = rg(en);
57  q[3] = rg(en);
58  q[4] = rg(en);
59  q[5] = rg(en);
60 }
61 
62 // Generate random joint pose -> Solve FK -> Solve IK -> Verify that new FK matches
63 // the original.
64 template <typename T>
66 {
67  const static unsigned int number_of_tests = 1000;
68 
69  Transform<T> pose, forward_pose;
70  std::array<T, 6> q_rand;
71  Solutions<T> sols;
72 
73  for (unsigned j = 0; j < number_of_tests; ++j)
74  {
75  // create a reachable pose based on a random robot position
76  getRandomJointValues(q_rand);
77  pose = opw_kinematics::forward(params, q_rand);
78 
79  // Solve Inverse kinematics
80  sols = opw_kinematics::inverse(params, pose);
81 
82  // check all valid solutions using forward kinematics
83  for (const auto& s : sols)
84  {
86  {
87  // Forward kinematics of a solution should result in the same pose
88  forward_pose = opw_kinematics::forward(params, s);
89  comparePoses(forward_pose, pose, TestTolerance<T>::TOLERANCE);
90  }
91  }
92  }
93 }
94 
95 // Generate random joint poses, time how long it takes to solve FK for all of them
96 // Then time how long it takes to solve IK for all of them
97 template <typename T>
99 {
100  const static unsigned int number_of_tests = 10000;
101 
102  std::vector<Transform<T>, Eigen::aligned_allocator<Transform<T>>> poses;
103  poses.resize(number_of_tests);
104 
105  {
106  // Generate N random joint poses
107  std::vector<std::array<T, 6>> random_joint_values;
108  random_joint_values.resize(number_of_tests);
109 
110  for (std::size_t i = 0; i < number_of_tests; ++i)
111  {
112  getRandomJointValues(random_joint_values[i]);
113  }
114 
115  // Time the solving of FK
116  const auto fk_start_tm = std::chrono::steady_clock::now();
117  for (std::size_t i = 0; i < number_of_tests; ++i)
118  {
119  poses[i] = opw_kinematics::forward(params, random_joint_values[i]);
120  }
121  const auto fk_end_tm = std::chrono::steady_clock::now();
122 
123  // Report FK timing
124  const auto fk_dt_us = std::chrono::duration_cast<std::chrono::microseconds>(fk_end_tm - fk_start_tm).count();
125  std::cout << "Forward Kinematics " << TestTolerance<T>::NAME << " generated " << number_of_tests << " poses in "
126  << fk_dt_us << " us\n";
127  std::cout << "Average us per fk solve: " << static_cast<double>(fk_dt_us) / number_of_tests << "\n";
128  }
129 
130  Solutions<T> ik_sol_space;
131  const auto ik_start_tm = std::chrono::steady_clock::now();
132  for (std::size_t i = 0; i < number_of_tests; ++i)
133  {
134  ik_sol_space = opw_kinematics::inverse(params, poses[i]);
135  }
136  const auto ik_end_tm = std::chrono::steady_clock::now();
137  // Report FK timing
138  const auto ik_dt_us = std::chrono::duration_cast<std::chrono::microseconds>(ik_end_tm - ik_start_tm).count();
139  std::cout << "Inverse Kinematics " << TestTolerance<T>::NAME << " generated " << number_of_tests << " poses in "
140  << ik_dt_us << " us\n";
141  std::cout << "Average us per ik solve: " << static_cast<double>(ik_dt_us) / number_of_tests << "\n";
142 }
143 
144 TEST(kuka_kr6, random_reachable_poses_double) // NOLINT
145 {
146  const auto kukaKR6_R700_sixx = opw_kinematics::makeKukaKR6_R700_sixx<double>();
147  runRandomReachablePosesTest(kukaKR6_R700_sixx);
148 }
149 
150 TEST(kuka_kr6, random_reachable_poses_float) // NOLINT
151 {
152  const auto kukaKR6_R700_sixx = opw_kinematics::makeKukaKR6_R700_sixx<float>();
153  runRandomReachablePosesTest(kukaKR6_R700_sixx);
154 }
155 
156 TEST(kuka_kr6, throughput_tests_float) // NOLINT
157 {
158  const auto params = opw_kinematics::makeKukaKR6_R700_sixx<float>();
159  runThroughputTests(params);
160 }
161 
162 TEST(kuka_kr6, throughput_tests_double) // NOLINT
163 {
164  const auto params = opw_kinematics::makeKukaKR6_R700_sixx<double>();
165  runThroughputTests(params);
166 }
167 
168 TEST(abb_2400, throughput_tests_float) // NOLINT
169 {
170  const auto params = opw_kinematics::makeIrb2400_10<float>();
171  runThroughputTests(params);
172 }
173 
174 TEST(abb_2400, random_reachable_poses_double) // NOLINT
175 {
176  const auto params = opw_kinematics::makeIrb2400_10<double>();
178 }
179 
180 TEST(abb_2400, random_reachable_poses_float) // NOLINT
181 {
182  const auto params = opw_kinematics::makeIrb2400_10<float>();
184 }
185 
186 TEST(abb_2400, throughput_tests_double) // NOLINT
187 {
188  const auto params = opw_kinematics::makeIrb2400_10<double>();
189  runThroughputTests(params);
190 }
191 
192 TEST(abb_2600, throughput_tests_float) // NOLINT
193 {
194  const auto params = opw_kinematics::makeIrb2600_12_165<float>();
195  runThroughputTests(params);
196 }
197 
198 TEST(abb_2600, random_reachable_poses_double) // NOLINT
199 {
200  const auto params = opw_kinematics::makeIrb2600_12_165<double>();
202 }
203 
204 TEST(abb_2600, random_reachable_poses_float) // NOLINT
205 {
206  const auto params = opw_kinematics::makeIrb2600_12_165<float>();
208 }
209 
210 TEST(abb_2600, throughput_tests_double) // NOLINT
211 {
212  const auto params = opw_kinematics::makeIrb2600_12_165<double>();
213  runThroughputTests(params);
214 }
215 
216 TEST(abb_2600, numerical_issue_double) // NOLINT
217 {
218  const auto params = opw_kinematics::makeIrb2600_12_165<double>();
219  std::array<double, 6> jv{ 0, M_PI_4, 0, 0, 0, 0 };
220  Transform<double> pose = opw_kinematics::forward(params, jv);
221 
223  pose2(0, 0) = -0.707106781186547;
224  pose2(1, 0) = 0;
225  pose2(2, 0) = -0.707106781186548;
226  pose2(0, 1) = 4.9065389333868E-018;
227  pose2(1, 1) = 1;
228  pose2(2, 1) = -4.9065389333868E-018;
229  pose2(0, 2) = 0.707106781186548;
230  pose2(1, 2) = 0;
231  pose2(2, 2) = -0.707106781186547;
232  pose2(0, 3) = 1.3485459941112;
233  pose2(1, 3) = 0;
234  pose2(2, 3) = 0.399038059222874;
235 
237 
238  auto sols = opw_kinematics::inverse(params, pose2);
239  for (const auto& s : sols)
240  {
243  }
244 }
245 
246 TEST(abb_2600, numerical_issue2_double) // NOLINT
247 {
248  const auto params = opw_kinematics::makeIrb2600_12_165<double>();
249  std::array<double, 6> jv{ M_PI_4, 0, 0, 0, 0, 0 };
250  Transform<double> pose = opw_kinematics::forward(params, jv);
251 
253  pose2(0, 0) = 1.5700924586837752e-16;
254  pose2(1, 0) = 1.570092458683775e-16;
255  pose2(2, 0) = -1;
256  pose2(0, 1) = -0.7071067811865475;
257  pose2(1, 1) = 0.7071067811865476;
258  pose2(2, 1) = 0;
259  pose2(0, 2) = 0.7071067811865476;
260  pose2(1, 2) = 0.7071067811865475;
261  pose2(2, 2) = 2.220446049250313e-16;
262  pose2(0, 3) = 0.7283199846221441;
263  pose2(1, 3) = 0.728319984622144;
264  pose2(2, 3) = 1.26;
265 
267 
268  auto sols = opw_kinematics::inverse(params, pose2);
269  for (const auto& s : sols)
270  {
273  }
274 }
275 
276 TEST(abb_4600, numerical_issue_double) // NOLINT
277 {
278  const auto params = opw_kinematics::makeIrb4600_60_205<double>();
279 
281  pose2(0, 0) = 3.46244636694609e-12;
282  pose2(1, 0) = 3.46244625852587e-12;
283  pose2(2, 0) = -1;
284  pose2(0, 1) = -0.707106781186547;
285  pose2(1, 1) = 0.707106781186547;
286  pose2(2, 1) = 0;
287  pose2(0, 2) = 0.707106781186547;
288  pose2(1, 2) = 0.707106781186547;
289  pose2(2, 2) = 4.89663875852947e-12;
290  pose2(0, 3) = 0.898025612106916;
291  pose2(1, 3) = 0.898025612106915;
292  pose2(2, 3) = 1.57;
293 
294  auto sols = opw_kinematics::inverse(params, pose2);
295  for (const auto& s : sols)
296  {
299  }
300 }
301 
302 OPW_IGNORE_WARNINGS_PUSH
303 TEST(fanuc_r2000, random_reachable_poses_double) // NOLINT
304 {
305  const auto params = opw_kinematics::makeFanucR2000iB_200R<double>();
307 }
308 
309 TEST(fanuc_r2000, random_reachable_poses_float) // NOLINT
310 {
311  const auto params = opw_kinematics::makeFanucR2000iB_200R<float>();
313 }
314 
315 TEST(fanuc_r2000, throughput_tests_float) // NOLINT
316 {
317  const auto params = opw_kinematics::makeFanucR2000iB_200R<float>();
318  runThroughputTests(params);
319 }
320 
321 TEST(fanuc_r2000, throughput_tests_double) // NOLINT
322 {
323  const auto params = opw_kinematics::makeFanucR2000iB_200R<double>();
324  runThroughputTests(params);
325 }
326 OPW_IGNORE_WARNINGS_POP
327 
328 int main(int argc, char** argv)
329 {
330  testing::InitGoogleTest(&argc, argv);
331  return RUN_ALL_TESTS();
332 }
TOLERANCE
OPW_IGNORE_WARNINGS_PUSH const OPW_IGNORE_WARNINGS_POP double TOLERANCE
Definition: sign_corrections_tests.cpp:15
opw_kinematics::isValid
bool isValid(const std::array< T, 6 > &qs)
Definition: opw_utilities.h:10
opw_kinematics::Transform
Eigen::Transform< T, 3, Eigen::Isometry > Transform
Definition: opw_kinematics.h:15
opw_kinematics.h
Transform
opw_kinematics::Transform< double > Transform
Definition: abb2400_ikfast_tests.cpp:17
TestTolerance
Definition: fk_ik_tests.cpp:18
opw_kinematics::Solutions
std::array< std::array< T, 6 >, 8 > Solutions
Definition: opw_kinematics.h:22
Solutions
opw_kinematics::Solutions< double > Solutions
Definition: abb2400_ikfast_tests.cpp:18
runRandomReachablePosesTest
void runRandomReachablePosesTest(const opw_kinematics::Parameters< T > &params)
Definition: fk_ik_tests.cpp:65
opw_utilities.h
opw_kinematics::forward
Transform< T > forward(const Parameters< T > &p, const std::array< T, 6 > &qs) noexcept
Computes the tool pose of the robot described by when said robot has the joint positions given by qs,...
Definition: opw_kinematics_impl.h:34
opw_kinematics::inverse
Solutions< T > inverse(const Parameters< T > &params, const Transform< T > &pose) noexcept
Computes up to 8 kinematically unique joint solutions that put the tool flange of the robot described...
Definition: opw_kinematics_impl.h:113
opw_parameters_examples.h
main
OPW_IGNORE_WARNINGS_POP int main(int argc, char **argv)
Definition: fk_ik_tests.cpp:328
getRandomJointValues
void getRandomJointValues(std::array< T, 6 > &q)
Definition: fk_ik_tests.cpp:49
comparePoses
void comparePoses(const Transform< T > &Ta, const Transform< T > &Tb, double tolerance)
Definition: fk_ik_tests.cpp:39
opw_macros.h
runThroughputTests
void runThroughputTests(const opw_kinematics::Parameters< T > &params)
Definition: fk_ik_tests.cpp:98
opw_kinematics::Parameters
Definition: opw_parameters.h:10
TEST
TEST(kuka_kr6, random_reachable_poses_double)
Definition: fk_ik_tests.cpp:144


opw_kinematics
Author(s): Jon Meyer , Jeroen De Maeyer
autogenerated on Thu Jan 16 2025 03:40:37