Skip to content

Commit 3497fde

Browse files
authored
Update README.md
1 parent 85fe095 commit 3497fde

File tree

1 file changed

+148
-19
lines changed

1 file changed

+148
-19
lines changed

README.md

Lines changed: 148 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,64 @@
1-
# rossdl (ROS System Definition Language)
1+
# ROSSDL (ROS System Definition Language)
2+
3+
Authors:
4+
* Francisco Martín Rico - [email protected]
5+
* Nadia Hammoudeh García - [email protected]
26

37
[![rolling](https://github.com/fmrico/rossdl/actions/workflows/rolling.yaml/badge.svg)](https://github.com/fmrico/rossdl/actions/workflows/rolling.yaml)
48

9+
*Brave ROS developers like to code*. ***But they like even more that their applications work***.
10+
11+
What is clear is that they do not like to plan their applications by applying tedious Software Engineering and Model-driven Engineering techniques, which require drawing boxes and connections at different levels and from different perspectives. But sometimes applications become large and unwieldy, and these software engineering techniques are required to validate, verify, and certify that the applications are correct, like it or not.
12+
13+
![ROSSDL_idea](https://github.com/user-attachments/assets/24bdacfe-bac3-4b06-a062-c2021082c522)
14+
15+
ROSSDL provides a tool that is in the middle of these two perspectives and is useful for both worlds: Programmers can continue writing lines of code, and software engineers are provided with a model-based file format where they can dump the output of their tools and take inputs for verification tasks.
16+
17+
## Quick trip through ROSSDL
18+
19+
Let's imagine that we need to develop an application in ROS 2 that looks like the following diagram:
20+
21+
![ROSSDL_simple_0](https://github.com/user-attachments/assets/e7e7356a-2d6d-438c-82d8-f248c11d71ef)
22+
23+
This is an application that has two nodes. The first, the Image Filter, subscribes to images from a camera and a laser range sensor to filter and merge these two inputs. The output of this node is received by a Consumer node that does some processing and publishes its result.
24+
25+
This is a simple application, but it already presents some challenges that waste a lot of a programmer's time. Connecting inputs from one node to outputs from another may be trivial, but it is a common point of failure due to topic names and qualities of service. Also, these nodes probably have some parameters that need to be kept track of.
26+
27+
In ROSSDL we are going to differentiate two different moments, which we often mix up: **Development** and **deployment**.
28+
29+
* By ***development***, we mean the development of the nodes that have to do with the application individually. The following diagram represents the simplified development planning of the application nodes:
530

6-
This repo contains a code generator that automatically generate base class for ROS2 nodes.
7-
It starts from a file like this:
31+
![ROSSDL_simple_1](https://github.com/user-attachments/assets/8bb716d7-347b-4449-9585-f2af746f839a)
32+
33+
* By ***deployment***, we mean how we configure our application components to be executed. In ROS 2, we typically do this by using launchers, which define parameters, connect nodes, and define all the details. Let's look at a diagram that shows deployment:
34+
35+
![ROSSDL_simple_2](https://github.com/user-attachments/assets/c66a111a-6384-4606-b63b-9d760d272a02)
36+
37+
### Development with ROSSDL
38+
39+
To use ROSSDL, you simply create `.ros2` and `.rossystem` files in your package.
40+
41+
![image](https://github.com/user-attachments/assets/7bae0b70-4866-41db-9d74-e83ee697c957)
42+
43+
These Yaml files define the nodes to develop with publishers, subscribers, and parameters (services and actions are not supported yet). In the development phase, we are only interested in the ".ros2" file, which looks like this:
844

945
```
1046
---
11-
rossdl_test:
47+
rossdl_simple_test:
1248
fromGitRepo: "https://github.com/jane-doe/project_example.git:branch"
1349
artifacts:
1450
image_filter:
1551
node: "image_filter"
1652
publishers:
1753
image_out:
1854
type: "sensor_msgs/msg/Image"
19-
qos:
20-
qos_profile: "sensor_qos"
2155
description_out:
2256
type: "std_msgs/msg/String"
23-
qos:
24-
qos_history_depth: 100
2557
subscribers:
2658
image_in:
2759
type: "sensor_msgs/msg/Image"
28-
qos:
29-
qos_profile: "sensor_qos"
30-
qos_reliability: "reliable"
3160
laser_in:
3261
type: "sensor_msgs/msg/LaserScan"
33-
qos:
34-
qos_profile: "sensor_qos"
35-
qos_reliability: "reliable"
3662
parameters:
3763
description_label:
3864
type: string
@@ -42,28 +68,131 @@ rossdl_test:
4268
subscribers:
4369
image_in:
4470
type: "sensor_msgs/msg/Image"
45-
qos:
46-
qos_profile: "sensor_qos"
47-
qos_reliability: "reliable"
4871
description_in:
4972
type: "std_msgs/msg/String"
73+
publishers:
74+
image_out:
75+
type: "sensor_msgs/msg/Image"
5076
```
5177

78+
When the workspace is compiled using `colcon build`, this file is read and the skeleton of the nodes is generated in the build directory. This approach is crucial as it prevents the source directory from being cluttered with generated code. The generated code consists of base classes for the nodes, which abstract the complexity of managing publishers, subscribers, and parameters. Consequently, the programmer only needs to define the application logic by inheriting from these base classes and adhering to some basic conventions and mechanisms, for example:
79+
80+
- If your node is called `consumer`, the base class will be `ConsumerBase`.
81+
- If you have a subscriber called `image_in`, its callback will be `image_in_callback`.
82+
- All topic names include as a prefix the node name.
83+
84+
```
85+
Consumer::Consumer(const rclcpp::NodeOptions & options)
86+
: ConsumerBase(options)
87+
{
88+
}
89+
90+
void
91+
Consumer::image_in_callback(sensor_msgs::msg::Image::SharedPtr msg)
92+
{
93+
RCLCPP_INFO(get_logger(), "Image message received");
94+
auto pub = get_publisher<sensor_msgs::msg::Image>("image_out");
95+
pub->publish(*msg);
96+
}
97+
98+
void
99+
Consumer::description_in_callback(std_msgs::msg::String::SharedPtr msg)
100+
{
101+
(void)msg;
102+
RCLCPP_INFO(get_logger(), "String message received");
103+
}
104+
```
105+
### Deployment with ROSSDL
106+
107+
In the deployment phase, we define one or more **systems**, each one will be a launcher file that will be generated in the `install` directory, right in the correct location. A `.rossystem` file written in Yaml define a system complete, selecting nodes to deploy, their connections, and parameters. This is an example of two systems in the same file:
108+
109+
```
110+
---
111+
rossdl_simple_test:
112+
fromGitRepo: "https://github.com/jane-doe/project_example.git:branch"
113+
systems:
114+
system_1:
115+
nodes: [rossdl_simple_test::image_filter, rossdl_simple_test::consumer]
116+
connections:
117+
- [/image_filter/image_out, /consumer/image_in]
118+
- [/image_filter/description_out, /consumer/description_in]
119+
- [/camera/rgb/image_raw, /image_filter/image_in]
120+
- [/consumer/image_out, /other_node/image_in]
121+
parameters:
122+
- [/image_filter/description_label, 'image raw']
123+
- [/*/use_sim_time, True]
124+
system_2:
125+
nodes: [rossdl_simple_test::image_filter, rossdl_simple_test::consumer]
126+
connections:
127+
- [/image_filter/image_out, /consumer/image_in]
128+
- [/image_filter/description_out, /consumer/description_in]
129+
parameters:
130+
- [/image_filter/description_label, 'image compressed']
131+
- [/*/use_sim_time, False]
132+
```
133+
134+
When building the system, launchers for both systems can be created. For example, the generated file `system_1.launcher.py` (in `install/rossdl_simple_test/share/rossdl_simple_test/launch/`) will have code like this:
135+
136+
```
137+
load_composable_nodes = LoadComposableNodes(
138+
target_container=container_name,
139+
composable_node_descriptions=[
140+
ComposableNode(
141+
package = 'rossdl_simple_test',
142+
plugin = 'rossdl_simple_test::ImageFilter',
143+
name = 'image_filter',
144+
remappings = [
145+
('/image_filter/image_out', '/consumer/image_in'),
146+
('/image_filter/description_out', '/consumer/description_in'),
147+
('/image_filter/image_in', '/camera/rgb/image_raw'),
148+
],
149+
parameters=[{
150+
'description_label': 'image raw',
151+
'use_sim_time': True,
152+
}],
153+
),
154+
ComposableNode(
155+
package = 'rossdl_simple_test',
156+
plugin = 'rossdl_simple_test::Consumer',
157+
name = 'consumer',
158+
remappings = [
159+
('/consumer/image_out', '/other_node/image_in'),
160+
],
161+
parameters=[{
162+
'use_sim_time': True,
163+
}],
164+
),
165+
])
166+
```
167+
168+
## Further documentation
169+
170+
* More examples: https://github.com/CoreSenseEU/rossdl/tree/rolling/rossdl_tests
171+
* More documentation: Coming soon at https://coresenseeu.github.io/
172+
52173
## Usage
53174

54-
Just place a definition file in your package, add this to CMakeLists:
175+
Just place a definition file in your package and add this to CMakeLists:
55176

56177
```
178+
find_package(rossdl_cmake REQUIRED)
179+
57180
rossdl_generate_code(${PROJECT_NAME}
58181
"description.ros2"
59182
${dependencies}
60183
)
184+
185+
rossdl_generate_system(
186+
"description.rossystem"
187+
"system_1"
188+
"system_2"
189+
)
61190
```
62191

63192
and compile with colcon:
64193

65194
```
66-
colcon build --symlink-install --packages-select rossdl_cmake rossdl_test
195+
colcon build --symlink-install
67196
```
68197

69198
Package `rossdl_test` contains an example of use.

0 commit comments

Comments
 (0)