26#include <warehouse_ros/message_collection.h>
28#include <rclcpp/rclcpp.hpp>
29#include <rclcpp/logging.hpp>
34namespace trajectory_cache
37using warehouse_ros::MessageWithMetadata;
38using warehouse_ros::Metadata;
39using warehouse_ros::Query;
49 const moveit_msgs::msg::WorkspaceParameters& workspace_parameters)
51 if (workspace_parameters.header.frame_id.empty())
53 return move_group.getRobotModel()->getModelFrame();
57 return workspace_parameters.header.frame_id;
66 const moveit_msgs::srv::GetCartesianPath::Request& path_request)
68 if (path_request.header.frame_id.empty())
74 return path_request.header.frame_id;
81 query.appendRangeInclusive(name, center - tolerance / 2, center + tolerance / 2);
85void sortConstraints(std::vector<moveit_msgs::msg::JointConstraint>& joint_constraints,
86 std::vector<moveit_msgs::msg::PositionConstraint>& position_constraints,
87 std::vector<moveit_msgs::msg::OrientationConstraint>& orientation_constraints)
89 std::sort(joint_constraints.begin(), joint_constraints.end(),
90 [](
const moveit_msgs::msg::JointConstraint& l,
const moveit_msgs::msg::JointConstraint& r) {
91 return l.joint_name < r.joint_name;
94 std::sort(position_constraints.begin(), position_constraints.end(),
95 [](
const moveit_msgs::msg::PositionConstraint& l,
const moveit_msgs::msg::PositionConstraint& r) {
96 return l.link_name < r.link_name;
99 std::sort(orientation_constraints.begin(), orientation_constraints.end(),
100 [](
const moveit_msgs::msg::OrientationConstraint& l,
const moveit_msgs::msg::OrientationConstraint& r) {
101 return l.link_name < r.link_name;
108 : node_(node), logger_(
moveit::getLogger(
"moveit.ros.trajectory_cache"))
110 tf_buffer_ = std::make_unique<tf2_ros::Buffer>(node_->get_clock());
111 tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
116 RCLCPP_DEBUG(logger_,
"Opening trajectory cache database at: %s (Port: %d, Precision: %f)", options.db_path.c_str(),
117 options.db_port, options.exact_match_precision);
124 db_->setParams(options.db_path, options.db_port);
125 return db_->connect();
130 auto coll = db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_trajectory_cache", cache_namespace);
137 db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_cartesian_trajectory_cache", cache_namespace);
171 size_t num_additional_trajectories_to_preserve_when_deleting_worse)
174 num_additional_trajectories_to_preserve_when_deleting_worse;
181std::vector<MessageWithMetadata<moveit_msgs::msg::RobotTrajectory>::ConstPtr>
183 const std::string& cache_namespace,
184 const moveit_msgs::msg::MotionPlanRequest& plan_request,
185 double start_tolerance,
double goal_tolerance,
bool metadata_only,
186 const std::string& sort_by,
bool ascending)
const
188 auto coll = db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_trajectory_cache", cache_namespace);
190 Query::Ptr query = coll.createQuery();
192 bool start_ok = this->extractAndAppendTrajectoryStartToQuery(*query,
move_group, plan_request, start_tolerance);
193 bool goal_ok = this->extractAndAppendTrajectoryGoalToQuery(*query,
move_group, plan_request, goal_tolerance);
195 if (!start_ok || !goal_ok)
197 RCLCPP_ERROR(logger_,
"Could not construct trajectory query.");
201 return coll.queryList(query, metadata_only, sort_by, ascending);
206 const moveit_msgs::msg::MotionPlanRequest& plan_request,
double start_tolerance,
double goal_tolerance,
207 bool metadata_only,
const std::string& sort_by,
bool ascending)
const
212 move_group, cache_namespace, plan_request, start_tolerance, goal_tolerance,
true, sort_by, ascending);
214 if (matching_trajectories.empty())
216 RCLCPP_DEBUG(logger_,
"No matching trajectories found.");
220 auto coll = db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_trajectory_cache", cache_namespace);
224 int best_trajectory_id = matching_trajectories.at(0)->lookupInt(
"id");
225 Query::Ptr best_query = coll.createQuery();
226 best_query->append(
"id", best_trajectory_id);
228 return coll.findOne(best_query, metadata_only);
232 const std::string& cache_namespace,
233 const moveit_msgs::msg::MotionPlanRequest& plan_request,
234 const moveit_msgs::msg::RobotTrajectory& trajectory,
double execution_time_s,
235 double planning_time_s,
bool prune_worse_trajectories)
240 if (!trajectory.multi_dof_joint_trajectory.points.empty())
242 RCLCPP_ERROR(logger_,
"Skipping plan insert: Multi-DOF trajectory plans are not supported.");
245 if (workspace_frame_id.empty())
247 RCLCPP_ERROR(logger_,
"Skipping plan insert: Workspace frame ID cannot be empty.");
250 if (trajectory.joint_trajectory.header.frame_id.empty())
252 RCLCPP_ERROR(logger_,
"Skipping plan insert: Trajectory frame ID cannot be empty.");
255 if (workspace_frame_id != trajectory.joint_trajectory.header.frame_id)
257 RCLCPP_ERROR(logger_,
258 "Skipping plan insert: "
259 "Plan request frame (%s) does not match plan frame (%s).",
260 workspace_frame_id.c_str(), trajectory.joint_trajectory.header.frame_id.c_str());
264 auto coll = db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_trajectory_cache", cache_namespace);
267 Query::Ptr exact_query = coll.createQuery();
269 bool start_query_ok = this->extractAndAppendTrajectoryStartToQuery(*exact_query,
move_group, plan_request, 0);
270 bool goal_query_ok = this->extractAndAppendTrajectoryGoalToQuery(*exact_query,
move_group, plan_request, 0);
272 if (!start_query_ok || !goal_query_ok)
274 RCLCPP_ERROR(logger_,
"Skipping plan insert: Could not construct lookup query.");
279 coll.queryList(exact_query,
true,
"execution_time_s",
true);
281 double best_execution_time = std::numeric_limits<double>::infinity();
282 if (!exact_matches.empty())
284 best_execution_time = exact_matches.at(0)->lookupDouble(
"execution_time_s");
286 if (prune_worse_trajectories)
288 size_t preserved_count = 0;
289 for (
auto& match : exact_matches)
291 double match_execution_time_s = match->lookupDouble(
"execution_time_s");
293 execution_time_s < match_execution_time_s)
295 int delete_id = match->lookupInt(
"id");
296 RCLCPP_DEBUG(logger_,
297 "Overwriting plan (id: %d): "
298 "execution_time (%es) > new trajectory's execution_time (%es)",
299 delete_id, match_execution_time_s, execution_time_s);
301 Query::Ptr delete_query = coll.createQuery();
302 delete_query->append(
"id", delete_id);
303 coll.removeMessages(delete_query);
310 if (execution_time_s < best_execution_time)
312 Metadata::Ptr insert_metadata = coll.createMetadata();
314 bool start_meta_ok = this->extractAndAppendTrajectoryStartToMetadata(*insert_metadata,
move_group, plan_request);
315 bool goal_meta_ok = this->extractAndAppendTrajectoryGoalToMetadata(*insert_metadata,
move_group, plan_request);
316 insert_metadata->append(
"execution_time_s", execution_time_s);
317 insert_metadata->append(
"planning_time_s", planning_time_s);
319 if (!start_meta_ok || !goal_meta_ok)
321 RCLCPP_ERROR(logger_,
"Skipping plan insert: Could not construct insert metadata.");
325 RCLCPP_DEBUG(logger_,
326 "Inserting trajectory: New trajectory execution_time (%es) "
327 "is better than best trajectory's execution_time (%es)",
328 execution_time_s, best_execution_time);
330 coll.insert(trajectory, insert_metadata);
334 RCLCPP_DEBUG(logger_,
335 "Skipping plan insert: New trajectory execution_time (%es) "
336 "is worse than best trajectory's execution_time (%es)",
337 execution_time_s, best_execution_time);
345moveit_msgs::srv::GetCartesianPath::Request
347 const std::vector<geometry_msgs::msg::Pose>& waypoints,
348 double max_step,
double jump_threshold,
bool avoid_collisions)
350 moveit_msgs::srv::GetCartesianPath::Request out;
352 move_group.constructRobotState(out.start_state);
355 out.max_velocity_scaling_factor =
move_group.getMaxVelocityScalingFactor();
356 out.max_acceleration_scaling_factor =
move_group.getMaxVelocityScalingFactor();
358 out.header.frame_id =
move_group.getPoseReferenceFrame();
359 out.waypoints = waypoints;
360 out.max_step = max_step;
361 out.jump_threshold = jump_threshold;
362 out.path_constraints = moveit_msgs::msg::Constraints();
363 out.avoid_collisions = avoid_collisions;
364 out.link_name =
move_group.getEndEffectorLink();
365 out.header.stamp =
move_group.getNode()->now();
370std::vector<MessageWithMetadata<moveit_msgs::msg::RobotTrajectory>::ConstPtr>
372 const std::string& cache_namespace,
373 const moveit_msgs::srv::GetCartesianPath::Request& plan_request,
374 double min_fraction,
double start_tolerance,
375 double goal_tolerance,
bool metadata_only,
376 const std::string& sort_by,
bool ascending)
const
379 db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_cartesian_trajectory_cache", cache_namespace);
381 Query::Ptr query = coll.createQuery();
384 this->extractAndAppendCartesianTrajectoryStartToQuery(*query,
move_group, plan_request, start_tolerance);
385 bool goal_ok = this->extractAndAppendCartesianTrajectoryGoalToQuery(*query,
move_group, plan_request, goal_tolerance);
387 if (!start_ok || !goal_ok)
389 RCLCPP_ERROR(logger_,
"Could not construct cartesian trajectory query.");
393 query->appendGTE(
"fraction", min_fraction);
394 return coll.queryList(query, metadata_only, sort_by, ascending);
399 const moveit_msgs::srv::GetCartesianPath::Request& plan_request,
double min_fraction,
double start_tolerance,
400 double goal_tolerance,
bool metadata_only,
const std::string& sort_by,
bool ascending)
const
404 auto matching_trajectories =
406 start_tolerance, goal_tolerance,
true, sort_by, ascending);
408 if (matching_trajectories.empty())
410 RCLCPP_DEBUG(logger_,
"No matching cartesian trajectories found.");
415 db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_cartesian_trajectory_cache", cache_namespace);
419 int best_trajectory_id = matching_trajectories.at(0)->lookupInt(
"id");
420 Query::Ptr best_query = coll.createQuery();
421 best_query->append(
"id", best_trajectory_id);
423 return coll.findOne(best_query, metadata_only);
427 const std::string& cache_namespace,
428 const moveit_msgs::srv::GetCartesianPath::Request& plan_request,
429 const moveit_msgs::msg::RobotTrajectory& trajectory,
430 double execution_time_s,
double planning_time_s,
double fraction,
431 bool prune_worse_trajectories)
436 if (!trajectory.multi_dof_joint_trajectory.points.empty())
438 RCLCPP_ERROR(logger_,
"Skipping cartesian trajectory insert: "
439 "Multi-DOF trajectory plans are not supported.");
442 if (path_request_frame_id.empty())
444 RCLCPP_ERROR(logger_,
"Skipping cartesian trajectory insert: Path request frame ID cannot be empty.");
447 if (trajectory.joint_trajectory.header.frame_id.empty())
449 RCLCPP_ERROR(logger_,
"Skipping cartesian trajectory insert: Trajectory frame ID cannot be empty.");
454 db_->openCollection<moveit_msgs::msg::RobotTrajectory>(
"move_group_cartesian_trajectory_cache", cache_namespace);
457 Query::Ptr exact_query = coll.createQuery();
459 bool start_query_ok =
460 this->extractAndAppendCartesianTrajectoryStartToQuery(*exact_query,
move_group, plan_request, 0);
461 bool goal_query_ok = this->extractAndAppendCartesianTrajectoryGoalToQuery(*exact_query,
move_group, plan_request, 0);
462 exact_query->append(
"fraction", fraction);
464 if (!start_query_ok || !goal_query_ok)
466 RCLCPP_ERROR(logger_,
"Skipping cartesian trajectory insert: Could not construct lookup query.");
471 coll.queryList(exact_query,
true,
"execution_time_s",
true);
472 double best_execution_time = std::numeric_limits<double>::infinity();
473 if (!exact_matches.empty())
475 best_execution_time = exact_matches.at(0)->lookupDouble(
"execution_time_s");
477 if (prune_worse_trajectories)
479 size_t preserved_count = 0;
480 for (
auto& match : exact_matches)
482 double match_execution_time_s = match->lookupDouble(
"execution_time_s");
484 execution_time_s < match_execution_time_s)
486 int delete_id = match->lookupInt(
"id");
487 RCLCPP_DEBUG(logger_,
488 "Overwriting cartesian trajectory (id: %d): "
489 "execution_time (%es) > new trajectory's execution_time (%es)",
490 delete_id, match_execution_time_s, execution_time_s);
492 Query::Ptr delete_query = coll.createQuery();
493 delete_query->append(
"id", delete_id);
494 coll.removeMessages(delete_query);
501 if (execution_time_s < best_execution_time)
503 Metadata::Ptr insert_metadata = coll.createMetadata();
506 this->extractAndAppendCartesianTrajectoryStartToMetadata(*insert_metadata,
move_group, plan_request);
508 this->extractAndAppendCartesianTrajectoryGoalToMetadata(*insert_metadata,
move_group, plan_request);
509 insert_metadata->append(
"execution_time_s", execution_time_s);
510 insert_metadata->append(
"planning_time_s", planning_time_s);
511 insert_metadata->append(
"fraction", fraction);
513 if (!start_meta_ok || !goal_meta_ok)
515 RCLCPP_ERROR(logger_,
"Skipping cartesian trajectory insert: "
516 "Could not construct insert metadata.");
520 RCLCPP_DEBUG(logger_,
521 "Inserting cartesian trajectory: New trajectory execution_time (%es) "
522 "is better than best trajectory's execution_time (%es) at fraction (%es)",
523 execution_time_s, best_execution_time, fraction);
525 coll.insert(trajectory, insert_metadata);
529 RCLCPP_DEBUG(logger_,
530 "Skipping cartesian trajectory insert: New trajectory execution_time (%es) "
531 "is worse than best trajectory's execution_time (%es) at fraction (%es)",
532 execution_time_s, best_execution_time, fraction);
542bool TrajectoryCache::extractAndAppendTrajectoryStartToQuery(
544 const moveit_msgs::msg::MotionPlanRequest& plan_request,
double match_tolerance)
const
550 if (!plan_request.start_state.multi_dof_joint_state.joint_names.empty())
552 RCLCPP_WARN(logger_,
"Ignoring start_state.multi_dof_joint_states: Not supported.");
554 if (!plan_request.start_state.attached_collision_objects.empty())
556 RCLCPP_WARN(logger_,
"Ignoring start_state.attached_collision_objects: Not supported.");
559 query.append(
"group_name", plan_request.group_name);
563 query.append(
"workspace_parameters.header.frame_id", workspace_frame_id);
564 query.appendGTE(
"workspace_parameters.min_corner.x", plan_request.workspace_parameters.min_corner.x);
565 query.appendGTE(
"workspace_parameters.min_corner.y", plan_request.workspace_parameters.min_corner.y);
566 query.appendGTE(
"workspace_parameters.min_corner.z", plan_request.workspace_parameters.min_corner.z);
567 query.appendLTE(
"workspace_parameters.max_corner.x", plan_request.workspace_parameters.max_corner.x);
568 query.appendLTE(
"workspace_parameters.max_corner.y", plan_request.workspace_parameters.max_corner.y);
569 query.appendLTE(
"workspace_parameters.max_corner.z", plan_request.workspace_parameters.max_corner.z);
573 if (plan_request.start_state.is_diff)
589 moveit::core::RobotStatePtr current_state =
move_group.getCurrentState();
592 RCLCPP_WARN(logger_,
"Skipping start query append: Could not get robot state.");
599 moveit_msgs::msg::RobotState current_state_msg;
602 for (
size_t i = 0; i < current_state_msg.joint_state.name.size(); i++)
604 query.append(
"start_state.joint_state.name_" + std::to_string(i), current_state_msg.joint_state.name.at(i));
606 current_state_msg.joint_state.position.at(i), match_tolerance);
611 for (
size_t i = 0; i < plan_request.start_state.joint_state.name.size(); i++)
613 query.append(
"start_state.joint_state.name_" + std::to_string(i), plan_request.start_state.joint_state.name.at(i));
615 plan_request.start_state.joint_state.position.at(i), match_tolerance);
621bool TrajectoryCache::extractAndAppendTrajectoryGoalToQuery(
623 const moveit_msgs::msg::MotionPlanRequest& plan_request,
double match_tolerance)
const
629 bool emit_position_constraint_warning =
false;
630 for (
auto& constraint : plan_request.goal_constraints)
632 for (
auto& position_constraint : constraint.position_constraints)
634 if (!position_constraint.constraint_region.primitives.empty())
636 emit_position_constraint_warning =
true;
640 if (emit_position_constraint_warning)
645 if (emit_position_constraint_warning)
647 RCLCPP_WARN(logger_,
"Ignoring goal_constraints.position_constraints.constraint_region: "
654 plan_request.max_acceleration_scaling_factor, match_tolerance);
659 std::vector<moveit_msgs::msg::JointConstraint> joint_constraints;
660 std::vector<moveit_msgs::msg::PositionConstraint> position_constraints;
661 std::vector<moveit_msgs::msg::OrientationConstraint> orientation_constraints;
662 for (
auto& constraint : plan_request.goal_constraints)
664 for (
auto& joint_constraint : constraint.joint_constraints)
666 joint_constraints.push_back(joint_constraint);
668 for (
auto& position_constraint : constraint.position_constraints)
670 position_constraints.push_back(position_constraint);
672 for (
auto& orientation_constraint : constraint.orientation_constraints)
674 orientation_constraints.push_back(orientation_constraint);
678 sortConstraints(joint_constraints, position_constraints, orientation_constraints);
682 size_t joint_idx = 0;
683 for (
auto& constraint : joint_constraints)
685 std::string meta_name =
"goal_constraints.joint_constraints_" + std::to_string(joint_idx++);
687 query.append(meta_name +
".joint_name", constraint.joint_name);
689 query.appendGTE(meta_name +
".tolerance_above", constraint.tolerance_above);
690 query.appendLTE(meta_name +
".tolerance_below", constraint.tolerance_below);
696 if (!position_constraints.empty())
698 query.append(
"goal_constraints.position_constraints.header.frame_id", workspace_frame_id);
701 for (
auto& constraint : position_constraints)
703 std::string meta_name =
"goal_constraints.position_constraints_" + std::to_string(pos_idx++);
710 if (workspace_frame_id != constraint.header.frame_id)
715 tf_buffer_->lookupTransform(constraint.header.frame_id, workspace_frame_id, tf2::TimePointZero);
717 x_offset = transform.transform.translation.x;
718 y_offset = transform.transform.translation.y;
719 z_offset = transform.transform.translation.z;
721 catch (tf2::TransformException& ex)
724 "Skipping goal query append: "
725 "Could not get goal transform for translation %s to %s: %s",
726 workspace_frame_id.c_str(), constraint.header.frame_id.c_str(), ex.what());
735 query.append(meta_name +
".link_name", constraint.link_name);
738 x_offset + constraint.target_point_offset.x, match_tolerance);
740 y_offset + constraint.target_point_offset.y, match_tolerance);
742 z_offset + constraint.target_point_offset.z, match_tolerance);
749 if (!orientation_constraints.empty())
751 query.append(
"goal_constraints.orientation_constraints.header.frame_id", workspace_frame_id);
754 for (
auto& constraint : orientation_constraints)
756 std::string meta_name =
"goal_constraints.orientation_constraints_" + std::to_string(ori_idx++);
759 geometry_msgs::msg::Quaternion quat_offset;
765 if (workspace_frame_id != constraint.header.frame_id)
770 tf_buffer_->lookupTransform(constraint.header.frame_id, workspace_frame_id, tf2::TimePointZero);
772 quat_offset = transform.transform.rotation;
774 catch (tf2::TransformException& ex)
777 "Skipping goal query append: "
778 "Could not get goal transform for orientation %s to %s: %s",
779 workspace_frame_id.c_str(), constraint.header.frame_id.c_str(), ex.what());
788 query.append(meta_name +
".link_name", constraint.link_name);
791 tf2::Quaternion tf2_quat_frame_offset(quat_offset.x, quat_offset.y, quat_offset.z, quat_offset.w);
795 tf2::Quaternion tf2_quat_goal_offset(constraint.orientation.x, constraint.orientation.y, constraint.orientation.z,
796 constraint.orientation.w);
798 tf2_quat_frame_offset.normalize();
799 tf2_quat_goal_offset.normalize();
801 auto final_quat = tf2_quat_goal_offset * tf2_quat_frame_offset;
802 final_quat.normalize();
820bool TrajectoryCache::extractAndAppendTrajectoryStartToMetadata(
822 const moveit_msgs::msg::MotionPlanRequest& plan_request)
const
827 if (!plan_request.start_state.multi_dof_joint_state.joint_names.empty())
829 RCLCPP_WARN(logger_,
"Ignoring start_state.multi_dof_joint_states: Not supported.");
831 if (!plan_request.start_state.attached_collision_objects.empty())
833 RCLCPP_WARN(logger_,
"Ignoring start_state.attached_collision_objects: Not supported.");
836 metadata.append(
"group_name", plan_request.group_name);
839 metadata.append(
"workspace_parameters.header.frame_id", workspace_frame_id);
840 metadata.append(
"workspace_parameters.min_corner.x", plan_request.workspace_parameters.min_corner.x);
841 metadata.append(
"workspace_parameters.min_corner.y", plan_request.workspace_parameters.min_corner.y);
842 metadata.append(
"workspace_parameters.min_corner.z", plan_request.workspace_parameters.min_corner.z);
843 metadata.append(
"workspace_parameters.max_corner.x", plan_request.workspace_parameters.max_corner.x);
844 metadata.append(
"workspace_parameters.max_corner.y", plan_request.workspace_parameters.max_corner.y);
845 metadata.append(
"workspace_parameters.max_corner.z", plan_request.workspace_parameters.max_corner.z);
849 if (plan_request.start_state.is_diff)
865 moveit::core::RobotStatePtr current_state =
move_group.getCurrentState();
868 RCLCPP_WARN(logger_,
"Skipping start metadata append: Could not get robot state.");
875 moveit_msgs::msg::RobotState current_state_msg;
878 for (
size_t i = 0; i < current_state_msg.joint_state.name.size(); i++)
880 metadata.append(
"start_state.joint_state.name_" + std::to_string(i), current_state_msg.joint_state.name.at(i));
881 metadata.append(
"start_state.joint_state.position_" + std::to_string(i),
882 current_state_msg.joint_state.position.at(i));
887 for (
size_t i = 0; i < plan_request.start_state.joint_state.name.size(); i++)
889 metadata.append(
"start_state.joint_state.name_" + std::to_string(i),
890 plan_request.start_state.joint_state.name.at(i));
891 metadata.append(
"start_state.joint_state.position_" + std::to_string(i),
892 plan_request.start_state.joint_state.position.at(i));
899bool TrajectoryCache::extractAndAppendTrajectoryGoalToMetadata(
901 const moveit_msgs::msg::MotionPlanRequest& plan_request)
const
906 bool emit_position_constraint_warning =
false;
907 for (
auto& constraint : plan_request.goal_constraints)
909 for (
auto& position_constraint : constraint.position_constraints)
911 if (!position_constraint.constraint_region.primitives.empty())
913 emit_position_constraint_warning =
true;
917 if (emit_position_constraint_warning)
922 if (emit_position_constraint_warning)
924 RCLCPP_WARN(logger_,
"Ignoring goal_constraints.position_constraints.constraint_region: "
928 metadata.append(
"max_velocity_scaling_factor", plan_request.max_velocity_scaling_factor);
929 metadata.append(
"max_acceleration_scaling_factor", plan_request.max_acceleration_scaling_factor);
930 metadata.append(
"max_cartesian_speed", plan_request.max_cartesian_speed);
933 std::vector<moveit_msgs::msg::JointConstraint> joint_constraints;
934 std::vector<moveit_msgs::msg::PositionConstraint> position_constraints;
935 std::vector<moveit_msgs::msg::OrientationConstraint> orientation_constraints;
936 for (
auto& constraint : plan_request.goal_constraints)
938 for (
auto& joint_constraint : constraint.joint_constraints)
940 joint_constraints.push_back(joint_constraint);
942 for (
auto& position_constraint : constraint.position_constraints)
944 position_constraints.push_back(position_constraint);
946 for (
auto& orientation_constraint : constraint.orientation_constraints)
948 orientation_constraints.push_back(orientation_constraint);
952 sortConstraints(joint_constraints, position_constraints, orientation_constraints);
956 size_t joint_idx = 0;
957 for (
auto& constraint : joint_constraints)
959 std::string meta_name =
"goal_constraints.joint_constraints_" + std::to_string(joint_idx++);
961 metadata.append(meta_name +
".joint_name", constraint.joint_name);
962 metadata.append(meta_name +
".position", constraint.position);
963 metadata.append(meta_name +
".tolerance_above", constraint.tolerance_above);
964 metadata.append(meta_name +
".tolerance_below", constraint.tolerance_below);
968 if (!position_constraints.empty())
972 metadata.append(
"goal_constraints.position_constraints.header.frame_id", workspace_frame_id);
974 size_t position_idx = 0;
975 for (
auto& constraint : position_constraints)
977 std::string meta_name =
"goal_constraints.position_constraints_" + std::to_string(position_idx++);
984 if (workspace_frame_id != constraint.header.frame_id)
989 tf_buffer_->lookupTransform(constraint.header.frame_id, workspace_frame_id, tf2::TimePointZero);
991 x_offset = transform.transform.translation.x;
992 y_offset = transform.transform.translation.y;
993 z_offset = transform.transform.translation.z;
995 catch (tf2::TransformException& ex)
998 "Skipping goal metadata append: "
999 "Could not get goal transform for translation %s to %s: %s",
1000 workspace_frame_id.c_str(), constraint.header.frame_id.c_str(), ex.what());
1009 metadata.append(meta_name +
".link_name", constraint.link_name);
1011 metadata.append(meta_name +
".target_point_offset.x", x_offset + constraint.target_point_offset.x);
1012 metadata.append(meta_name +
".target_point_offset.y", y_offset + constraint.target_point_offset.y);
1013 metadata.append(meta_name +
".target_point_offset.z", z_offset + constraint.target_point_offset.z);
1018 if (!orientation_constraints.empty())
1022 metadata.append(
"goal_constraints.orientation_constraints.header.frame_id", workspace_frame_id);
1025 for (
auto& constraint : orientation_constraints)
1027 std::string meta_name =
"goal_constraints.orientation_constraints_" + std::to_string(ori_idx++);
1030 geometry_msgs::msg::Quaternion quat_offset;
1036 if (workspace_frame_id != constraint.header.frame_id)
1041 tf_buffer_->lookupTransform(constraint.header.frame_id, workspace_frame_id, tf2::TimePointZero);
1043 quat_offset = transform.transform.rotation;
1045 catch (tf2::TransformException& ex)
1047 RCLCPP_WARN(logger_,
1048 "Skipping goal metadata append: "
1049 "Could not get goal transform for orientation %s to %s: %s",
1050 workspace_frame_id.c_str(), constraint.header.frame_id.c_str(), ex.what());
1059 metadata.append(meta_name +
".link_name", constraint.link_name);
1062 tf2::Quaternion tf2_quat_frame_offset(quat_offset.x, quat_offset.y, quat_offset.z, quat_offset.w);
1066 tf2::Quaternion tf2_quat_goal_offset(constraint.orientation.x, constraint.orientation.y, constraint.orientation.z,
1067 constraint.orientation.w);
1069 tf2_quat_frame_offset.normalize();
1070 tf2_quat_goal_offset.normalize();
1072 auto final_quat = tf2_quat_goal_offset * tf2_quat_frame_offset;
1073 final_quat.normalize();
1075 metadata.append(meta_name +
".target_point_offset.x", final_quat.getX());
1076 metadata.append(meta_name +
".target_point_offset.y", final_quat.getY());
1077 metadata.append(meta_name +
".target_point_offset.z", final_quat.getZ());
1078 metadata.append(meta_name +
".target_point_offset.w", final_quat.getW());
1091bool TrajectoryCache::extractAndAppendCartesianTrajectoryStartToQuery(
1093 const moveit_msgs::srv::GetCartesianPath::Request& plan_request,
double match_tolerance)
const
1099 if (!plan_request.start_state.multi_dof_joint_state.joint_names.empty())
1101 RCLCPP_WARN(logger_,
"Ignoring start_state.multi_dof_joint_states: Not supported.");
1103 if (!plan_request.start_state.attached_collision_objects.empty())
1105 RCLCPP_WARN(logger_,
"Ignoring start_state.attached_collision_objects: Not supported.");
1108 query.append(
"group_name", plan_request.group_name);
1109 query.append(
"path_request.header.frame_id", path_request_frame_id);
1113 if (plan_request.start_state.is_diff)
1129 moveit::core::RobotStatePtr current_state =
move_group.getCurrentState();
1132 RCLCPP_WARN(logger_,
"Skipping start metadata append: Could not get robot state.");
1139 moveit_msgs::msg::RobotState current_state_msg;
1142 for (
size_t i = 0; i < current_state_msg.joint_state.name.size(); i++)
1144 query.append(
"start_state.joint_state.name_" + std::to_string(i), current_state_msg.joint_state.name.at(i));
1146 current_state_msg.joint_state.position.at(i), match_tolerance);
1151 for (
size_t i = 0; i < plan_request.start_state.joint_state.name.size(); i++)
1153 query.append(
"start_state.joint_state.name_" + std::to_string(i), plan_request.start_state.joint_state.name.at(i));
1155 plan_request.start_state.joint_state.position.at(i), match_tolerance);
1162bool TrajectoryCache::extractAndAppendCartesianTrajectoryGoalToQuery(
1164 const moveit_msgs::srv::GetCartesianPath::Request& plan_request,
double match_tolerance)
const
1170 if (!plan_request.path_constraints.joint_constraints.empty() ||
1171 !plan_request.path_constraints.position_constraints.empty() ||
1172 !plan_request.path_constraints.orientation_constraints.empty() ||
1173 !plan_request.path_constraints.visibility_constraints.empty())
1175 RCLCPP_WARN(logger_,
"Ignoring path_constraints: Not supported.");
1177 if (plan_request.avoid_collisions)
1179 RCLCPP_WARN(logger_,
"Ignoring avoid_collisions: Not supported.");
1185 plan_request.max_acceleration_scaling_factor, match_tolerance);
1191 std::string base_frame =
move_group.getRobotModel()->getModelFrame();
1194 double x_offset = 0;
1195 double y_offset = 0;
1196 double z_offset = 0;
1198 geometry_msgs::msg::Quaternion quat_offset;
1204 if (base_frame != path_request_frame_id)
1208 auto transform = tf_buffer_->lookupTransform(path_request_frame_id, base_frame, tf2::TimePointZero);
1210 x_offset = transform.transform.translation.x;
1211 y_offset = transform.transform.translation.y;
1212 z_offset = transform.transform.translation.z;
1213 quat_offset = transform.transform.rotation;
1215 catch (tf2::TransformException& ex)
1217 RCLCPP_WARN(logger_,
1218 "Skipping goal metadata append: "
1219 "Could not get goal transform for %s to %s: %s",
1220 base_frame.c_str(), path_request_frame_id.c_str(), ex.what());
1229 tf2::Quaternion tf2_quat_frame_offset(quat_offset.x, quat_offset.y, quat_offset.z, quat_offset.w);
1230 tf2_quat_frame_offset.normalize();
1232 size_t waypoint_idx = 0;
1233 for (
auto& waypoint : plan_request.waypoints)
1235 std::string meta_name =
"waypoints_" + std::to_string(waypoint_idx++);
1247 tf2::Quaternion tf2_quat_goal_offset(waypoint.orientation.x, waypoint.orientation.y, waypoint.orientation.z,
1248 waypoint.orientation.w);
1249 tf2_quat_goal_offset.normalize();
1251 auto final_quat = tf2_quat_goal_offset * tf2_quat_frame_offset;
1252 final_quat.normalize();
1260 query.append(
"link_name", plan_request.link_name);
1261 query.append(
"header.frame_id", base_frame);
1268bool TrajectoryCache::extractAndAppendCartesianTrajectoryStartToMetadata(
1270 const moveit_msgs::srv::GetCartesianPath::Request& plan_request)
const
1275 if (!plan_request.start_state.multi_dof_joint_state.joint_names.empty())
1277 RCLCPP_WARN(logger_,
"Ignoring start_state.multi_dof_joint_states: Not supported.");
1279 if (!plan_request.start_state.attached_collision_objects.empty())
1281 RCLCPP_WARN(logger_,
"Ignoring start_state.attached_collision_objects: Not supported.");
1284 metadata.append(
"group_name", plan_request.group_name);
1285 metadata.append(
"path_request.header.frame_id", path_request_frame_id);
1289 if (plan_request.start_state.is_diff)
1305 moveit::core::RobotStatePtr current_state =
move_group.getCurrentState();
1308 RCLCPP_WARN(logger_,
"Skipping start metadata append: Could not get robot state.");
1315 moveit_msgs::msg::RobotState current_state_msg;
1318 for (
size_t i = 0; i < current_state_msg.joint_state.name.size(); i++)
1320 metadata.append(
"start_state.joint_state.name_" + std::to_string(i), current_state_msg.joint_state.name.at(i));
1321 metadata.append(
"start_state.joint_state.position_" + std::to_string(i),
1322 current_state_msg.joint_state.position.at(i));
1327 for (
size_t i = 0; i < plan_request.start_state.joint_state.name.size(); i++)
1329 metadata.append(
"start_state.joint_state.name_" + std::to_string(i),
1330 plan_request.start_state.joint_state.name.at(i));
1331 metadata.append(
"start_state.joint_state.position_" + std::to_string(i),
1332 plan_request.start_state.joint_state.position.at(i));
1339bool TrajectoryCache::extractAndAppendCartesianTrajectoryGoalToMetadata(
1341 const moveit_msgs::srv::GetCartesianPath::Request& plan_request)
const
1346 if (!plan_request.path_constraints.joint_constraints.empty() ||
1347 !plan_request.path_constraints.position_constraints.empty() ||
1348 !plan_request.path_constraints.orientation_constraints.empty() ||
1349 !plan_request.path_constraints.visibility_constraints.empty())
1351 RCLCPP_WARN(logger_,
"Ignoring path_constraints: Not supported.");
1353 if (plan_request.avoid_collisions)
1355 RCLCPP_WARN(logger_,
"Ignoring avoid_collisions: Not supported.");
1358 metadata.append(
"max_velocity_scaling_factor", plan_request.max_velocity_scaling_factor);
1359 metadata.append(
"max_acceleration_scaling_factor", plan_request.max_acceleration_scaling_factor);
1360 metadata.append(
"max_step", plan_request.max_step);
1361 metadata.append(
"jump_threshold", plan_request.jump_threshold);
1365 std::string base_frame =
move_group.getRobotModel()->getModelFrame();
1368 double x_offset = 0;
1369 double y_offset = 0;
1370 double z_offset = 0;
1372 geometry_msgs::msg::Quaternion quat_offset;
1378 if (base_frame != path_request_frame_id)
1382 auto transform = tf_buffer_->lookupTransform(path_request_frame_id, base_frame, tf2::TimePointZero);
1384 x_offset = transform.transform.translation.x;
1385 y_offset = transform.transform.translation.y;
1386 z_offset = transform.transform.translation.z;
1387 quat_offset = transform.transform.rotation;
1389 catch (tf2::TransformException& ex)
1391 RCLCPP_WARN(logger_,
1392 "Skipping goal metadata append: "
1393 "Could not get goal transform for %s to %s: %s",
1394 base_frame.c_str(), path_request_frame_id.c_str(), ex.what());
1403 tf2::Quaternion tf2_quat_frame_offset(quat_offset.x, quat_offset.y, quat_offset.z, quat_offset.w);
1404 tf2_quat_frame_offset.normalize();
1406 size_t waypoint_idx = 0;
1407 for (
auto& waypoint : plan_request.waypoints)
1409 std::string meta_name =
"waypoints_" + std::to_string(waypoint_idx++);
1413 metadata.append(meta_name +
".position.x", x_offset + waypoint.position.x);
1414 metadata.append(meta_name +
".position.y", y_offset + waypoint.position.y);
1415 metadata.append(meta_name +
".position.z", z_offset + waypoint.position.z);
1418 tf2::Quaternion tf2_quat_goal_offset(waypoint.orientation.x, waypoint.orientation.y, waypoint.orientation.z,
1419 waypoint.orientation.w);
1420 tf2_quat_goal_offset.normalize();
1422 auto final_quat = tf2_quat_goal_offset * tf2_quat_frame_offset;
1423 final_quat.normalize();
1425 metadata.append(meta_name +
".orientation.x", final_quat.getX());
1426 metadata.append(meta_name +
".orientation.y", final_quat.getY());
1427 metadata.append(meta_name +
".orientation.z", final_quat.getZ());
1428 metadata.append(meta_name +
".orientation.w", final_quat.getW());
1431 metadata.append(
"link_name", plan_request.link_name);
1432 metadata.append(
"header.frame_id", base_frame);
Client class to conveniently use the ROS interfaces provided by the move_group node.
bool insertTrajectory(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::msg::MotionPlanRequest &plan_request, const moveit_msgs::msg::RobotTrajectory &trajectory, double execution_time_s, double planning_time_s, bool prune_worse_trajectories=true)
Inserts a trajectory into the database if it is the best matching trajectory seen so far.
unsigned countCartesianTrajectories(const std::string &cache_namespace)
Count the number of cartesian trajectories for a particular cache namespace.
unsigned countTrajectories(const std::string &cache_namespace)
Count the number of non-cartesian trajectories for a particular cache namespace.
void setNumAdditionalTrajectoriesToPreserveWhenDeletingWorse(size_t num_additional_trajectories_to_preserve_when_deleting_worse)
Set the number of additional trajectories to preserve when deleting worse trajectories.
TrajectoryCache(const rclcpp::Node::SharedPtr &node)
Constructs a TrajectoryCache.
double getExactMatchPrecision() const
Gets the exact match precision.
size_t getNumAdditionalTrajectoriesToPreserveWhenDeletingWorse() const
Get the number of trajectories to preserve when deleting worse trajectories.
void setExactMatchPrecision(double exact_match_precision)
Sets the exact match precision.
warehouse_ros::MessageWithMetadata< moveit_msgs::msg::RobotTrajectory >::ConstPtr fetchBestMatchingCartesianTrajectory(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::srv::GetCartesianPath::Request &plan_request, double min_fraction, double start_tolerance, double goal_tolerance, bool metadata_only=false, const std::string &sort_by="execution_time_s", bool ascending=true) const
Fetches the best cartesian trajectory that fits within the requested tolerances for start and goal co...
std::vector< warehouse_ros::MessageWithMetadata< moveit_msgs::msg::RobotTrajectory >::ConstPtr > fetchAllMatchingTrajectories(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::msg::MotionPlanRequest &plan_request, double start_tolerance, double goal_tolerance, bool metadata_only=false, const std::string &sort_by="execution_time_s", bool ascending=true) const
Fetches all plans that fit within the requested tolerances for start and goal conditions,...
warehouse_ros::MessageWithMetadata< moveit_msgs::msg::RobotTrajectory >::ConstPtr fetchBestMatchingTrajectory(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::msg::MotionPlanRequest &plan_request, double start_tolerance, double goal_tolerance, bool metadata_only=false, const std::string &sort_by="execution_time_s", bool ascending=true) const
Fetches the best trajectory that fits within the requested tolerances for start and goal conditions,...
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.
std::string getDbPath() const
Gets the database path.
std::vector< warehouse_ros::MessageWithMetadata< moveit_msgs::msg::RobotTrajectory >::ConstPtr > fetchAllMatchingCartesianTrajectories(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::srv::GetCartesianPath::Request &plan_request, double min_fraction, double start_tolerance, double goal_tolerance, bool metadata_only=false, const std::string &sort_by="execution_time_s", bool ascending=true) const
Fetches all cartesian trajectories that fit within the requested tolerances for start and goal condit...
bool init(const Options &options)
Initializes the TrajectoryCache.
bool insertCartesianTrajectory(const moveit::planning_interface::MoveGroupInterface &move_group, const std::string &cache_namespace, const moveit_msgs::srv::GetCartesianPath::Request &plan_request, const moveit_msgs::msg::RobotTrajectory &trajectory, double execution_time_s, double planning_time_s, double fraction, bool prune_worse_trajectories=true)
Inserts a cartesian trajectory into the database if it is the best matching cartesian trajectory seen...
uint32_t getDbPort() const
Gets the database port.
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
void queryAppendRangeInclusiveWithTolerance(Query &query, const std::string &name, double center, double tolerance)
std::string getWorkspaceFrameId(const moveit::planning_interface::MoveGroupInterface &move_group, const moveit_msgs::msg::WorkspaceParameters &workspace_parameters)
std::string getCartesianPathRequestFrameId(const moveit::planning_interface::MoveGroupInterface &move_group, const moveit_msgs::srv::GetCartesianPath::Request &path_request)
void sortConstraints(std::vector< moveit_msgs::msg::JointConstraint > &joint_constraints, std::vector< moveit_msgs::msg::PositionConstraint > &position_constraints, std::vector< moveit_msgs::msg::OrientationConstraint > &orientation_constraints)
warehouse_ros::DatabaseConnection::Ptr loadDatabase(const rclcpp::Node::SharedPtr &node)
Load a database connection.
Main namespace for MoveIt.
size_t num_additional_trajectories_to_preserve_when_deleting_worse
double exact_match_precision
Fuzzy-Matching Trajectory Cache.