Skip to content

Commit 4d05da5

Browse files
committed
Support .idl files for ROS message/service/action
1 parent 82bbc82 commit 4d05da5

File tree

8 files changed

+1532
-38
lines changed

8 files changed

+1532
-38
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ jobs:
7474
npm test
7575
npm run clean
7676
77+
- name: Test with IDL ROS messages
78+
if: ${{ matrix.ros_distribution == 'rolling' }}
79+
run: |
80+
npm i
81+
npm test-idl
82+
npm run clean
83+
7784
- name: Coveralls Parallel
7885
uses: coverallsapp/github-action@v2
7986
with:

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"postinstall": "npm run generate-messages",
2626
"docs": "cd docs && make",
2727
"test": "nyc node --expose-gc ./scripts/run_test.js && tsd",
28+
"test-idl": "nyc node --expose-gc ./scripts/run_test.js --idl",
2829
"lint": "eslint && node ./scripts/cpplint.js",
2930
"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}",
3031
"prepare": "husky",

rosidl_convertor/README.md

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
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+
- **Multi-Interface Support**: Handles messages, services, and actions in a single IDL file
10+
- **Namespace Support**: Properly handles namespaced types (e.g., `std_msgs::msg::Header``std_msgs/Header`)
11+
- **Command Line Interface**: Easy to use with command line arguments
12+
- **Verbose Output**: Optional detailed output showing parsed structures and generated files
13+
14+
## Usage
15+
16+
### Basic Usage
17+
18+
```bash
19+
python3 idl_parser.py <idl_file>
20+
```
21+
22+
### With Options
23+
24+
```bash
25+
python3 idl_parser.py <idl_file> [options]
26+
```
27+
28+
### Options
29+
30+
- `-o, --output DIR`: Output directory name for generated files (default: `ros_interfaces`)
31+
- `-r, --root PATH`: Root path where the generated files will be located (default: current directory)
32+
- `-p, --package NAME`: Package name to use for generated files (overrides package name from IDL)
33+
- `-v, --verbose`: Enable verbose output showing parsed structures and file contents
34+
- `-h, --help`: Show help message
35+
36+
### Advanced Examples
37+
38+
#### Custom Output Directory
39+
40+
```bash
41+
python3 idl_parser.py JointState.idl -o my_interfaces
42+
```
43+
44+
#### Custom Root Path
45+
46+
```bash
47+
python3 idl_parser.py SetCameraInfo.idl -r /path/to/workspace -o sensor_msgs
48+
# Generates files in: /path/to/workspace/sensor_msgs/srv/SetCameraInfo.srv
49+
```
50+
51+
#### Custom Package Name
52+
53+
```bash
54+
python3 idl_parser.py JointState.idl -p my_package_name
55+
# Overrides the package name from the IDL file
56+
```
57+
58+
#### Combined Options
59+
60+
```bash
61+
python3 idl_parser.py SetCameraInfo.idl -r ~/ros2_ws/src -o sensor_msgs -p sensor_msgs -v
62+
# Generates: ~/ros2_ws/src/sensor_msgs/srv/SetCameraInfo.srv with package name "sensor_msgs"
63+
```
64+
65+
## Examples
66+
67+
### 1. Convert a Message IDL
68+
69+
Input file `JointState.idl`:
70+
71+
```idl
72+
#include "std_msgs/msg/Header.idl"
73+
74+
module sensor_msgs {
75+
module msg {
76+
struct JointState {
77+
std_msgs::msg::Header header;
78+
sequence<string> name;
79+
sequence<double> position;
80+
sequence<double> velocity;
81+
sequence<double> effort;
82+
};
83+
};
84+
};
85+
```
86+
87+
Output `JointState.msg`:
88+
89+
```
90+
# JointState.msg
91+
# Generated from IDL file
92+
93+
std_msgs/Header header
94+
string[] name
95+
float64[] position
96+
float64[] velocity
97+
float64[] effort
98+
```
99+
100+
### 2. Convert a Service IDL
101+
102+
Input file `SetCameraInfo.idl`:
103+
104+
```idl
105+
#include "sensor_msgs/msg/CameraInfo.idl"
106+
107+
module sensor_msgs {
108+
module srv {
109+
struct SetCameraInfo_Request {
110+
sensor_msgs::msg::CameraInfo camera_info;
111+
};
112+
struct SetCameraInfo_Response {
113+
boolean success;
114+
string status_message;
115+
};
116+
};
117+
};
118+
```
119+
120+
Output `SetCameraInfo.srv`:
121+
122+
```
123+
# SetCameraInfo.srv
124+
# Generated from IDL file
125+
126+
# Request
127+
sensor_msgs/CameraInfo camera_info
128+
---
129+
# Response
130+
bool success
131+
string status_message
132+
```
133+
134+
### 3. Convert an Action IDL
135+
136+
Input file `Fibonacci.idl`:
137+
138+
```idl
139+
module example_interfaces {
140+
module action {
141+
struct FibonacciGoal {
142+
int32 order;
143+
};
144+
145+
struct FibonacciResult {
146+
sequence<int32> sequence;
147+
};
148+
149+
struct FibonacciFeedback {
150+
sequence<int32> partial_sequence;
151+
};
152+
};
153+
};
154+
```
155+
156+
Generates separate message files for goal, result, and feedback components.
157+
158+
## Type Mappings
159+
160+
| IDL Type | ROS2 Type |
161+
| ---------------- | ---------- |
162+
| `boolean` | `bool` |
163+
| `octet` | `uint8` |
164+
| `int8` | `int8` |
165+
| `uint8` | `uint8` |
166+
| `int16` | `int16` |
167+
| `uint16` | `uint16` |
168+
| `int32` | `int32` |
169+
| `uint32` | `uint32` |
170+
| `int64` | `int64` |
171+
| `uint64` | `uint64` |
172+
| `float` | `float32` |
173+
| `double` | `float64` |
174+
| `string` | `string` |
175+
| `wstring` | `wstring` |
176+
| `sequence<T>` | `T[]` |
177+
| `T[N]` | `T[N]` |
178+
| `pkg::msg::Type` | `pkg/Type` |
179+
180+
## Output Structure
181+
182+
The tool creates the following directory structure:
183+
184+
```
185+
<root>/<output>/
186+
├── msg/ # Generated .msg files
187+
├── srv/ # Generated .srv files
188+
└── action/ # Generated .action files
189+
```
190+
191+
### ROS2 Workspace Integration
192+
193+
For proper ROS2 workspace integration, you can use the parameters to match the expected structure:
194+
195+
```bash
196+
# Generate files for a ROS2 package in a workspace
197+
python3 idl_parser.py MyMessage.idl \
198+
-r ~/ros2_ws/src \
199+
-o my_package_name \
200+
-p my_package_name
201+
202+
# This creates:
203+
# ~/ros2_ws/src/my_package_name/msg/MyMessage.msg
204+
# ~/ros2_ws/src/my_package_name/srv/MyService.srv
205+
# ~/ros2_ws/src/my_package_name/action/MyAction.action
206+
```
207+
208+
The generated files will be compatible with ROS2 build tools like `colcon build`.
209+
210+
## Implementation Details
211+
212+
### Classes
213+
214+
- **`IdlParser`**: Parses IDL files and extracts interface definitions
215+
- **`RosInterfaceGenerator`**: Generates ROS2 interface files from parsed data
216+
- **`IdlField`**: Represents a field in an IDL structure
217+
- **`IdlStructure`**: Represents an IDL structure (message, service part, etc.)
218+
- **`IdlInterface`**: Represents a complete IDL interface definition
219+
220+
### Key Features
221+
222+
- **Robust Parsing**: Handles comments, nested modules, and complex type definitions
223+
- **Error Handling**: Graceful error handling with informative messages
224+
- **Extensible**: Easy to extend for additional IDL features or output formats
225+
226+
## Testing
227+
228+
The tool has been tested with:
229+
230+
- ✅ Basic message types (JointState)
231+
- ✅ Service definitions (SetCameraInfo) - generates proper .srv files
232+
- ✅ Action definitions (Fibonacci) - generates proper .action files
233+
- ✅ Array and sequence types
234+
- ✅ Namespaced types
235+
- ✅ Command line interface
236+
-@verbatim comment handling
237+
- ✅ Request/Response combination for services
238+
- ✅ Goal/Result/Feedback combination for actions
239+
240+
## Future Enhancements
241+
242+
- [ ] Support for constants and default values
243+
- [ ] Support for nested structures
244+
- [ ] Support for enums and unions
245+
- [ ] Validation of generated files
246+
- [ ] Support for inheritance and composition
247+
248+
## Requirements
249+
250+
- Python 3.6+
251+
- No external dependencies (uses only standard library)
252+
253+
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.

rosidl_convertor/idl_convertor.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) 2025, The Robot Web Tools Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const path = require('path');
18+
const fse = require('fs-extra');
19+
const execFile = require('child_process').execFile;
20+
const pythonExecutable =
21+
require('../rosidl_parser/py_utils').getPythonExecutable('python3');
22+
23+
async function convertIDLToROS2IDL(pkgName, idlFilePath, outputDir) {
24+
const packagePath = path.join(outputDir, pkgName);
25+
if (!fse.existsSync(packagePath)) {
26+
fse.mkdirSync(packagePath);
27+
}
28+
return new Promise((resolve, reject) => {
29+
const args = [idlFilePath, '-o', packagePath];
30+
const convertor = path.join(__dirname, 'idl_convertor.py');
31+
const [pythonExecutableFile, pythonExecutableArgs] = pythonExecutable;
32+
33+
execFile(
34+
pythonExecutableFile,
35+
[convertor, ...args],
36+
(error, stdout, stderr) => {
37+
if (error) {
38+
return reject(error);
39+
}
40+
if (stderr) {
41+
console.error(stderr);
42+
}
43+
resolve();
44+
}
45+
);
46+
});
47+
}
48+
49+
module.exports = convertIDLToROS2IDL;

0 commit comments

Comments
 (0)