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) 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 
45 namespace moveit_cpp
46 {
47 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit.ros_planning_interface.planning_component");
48 
49 PlanningComponent::PlanningComponent(const std::string& group_name, const MoveItCppPtr& moveit_cpp)
50  : node_(moveit_cpp->getNode()), moveit_cpp_(moveit_cpp), group_name_(group_name)
51 {
52  joint_model_group_ = moveit_cpp_->getRobotModel()->getJointModelGroup(group_name);
53  if (!joint_model_group_)
54  {
55  std::string error = "Could not find joint model group '" + group_name + "'.";
56  RCLCPP_FATAL_STREAM(LOGGER, error);
57  throw std::runtime_error(error);
58  }
59  planning_pipeline_names_ = moveit_cpp_->getPlanningPipelineNames(group_name);
60  plan_request_parameters_.load(node_);
61  RCLCPP_DEBUG_STREAM(
62  LOGGER, "Plan request parameters loaded with --"
63  << " planning_pipeline: " << plan_request_parameters_.planning_pipeline << ","
64  << " planner_id: " << plan_request_parameters_.planner_id << ","
65  << " planning_time: " << plan_request_parameters_.planning_time << ","
66  << " planning_attempts: " << plan_request_parameters_.planning_attempts << ","
67  << " max_velocity_scaling_factor: " << plan_request_parameters_.max_velocity_scaling_factor << ","
68  << " max_acceleration_scaling_factor: " << plan_request_parameters_.max_acceleration_scaling_factor);
69 }
70 
71 PlanningComponent::PlanningComponent(const std::string& group_name, const rclcpp::Node::SharedPtr& node)
72  : PlanningComponent(group_name, std::make_shared<MoveItCpp>(node))
73 {
74  joint_model_group_ = moveit_cpp_->getRobotModel()->getJointModelGroup(group_name);
75  if (!joint_model_group_)
76  {
77  std::string error = "Could not find joint model group '" + group_name + "'.";
78  RCLCPP_FATAL_STREAM(LOGGER, error);
79  throw std::runtime_error(error);
80  }
81  planning_pipeline_names_ = moveit_cpp_->getPlanningPipelineNames(group_name);
82 }
83 
84 const std::vector<std::string> PlanningComponent::getNamedTargetStates()
85 {
86  if (joint_model_group_)
87  {
88  return joint_model_group_->getDefaultStateNames();
89  }
90  else
91  {
92  RCLCPP_WARN(LOGGER, "Unable to find joint group with name '%s'.", group_name_.c_str());
93  }
94 
95  std::vector<std::string> empty;
96  return empty;
97 }
98 
99 const std::string& PlanningComponent::getPlanningGroupName() const
100 {
101  return group_name_;
102 }
103 
104 bool PlanningComponent::setPathConstraints(const moveit_msgs::msg::Constraints& path_constraints)
105 {
106  current_path_constraints_ = path_constraints;
107  return true;
108 }
109 
111 {
112  last_plan_solution_ = std::make_shared<PlanSolution>();
113  if (!joint_model_group_)
114  {
115  RCLCPP_ERROR(LOGGER, "Failed to retrieve joint model group for name '%s'.", group_name_.c_str());
116  last_plan_solution_->error_code = moveit::core::MoveItErrorCode::INVALID_GROUP_NAME;
117  return *last_plan_solution_;
118  }
119 
120  // Clone current planning scene
121  planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor =
122  moveit_cpp_->getPlanningSceneMonitorNonConst();
123  planning_scene_monitor->updateFrameTransforms();
124  const planning_scene::PlanningScenePtr planning_scene = [planning_scene_monitor] {
127  }();
128  planning_scene_monitor.reset(); // release this pointer
129 
130  // Init MotionPlanRequest
132  req.group_name = group_name_;
133  req.planner_id = parameters.planner_id;
134  req.num_planning_attempts = std::max(1, parameters.planning_attempts);
135  req.allowed_planning_time = parameters.planning_time;
136  req.max_velocity_scaling_factor = parameters.max_velocity_scaling_factor;
137  req.max_acceleration_scaling_factor = parameters.max_acceleration_scaling_factor;
138  if (workspace_parameters_set_)
139  req.workspace_parameters = workspace_parameters_;
140 
141  // Set start state
142  moveit::core::RobotStatePtr start_state = considered_start_state_;
143  if (!start_state)
144  start_state = moveit_cpp_->getCurrentState();
145  start_state->update();
146  moveit::core::robotStateToRobotStateMsg(*start_state, req.start_state);
147  planning_scene->setCurrentState(*start_state);
148 
149  // Set goal constraints
150  if (current_goal_constraints_.empty())
151  {
152  RCLCPP_ERROR(LOGGER, "No goal constraints set for planning request");
153  last_plan_solution_->error_code = moveit::core::MoveItErrorCode::INVALID_GOAL_CONSTRAINTS;
154  return *last_plan_solution_;
155  }
156  req.goal_constraints = current_goal_constraints_;
157 
158  // Set path constraints
159  req.path_constraints = current_path_constraints_;
160 
161  // Run planning attempt
163  if (planning_pipeline_names_.find(parameters.planning_pipeline) == planning_pipeline_names_.end())
164  {
165  RCLCPP_ERROR(LOGGER, "No planning pipeline available for name '%s'", parameters.planning_pipeline.c_str());
166  last_plan_solution_->error_code = moveit::core::MoveItErrorCode::FAILURE;
167  return *last_plan_solution_;
168  }
169  const planning_pipeline::PlanningPipelinePtr pipeline =
170  moveit_cpp_->getPlanningPipelines().at(parameters.planning_pipeline);
171  pipeline->generatePlan(planning_scene, req, res);
172  last_plan_solution_->error_code = res.error_code_.val;
173  if (res.error_code_.val != res.error_code_.SUCCESS)
174  {
175  RCLCPP_ERROR(LOGGER, "Could not compute plan successfully");
176  return *last_plan_solution_;
177  }
178  last_plan_solution_->start_state = req.start_state;
179  last_plan_solution_->trajectory = res.trajectory_;
180  // TODO(henningkayser): Visualize trajectory
181  // std::vector<const moveit::core::LinkModel*> eef_links;
182  // if (joint_model_group->getEndEffectorTips(eef_links))
183  //{
184  // for (const auto& eef_link : eef_links)
185  // {
186  // RCLCPP_INFO_STREAM("Publishing trajectory for end effector " << eef_link->getName());
187  // visual_tools_->publishTrajectoryLine(last_solution_trajectory_, eef_link);
188  // visual_tools_->publishTrajectoryPath(last_solution_trajectory_, false);
189  // visual_tools_->publishRobotState(last_solution_trajectory_->getLastWayPoint(), rviz_visual_tools::TRANSLUCENT);
190  // }
191  //}
192  return *last_plan_solution_;
193 }
194 
196 {
197  return plan(plan_request_parameters_);
198 }
199 
201 {
202  considered_start_state_ = std::make_shared<moveit::core::RobotState>(start_state);
203  return true;
204 }
205 
206 moveit::core::RobotStatePtr PlanningComponent::getStartState()
207 {
208  if (considered_start_state_)
209  return considered_start_state_;
210  else
211  {
212  moveit::core::RobotStatePtr s;
213  moveit_cpp_->getCurrentState(s, 1.0);
214  return s;
215  }
216 }
217 
218 bool PlanningComponent::setStartState(const std::string& start_state_name)
219 {
220  const auto& named_targets = getNamedTargetStates();
221  if (std::find(named_targets.begin(), named_targets.end(), start_state_name) == named_targets.end())
222  {
223  RCLCPP_ERROR(LOGGER, "No predefined joint state found for target name '%s'", start_state_name.c_str());
224  return false;
225  }
226  moveit::core::RobotState start_state(moveit_cpp_->getRobotModel());
227  start_state.setToDefaultValues(joint_model_group_, start_state_name);
228  return setStartState(start_state);
229 }
230 
232 {
233  considered_start_state_.reset();
234 }
235 
236 std::map<std::string, double> PlanningComponent::getNamedTargetStateValues(const std::string& name)
237 {
238  // TODO(henningkayser): verify result
239  std::map<std::string, double> positions;
240  joint_model_group_->getVariableDefaultPositions(name, positions);
241  return positions;
242 }
243 
244 void PlanningComponent::setWorkspace(double minx, double miny, double minz, double maxx, double maxy, double maxz)
245 {
246  workspace_parameters_.header.frame_id = moveit_cpp_->getRobotModel()->getModelFrame();
247  workspace_parameters_.header.stamp = node_->now();
248  workspace_parameters_.min_corner.x = minx;
249  workspace_parameters_.min_corner.y = miny;
250  workspace_parameters_.min_corner.z = minz;
251  workspace_parameters_.max_corner.x = maxx;
252  workspace_parameters_.max_corner.y = maxy;
253  workspace_parameters_.max_corner.z = maxz;
254  workspace_parameters_set_ = true;
255 }
256 
258 {
259  workspace_parameters_set_ = false;
260 }
261 
262 bool PlanningComponent::setGoal(const std::vector<moveit_msgs::msg::Constraints>& goal_constraints)
263 {
264  current_goal_constraints_ = goal_constraints;
265  return true;
266 }
267 
269 {
270  current_goal_constraints_ = { kinematic_constraints::constructGoalConstraints(goal_state, joint_model_group_) };
271  return true;
272 }
273 
274 bool PlanningComponent::setGoal(const geometry_msgs::msg::PoseStamped& goal_pose, const std::string& link_name)
275 {
276  current_goal_constraints_ = { kinematic_constraints::constructGoalConstraints(link_name, goal_pose) };
277  return true;
278 }
279 
280 bool PlanningComponent::setGoal(const std::string& goal_state_name)
281 {
282  const auto& named_targets = getNamedTargetStates();
283  if (std::find(named_targets.begin(), named_targets.end(), goal_state_name) == named_targets.end())
284  {
285  RCLCPP_ERROR(LOGGER, "No predefined joint state found for target name '%s'", goal_state_name.c_str());
286  return false;
287  }
288  moveit::core::RobotState goal_state(moveit_cpp_->getRobotModel());
289  goal_state.setToDefaultValues(joint_model_group_, goal_state_name);
290  return setGoal(goal_state);
291 }
292 
293 bool PlanningComponent::execute(bool blocking)
294 {
295  if (!last_plan_solution_)
296  {
297  RCLCPP_ERROR(LOGGER, "There is no successful plan to execute");
298  return false;
299  }
300 
301  // TODO(henningkayser): parameterize timestamps if required
302  // trajectory_processing::TimeOptimalTrajectoryGeneration totg;
303  // if (!totg.computeTimeStamps(*last_solution_trajectory_, max_velocity_scaling_factor_,
304  // max_acceleration_scaling_factor_))
305  //{
306  // RCLCPP_ERROR("Failed to parameterize trajectory");
307  // return false;
308  //}
309  return moveit_cpp_->execute(group_name_, last_plan_solution_->trajectory, blocking);
310 }
311 
312 const PlanningComponent::PlanSolutionPtr PlanningComponent::getLastPlanSolution()
313 {
314  return last_plan_solution_;
315 }
316 } // 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.
Definition: robot_state.h:90
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.
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.
PlanSolution plan()
Run a plan from start or current state to fulfill the last goal constraints provided by setGoal() usi...
const std::string & getPlanningGroupName() const
Get the name of the planning group.
const PlanSolutionPtr getLastPlanSolution()
Return the last plan solution.
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.
const std::vector< std::string > getNamedTargetStates()
Get the names of the named robot states available as targets.
bool execute(bool blocking=true)
Execute the latest computed solution trajectory computed by plan(). By default this function terminat...
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:144
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.
name
Definition: setup.py:7
const rclcpp::Logger LOGGER
Definition: async_test.h:31
Planner parameters provided with the MotionPlanRequest.
void load(const rclcpp::Node::SharedPtr &node)
The representation of a plan solution.
robot_trajectory::RobotTrajectoryPtr trajectory_
moveit_msgs::msg::MoveItErrorCodes error_code_