Nav2 Navigation Stack - jazzy  jazzy
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 }
30 
32  const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
33  std::shared_ptr<tf2_ros::Buffer> tf)
34 {
35  node_ = parent;
36  auto node = node_.lock();
37 
38  if (!getDockPlugins(node, tf)) {
39  RCLCPP_ERROR(
40  node->get_logger(),
41  "An error occurred while getting the dock plugins!");
42  return false;
43  }
44 
45  if (!getDockInstances(node)) {
46  RCLCPP_ERROR(
47  node->get_logger(),
48  "An error occurred while getting the dock instances!");
49  return false;
50  }
51 
52  RCLCPP_INFO(
53  node->get_logger(),
54  "Docking Server has %u dock types and %u dock instances available.",
55  this->plugin_size(), this->instance_size());
56 
57  reload_db_service_ = node->create_service<nav2_msgs::srv::ReloadDockDatabase>(
58  "~/reload_database",
59  std::bind(
61  std::placeholders::_1, std::placeholders::_2));
62 
63  return true;
64 }
65 
67 {
68  DockPluginMap::iterator it;
69  for (it = dock_plugins_.begin(); it != dock_plugins_.end(); ++it) {
70  it->second->activate();
71  }
72 }
73 
75 {
76  DockPluginMap::iterator it;
77  for (it = dock_plugins_.begin(); it != dock_plugins_.end(); ++it) {
78  it->second->deactivate();
79  }
80 }
81 
83  const std::shared_ptr<nav2_msgs::srv::ReloadDockDatabase::Request> request,
84  std::shared_ptr<nav2_msgs::srv::ReloadDockDatabase::Response> response)
85 {
86  if (!mutex_->try_lock()) {
87  RCLCPP_ERROR(node_.lock()->get_logger(), "Cannot reload database while docking!");
88  response->success = false;
89  return;
90  }
91 
92  auto node = node_.lock();
93  DockMap dock_instances;
94  if (utils::parseDockFile(request->filepath, node, dock_instances)) {
95  dock_instances_ = dock_instances;
96  response->success = true;
97  RCLCPP_INFO(
98  node->get_logger(),
99  "Dock database reloaded from file %s.", request->filepath.c_str());
100  mutex_->unlock();
101  return;
102  }
103  response->success = false;
104  mutex_->unlock();
105 }
106 
107 Dock * DockDatabase::findDock(const std::string & dock_id)
108 {
109  Dock * dock_instance = findDockInstance(dock_id);
110  ChargingDock::Ptr dock_plugin{nullptr};
111 
112  if (dock_instance) {
113  dock_plugin = findDockPlugin(dock_instance->type);
114  if (dock_plugin) {
115  // Populate the plugin shared pointer
116  dock_instance->plugin = dock_plugin;
117  return dock_instance;
118  }
119  throw opennav_docking_core::DockNotValid("Dock requested has no valid plugin!");
120  }
121  throw opennav_docking_core::DockNotInDB("Dock ID requested is not in database!");
122 }
123 
124 Dock * DockDatabase::findDockInstance(const std::string & dock_id)
125 {
126  auto it = dock_instances_.find(dock_id);
127  if (it != dock_instances_.end()) {
128  return &(it->second);
129  }
130  return nullptr;
131 }
132 
133 ChargingDock::Ptr DockDatabase::findDockPlugin(const std::string & type)
134 {
135  // If only one dock plugin and type not set, use the default dock
136  if (type.empty() && dock_plugins_.size() == 1) {
137  return dock_plugins_.begin()->second;
138  }
139 
140  auto it = dock_plugins_.find(type);
141  if (it != dock_plugins_.end()) {
142  return it->second;
143  }
144  return nullptr;
145 }
146 
148  const rclcpp_lifecycle::LifecycleNode::SharedPtr & node,
149  std::shared_ptr<tf2_ros::Buffer> tf)
150 {
151  std::vector<std::string> docks_plugins;
152  if (!node->has_parameter("dock_plugins")) {
153  node->declare_parameter("dock_plugins", rclcpp::ParameterType::PARAMETER_STRING_ARRAY);
154  }
155  if (!node->get_parameter("dock_plugins", docks_plugins)) {
156  RCLCPP_ERROR(node->get_logger(), "Charging dock plugins not given!");
157  return false;
158  }
159 
160  if (docks_plugins.size() < 1u) {
161  RCLCPP_ERROR(node->get_logger(), "Charging dock plugins empty! Must provide 1.");
162  return false;
163  }
164 
165  for (size_t i = 0; i != docks_plugins.size(); i++) {
166  try {
167  std::string plugin_type = nav2_util::get_plugin_type_param(
168  node, docks_plugins[i]);
169  opennav_docking_core::ChargingDock::Ptr dock =
170  dock_loader_.createUniqueInstance(plugin_type);
171  RCLCPP_INFO(
172  node->get_logger(), "Created charging dock plugin %s of type %s",
173  docks_plugins[i].c_str(), plugin_type.c_str());
174  dock->configure(node, docks_plugins[i], tf);
175  dock_plugins_.insert({docks_plugins[i], dock});
176  } catch (const std::exception & ex) {
177  RCLCPP_FATAL(
178  node->get_logger(), "Failed to create Charging Dock plugin. Exception: %s",
179  ex.what());
180  return false;
181  }
182  }
183 
184  return true;
185 }
186 
187 bool DockDatabase::getDockInstances(const rclcpp_lifecycle::LifecycleNode::SharedPtr & node)
188 {
189  using rclcpp::ParameterType::PARAMETER_STRING;
190  using rclcpp::ParameterType::PARAMETER_STRING_ARRAY;
191 
192  // Attempt to obtain docks from separate file
193  std::string dock_filepath;
194  if (!node->has_parameter("dock_database")) {
195  node->declare_parameter("dock_database", PARAMETER_STRING);
196  }
197  if (node->get_parameter("dock_database", dock_filepath)) {
198  RCLCPP_INFO(
199  node->get_logger(), "Loading dock from database file %s.", dock_filepath.c_str());
200  try {
201  return utils::parseDockFile(dock_filepath, node, dock_instances_);
202  } catch (YAML::ParserException & e) {
203  RCLCPP_ERROR(
204  node->get_logger(),
205  "Dock database (%s) is malformed: %s.", dock_filepath.c_str(), e.what());
206  return false;
207  }
208  return true;
209  }
210 
211  // Attempt to obtain docks from parameter file
212  std::vector<std::string> docks_param;
213  if (!node->has_parameter("docks")) {
214  node->declare_parameter("docks", PARAMETER_STRING_ARRAY);
215  }
216  if (node->get_parameter("docks", docks_param)) {
217  RCLCPP_INFO(node->get_logger(), "Loading docks from parameter file.");
218  return utils::parseDockParams(docks_param, node, dock_instances_);
219  }
220 
221  RCLCPP_WARN(
222  node->get_logger(),
223  "Dock database filepath nor dock parameters set. "
224  "Docking actions can only be executed specifying the dock pose via the action request. "
225  "Or update the dock database via the reload_database service.");
226  return true;
227 }
228 
229 unsigned int DockDatabase::plugin_size() const
230 {
231  return dock_plugins_.size();
232 }
233 
234 unsigned int DockDatabase::instance_size() const
235 {
236  return dock_instances_.size();
237 }
238 
239 } // namespace opennav_docking
Dock * findDock(const std::string &dock_id)
Find a dock instance & plugin in the databases from ID.
void reloadDbCb(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.
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 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