ros2_client/service/
mod.rs

1//! Implementation of ROS 2 [Services](https://docs.ros.org/en/rolling/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Services/Understanding-ROS2-Services.html)
2use std::marker::PhantomData;
3
4#[allow(unused_imports)]
5use log::{debug, error, info, warn};
6
7use crate::message::Message;
8
9pub mod client;
10pub mod request_id;
11pub mod server;
12pub(super) mod wrappers;
13
14pub use request_id::*;
15use wrappers::*;
16pub use server::*;
17pub use client::*;
18
19// --------------------------------------------
20// --------------------------------------------
21
22/// Service trait pairs the Request and Response types together.
23/// Additionally, it ensures that Response and Request are Messages
24/// (Serializable), and we have a means to name the types.
25pub trait Service {
26  type Request: Message;
27  type Response: Message;
28  fn request_type_name(&self) -> &str;
29  fn response_type_name(&self) -> &str;
30}
31
32// --------------------------------------------
33// --------------------------------------------
34
35/// AService is a means of constructing a descriptor for a Service on the fly.
36/// This allows generic code to construct a Service from the types of
37/// request and response.
38pub struct AService<Q, S>
39where
40  Q: Message,
41  S: Message,
42{
43  q: PhantomData<Q>,
44  s: PhantomData<S>,
45  req_type_name: String,
46  resp_type_name: String,
47}
48
49impl<Q, S> AService<Q, S>
50where
51  Q: Message,
52  S: Message,
53{
54  pub fn new(req_type_name: String, resp_type_name: String) -> Self {
55    Self {
56      req_type_name,
57      resp_type_name,
58      q: PhantomData,
59      s: PhantomData,
60    }
61  }
62}
63
64impl<Q, S> Service for AService<Q, S>
65where
66  Q: Message,
67  S: Message,
68{
69  type Request = Q;
70  type Response = S;
71
72  fn request_type_name(&self) -> &str {
73    &self.req_type_name
74  }
75
76  fn response_type_name(&self) -> &str {
77    &self.resp_type_name
78  }
79}
80
81// --------------------------------------------
82// --------------------------------------------
83
84/// Selects how Service Requests and Responses are to be mapped to DDS.
85///
86/// There are different and incompatible ways to map Services onto DDS Topics.
87/// In order to interoperate with ROS 2, you have to select the same mapping it
88/// uses. The mapping used by ROS2 depends on the DDS implementation used and
89/// its configuration.
90///
91/// For details, see OMG Specification
92/// [RPC over DDS](https://www.omg.org/spec/DDS-RPC/1.0/About-DDS-RPC/)
93/// Section "7.2.4 Basic and Enhanced Service Mapping for RPC over DDS",
94/// which defines Service Mappings "Basic" and "Enhanced".
95///
96/// ServiceMapping::Cyclone represents a third mapping used by RMW for
97/// CycloneDDS.
98#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99pub enum ServiceMapping {
100  /// "Basic" service mapping from RPC over DDS specification.
101  /// * RTI Connext with `RMW_CONNEXT_REQUEST_REPLY_MAPPING=basic`, but this is
102  ///   not tested, so may not work.
103  Basic,
104
105  /// "Enhanced" service mapping from RPC over DDS specification.
106  /// * ROS2 Foxy with eProsima DDS,
107  /// * ROS2 Galactic with RTI Connext (rmw_connextdds, not rmw_connext_cpp) -
108  ///   set environment variable `RMW_CONNEXT_REQUEST_REPLY_MAPPING=extended`
109  ///   before running ROS2 executable.
110  Enhanced,
111
112  /// CycloneDDS-specific service mapping.
113  /// Specification for this mapping is unknown, technical details are
114  /// reverse-engineered from ROS2 sources.
115  /// * ROS2 Galactic with CycloneDDS - Seems to work on the same host only, not
116  ///   over actual network.
117  Cyclone,
118}