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