moveit2
The MoveIt Motion Planning Framework for ROS 2.
move_group.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 
39 #include <tf2_ros/transform_listener.h>
42 #include <boost/tokenizer.hpp>
45 #include <memory>
46 #include <set>
47 
48 static const std::string ROBOT_DESCRIPTION =
49  "robot_description"; // name of the robot description (a param name, so it can be changed externally)
50 
51 static const rclcpp::Logger LOGGER = rclcpp::get_logger("move_group.move_group");
52 
53 namespace move_group
54 {
55 // These capabilities are loaded unless listed in disable_capabilities
56 // clang-format off
57 static const char* const DEFAULT_CAPABILITIES[] = {
58  "move_group/MoveGroupCartesianPathService",
59  "move_group/MoveGroupKinematicsService",
60  "move_group/MoveGroupExecuteTrajectoryAction",
61  "move_group/MoveGroupMoveAction",
62  "move_group/MoveGroupPlanService",
63  "move_group/MoveGroupQueryPlannersService",
64  "move_group/MoveGroupStateValidationService",
65  "move_group/MoveGroupGetPlanningSceneService",
66  "move_group/ApplyPlanningSceneService",
67  "move_group/ClearOctomapService",
68 };
69 // clang-format on
70 
72 {
73 public:
74  MoveGroupExe(const moveit_cpp::MoveItCppPtr& moveit_cpp, const std::string& default_planning_pipeline, bool debug)
75  {
76  // if the user wants to be able to disable execution of paths, they can just set this ROS param to false
77  bool allow_trajectory_execution;
78  moveit_cpp->getNode()->get_parameter_or("allow_trajectory_execution", allow_trajectory_execution, true);
79 
80  context_ =
81  std::make_shared<MoveGroupContext>(moveit_cpp, default_planning_pipeline, allow_trajectory_execution, debug);
82 
83  // start the capabilities
84  configureCapabilities();
85  }
86 
88  {
89  capabilities_.clear();
90  context_.reset();
91  capability_plugin_loader_.reset();
92  }
93 
94  void status()
95  {
96  if (context_)
97  {
98  if (context_->status())
99  {
100  if (capabilities_.empty())
101  {
102  printf("\n" MOVEIT_CONSOLE_COLOR_BLUE
103  "move_group is running but no capabilities are loaded." MOVEIT_CONSOLE_COLOR_RESET "\n\n");
104  }
105  else
106  {
107  printf("\n" MOVEIT_CONSOLE_COLOR_GREEN "You can start planning now!" MOVEIT_CONSOLE_COLOR_RESET "\n\n");
108  }
109  fflush(stdout);
110  }
111  }
112  else
113  RCLCPP_ERROR(LOGGER, "No MoveGroup context created. Nothing will work.");
114  }
115 
116  MoveGroupContextPtr getContext()
117  {
118  return context_;
119  }
120 
121 private:
122  void configureCapabilities()
123  {
124  try
125  {
126  capability_plugin_loader_ = std::make_shared<pluginlib::ClassLoader<MoveGroupCapability>>(
127  "moveit_ros_move_group", "move_group::MoveGroupCapability");
128  }
129  catch (pluginlib::PluginlibException& ex)
130  {
131  RCLCPP_FATAL_STREAM(LOGGER, "Exception while creating plugin loader for move_group capabilities: " << ex.what());
132  return;
133  }
134 
135  std::set<std::string> capabilities;
136 
137  // add default capabilities
138  for (const char* capability : DEFAULT_CAPABILITIES)
139  capabilities.insert(capability);
140 
141  // add capabilities listed in ROS parameter
142  std::string capability_plugins;
143  if (context_->moveit_cpp_->getNode()->get_parameter("capabilities", capability_plugins))
144  {
145  boost::char_separator<char> sep(" ");
146  boost::tokenizer<boost::char_separator<char>> tok(capability_plugins, sep);
147  capabilities.insert(tok.begin(), tok.end());
148  }
149 
150  // add capabilities configured for planning pipelines
151  for (const auto& pipeline_entry : context_->moveit_cpp_->getPlanningPipelines())
152  {
153  const auto& pipeline_name = pipeline_entry.first;
154  std::string pipeline_capabilities;
155  if (context_->moveit_cpp_->getNode()->get_parameter(pipeline_name + ".capabilities", pipeline_capabilities))
156  {
157  boost::char_separator<char> sep(" ");
158  boost::tokenizer<boost::char_separator<char>> tok(pipeline_capabilities, sep);
159  capabilities.insert(tok.begin(), tok.end());
160  }
161  }
162 
163  // drop capabilities that have been explicitly disabled
164  if (context_->moveit_cpp_->getNode()->get_parameter("disable_capabilities", capability_plugins))
165  {
166  boost::char_separator<char> sep(" ");
167  boost::tokenizer<boost::char_separator<char>> tok(capability_plugins, sep);
168  for (boost::tokenizer<boost::char_separator<char>>::iterator cap_name = tok.begin(); cap_name != tok.end();
169  ++cap_name)
170  capabilities.erase(*cap_name);
171  }
172 
173  for (const std::string& capability : capabilities)
174  {
175  try
176  {
177  printf(MOVEIT_CONSOLE_COLOR_CYAN "Loading '%s'..." MOVEIT_CONSOLE_COLOR_RESET "\n", capability.c_str());
178  MoveGroupCapabilityPtr cap = capability_plugin_loader_->createUniqueInstance(capability);
179  cap->setContext(context_);
180  cap->initialize();
181  capabilities_.push_back(cap);
182  }
183  catch (pluginlib::PluginlibException& ex)
184  {
185  RCLCPP_ERROR_STREAM(LOGGER,
186  "Exception while loading move_group capability '" << capability << "': " << ex.what());
187  }
188  }
189 
190  std::stringstream ss;
191  ss << '\n';
192  ss << '\n';
193  ss << "********************************************************" << '\n';
194  ss << "* MoveGroup using: " << '\n';
195  for (const MoveGroupCapabilityPtr& cap : capabilities_)
196  ss << "* - " << cap->getName() << '\n';
197  ss << "********************************************************" << '\n';
198  RCLCPP_INFO(LOGGER, "%s", ss.str().c_str());
199  }
200 
201  MoveGroupContextPtr context_;
202  std::shared_ptr<pluginlib::ClassLoader<MoveGroupCapability>> capability_plugin_loader_;
203  std::vector<MoveGroupCapabilityPtr> capabilities_;
204 };
205 } // namespace move_group
206 
207 int main(int argc, char** argv)
208 {
209  rclcpp::init(argc, argv);
210 
211  rclcpp::NodeOptions opt;
212  opt.allow_undeclared_parameters(true);
213  opt.automatically_declare_parameters_from_overrides(true);
214  rclcpp::Node::SharedPtr nh = rclcpp::Node::make_shared("move_group", opt);
215  moveit_cpp::MoveItCpp::Options moveit_cpp_options(nh);
216 
217  // Prepare PlanningPipelineOptions
218  moveit_cpp_options.planning_pipeline_options.parent_namespace = nh->get_effective_namespace() + ".planning_pipelines";
219  std::vector<std::string> planning_pipeline_configs;
220  if (nh->get_parameter("planning_pipelines", planning_pipeline_configs))
221  {
222  if (planning_pipeline_configs.empty())
223  {
224  RCLCPP_ERROR(LOGGER, "Failed to read parameter 'move_group.planning_pipelines'");
225  }
226  else
227  {
228  for (const auto& config : planning_pipeline_configs)
229  {
230  moveit_cpp_options.planning_pipeline_options.pipeline_names.push_back(config);
231  }
232  }
233  }
234 
235  // Retrieve default planning pipeline
236  auto& pipeline_names = moveit_cpp_options.planning_pipeline_options.pipeline_names;
237  std::string default_planning_pipeline;
238  if (nh->get_parameter("default_planning_pipeline", default_planning_pipeline))
239  {
240  // Ignore default_planning_pipeline if there is no matching entry in pipeline_names
241  if (std::find(pipeline_names.begin(), pipeline_names.end(), default_planning_pipeline) == pipeline_names.end())
242  {
243  RCLCPP_WARN(LOGGER,
244  "MoveGroup launched with ~default_planning_pipeline '%s' not configured in ~planning_pipelines",
245  default_planning_pipeline.c_str());
246  default_planning_pipeline = ""; // reset invalid pipeline id
247  }
248  }
249  else if (pipeline_names.size() > 1) // only warn if there are multiple pipelines to choose from
250  {
251  // Handle deprecated move_group.launch
252  RCLCPP_WARN(LOGGER,
253  "MoveGroup launched without ~default_planning_pipeline specifying the namespace for the default "
254  "planning pipeline configuration");
255  }
256 
257  // If there is no valid default pipeline, either pick the first available one, or fall back to old behavior
258  if (default_planning_pipeline.empty())
259  {
260  if (!pipeline_names.empty())
261  {
262  RCLCPP_WARN(LOGGER, "Using default pipeline '%s'", pipeline_names[0].c_str());
263  default_planning_pipeline = pipeline_names[0];
264  }
265  else
266  {
267  RCLCPP_WARN(LOGGER, "Falling back to using the the move_group node namespace (deprecated behavior).");
268  default_planning_pipeline = "move_group";
269  moveit_cpp_options.planning_pipeline_options.pipeline_names = { default_planning_pipeline };
270  moveit_cpp_options.planning_pipeline_options.parent_namespace = nh->get_effective_namespace();
271  }
272 
273  // Reset invalid pipeline parameter for MGI requests
274  nh->set_parameter(rclcpp::Parameter("default_planning_pipeline", default_planning_pipeline));
275  }
276 
277  // Initialize MoveItCpp
278  const auto tf_buffer = std::make_shared<tf2_ros::Buffer>(nh->get_clock(), tf2::durationFromSec(10.0));
279  const auto moveit_cpp = std::make_shared<moveit_cpp::MoveItCpp>(nh, moveit_cpp_options, tf_buffer);
280  const auto planning_scene_monitor = moveit_cpp->getPlanningSceneMonitorNonConst();
281 
282  if (planning_scene_monitor->getPlanningScene())
283  {
284  bool debug = false;
285  for (int i = 1; i < argc; ++i)
286  {
287  if (strncmp(argv[i], "--debug", 7) == 0)
288  {
289  debug = true;
290  break;
291  }
292  }
293  debug = true;
294  if (debug)
295  {
296  RCLCPP_INFO(LOGGER, "MoveGroup debug mode is ON");
297  }
298  else
299  {
300  RCLCPP_INFO(LOGGER, "MoveGroup debug mode is OFF");
301  }
302 
303  rclcpp::executors::MultiThreadedExecutor executor;
304 
305  move_group::MoveGroupExe mge(moveit_cpp, default_planning_pipeline, debug);
306 
307  bool monitor_dynamics;
308  if (nh->get_parameter("monitor_dynamics", monitor_dynamics) && monitor_dynamics)
309  {
310  RCLCPP_INFO(LOGGER, "MoveGroup monitors robot dynamics (higher load)");
311  planning_scene_monitor->getStateMonitor()->enableCopyDynamics(true);
312  }
313 
314  planning_scene_monitor->publishDebugInformation(debug);
315 
316  mge.status();
317  executor.add_node(nh);
318  executor.spin();
319 
320  rclcpp::shutdown();
321  }
322  else
323  RCLCPP_ERROR(LOGGER, "Planning scene not configured");
324 
325  return 0;
326 }
MoveGroupContextPtr getContext()
Definition: move_group.cpp:116
MoveGroupExe(const moveit_cpp::MoveItCppPtr &moveit_cpp, const std::string &default_planning_pipeline, bool debug)
Definition: move_group.cpp:74
#define MOVEIT_CONSOLE_COLOR_BLUE
#define MOVEIT_CONSOLE_COLOR_GREEN
#define MOVEIT_CONSOLE_COLOR_RESET
#define MOVEIT_CONSOLE_COLOR_CYAN
int main(int argc, char **argv)
Definition: move_group.cpp:207
Parameter container for initializing MoveItCpp.
Definition: moveit_cpp.h:99
PlanningPipelineOptions planning_pipeline_options
Definition: moveit_cpp.h:107
std::vector< std::string > pipeline_names
Definition: moveit_cpp.h:93