Skip to content

Commit a5435d8

Browse files
pablogs9jamoralpFranFin
authored
Add custom transport tutorial (#287)
* Add custom transport tutorial * Update * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Add jose's endpoints * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> * Update _docs/tutorials/advanced/create_custom_transports/index.md Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com> Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com> Co-authored-by: FranFin <58737168+FranFin@users.noreply.github.com>
1 parent 0290412 commit a5435d8

2 files changed

Lines changed: 242 additions & 0 deletions

File tree

_data/docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
- tutorials/advanced/benchmarking
6363
- tutorials/advanced/zephyr_emulator
6464
- tutorials/advanced/create_custom_static_library
65+
- tutorials/advanced/create_custom_transports
6566

6667
- title: Demos
6768
docs:
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
---
2+
title: Creating custom micro-ROS transports
3+
permalink: /docs/tutorials/advanced/create_custom_transports/
4+
---
5+
6+
This tutorial aims at providing step-by-step guidance for those users interested in creating micro-ROS custom transports, instead of using the ones provided by default in the micro-ROS tools set.
7+
8+
This tutorial starts from a previously created micro-ROS environment. Check the first steps of [**First micro-ROS application on an RTOS**](../../core/first_application_rtos/) for instructions on how to create a micro-ROS environment for embedded platforms.
9+
10+
The micro-ROS middleware, *eProsima Micro XRCE-DDS*, provides a user API that allows interfacing with the lowest level transport layer at runtime,
11+
which enables users to implement their own transports in both the micro-ROS Client and micro-ROS Agent libraries.
12+
Thanks to this, the Micro XRCE-DDS wire protocol can be transmitted over virtually any protocol, network or communication
13+
mechanism. In order to do so, two general communication modes are provided:
14+
15+
* **Stream-oriented mode**: the communication mechanism implemented does not have the concept of packet.
16+
[HDLC framing](https://micro-xrce-dds.docs.eprosima.com/en/latest/transport.html?highlight=hdlc#custom-serial-transport) will be used.
17+
* **Packet-oriented mode**: the communication mechanism implemented is able to send a whole packet that includes an XRCE message.
18+
19+
These two modes can be selected by activating and deactivating the `framing` parameter in both the micro-ROS Client and the micro-ROS Agent functions.
20+
21+
## micro-ROS Client
22+
23+
An example on how to set these external transport callbacks in the micro-ROS Client API is:
24+
25+
```c
26+
#include <rmw_uros/options.h>
27+
28+
...
29+
30+
struct custom_args {
31+
...
32+
}
33+
34+
struct custom_args args;
35+
36+
rmw_uros_set_custom_transport(
37+
true, // Framing enabled here. Using Stream-oriented mode.
38+
(void *) &args,
39+
my_custom_transport_open,
40+
my_custom_transport_close,
41+
my_custom_transport_write,
42+
my_custom_transport_read
43+
);
44+
```
45+
46+
It is important to notice that in `rmw_uros_set_custom_transport` a pointer to custom arguments is set. This reference will be available to every callbacks call.
47+
48+
In general, four functions must be implemented. The behaviour of these functions is slightly different, depending on the selected mode:
49+
50+
### Open function
51+
52+
```c
53+
bool my_custom_transport_open(uxrCustomTransport* transport)
54+
{
55+
...
56+
}
57+
```
58+
This function should open and init the custom transport. It returns a boolean indicating if the opening was successful.
59+
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.
60+
61+
### Close function
62+
```c
63+
bool my_custom_transport_close(uxrCustomTransport* transport)
64+
{
65+
...
66+
}
67+
```
68+
This function should close the custom transport. It returns a boolean indicating if closing was successful.
69+
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.
70+
71+
### Write function
72+
```c
73+
size_t my_custom_transport_write(
74+
uxrCustomTransport* transport,
75+
const uint8_t* buffer,
76+
size_t length,
77+
uint8_t* errcode)
78+
{
79+
...
80+
}
81+
```
82+
This function should write data to the custom transport. It returns the number of bytes written.
83+
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.
84+
85+
* **Stream-oriented mode:** The function can send up to `length` bytes from `buffer`.
86+
87+
* **Packet-oriented mode:** The function should send `length` bytes from `buffer`. If less than `length` bytes are written, `errcode` can be set.
88+
89+
### Read function
90+
```c
91+
size_t my_custom_transport_read(
92+
uxrCustomTransport* transport,
93+
uint8_t* buffer,
94+
size_t length,
95+
int timeout,
96+
uint8_t* errcode)
97+
{
98+
...
99+
}
100+
```
101+
This function should read data from the custom transport. It returns the number of bytes read.
102+
`transport->args` have the arguments passed through `uxr_init_custom_transport`.
103+
104+
* **Stream-oriented mode:** The function should retrieve up to `length` bytes from the transport
105+
and write them into `buffer` in `timeout` milliseconds.
106+
107+
* **Packet-oriented mode:** The function should retrieve `length` Bytes from transport
108+
and write them into `buffer` in `timeout` milliseconds. If less than `length` bytes are read, `errcode` can be set.
109+
110+
111+
112+
## Micro XRCE-DDS Agent
113+
114+
The micro-ROS Agent profile for custom transports is enabled by default.
115+
116+
An example on how to set the external transport callbacks in the micro-ROS Agent API is:
117+
118+
```cpp
119+
eprosima::uxr::Middleware::Kind mw_kind(eprosima::uxr::Middleware::Kind::FASTDDS);
120+
eprosima::uxr::CustomEndPoint custom_endpoint;
121+
122+
// Add transport endpoing parameters
123+
custom_endpoint.add_member<uint32_t>("param1");
124+
custom_endpoint.add_member<uint16_t>("param2");
125+
custom_endpoint.add_member<std::string>("param3");
126+
127+
eprosima::uxr::CustomAgent custom_agent(
128+
"my_custom_transport",
129+
&custom_endpoint,
130+
mw_kind,
131+
true, // Framing enabled here. Using Stream-oriented mode.
132+
my_custom_transport_open,
133+
my_custom_transport_close,
134+
my_custom_transport_write
135+
my_custom_transport_read);
136+
137+
custom_agent.start();
138+
```
139+
As in the *Client* API, four functions should be implemented. The behavior of these functions is sightly different
140+
depending on the selected mode.
141+
142+
### CustomEndPoint
143+
144+
The `custom_endpoint` is an object of type `eprosima::uxr::CustomEndPoint` and it is in charge of handling the endpoint parameters. The *Agent*, unlike the *Client*, can receive
145+
messages from multiple *Clients* so it must be able to differentiate between them.
146+
Therefore, the `eprosima::uxr::CustomEndPoint` should be provided with information about the origin of the message
147+
in the read callback, and with information about the destination of the message in the write callback.
148+
149+
In general, the members of a `eprosima::uxr::CustomEndPoint` object can be unsigned integers and strings.
150+
151+
`CustomEndPoint` defines three methods:
152+
153+
Add member
154+
```cpp
155+
bool eprosima::uxr::CustomEndPoint::add_member<*KIND*>(const std::string& member_name);
156+
```
157+
This function allows to dynamically add a new member to the endpoint definition.
158+
159+
Ir returns ``true`` if the member was correctly added, ``false`` if something went wrong (for example, if the member already exists).
160+
161+
- **KIND**: To be chosen from: `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.
162+
- **member_name**: The tag used to identify the endpoint member.
163+
164+
Set member value
165+
```cpp
166+
void eprosima::uxr::CustomEndPoint::set_member_value(const std::string& member_name, const *KIND* & value);
167+
```
168+
169+
This function sets the specific value (numeric or string) for a certain member, which must previously exist in the `CustomEndPoint`.
170+
171+
- **member_name**: The member whose value is going to be modified.
172+
- **value**: The value to be set, of `KIND`: `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.
173+
174+
Get member
175+
```cpp
176+
const *KIND* & eprosima::uxr::CustomEndPoint::get_member(const std::string& member_name);
177+
```
178+
179+
This function gets the current value of the member registered with the given parameter.
180+
The retrieved value might be an `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.
181+
182+
- **member_name**: The `CustomEndPoint` member name whose current value is requested.
183+
184+
### Open function
185+
```cpp
186+
eprosima::uxr::CustomAgent::InitFunction my_custom_transport_open = [&]() -> bool
187+
{
188+
...
189+
}
190+
```
191+
This function should open and init the custom transport. It returns a boolean indicating if the opening was successful.
192+
193+
### Close function
194+
```cpp
195+
eprosima::uxr::CustomAgent::FiniFunction my_custom_transport_close = [&]() -> bool
196+
{
197+
...
198+
}
199+
```
200+
This function should close the custom transport. It returns a boolean indicating if the closing was successful.
201+
202+
### Write function
203+
```cpp
204+
eprosima::uxr::CustomAgent::SendMsgFunction my_custom_transport_write = [&](
205+
const eprosima::uxr::CustomEndPoint* destination_endpoint,
206+
uint8_t* buffer,
207+
size_t length,
208+
eprosima::uxr::TransportRc& transport_rc) -> ssize_t
209+
{
210+
...
211+
}
212+
```
213+
This function should write data to the custom transport. It must use
214+
the `destination_endpoint` members to set the data destination. It returns the number of bytes written.
215+
It should set `transport_rc` indicating the result of the operation.
216+
217+
* **Stream-oriented mode:** The function can send up to `length` Bytes from `buffer`.
218+
219+
* **Packet-oriented mode:** The function should send `length` Bytes from `buffer`. If less than `length` bytes are written, `transport_rc` can be set.
220+
221+
### Read function
222+
```cpp
223+
eprosima::uxr::CustomAgent::RecvMsgFunction my_custom_transport_read = [&](
224+
eprosima::uxr::CustomEndPoint* source_endpoint,
225+
uint8_t* buffer,
226+
size_t length,
227+
int timeout,
228+
eprosima::uxr::TransportRc& transport_rc) -> ssize_t
229+
{
230+
...
231+
}
232+
```
233+
This function should read data to the custom transport. It must fill `source_endpoint` members with data source.
234+
It returns the number of bytes read.
235+
It should set `transport_rc` indicating the result of the operation.
236+
237+
* **Stream-oriented mode:** The function should retrieve up to `length` bytes from the transport
238+
and write them into `buffer` in `timeout` milliseconds.
239+
240+
* **Packet-oriented mode:** The function should retrieve `length` bytes from the transport
241+
and write them into `buffer` in `timeout` milliseconds. If less than `length` bytes are read, `transport_rc` can be set.

0 commit comments

Comments
 (0)