rclcpp_action  master
C++ ROS Action Client Library
server.hpp
Go to the documentation of this file.
1 // Copyright 2018 Open Source Robotics Foundation, Inc.
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 RCLCPP_ACTION__SERVER_HPP_
16 #define RCLCPP_ACTION__SERVER_HPP_
17 
19 #include <rosidl_generator_c/action_type_support_struct.h>
20 #include <rosidl_typesupport_cpp/action_type_support.hpp>
24 #include <rclcpp/waitable.hpp>
25 
26 #include <functional>
27 #include <memory>
28 #include <mutex>
29 #include <string>
30 #include <unordered_map>
31 #include <utility>
32 
35 #include "rclcpp_action/types.hpp"
36 
37 namespace rclcpp_action
38 {
39 // Forward declaration
40 class ServerBaseImpl;
41 
43 enum class GoalResponse : int8_t
44 {
46  REJECT = 1,
50  ACCEPT_AND_DEFER = 3,
51 };
52 
54 enum class CancelResponse : int8_t
55 {
57  REJECT = 1,
59  ACCEPT = 2,
60 };
61 
64 
71 {
72 public:
74  virtual ~ServerBase();
75 
76  // -------------
77  // Waitables API
78 
82  size_t
83  get_number_of_ready_subscriptions() override;
84 
88  size_t
89  get_number_of_ready_timers() override;
90 
94  size_t
95  get_number_of_ready_clients() override;
96 
100  size_t
101  get_number_of_ready_services() override;
102 
106  size_t
107  get_number_of_ready_guard_conditions() override;
108 
112  bool
113  add_to_wait_set(rcl_wait_set_t * wait_set) override;
114 
118  bool
119  is_ready(rcl_wait_set_t *) override;
120 
124  void
125  execute() override;
126 
127  // End Waitables API
128  // -----------------
129 
130 protected:
132  ServerBase(
133  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
134  rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
135  rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
136  const std::string & name,
137  const rosidl_action_type_support_t * type_support,
138  const rcl_action_server_options_t & options);
139 
140  // -----------------------------------------------------
141  // API for communication between ServerBase and Server<>
142 
143  // ServerBase will call this function when a goal request is received.
144  // The subclass should convert to the real type and call a user's callback.
147  virtual
149  call_handle_goal_callback(GoalID &, std::shared_ptr<void> request) = 0;
150 
151  // ServerBase will determine which goal ids are being cancelled, and then call this function for
152  // each goal id.
153  // The subclass should look up a goal handle and call the user's callback.
156  virtual
158  call_handle_cancel_callback(const GoalID & uuid) = 0;
159 
163  virtual
164  GoalID
165  get_goal_id_from_goal_request(void * message) = 0;
166 
170  virtual
172  create_goal_request() = 0;
173 
177  virtual
178  void
179  call_goal_accepted_callback(
181  GoalID uuid, std::shared_ptr<void> goal_request_message) = 0;
182 
186  virtual
187  GoalID
188  get_goal_id_from_result_request(void * message) = 0;
189 
193  virtual
195  create_result_request() = 0;
196 
200  virtual
202  create_result_response(decltype(action_msgs::msg::GoalStatus::status) status) = 0;
203 
206  void
207  publish_status();
208 
211  void
212  notify_goal_terminal_state();
213 
216  void
217  publish_result(const GoalID & uuid, std::shared_ptr<void> result_msg);
218 
221  void
222  publish_feedback(std::shared_ptr<void> feedback_msg);
223 
224  // End API for communication between ServerBase and Server<>
225  // ---------------------------------------------------------
226 
227 private:
231  void
232  execute_goal_request_received();
233 
237  void
238  execute_cancel_request_received();
239 
243  void
244  execute_result_request_received();
245 
249  void
250  execute_check_expired_goals();
251 
255 };
256 
258 
267 template<typename ActionT>
268 class Server : public ServerBase, public std::enable_shared_from_this<Server<ActionT>>
269 {
270 public:
272 
273 
280 
282 
308  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
309  rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
310  rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
311  const std::string & name,
312  const rcl_action_server_options_t & options,
313  GoalCallback handle_goal,
314  CancelCallback handle_cancel,
315  AcceptedCallback handle_accepted
316  )
317  : ServerBase(
318  node_base,
319  node_clock,
320  node_logging,
321  name,
322  rosidl_typesupport_cpp::get_action_type_support_handle<ActionT>(),
323  options),
324  handle_goal_(handle_goal),
325  handle_cancel_(handle_cancel),
326  handle_accepted_(handle_accepted)
327  {
328  }
329 
330  virtual ~Server() = default;
331 
332 protected:
333  // -----------------------------------------------------
334  // API for communication between ServerBase and Server<>
335 
339  {
340  // TODO(sloretz) update and remove assert when IDL pipeline allows nesting user's type
341  static_assert(
343  "Assuming user fields were merged with goal request fields");
344  GoalResponse user_response = handle_goal_(
345  uuid, std::static_pointer_cast<typename ActionT::Goal>(message));
346 
347  auto ros_response = std::make_shared<typename ActionT::GoalRequestService::Response>();
348  ros_response->accepted = GoalResponse::ACCEPT_AND_EXECUTE == user_response ||
349  GoalResponse::ACCEPT_AND_DEFER == user_response;
350  return std::make_pair(user_response, ros_response);
351  }
352 
355  call_handle_cancel_callback(const GoalID & uuid) override
356  {
357  std::lock_guard<std::mutex> lock(goal_handles_mutex_);
359  auto element = goal_handles_.find(uuid);
360  if (element != goal_handles_.end()) {
361  std::shared_ptr<ServerGoalHandle<ActionT>> goal_handle = element->second.lock();
362  if (goal_handle) {
363  resp = handle_cancel_(goal_handle);
364  if (CancelResponse::ACCEPT == resp) {
365  goal_handle->_set_canceling();
366  }
367  }
368  }
369  return resp;
370  }
371 
373  void
376  GoalID uuid, std::shared_ptr<void> goal_request_message) override
377  {
379  std::weak_ptr<Server<ActionT>> weak_this = this->shared_from_this();
380 
382  [weak_this](const GoalID & uuid, std::shared_ptr<void> result_message)
383  {
384  std::shared_ptr<Server<ActionT>> shared_this = weak_this.lock();
385  if (!shared_this) {
386  return;
387  }
388  // Send result message to anyone that asked
389  shared_this->publish_result(uuid, result_message);
390  // Publish a status message any time a goal handle changes state
391  shared_this->publish_status();
392  // notify base so it can recalculate the expired goal timer
393  shared_this->notify_goal_terminal_state();
394  // Delete data now (ServerBase and rcl_action_server_t keep data until goal handle expires)
395  std::lock_guard<std::mutex> lock(shared_this->goal_handles_mutex_);
396  shared_this->goal_handles_.erase(uuid);
397  };
398 
400  [weak_this](const GoalID & uuid)
401  {
402  std::shared_ptr<Server<ActionT>> shared_this = weak_this.lock();
403  if (!shared_this) {
404  return;
405  }
406  (void)uuid;
407  // Publish a status message any time a goal handle changes state
408  shared_this->publish_status();
409  };
410 
412  [weak_this](std::shared_ptr<typename ActionT::Feedback> feedback_msg)
413  {
414  std::shared_ptr<Server<ActionT>> shared_this = weak_this.lock();
415  if (!shared_this) {
416  return;
417  }
418  shared_this->publish_feedback(std::static_pointer_cast<void>(feedback_msg));
419  };
420 
421  goal_handle.reset(
423  rcl_goal_handle, uuid,
424  std::static_pointer_cast<const typename ActionT::Goal>(goal_request_message),
425  on_terminal_state, on_executing, publish_feedback));
426  {
427  std::lock_guard<std::mutex> lock(goal_handles_mutex_);
428  goal_handles_[uuid] = goal_handle;
429  }
430  handle_accepted_(goal_handle);
431  }
432 
434  GoalID
435  get_goal_id_from_goal_request(void * message) override
436  {
437  return
438  static_cast<typename ActionT::GoalRequestService::Request *>(message)->action_goal_id.uuid;
439  }
440 
444  {
445  return std::shared_ptr<void>(new typename ActionT::GoalRequestService::Request());
446  }
447 
449  GoalID
450  get_goal_id_from_result_request(void * message) override
451  {
452  return
453  static_cast<typename ActionT::GoalResultService::Request *>(message)->action_goal_id.uuid;
454  }
455 
459  {
460  return std::shared_ptr<void>(new typename ActionT::GoalResultService::Request());
461  }
462 
465  create_result_response(decltype(action_msgs::msg::GoalStatus::status) status) override
466  {
467  auto result = std::make_shared<typename ActionT::GoalResultService::Response>();
468  result->action_status = status;
469  return std::static_pointer_cast<void>(result);
470  }
471 
472  // End API for communication between ServerBase and Server<>
473  // ---------------------------------------------------------
474 
475 private:
476  GoalCallback handle_goal_;
477  CancelCallback handle_cancel_;
478  AcceptedCallback handle_accepted_;
479 
484  std::mutex goal_handles_mutex_;
485 };
486 } // namespace rclcpp_action
487 #endif // RCLCPP_ACTION__SERVER_HPP_
GoalResponse
A response returned by an action server callback when a goal is requested.
Definition: server.hpp:43
GoalID get_goal_id_from_result_request(void *message) override
Definition: server.hpp:450
std::shared_ptr< void > create_result_response(decltype(action_msgs::msg::GoalStatus::status) status) override
Definition: server.hpp:465
CancelResponse
A response returned by an action server callback when a goal has been asked to be canceled...
Definition: server.hpp:54
std::pair< GoalResponse, std::shared_ptr< void > > call_handle_goal_callback(GoalID &uuid, std::shared_ptr< void > message) override
Definition: server.hpp:338
Action Server.
Definition: server.hpp:268
The server has agreed to try to cancel the goal.
Class to interact with goals on a server.
Definition: server_goal_handle.hpp:135
Definition: server.hpp:70
T lock(T... args)
T make_pair(T... args)
The goal is rejected and will not be executed.
std::shared_ptr< void > create_goal_request() override
Definition: server.hpp:443
T reset(T... args)
GoalID get_goal_id_from_goal_request(void *message) override
Definition: server.hpp:435
T static_pointer_cast(T... args)
Server(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base, rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock, rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging, const std::string &name, const rcl_action_server_options_t &options, GoalCallback handle_goal, CancelCallback handle_cancel, AcceptedCallback handle_accepted)
Construct an action server.
Definition: server.hpp:307
#define RCLCPP_ACTION_PUBLIC
Definition: visibility_control.hpp:50
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
std::shared_ptr< void > create_result_request() override
Definition: server.hpp:458
The server accepts the goal, and is going to execute it later.
Definition: client.hpp:44
CancelResponse call_handle_cancel_callback(const GoalID &uuid) override
Definition: server.hpp:355
void call_goal_accepted_callback(std::shared_ptr< rcl_action_goal_handle_t > rcl_goal_handle, GoalID uuid, std::shared_ptr< void > goal_request_message) override
Definition: server.hpp:374
The server accepts the goal, and is going to begin execution immediately.