|
| 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