Nav2 Navigation Stack - jazzy  jazzy
ROS 2 Navigation Stack
dummy_action_server.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_ACTION_SERVER_HPP_
16 #define BEHAVIOR_TREE__DUMMY_ACTION_SERVER_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 namespace nav2_system_tests
28 {
29 
30 using namespace std::chrono_literals; // NOLINT
31 using namespace std::chrono; // NOLINT
32 using namespace std::placeholders; // NOLINT
33 
34 using Range = std::pair<unsigned int, unsigned int>;
35 using Ranges = std::vector<Range>;
36 
37 template<class ActionT>
39 {
40 public:
41  explicit DummyActionServer(
42  const rclcpp::Node::SharedPtr & node,
43  std::string action_name)
44  : action_name_(action_name),
45  goal_count_(0)
46  {
47  action_server_ = rclcpp_action::create_server<ActionT>(
48  node->get_node_base_interface(),
49  node->get_node_clock_interface(),
50  node->get_node_logging_interface(),
51  node->get_node_waitables_interface(),
52  action_name,
53  std::bind(&DummyActionServer::handle_goal, this, _1, _2),
54  std::bind(&DummyActionServer::handle_cancel, this, _1),
55  std::bind(&DummyActionServer::handle_accepted, this, _1));
56  }
57 
58  virtual ~DummyActionServer() = default;
59  void setFailureRanges(const Ranges & failureRanges)
60  {
61  failure_ranges_ = failureRanges;
62  }
63 
64  void setRunningRanges(const Ranges & runningRanges)
65  {
66  running_ranges_ = runningRanges;
67  }
68 
69  void reset()
70  {
71  failure_ranges_.clear();
72  running_ranges_.clear();
73  goal_count_ = 0;
74  }
75 
76  int getGoalCount() const
77  {
78  return goal_count_;
79  }
80 
81 protected:
82  virtual std::shared_ptr<typename ActionT::Result> fillResult()
83  {
84  return std::make_shared<typename ActionT::Result>();
85  }
86 
87  virtual void updateResultForFailure(std::shared_ptr<typename ActionT::Result> &)
88  {
89  }
90 
91  virtual void updateResultForSuccess(std::shared_ptr<typename ActionT::Result> &)
92  {
93  }
94 
95  virtual rclcpp_action::GoalResponse handle_goal(
96  const rclcpp_action::GoalUUID &,
97  std::shared_ptr<const typename ActionT::Goal>/*goal*/)
98  {
99  return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
100  }
101 
102  virtual rclcpp_action::CancelResponse handle_cancel(
103  const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>)
104  {
105  return rclcpp_action::CancelResponse::ACCEPT;
106  }
107 
108  void execute(
109  const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
110  {
111  goal_count_++;
112  auto result = fillResult();
113 
114  // if current goal index exists in running range, the thread sleeps for 1 second
115  // to simulate a long running action
116  for (auto & index : running_ranges_) {
117  if (goal_count_ >= index.first && goal_count_ <= index.second) {
118  std::this_thread::sleep_for(1s);
119  break;
120  }
121  }
122 
123  // if current goal index exists in failure range, the goal will be aborted
124  for (auto & index : failure_ranges_) {
125  if (goal_count_ >= index.first && goal_count_ <= index.second) {
126  updateResultForFailure(result);
127  goal_handle->abort(result);
128  return;
129  }
130  }
131 
132  // goal succeeds for all other indices
133  updateResultForSuccess(result);
134  goal_handle->succeed(result);
135  }
136 
137  void handle_accepted(
138  const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
139  {
140  using namespace std::placeholders; // NOLINT
141  // this needs to return quickly to avoid blocking the executor, so spin up a new thread
142  std::thread{std::bind(&DummyActionServer::execute, this, _1), goal_handle}.detach();
143  }
144 
145 protected:
146  typename rclcpp_action::Server<ActionT>::SharedPtr action_server_;
147  std::string action_name_;
148 
149  // contains pairs of indices which define a range for which the
150  // requested action goal will return running for 1s or be aborted
151  // for all other indices, the action server will return success
152  Ranges failure_ranges_;
153  Ranges running_ranges_;
154 
155  unsigned int goal_count_;
156 };
157 } // namespace nav2_system_tests
158 
159 #endif // BEHAVIOR_TREE__DUMMY_ACTION_SERVER_HPP_