Nav2 Navigation Stack - kilted  kilted
ROS 2 Navigation Stack
dock_database.cpp
1 // Copyright (c) 2024 Open Navigation LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "opennav_docking/dock_database.hpp"
16 
17 namespace opennav_docking
18 {
19 
20 DockDatabase::DockDatabase(std::shared_ptr<std::mutex> mutex)
21 : mutex_(mutex),
22  dock_loader_("opennav_docking_core", "opennav_docking_core::ChargingDock")
23 {}
24 
26 {
27  dock_instances_.clear();
28  dock_plugins_.clear();
29  reload_db_service_.reset();
30 }
31 
33  const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
34  std::shared_ptr<tf2_ros::Buffer> tf)
35 {
36  node_ = parent;
37  auto node = node_.lock();
38 
39  if (!getDockPlugins(node, tf)) {
40  RCLCPP_ERROR(
41  node->get_logger(),
42  "An error occurred while getting the dock plugins!");
43  return false;
44  }
45 
46  if (!getDockInstances(node)) {
47  RCLCPP_ERROR(
48  node->get_logger(),
49  "An error occurred while getting the dock instances!");
50  return false;
51  }
52 
53  RCLCPP_INFO(
54  node->get_logger(),
55  "Docking Server has %u dock types and %u dock instances available.",
56  this->plugin_size(), this->instance_size());
57 
58  reload_db_service_ = std::make_shared<nav2_util::ServiceServer<nav2_msgs::srv::ReloadDockDatabase,
59  std::shared_ptr<rclcpp_lifecycle::LifecycleNode>>>(
60  "~/reload_database",
61  node,
62  std::bind(
64  std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
65 
66  return true;
67 }
68 
70 {
71  DockPluginMap::iterator it;
72  for (it = dock_plugins_.begin(); it != dock_plugins_.end(); ++it) {
73  it->second->activate();
74  }
75 }
76 
78 {
79  DockPluginMap::iterator it;
80  for (it = dock_plugins_.begin(); it != dock_plugins_.end(); ++it) {
81  it->second->deactivate();
82  }
83 }
84 
86  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
87  const std::shared_ptr<nav2_msgs::srv::ReloadDockDatabase::Request> request,
88  std::shared_ptr<nav2_msgs::srv::ReloadDockDatabase::Response> response)
89 {
90  if (!mutex_->try_lock()) {
91  RCLCPP_ERROR(node_.lock()->get_logger(), "Cannot reload database while docking!");
92  response->success = false;
93  return;
94  }
95 
96  auto node = node_.lock();
97  DockMap dock_instances;
98  if (utils::parseDockFile(request->filepath, node, dock_instances)) {
99  dock_instances_ = dock_instances;
100  response->success = true;
101  RCLCPP_INFO(
102  node->get_logger(),
103  "Dock database reloaded from file %s.", request->filepath.c_str());
104  mutex_->unlock();
105  return;
106  }
107  response->success = false;
108  mutex_->unlock();
109 }
110 
111 Dock * DockDatabase::findDock(const std::string & dock_id)
112 {
113  Dock * dock_instance = findDockInstance(dock_id);
114  ChargingDock::Ptr dock_plugin{nullptr};
115 
116  if (dock_instance) {
117  dock_plugin = findDockPlugin(dock_instance->type);
118  if (dock_plugin) {
119  // Populate the plugin shared pointer
120  dock_instance->plugin = dock_plugin;
121  return dock_instance;
122  }
123  throw opennav_docking_core::DockNotValid("Dock requested has no valid plugin!");
124  }
125  throw opennav_docking_core::DockNotInDB("Dock ID requested is not in database!");
126 }
127 
128 Dock * DockDatabase::findDockInstance(const std::string & dock_id)
129 {
130  auto it = dock_instances_.find(dock_id);
131  if (it != dock_instances_.end()) {
132  return &(it->second);
133  }
134  return nullptr;
135 }
136 
137 ChargingDock::Ptr DockDatabase::findDockPlugin(const std::string & type)
138 {
139  // If only one dock plugin and type not set, use the default dock
140  if (type.empty() && dock_plugins_.size() == 1) {
141  return dock_plugins_.begin()->second;
142  }
143 
144  auto it = dock_plugins_.find(type);
145  if (it != dock_plugins_.end()) {
146  return it->second;
147  }
148  return nullptr;
149 }
150 
152  const rclcpp_lifecycle::LifecycleNode::SharedPtr & node,
153  std::shared_ptr<tf2_ros::Buffer> tf)
154 {
155  std::vector<std::string> docks_plugins;
156  if (!node->has_parameter("dock_plugins")) {
157  node->declare_parameter("dock_plugins", rclcpp::ParameterType::PARAMETER_STRING_ARRAY);
158  }
159  if (!node->get_parameter("dock_plugins", docks_plugins)) {
160  RCLCPP_ERROR(node->get_logger(), "Charging dock plugins not given!");
161  return false;
162  }
163 
164  if (docks_plugins.size() < 1u) {
165  RCLCPP_ERROR(node->get_logger(), "Charging dock plugins empty! Must provide 1.");
166  return false;
167  }
168 
169  for (size_t i = 0; i != docks_plugins.size(); i++) {
170  try {
171  std::string plugin_type = nav2_util::get_plugin_type_param(
172  node, docks_plugins[i]);
173  opennav_docking_core::ChargingDock::Ptr dock =
174  dock_loader_.createUniqueInstance(plugin_type);
175  RCLCPP_INFO(
176  node->get_logger(), "Created charging dock plugin %s of type %s",
177  docks_plugins[i].c_str(), plugin_type.c_str());
178  dock->configure(node, docks_plugins[i], tf);
179  dock_plugins_.insert({docks_plugins[i], dock});
180  } catch (const std::exception & ex) {
181  RCLCPP_FATAL(
182  node->get_logger(), "Failed to create Charging Dock plugin. Exception: %s",
183  ex.what());
184  return false;
185  }
186  }
187 
188  return true;
189 }
190 
191 bool DockDatabase::getDockInstances(const rclcpp_lifecycle::LifecycleNode::SharedPtr & node)
192 {
193  using rclcpp::ParameterType::PARAMETER_STRING;
194  using rclcpp::ParameterType::PARAMETER_STRING_ARRAY;
195 
196  // Attempt to obtain docks from separate file
197  std::string dock_filepath;
198  if (!node->has_parameter("dock_database")) {
199  node->declare_parameter("dock_database", PARAMETER_STRING);
200  }
201  if (node->get_parameter("dock_database", dock_filepath)) {
202  RCLCPP_INFO(
203  node->get_logger(), "Loading dock from database file %s.", dock_filepath.c_str());
204  try {
205  return utils::parseDockFile(dock_filepath, node, dock_instances_);
206  } catch (YAML::BadConversion & e) {
207  RCLCPP_ERROR(
208  node->get_logger(),
209  "Dock database (%s) is malformed: %s.", dock_filepath.c_str(), e.what());
210  return false;
211  }
212  return true;
213  }
214 
215  // Attempt to obtain docks from parameter file
216  std::vector<std::string> docks_param;
217  if (!node->has_parameter("docks")) {
218  node->declare_parameter("docks", PARAMETER_STRING_ARRAY);
219  }
220  if (node->get_parameter("docks", docks_param)) {
221  RCLCPP_INFO(node->get_logger(), "Loading docks from parameter file.");
222  return utils::parseDockParams(docks_param, node, dock_instances_);
223  }
224 
225  RCLCPP_WARN(
226  node->get_logger(),
227  "Dock database filepath nor dock parameters set. "
228  "Docking actions can only be executed specifying the dock pose via the action request. "
229  "Or update the dock database via the reload_database service.");
230  return true;
231 }
232 
233 unsigned int DockDatabase::plugin_size() const
234 {
235  return dock_plugins_.size();
236 }
237 
238 unsigned int DockDatabase::instance_size() const
239 {
240  return dock_instances_.size();
241 }
242 
243 } // namespace opennav_docking
A simple wrapper on ROS2 services server.
Dock * findDock(const std::string &dock_id)
Find a dock instance & plugin in the databases from ID.
bool getDockInstances(const rclcpp_lifecycle::LifecycleNode::SharedPtr &node)
Populate database of dock instances.
Dock * findDockInstance(const std::string &dock_id)
Find a dock instance in the database from ID.
bool initialize(const rclcpp_lifecycle::LifecycleNode::WeakPtr &parent, std::shared_ptr< tf2_ros::Buffer > tf)
A setup function to populate database.
ChargingDock::Ptr findDockPlugin(const std::string &type)
Find a dock plugin to use for a given type.
void reloadDbCb(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::ReloadDockDatabase::Request > request, std::shared_ptr< nav2_msgs::srv::ReloadDockDatabase::Response > response)
Service request to reload database of docks.
void deactivate()
An deactivation method.
unsigned int plugin_size() const
Get the number of dock types in the database.
~DockDatabase()
A destructor for opennav_docking::DockDatabase.
unsigned int instance_size() const
Get the number of docks in the database.
DockDatabase(std::shared_ptr< std::mutex > mutex=std::make_shared< std::mutex >())
A constructor for opennav_docking::DockDatabase.
void activate()
An activation method.
bool getDockPlugins(const rclcpp_lifecycle::LifecycleNode::SharedPtr &node, std::shared_ptr< tf2_ros::Buffer > tf)
Populate database of dock type plugins.
Dock was not found in the provided dock database.
Dock plugin provided in the database or action was invalid.
Definition: types.hpp:33