16#ifndef EASYFLEET_CORE__DETAIL__CAPABILITY_IMPL_HPP_
17#define EASYFLEET_CORE__DETAIL__CAPABILITY_IMPL_HPP_
31#include "easyfleet_core/detail/namespace_utils.hpp"
33namespace easyfleet_core
38constexpr char kCapabilitiesFileParam[] =
"capabilities_file";
41template<
typename ActionServerT>
43 const std::string & capability_name,
44 const rclcpp::NodeOptions & options)
45: rclcpp_lifecycle::LifecycleNode(capability_name, options),
46 capability_name_(capability_name)
48 this->declare_parameter(detail::kCapabilitiesFileParam, std::string());
49 action_server_ = std::make_shared<ActionServerT>(*
this, capability_name_);
51 robot_name_ = detail::strip_leading_slash(this->get_namespace());
53 action_server_->get_action_name(),
false);
57 "Starting capability '%s' on robot '%s' (action: %s).",
58 capability_name_.c_str(),
59 detail::robot_label(this->get_namespace()).c_str(),
60 resolved_action_name_.c_str());
63template<
typename ActionServerT>
64Capability<ActionServerT>::~Capability()
69template<
typename ActionServerT>
73 return action_server_;
76template<
typename ActionServerT>
79 return capability_name_;
82template<
typename ActionServerT>
88template<
typename ActionServerT>
91 return resolved_action_name_;
94template<
typename ActionServerT>
98 capabilities_pub_ = this->create_publisher<easyfleet_interfaces::msg::CapabilityDescription>(
99 "/capabilities", rclcpp::QoS(1).reliable().transient_local());
100 status_pub_ = this->create_publisher<easyfleet_interfaces::msg::CapabilityStatus>(
101 "/capabilities_status", rclcpp::QoS(1).reliable());
102 return CallbackReturn::SUCCESS;
105template<
typename ActionServerT>
112 rclcpp_lifecycle::LifecycleNode::on_activate(previous_state);
114 const auto file_path = this->get_parameter(detail::kCapabilitiesFileParam).as_string();
115 if (file_path.empty()) {
118 "Capability '%s': the '%s' parameter must be set to a capabilities JSON file path.",
119 capability_name_.c_str(), detail::kCapabilitiesFileParam);
120 return CallbackReturn::FAILURE;
123 std::ifstream file(file_path);
124 if (!file.is_open()) {
127 "Capability '%s': could not open capabilities file '%s'.",
128 capability_name_.c_str(), file_path.c_str());
129 return CallbackReturn::FAILURE;
131 std::ostringstream contents;
132 contents << file.rdbuf();
134 easyfleet_interfaces::msg::CapabilityDescription description_msg;
135 description_msg.robot = robot_name_;
136 description_msg.capability = capability_name_;
137 description_msg.action_name = resolved_action_name_;
138 description_msg.description_json = contents.str();
139 capabilities_pub_->publish(description_msg);
141 heartbeat_timer_ = this->create_wall_timer(
142 std::chrono::seconds(1), std::bind(&Capability::publish_heartbeat,
this));
144 return CallbackReturn::SUCCESS;
147template<
typename ActionServerT>
152 rclcpp_lifecycle::LifecycleNode::on_deactivate(previous_state);
153 return CallbackReturn::SUCCESS;
156template<
typename ActionServerT>
161 capabilities_pub_.reset();
163 return CallbackReturn::SUCCESS;
166template<
typename ActionServerT>
171 capabilities_pub_.reset();
173 return CallbackReturn::SUCCESS;
176template<
typename ActionServerT>
177void Capability<ActionServerT>::publish_heartbeat()
179 easyfleet_interfaces::msg::CapabilityStatus msg;
180 msg.robot = robot_name_;
181 msg.capability = capability_name_;
182 msg.action_name = resolved_action_name_;
183 msg.busy = action_server_->is_active();
184 status_pub_->publish(msg);
187template<
typename ActionServerT>
188void Capability<ActionServerT>::stop_heartbeat()
190 if (heartbeat_timer_) {
191 heartbeat_timer_->cancel();
192 heartbeat_timer_.reset();
203template<
typename ActionServerT>
208 this->configure(cb_return_code);
209 return cb_return_code;
212template<
typename ActionServerT>
217 this->activate(cb_return_code);
218 return cb_return_code;
221template<
typename ActionServerT>
226 this->deactivate(cb_return_code);
227 return cb_return_code;
230template<
typename ActionServerT>
235 this->cleanup(cb_return_code);
236 return cb_return_code;
239template<
typename ActionServerT>
244 this->shutdown(cb_return_code);
245 return cb_return_code;
248template<
typename ActionServerT>
251 return rclcpp_lifecycle::LifecycleNode::get_current_state().id();
254template<
typename ActionServerT>
255rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
258 return rclcpp_lifecycle::LifecycleNode::get_node_base_interface();
std::shared_ptr< ActionServerBase< typename ActionServerT::ActionType > > SharedPtr
Definition action_server_base.hpp:81
CallbackReturn activate_node() override
Drive the underlying lifecycle node from INACTIVE to ACTIVE.
Definition capability_impl.hpp:214
CallbackReturn on_configure(const rclcpp_lifecycle::State &previous_state) override
Reads capabilities_file and configures the contained ActionServerT.
Definition capability_impl.hpp:96
CallbackReturn on_shutdown(const rclcpp_lifecycle::State &previous_state) override
Stops the status heartbeat if still running.
Definition capability_impl.hpp:168
const std::string & get_resolved_action_name() const noexcept
Fully-qualified name of the action this capability exposes, e.g.
Definition capability_impl.hpp:89
CallbackReturn on_deactivate(const rclcpp_lifecycle::State &previous_state) override
Stops the status heartbeat.
Definition capability_impl.hpp:149
Capability(const std::string &capability_name, const rclcpp::NodeOptions &options=rclcpp::NodeOptions())
Constructs the capability node.
Definition capability_impl.hpp:42
CallbackReturn on_activate(const rclcpp_lifecycle::State &previous_state) override
Publishes the capability description and starts the status heartbeat.
Definition capability_impl.hpp:107
CallbackReturn on_cleanup(const rclcpp_lifecycle::State &previous_state) override
Releases the resources acquired in on_configure().
Definition capability_impl.hpp:158
ActionServerBaseT::SharedPtr get_action_server() const noexcept
The action server backing this capability.
Definition capability_impl.hpp:71
CallbackReturn shutdown_node() override
Drive the underlying lifecycle node to FINALIZED, from whatever state it is currently in.
Definition capability_impl.hpp:241
CallbackReturn cleanup_node() override
Drive the underlying lifecycle node from INACTIVE to UNCONFIGURED.
Definition capability_impl.hpp:232
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn CallbackReturn
Lifecycle transition result type shared with rclcpp_lifecycle.
Definition capability.hpp:68
uint8_t get_current_state_id() const override
The underlying lifecycle node's current state id.
Definition capability_impl.hpp:249
CallbackReturn deactivate_node() override
Drive the underlying lifecycle node from ACTIVE to INACTIVE.
Definition capability_impl.hpp:223
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_base_interface() override
So a Deployment can add the underlying node to its shared executor without knowing its concrete type.
Definition capability_impl.hpp:256
const std::string & get_capability_name() const noexcept override
The capability identity field published on /capabilities and /capabilities_status.
Definition capability_impl.hpp:77
CallbackReturn configure_node() override
Drive the underlying lifecycle node from UNCONFIGURED to INACTIVE.
Definition capability_impl.hpp:205
const std::string & get_robot_name() const noexcept override
This node's namespace, without the leading '/' (empty if none), e.g.
Definition capability_impl.hpp:83