moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
moveit_simple_controller_manager.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2013, Unbounded Robotics Inc.
5 * Copyright (c) 2012, Willow Garage, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of the Willow Garage nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *********************************************************************/
35
36/* Author: Michael Ferguson, Ioan Sucan, E. Gil Jones */
37
42#include <boost/algorithm/string/join.hpp>
43#include <pluginlib/class_list_macros.hpp>
44#include <rclcpp/logger.hpp>
45#include <rclcpp/logging.hpp>
46#include <rclcpp/node.hpp>
47#include <rclcpp/parameter.hpp>
48#include <rclcpp/parameter_value.hpp>
49#include <algorithm>
50#include <map>
52
53namespace
54{
61template <typename... T>
62std::string concatenateWithSeparator(char separator, T... content)
63{
64 std::string result;
65 (result.append(content).append({ separator }), ...);
66 result.erase(result.end() - 1); // delete trailing separator
67 return result;
68}
69
77template <typename... T>
78std::string makeParameterName(T... strings)
79{
80 return concatenateWithSeparator<T...>('.', strings...);
81}
82
83} // namespace
84
86{
87namespace
88{
89rclcpp::Logger getLogger()
90{
91 return moveit::getLogger("moveit.plugins.simple_controller_manager");
92}
93} // namespace
94static const std::string PARAM_BASE_NAME = "moveit_simple_controller_manager";
96{
97public:
99
100 ~MoveItSimpleControllerManager() override = default;
101
102 void initialize(const rclcpp::Node::SharedPtr& node) override
103 {
104 node_ = node;
105 if (!node_->has_parameter(makeParameterName(PARAM_BASE_NAME, "controller_names")))
106 {
107 RCLCPP_ERROR_STREAM(getLogger(), "No controller_names specified.");
108 return;
109 }
110 rclcpp::Parameter controller_names_param;
111 node_->get_parameter(makeParameterName(PARAM_BASE_NAME, "controller_names"), controller_names_param);
112 if (controller_names_param.get_type() != rclcpp::ParameterType::PARAMETER_STRING_ARRAY)
113 {
114 RCLCPP_ERROR(getLogger(), "Parameter controller_names should be specified as a string array");
115 return;
116 }
117 std::vector<std::string> controller_names = controller_names_param.as_string_array();
118 /* actually create each controller */
119 for (const std::string& controller_name : controller_names)
120 {
121 try
122 {
123 std::string action_ns;
124 const std::string& action_ns_param = makeParameterName(PARAM_BASE_NAME, controller_name, "action_ns");
125 if (!node_->get_parameter(action_ns_param, action_ns))
126 {
127 RCLCPP_ERROR_STREAM(getLogger(), "No action namespace specified for controller `"
128 << controller_name << "` through parameter `" << action_ns_param << '`');
129 continue;
130 }
131
132 std::string type;
133 if (!node_->get_parameter(makeParameterName(PARAM_BASE_NAME, controller_name, "type"), type))
134 {
135 RCLCPP_ERROR_STREAM(getLogger(), "No type specified for controller " << controller_name);
136 continue;
137 }
138
139 std::vector<std::string> controller_joints;
140 if (!node_->get_parameter(makeParameterName(PARAM_BASE_NAME, controller_name, "joints"), controller_joints) ||
141 controller_joints.empty())
142 {
143 RCLCPP_ERROR_STREAM(getLogger(), "No joints specified for controller " << controller_name);
144 continue;
145 }
146
147 ActionBasedControllerHandleBasePtr new_handle;
148 if (type == "GripperCommand")
149 {
150 double max_effort;
151 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "max_effort"), max_effort, 0.0);
152 RCLCPP_INFO_STREAM(getLogger(), controller_name << " will command a max effort of: " << max_effort);
153
154 new_handle = std::make_shared<GripperCommandControllerHandle>(node_, controller_name, action_ns, max_effort);
155 bool parallel_gripper = false;
156 if (node_->get_parameter(makeParameterName(PARAM_BASE_NAME, controller_name, "parallel"), parallel_gripper) &&
157 parallel_gripper)
158 {
159 if (controller_joints.size() != 2)
160 {
161 RCLCPP_ERROR_STREAM(getLogger(), "Parallel Gripper requires exactly two joints, "
162 << controller_joints.size() << " are specified");
163 continue;
164 }
165 static_cast<GripperCommandControllerHandle*>(new_handle.get())
166 ->setParallelJawGripper(controller_joints[0], controller_joints[1]);
167 }
168 else
169 {
170 std::string command_joint;
171 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "command_joint"), command_joint,
172 controller_joints[0]);
173
174 static_cast<GripperCommandControllerHandle*>(new_handle.get())->setCommandJoint(command_joint);
175 }
176
177 bool allow_failure;
178 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "allow_failure"), allow_failure,
179 false);
180 static_cast<GripperCommandControllerHandle*>(new_handle.get())->allowFailure(allow_failure);
181
182 RCLCPP_INFO_STREAM(getLogger(), "Added GripperCommand controller for " << controller_name);
183 controllers_[controller_name] = new_handle;
184 }
185 else if (type == "ParallelGripperCommand")
186 {
187 double max_effort;
188 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "max_effort"), max_effort, 0.0);
189 if (max_effort > 0.0)
190 {
191 RCLCPP_INFO_STREAM(getLogger(), controller_name << " will command a max effort of: " << max_effort);
192 }
193
194 double max_velocity;
195 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "max_velocity"), max_velocity,
196 0.0);
197 if (max_effort > 0.0)
198 {
199 RCLCPP_INFO_STREAM(getLogger(), controller_name << " will command a max velocity of: " << max_velocity);
200 }
201
202 new_handle = std::make_shared<ParallelGripperCommandControllerHandle>(node_, controller_name, action_ns,
203 max_effort, max_velocity);
204
205 if (controller_joints.size() > 1)
206 {
207 RCLCPP_WARN_STREAM(getLogger(), "ParallelGripperCommand controller only supports commanding a single joint "
208 "and multiple joint names were specified. Assuming control of joint: "
209 << controller_joints[0]);
210 }
211 static_cast<ParallelGripperCommandControllerHandle*>(new_handle.get())->setCommandJoint(controller_joints[0]);
212
213 RCLCPP_INFO_STREAM(getLogger(), "Added ParallelGripperCommand controller for " << controller_name);
214 controllers_[controller_name] = new_handle;
215 }
216 else if (type == "FollowJointTrajectory")
217 {
218 new_handle = std::make_shared<FollowJointTrajectoryControllerHandle>(node_, controller_name, action_ns);
219 RCLCPP_INFO_STREAM(getLogger(), "Added FollowJointTrajectory controller for " << controller_name);
220 controllers_[controller_name] = new_handle;
221 }
222 else
223 {
224 RCLCPP_ERROR_STREAM(getLogger(), "Unknown controller type: " << type);
225 continue;
226 }
227 if (!controllers_[controller_name])
228 {
229 controllers_.erase(controller_name);
230 continue;
231 }
232
234 node_->get_parameter_or(makeParameterName(PARAM_BASE_NAME, controller_name, "default"), state.default_, false);
235 state.active_ = true;
236
237 controller_states_[controller_name] = state;
238
239 /* add list of joints, used by controller manager and MoveIt */
240 for (const std::string& controller_joint : controller_joints)
241 new_handle->addJoint(controller_joint);
242 }
243 catch (...)
244 {
245 RCLCPP_ERROR_STREAM(getLogger(), "Caught unknown exception while parsing controller information");
246 }
247 }
248 }
249 /*
250 * Get a controller, by controller name (which was specified in the controllers.yaml
251 */
252 moveit_controller_manager::MoveItControllerHandlePtr getControllerHandle(const std::string& name) override
253 {
254 std::map<std::string, ActionBasedControllerHandleBasePtr>::const_iterator it = controllers_.find(name);
255 if (it != controllers_.end())
256 {
257 return static_cast<moveit_controller_manager::MoveItControllerHandlePtr>(it->second);
258 }
259 else
260 {
261 RCLCPP_FATAL_STREAM(getLogger(), "No such controller: " << name);
262 }
263 return moveit_controller_manager::MoveItControllerHandlePtr();
264 }
265
266 /*
267 * Get the list of controller names.
268 */
269 void getControllersList(std::vector<std::string>& names) override
270 {
271 for (std::map<std::string, ActionBasedControllerHandleBasePtr>::const_iterator it = controllers_.begin();
272 it != controllers_.end(); ++it)
273 names.push_back(it->first);
274 RCLCPP_INFO_STREAM(getLogger(), "Returned " << names.size() << " controllers in list");
275 }
276
277 /*
278 * This plugin assumes that all controllers are already active -- and if they are not, well, it has no way to deal
279 * with it anyways!
280 */
281 void getActiveControllers(std::vector<std::string>& names) override
282 {
283 getControllersList(names);
284 }
285
286 /*
287 * Controller must be loaded to be active, see comment above about active controllers...
288 */
289 virtual void getLoadedControllers(std::vector<std::string>& names)
290 {
291 getControllersList(names);
292 }
293
294 /*
295 * Get the list of joints that a controller can control.
296 */
297 void getControllerJoints(const std::string& name, std::vector<std::string>& joints) override
298 {
299 std::map<std::string, ActionBasedControllerHandleBasePtr>::const_iterator it = controllers_.find(name);
300 if (it != controllers_.end())
301 {
302 it->second->getJoints(joints);
303 }
304 else
305 {
306 RCLCPP_WARN(getLogger(),
307 "The joints for controller '%s' are not known. Perhaps the controller configuration is "
308 "not loaded on the param server?",
309 name.c_str());
310 joints.clear();
311 }
312 }
313
315 getControllerState(const std::string& name) override
316 {
317 return controller_states_[name];
318 }
319
320 /* Cannot switch our controllers */
321 bool switchControllers(const std::vector<std::string>& /* activate */,
322 const std::vector<std::string>& /* deactivate */) override
323 {
324 return false;
325 }
326
327protected:
328 rclcpp::Node::SharedPtr node_;
329 std::map<std::string, ActionBasedControllerHandleBasePtr> controllers_;
330 std::map<std::string, moveit_controller_manager::MoveItControllerManager::ControllerState> controller_states_;
331};
332
333} // end namespace moveit_simple_controller_manager
334
MoveIt does not enforce how controllers are implemented. To make your controllers usable by MoveIt,...
bool switchControllers(const std::vector< std::string > &, const std::vector< std::string > &) override
Activate and deactivate controllers.
void getControllerJoints(const std::string &name, std::vector< std::string > &joints) override
Report the joints a controller operates on, given the controller name.
void getActiveControllers(std::vector< std::string > &names) override
Get the list of active controllers.
moveit_controller_manager::MoveItControllerHandlePtr getControllerHandle(const std::string &name) override
Return a given named controller.
std::map< std::string, moveit_controller_manager::MoveItControllerManager::ControllerState > controller_states_
std::map< std::string, ActionBasedControllerHandleBasePtr > controllers_
moveit_controller_manager::MoveItControllerManager::ControllerState getControllerState(const std::string &name) override
Report the state of a controller, given its name.
void getControllersList(std::vector< std::string > &names) override
Get the list of known controller names.
PLUGINLIB_EXPORT_CLASS(moveit_simple_controller_manager::MoveItSimpleControllerManager, moveit_controller_manager::MoveItControllerManager)
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79
Each controller known to MoveIt has a state. This structure describes that controller's state.
bool default_
It is often the case that multiple controllers could be used to execute a motion. Marking a controlle...
bool active_
A controller can be active or inactive. This means that MoveIt could activate the controller when nee...