19 #include <rclcpp/rclcpp.hpp>
36 void checkAndEmit(
bool predicate,
const std::string& test_case,
const std::string& label)
40 std::cout <<
"[PASS] " << test_case <<
": " << label <<
"\n";
44 std::cout <<
"[FAIL] " << test_case <<
": " << label <<
"\n";
50 static moveit_msgs::msg::RobotTrajectory out = []() {
51 moveit_msgs::msg::RobotTrajectory traj;
53 auto trajectory = &traj.joint_trajectory;
56 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint1");
57 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint2");
58 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint3");
59 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint4");
60 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint5");
61 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint6");
62 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint7");
64 trajectory->points.emplace_back();
65 trajectory->points.at(0).positions = { 0, 0, 0, 0, 0, 0 };
66 trajectory->points.at(0).velocities = { 0, 0, 0, 0, 0, 0 };
67 trajectory->points.at(0).accelerations = { 0, 0, 0, 0, 0, 0 };
68 trajectory->points.at(0).time_from_start.sec = 999999;
77 static std::vector<geometry_msgs::msg::Pose> out = []() {
78 std::vector<geometry_msgs::msg::Pose> waypoints;
79 for (
size_t i = 0; i < 3; i++)
81 waypoints.emplace_back();
82 waypoints.at(i).position.x = i;
83 waypoints.at(i).position.y = i;
84 waypoints.at(i).position.z = i;
85 waypoints.at(i).orientation.w = i;
86 waypoints.at(i).orientation.x = i + 0.1;
87 waypoints.at(i).orientation.y = i + 0.1;
88 waypoints.at(i).orientation.z = i + 0.1;
97 std::string test_case =
"getters_and_setters";
99 checkAndEmit(cache->getDbPath() ==
":memory:", test_case,
"getDbPath");
100 checkAndEmit(cache->getDbPort() == 0, test_case,
"getDbPort");
102 checkAndEmit(cache->getExactMatchPrecision() == 10, test_case,
"getExactMatchPrecision");
103 cache->setExactMatchPrecision(1);
104 checkAndEmit(cache->getExactMatchPrecision() == 1, test_case,
"getExactMatchPrecisionAfterSet");
106 checkAndEmit(cache->getNumAdditionalTrajectoriesToPreserveWhenDeletingWorse() == 10, test_case,
107 "getNumAdditionalTrajectoriesToPreserveWhenDeletingWorse");
108 cache->setNumAdditionalTrajectoriesToPreserveWhenDeletingWorse(1);
109 checkAndEmit(cache->getNumAdditionalTrajectoriesToPreserveWhenDeletingWorse() == 1, test_case,
110 "getNumAdditionalTrajectoriesToPreserveWhenDeletingWorseAfterSet");
114 const std::shared_ptr<TrajectoryCache>& cache)
123 move_group->constructMotionPlanRequest(plan_req);
124 plan_req.workspace_parameters.header.frame_id =
ROBOT_FRAME;
125 plan_req.workspace_parameters.max_corner.x = 10;
126 plan_req.workspace_parameters.max_corner.y = 10;
127 plan_req.workspace_parameters.max_corner.z = 10;
128 plan_req.workspace_parameters.min_corner.x = -10;
129 plan_req.workspace_parameters.min_corner.y = -10;
130 plan_req.workspace_parameters.min_corner.z = -10;
131 plan_req.start_state.multi_dof_joint_state.joint_names.clear();
132 plan_req.start_state.multi_dof_joint_state.transforms.clear();
133 plan_req.start_state.multi_dof_joint_state.twist.clear();
134 plan_req.start_state.multi_dof_joint_state.wrench.clear();
138 empty_frame_plan_req.workspace_parameters.header.frame_id =
"";
141 auto is_diff_plan_req = plan_req;
142 is_diff_plan_req.start_state.is_diff =
true;
143 is_diff_plan_req.start_state.joint_state.header.frame_id =
"";
144 is_diff_plan_req.start_state.joint_state.name.clear();
145 is_diff_plan_req.start_state.joint_state.position.clear();
146 is_diff_plan_req.start_state.joint_state.velocity.clear();
147 is_diff_plan_req.start_state.joint_state.effort.clear();
150 auto close_matching_plan_req = plan_req;
151 close_matching_plan_req.workspace_parameters.max_corner.x += 0.05;
152 close_matching_plan_req.workspace_parameters.min_corner.x -= 0.05;
153 close_matching_plan_req.start_state.joint_state.position.at(0) -= 0.05;
154 close_matching_plan_req.start_state.joint_state.position.at(1) += 0.05;
155 close_matching_plan_req.start_state.joint_state.position.at(2) -= 0.05;
156 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(0).position -= 0.05;
157 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(1).position += 0.05;
158 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(2).position -= 0.05;
161 auto swapped_close_matching_plan_req = close_matching_plan_req;
162 std::swap(swapped_close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(0),
163 swapped_close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(1));
166 auto smaller_workspace_plan_req = plan_req;
167 smaller_workspace_plan_req.workspace_parameters.max_corner.x = 1;
168 smaller_workspace_plan_req.workspace_parameters.max_corner.y = 1;
169 smaller_workspace_plan_req.workspace_parameters.max_corner.z = 1;
170 smaller_workspace_plan_req.workspace_parameters.min_corner.x = -1;
171 smaller_workspace_plan_req.workspace_parameters.min_corner.y = -1;
172 smaller_workspace_plan_req.workspace_parameters.min_corner.z = -1;
175 auto larger_workspace_plan_req = plan_req;
176 larger_workspace_plan_req.workspace_parameters.max_corner.x = 50;
177 larger_workspace_plan_req.workspace_parameters.max_corner.y = 50;
178 larger_workspace_plan_req.workspace_parameters.max_corner.z = 50;
179 larger_workspace_plan_req.workspace_parameters.min_corner.x = -50;
180 larger_workspace_plan_req.workspace_parameters.min_corner.y = -50;
181 larger_workspace_plan_req.workspace_parameters.min_corner.z = -50;
184 auto different_plan_req = plan_req;
185 different_plan_req.workspace_parameters.max_corner.x += 1.05;
186 different_plan_req.workspace_parameters.min_corner.x -= 2.05;
187 different_plan_req.start_state.joint_state.position.at(0) -= 3.05;
188 different_plan_req.start_state.joint_state.position.at(1) += 4.05;
189 different_plan_req.start_state.joint_state.position.at(2) -= 5.05;
190 different_plan_req.goal_constraints.at(0).joint_constraints.at(0).position -= 6.05;
191 different_plan_req.goal_constraints.at(0).joint_constraints.at(1).position += 7.05;
192 different_plan_req.goal_constraints.at(0).joint_constraints.at(2).position -= 8.05;
200 auto empty_frame_traj = traj;
201 empty_frame_traj.joint_trajectory.header.frame_id =
"";
203 auto different_traj = traj;
204 different_traj.joint_trajectory.points.at(0).positions.at(0) = 999;
205 different_traj.joint_trajectory.points.at(0).positions.at(1) = 999;
206 different_traj.joint_trajectory.points.at(0).positions.at(2) = 999;
210 std::string test_case;
215 test_case =
"testMotionTrajectories.empty";
220 "Fetch all trajectories on empty cache returns empty");
223 "Fetch best trajectory on empty cache returns nullptr");
228 test_case =
"testMotionTrajectories.insertTrajectory_empty_frame";
229 double execution_time = 999;
230 double planning_time = 999;
233 planning_time,
false),
234 test_case,
"Put empty frame trajectory, no prune_worse_trajectories, not ok");
241 test_case =
"testMotionTrajectories.insertTrajectory_req_empty_frame";
242 execution_time = 1000;
243 planning_time = 1000;
246 planning_time,
false),
247 test_case,
"Put empty frame req trajectory, no prune_worse_trajectories, ok");
252 test_case =
"testMotionTrajectories.put_second";
253 execution_time = 999;
257 test_case,
"Put second valid trajectory, no prune_worse_trajectories, ok");
264 test_case =
"testMotionTrajectories.put_second.fetch_matching_no_tolerance";
266 auto fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
268 auto fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
270 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
271 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
273 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
275 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
277 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
278 "Fetched trajectory has correct execution time");
280 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
281 "Fetched trajectory has correct planning time");
287 test_case =
"testMotionTrajectories.put_second.fetch_is_diff_no_tolerance";
289 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, is_diff_plan_req, 0, 0);
291 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, is_diff_plan_req, 0, 0);
293 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
294 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
296 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
298 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
300 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
301 "Fetched trajectory has correct execution time");
303 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
304 "Fetched trajectory has correct planning time");
309 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_out_of_tolerance";
311 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 0);
313 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 0);
315 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
316 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
321 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_start_in_tolerance";
323 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 999, 0);
325 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 999, 0);
327 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
328 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
333 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_goal_in_tolerance";
335 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 999);
337 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 999);
339 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
340 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
345 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_in_tolerance";
347 fetched_trajectories =
348 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0.1, 0.1);
350 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0.1, 0.1);
352 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
353 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
355 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
357 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
359 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
360 "Fetched trajectory has correct execution time");
362 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
363 "Fetched trajectory has correct planning time");
368 test_case =
"testMotionTrajectories.put_second.fetch_swapped";
370 fetched_trajectories =
371 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, swapped_close_matching_plan_req, 0.1, 0.1);
373 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, swapped_close_matching_plan_req, 0.1, 0.1);
375 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
376 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
378 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
380 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
382 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
383 "Fetched trajectory has correct execution time");
385 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
386 "Fetched trajectory has correct planning time");
392 test_case =
"testMotionTrajectories.put_second.fetch_smaller_workspace";
394 fetched_trajectories =
395 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, smaller_workspace_plan_req, 999, 999);
397 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, smaller_workspace_plan_req, 999, 999);
399 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
400 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
406 test_case =
"testMotionTrajectories.put_second.fetch_larger_workspace";
408 fetched_trajectories =
409 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, larger_workspace_plan_req, 999, 999);
411 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, larger_workspace_plan_req, 999, 999);
413 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
414 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
416 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
418 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
420 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
421 "Fetched trajectory has correct execution time");
423 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
424 "Fetched trajectory has correct planning time");
426 checkAndEmit(fetched_traj->lookupDouble(
"workspace_parameters.max_corner.x") <=
427 larger_workspace_plan_req.workspace_parameters.max_corner.x,
428 test_case,
"Fetched trajectory has more restrictive workspace max_corner");
430 checkAndEmit(fetched_traj->lookupDouble(
"workspace_parameters.max_corner.x") >=
431 larger_workspace_plan_req.workspace_parameters.min_corner.x,
432 test_case,
"Fetched trajectory has more restrictive workspace min_corner");
437 test_case =
"testMotionTrajectories.put_worse";
438 double worse_execution_time = execution_time + 100;
442 test_case,
"Put worse trajectory, no prune_worse_trajectories, not ok");
449 test_case =
"testMotionTrajectories.put_better";
450 double better_execution_time = execution_time - 100;
454 test_case,
"Put better trajectory, no prune_worse_trajectories, ok");
461 test_case =
"testMotionTrajectories.put_better.fetch_sorted";
463 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
467 checkAndEmit(fetched_trajectories.size() == 3, test_case,
"Fetch all returns three");
468 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
470 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
472 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
474 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
475 "Fetched trajectory has correct execution time");
477 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
478 "Fetched trajectory has correct planning time");
480 checkAndEmit(fetched_trajectories.at(0)->lookupDouble(
"execution_time_s") == better_execution_time &&
481 fetched_trajectories.at(1)->lookupDouble(
"execution_time_s") == execution_time,
482 test_case,
"Fetched trajectories are sorted correctly");
487 test_case =
"testMotionTrajectories.put_better_prune_worse_trajectories";
488 double even_better_execution_time = better_execution_time - 100;
491 planning_time,
true),
492 test_case,
"Put better trajectory, prune_worse_trajectories, ok");
497 test_case =
"testMotionTrajectories.put_better_prune_worse_trajectories.fetch";
499 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
503 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
504 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
506 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
508 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
510 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == even_better_execution_time, test_case,
511 "Fetched trajectory has correct execution time");
513 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
514 "Fetched trajectory has correct planning time");
519 test_case =
"testMotionTrajectories.put_different_req";
522 better_execution_time, planning_time,
true),
523 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
530 test_case =
"testMotionTrajectories.put_different_req.fetch";
532 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
534 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
536 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
537 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
539 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
541 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
543 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
544 "Fetched trajectory has correct execution time");
546 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
547 "Fetched trajectory has correct planning time");
552 test_case =
"testMotionTrajectories.different_robot.empty";
553 std::string different_robot_name =
"different_robot";
555 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 0, test_case,
"No trajectories in cache");
560 test_case =
"testMotionTrajectories.different_robot.put_first";
561 checkAndEmit(cache->insertTrajectory(*
move_group, different_robot_name, different_plan_req, different_traj,
562 better_execution_time, planning_time,
true),
563 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
565 checkAndEmit(cache->countTrajectories(different_robot_name) == 1, test_case,
"One trajectory in cache");
567 checkAndEmit(cache->countTrajectories(
ROBOT_NAME) == 2, test_case,
"Two trajectories in original robot's cache");
569 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
571 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all on original still returns one");
575 const std::shared_ptr<TrajectoryCache>& cache)
577 std::string test_case;
582 test_case =
"testCartesianTrajectories.constructGetCartesianPathRequest";
587 auto cartesian_plan_req_under_test =
588 cache->constructGetCartesianPathRequest(*
move_group, test_waypoints, test_step, test_jump,
false);
590 checkAndEmit(cartesian_plan_req_under_test.waypoints == test_waypoints &&
591 static_cast<int>(cartesian_plan_req_under_test.max_step) == test_step &&
592 static_cast<int>(cartesian_plan_req_under_test.jump_threshold) == test_jump &&
593 !cartesian_plan_req_under_test.avoid_collisions,
603 auto cartesian_plan_req = cache->constructGetCartesianPathRequest(*
move_group, waypoints, 1, 1,
false);
604 cartesian_plan_req.start_state.multi_dof_joint_state.joint_names.clear();
605 cartesian_plan_req.start_state.multi_dof_joint_state.transforms.clear();
606 cartesian_plan_req.start_state.multi_dof_joint_state.twist.clear();
607 cartesian_plan_req.start_state.multi_dof_joint_state.wrench.clear();
608 cartesian_plan_req.path_constraints.joint_constraints.clear();
609 cartesian_plan_req.path_constraints.position_constraints.clear();
610 cartesian_plan_req.path_constraints.orientation_constraints.clear();
611 cartesian_plan_req.path_constraints.visibility_constraints.clear();
614 auto empty_frame_cartesian_plan_req = cartesian_plan_req;
615 empty_frame_cartesian_plan_req.header.frame_id =
"";
618 auto is_diff_cartesian_plan_req = cartesian_plan_req;
619 is_diff_cartesian_plan_req.start_state.is_diff =
true;
620 is_diff_cartesian_plan_req.start_state.joint_state.header.frame_id =
"";
621 is_diff_cartesian_plan_req.start_state.joint_state.name.clear();
622 is_diff_cartesian_plan_req.start_state.joint_state.position.clear();
623 is_diff_cartesian_plan_req.start_state.joint_state.velocity.clear();
624 is_diff_cartesian_plan_req.start_state.joint_state.effort.clear();
627 auto close_matching_cartesian_plan_req = cartesian_plan_req;
628 close_matching_cartesian_plan_req.start_state.joint_state.position.at(0) -= 0.05;
629 close_matching_cartesian_plan_req.start_state.joint_state.position.at(1) += 0.05;
630 close_matching_cartesian_plan_req.start_state.joint_state.position.at(2) -= 0.05;
631 close_matching_cartesian_plan_req.waypoints.at(0).position.x -= 0.05;
632 close_matching_cartesian_plan_req.waypoints.at(1).position.x += 0.05;
633 close_matching_cartesian_plan_req.waypoints.at(2).position.x -= 0.05;
636 auto different_cartesian_plan_req = cartesian_plan_req;
637 different_cartesian_plan_req.start_state.joint_state.position.at(0) -= 1.05;
638 different_cartesian_plan_req.start_state.joint_state.position.at(1) += 2.05;
639 different_cartesian_plan_req.start_state.joint_state.position.at(2) -= 3.05;
640 different_cartesian_plan_req.waypoints.at(0).position.x -= 1.05;
641 different_cartesian_plan_req.waypoints.at(1).position.x += 2.05;
642 different_cartesian_plan_req.waypoints.at(2).position.x -= 3.05;
650 auto empty_frame_traj = traj;
651 empty_frame_traj.joint_trajectory.header.frame_id =
"";
653 auto different_traj = traj;
654 different_traj.joint_trajectory.points.at(0).positions.at(0) = 999;
655 different_traj.joint_trajectory.points.at(0).positions.at(1) = 999;
656 different_traj.joint_trajectory.points.at(0).positions.at(2) = 999;
661 test_case =
"testCartesianTrajectories.empty";
663 checkAndEmit(cache->countCartesianTrajectories(
ROBOT_NAME) == 0, test_case,
"Trajectory cache initially empty");
666 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999).empty(),
667 test_case,
"Fetch all trajectories on empty cache returns empty");
671 test_case,
"Fetch best trajectory on empty cache returns nullptr");
676 test_case =
"testCartesianTrajectories.insertTrajectory_empty_frame";
677 double execution_time = 999;
678 double planning_time = 999;
679 double fraction = 0.5;
682 execution_time, planning_time, fraction,
false),
683 test_case,
"Put empty frame trajectory, no prune_worse_trajectories, not ok");
690 test_case =
"testCartesianTrajectories.insertTrajectory_req_empty_frame";
691 execution_time = 1000;
692 planning_time = 1000;
695 execution_time, planning_time, fraction,
false),
696 test_case,
"Put empty frame req trajectory, no prune_worse_trajectories, ok");
701 test_case =
"testCartesianTrajectories.put_second";
702 execution_time = 999;
706 planning_time, fraction,
false),
707 test_case,
"Put second valid trajectory, no prune_worse_trajectories, ok");
714 test_case =
"testCartesianTrajectories.put_second.fetch_matching_no_tolerance";
716 auto fetched_trajectories =
717 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
720 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
722 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
723 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
725 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
727 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
729 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
730 "Fetched trajectory has correct execution time");
732 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
733 "Fetched trajectory has correct planning time");
735 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
741 test_case =
"testCartesianTrajectories.put_second.fetch_is_diff_no_tolerance";
743 fetched_trajectories =
744 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, is_diff_cartesian_plan_req, fraction, 0, 0);
747 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, is_diff_cartesian_plan_req, fraction, 0, 0);
749 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
750 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
752 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
754 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
756 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
757 "Fetched trajectory has correct execution time");
759 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
760 "Fetched trajectory has correct planning time");
762 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
767 test_case =
"testCartesianTrajectories.put_second.fetch_non_matching_out_of_tolerance";
769 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
772 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
775 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
776 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
781 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_start_in_tolerance";
783 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
786 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
789 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
790 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
795 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_goal_in_tolerance";
797 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
800 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
803 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
804 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
809 test_case =
"testCartesianTrajectories.put_second.fetch_non_matching_in_tolerance";
811 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
814 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
817 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
818 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
820 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
822 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
824 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
825 "Fetched trajectory has correct execution time");
827 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
828 "Fetched trajectory has correct planning time");
830 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
836 test_case =
"testCartesianTrajectories.put_second.fetch_higher_fraction";
838 fetched_trajectories =
839 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 1, 999, 999);
841 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, 1, 999, 999);
843 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
844 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
850 test_case =
"testCartesianTrajectories.put_second.fetch_lower_fraction";
852 fetched_trajectories =
853 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999);
855 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999);
857 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
858 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
860 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
862 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
864 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
865 "Fetched trajectory has correct execution time");
867 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
868 "Fetched trajectory has correct planning time");
870 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
875 test_case =
"testCartesianTrajectories.put_worse";
876 double worse_execution_time = execution_time + 100;
879 worse_execution_time, planning_time, fraction,
false),
880 test_case,
"Put worse trajectory, no prune_worse_trajectories, not ok");
887 test_case =
"testCartesianTrajectories.put_better";
888 double better_execution_time = execution_time - 100;
891 better_execution_time, planning_time, fraction,
false),
892 test_case,
"Put better trajectory, no prune_worse_trajectories, ok");
894 checkAndEmit(cache->countCartesianTrajectories(
ROBOT_NAME) == 3, test_case,
"Three trajectories in cache");
899 test_case =
"testCartesianTrajectories.put_better.fetch_sorted";
901 fetched_trajectories =
902 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
905 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
907 checkAndEmit(fetched_trajectories.size() == 3, test_case,
"Fetch all returns three");
908 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
910 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
912 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
914 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
915 "Fetched trajectory has correct execution time");
917 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
918 "Fetched trajectory has correct planning time");
920 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
922 checkAndEmit(fetched_trajectories.at(0)->lookupDouble(
"execution_time_s") == better_execution_time &&
923 fetched_trajectories.at(1)->lookupDouble(
"execution_time_s") == execution_time,
924 test_case,
"Fetched trajectories are sorted correctly");
929 test_case =
"testCartesianTrajectories.put_better_prune_worse_trajectories";
930 double even_better_execution_time = better_execution_time - 100;
933 even_better_execution_time, planning_time, fraction,
true),
934 test_case,
"Put better trajectory, prune_worse_trajectories, ok");
939 test_case =
"testCartesianTrajectories.put_better_prune_worse_trajectories.fetch";
941 fetched_trajectories =
942 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
945 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
947 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
948 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
950 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
952 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
954 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == even_better_execution_time, test_case,
955 "Fetched trajectory has correct execution time");
957 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
958 "Fetched trajectory has correct planning time");
960 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
965 test_case =
"testCartesianTrajectories.put_different_req";
968 better_execution_time, planning_time, fraction,
true),
969 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
976 test_case =
"testCartesianTrajectories.put_different_req.fetch";
979 different_cartesian_plan_req, fraction, 0, 0);
981 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, different_cartesian_plan_req,
984 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
985 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
987 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
989 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
991 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
992 "Fetched trajectory has correct execution time");
994 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
995 "Fetched trajectory has correct planning time");
997 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
1002 test_case =
"testCartesianTrajectories.different_robot.empty";
1003 std::string different_robot_name =
"different_robot";
1005 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 0, test_case,
"No trajectories in cache");
1010 test_case =
"testCartesianTrajectories.different_robot.put_first";
1011 checkAndEmit(cache->insertCartesianTrajectory(*
move_group, different_robot_name, different_cartesian_plan_req,
1012 different_traj, better_execution_time, planning_time, fraction,
true),
1013 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
1015 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 1, test_case,
"One trajectory in cache");
1018 "Two trajectories in original robot's cache");
1021 different_cartesian_plan_req, fraction, 0, 0);
1023 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all on original still returns one");
1029 rclcpp::init(argc, argv);
1031 rclcpp::NodeOptions test_node_options;
1032 test_node_options.automatically_declare_parameters_from_overrides(
true);
1033 test_node_options.arguments({
"--ros-args",
"-r",
"__node:=test_node" });
1035 rclcpp::NodeOptions move_group_node_options;
1036 move_group_node_options.automatically_declare_parameters_from_overrides(
true);
1037 move_group_node_options.arguments({
"--ros-args",
"-r",
"__node:=move_group_node" });
1039 auto test_node = rclcpp::Node::make_shared(
"test_node", test_node_options);
1040 auto move_group_node = rclcpp::Node::make_shared(
"move_group_node", move_group_node_options);
1042 std::atomic<bool> running =
true;
1044 std::thread spin_thread([&]() {
1045 while (rclcpp::ok() && running)
1047 rclcpp::spin_some(test_node);
1048 rclcpp::spin_some(move_group_node);
1053 test_node->declare_parameter<std::string>(
"warehouse_plugin",
"warehouse_ros_sqlite::DatabaseConnection");
1058 auto move_group = std::make_shared<MoveGroupInterface>(move_group_node,
"panda_arm");
1059 auto curr_state =
move_group->getCurrentState(60);
1062 auto cache = std::make_shared<TrajectoryCache>(test_node);
1064 TrajectoryCache::Options
options;
1067 options.exact_match_precision = 10;
1068 options.num_additional_trajectories_to_preserve_when_deleting_worse = 10;
1076 cache->setExactMatchPrecision(1e-4);
1077 cache->setNumAdditionalTrajectoriesToPreserveWhenDeletingWorse(0);
1087 move_group_node.reset();
Client class to conveniently use the ROS interfaces provided by the move_group node.
Trajectory Cache manager for MoveIt.
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
const std::string ROBOT_NAME
int main(int argc, char **argv)
void testGettersAndSetters(const std::shared_ptr< TrajectoryCache > &cache)
void testMotionTrajectories(const std::shared_ptr< MoveGroupInterface > &move_group, const std::shared_ptr< TrajectoryCache > &cache)
const std::string ROBOT_FRAME
std::vector< geometry_msgs::msg::Pose > getDummyWaypoints()
void testCartesianTrajectories(const std::shared_ptr< MoveGroupInterface > &move_group, const std::shared_ptr< TrajectoryCache > &cache)
void checkAndEmit(bool predicate, const std::string &test_case, const std::string &label)
moveit_msgs::msg::RobotTrajectory getDummyPandaTraj()
Fuzzy-Matching Trajectory Cache.