5#include <condition_variable>
7#include <bondcpp/bond.hpp>
8#include <rclcpp/rclcpp.hpp>
14#include <capabilities2_msgs/srv/establish_bond.hpp>
15#include <capabilities2_msgs/srv/get_interfaces.hpp>
16#include <capabilities2_msgs/srv/get_semantic_interfaces.hpp>
17#include <capabilities2_msgs/srv/get_providers.hpp>
18#include <capabilities2_msgs/srv/use_capability.hpp>
19#include <capabilities2_msgs/srv/free_capability.hpp>
20#include <capabilities2_msgs/srv/connect_capability.hpp>
21#include <capabilities2_msgs/srv/trigger_capability.hpp>
23#include <capabilities2_msgs/msg/capability_event_code.hpp>
70 if (!
node_->has_parameter(
"capability_client.service_wait_timeout_sec"))
71 node_->declare_parameter<
int>(
"capability_client.service_wait_timeout_sec", -1);
74 node_->declare_parameter<std::string>(
"capability_client.services.get_interfaces",
"/capabilities/get_interfaces");
75 node_->declare_parameter<std::string>(
"capability_client.services.get_semantic_interfaces",
"/capabilities/get_semantic_interfaces");
76 node_->declare_parameter<std::string>(
"capability_client.services.get_providers",
"/capabilities/get_providers");
77 node_->declare_parameter<std::string>(
"capability_client.services.establish_bond",
"/capabilities/establish_bond");
78 node_->declare_parameter<std::string>(
"capability_client.services.use_capability",
"/capabilities/use_capability");
79 node_->declare_parameter<std::string>(
"capability_client.services.free_capability",
"/capabilities/free_capability");
80 node_->declare_parameter<std::string>(
"capability_client.services.trigger_capability",
"/capabilities/trigger_capability");
81 node_->declare_parameter<std::string>(
"capability_client.services.connect_capability",
"/capabilities/connect_capability");
111 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] initialized.");
123 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] requesting Interface information");
125 auto request_interface = std::make_shared<GetInterfaces::Request>();
127 bool completed =
false;
129 std::condition_variable cv;
130 std::unique_lock<std::mutex> lock(mtx);
134 request_interface, [
this, &completed, &cv, &capabilities](GetInterfacesClient::SharedFuture future) {
137 throw fabric::fabric_exception(
"Failed to get Interface information from "
141 auto response = future.get();
143 for (
const auto& interface : response->interfaces)
149 capabilities.push_back(info);
157 cv.wait(lock, [&completed]() {
return completed; });
159 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] received %d interfaces from server\n",
static_cast<int>(capabilities.size()));
170 int interface_count = capabilities.size();
172 std::vector<CapabilityInfo> new_capabilities;
174 for (
auto& capability : capabilities)
176 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] checking %s for semantic interfaces", capability.interface.c_str());
178 auto request_semantic = std::make_shared<GetSemanticInterfaces::Request>();
179 request_semantic->interface = capability.interface;
181 bool completed =
false;
183 std::condition_variable cv;
184 std::unique_lock<std::mutex> lock(mtx);
188 request_semantic, [
this, &new_capabilities, &completed, &cv](GetSemanticInterfacesClient::SharedFuture future) {
191 throw fabric::fabric_exception(
"Failed to get Semantic Interface information from server");
194 auto response = future.get();
197 for (
const auto& interface : response->semantic_interfaces)
203 new_capabilities.push_back(info);
204 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] Semantic interface: %s added\n", interface.c_str());
212 cv.wait(lock, [&completed]() {
return completed; });
216 capabilities.insert(capabilities.end(), new_capabilities.begin(), new_capabilities.end());
228 for (
auto& capability : capabilities)
230 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] requesting provider for %s", capability.interface.c_str());
232 auto request_providers = std::make_shared<GetProviders::Request>();
235 request_providers->interface = capability.interface;
236 request_providers->include_semantic = capability.is_semantic;
238 bool completed =
false;
240 std::condition_variable cv;
241 std::unique_lock<std::mutex> lock(mtx);
243 auto result_providers_future =
244 get_providers_client_->async_send_request(request_providers, [
this, &capability, &completed, &cv](GetProvidersClient::SharedFuture future) {
247 throw fabric::fabric_exception(
"Failed to get Provider information from server");
250 auto response = future.get();
251 capability.alt_providers = response->providers;
252 capability.provider = response->default_provider;
258 cv.wait(lock, [&completed]() {
return completed; });
260 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] received for %s, default provider: %s, number of alternative providers: %d\n",
261 capability.interface.c_str(), capability.provider.c_str(),
static_cast<int>(capability.alt_providers.size()));
272 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] requesting bond id");
275 auto request_bond = std::make_shared<EstablishBond::Request>();
278 bool completed =
false;
280 std::condition_variable cv;
281 std::unique_lock<std::mutex> lock(mtx);
288 throw fabric::fabric_exception(
"Failed to establish bond with capabilities2 server");
291 auto response = future.get();
292 bond_id = response->bond_id;
293 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] received bond id : %s\n", bond_id.c_str());
300 cv.wait(lock, [&completed]() {
return completed; });
320 auto request_use = std::make_shared<UseCapability::Request>();
323 request_use->bond_id = plan.
bond_id;
327 bool completed =
false;
329 std::condition_variable cv;
330 std::unique_lock<std::mutex> lock(mtx);
332 auto result_future =
use_capability_client_->async_send_request(request_use, [
this, &completed, &cv](UseCapabilityClient::SharedFuture future) {
335 throw fabric::fabric_exception(
"Failed to use capability");
338 auto response = future.get();
344 cv.wait(lock, [&completed]() {
return completed; });
361 std::vector<std::string> freed_capabilities;
377 bool completed =
false;
379 std::condition_variable cv;
380 std::unique_lock<std::mutex> lock(mtx);
385 auto request_free = std::make_shared<FreeCapability::Request>();
386 request_free->capability = capability;
387 request_free->bond_id = plan.
bond_id;
391 request_free, [
this, &completed, &cv, &capability](FreeCapabilityClient::SharedFuture future) {
394 throw fabric::fabric_exception(
"Failed to free capability " + capability);
397 auto response = future.get();
398 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] capability %s freed successfully.\n", capability.c_str());
404 cv.wait(lock, [&completed]() {
return completed; });
407 freed_capabilities.push_back(capability);
411 RCLCPP_WARN(
node_->get_logger(),
"[Capability client] capability %s was not started as part of the plan, skipping free request.",
417 for (
const auto& capability : freed_capabilities)
423 auto request = std::make_shared<ConnectCapability::Request>();
425 request->bond_id = bond_id;
427 request->connection.type.code = code;
429 request->connection.source = source.
parameters.toMsg();
430 request->connection.source.capability = source.
interface;
431 request->connection.source.provider = source.
provider;
432 request->connection.source.instance_id = std::to_string(source.
instance_id);
434 request->connection.target = target.
parameters.toMsg();
435 request->connection.target.capability = target.
interface;
436 request->connection.target.provider = target.
provider;
437 request->connection.target.instance_id = std::to_string(target.
instance_id);
439 bool completed =
false;
441 std::condition_variable cv;
442 std::unique_lock<std::mutex> lock(mtx);
446 connect_capability_client_->async_send_request(request, [
this, &completed, &cv](ConnectCapabilityClient::SharedFuture future) {
449 throw fabric::fabric_exception(
"Failed to configure capability connection event");
452 auto response = future.get();
454 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] capability connection event configured successfully.\n");
460 cv.wait(lock, [&completed]() {
return completed; });
478 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] connection to %s/%d on_start configuration requested",
485 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] connection to %s/%d on_stop configuration requested",
492 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] connection to %s/%d on_success configuration requested",
499 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] connection to %s/%d on_failure configuration requested",
514 auto request_trigger = std::make_shared<TriggerCapability::Request>();
516 bool completed =
false;
518 std::condition_variable cv;
519 std::unique_lock<std::mutex> lock(mtx);
521 request_trigger->bond_id = plan.
bond_id;
522 request_trigger->capability.instance_id = std::to_string(plan.
connections[0].source.instance_id);
523 request_trigger->capability.capability = plan.
connections[0].source.interface;
524 request_trigger->capability.parameters = plan.
connections[0].source.parameters.toMsg().parameters;
528 trig_capability_client_->async_send_request(request_trigger, [
this, &completed, &cv](TriggerCapabilityClient::SharedFuture future) {
531 throw fabric::fabric_exception(
"Failed to trigger the first capability.");
534 auto response = future.get();
537 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] first capability triggered successfully.");
541 cv.wait(lock, [&completed]() {
return completed; });
548 template <
typename ClientT>
549 void wait_for_service(
const std::shared_ptr<ClientT>& client,
const std::string& service_name)
551 using namespace std::chrono_literals;
553 auto start = std::chrono::steady_clock::now();
556 if (client->wait_for_service(1s))
558 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] %s connected", service_name.c_str());
562 RCLCPP_INFO(
node_->get_logger(),
"[Capability client] %s is not available", service_name.c_str());
566 const auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start);
Class for capability client interactions.
Definition capability_client.hpp:33
std::string get_semantic_interfaces_
Definition capability_client.hpp:588
void free_capabilities(fabric::Plan &plan)
Request free of all started capabilities from capabilities2 server.
Definition capability_client.hpp:358
rclcpp::Client< GetProviders > GetProvidersClient
Definition capability_client.hpp:48
rclcpp::Client< GetInterfaces > GetInterfacesClient
Definition capability_client.hpp:46
std::string configure_capability_
Definition capability_client.hpp:594
void connect_capabilities(fabric::Plan &plan)
Request connection between capabilities from according to the provided plan.
Definition capability_client.hpp:469
std::string free_capability_
Definition capability_client.hpp:592
void trigger_first_node(fabric::Plan &plan)
Trigger the first node.
Definition capability_client.hpp:512
std::string use_capability_
Definition capability_client.hpp:591
GetProvidersClient::SharedPtr get_providers_client_
Definition capability_client.hpp:611
rclcpp::Client< GetSemanticInterfaces > GetSemanticInterfacesClient
Definition capability_client.hpp:47
capabilities2_msgs::srv::GetSemanticInterfaces GetSemanticInterfaces
Definition capability_client.hpp:36
void getInterfaces(std::vector< CapabilityInfo > &capabilities)
Get the Interfaces from the capabilities2 server via related service client.
Definition capability_client.hpp:121
std::string request_bond()
Request the bond from the capabilities2 server.
Definition capability_client.hpp:270
std::string connect_capability_
Definition capability_client.hpp:595
rclcpp::Client< EstablishBond > EstablishBondClient
Definition capability_client.hpp:49
std::vector< std::string > started_capabilities_
Definition capability_client.hpp:602
rclcpp::Client< ConnectCapability > ConnectCapabilityClient
Definition capability_client.hpp:52
capabilities2_msgs::srv::GetInterfaces GetInterfaces
Definition capability_client.hpp:35
std::shared_ptr< bond::Bond > bond_
Heart beat bond with capabilities server.
Definition capability_client.hpp:600
capabilities2_msgs::srv::FreeCapability FreeCapability
Definition capability_client.hpp:40
rclcpp::Client< TriggerCapability > TriggerCapabilityClient
Definition capability_client.hpp:53
TriggerCapabilityClient::SharedPtr trig_capability_client_
Definition capability_client.hpp:626
virtual void initialize(const rclcpp::Node::SharedPtr &node)
Initialize the capability client with the given ROS2 node.
Definition capability_client.hpp:66
GetInterfacesClient::SharedPtr get_interfaces_client_
Definition capability_client.hpp:605
void use_capabilities(fabric::Plan &plan)
Request use of capability from capabilities2 server.
Definition capability_client.hpp:312
GetSemanticInterfacesClient::SharedPtr get_sem_interf_client_
Definition capability_client.hpp:608
capabilities2_msgs::srv::EstablishBond EstablishBond
Definition capability_client.hpp:38
void getSemanticInterfaces(std::vector< CapabilityInfo > &capabilities)
Get the Semantic Interfaces from the capabilities2 server via related service client.
Definition capability_client.hpp:168
void getProviders(std::vector< CapabilityInfo > &capabilities)
Get the Provider information for the related interfaces. T.
Definition capability_client.hpp:226
ConnectCapabilityClient::SharedPtr connect_capability_client_
Definition capability_client.hpp:623
rclcpp::Client< FreeCapability > FreeCapabilityClient
Definition capability_client.hpp:51
std::string establish_bond_
Definition capability_client.hpp:590
void wait_for_service(const std::shared_ptr< ClientT > &client, const std::string &service_name)
Wait for a service to become available.
Definition capability_client.hpp:549
capabilities2_msgs::srv::GetProviders GetProviders
Definition capability_client.hpp:37
void connect_capability(const std::string &bond_id, uint8_t code, const fabric::node &source, const fabric::node &target)
Definition capability_client.hpp:421
virtual ~CapabilityClient()=default
UseCapabilityClient::SharedPtr use_capability_client_
Definition capability_client.hpp:617
std::string get_interfaces_
service names
Definition capability_client.hpp:587
FreeCapabilityClient::SharedPtr free_capability_client_
Definition capability_client.hpp:620
rclcpp::Client< UseCapability > UseCapabilityClient
Definition capability_client.hpp:50
capabilities2_msgs::msg::CapabilityEventCode CapabilityEventCode
Definition capability_client.hpp:44
std::string get_providers_
Definition capability_client.hpp:589
capabilities2_msgs::srv::ConnectCapability ConnectCapability
Definition capability_client.hpp:41
int service_wait_timeout_sec_
Definition capability_client.hpp:582
capabilities2_msgs::srv::TriggerCapability TriggerCapability
Definition capability_client.hpp:42
CapabilityClient()
Definition capability_client.hpp:55
EstablishBondClient::SharedPtr establish_bond_client_
Definition capability_client.hpp:614
std::string trigger_capability_
Definition capability_client.hpp:593
rclcpp::Node::SharedPtr node_
pointer to the ROS2 node
Definition capability_client.hpp:580
capabilities2_msgs::srv::UseCapability UseCapability
Definition capability_client.hpp:39
Definition parser_base.hpp:9
Definition structs.hpp:80
std::string interface
Definition structs.hpp:81
bool is_semantic
Definition structs.hpp:83
Definition structs.hpp:70
std::map< int, connection > connections
Definition structs.hpp:74
std::string bond_id
Definition structs.hpp:73
Structure representing connections between nodes.
Definition structs.hpp:42
node on_success
Definition structs.hpp:46
node on_start
Definition structs.hpp:44
node source
Definition structs.hpp:43
node on_failure
Definition structs.hpp:47
node on_stop
Definition structs.hpp:45
Base class for driver exceptions.
Definition exception.hpp:14
Structure representing a node in the fabric.
Definition structs.hpp:26
std::string provider
Definition structs.hpp:28
std::string interface
Definition structs.hpp:27
bool exists() const
Definition structs.hpp:32
capabilities2_events::EventParameters parameters
Definition structs.hpp:29
int instance_id
Definition structs.hpp:30