Nav2 Navigation Stack - jazzy  jazzy
ROS 2 Navigation Stack
utils.hpp
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 #ifndef OPENNAV_DOCKING__UTILS_HPP_
16 #define OPENNAV_DOCKING__UTILS_HPP_
17 
18 #include <string>
19 #include <vector>
20 
21 #include "yaml-cpp/yaml.h"
22 #include "rclcpp_lifecycle/lifecycle_node.hpp"
23 #include "rclcpp/rclcpp.hpp"
24 #include "nav2_util/geometry_utils.hpp"
25 #include "angles/angles.h"
26 #include "opennav_docking/types.hpp"
27 #include "tf2/utils.h"
28 
29 namespace utils
30 {
31 
32 using rclcpp::ParameterType::PARAMETER_STRING;
33 using rclcpp::ParameterType::PARAMETER_STRING_ARRAY;
34 using rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY;
35 using nav2_util::geometry_utils::orientationAroundZAxis;
36 
43 inline bool parseDockFile(
44  const std::string & yaml_filepath,
45  const rclcpp_lifecycle::LifecycleNode::SharedPtr & node,
46  DockMap & dock_db)
47 {
48  YAML::Node yaml_file;
49  try {
50  yaml_file = YAML::LoadFile(yaml_filepath);
51  } catch (...) {
52  return false;
53  }
54 
55  if (!yaml_file["docks"]) {
56  RCLCPP_ERROR(
57  node->get_logger(),
58  "Dock database (%s) does not contain 'docks'.", yaml_filepath.c_str());
59  return false;
60  }
61 
62  auto yaml_docks = yaml_file["docks"];
63  Dock curr_dock;
64  for (const auto & yaml_dock : yaml_docks) {
65  std::string dock_name = yaml_dock.first.as<std::string>();
66  const YAML::Node & dock_attribs = yaml_dock.second;
67 
68  curr_dock.frame = "map";
69  if (dock_attribs["frame"]) {
70  curr_dock.frame = dock_attribs["frame"].as<std::string>();
71  }
72 
73  if (!dock_attribs["type"]) {
74  RCLCPP_ERROR(
75  node->get_logger(),
76  "Dock database (%s) entries do not contain 'type'.", yaml_filepath.c_str());
77  return false;
78  }
79  curr_dock.type = dock_attribs["type"].as<std::string>();
80 
81  if (!dock_attribs["pose"]) {
82  RCLCPP_ERROR(
83  node->get_logger(),
84  "Dock database (%s) entries do not contain 'pose'.", yaml_filepath.c_str());
85  return false;
86  }
87  std::vector<double> pose_arr = dock_attribs["pose"].as<std::vector<double>>();
88  if (pose_arr.size() != 3u) {
89  RCLCPP_ERROR(
90  node->get_logger(),
91  "Dock database (%s) entries do not contain pose of size 3.", yaml_filepath.c_str());
92  return false;
93  }
94  curr_dock.pose.position.x = pose_arr[0];
95  curr_dock.pose.position.y = pose_arr[1];
96  curr_dock.pose.orientation = orientationAroundZAxis(pose_arr[2]);
97 
98  if (dock_attribs["id"]) {
99  curr_dock.id = dock_attribs["id"].as<std::string>();
100  }
101 
102  // Insert into dock instance database
103  dock_db.emplace(dock_name, curr_dock);
104  }
105 
106  return true;
107 }
108 
115 inline bool parseDockParams(
116  const std::vector<std::string> & docks_param,
117  const rclcpp_lifecycle::LifecycleNode::SharedPtr & node,
118  DockMap & dock_db)
119 {
120  Dock curr_dock;
121  std::vector<double> pose_arr;
122  for (const auto & dock_name : docks_param) {
123  if (!node->has_parameter(dock_name + ".frame")) {
124  node->declare_parameter(dock_name + ".frame", "map");
125  }
126  node->get_parameter(dock_name + ".frame", curr_dock.frame);
127 
128  if (!node->has_parameter(dock_name + ".type")) {
129  node->declare_parameter(dock_name + ".type", PARAMETER_STRING);
130  }
131  if (!node->get_parameter(dock_name + ".type", curr_dock.type)) {
132  RCLCPP_ERROR(node->get_logger(), "Dock %s has no dock 'type'.", dock_name.c_str());
133  return false;
134  }
135 
136  pose_arr.clear();
137  if (!node->has_parameter(dock_name + ".pose")) {
138  node->declare_parameter(dock_name + ".pose", PARAMETER_DOUBLE_ARRAY);
139  }
140  if (!node->get_parameter(dock_name + ".pose", pose_arr) || pose_arr.size() != 3u) {
141  RCLCPP_ERROR(node->get_logger(), "Dock %s has no valid 'pose'.", dock_name.c_str());
142  return false;
143  }
144  curr_dock.pose.position.x = pose_arr[0];
145  curr_dock.pose.position.y = pose_arr[1];
146  curr_dock.pose.orientation = orientationAroundZAxis(pose_arr[2]);
147 
148  if (!node->has_parameter(dock_name + ".id")) {
149  node->declare_parameter(dock_name + ".id", "");
150  }
151  node->get_parameter(dock_name + ".id", curr_dock.id);
152 
153  // Insert into dock instance database
154  dock_db.emplace(dock_name, curr_dock);
155  }
156  return true;
157 }
158 
165 inline geometry_msgs::msg::PoseStamped getDockPoseStamped(
166  const Dock * dock, const rclcpp::Time & t)
167 {
168  geometry_msgs::msg::PoseStamped pose;
169  pose.pose = dock->pose;
170  pose.header.frame_id = dock->frame;
171  pose.header.stamp = t;
172  return pose;
173 }
174 
175 inline double l2Norm(const geometry_msgs::msg::Pose & a, const geometry_msgs::msg::Pose & b)
176 {
177  double angle_a = tf2::getYaw(a.orientation);
178  double angle_b = tf2::getYaw(b.orientation);
179  double delta_angle = angles::shortest_angular_distance(angle_a, angle_b);
180  return sqrt(
181  (a.position.x - b.position.x) * (a.position.x - b.position.x) +
182  (a.position.y - b.position.y) * (a.position.y - b.position.y) +
183  delta_angle * delta_angle);
184 }
185 
186 } // namespace utils
187 
188 #endif // OPENNAV_DOCKING__UTILS_HPP_
Definition: types.hpp:33