moveit2
The MoveIt Motion Planning Framework for ROS 2.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
planning_component.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2019, PickNik Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of PickNik Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Henning Kayser */
36
37#include <stdexcept>
38
44#include <thread>
46
47namespace moveit_cpp
48{
49
50PlanningComponent::PlanningComponent(const std::string& group_name, const MoveItCppPtr& moveit_cpp)
51 : node_(moveit_cpp->getNode())
52 , moveit_cpp_(moveit_cpp)
53 , group_name_(group_name)
54 , logger_(moveit::getLogger("moveit.ros.planning_component"))
55{
56 joint_model_group_ = moveit_cpp_->getRobotModel()->getJointModelGroup(group_name);
57 if (!joint_model_group_)
58 {
59 std::string error = "Could not find joint model group '" + group_name + "'.";
60 RCLCPP_FATAL_STREAM(logger_, error);
61 throw std::runtime_error(error);
62 }
63}
64
65PlanningComponent::PlanningComponent(const std::string& group_name, const rclcpp::Node::SharedPtr& node)
66 : PlanningComponent(group_name, std::make_shared<MoveItCpp>(node))
67{
68 joint_model_group_ = moveit_cpp_->getRobotModel()->getJointModelGroup(group_name);
69 if (!joint_model_group_)
70 {
71 std::string error = "Could not find joint model group '" + group_name + "'.";
72 RCLCPP_FATAL_STREAM(logger_, error);
73 throw std::runtime_error(error);
74 }
75}
76
77const std::vector<std::string> PlanningComponent::getNamedTargetStates()
78{
79 if (joint_model_group_)
80 {
81 return joint_model_group_->getDefaultStateNames();
82 }
83 else
84 {
85 RCLCPP_WARN(logger_, "Unable to find joint group with name '%s'.", group_name_.c_str());
86 }
87
88 std::vector<std::string> empty;
89 return empty;
90}
91
93{
94 return group_name_;
95}
96
97bool PlanningComponent::setPathConstraints(const moveit_msgs::msg::Constraints& path_constraints)
98{
99 current_path_constraints_ = path_constraints;
100 return true;
101}
102
103bool PlanningComponent::setTrajectoryConstraints(const moveit_msgs::msg::TrajectoryConstraints& trajectory_constraints)
104{
105 current_trajectory_constraints_ = trajectory_constraints;
106 return true;
107}
108
110 planning_scene::PlanningScenePtr planning_scene)
111{
112 auto plan_solution = planning_interface::MotionPlanResponse();
113
114 // check if joint_model_group exists
115 if (!joint_model_group_)
116 {
117 RCLCPP_ERROR(logger_, "Failed to retrieve joint model group for name '%s'.", group_name_.c_str());
118 plan_solution.error_code = moveit::core::MoveItErrorCode::INVALID_GROUP_NAME;
119 return plan_solution;
120 }
121
122 // Check if goal constraints exist
123 if (current_goal_constraints_.empty())
124 {
125 RCLCPP_ERROR(logger_, "No goal constraints set for planning request");
126 plan_solution.error_code = moveit::core::MoveItErrorCode::INVALID_GOAL_CONSTRAINTS;
127 return plan_solution;
128 }
129
130 if (!planning_scene)
131 { // Clone current planning scene
132 auto planning_scene_monitor = moveit_cpp_->getPlanningSceneMonitorNonConst();
133 planning_scene_monitor->updateFrameTransforms();
134 planning_scene = planning_scene_monitor->copyPlanningScene();
135 }
136 // Init MotionPlanRequest
138
139 // Set start state
140 planning_scene->setCurrentState(request.start_state);
141
142 // Run planning attempt
144 moveit_cpp_->getPlanningPipelines());
145}
146
148 const MultiPipelinePlanRequestParameters& parameters,
151 planning_scene::PlanningScenePtr planning_scene)
152{
153 auto plan_solution = planning_interface::MotionPlanResponse();
154
155 // check if joint_model_group exists
156 if (!joint_model_group_)
157 {
158 RCLCPP_ERROR(logger_, "Failed to retrieve joint model group for name '%s'.", group_name_.c_str());
159 plan_solution.error_code = moveit::core::MoveItErrorCode::INVALID_GROUP_NAME;
160 return plan_solution;
161 }
162
163 // Check if goal constraints exist
164 if (current_goal_constraints_.empty())
165 {
166 RCLCPP_ERROR(logger_, "No goal constraints set for planning request");
167 plan_solution.error_code = moveit::core::MoveItErrorCode::INVALID_GOAL_CONSTRAINTS;
168 return plan_solution;
169 }
170
171 if (!planning_scene)
172 { // Clone current planning scene
173 planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor =
174 moveit_cpp_->getPlanningSceneMonitorNonConst();
175 planning_scene_monitor->updateFrameTransforms();
179 }();
180 planning_scene_monitor.reset(); // release this pointer}
181 }
182 // Init MotionPlanRequest
183 std::vector<::planning_interface::MotionPlanRequest> requests = getMotionPlanRequestVector(parameters);
184
185 // Set start state
186 for (const auto& request : requests)
187 {
188 planning_scene->setCurrentState(request.start_state);
189 }
190
191 const auto motion_plan_response_vector = moveit::planning_pipeline_interfaces::planWithParallelPipelines(
192 requests, planning_scene, moveit_cpp_->getPlanningPipelines(), stopping_criterion_callback,
193 solution_selection_function);
194
195 try
196 {
197 // If a solution_selection function is passed to the parallel pipeline interface, the returned vector contains only
198 // the selected solution
199 plan_solution = motion_plan_response_vector.at(0);
200 }
201 catch (std::out_of_range&)
202 {
203 RCLCPP_ERROR(logger_, "MotionPlanResponse vector was empty after parallel planning");
204 plan_solution.error_code = moveit::core::MoveItErrorCode::INVALID_GOAL_CONSTRAINTS;
205 }
206 // Run planning attempt
207 return plan_solution;
208}
209
211{
212 PlanRequestParameters plan_request_parameters;
213 plan_request_parameters.load(node_);
214 RCLCPP_DEBUG_STREAM(
215 logger_, "Default plan request parameters loaded with --"
216 << " planning_pipeline: " << plan_request_parameters.planning_pipeline << ','
217 << " planner_id: " << plan_request_parameters.planner_id << ','
218 << " planning_time: " << plan_request_parameters.planning_time << ','
219 << " planning_attempts: " << plan_request_parameters.planning_attempts << ','
220 << " max_velocity_scaling_factor: " << plan_request_parameters.max_velocity_scaling_factor << ','
221 << " max_acceleration_scaling_factor: " << plan_request_parameters.max_acceleration_scaling_factor);
222 return plan(plan_request_parameters);
223}
224
226{
227 considered_start_state_ = std::make_shared<moveit::core::RobotState>(start_state);
228 return true;
229}
230
231moveit::core::RobotStatePtr PlanningComponent::getStartState()
232{
233 if (considered_start_state_)
234 {
235 return considered_start_state_;
236 }
237 else
238 {
239 moveit::core::RobotStatePtr s;
240 moveit_cpp_->getCurrentState(s, 1.0);
241 return s;
242 }
243}
244
245bool PlanningComponent::setStartState(const std::string& start_state_name)
246{
247 const auto& named_targets = getNamedTargetStates();
248 if (std::find(named_targets.begin(), named_targets.end(), start_state_name) == named_targets.end())
249 {
250 RCLCPP_ERROR(logger_, "No predefined joint state found for target name '%s'", start_state_name.c_str());
251 return false;
252 }
253 moveit::core::RobotState start_state(moveit_cpp_->getRobotModel());
254 start_state.setToDefaultValues(); // required to ensure all joints are initialized
255 start_state.setToDefaultValues(joint_model_group_, start_state_name);
256 return setStartState(start_state);
257}
258
260{
261 considered_start_state_.reset();
262}
263
264std::map<std::string, double> PlanningComponent::getNamedTargetStateValues(const std::string& name)
265{
266 // TODO(henningkayser): verify result
267 std::map<std::string, double> positions;
268 joint_model_group_->getVariableDefaultPositions(name, positions);
269 return positions;
270}
271
272void PlanningComponent::setWorkspace(double minx, double miny, double minz, double maxx, double maxy, double maxz)
273{
274 workspace_parameters_.header.frame_id = moveit_cpp_->getRobotModel()->getModelFrame();
275 workspace_parameters_.header.stamp = node_->now();
276 workspace_parameters_.min_corner.x = minx;
277 workspace_parameters_.min_corner.y = miny;
278 workspace_parameters_.min_corner.z = minz;
279 workspace_parameters_.max_corner.x = maxx;
280 workspace_parameters_.max_corner.y = maxy;
281 workspace_parameters_.max_corner.z = maxz;
282 workspace_parameters_set_ = true;
283}
284
286{
287 workspace_parameters_set_ = false;
288}
289
290bool PlanningComponent::setGoal(const std::vector<moveit_msgs::msg::Constraints>& goal_constraints)
291{
292 current_goal_constraints_ = goal_constraints;
293 return true;
294}
295
297{
298 current_goal_constraints_ = { kinematic_constraints::constructGoalConstraints(goal_state, joint_model_group_) };
299 return true;
300}
301
302bool PlanningComponent::setGoal(const geometry_msgs::msg::PoseStamped& goal_pose, const std::string& link_name)
303{
304 current_goal_constraints_ = { kinematic_constraints::constructGoalConstraints(link_name, goal_pose) };
305 return true;
306}
307
308bool PlanningComponent::setGoal(const std::string& goal_state_name)
309{
310 const auto& named_targets = getNamedTargetStates();
311 if (std::find(named_targets.begin(), named_targets.end(), goal_state_name) == named_targets.end())
312 {
313 RCLCPP_ERROR(logger_, "No predefined joint state found for target name '%s'", goal_state_name.c_str());
314 return false;
315 }
316 moveit::core::RobotState goal_state(moveit_cpp_->getRobotModel());
317 goal_state.setToDefaultValues(joint_model_group_, goal_state_name);
318 return setGoal(goal_state);
319}
320
323{
325 request.group_name = group_name_;
326 request.pipeline_id = plan_request_parameters.planning_pipeline;
327 request.planner_id = plan_request_parameters.planner_id;
328 request.num_planning_attempts = std::max(1, plan_request_parameters.planning_attempts);
329 request.allowed_planning_time = plan_request_parameters.planning_time;
330 request.max_velocity_scaling_factor = plan_request_parameters.max_velocity_scaling_factor;
331 request.max_acceleration_scaling_factor = plan_request_parameters.max_acceleration_scaling_factor;
332 if (workspace_parameters_set_)
333 {
334 request.workspace_parameters = workspace_parameters_;
335 }
336 request.goal_constraints = current_goal_constraints_;
337 request.path_constraints = current_path_constraints_;
338 request.trajectory_constraints = current_trajectory_constraints_;
339
340 // Set start state
341 moveit::core::RobotStatePtr start_state = considered_start_state_;
342 if (!start_state)
343 {
344 start_state = moveit_cpp_->getCurrentState();
345 }
346 start_state->update();
347 moveit::core::robotStateToRobotStateMsg(*start_state, request.start_state);
348 return request;
349}
350
351std::vector<::planning_interface::MotionPlanRequest> PlanningComponent::getMotionPlanRequestVector(
352 const MultiPipelinePlanRequestParameters& multi_pipeline_plan_request_parameters)
353{
354 std::vector<::planning_interface::MotionPlanRequest> motion_plan_requests;
355 motion_plan_requests.reserve(multi_pipeline_plan_request_parameters.plan_request_parameter_vector.size());
356 for (const auto& plan_request_parameters : multi_pipeline_plan_request_parameters.plan_request_parameter_vector)
357 {
358 motion_plan_requests.push_back(getMotionPlanRequest(plan_request_parameters));
359 }
360 return motion_plan_requests;
361}
362} // namespace moveit_cpp
bool getVariableDefaultPositions(const std::string &name, std::map< std::string, double > &values) const
Get the values that correspond to a named state as read from the URDF. Return false on failure.
const std::vector< std::string > & getDefaultStateNames() const
Get the names of the known default states (as specified in the SRDF)
Representation of a robot's state. This includes position, velocity, acceleration and effort.
void setToDefaultValues()
Set all joints to their default positions. The default position is 0, or if that is not within bounds...
void setStartStateToCurrentState()
Set the start state for planning to be the current state of the robot.
bool setStartState(const moveit::core::RobotState &start_state)
Set the robot state that should be considered as start state for planning.
std::map< std::string, double > getNamedTargetStateValues(const std::string &name)
Get the joint values for targets specified by name.
planning_interface::MotionPlanResponse plan()
Run a plan from start or current state to fulfill the last goal constraints provided by setGoal() usi...
void unsetWorkspace()
Remove the workspace bounding box from planning.
bool setGoal(const std::vector< moveit_msgs::msg::Constraints > &goal_constraints)
Set the goal constraints used for planning.
const std::string & getPlanningGroupName() const
Get the name of the planning group.
::planning_interface::MotionPlanRequest getMotionPlanRequest(const PlanRequestParameters &plan_request_parameters)
Utility function to get a MotionPlanRequest from PlanRequestParameters and the internal state of the ...
bool setTrajectoryConstraints(const moveit_msgs::msg::TrajectoryConstraints &trajectory_constraints)
Set the trajectory constraints generated from a moveit msg Constraints.
PlanningComponent(const std::string &group_name, const rclcpp::Node::SharedPtr &node)
Constructor.
void setWorkspace(double minx, double miny, double minz, double maxx, double maxy, double maxz)
Specify the workspace bounding box. The box is specified in the planning frame (i....
bool setPathConstraints(const moveit_msgs::msg::Constraints &path_constraints)
Set the path constraints generated from a moveit msg Constraints.
std::vector<::planning_interface::MotionPlanRequest > getMotionPlanRequestVector(const MultiPipelinePlanRequestParameters &multi_pipeline_plan_request_parameters)
Utility function to get a Vector of MotionPlanRequest from a vector of PlanRequestParameters and the ...
const std::vector< std::string > getNamedTargetStates()
Get the names of the named robot states available as targets.
moveit::core::RobotStatePtr getStartState()
Get the considered start state if defined, otherwise get the current state.
static PlanningScenePtr clone(const PlanningSceneConstPtr &scene)
Clone a planning scene. Even if the scene scene depends on a parent, the cloned scene will not.
This is a convenience class for obtaining access to an instance of a locked PlanningScene.
moveit_msgs::msg::Constraints constructGoalConstraints(const moveit::core::RobotState &state, const moveit::core::JointModelGroup *jmg, double tolerance_below, double tolerance_above)
Generates a constraint message intended to be used as a goal constraint for a joint group....
Definition utils.cpp:152
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.
::planning_interface::MotionPlanResponse planWithSinglePipeline(const ::planning_interface::MotionPlanRequest &motion_plan_request, const ::planning_scene::PlanningSceneConstPtr &planning_scene, const std::unordered_map< std::string, planning_pipeline::PlanningPipelinePtr > &planning_pipelines)
Function to calculate the MotionPlanResponse for a given MotionPlanRequest and a PlanningScene.
std::function< bool(const PlanResponsesContainer &plan_responses_container, const std::vector<::planning_interface::MotionPlanRequest > &plan_requests)> StoppingCriterionFunction
A stopping criterion callback function for the parallel planning API of planning component.
const std::vector<::planning_interface::MotionPlanResponse > planWithParallelPipelines(const std::vector<::planning_interface::MotionPlanRequest > &motion_plan_requests, const ::planning_scene::PlanningSceneConstPtr &planning_scene, const std::unordered_map< std::string, planning_pipeline::PlanningPipelinePtr > &planning_pipelines, const StoppingCriterionFunction &stopping_criterion_callback=nullptr, const SolutionSelectionFunction &solution_selection_function=nullptr)
Function to solve multiple planning problems in parallel threads with multiple planning pipelines at ...
std::function<::planning_interface::MotionPlanResponse(const std::vector<::planning_interface::MotionPlanResponse > &solutions)> SolutionSelectionFunction
A solution callback function type for the parallel planning API of planning component.
Main namespace for MoveIt.
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
This namespace includes the central class for representing planning contexts.
Planner parameters provided with the MotionPlanRequest.
Planner parameters provided with the MotionPlanRequest.
void load(const rclcpp::Node::SharedPtr &node, const std::string &param_namespace="")