Nav2 Navigation Stack - humble  humble
ROS 2 Navigation Stack
dummy_servers.hpp
1 // Copyright (c) 2020 Sarthak Mittal
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. Reserved.
14 
15 #ifndef BEHAVIOR_TREE__DUMMY_SERVERS_HPP_
16 #define BEHAVIOR_TREE__DUMMY_SERVERS_HPP_
17 
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 #include <chrono>
23 
24 #include "rclcpp_action/rclcpp_action.hpp"
25 #include "rclcpp/rclcpp.hpp"
26 
27 using namespace std::chrono_literals; // NOLINT
28 using namespace std::chrono; // NOLINT
29 using namespace std::placeholders; // NOLINT
30 
31 template<class ServiceT>
33 {
34 public:
35  explicit DummyService(
36  const rclcpp::Node::SharedPtr & node,
37  std::string service_name)
38  : node_(node),
39  service_name_(service_name),
40  request_count_(0),
41  disabled_(false)
42  {
43  server_ = node->create_service<ServiceT>(
44  service_name,
45  std::bind(&DummyService::handle_service, this, _1, _2, _3));
46  }
47 
48  void disable()
49  {
50  server_.reset();
51  disabled_ = true;
52  }
53 
54  void enable()
55  {
56  if (disabled_) {
57  server_ = node_->create_service<ServiceT>(
58  service_name_,
59  std::bind(&DummyService::handle_service, this, _1, _2, _3));
60  disabled_ = false;
61  }
62  }
63 
64  void reset()
65  {
66  enable();
67  request_count_ = 0;
68  }
69 
70  int getRequestCount() const
71  {
72  return request_count_;
73  }
74 
75 protected:
76  virtual void fillResponse(
77  const std::shared_ptr<typename ServiceT::Request>/*request*/,
78  const std::shared_ptr<typename ServiceT::Response>/*response*/) {}
79 
80  void handle_service(
81  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
82  const std::shared_ptr<typename ServiceT::Request> request,
83  const std::shared_ptr<typename ServiceT::Response> response)
84  {
85  request_count_++;
86  fillResponse(request, response);
87  }
88 
89 private:
90  rclcpp::Node::SharedPtr node_;
91  typename rclcpp::Service<ServiceT>::SharedPtr server_;
92  std::string service_name_;
93  int request_count_;
94  bool disabled_;
95 };
96 
97 template<class ActionT>
99 {
100 public:
101  explicit DummyActionServer(
102  const rclcpp::Node::SharedPtr & node,
103  std::string action_name)
104  : action_name_(action_name),
105  goal_count_(0)
106  {
107  this->action_server_ = rclcpp_action::create_server<ActionT>(
108  node->get_node_base_interface(),
109  node->get_node_clock_interface(),
110  node->get_node_logging_interface(),
111  node->get_node_waitables_interface(),
112  action_name,
113  std::bind(&DummyActionServer::handle_goal, this, _1, _2),
114  std::bind(&DummyActionServer::handle_cancel, this, _1),
115  std::bind(&DummyActionServer::handle_accepted, this, _1));
116  }
117 
118  void setFailureRanges(const std::vector<std::pair<int, int>> & failureRanges)
119  {
120  failure_ranges_ = failureRanges;
121  }
122 
123  void setRunningRanges(const std::vector<std::pair<int, int>> & runningRanges)
124  {
125  running_ranges_ = runningRanges;
126  }
127 
128  void reset()
129  {
130  failure_ranges_.clear();
131  running_ranges_.clear();
132  goal_count_ = 0;
133  }
134 
135  int getGoalCount() const
136  {
137  return goal_count_;
138  }
139 
140 protected:
141  virtual std::shared_ptr<typename ActionT::Result> fillResult()
142  {
143  return std::make_shared<typename ActionT::Result>();
144  }
145 
146  virtual rclcpp_action::GoalResponse handle_goal(
147  const rclcpp_action::GoalUUID &,
148  std::shared_ptr<const typename ActionT::Goal>/*goal*/)
149  {
150  return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
151  }
152 
153  virtual rclcpp_action::CancelResponse handle_cancel(
154  const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>)
155  {
156  return rclcpp_action::CancelResponse::ACCEPT;
157  }
158 
159  void execute(
160  const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
161  {
162  goal_count_++;
163  auto result = fillResult();
164 
165  // if current goal index exists in running range, the thread sleeps for 1 second
166  // to simulate a long running action
167  for (auto & index : running_ranges_) {
168  if (goal_count_ >= index.first && goal_count_ <= index.second) {
169  std::this_thread::sleep_for(1s);
170  break;
171  }
172  }
173 
174  // if current goal index exists in failure range, the goal will be aborted
175  for (auto & index : failure_ranges_) {
176  if (goal_count_ >= index.first && goal_count_ <= index.second) {
177  goal_handle->abort(result);
178  return;
179  }
180  }
181 
182  // goal succeeds for all other indices
183  goal_handle->succeed(result);
184  }
185 
186  void handle_accepted(
187  const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
188  {
189  using namespace std::placeholders; // NOLINT
190  // this needs to return quickly to avoid blocking the executor, so spin up a new thread
191  std::thread{std::bind(&DummyActionServer::execute, this, _1), goal_handle}.detach();
192  }
193 
194 protected:
195  typename rclcpp_action::Server<ActionT>::SharedPtr action_server_;
196  std::string action_name_;
197 
198  // contains pairs of indices which define a range for which the
199  // requested action goal will return running for 1s or be aborted
200  // for all other indices, the action server will return success
201  std::vector<std::pair<int, int>> failure_ranges_;
202  std::vector<std::pair<int, int>> running_ranges_;
203 
204  int goal_count_;
205 };
206 
207 #endif // BEHAVIOR_TREE__DUMMY_SERVERS_HPP_