gpp_plugin.cpp
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2020 Dima Dorezyuk
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
26 
27 #include <mbf_msgs/GetPathResult.h>
30 #include <xmlrpcpp/XmlRpcValue.h>
31 
32 #include <stdexcept>
33 #include <utility>
34 
35 namespace gpp_plugin {
36 
37 // define name of the lib
38 constexpr char gpp_name__[] = "[gpp]: ";
39 
40 // define named prints
41 #define GPP_DEBUG(_msg) ROS_DEBUG_STREAM(gpp_name__ << _msg)
42 #define GPP_INFO(_msg) ROS_INFO_STREAM(gpp_name__ << _msg)
43 #define GPP_WARN(_msg) ROS_WARN_STREAM(gpp_name__ << _msg)
44 #define GPP_ERROR(_msg) ROS_ERROR_STREAM(gpp_name__ << _msg)
45 #define GPP_FATAL(_msg) ROS_FATAL_STREAM(gpp_name__ << _msg)
46 
47 // outcome definition for mbf_costmap_core based plugins
48 constexpr uint32_t MBF_SUCCESS = mbf_msgs::GetPathResult::SUCCESS;
49 constexpr uint32_t MBF_FAILURE = mbf_msgs::GetPathResult::FAILURE;
50 
53 inline std::string
54 _getStringElement(const XmlRpc::XmlRpcValue& _v, const std::string& _tag) {
55  // we have to check manually, since XmlRpc would just return _tag if its
56  // missing...
57  if (!_v.hasMember(_tag))
58  throw XmlRpc::XmlRpcException(_tag + " not found");
59 
60  return static_cast<std::string>(_v[_tag]);
61 }
62 
65 template <typename _T>
66 _T
67 _getElement(const XmlRpc::XmlRpcValue& _v, const std::string& _tag,
68  const _T& _default) noexcept {
69  // check if the tag is defined (see above for explanation)
70  if (!_v.hasMember(_tag))
71  return _default;
72 
73  // try to get the desired value
74  try {
75  return static_cast<_T>(_v[_tag]);
76  }
77  catch (XmlRpc::XmlRpcException& _ex) {
78  return _default;
79  }
80 }
81 
82 template <typename _Plugin>
83 void
84 ArrayPluginManager<_Plugin>::load(const std::string& _resource,
85  ros::NodeHandle& _nh) {
86  // load the group parameters
87  PluginGroup<_Plugin>::name_ = _resource;
89  _nh.param(_resource + "_default_value", true);
90 
91  // we expect that _resource defines an array
92  using namespace XmlRpc;
93  XmlRpcValue raw;
94 
95  // load the data from the param server
96  if (!_nh.getParam(_resource, raw)) {
97  GPP_DEBUG("no parameter " << _nh.getNamespace() << "/" << _resource);
98  return;
99  }
100 
101  if (raw.getType() != XmlRpcValue::TypeArray) {
102  GPP_WARN("invalid type for " << _resource);
103  return;
104  }
105 
106  // will throw if not XmlRpcValue::TypeArray
107  const auto size = raw.size();
108 
109  // clear the old data and allocate space
111  PluginGroup<_Plugin>::plugins_.reserve(size);
112 
113  // note: size raw.size() returns int
114  for (int ii = 0; ii != size; ++ii) {
115  const auto& element = raw[ii];
116 
117  try {
118  // will throw if the tags are missing or not convertable to std::string
119  const auto type = _getStringElement(element, "type");
120  const auto name = _getStringElement(element, "name");
121 
122  // will throw if the loading fails
123  // mind the "this"
124  auto plugin = this->createCustomInstance(type);
125 
126  // assemble the parameter struct
128  param.name = name;
129  param.on_failure_break =
130  _getElement(element, "on_failure_break", param.on_failure_break);
131  param.on_success_break =
132  _getElement(element, "on_success_break", param.on_success_break);
133  // this should not throw anymore
134  PluginGroup<_Plugin>::plugins_.emplace_back(param, std::move(plugin));
135 
136  // notify the user
137  GPP_INFO("Successfully loaded " << type << " under the name " << name);
138  }
139  catch (XmlRpcException& ex) {
140  GPP_WARN("failed to read the tag: " << ex.getMessage());
141  }
142  catch (pluginlib::LibraryLoadException& ex) {
143  GPP_WARN("failed to load the library: " << ex.what());
144  }
145  catch (pluginlib::CreateClassException& ex) {
146  GPP_WARN("failed to create the class: " << ex.what());
147  }
148  }
149 }
150 
152  impl_(std::move(_impl)) {
153  // check once so we don't have to check everytime we call makePlan
154  if (!impl_)
155  throw std::invalid_argument("nullptr is not supported");
156 }
157 
158 bool
159 BaseGlobalPlannerWrapper::makePlan(const Pose& start, const Pose& goal,
160  Path& plan) {
161  double cost;
162  return makePlan(start, goal, plan, cost);
163 }
164 
165 bool
166 BaseGlobalPlannerWrapper::makePlan(const Pose& start, const Pose& goal,
167  Path& plan, double& cost) {
168  std::string message;
169  return impl_->makePlan(start, goal, 0, plan, cost, message) == MBF_SUCCESS;
170 }
171 
172 void
173 BaseGlobalPlannerWrapper::initialize(std::string _name, Map* _map) {
174  impl_->initialize(_name, _map);
175 }
176 
178 
179 inline void
181  delete impl;
182 }
183 
184 pluginlib::UniquePtr<BaseGlobalPlanner>
186  // check if this type is known
187  if (isClassAvailable(_type))
188  return createUniqueInstance(_type);
189 
190  // delegate the construction to the helper manager
191  auto impl_planner = manager_.createCustomInstance(_type);
192  // according to the pluginlib::UniquePtr, we have to privide a deleter
193  // function. here, we just pass a default-deleter, since its not bound to
194  // the class-loader
195  return pluginlib::UniquePtr<BaseGlobalPlanner>{
196  new BaseGlobalPlannerWrapper(std::move(impl_planner)), _default_deleter};
197 }
198 
199 template <typename _Plugin>
200 void
201 _initGroup(const std::string& _name, costmap_2d::Costmap2DROS* _costmap,
203  // load the plugins under the name _name
204  _group.load(_name, _nh);
205 
206  // init the plugins
207  const auto& plugins = _group.getPlugins();
208  for (const auto& plugin : plugins)
209  plugin.second->initialize(plugin.first.name, _costmap);
210 }
211 
212 void
213 GppPlugin::initialize(std::string _name, Map* _costmap) {
214  name_ = _name;
215  costmap_ = _costmap;
216 
217  // get the nodehandle with the private namespace.
218  ros::NodeHandle nh("~" + name_);
219 
220  // load the plugins from the param-server
221  _initGroup("pre_planning", costmap_, nh, pre_planning_);
222  _initGroup("post_planning", costmap_, nh, post_planning_);
223  _initGroup("planning", costmap_, nh, global_planning_);
224 }
225 
226 bool
227 GppPlugin::prePlanning(Pose& _start, Pose& _goal) {
228  auto pre_planning = [&](PrePlanningInterface& _plugin) {
229  return _plugin.preProcess(_start, _goal);
230  };
231  return runPlugins(pre_planning_, pre_planning, cancel_);
232 }
233 
234 bool
235 GppPlugin::postPlanning(const Pose& _start, const Pose& _goal, Path& _path,
236  double& _cost) {
237  auto post_planning = [&](PostPlanningInterface& _plugin) {
238  return _plugin.postProcess(_start, _goal, _path, _cost);
239  };
240  return runPlugins(post_planning_, post_planning, cancel_);
241 }
242 
243 bool
244 GppPlugin::globalPlanning(const Pose& _start, const Pose& _goal, Path& _plan,
245  double& _cost) {
246  auto planning = [&](BaseGlobalPlanner& _plugin) {
247  return _plugin.makePlan(_start, _goal, _plan, _cost);
248  };
249  return runPlugins(global_planning_, planning, cancel_);
250 }
251 
252 bool
253 GppPlugin::makePlan(const Pose& _start, const Pose& _goal, Path& _plan) {
254  double cost;
255  return makePlan(_start, _goal, _plan, cost);
256 }
257 
258 bool
259 GppPlugin::makePlan(const Pose& _start, const Pose& _goal, Path& _plan,
260  double& _cost) {
261  std::string message;
262  return makePlan(_start, _goal, 0, _plan, _cost, message) == MBF_SUCCESS;
263 }
264 
265 uint32_t
266 GppPlugin::makePlan(const Pose& _start, const Pose& _goal,
267  const double _tolerance, Path& _plan, double& _cost,
268  std::string& _message) {
269  // reset cancel flag
270  cancel_ = false;
271 
272  // local copies since we might alter the poses
273  Pose start = _start;
274  Pose goal = _goal;
275 
276  // pre-planning
277  if (!prePlanning(start, goal))
278  return MBF_FAILURE;
279 
280  // planning
281  if (!globalPlanning(start, goal, _plan, _cost))
282  return MBF_FAILURE;
283 
284  // post-planning
285  if (!postPlanning(start, goal, _plan, _cost))
286  return MBF_FAILURE;
287 
288  return MBF_SUCCESS;
289 }
290 
291 bool
293  GPP_INFO("cancelling");
294  cancel_ = true;
295  return true;
296 }
297 
298 } // namespace gpp_plugin
299 
300 // register for both interfaces
302 
XmlRpc::XmlRpcValue::size
int size() const
gpp_plugin::_default_deleter
void _default_deleter(BaseGlobalPlanner *impl)
Definition: gpp_plugin.cpp:180
gpp_plugin::PluginGroup::plugins_
PluginMap plugins_
Definition: gpp_plugin.hpp:173
pluginlib::CreateClassException
pluginlib::ClassLoader< _Plugin >::isClassAvailable
virtual bool isClassAvailable(const std::string &lookup_name)
gpp_plugin::MBF_FAILURE
constexpr uint32_t MBF_FAILURE
Definition: gpp_plugin.cpp:49
gpp_plugin::gpp_name__
constexpr char gpp_name__[]
Definition: gpp_plugin.cpp:38
XmlRpc::XmlRpcException::getMessage
const std::string & getMessage() const
gpp_plugin::BaseGlobalPlannerWrapper::BaseGlobalPlannerWrapper
BaseGlobalPlannerWrapper(ImplPlanner &&_impl)
our c'tor
Definition: gpp_plugin.cpp:151
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
gpp_plugin::BaseGlobalPlannerWrapper::impl_
ImplPlanner impl_
Definition: gpp_plugin.hpp:339
gpp_plugin::CostmapPlannerManager::createCustomInstance
pluginlib::UniquePtr< BaseGlobalPlanner > createCustomInstance(const std::string &_type) override
Definition: gpp_plugin.cpp:185
gpp_plugin::GppPlugin::post_planning_
PostPlanningManager post_planning_
Definition: gpp_plugin.hpp:451
gpp_plugin::GppPlugin::cancel
bool cancel() override
Definition: gpp_plugin.cpp:292
gpp_plugin::GppPlugin::global_planning_
CostmapPlannerManager global_planning_
Definition: gpp_plugin.hpp:452
gpp_plugin::BaseGlobalPlannerWrapper
Wrappes the CostmapPlaner API into the traditional BaseGlobalPlanner API.
Definition: gpp_plugin.hpp:316
XmlRpc
gpp_plugin.hpp
GPP_INFO
#define GPP_INFO(_msg)
Definition: gpp_plugin.cpp:42
gpp_plugin::PluginGroup::getPlugins
const PluginMap & getPlugins() const noexcept
Definition: gpp_plugin.hpp:156
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(gpp_plugin::GppPlugin, nav_core::BaseGlobalPlanner)
class_list_macros.h
gpp_plugin::BaseGlobalPlannerWrapper::initialize
void initialize(std::string name, Map *costmap_ros) override
Definition: gpp_plugin.cpp:173
gpp_plugin::_getElement
_T _getElement(const XmlRpc::XmlRpcValue &_v, const std::string &_tag, const _T &_default) noexcept
helper to get any value from _v under _tag. If anything goes wrong, the function will fall-back to th...
Definition: gpp_plugin.cpp:67
gpp_plugin::runPlugins
bool runPlugins(const PluginGroup< _Plugin > &_grp, const _Functor &_func, const std::atomic_bool &_cancel)
as _runPlugins but with a warning on failure
Definition: gpp_plugin.hpp:221
mbf_costmap_core::CostmapPlanner
gpp_plugin::_getStringElement
std::string _getStringElement(const XmlRpc::XmlRpcValue &_v, const std::string &_tag)
helper to get a string element with the tag _tag from _v
Definition: gpp_plugin.cpp:54
gpp_interface::PostPlanningInterface
gpp_plugin::BaseGlobalPlannerWrapper::Pose
geometry_msgs::PoseStamped Pose
Definition: gpp_plugin.hpp:318
gpp_plugin::MBF_SUCCESS
constexpr uint32_t MBF_SUCCESS
Definition: gpp_plugin.cpp:48
gpp_plugin::ArrayPluginManager
Loads an array of plugins.
Definition: gpp_plugin.hpp:297
gpp_plugin::BaseGlobalPlannerWrapper::makePlan
bool makePlan(const Pose &start, const Pose &goal, Path &plan) override
Definition: gpp_plugin.cpp:159
gpp_plugin::BaseGlobalPlannerWrapper::Path
std::vector< Pose > Path
Definition: gpp_plugin.hpp:319
GPP_DEBUG
#define GPP_DEBUG(_msg)
Definition: gpp_plugin.cpp:41
XmlRpcValue.h
gpp_plugin::GppPlugin::prePlanning
bool prePlanning(Pose &_start, Pose &_goal)
Definition: gpp_plugin.cpp:227
XmlRpc::XmlRpcValue::getType
const Type & getType() const
gpp_plugin::GppPlugin::globalPlanning
bool globalPlanning(const Pose &_start, const Pose &_goal, Path &_plan, double &_cost)
Definition: gpp_plugin.cpp:244
gpp_plugin::GppPlugin::initialize
void initialize(std::string name, Map *costmap_ros) override
Definition: gpp_plugin.cpp:213
XmlRpc::XmlRpcException
gpp_plugin::GppPlugin::cancel_
std::atomic_bool cancel_
Definition: gpp_plugin.hpp:444
start
ROSCPP_DECL void start()
XmlRpc::XmlRpcValue::hasMember
bool hasMember(const std::string &name) const
gpp_interface::PrePlanningInterface
gpp_plugin::CostmapPlannerManager::manager_
PluginManager< CostmapPlanner > manager_
Definition: gpp_plugin.hpp:357
gpp_plugin::GppPlugin::makePlan
bool makePlan(const Pose &_start, const Pose &_goal, Path &_plan) override
Definition: gpp_plugin.cpp:253
std
gpp_plugin::GppPlugin::name_
std::string name_
Definition: gpp_plugin.hpp:447
gpp_plugin::GppPlugin::postPlanning
bool postPlanning(const Pose &_start, const Pose &_goal, Path &_path, double &_cost)
Definition: gpp_plugin.cpp:235
gpp_plugin::GppPlugin::Path
std::vector< Pose > Path
Definition: gpp_plugin.hpp:413
ros::NodeHandle::param
T param(const std::string &param_name, const T &default_val) const
gpp_plugin::GppPlugin::costmap_
Map * costmap_
Definition: gpp_plugin.hpp:448
gpp_plugin
Definition: gpp_plugin.hpp:41
gpp_plugin::CostmapPlannerManager::~CostmapPlannerManager
~CostmapPlannerManager()
Definition: gpp_plugin.cpp:177
pluginlib::LibraryLoadException
param
T param(const std::string &param_name, const T &default_val)
XmlRpcException.h
gpp_plugin::PluginGroup
Common interface to a plugin group.
Definition: gpp_plugin.hpp:148
gpp_plugin::GppPlugin::Pose
geometry_msgs::PoseStamped Pose
Definition: gpp_plugin.hpp:412
ros::NodeHandle::getNamespace
const std::string & getNamespace() const
gpp_plugin::ArrayPluginManager::load
void load(const std::string &_resource, ros::NodeHandle &_nh)
Definition: gpp_plugin.cpp:84
nav_core::BaseGlobalPlanner
gpp_plugin::BaseGlobalPlannerWrapper::ImplPlanner
pluginlib::UniquePtr< CostmapPlanner > ImplPlanner
Definition: gpp_plugin.hpp:321
gpp_plugin::GppPlugin
Combine pre-planning, planning and post-planning to customize the your path.
Definition: gpp_plugin.hpp:410
gpp_plugin::PluginParameter
Parameters defining how to execute a plugin.
Definition: gpp_plugin.hpp:135
costmap_2d::Costmap2DROS
gpp_plugin::GppPlugin::pre_planning_
PrePlanningManager pre_planning_
Definition: gpp_plugin.hpp:450
XmlRpc::XmlRpcValue
GPP_WARN
#define GPP_WARN(_msg)
Definition: gpp_plugin.cpp:43
gpp_plugin::_initGroup
void _initGroup(const std::string &_name, costmap_2d::Costmap2DROS *_costmap, ros::NodeHandle &_nh, ArrayPluginManager< _Plugin > &_group)
Definition: gpp_plugin.cpp:201
ros::NodeHandle


gpp_plugin
Author(s):
autogenerated on Wed Mar 2 2022 00:21:23