38#include <fmt/format.h>
57[[nodiscard]] std::vector<moveit_msgs::msg::Constraints>
58getTrajectoryConstraints(
const robot_trajectory::RobotTrajectoryPtr& trajectory)
60 const std::vector<std::string> joint_names =
61 trajectory->getFirstWayPoint().getJointModelGroup(trajectory->getGroupName())->getActiveJointModelNames();
63 std::vector<moveit_msgs::msg::Constraints> trajectory_constraints;
65 for (
size_t waypoint_index = 0; waypoint_index < trajectory->getWayPointCount(); ++waypoint_index)
67 moveit_msgs::msg::Constraints new_waypoint_constraint;
69 for (
const auto& joint_name : joint_names)
71 moveit_msgs::msg::JointConstraint new_joint_constraint;
72 new_joint_constraint.joint_name = joint_name;
73 new_joint_constraint.position = trajectory->getWayPoint(waypoint_index).getVariablePosition(joint_name);
74 new_waypoint_constraint.joint_constraints.push_back(new_joint_constraint);
76 trajectory_constraints.push_back(new_waypoint_constraint);
78 return trajectory_constraints;
85 const std::shared_ptr<rclcpp::Node>& node,
const std::string& parameter_namespace)
88 , parameter_namespace_(parameter_namespace)
90 , logger_(
moveit::getLogger(
"moveit.ros.planning_pipeline"))
92 auto param_listener = planning_pipeline_parameters::ParamListener(node, parameter_namespace);
93 pipeline_parameters_ = param_listener.get_params();
99 const std::shared_ptr<rclcpp::Node>& node,
const std::string& parameter_namespace,
100 const std::vector<std::string>& planner_plugin_names,
101 const std::vector<std::string>& request_adapter_plugin_names,
102 const std::vector<std::string>& response_adapter_plugin_names)
105 , parameter_namespace_(parameter_namespace)
106 , robot_model_(model)
107 , logger_(
moveit::getLogger(
"moveit.ros.planning_pipeline"))
109 pipeline_parameters_.planning_plugins = planner_plugin_names;
110 pipeline_parameters_.request_adapters = request_adapter_plugin_names;
111 pipeline_parameters_.response_adapters = response_adapter_plugin_names;
115void PlanningPipeline::configure()
118 if (!pipeline_parameters_.progress_topic.empty())
120 progress_publisher_ = node_->create_publisher<moveit_msgs::msg::PipelineState>(pipeline_parameters_.progress_topic,
121 rclcpp::SystemDefaultsQoS());
127 planner_plugin_loader_ = std::make_unique<pluginlib::ClassLoader<planning_interface::PlannerManager>>(
128 "moveit_core",
"planning_interface::PlannerManager");
130 catch (pluginlib::PluginlibException& ex)
132 RCLCPP_FATAL(logger_,
"Exception while creating planning plugin loader %s", ex.what());
136 if (pipeline_parameters_.planning_plugins.empty() || pipeline_parameters_.planning_plugins.at(0) ==
"UNKNOWN")
138 const std::string classes_str = fmt::format(
"{}", fmt::join(planner_plugin_loader_->getDeclaredClasses(),
", "));
139 throw std::runtime_error(
"Planning plugin name is empty or not defined in namespace '" + parameter_namespace_ +
140 "'. Please choose one of the available plugins: " + classes_str);
143 for (
const auto& planner_name : pipeline_parameters_.planning_plugins)
145 planning_interface::PlannerManagerPtr planner_instance;
150 planner_instance = planner_plugin_loader_->createUniqueInstance(planner_name);
152 catch (pluginlib::PluginlibException& ex)
154 std::string classes_str = fmt::format(
"{}", fmt::join(planner_plugin_loader_->getDeclaredClasses(),
", "));
156 "Exception while loading planner '%s': %s"
157 "Available plugins: %s",
158 planner_name.c_str(), ex.what(), classes_str.c_str());
163 if (!planner_instance)
165 throw std::runtime_error(
"Unable to initialize planning plugin " + planner_name +
166 ". Planner instance is nullptr.");
170 if (!planner_instance->initialize(robot_model_, node_, parameter_namespace_))
172 throw std::runtime_error(
"Unable to initialize planning plugin " + planner_name);
174 RCLCPP_INFO(
getLogger(),
"Successfully loaded planner '%s'", planner_instance->getDescription().c_str());
175 planner_map_.insert(std::make_pair(planner_name, planner_instance));
179 if (!pipeline_parameters_.request_adapters.empty())
183 request_adapter_plugin_loader_ =
184 std::make_unique<pluginlib::ClassLoader<planning_interface::PlanningRequestAdapter>>(
185 "moveit_core",
"planning_interface::PlanningRequestAdapter");
187 catch (pluginlib::PluginlibException& ex)
189 RCLCPP_FATAL(logger_,
"Exception while creating planning plugin loader %s", ex.what());
193 if (request_adapter_plugin_loader_)
195 loadPluginVector<planning_interface::PlanningRequestAdapter>(node_, request_adapter_plugin_loader_,
196 planning_request_adapter_vector_,
197 pipeline_parameters_.request_adapters,
198 parameter_namespace_);
202 RCLCPP_WARN(logger_,
"No planning request adapter names specified.");
207 RCLCPP_WARN(logger_,
"No planning request adapter names specified.");
210 if (!pipeline_parameters_.response_adapters.empty())
214 response_adapter_plugin_loader_ =
215 std::make_unique<pluginlib::ClassLoader<planning_interface::PlanningResponseAdapter>>(
216 "moveit_core",
"planning_interface::PlanningResponseAdapter");
218 catch (pluginlib::PluginlibException& ex)
220 RCLCPP_FATAL(logger_,
"Exception while creating planning plugin loader %s", ex.what());
223 if (response_adapter_plugin_loader_)
225 loadPluginVector<planning_interface::PlanningResponseAdapter>(node_, response_adapter_plugin_loader_,
226 planning_response_adapter_vector_,
227 pipeline_parameters_.response_adapters,
228 parameter_namespace_);
233 RCLCPP_WARN(logger_,
"No planning response adapter names specified.");
237void PlanningPipeline::publishPipelineState(moveit_msgs::msg::MotionPlanRequest req,
239 const std::string& pipeline_stage)
const
241 if (progress_publisher_)
243 moveit_msgs::msg::PipelineState progress;
244 progress.request = std::move(req);
246 progress.pipeline_stage = pipeline_stage;
247 progress_publisher_->publish(progress);
254 const bool publish_received_requests)
const
256 assert(!planner_map_.empty());
262 if (publish_received_requests)
264 publishPipelineState(req, res, std::string(
""));
275 for (
const auto& req_adapter : planning_request_adapter_vector_)
278 RCLCPP_INFO(node_->get_logger(),
"Calling PlanningRequestAdapter '%s'", req_adapter->getDescription().c_str());
279 const auto status = req_adapter->adapt(
planning_scene, mutable_request);
282 publishPipelineState(mutable_request, res, req_adapter->getDescription());
286 RCLCPP_ERROR(node_->get_logger(),
287 "PlanningRequestAdapter '%s' failed, because '%s'. Aborting planning pipeline.",
288 req_adapter->getDescription().c_str(), status.message.c_str());
295 for (
const auto& planner_name : pipeline_parameters_.planning_plugins)
297 const auto& planner = planner_map_.at(planner_name);
301 mutable_request.trajectory_constraints.constraints = getTrajectoryConstraints(res.
trajectory);
305 planning_interface::PlanningContextPtr context =
309 RCLCPP_ERROR(node_->get_logger(),
310 "Failed to create PlanningContext for planner '%s'. Aborting planning pipeline.",
311 planner->getDescription().c_str());
312 res.
error_code = moveit::core::MoveItErrorCode::PLANNING_FAILED;
318 RCLCPP_INFO(node_->get_logger(),
"Calling Planner '%s'", planner->getDescription().c_str());
320 publishPipelineState(mutable_request, res, planner->getDescription());
325 RCLCPP_ERROR(node_->get_logger(),
"Planner '%s' failed with error code %s", planner->getDescription().c_str(),
336 for (
const auto& res_adapter : planning_response_adapter_vector_)
339 RCLCPP_INFO(node_->get_logger(),
"Calling PlanningResponseAdapter '%s'", res_adapter->getDescription().c_str());
341 publishPipelineState(mutable_request, res, res_adapter->getDescription());
345 RCLCPP_ERROR(node_->get_logger(),
"PlanningResponseAdapter '%s' failed with error code %s",
346 res_adapter->getDescription().c_str(), errorCodeToString(res.
error_code).c_str());
353 catch (std::exception& ex)
355 RCLCPP_ERROR(logger_,
"Exception caught: '%s'", ex.what());
365 "The planner plugin did not fill out the 'planner_id' field of the MotionPlanResponse. Setting "
366 "it to the planner ID name of the MotionPlanRequest assuming that the planner plugin does warn "
367 "you if it does not use the requested planner.");
373 return static_cast<bool>(res);
378 for (
const auto& planner_pair : planner_map_)
380 if (planner_pair.second)
382 planner_pair.second->terminate();
bool generatePlan(const planning_scene::PlanningSceneConstPtr &, const planning_interface::MotionPlanRequest &, planning_interface::MotionPlanResponse &, const bool, const bool, const bool) const
void terminate() const
Request termination, if a generatePlan() function is currently computing plans.
PlanningPipeline(const moveit::core::RobotModelConstPtr &model, const std::shared_ptr< rclcpp::Node > &node, const std::string ¶meter_namespace)
Given a robot model, a ROS node, and a parameter namespace, initialize the planning pipeline....
rclcpp::Logger getLogger()
Main namespace for MoveIt.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
This namespace includes the central class for representing planning contexts.
Response to a planning query.
moveit::core::MoveItErrorCode error_code
robot_trajectory::RobotTrajectoryPtr trajectory
void getMessage(moveit_msgs::msg::MotionPlanResponse &msg) const
Construct a ROS message from struct data.