Skip to content

Commit f800f4d

Browse files
committed
Renaming packages to better align with REP-0144 guidelines
1 parent a9268c6 commit f800f4d

22 files changed

+219
-89
lines changed

CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.10)
2-
project(ros2_serial)
2+
project(remote_serial)
33

44
# Compiler settings
55
if(NOT CMAKE_CXX_STANDARD)
@@ -9,6 +9,7 @@ endif()
99
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
1010
add_compile_options(-Wall -Wextra -Wpedantic)
1111
endif()
12+
add_compile_options(-fPIC)
1213

1314
# Dependencies
1415
find_package(ament_cmake REQUIRED)

README.md

+151-24
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,79 @@
1-
# OpenVMP
1+
# remote_serial
22

3-
[![License](./license.svg)](./LICENSE.txt)
3+
[![License](./apache20.svg)](./LICENSE.txt)
44

5-
This package is a part of [the OpenVMP project](https://github.com/openvmp/openvmp).
6-
But it's designed to be universal and usable independently from the rest of OpenVMP or in a combination with select OpenVMP packages.
5+
This is an ultimate implementation of serial line interface for ROS2.
76

8-
## ROS2 serial driver
9-
10-
This is an ultimate C++ implementation of serial port driver for ROS2.
11-
12-
It can be used either as a library or a standalone process. In both cases it
13-
provides ROS2 interfaces for inter-process access, introspection and
7+
It provides ROS2 interfaces for inter-process access, introspection and
148
debugging.
159
It performs wisely in case of serial line saturation in any of
1610
the I/O directions, minimizing data loses and blocking behavior,
17-
ensuring maximum performance.
11+
ensuring optimum performance.
12+
13+
This package implements a generic purpose serial port driver using
14+
character device files.
15+
However this package also implements most of the logic required for other
16+
serial line drivers (see the "Examples" section below).
17+
18+
## ROS2 interfaces
19+
20+
### Parameters
21+
22+
All classes:
23+
24+
- `serial_prefix`: the prefix to ROS2 interfaces exposed by this driver
25+
("/serial/<node-name>" by default)
26+
27+
The factory class:
1828

29+
- `serial_is_remote`: instructs whether
30+
to instantiate the driver locally or to connect to a remote instance
31+
("true" by default)
1932

20-
### Basic setup
33+
Serial port driver:
34+
35+
- `serial_dev_name`: the character device path ("/dev/ttyS0" by default)
36+
- serial port settings:
37+
- `serial_skip_init`: skip the port initialization (ignore the below parameters)
38+
- `serial_baud_rate`: baud rate ("115200" by default)
39+
- `serial_data`: data bits ("8" by default)
40+
- `serial_parity`: parity bit ("false" by default)
41+
- `serial_stop`: stop bits ("1" by default)
42+
- `serial_flow_control`: hardware flow control ("false" by default)
43+
- `serial_sw_flow_control`: software flow control ("false" by default)
44+
- `serial_bs`: the size of read buffer ("1024" by default)
45+
46+
### Topics
47+
48+
#### Subscribers
49+
50+
- `<namespace>/<serial_prefix>/inject/input`: injects the given bytes into
51+
the serial line as if it was written to the line by the driver
52+
- `<namespace>/<serial_prefix>/inject/output`: injects the given bytes into
53+
the serial line as if it was received by the driver from the line
54+
55+
#### Publishers
56+
57+
- `<namespace>/<serial_prefix>/inspect/input`: publishes data
58+
received by the driver from the line
59+
- `<namespace>/<serial_prefix>/inspect/output`: publishes data
60+
sent by the driver to the line
61+
62+
## Basic setup
2163

2264
Launch it as a separate node for each serial port:
2365

2466
```
25-
$ ros2 run ros2_serial ros2_serial_standalone
67+
$ ros2 run remote_serial remote_serial_standalone
2668
```
2769

2870
or
2971

3072
```
31-
$ ros2 run ros2_serial ros2_serial_standalone \
73+
$ ros2 run remote_serial remote_serial_standalone \
3274
--ros-args \
3375
--remap serial:__node:=serial_com1 \
76+
-p serial_is_remote:=false \
3477
-p serial_prefix:=/serial/com1 \
3578
-p serial_dev_name:=/dev/ttyS0 \
3679
-p serial_baud_rate:=115200 \
@@ -42,15 +85,15 @@ $ ros2 run ros2_serial ros2_serial_standalone \
4285

4386
```mermaid
4487
flowchart TB
45-
cli["$ ros2 topic echo /serial/com1"] -. "DDS" .-> topic_serial[/ROS2 interfaces:\n/serial/com1/.../]
88+
cli["<p style='text-align:left'>$ ros2 topic echo /serial/com1/inspect/input\n$ ros2 topic echo /serial/com1/inspect/output\n$ ros2 topic pub /serial/com1/inject/output \\n&nbsp;&nbsp;&nbsp;std_msgs/msg/UInt8MultiArray {'data':'ATH+CHUP\r\ n'}</p>"] -. "DDS" .-> topic_serial[/ROS2 interfaces:\n/serial/com1/.../]
4689
app["Your process"] -- "DDS\n(with context switch)" --> topic_serial
47-
subgraph serial["Process: ros2_serial_standalone"]
90+
subgraph serial["Process: remote_serial_standalone"]
4891
topic_serial --> driver["Serial port driver"]
4992
end
5093
driver --> file{{"Character device: /dev/ttyS0"}}
5194
```
5295

53-
### Advanced setup
96+
## Advanced setup
5497

5598
The more advanced setup is to initialize it as a separate node in the very executable which will be communicating with the port all the time
5699
(e.g. a MODBUS RTU implementation).
@@ -61,9 +104,9 @@ See an example of such a setup in the Modbus RTU package:
61104

62105
```mermaid
63106
flowchart TB
64-
cli_serial["# Serial debugging\n$ ros2 topic echo /serial"] -. "DDS" ..-> topic_serial[/ROS2 interfaces:\n/serial/.../]
107+
cli_serial["<p style='text-align:left'># Serial debugging and troubleshooting\n$ ros2 topic echo /serial/inspect/input\n...</p>"] -. "DDS" ..-> topic_serial[/ROS2 interfaces:\n/serial/.../]
65108
subgraph modbus_exe["Your process"]
66-
subgraph serial["Library: ros2_serial"]
109+
subgraph serial["Library: remote_serial"]
67110
topic_serial --> driver["Serial port driver"]
68111
end
69112
code["Your code"] -- "DDS\n(potentially without\ncontext switch)" --> topic_serial
@@ -73,16 +116,18 @@ flowchart TB
73116
```
74117

75118

76-
### Implementation details
119+
## Implementation details
120+
121+
The following diagram shows the high level view on the internals of this package:
77122

78123
```mermaid
79124
flowchart TB
80125
owner["Native API"]
81126
external["ROS2 Interface API"]
82127
83-
subgraph node["ros2_serial::Node"]
128+
subgraph node["remote_serial::Node"]
84129
85-
subgraph interface_ros2["ros2_serial::InterfaceRemote"]
130+
subgraph interface_ros2["remote_serial::Interface"]
86131
subgraph topics["Topics: /serial"]
87132
published_input[//inspect/input/]
88133
published_output[//inspect/output/]
@@ -94,11 +139,11 @@ flowchart TB
94139
end
95140
end
96141
97-
subgraph worker["ros2_serial::Port"]
142+
subgraph worker["remote_serial::Port"]
98143
output_queue["Output Queue"]
99144
thread["Worker thread\nrunning select()"]
100145
101-
subgraph interface_native["ros2_serial::Implementation"]
146+
subgraph interface_native["remote_serial::Implementation"]
102147
subgraph register_input_cb["register_input_cb()"]
103148
input_cb["input_cb()"]
104149
end
@@ -133,3 +178,85 @@ flowchart TB
133178
thread -- "output" --> fd -- "output" --> file
134179
135180
```
181+
182+
## Implementing serial line drivers
183+
184+
The serial line drivers implement the base class provided by this package.
185+
For C++ drivers, that means that they use
186+
`remote_serial::Implementation` as a parent class.
187+
Its constructor requires an instance of `rclcpp::Node` to read the
188+
parameters from.
189+
190+
<i>
191+
Note:
192+
There can be more than one instance of `remote_serial::Implementation`
193+
per node. However they will all be controlled by the same parameters.
194+
Though the default value of the parameter `serial_prefix` can be passed
195+
into each individual constructor which is sufficient for common use cases.
196+
</i>
197+
<br/>
198+
<br/>
199+
200+
The following methods need to be implemented by each driver:
201+
202+
```c++
203+
public:
204+
// output writes bytes to the serial line
205+
virtual void output(const std::string &) override;
206+
207+
// register_input_cb is used to set the callback function which
208+
// is called every time data is received from the serial line
209+
virtual void register_input_cb(void (*)(const std::string &msg,
210+
void *user_data),
211+
void *user_data) override;
212+
```
213+
214+
The users can chose one of three ways to interact with child classes of `remote_serial::Implementation`:
215+
216+
- Link with the driver directly to make native API calls:
217+
218+
```c++
219+
auto serial = \
220+
std::make_shared<driver_package::DriverClass>(node, "/serial");
221+
serial->output("ATH+CHUP\r\n");
222+
```
223+
224+
In this case the driver is running within the same process and it is
225+
destroyed when the `serial` object is destroyed.
226+
227+
- Link with `remote_serial` to make ROS2 interface (DDS) calls
228+
(locally or over a network):
229+
230+
```c++
231+
auto serial = \
232+
std::make_shared<remote_serial::RemoteInterface>(node, "/serial");
233+
serial->output("ATH+CHUP\r\n");
234+
```
235+
236+
In this case the driver can be elsewhere within DDS' reach
237+
(same process or another side of the globe).
238+
239+
- Let the runtime make the choice between the above two options:
240+
241+
```c++
242+
auto serial = \
243+
remote_serial::Factory::New(node, "/serial");
244+
// or
245+
auto serial = \
246+
driver_package::Factory::New(node, "/serial");
247+
```
248+
249+
In this case the boolean value of the parameter `serial_is_remote`
250+
determines whether the driver is instantiated locally or if a remote
251+
interface is used to reach the driver instantiated elsewhere.
252+
Please, note, the trivial class `driver_package::Factory`
253+
(similar to `remote_serial::Factory`) has to be written
254+
to support this use case.
255+
256+
## Examples
257+
258+
### remote_microcontroller
259+
260+
See the UART implementation in
261+
[remote_microcontroller](https://github.com/openvmp/microcontroller)
262+
for an example of a driver that implements `remote_serial`.

license.svg apache20.svg

File renamed without changes.

include/ros2_serial/factory.hpp include/remote_serial/factory.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
#include <memory>
1414

1515
#include "rclcpp/rclcpp.hpp"
16-
#include "ros2_serial/interface.hpp"
16+
#include "remote_serial/interface.hpp"
1717

18-
namespace ros2_serial {
18+
namespace remote_serial {
1919

2020
class Factory {
2121
public:
2222
static std::shared_ptr<Interface> New(rclcpp::Node *node);
2323
};
2424

25-
} // namespace ros2_serial
25+
} // namespace remote_serial
2626

2727
#endif // OPENVMP_SERIAL_FACTORY_H

include/ros2_serial/implementation.hpp include/remote_serial/implementation.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
#include <string>
1515

1616
#include "rclcpp/rclcpp.hpp"
17-
#include "ros2_serial/interface.hpp"
17+
#include "remote_serial/interface.hpp"
1818
#include "std_msgs/msg/empty.hpp"
1919
#include "std_msgs/msg/u_int8_multi_array.hpp"
2020
#include "std_srvs/srv/empty.hpp"
2121

22-
namespace ros2_serial {
22+
namespace remote_serial {
2323

2424
class Implementation : public Interface {
2525
public:
@@ -55,6 +55,6 @@ class Implementation : public Interface {
5555
void inject_output_handler_(const std_msgs::msg::UInt8MultiArray::SharedPtr);
5656
};
5757

58-
} // namespace ros2_serial
58+
} // namespace remote_serial
5959

6060
#endif // OPENVMP_SERIAL_IMPLEMENTATION_H

include/ros2_serial/interface.hpp include/remote_serial/interface.hpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@
2121
#define SERIAL_TOPIC_INJECT_OUTPUT "/inject/output"
2222
#define SERIAL_SERVICE_FLUSH "/flush"
2323

24-
namespace ros2_serial {
24+
namespace remote_serial {
2525

2626
class Interface {
2727
public:
2828
Interface(rclcpp::Node *node, const std::string &default_prefix = "");
2929
virtual ~Interface() {}
3030

31+
// output writes bytes to the serial line
3132
virtual void output(const std::string &) = 0;
3233

33-
// having pure pointers would improve performance here
34-
// but it would be against the religion of so many
34+
// register_input_cb is used to set the callback function which
35+
// is called every time data is received from the serial line
3536
virtual void register_input_cb(void (*)(const std::string &msg,
3637
void *user_data),
3738
void *user_data) = 0;
@@ -47,6 +48,6 @@ class Interface {
4748
rclcpp::Parameter interface_prefix_;
4849
};
4950

50-
} // namespace ros2_serial
51+
} // namespace remote_serial
5152

5253
#endif // OPENVMP_SERIAL_INTERFACE_H

include/ros2_serial/interface_remote.hpp include/remote_serial/interface_remote.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
#include "rclcpp/callback_group.hpp"
1818
#include "rclcpp/rclcpp.hpp"
19-
#include "ros2_serial/interface.hpp"
19+
#include "remote_serial/interface.hpp"
2020
#include "std_msgs/msg/empty.hpp"
2121
#include "std_msgs/msg/u_int8_multi_array.hpp"
2222
#include "std_srvs/srv/empty.hpp"
2323

24-
namespace ros2_serial {
24+
namespace remote_serial {
2525

2626
class RemoteInterface final : public Interface {
2727
public:
@@ -55,6 +55,6 @@ class RemoteInterface final : public Interface {
5555
rclcpp::Client<std_srvs::srv::Empty>::SharedPtr clnt_flush_;
5656
};
5757

58-
} // namespace ros2_serial
58+
} // namespace remote_serial
5959

6060
#endif // OPENVMP_SERIAL_INTERFACE_REMOTE_H

include/ros2_serial/node.hpp include/remote_serial/node.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#include <string>
1515

1616
#include "rclcpp/rclcpp.hpp"
17-
#include "ros2_serial/port.hpp"
17+
#include "remote_serial/port.hpp"
1818

19-
namespace ros2_serial {
19+
namespace remote_serial {
2020

2121
class Node : public rclcpp::Node {
2222
public:
@@ -26,6 +26,6 @@ class Node : public rclcpp::Node {
2626
std::shared_ptr<Port> impl_;
2727
};
2828

29-
} // namespace ros2_serial
29+
} // namespace remote_serial
3030

3131
#endif // OPENVMP_SERIAL_NODE_H

include/ros2_serial/port.hpp include/remote_serial/port.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#include <string>
1515

1616
#include "rclcpp/rclcpp.hpp"
17-
#include "ros2_serial/implementation.hpp"
17+
#include "remote_serial/implementation.hpp"
1818

19-
namespace ros2_serial {
19+
namespace remote_serial {
2020

2121
class PortSettings {
2222
public:
@@ -61,6 +61,6 @@ class Port final : public Implementation {
6161
std::shared_ptr<Worker> worker_;
6262
};
6363

64-
} // namespace ros2_serial
64+
} // namespace remote_serial
6565

6666
#endif // OPENVMP_SERIAL_PORT_H

0 commit comments

Comments
 (0)