41 #include <boost/tokenizer.hpp>
42 #include <boost/algorithm/string/join.hpp>
45 static const rclcpp::Logger
LOGGER = rclcpp::get_logger(
"moveit.ros_planning.planning_pipeline");
52 const std::shared_ptr<rclcpp::Node>& node,
53 const std::string& parameter_namespace,
54 const std::string& planner_plugin_param_name,
55 const std::string& adapter_plugins_param_name)
56 : node_(node), parameter_namespace_(parameter_namespace), robot_model_(model)
58 std::string planner_plugin_fullname = parameter_namespace_ +
"." + planner_plugin_param_name;
59 if (parameter_namespace_.empty())
60 planner_plugin_fullname = planner_plugin_param_name;
61 if (node_->has_parameter(planner_plugin_fullname))
63 node_->get_parameter(planner_plugin_fullname, planner_plugin_name_);
66 std::string adapter_plugins_fullname = parameter_namespace_ +
"." + adapter_plugins_param_name;
67 if (parameter_namespace_.empty())
68 adapter_plugins_fullname = adapter_plugins_param_name;
71 if (node_->has_parameter(adapter_plugins_fullname))
73 node_->get_parameter(adapter_plugins_fullname, adapters);
74 boost::char_separator<char> sep(
" ");
75 boost::tokenizer<boost::char_separator<char>> tok(adapters, sep);
76 for (boost::tokenizer<boost::char_separator<char>>::iterator beg = tok.begin(); beg != tok.end(); ++beg)
77 adapter_plugin_names_.push_back(*beg);
84 const std::shared_ptr<rclcpp::Node>& node,
85 const std::string& parameter_namespace,
86 const std::string& planner_plugin_name,
87 const std::vector<std::string>& adapter_plugin_names)
89 , parameter_namespace_(parameter_namespace)
90 , planner_plugin_name_(planner_plugin_name)
91 , adapter_plugin_names_(adapter_plugin_names)
97 void planning_pipeline::PlanningPipeline::configure()
99 check_solution_paths_ =
false;
100 publish_received_requests_ =
false;
101 display_computed_motion_plans_ =
false;
106 planner_plugin_loader_ = std::make_unique<pluginlib::ClassLoader<planning_interface::PlannerManager>>(
107 "moveit_core",
"planning_interface::PlannerManager");
109 catch (pluginlib::PluginlibException& ex)
111 RCLCPP_FATAL(LOGGER,
"Exception while creating planning plugin loader %s", ex.what());
114 std::vector<std::string> classes;
115 if (planner_plugin_loader_)
116 classes = planner_plugin_loader_->getDeclaredClasses();
117 if (planner_plugin_name_.empty() && classes.size() == 1)
119 planner_plugin_name_ = classes[0];
122 "No '~planning_plugin' parameter specified, but only '%s' planning plugin is available. Using that one.",
123 planner_plugin_name_.c_str());
125 if (planner_plugin_name_.empty() && classes.size() > 1)
127 planner_plugin_name_ = classes[0];
130 "Multiple planning plugins available. You should specify the '~planning_plugin' parameter. Using '%s' for "
132 planner_plugin_name_.c_str());
136 planner_instance_ = planner_plugin_loader_->createUniqueInstance(planner_plugin_name_);
137 if (!planner_instance_->initialize(robot_model_, node_, parameter_namespace_))
138 throw std::runtime_error(
"Unable to initialize planning plugin");
139 RCLCPP_INFO(LOGGER,
"Using planning interface '%s'", planner_instance_->getDescription().c_str());
141 catch (pluginlib::PluginlibException& ex)
143 std::string classes_str = boost::algorithm::join(classes,
", ");
145 "Exception while loading planner '%s': %s"
146 "Available plugins: %s",
147 planner_plugin_name_.c_str(), ex.what(), classes_str.c_str());
151 if (!adapter_plugin_names_.empty())
153 std::vector<planning_request_adapter::PlanningRequestAdapterConstPtr> ads;
156 adapter_plugin_loader_ =
157 std::make_unique<pluginlib::ClassLoader<planning_request_adapter::PlanningRequestAdapter>>(
158 "moveit_core",
"planning_request_adapter::PlanningRequestAdapter");
160 catch (pluginlib::PluginlibException& ex)
162 RCLCPP_ERROR(LOGGER,
"Exception while creating planning plugin loader %s", ex.what());
165 if (adapter_plugin_loader_)
166 for (
const std::string& adapter_plugin_name : adapter_plugin_names_)
168 planning_request_adapter::PlanningRequestAdapterPtr ad;
171 ad = adapter_plugin_loader_->createUniqueInstance(adapter_plugin_name);
173 catch (pluginlib::PluginlibException& ex)
175 RCLCPP_ERROR(LOGGER,
"Exception while loading planning adapter plugin '%s': %s", adapter_plugin_name.c_str(),
180 ad->initialize(node_, parameter_namespace_);
181 ads.push_back(std::move(ad));
186 adapter_chain_ = std::make_unique<planning_request_adapter::PlanningRequestAdapterChain>();
187 for (planning_request_adapter::PlanningRequestAdapterConstPtr& ad : ads)
189 RCLCPP_INFO(LOGGER,
"Using planning request adapter '%s'", ad->getDescription().c_str());
190 adapter_chain_->addAdapter(ad);
194 displayComputedMotionPlans(
true);
195 checkSolutionPaths(
true);
200 if (display_computed_motion_plans_ && !flag)
201 display_path_publisher_.reset();
202 else if (!display_computed_motion_plans_ && flag)
204 display_path_publisher_ = node_->create_publisher<moveit_msgs::msg::DisplayTrajectory>(DISPLAY_PATH_TOPIC, 10);
206 display_computed_motion_plans_ = flag;
211 if (publish_received_requests_ && !flag)
212 received_request_publisher_.reset();
213 else if (!publish_received_requests_ && flag)
215 received_request_publisher_ =
218 publish_received_requests_ = flag;
223 if (check_solution_paths_ && !flag)
224 contacts_publisher_.reset();
225 else if (!check_solution_paths_ && flag)
227 contacts_publisher_ = node_->create_publisher<visualization_msgs::msg::MarkerArray>(MOTION_CONTACTS_TOPIC, 10);
229 check_solution_paths_ = flag;
236 std::vector<std::size_t> dummy;
243 std::vector<std::size_t>& adapter_added_state_index)
const
246 if (publish_received_requests_)
247 received_request_publisher_->publish(req);
248 adapter_added_state_index.clear();
250 if (!planner_instance_)
252 RCLCPP_ERROR(LOGGER,
"No planning plugin loaded. Cannot plan.");
261 solved = adapter_chain_->adaptAndPlan(planner_instance_,
planning_scene, req, res, adapter_added_state_index);
262 if (!adapter_added_state_index.empty())
264 std::stringstream ss;
265 for (std::size_t added_index : adapter_added_state_index)
266 ss << added_index <<
" ";
267 RCLCPP_INFO(LOGGER,
"Planning adapters have added states at index positions: [ %s]", ss.str().c_str());
272 planning_interface::PlanningContextPtr context =
274 solved = context ? context->solve(res) :
false;
277 catch (std::exception& ex)
279 RCLCPP_ERROR(LOGGER,
"Exception caught: '%s'", ex.what());
286 std::size_t state_count = res.
trajectory_->getWayPointCount();
287 RCLCPP_DEBUG(LOGGER,
"Motion planner reported a solution path with %ld states", state_count);
288 if (check_solution_paths_)
290 visualization_msgs::msg::MarkerArray arr;
291 visualization_msgs::msg::Marker m;
292 m.action = visualization_msgs::msg::Marker::DELETEALL;
293 arr.markers.push_back(m);
295 std::vector<std::size_t> index;
300 bool problem =
false;
301 for (std::size_t i = 0; i < index.size() && !problem; ++i)
304 for (std::size_t added_index : adapter_added_state_index)
305 if (index[i] == added_index)
315 if (index.size() == 1 && index[0] == 0)
317 RCLCPP_DEBUG(LOGGER,
"It appears the robot is starting at an invalid state, but that is ok.");
322 res.
error_code_.val = moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN;
325 std::stringstream ss;
326 for (std::size_t it : index)
329 RCLCPP_ERROR_STREAM(LOGGER,
"Computed path is not valid. Invalid states at index locations: [ "
330 << ss.str() <<
"] out of " << state_count
331 <<
". Explanations follow in command line. Contacts are published on "
332 << contacts_publisher_->get_topic_name());
335 for (std::size_t it : index)
339 planning_scene->isStateValid(robot_state, req.path_constraints, req.group_name,
true);
351 visualization_msgs::msg::MarkerArray arr_i;
354 arr.markers.insert(arr.markers.end(), arr_i.markers.begin(), arr_i.markers.end());
357 RCLCPP_ERROR(LOGGER,
"Completed listing of explanations for invalid states.");
363 "Planned path was found to be valid, except for states that were added by planning request "
364 "adapters, but that is ok.");
368 RCLCPP_DEBUG(LOGGER,
"Planned path was found to be valid when rechecked");
369 contacts_publisher_->publish(arr);
374 if (display_computed_motion_plans_ && solved)
376 moveit_msgs::msg::DisplayTrajectory disp;
377 disp.model_id = robot_model_->getName();
378 disp.trajectory.resize(1);
379 res.
trajectory_->getRobotTrajectoryMsg(disp.trajectory[0]);
381 display_path_publisher_->publish(disp);
388 bool stacked_constraints =
false;
389 if (req.path_constraints.position_constraints.size() > 1 || req.path_constraints.orientation_constraints.size() > 1)
390 stacked_constraints =
true;
391 for (
const auto& constraint : req.goal_constraints)
393 if (constraint.position_constraints.size() > 1 || constraint.orientation_constraints.size() > 1)
394 stacked_constraints =
true;
396 if (stacked_constraints)
397 RCLCPP_WARN(LOGGER,
"More than one constraint is set. If your move_group does not have multiple end "
398 "effectors/arms, this is "
399 "unusual. Are you using a move_group_interface and forgetting to call clearPoseTargets() or "
403 return solved && valid;
408 if (planner_instance_)
409 planner_instance_->terminate();
Representation of a robot's state. This includes position, velocity, acceleration and effort.
bool generatePlan(const planning_scene::PlanningSceneConstPtr &planning_scene, const planning_interface::MotionPlanRequest &req, planning_interface::MotionPlanResponse &res) const
Call the motion planner plugin and the sequence of planning request adapters (if any).
void publishReceivedRequests(bool flag)
Pass a flag telling the pipeline whether or not to publish the received motion planning requests on M...
PlanningPipeline(const moveit::core::RobotModelConstPtr &model, const std::shared_ptr< rclcpp::Node > &node, const std::string ¶meter_namespace, const std::string &planning_plugin_param_name="planning_plugin", const std::string &adapter_plugins_param_name="request_adapters")
Given a robot model (model), a node handle (pipeline_nh), initialize the planning pipeline.
void checkSolutionPaths(bool flag)
Pass a flag telling the pipeline whether or not to re-check the solution paths reported by the planne...
void terminate() const
Request termination, if a generatePlan() function is currently computing plans.
static const std::string MOTION_PLAN_REQUEST_TOPIC
When motion planning requests are received and they are supposed to be automatically published,...
void displayComputedMotionPlans(bool flag)
Pass a flag telling the pipeline whether or not to publish the computed motion plans on DISPLAY_PATH_...
static const std::string MOTION_CONTACTS_TOPIC
When contacts are found in the solution path reported by a planner, they can be published as markers ...
static const std::string DISPLAY_PATH_TOPIC
When motion plans are computed and they are supposed to be automatically displayed,...
void getCollisionMarkersFromContacts(visualization_msgs::msg::MarkerArray &arr, const std::string &frame_id, const CollisionResult::ContactMap &con, const std_msgs::msg::ColorRGBA &color, const rclcpp::Duration &lifetime, const double radius=0.035)
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.
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
This namespace includes the central class for representing planning contexts.
const rclcpp::Logger LOGGER
Representation of a collision checking request.
bool verbose
Flag indicating whether information about detected collisions should be reported.
bool contacts
If true, compute contacts. Otherwise only a binary collision yes/no is reported.
std::size_t max_contacts
Overall maximum number of contacts to compute.
std::size_t max_contacts_per_pair
Maximum number of contacts to compute per pair of bodies (multiple bodies may be in contact at differ...
Representation of a collision checking result.
std::size_t contact_count
Number of contacts returned.
robot_trajectory::RobotTrajectoryPtr trajectory_
moveit_msgs::msg::MoveItErrorCodes error_code_