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