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