19 #include <rclcpp/rclcpp.hpp>
38 void checkAndEmit(
bool predicate,
const std::string& test_case,
const std::string& label)
42 std::cout <<
"[PASS] " << test_case <<
": " << label <<
"\n";
46 std::cout <<
"[FAIL] " << test_case <<
": " << label <<
"\n";
52 static moveit_msgs::msg::RobotTrajectory out = []() {
53 moveit_msgs::msg::RobotTrajectory traj;
55 auto trajectory = &traj.joint_trajectory;
58 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint1");
59 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint2");
60 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint3");
61 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint4");
62 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint5");
63 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint6");
64 trajectory->joint_names.push_back(
ROBOT_NAME +
"_joint7");
66 trajectory->points.emplace_back();
67 trajectory->points.at(0).positions = { 0, 0, 0, 0, 0, 0 };
68 trajectory->points.at(0).velocities = { 0, 0, 0, 0, 0, 0 };
69 trajectory->points.at(0).accelerations = { 0, 0, 0, 0, 0, 0 };
70 trajectory->points.at(0).time_from_start.sec = 999999;
79 static std::vector<geometry_msgs::msg::Pose> out = []() {
80 std::vector<geometry_msgs::msg::Pose> waypoints;
81 for (
size_t i = 0; i < 3; i++)
83 waypoints.emplace_back();
84 waypoints.at(i).position.x = i;
85 waypoints.at(i).position.y = i;
86 waypoints.at(i).position.z = i;
87 waypoints.at(i).orientation.w = i;
88 waypoints.at(i).orientation.x = i + 0.1;
89 waypoints.at(i).orientation.y = i + 0.1;
90 waypoints.at(i).orientation.z = i + 0.1;
99 std::string test_case =
"getters_and_setters";
101 checkAndEmit(cache->getDbPath() ==
":memory:", test_case,
"getDbPath");
102 checkAndEmit(cache->getDbPort() == 0, test_case,
"getDbPort");
104 checkAndEmit(cache->getExactMatchPrecision() == 10, test_case,
"getExactMatchPrecision");
105 cache->setExactMatchPrecision(1);
106 checkAndEmit(cache->getExactMatchPrecision() == 1, test_case,
"getExactMatchPrecisionAfterSet");
108 checkAndEmit(cache->getNumAdditionalTrajectoriesToPreserveWhenPruningWorse() == 10, test_case,
109 "getNumAdditionalTrajectoriesToPreserveWhenPruningWorse");
110 cache->setNumAdditionalTrajectoriesToPreserveWhenPruningWorse(1);
111 checkAndEmit(cache->getNumAdditionalTrajectoriesToPreserveWhenPruningWorse() == 1, test_case,
112 "getNumAdditionalTrajectoriesToPreserveWhenPruningWorseAfterSet");
116 const std::shared_ptr<TrajectoryCache>& cache)
125 move_group->constructMotionPlanRequest(plan_req);
126 plan_req.workspace_parameters.header.frame_id =
ROBOT_FRAME;
127 plan_req.workspace_parameters.max_corner.x = 10;
128 plan_req.workspace_parameters.max_corner.y = 10;
129 plan_req.workspace_parameters.max_corner.z = 10;
130 plan_req.workspace_parameters.min_corner.x = -10;
131 plan_req.workspace_parameters.min_corner.y = -10;
132 plan_req.workspace_parameters.min_corner.z = -10;
133 plan_req.start_state.multi_dof_joint_state.joint_names.clear();
134 plan_req.start_state.multi_dof_joint_state.transforms.clear();
135 plan_req.start_state.multi_dof_joint_state.twist.clear();
136 plan_req.start_state.multi_dof_joint_state.wrench.clear();
140 empty_frame_plan_req.workspace_parameters.header.frame_id =
"";
143 auto is_diff_plan_req = plan_req;
144 is_diff_plan_req.start_state.is_diff =
true;
145 is_diff_plan_req.start_state.joint_state.header.frame_id =
"";
146 is_diff_plan_req.start_state.joint_state.name.clear();
147 is_diff_plan_req.start_state.joint_state.position.clear();
148 is_diff_plan_req.start_state.joint_state.velocity.clear();
149 is_diff_plan_req.start_state.joint_state.effort.clear();
152 auto close_matching_plan_req = plan_req;
153 close_matching_plan_req.workspace_parameters.max_corner.x += 0.05;
154 close_matching_plan_req.workspace_parameters.min_corner.x -= 0.05;
155 close_matching_plan_req.start_state.joint_state.position.at(0) -= 0.05;
156 close_matching_plan_req.start_state.joint_state.position.at(1) += 0.05;
157 close_matching_plan_req.start_state.joint_state.position.at(2) -= 0.05;
158 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(0).position -= 0.05;
159 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(1).position += 0.05;
160 close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(2).position -= 0.05;
163 auto swapped_close_matching_plan_req = close_matching_plan_req;
164 std::swap(swapped_close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(0),
165 swapped_close_matching_plan_req.goal_constraints.at(0).joint_constraints.at(1));
168 auto smaller_workspace_plan_req = plan_req;
169 smaller_workspace_plan_req.workspace_parameters.max_corner.x = 1;
170 smaller_workspace_plan_req.workspace_parameters.max_corner.y = 1;
171 smaller_workspace_plan_req.workspace_parameters.max_corner.z = 1;
172 smaller_workspace_plan_req.workspace_parameters.min_corner.x = -1;
173 smaller_workspace_plan_req.workspace_parameters.min_corner.y = -1;
174 smaller_workspace_plan_req.workspace_parameters.min_corner.z = -1;
177 auto larger_workspace_plan_req = plan_req;
178 larger_workspace_plan_req.workspace_parameters.max_corner.x = 50;
179 larger_workspace_plan_req.workspace_parameters.max_corner.y = 50;
180 larger_workspace_plan_req.workspace_parameters.max_corner.z = 50;
181 larger_workspace_plan_req.workspace_parameters.min_corner.x = -50;
182 larger_workspace_plan_req.workspace_parameters.min_corner.y = -50;
183 larger_workspace_plan_req.workspace_parameters.min_corner.z = -50;
186 auto different_plan_req = plan_req;
187 different_plan_req.workspace_parameters.max_corner.x += 1.05;
188 different_plan_req.workspace_parameters.min_corner.x -= 2.05;
189 different_plan_req.start_state.joint_state.position.at(0) -= 3.05;
190 different_plan_req.start_state.joint_state.position.at(1) += 4.05;
191 different_plan_req.start_state.joint_state.position.at(2) -= 5.05;
192 different_plan_req.goal_constraints.at(0).joint_constraints.at(0).position -= 6.05;
193 different_plan_req.goal_constraints.at(0).joint_constraints.at(1).position += 7.05;
194 different_plan_req.goal_constraints.at(0).joint_constraints.at(2).position -= 8.05;
202 auto empty_frame_traj = traj;
203 empty_frame_traj.joint_trajectory.header.frame_id =
"";
205 auto different_traj = traj;
206 different_traj.joint_trajectory.points.at(0).positions.at(0) = 999;
207 different_traj.joint_trajectory.points.at(0).positions.at(1) = 999;
208 different_traj.joint_trajectory.points.at(0).positions.at(2) = 999;
212 std::string test_case;
217 test_case =
"testMotionTrajectories.empty";
222 "Fetch all trajectories on empty cache returns empty");
225 "Fetch best trajectory on empty cache returns nullptr");
230 test_case =
"testMotionTrajectories.insertTrajectory_empty_frame";
231 double execution_time = 999;
232 double planning_time = 999;
235 planning_time,
false),
236 test_case,
"Put empty frame trajectory, no prune_worse_trajectories, not ok");
243 test_case =
"testMotionTrajectories.insertTrajectory_req_empty_frame";
244 execution_time = 1000;
245 planning_time = 1000;
248 planning_time,
false),
249 test_case,
"Put empty frame req trajectory, no prune_worse_trajectories, ok");
254 test_case =
"testMotionTrajectories.put_second";
255 execution_time = 999;
259 test_case,
"Put second valid trajectory, no prune_worse_trajectories, ok");
266 test_case =
"testMotionTrajectories.put_second.fetch_matching_no_tolerance";
268 auto fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
270 auto fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
272 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
273 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
275 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
277 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
279 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
280 "Fetched trajectory has correct execution time");
282 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
283 "Fetched trajectory has correct planning time");
289 test_case =
"testMotionTrajectories.put_second.fetch_is_diff_no_tolerance";
291 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, is_diff_plan_req, 0, 0);
293 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, is_diff_plan_req, 0, 0);
295 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
296 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
298 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
300 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
302 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
303 "Fetched trajectory has correct execution time");
305 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
306 "Fetched trajectory has correct planning time");
311 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_out_of_tolerance";
313 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 0);
315 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 0);
317 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
318 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
323 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_start_in_tolerance";
325 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 999, 0);
327 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 999, 0);
329 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
330 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
335 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_goal_in_tolerance";
337 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 999);
339 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0, 999);
341 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
342 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
347 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_in_tolerance";
349 fetched_trajectories =
350 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0.1, 0.1);
352 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, close_matching_plan_req, 0.1, 0.1);
354 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
355 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
357 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
359 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
361 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
362 "Fetched trajectory has correct execution time");
364 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
365 "Fetched trajectory has correct planning time");
370 test_case =
"testMotionTrajectories.put_second.fetch_swapped";
372 fetched_trajectories =
373 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, swapped_close_matching_plan_req, 0.1, 0.1);
375 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, swapped_close_matching_plan_req, 0.1, 0.1);
377 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
378 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
380 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
382 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
384 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
385 "Fetched trajectory has correct execution time");
387 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
388 "Fetched trajectory has correct planning time");
394 test_case =
"testMotionTrajectories.put_second.fetch_smaller_workspace";
396 fetched_trajectories =
397 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, smaller_workspace_plan_req, 999, 999);
399 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, smaller_workspace_plan_req, 999, 999);
401 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
402 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
408 test_case =
"testMotionTrajectories.put_second.fetch_larger_workspace";
410 fetched_trajectories =
411 cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, larger_workspace_plan_req, 999, 999);
413 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, larger_workspace_plan_req, 999, 999);
415 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
416 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
418 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
420 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
422 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
423 "Fetched trajectory has correct execution time");
425 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
426 "Fetched trajectory has correct planning time");
428 checkAndEmit(fetched_traj->lookupDouble(
"workspace_parameters.max_corner.x") <=
429 larger_workspace_plan_req.workspace_parameters.max_corner.x,
430 test_case,
"Fetched trajectory has more restrictive workspace max_corner");
432 checkAndEmit(fetched_traj->lookupDouble(
"workspace_parameters.max_corner.x") >=
433 larger_workspace_plan_req.workspace_parameters.min_corner.x,
434 test_case,
"Fetched trajectory has more restrictive workspace min_corner");
439 test_case =
"testMotionTrajectories.put_worse";
440 double worse_execution_time = execution_time + 100;
444 test_case,
"Put worse trajectory, no prune_worse_trajectories, not ok");
451 test_case =
"testMotionTrajectories.put_better";
452 double better_execution_time = execution_time - 100;
456 test_case,
"Put better trajectory, no prune_worse_trajectories, ok");
463 test_case =
"testMotionTrajectories.put_better.fetch_sorted";
465 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
469 checkAndEmit(fetched_trajectories.size() == 3, test_case,
"Fetch all returns three");
470 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
472 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
474 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
476 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
477 "Fetched trajectory has correct execution time");
479 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
480 "Fetched trajectory has correct planning time");
482 checkAndEmit(fetched_trajectories.at(0)->lookupDouble(
"execution_time_s") == better_execution_time &&
483 fetched_trajectories.at(1)->lookupDouble(
"execution_time_s") == execution_time,
484 test_case,
"Fetched trajectories are sorted correctly");
489 test_case =
"testMotionTrajectories.put_better_prune_worse_trajectories";
490 double even_better_execution_time = better_execution_time - 100;
493 planning_time,
true),
494 test_case,
"Put better trajectory, prune_worse_trajectories, ok");
499 test_case =
"testMotionTrajectories.put_better_prune_worse_trajectories.fetch";
501 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, plan_req, 0, 0);
505 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
506 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
508 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
510 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
512 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == even_better_execution_time, test_case,
513 "Fetched trajectory has correct execution time");
515 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
516 "Fetched trajectory has correct planning time");
521 test_case =
"testMotionTrajectories.put_different_req";
524 better_execution_time, planning_time,
true),
525 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
532 test_case =
"testMotionTrajectories.put_different_req.fetch";
534 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
536 fetched_traj = cache->fetchBestMatchingTrajectory(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
538 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
539 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
541 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
543 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
545 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
546 "Fetched trajectory has correct execution time");
548 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
549 "Fetched trajectory has correct planning time");
554 test_case =
"testMotionTrajectories.different_robot.empty";
555 std::string different_robot_name =
"different_robot";
557 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 0, test_case,
"No trajectories in cache");
562 test_case =
"testMotionTrajectories.different_robot.put_first";
563 checkAndEmit(cache->insertTrajectory(*
move_group, different_robot_name, different_plan_req, different_traj,
564 better_execution_time, planning_time,
true),
565 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
567 checkAndEmit(cache->countTrajectories(different_robot_name) == 1, test_case,
"One trajectory in cache");
569 checkAndEmit(cache->countTrajectories(
ROBOT_NAME) == 2, test_case,
"Two trajectories in original robot's cache");
571 fetched_trajectories = cache->fetchAllMatchingTrajectories(*
move_group,
ROBOT_NAME, different_plan_req, 0, 0);
573 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all on original still returns one");
577 const std::shared_ptr<TrajectoryCache>& cache)
579 std::string test_case;
584 test_case =
"testCartesianTrajectories.constructGetCartesianPathRequest";
589 auto cartesian_plan_req_under_test =
592 checkAndEmit(cartesian_plan_req_under_test.waypoints == test_waypoints &&
593 static_cast<int>(cartesian_plan_req_under_test.max_step) == test_step &&
594 static_cast<int>(cartesian_plan_req_under_test.jump_threshold) == test_jump &&
595 !cartesian_plan_req_under_test.avoid_collisions,
606 cartesian_plan_req.start_state.multi_dof_joint_state.joint_names.clear();
607 cartesian_plan_req.start_state.multi_dof_joint_state.transforms.clear();
608 cartesian_plan_req.start_state.multi_dof_joint_state.twist.clear();
609 cartesian_plan_req.start_state.multi_dof_joint_state.wrench.clear();
610 cartesian_plan_req.path_constraints.joint_constraints.clear();
611 cartesian_plan_req.path_constraints.position_constraints.clear();
612 cartesian_plan_req.path_constraints.orientation_constraints.clear();
613 cartesian_plan_req.path_constraints.visibility_constraints.clear();
616 auto empty_frame_cartesian_plan_req = cartesian_plan_req;
617 empty_frame_cartesian_plan_req.header.frame_id =
"";
620 auto is_diff_cartesian_plan_req = cartesian_plan_req;
621 is_diff_cartesian_plan_req.start_state.is_diff =
true;
622 is_diff_cartesian_plan_req.start_state.joint_state.header.frame_id =
"";
623 is_diff_cartesian_plan_req.start_state.joint_state.name.clear();
624 is_diff_cartesian_plan_req.start_state.joint_state.position.clear();
625 is_diff_cartesian_plan_req.start_state.joint_state.velocity.clear();
626 is_diff_cartesian_plan_req.start_state.joint_state.effort.clear();
629 auto close_matching_cartesian_plan_req = cartesian_plan_req;
630 close_matching_cartesian_plan_req.start_state.joint_state.position.at(0) -= 0.05;
631 close_matching_cartesian_plan_req.start_state.joint_state.position.at(1) += 0.05;
632 close_matching_cartesian_plan_req.start_state.joint_state.position.at(2) -= 0.05;
633 close_matching_cartesian_plan_req.waypoints.at(0).position.x -= 0.05;
634 close_matching_cartesian_plan_req.waypoints.at(1).position.x += 0.05;
635 close_matching_cartesian_plan_req.waypoints.at(2).position.x -= 0.05;
638 auto different_cartesian_plan_req = cartesian_plan_req;
639 different_cartesian_plan_req.start_state.joint_state.position.at(0) -= 1.05;
640 different_cartesian_plan_req.start_state.joint_state.position.at(1) += 2.05;
641 different_cartesian_plan_req.start_state.joint_state.position.at(2) -= 3.05;
642 different_cartesian_plan_req.waypoints.at(0).position.x -= 1.05;
643 different_cartesian_plan_req.waypoints.at(1).position.x += 2.05;
644 different_cartesian_plan_req.waypoints.at(2).position.x -= 3.05;
652 auto empty_frame_traj = traj;
653 empty_frame_traj.joint_trajectory.header.frame_id =
"";
655 auto different_traj = traj;
656 different_traj.joint_trajectory.points.at(0).positions.at(0) = 999;
657 different_traj.joint_trajectory.points.at(0).positions.at(1) = 999;
658 different_traj.joint_trajectory.points.at(0).positions.at(2) = 999;
663 test_case =
"testCartesianTrajectories.empty";
665 checkAndEmit(cache->countCartesianTrajectories(
ROBOT_NAME) == 0, test_case,
"Trajectory cache initially empty");
668 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999).empty(),
669 test_case,
"Fetch all trajectories on empty cache returns empty");
673 test_case,
"Fetch best trajectory on empty cache returns nullptr");
678 test_case =
"testCartesianTrajectories.insertTrajectory_empty_frame";
679 double execution_time = 999;
680 double planning_time = 999;
681 double fraction = 0.5;
684 execution_time, planning_time, fraction,
false),
685 test_case,
"Put empty frame trajectory, no prune_worse_trajectories, not ok");
692 test_case =
"testCartesianTrajectories.insertTrajectory_req_empty_frame";
693 execution_time = 1000;
694 planning_time = 1000;
697 execution_time, planning_time, fraction,
false),
698 test_case,
"Put empty frame req trajectory, no prune_worse_trajectories, ok");
703 test_case =
"testCartesianTrajectories.put_second";
704 execution_time = 999;
708 planning_time, fraction,
false),
709 test_case,
"Put second valid trajectory, no prune_worse_trajectories, ok");
716 test_case =
"testCartesianTrajectories.put_second.fetch_matching_no_tolerance";
718 auto fetched_trajectories =
719 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
722 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
724 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
725 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
727 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
729 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
731 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
732 "Fetched trajectory has correct execution time");
734 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
735 "Fetched trajectory has correct planning time");
737 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
743 test_case =
"testCartesianTrajectories.put_second.fetch_is_diff_no_tolerance";
745 fetched_trajectories =
746 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, is_diff_cartesian_plan_req, fraction, 0, 0);
749 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, is_diff_cartesian_plan_req, fraction, 0, 0);
751 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
752 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
754 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
756 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
758 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
759 "Fetched trajectory has correct execution time");
761 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
762 "Fetched trajectory has correct planning time");
764 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
769 test_case =
"testCartesianTrajectories.put_second.fetch_non_matching_out_of_tolerance";
771 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
774 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
777 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
778 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
783 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_start_in_tolerance";
785 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
788 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
791 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
792 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
797 test_case =
"testMotionTrajectories.put_second.fetch_non_matching_only_goal_in_tolerance";
799 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
802 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
805 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
806 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
811 test_case =
"testCartesianTrajectories.put_second.fetch_non_matching_in_tolerance";
813 fetched_trajectories = cache->fetchAllMatchingCartesianTrajectories(
816 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, close_matching_cartesian_plan_req,
819 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
820 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
822 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
824 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
826 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
827 "Fetched trajectory has correct execution time");
829 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
830 "Fetched trajectory has correct planning time");
832 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
838 test_case =
"testCartesianTrajectories.put_second.fetch_higher_fraction";
840 fetched_trajectories =
841 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 1, 999, 999);
843 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, 1, 999, 999);
845 checkAndEmit(fetched_trajectories.empty(), test_case,
"Fetch all returns empty");
846 checkAndEmit(fetched_traj ==
nullptr, test_case,
"Fetch best trajectory is nullptr");
852 test_case =
"testCartesianTrajectories.put_second.fetch_lower_fraction";
854 fetched_trajectories =
855 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999);
857 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, 0, 999, 999);
859 checkAndEmit(fetched_trajectories.size() == 2, test_case,
"Fetch all returns two");
860 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
862 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
864 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
866 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == execution_time, test_case,
867 "Fetched trajectory has correct execution time");
869 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
870 "Fetched trajectory has correct planning time");
872 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
877 test_case =
"testCartesianTrajectories.put_worse";
878 double worse_execution_time = execution_time + 100;
881 worse_execution_time, planning_time, fraction,
false),
882 test_case,
"Put worse trajectory, no prune_worse_trajectories, not ok");
889 test_case =
"testCartesianTrajectories.put_better";
890 double better_execution_time = execution_time - 100;
893 better_execution_time, planning_time, fraction,
false),
894 test_case,
"Put better trajectory, no prune_worse_trajectories, ok");
896 checkAndEmit(cache->countCartesianTrajectories(
ROBOT_NAME) == 3, test_case,
"Three trajectories in cache");
901 test_case =
"testCartesianTrajectories.put_better.fetch_sorted";
903 fetched_trajectories =
904 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
907 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
909 checkAndEmit(fetched_trajectories.size() == 3, test_case,
"Fetch all returns three");
910 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
912 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
914 checkAndEmit(*fetched_traj == traj, test_case,
"Fetched trajectory matches original");
916 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
917 "Fetched trajectory has correct execution time");
919 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
920 "Fetched trajectory has correct planning time");
922 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
924 checkAndEmit(fetched_trajectories.at(0)->lookupDouble(
"execution_time_s") == better_execution_time &&
925 fetched_trajectories.at(1)->lookupDouble(
"execution_time_s") == execution_time,
926 test_case,
"Fetched trajectories are sorted correctly");
931 test_case =
"testCartesianTrajectories.put_better_prune_worse_trajectories";
932 double even_better_execution_time = better_execution_time - 100;
935 even_better_execution_time, planning_time, fraction,
true),
936 test_case,
"Put better trajectory, prune_worse_trajectories, ok");
941 test_case =
"testCartesianTrajectories.put_better_prune_worse_trajectories.fetch";
943 fetched_trajectories =
944 cache->fetchAllMatchingCartesianTrajectories(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
947 cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, cartesian_plan_req, fraction, 0, 0);
949 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
950 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
952 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
954 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
956 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == even_better_execution_time, test_case,
957 "Fetched trajectory has correct execution time");
959 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
960 "Fetched trajectory has correct planning time");
962 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
967 test_case =
"testCartesianTrajectories.put_different_req";
970 better_execution_time, planning_time, fraction,
true),
971 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
978 test_case =
"testCartesianTrajectories.put_different_req.fetch";
981 different_cartesian_plan_req, fraction, 0, 0);
983 fetched_traj = cache->fetchBestMatchingCartesianTrajectory(*
move_group,
ROBOT_NAME, different_cartesian_plan_req,
986 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all returns one");
987 checkAndEmit(fetched_traj !=
nullptr, test_case,
"Fetch best trajectory is not nullptr");
989 checkAndEmit(*fetched_trajectories.at(0) == *fetched_traj, test_case,
"Fetched trajectory on both fetches match");
991 checkAndEmit(*fetched_traj == different_traj, test_case,
"Fetched trajectory matches original");
993 checkAndEmit(fetched_traj->lookupDouble(
"execution_time_s") == better_execution_time, test_case,
994 "Fetched trajectory has correct execution time");
996 checkAndEmit(fetched_traj->lookupDouble(
"planning_time_s") == planning_time, test_case,
997 "Fetched trajectory has correct planning time");
999 checkAndEmit(fetched_traj->lookupDouble(
"fraction") == fraction, test_case,
"Fetched trajectory has correct fraction");
1004 test_case =
"testCartesianTrajectories.different_robot.empty";
1005 std::string different_robot_name =
"different_robot";
1007 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 0, test_case,
"No trajectories in cache");
1012 test_case =
"testCartesianTrajectories.different_robot.put_first";
1013 checkAndEmit(cache->insertCartesianTrajectory(*
move_group, different_robot_name, different_cartesian_plan_req,
1014 different_traj, better_execution_time, planning_time, fraction,
true),
1015 test_case,
"Put different trajectory req, prune_worse_trajectories, ok");
1017 checkAndEmit(cache->countCartesianTrajectories(different_robot_name) == 1, test_case,
"One trajectory in cache");
1020 "Two trajectories in original robot's cache");
1023 different_cartesian_plan_req, fraction, 0, 0);
1025 checkAndEmit(fetched_trajectories.size() == 1, test_case,
"Fetch all on original still returns one");
1031 rclcpp::init(argc, argv);
1033 rclcpp::NodeOptions test_node_options;
1034 test_node_options.automatically_declare_parameters_from_overrides(
true);
1035 test_node_options.arguments({
"--ros-args",
"-r",
"__node:=test_node" });
1037 rclcpp::NodeOptions move_group_node_options;
1038 move_group_node_options.automatically_declare_parameters_from_overrides(
true);
1039 move_group_node_options.arguments({
"--ros-args",
"-r",
"__node:=move_group_node" });
1041 auto test_node = rclcpp::Node::make_shared(
"test_node", test_node_options);
1042 auto move_group_node = rclcpp::Node::make_shared(
"move_group_node", move_group_node_options);
1044 std::atomic<bool> running =
true;
1046 std::thread spin_thread([&]() {
1047 while (rclcpp::ok() && running)
1049 rclcpp::spin_some(test_node);
1050 rclcpp::spin_some(move_group_node);
1055 test_node->declare_parameter<std::string>(
"warehouse_plugin",
"warehouse_ros_sqlite::DatabaseConnection");
1060 auto move_group = std::make_shared<MoveGroupInterface>(move_group_node,
"panda_arm");
1061 auto curr_state =
move_group->getCurrentState(60);
1064 auto cache = std::make_shared<TrajectoryCache>(test_node);
1066 TrajectoryCache::Options
options;
1069 options.exact_match_precision = 10;
1070 options.num_additional_trajectories_to_preserve_when_pruning_worse = 10;
1078 cache->setExactMatchPrecision(1e-4);
1079 cache->setNumAdditionalTrajectoriesToPreserveWhenPruningWorse(0);
1089 move_group_node.reset();
Client class to conveniently use the ROS interfaces provided by the move_group node.
Trajectory Cache manager for MoveIt.
Utilities used by the trajectory_cache package.
moveit_msgs::srv::GetCartesianPath::Request constructGetCartesianPathRequest(moveit::planning_interface::MoveGroupInterface &move_group, const std::vector< geometry_msgs::msg::Pose > &waypoints, double max_step, double jump_threshold, bool avoid_collisions=true)
Constructs a GetCartesianPath request.
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.