moveit2
The MoveIt Motion Planning Framework for ROS 2.
planning_component.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2022, Peter David Fagan
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 the copyright holder 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: Peter David Fagan */
36 
37 #include "planning_component.hpp"
38 #include <memory>
39 
40 namespace moveit_py
41 {
42 namespace bind_planning_component
43 {
45 plan(std::shared_ptr<moveit_cpp::PlanningComponent>& planning_component,
46  std::shared_ptr<moveit_cpp::PlanningComponent::PlanRequestParameters>& parameters)
47 {
48  if (parameters)
49  {
50  // cast parameters
51  std::shared_ptr<const moveit_cpp::PlanningComponent::PlanRequestParameters> const_single_plan_parameters =
52  std::const_pointer_cast<const moveit_cpp::PlanningComponent::PlanRequestParameters>(parameters);
53 
54  return planning_component->plan(*const_single_plan_parameters);
55  }
56  return planning_component->plan();
57 }
58 
59 bool setGoal(std::shared_ptr<moveit_cpp::PlanningComponent>& planning_component,
60  std::optional<std::string> configuration_name, std::optional<moveit::core::RobotState> robot_state,
61  std::optional<geometry_msgs::msg::PoseStamped> pose_stamped_msg, std::optional<std::string> pose_link,
62  std::optional<std::vector<moveit_msgs::msg::Constraints>> motion_plan_constraints)
63 {
64  // check that no more than one argument is specified
65  if (configuration_name && robot_state)
66  {
67  throw std::invalid_argument("Cannot specify both configuration name and robot state");
68  }
69  else if (configuration_name && pose_stamped_msg)
70  {
71  throw std::invalid_argument("Cannot specify both configuration name and pose msg");
72  }
73  else if (configuration_name && motion_plan_constraints)
74  {
75  throw std::invalid_argument("Cannot specify both configuration name and motion plan constraints");
76  }
77  else if (robot_state && pose_stamped_msg)
78  {
79  throw std::invalid_argument("Cannot specify both robot state and pose msg");
80  }
81  else if (robot_state && motion_plan_constraints)
82  {
83  throw std::invalid_argument("Cannot specify both robot state and motion plan constraints");
84  }
85  else if (pose_stamped_msg && motion_plan_constraints)
86  {
87  throw std::invalid_argument("Cannot specify both pose goal and motion plan constraints");
88  }
89  else if ((pose_stamped_msg && !pose_link) || (!pose_stamped_msg && pose_link))
90  {
91  throw std::invalid_argument("Must specify both message and corresponding link");
92  }
93 
94  // check that at least one argument is specified
95  if (!configuration_name && !robot_state && !pose_stamped_msg && !pose_link && !motion_plan_constraints)
96  {
97  throw std::invalid_argument("Must specify at least one argument");
98  }
99 
100  // 1. set goal from configuration name
101  if (configuration_name)
102  {
103  return planning_component->setGoal(*configuration_name);
104  }
105  // 2. set goal from robot_state
106  else if (robot_state)
107  {
108  return planning_component->setGoal(*robot_state);
109  }
110  // 3. set goal from pose_goal
111  else if (pose_stamped_msg && pose_link)
112  {
113  return planning_component->setGoal(*pose_stamped_msg, *pose_link);
114  }
115  // 4. set goal from motion_plan_constraints
116  else
117  {
118  return planning_component->setGoal(*motion_plan_constraints);
119  }
120 }
121 
122 bool setStartState(std::shared_ptr<moveit_cpp::PlanningComponent>& planning_component,
123  std::optional<std::string> configuration_name, std::optional<moveit::core::RobotState> robot_state)
124 {
125  // check that no more than one argument is specified
126  if (configuration_name && robot_state)
127  {
128  throw std::invalid_argument("Cannot specify both configuration name and robot state");
129  }
130 
131  // check that at least one argument is specified
132  if (!configuration_name && !robot_state)
133  {
134  throw std::invalid_argument("Must specify at least one argument");
135  }
136 
137  // 1. set start state from configuration name
138  if (configuration_name)
139  {
140  return planning_component->setStartState(*configuration_name);
141  }
142  // 2. set start state from robot_state
143  else
144  {
145  return planning_component->setStartState(*robot_state);
146  }
147 }
148 
149 moveit_msgs::msg::RobotState
150 getMotionPlanSolutionStartState(std::shared_ptr<moveit_cpp::PlanningComponent::PlanSolution>& plan_solution)
151 {
152  moveit_msgs::msg::RobotState robot_state_msg = plan_solution->start_state;
153  return robot_state_msg;
154 }
155 
156 moveit_msgs::msg::MoveItErrorCodes
157 getMotionPlanSolutionErrorCode(std::shared_ptr<moveit_cpp::PlanningComponent::PlanSolution>& plan_solution)
158 {
159  moveit_msgs::msg::MoveItErrorCodes error_code_msg =
160  static_cast<moveit_msgs::msg::MoveItErrorCodes>(plan_solution->error_code);
161  return error_code_msg;
162 }
163 
164 std::shared_ptr<robot_trajectory::RobotTrajectory>
165 getMotionPlanSolutionTrajectory(std::shared_ptr<moveit_cpp::PlanningComponent::PlanSolution>& plan_solution)
166 {
167  return plan_solution->trajectory;
168 }
169 
170 void initPlanRequestParameters(py::module& m)
171 {
173  std::shared_ptr<moveit_cpp::PlanningComponent::PlanRequestParameters>>(m, "PlanRequestParameters",
174  R"(
175  Planner parameters provided with a MotionPlanRequest.
176  )")
177  .def(py::init([](std::shared_ptr<moveit_cpp::MoveItCpp>& moveit_cpp) {
178  const rclcpp::Node::SharedPtr& node = moveit_cpp->getNode();
180  params.load(node);
181  return params;
182  }))
184  R"(
185  str: The planner id to use.
186  )")
188  R"(
189  str: The planning pipeline to use.
190  )")
192  R"(
193  int: The number of planning attempts to make.
194  )")
196  R"(
197  float: The amount of time to spend planning.
198  )")
199  .def_readwrite("max_velocity_scaling_factor",
201  R"(
202  float: The maximum velocity scaling factor that can be used.
203  )")
204  .def_readwrite("max_acceleration_scaling_factor",
206  R"(
207  float: The maximum scaling factor that can be used.
208  )");
209 }
210 
211 void initPlanningComponent(py::module& m)
212 {
213  py::class_<moveit_cpp::PlanningComponent, std::shared_ptr<moveit_cpp::PlanningComponent>>(m, "PlanningComponent",
214  R"(
215  Represents a joint model group and motion plans corresponding to this joint model group.
216  )")
217 
218  .def(py::init<const std::string&, const std::shared_ptr<moveit_cpp::MoveItCpp>&>(),
219  py::arg("joint_model_group_name"), py::arg("moveit_py_instance"),
220  R"(
221  Constructs a PlanningComponent instance.
222 
223  Args:
224  joint_model_group_name (str): The name of the joint model group to plan for.
225  moveit_py_instance (:py:class:`moveit_py.core.MoveItPy`): The MoveItPy instance to use.
226  )")
227 
228  .def("get_named_target_state_values", &moveit_cpp::PlanningComponent::getNamedTargetStateValues, py::arg("name"),
229  R"(
230  dict: The joint values for targets specified by name.
231  )")
232 
233  .def_property("planning_group_name", &moveit_cpp::PlanningComponent::getPlanningGroupName, nullptr,
234  R"(
235  str: The name of the planning group to plan for.
236  )")
237 
238  .def_property("named_target_states", &moveit_cpp::PlanningComponent::getNamedTargetStates, nullptr,
239  R"(
240  list of str: The names of the named robot states available as targets.
241  )")
242 
243  // start state methods
244  .def("set_start_state_to_current_state", &moveit_cpp::PlanningComponent::setStartStateToCurrentState,
245  R"(
246  Set the start state of the plan to the current state of the robot.
247  )")
248 
249  .def("set_start_state", &moveit_py::bind_planning_component::setStartState,
250  py::arg("configuration_name") = nullptr, py::arg("robot_state") = nullptr,
251  R"(
252  Set the start state of the plan to the given robot state.
253 
254  Args:
255  configuration_name (str): The name of the configuration to use as the start state.
256  robot_state (:py:class:`moveit_msgs.msg.RobotState`): The robot state to use as the start state.
257  )")
258 
259  .def("get_start_state", &moveit_cpp::PlanningComponent::getStartState,
260  py::return_value_policy::reference_internal,
261  R"(
262  Returns the current start state for the planning component.
263  )")
264 
265  // goal state methods
266  .def("set_goal_state",
267  py::overload_cast<std::shared_ptr<moveit_cpp::PlanningComponent>&, std::optional<std::string>,
268  std::optional<moveit::core::RobotState>, std::optional<geometry_msgs::msg::PoseStamped>,
269  std::optional<std::string>, std::optional<std::vector<moveit_msgs::msg::Constraints>>>(
271  py::arg("configuration_name") = nullptr, py::arg("robot_state") = nullptr,
272  py::arg("pose_stamped_msg") = nullptr, py::arg("pose_link") = nullptr,
273  py::arg("motion_plan_constraints") = nullptr,
274  R"(
275  Set the goal state for the planning component.
276 
277  Args:
278  configuration_name (str): The name of the configuration to set the goal to.
279  robot_state (moveit_py.core.RobotState): The state to set the goal to.
280  pose_stamped_msg (geometry_msgs.msg.PoseStamped): A PoseStamped ros message.
281  pose_link (str): The name of the link for which the pose constraint is specified.
282  motion_plan_constraints (list): The motion plan constraints to set the goal to.
283  )")
284 
285  // plan/execution methods
286 
287  // TODO (peterdavidfagan): improve the plan API
288  .def("plan", &moveit_py::bind_planning_component::plan, py::arg("parameters") = nullptr,
289  py::return_value_policy::move,
290  R"(
291  Plan a motion plan using the current start and goal states.
292 
293  Args:
294  plan_parameters (moveit_py.core.PlanParameters): The parameters to use for planning.
295  )")
296 
297  .def("set_path_constraints", &moveit_cpp::PlanningComponent::setPathConstraints, py::arg("path_constraints"),
298  py::return_value_policy::move,
299  R"(
300  Set the path constraints generated from a moveit msg Constraints.
301 
302  Args:
303  path_constraints (moveit_msgs.msg.Constraints): The path constraints.
304  )")
305 
306  // Interacting with workspace
307  .def("set_workspace", &moveit_cpp::PlanningComponent::setWorkspace, py::arg("min_x"), py::arg("min_y"),
308  py::arg("min_z"), py::arg("max_x"), py::arg("max_y"), py::arg("max_z"),
309  R"(
310  Specify the workspace bounding box. The box is specified in the planning frame (i.e. relative to the robot root link start position). The workspace applies only to the root joint of a mobile robot (driving base, quadrotor) and does not limit the workspace of a robot arm.
311 
312  Args:
313  min_x (float): The minimum x value of the workspace.
314  min_y (float): The minimum y value of the workspace.
315  min_z (float): The minimum z value of the workspace.
316  max_x (float): The maximum x value of the workspace.
317  max_y (float): The maximum y value of the workspace.
318  max_z (float): The maximum z value of the workspace.
319  )")
320 
321  .def("unset_workspace", &moveit_cpp::PlanningComponent::unsetWorkspace,
322  R"(
323  Remove the workspace bounding box from planning.
324  )");
325 }
326 void initPlanSolution(py::module& m)
327 {
328  py::class_<moveit_cpp::PlanningComponent::PlanSolution, moveit_cpp::PlanningComponent::PlanSolutionPtr>(
329  m, "PlanSolution", R"(
330  Represents a planning solution, including the trajectory and any error codes.)")
331  .def_property("start_state", &moveit_py::bind_planning_component::getMotionPlanSolutionStartState, nullptr,
332  py::return_value_policy::copy, "The starting state used for planning.")
333  .def_property("trajectory", &moveit_py::bind_planning_component::getMotionPlanSolutionTrajectory, nullptr,
334  py::return_value_policy::copy, "The resulting planned trajectory.")
335  .def_property("error_code", &moveit_py::bind_planning_component::getMotionPlanSolutionErrorCode, nullptr,
336  py::return_value_policy::copy, "The MoveIt error code of the planning request.")
337  .def(
338  "__bool__", [](const moveit_cpp::PlanningComponent::PlanSolution& self) { return static_cast<bool>(self); },
339  "Return True if planning was successful.");
340 }
341 } // namespace bind_planning_component
342 } // namespace moveit_py
void setStartStateToCurrentState()
Set the start state for planning to be the current state of the robot.
std::map< std::string, double > getNamedTargetStateValues(const std::string &name)
Get the joint values for targets specified by name.
void unsetWorkspace()
Remove the workspace bounding box from planning.
const std::string & getPlanningGroupName() const
Get the name of the planning group.
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.
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.
std::shared_ptr< robot_trajectory::RobotTrajectory > getMotionPlanSolutionTrajectory(std::shared_ptr< moveit_cpp::PlanningComponent::PlanSolution > &plan_solution)
moveit_cpp::PlanningComponent::PlanSolution plan(std::shared_ptr< moveit_cpp::PlanningComponent > &planning_component, std::shared_ptr< moveit_cpp::PlanningComponent::PlanRequestParameters > &parameters)
moveit_msgs::msg::MoveItErrorCodes getMotionPlanSolutionErrorCode(std::shared_ptr< moveit_cpp::PlanningComponent::PlanSolution > &plan_solution)
bool setGoal(std::shared_ptr< moveit_cpp::PlanningComponent > &planning_component, std::optional< std::string > configuration_name, std::optional< moveit::core::RobotState > robot_state, std::optional< geometry_msgs::msg::PoseStamped > pose_stamped_msg, std::optional< std::string > pose_link, std::optional< std::vector< moveit_msgs::msg::Constraints >> motion_plan_constraints)
moveit_msgs::msg::RobotState getMotionPlanSolutionStartState(std::shared_ptr< moveit_cpp::PlanningComponent::PlanSolution > &plan_solution)
bool setStartState(std::shared_ptr< moveit_cpp::PlanningComponent > &planning_component, std::optional< std::string > configuration_name, std::optional< moveit::core::RobotState > robot_state)
Planner parameters provided with the MotionPlanRequest.
void load(const rclcpp::Node::SharedPtr &node)
The representation of a plan solution.