moveit2
The MoveIt Motion Planning Framework for ROS 2.
move_group_capability.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, 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 Willow Garage 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: Ioan Sucan */
36 
41 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
42 #include <moveit/utils/logger.hpp>
43 
44 #include <sstream>
45 #include <string>
46 
47 namespace move_group
48 {
49 namespace
50 {
51 rclcpp::Logger getLogger()
52 {
53  return moveit::getLogger("moveit.ros.move_group.capability");
54 }
55 } // namespace
56 
57 void MoveGroupCapability::setContext(const MoveGroupContextPtr& context)
58 {
59  context_ = context;
60 }
61 
62 void MoveGroupCapability::convertToMsg(const std::vector<plan_execution::ExecutableTrajectory>& trajectory,
63  moveit_msgs::msg::RobotState& first_state_msg,
64  std::vector<moveit_msgs::msg::RobotTrajectory>& trajectory_msg) const
65 {
66  if (!trajectory.empty())
67  {
68  bool first = true;
69  trajectory_msg.resize(trajectory.size());
70  for (std::size_t i = 0; i < trajectory.size(); ++i)
71  {
72  if (trajectory[i].trajectory)
73  {
74  if (first && !trajectory[i].trajectory->empty())
75  {
76  moveit::core::robotStateToRobotStateMsg(trajectory[i].trajectory->getFirstWayPoint(), first_state_msg);
77  first = false;
78  }
79  trajectory[i].trajectory->getRobotTrajectoryMsg(trajectory_msg[i]);
80  }
81  }
82  }
83 }
84 
85 void MoveGroupCapability::convertToMsg(const robot_trajectory::RobotTrajectoryPtr& trajectory,
86  moveit_msgs::msg::RobotState& first_state_msg,
87  moveit_msgs::msg::RobotTrajectory& trajectory_msg) const
88 {
89  if (trajectory && !trajectory->empty())
90  {
91  moveit::core::robotStateToRobotStateMsg(trajectory->getFirstWayPoint(), first_state_msg);
92  trajectory->getRobotTrajectoryMsg(trajectory_msg);
93  }
94 }
95 
96 void MoveGroupCapability::convertToMsg(const std::vector<plan_execution::ExecutableTrajectory>& trajectory,
97  moveit_msgs::msg::RobotState& first_state_msg,
98  moveit_msgs::msg::RobotTrajectory& trajectory_msg) const
99 {
100  if (trajectory.size() > 1)
101  {
102  RCLCPP_ERROR_STREAM(getLogger(),
103  "Internal logic error: trajectory component ignored. !!! THIS IS A SERIOUS ERROR !!!");
104  }
105  if (!trajectory.empty())
106  {
107  convertToMsg(trajectory[0].trajectory, first_state_msg, trajectory_msg);
108  }
109 }
110 
113 {
115  r.start_state = moveit_msgs::msg::RobotState();
116  r.start_state.is_diff = true;
117  RCLCPP_WARN(getLogger(),
118  "Execution of motions should always start at the robot's current state. Ignoring the state supplied as "
119  "start state in the motion planning request");
120  return r;
121 }
122 
123 moveit_msgs::msg::PlanningScene
124 MoveGroupCapability::clearSceneRobotState(const moveit_msgs::msg::PlanningScene& scene) const
125 {
126  moveit_msgs::msg::PlanningScene r = scene;
127  r.robot_state = moveit_msgs::msg::RobotState();
128  r.robot_state.is_diff = true;
129  RCLCPP_WARN(getLogger(),
130  "Execution of motions should always start at the robot's current state. Ignoring the state supplied as "
131  "difference in the planning scene diff");
132  return r;
133 }
134 
135 std::string MoveGroupCapability::getActionResultString(const moveit_msgs::msg::MoveItErrorCodes& error_code,
136  bool planned_trajectory_empty, bool plan_only)
137 {
138  switch (error_code.val)
139  {
140  case moveit_msgs::msg::MoveItErrorCodes::SUCCESS:
141  if (planned_trajectory_empty)
142  {
143  return "Requested path and goal constraints are already met.";
144  }
145  else
146  {
147  if (plan_only)
148  {
149  return "Motion plan was computed successfully.";
150  }
151  else
152  {
153  return "Solution was found and executed.";
154  }
155  }
156  case moveit_msgs::msg::MoveItErrorCodes::INVALID_GROUP_NAME:
157  return "Invalid group in motion plan request";
158  case moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED:
159  case moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN:
160  if (planned_trajectory_empty)
161  {
162  return "No motion plan found. No execution attempted.";
163  }
164  else
165  {
166  return "Motion plan was found but it seems to be invalid (possibly due to postprocessing). Not executing.";
167  }
168  case moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA:
169  return "Motion plan was found but it seems to be too costly and looking around did not help.";
170  case moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE:
171  return "Solution found but the environment changed during execution and the path was aborted";
172  default:
173  return moveit::core::errorCodeToString(error_code);
174  }
175 }
176 
178 {
179  switch (state)
180  {
181  case IDLE:
182  return "IDLE";
183  case PLANNING:
184  return "PLANNING";
185  case MONITOR:
186  return "MONITOR";
187  case LOOK:
188  return "LOOK";
189  default:
190  return "UNKNOWN";
191  }
192 }
193 
194 bool MoveGroupCapability::performTransform(geometry_msgs::msg::PoseStamped& pose_msg,
195  const std::string& target_frame) const
196 {
197  if (!context_ || !context_->planning_scene_monitor_->getTFClient())
198  return false;
199  if (pose_msg.header.frame_id == target_frame)
200  return true;
201  if (pose_msg.header.frame_id.empty())
202  {
203  pose_msg.header.frame_id = target_frame;
204  return true;
205  }
206 
207  try
208  {
209  geometry_msgs::msg::TransformStamped common_tf = context_->planning_scene_monitor_->getTFClient()->lookupTransform(
210  pose_msg.header.frame_id, target_frame, rclcpp::Time(0.0));
211  geometry_msgs::msg::PoseStamped pose_msg_in(pose_msg);
212  pose_msg_in.header.stamp = common_tf.header.stamp;
213  context_->planning_scene_monitor_->getTFClient()->transform(pose_msg_in, pose_msg, target_frame);
214  }
215  catch (tf2::TransformException& ex)
216  {
217  RCLCPP_ERROR(getLogger(), "TF Problem: %s", ex.what());
218  return false;
219  }
220  return true;
221 }
222 
223 planning_pipeline::PlanningPipelinePtr MoveGroupCapability::resolvePlanningPipeline(const std::string& pipeline_id) const
224 {
225  if (pipeline_id.empty())
226  {
227  // Without specified planning pipeline we use the default
228  return context_->planning_pipeline_;
229  }
230  else
231  {
232  // Attempt to get the planning pipeline for the specified identifier
233  try
234  {
235  auto pipeline = context_->moveit_cpp_->getPlanningPipelines().at(pipeline_id);
236  RCLCPP_INFO(getLogger(), "Using planning pipeline '%s'", pipeline_id.c_str());
237  return pipeline;
238  }
239  catch (const std::out_of_range&)
240  {
241  RCLCPP_WARN(getLogger(), "Couldn't find requested planning pipeline '%s'", pipeline_id.c_str());
242  }
243  }
244 
245  return planning_pipeline::PlanningPipelinePtr();
246 }
247 
248 } // namespace move_group
void setContext(const MoveGroupContextPtr &context)
moveit_msgs::msg::PlanningScene clearSceneRobotState(const moveit_msgs::msg::PlanningScene &scene) const
planning_interface::MotionPlanRequest clearRequestStartState(const planning_interface::MotionPlanRequest &request) const
void convertToMsg(const std::vector< plan_execution::ExecutableTrajectory > &trajectory, moveit_msgs::msg::RobotState &first_state_msg, std::vector< moveit_msgs::msg::RobotTrajectory > &trajectory_msg) const
bool performTransform(geometry_msgs::msg::PoseStamped &pose_msg, const std::string &target_frame) const
std::string getActionResultString(const moveit_msgs::msg::MoveItErrorCodes &error_code, bool planned_trajectory_empty, bool plan_only)
std::string stateToStr(MoveGroupState state) const
planning_pipeline::PlanningPipelinePtr resolvePlanningPipeline(const std::string &pipeline_id) const
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.
std::string errorCodeToString(const MoveItErrorCode &error_code)
Convenience function to translated error message into string.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition: logger.cpp:79
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest