Skip to content

Commit 9bbf409

Browse files
authored
Support .idl files for ROS message/service/action (#1181)
This PR adds full support for ROS2 `.idl` files by extending parsing, generation, testing, and documentation to include IDL-based interfaces. - Extend `packages.js` and directory walkers to detect and store `.idl` files. - Integrate a Python-based IDL-to-ROS converter and wire it into `index.js` under a new `--idl` flag. - Update tests, npm scripts, CI workflows, versioning, and README to cover IDL support. - Pump `rosidl-generator` to `1.0.0`. Meanwhile, this patch pumps Windows action image to `windows-2025` because the previous one has been deprecated. Fix: #764
1 parent 82bbc82 commit 9bbf409

File tree

13 files changed

+1641
-42
lines changed

13 files changed

+1641
-42
lines changed

.github/workflows/linux-x64-build-and-test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ jobs:
7474
npm test
7575
npm run clean
7676
77+
- name: Test with IDL ROS messages against rolling
78+
if: ${{ matrix.ros_distribution == 'rolling' }}
79+
run: |
80+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
81+
npm i
82+
npm run test-idl
83+
npm run clean
84+
7785
- name: Coveralls Parallel
7886
uses: coverallsapp/github-action@v2
7987
with:

.github/workflows/windows-build-and-test-compatibility.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
build:
9-
runs-on: windows-2019
9+
runs-on: windows-2025
1010
strategy:
1111
fail-fast: false
1212
matrix:

.github/workflows/windows-build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ on:
1717

1818
jobs:
1919
build:
20-
runs-on: windows-2019
20+
runs-on: windows-2025
2121
strategy:
2222
fail-fast: false
2323
matrix:

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ rclnodejs.init().then(() => {
3232
- [rclnodejs-cli](#rclnodejs-cli)
3333
- [API Documentation](#api-documentation)
3434
- [Using TypeScript](#using-rclnodejs-with-typescript)
35+
- [ROS2 Interface Message Generation](#ros2-interface-message-generation-important)
36+
- [IDL Message Generation](#idl-message-generation)
3537
- [Examples](https://github.com/RobotWebTools/rclnodejs/tree/develop/example)
3638
- [Electron demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo)
3739
- [Efficient Usage Tips](./docs/EFFICIENCY.md)
@@ -146,6 +148,18 @@ let stringMsgObject = rclnodejs.createMessageObject('std_msgs/msg/String');
146148
stringMsgObject.data = 'hello world';
147149
```
148150

151+
## IDL Message Generation
152+
153+
In addition to the standard ROS2 message generation (`.msg`, `.srv`, and `.action`), rclnodejs provides advanced support for generating JavaScript message files directly from IDL (Interface Definition Language) files. This feature is particularly useful when working with custom IDL files or when you need more control over the message generation process.
154+
155+
### Running `generate-messages-idl`
156+
157+
To generate messages from IDL files, use the `generate-messages-idl` npm script:
158+
159+
```bash
160+
npm run generate-messages-idl
161+
```
162+
149163
### Maintaining Generated JavaScript Message Files
150164

151165
Message files are generated as a post-install step of the rclnodejs

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
"rebuild": "npm run clean && node-gyp -j 16 rebuild",
1919
"rebuild:dev": "npm run clean && node-gyp -j 16 rebuild --debug",
2020
"generate-messages": "node scripts/generate_messages.js",
21+
"generate-messages-idl": "node scripts/generate_messages.js --idl",
2122
"generate-messages:dev": "node scripts/generate_messages.js --debug && npx --yes prettier --ignore-path --write generated/**/*.js",
2223
"generate-tsd-messages": "node scripts/generate_tsd.js",
2324
"clean": "node-gyp clean && npx rimraf ./generated",
2425
"install": "npm run rebuild",
2526
"postinstall": "npm run generate-messages",
2627
"docs": "cd docs && make",
2728
"test": "nyc node --expose-gc ./scripts/run_test.js && tsd",
29+
"test-idl": "nyc node --expose-gc ./scripts/run_test.js --idl",
2830
"lint": "eslint && node ./scripts/cpplint.js",
2931
"format": "clang-format -i -style=file ./src/*.cpp ./src/*.h && npx --yes prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark,rostsd_gen}/**/*.{js,md,ts}\" ./*.{js,md,ts}",
3032
"prepare": "husky",

rosidl_convertor/README.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# ROS2 IDL to Interface Converter
2+
3+
This Python tool converts ROS2 `.idl` files to corresponding `.msg`, `.srv`, and `.action` files.
4+
5+
## Features
6+
7+
- **Complete IDL Parsing**: Parses ROS2 IDL syntax including modules, structs, sequences, and arrays
8+
- **Type Mapping**: Automatically maps IDL types to ROS2 types (e.g., `double``float64`, `sequence<T>``T[]`)
9+
- **Typedef Support**: Handles both simple and array typedefs for complex type definitions
10+
- **Constants and Default Values**: Supports constant definitions and field default values with `@default` annotations
11+
- **Comment Preservation**: Extracts and preserves comments from `@verbatim` blocks
12+
- **Key Annotation Detection**: Automatically skips IDL files with `@key` annotations (not supported in ROS2)
13+
- **Multi-Interface Support**: Handles messages, services, and actions in a single IDL file
14+
- **Namespace Support**: Properly handles namespaced types (e.g., `std_msgs::msg::Header``std_msgs/Header`)
15+
- **Command Line Interface**: Easy to use with command line arguments
16+
- **Verbose Output**: Optional detailed output showing parsed structures and generated files
17+
18+
## Usage
19+
20+
### Basic Usage
21+
22+
```bash
23+
python3 idl_convertor.py <idl_file>
24+
```
25+
26+
### With Options
27+
28+
```bash
29+
python3 idl_convertor.py <idl_file> [options]
30+
```
31+
32+
### Options
33+
34+
- `-o, --output DIR`: Output directory name for generated files (default: `ros_interfaces`)
35+
- `-r, --root PATH`: Root path where the generated files will be located (default: current directory)
36+
- `-p, --package NAME`: Package name to use for generated files (overrides package name from IDL)
37+
- `-v, --verbose`: Enable verbose output showing parsed structures and file contents
38+
- `-h, --help`: Show help message
39+
40+
### Advanced Examples
41+
42+
#### Custom Output Directory
43+
44+
```bash
45+
python3 idl_convertor.py JointState.idl -o my_interfaces
46+
```
47+
48+
#### Custom Root Path
49+
50+
```bash
51+
python3 idl_convertor.py SetCameraInfo.idl -r /path/to/workspace -o sensor_msgs
52+
# Generates files in: /path/to/workspace/sensor_msgs/srv/SetCameraInfo.srv
53+
```
54+
55+
#### Custom Package Name
56+
57+
```bash
58+
python3 idl_convertor.py JointState.idl -p my_package_name
59+
# Overrides the package name from the IDL file
60+
```
61+
62+
#### Combined Options
63+
64+
```bash
65+
python3 idl_convertor.py SetCameraInfo.idl -r ~/ros2_ws/src -o sensor_msgs -p sensor_msgs -v
66+
# Generates: ~/ros2_ws/src/sensor_msgs/srv/SetCameraInfo.srv with package name "sensor_msgs"
67+
```
68+
69+
## Examples
70+
71+
### 1. Convert a Message IDL
72+
73+
Input file `JointState.idl`:
74+
75+
```idl
76+
#include "std_msgs/msg/Header.idl"
77+
78+
module sensor_msgs {
79+
module msg {
80+
struct JointState {
81+
std_msgs::msg::Header header;
82+
sequence<string> name;
83+
sequence<double> position;
84+
sequence<double> velocity;
85+
sequence<double> effort;
86+
};
87+
};
88+
};
89+
```
90+
91+
Output `JointState.msg`:
92+
93+
```
94+
# JointState.msg
95+
# Generated from IDL file
96+
97+
std_msgs/Header header
98+
string[] name
99+
float64[] position
100+
float64[] velocity
101+
float64[] effort
102+
```
103+
104+
### 2. Convert a Service IDL
105+
106+
Input file `SetCameraInfo.idl`:
107+
108+
```idl
109+
#include "sensor_msgs/msg/CameraInfo.idl"
110+
111+
module sensor_msgs {
112+
module srv {
113+
struct SetCameraInfo_Request {
114+
sensor_msgs::msg::CameraInfo camera_info;
115+
};
116+
struct SetCameraInfo_Response {
117+
boolean success;
118+
string status_message;
119+
};
120+
};
121+
};
122+
```
123+
124+
Output `SetCameraInfo.srv`:
125+
126+
```
127+
# SetCameraInfo.srv
128+
# Generated from IDL file
129+
130+
# Request
131+
sensor_msgs/CameraInfo camera_info
132+
---
133+
# Response
134+
bool success
135+
string status_message
136+
```
137+
138+
### 3. Convert an Action IDL
139+
140+
Input file `Fibonacci.idl`:
141+
142+
```idl
143+
module example_interfaces {
144+
module action {
145+
struct FibonacciGoal {
146+
int32 order;
147+
};
148+
149+
struct FibonacciResult {
150+
sequence<int32> sequence;
151+
};
152+
153+
struct FibonacciFeedback {
154+
sequence<int32> partial_sequence;
155+
};
156+
};
157+
};
158+
```
159+
160+
Generates separate message files for goal, result, and feedback components.
161+
162+
## Type Mappings
163+
164+
### Basic Type Mappings
165+
166+
| IDL Type | ROS2 Type |
167+
| ---------------- | ---------- |
168+
| `boolean` | `bool` |
169+
| `octet` | `uint8` |
170+
| `int8` | `int8` |
171+
| `uint8` | `uint8` |
172+
| `int16` | `int16` |
173+
| `uint16` | `uint16` |
174+
| `int32` | `int32` |
175+
| `uint32` | `uint32` |
176+
| `int64` | `int64` |
177+
| `uint64` | `uint64` |
178+
| `float` | `float32` |
179+
| `double` | `float64` |
180+
| `string` | `string` |
181+
| `wstring` | `wstring` |
182+
| `sequence<T>` | `T[]` |
183+
| `T[N]` | `T[N]` |
184+
| `pkg::msg::Type` | `pkg/Type` |
185+
186+
### Typedef Support
187+
188+
The tool supports both simple and array typedefs:
189+
190+
- **Simple typedef**: `typedef double MyDouble;` → Maps `MyDouble` to `float64`
191+
- **Array typedef**: `typedef double MyArray[9];` → Maps `MyArray` to `float64[9]`
192+
- **Namespaced typedef**: `typedef std_msgs::msg::Header HeaderType;` → Maps `HeaderType` to `std_msgs/Header`
193+
194+
## Output Structure
195+
196+
The tool creates the following directory structure:
197+
198+
```
199+
<root>/<output>/
200+
├── msg/ # Generated .msg files
201+
├── srv/ # Generated .srv files
202+
└── action/ # Generated .action files
203+
```
204+
205+
### ROS2 Workspace Integration
206+
207+
For proper ROS2 workspace integration, you can use the parameters to match the expected structure:
208+
209+
```bash
210+
# Generate files for a ROS2 package in a workspace
211+
python3 idl_convertor.py MyMessage.idl \
212+
-r ~/ros2_ws/src \
213+
-o my_package_name \
214+
-p my_package_name
215+
216+
# This creates:
217+
# ~/ros2_ws/src/my_package_name/msg/MyMessage.msg
218+
# ~/ros2_ws/src/my_package_name/srv/MyService.srv
219+
# ~/ros2_ws/src/my_package_name/action/MyAction.action
220+
```
221+
222+
The generated files will be compatible with ROS2 build tools like `colcon build`.
223+
224+
## Important Notes
225+
226+
### DDS @key Annotation Handling
227+
228+
The tool automatically detects and skips IDL files that contain:
229+
230+
- Direct `@key` annotations (e.g., `@key string identifier;`)
231+
- References to types that use `@key` annotations (e.g., `KeyedString`, `KeyedLong`)
232+
233+
This is because `@key` annotations are DDS-specific features that are not supported in ROS2 .msg files. When such files are encountered, the tool will print a warning and skip processing:
234+
235+
```
236+
Warning: Skipping MyFile.idl - contains @key annotations which are not supported in ROS2 .msg files
237+
```
238+
239+
or
240+
241+
```
242+
Warning: Skipping MyFile.idl - references keyed types which are not supported in ROS2 .msg files
243+
```
244+
245+
## Implementation Details
246+
247+
### Classes
248+
249+
- **`IdlParser`**: Parses IDL files and extracts interface definitions
250+
- **`RosInterfaceGenerator`**: Generates ROS2 interface files from parsed data
251+
- **`IdlField`**: Represents a field in an IDL structure (with support for comments and default values)
252+
- **`IdlConstant`**: Represents a constant definition in an IDL structure
253+
- **`IdlStructure`**: Represents an IDL structure (message, service part, etc.)
254+
- **`IdlInterface`**: Represents a complete IDL interface definition
255+
256+
### Key Features
257+
258+
- **Robust Parsing**: Handles comments, nested modules, typedefs, and complex type definitions
259+
- **Key Annotation Detection**: Automatically detects and skips files with `@key` annotations
260+
- **Comment Preservation**: Extracts comments from `@verbatim` blocks and associates them with fields
261+
- **Default Value Support**: Processes `@default` annotations and formats them for ROS2
262+
- **Error Handling**: Graceful error handling with informative messages
263+
- **Extensible**: Easy to extend for additional IDL features or output formats
264+
265+
## Testing
266+
267+
The tool has been tested with:
268+
269+
- ✅ Basic message types (JointState)
270+
- ✅ Service definitions (SetCameraInfo) - generates proper .srv files
271+
- ✅ Action definitions (Fibonacci) - generates proper .action files
272+
- ✅ Array and sequence types
273+
- ✅ Namespaced types
274+
- ✅ Typedef declarations (simple and array types)
275+
- ✅ Constants and default values with `@default` annotations
276+
- ✅ Comment preservation from `@verbatim` blocks
277+
-`@key` annotation detection and file skipping
278+
- ✅ Command line interface with all options
279+
- ✅ Request/Response combination for services
280+
- ✅ Goal/Result/Feedback combination for actions
281+
- ✅ Field order preservation from IDL to generated files
282+
283+
## Future Enhancements
284+
285+
- [ ] Support for nested structures and complex type inheritance
286+
- [ ] Support for enums and unions
287+
- [ ] Support for IDL annotations beyond `@verbatim`, `@default`, and `@key`
288+
- [ ] Validation of generated files against ROS2 interface specifications
289+
- [ ] Support for composition and inheritance patterns
290+
- [ ] Batch processing of multiple IDL files
291+
- [ ] Integration with ROS2 build tools (ament, colcon)
292+
293+
## Requirements
294+
295+
- Python 3.6+
296+
- No external dependencies (uses only standard library)
297+
298+
This tool provides a robust solution for converting ROS2 IDL files to standard ROS2 interface formats, making it easier to work with interface definitions across different ROS2 tools and languages.

0 commit comments

Comments
 (0)