1261.40 IDL(Interface Definition Language)과 메시지 정의
1. 서론
분산 로봇 시스템에서 노드 간 데이터 교환의 정확성과 호환성을 보장하기 위해서는 교환되는 데이터의 구조를 명확하고 표준화된 방식으로 정의하여야 한다. 인터페이스 정의 언어(Interface Definition Language, IDL)는 통신에 참여하는 양 당사자가 공유하는 데이터 구조의 계약(contract)을 프로그래밍 언어에 독립적으로 명세하는 형식 언어이다. ROS2는 OMG(Object Management Group)의 IDL 표준을 채택하여 메시지, 서비스, 액션의 인터페이스를 정의하며, 이를 기반으로 다중 언어 지원과 DDS 미들웨어와의 연동을 실현한다. 본 절에서는 IDL의 기본 개념, ROS2에서의 적용 구조, 그리고 메시지 정의의 실제적 원칙을 분석한다.
2. IDL의 기본 개념과 역사
2.1 인터페이스 정의 언어의 정의
IDL은 소프트웨어 컴포넌트 간의 인터페이스를 플랫폼 및 프로그래밍 언어에 독립적으로 기술하는 선언적(declarative) 형식 언어이다. IDL 명세는 데이터의 구조와 타입만을 정의하며, 데이터의 처리 로직이나 알고리즘은 포함하지 않는다. IDL 컴파일러가 IDL 명세를 입력으로 받아 특정 프로그래밍 언어(C, C++, Python, Java 등)의 데이터 타입, 직렬화/역직렬화 코드, 그리고 타입 지원 함수를 자동 생성한다.
2.2 OMG IDL 표준의 역사
IDL의 기원은 1991년 OMG가 발표한 CORBA(Common Object Request Broker Architecture) 표준으로 거슬러 올라간다. CORBA IDL은 분산 객체 시스템에서 원격 인터페이스를 정의하기 위하여 설계되었으며, 이후 DDS(Data Distribution Service) 표준에서 데이터 타입 정의에 활용되었다. OMG IDL 4.2 버전(2018)은 현재 DDS 및 ROS2에서 사용되는 표준 버전이다.
3. ROS2에서의 IDL 적용
3.1 ROS2 인터페이스 정의 체계
ROS2는 두 가지 수준의 인터페이스 정의 형식을 사용한다.
첫째, ROS2 고유 형식으로 .msg, .srv, .action 파일이 있다. 이 형식은 ROS1에서 유래한 간결한 구문을 사용하며, 개발자의 편의성을 우선한다. 각 파일은 단순한 필드 목록과 자료형 선언으로 구성된다.
둘째, OMG IDL 형식으로 .idl 파일이 있다. 이 형식은 DDS 표준과 직접 호환되며, 보다 풍부한 타입 시스템과 어노테이션(annotation)을 지원한다.
ROS2의 빌드 시스템은 내부적으로 .msg, .srv, .action 파일을 OMG IDL 형식으로 변환한 후, IDL 컴파일러를 통하여 언어별 코드를 생성한다. 이 변환 과정은 rosidl_adapter 패키지에 의하여 수행된다.
3.2 rosidl 파이프라인의 구조
ROS2의 인터페이스 코드 생성 파이프라인은 다음의 단계로 구성된다.
1단계: 인터페이스 명세 작성. 개발자가 .msg, .srv, .action 또는 .idl 형식으로 인터페이스를 정의한다.
2단계: IDL 변환. rosidl_adapter가 ROS2 고유 형식을 OMG IDL 형식으로 변환한다. .idl 파일이 직접 제공된 경우 이 단계는 생략된다.
3단계: 타입 지원 코드 생성. rosidl_typesupport_* 패키지가 DDS 벤더별 타입 지원 코드를 생성한다. 이 코드는 메시지의 직렬화/역직렬화 함수와 DDS 토픽 등록을 위한 메타데이터를 포함한다.
4단계: 언어별 바인딩 생성. rosidl_generator_c, rosidl_generator_cpp, rosidl_generator_py 등이 각 프로그래밍 언어에 적합한 데이터 구조와 접근 함수를 생성한다.
4. IDL의 자료형 체계
4.1 기본 자료형
OMG IDL은 다음의 기본 자료형을 정의한다. ROS2 메시지에서 사용되는 자료형과의 대응 관계는 다음과 같다.
| OMG IDL 자료형 | ROS2 자료형 | 크기(비트) | 설명 |
|---|---|---|---|
| boolean | bool | 8 | 논리값 |
| octet | byte | 8 | 부호 없는 8비트 값 |
| char | char | 8 | ASCII 문자 |
| wchar | wchar | 16 | 유니코드 문자 |
| short | int16 | 16 | 부호 있는 16비트 정수 |
| unsigned short | uint16 | 16 | 부호 없는 16비트 정수 |
| long | int32 | 32 | 부호 있는 32비트 정수 |
| unsigned long | uint32 | 32 | 부호 없는 32비트 정수 |
| long long | int64 | 64 | 부호 있는 64비트 정수 |
| unsigned long long | uint64 | 64 | 부호 없는 64비트 정수 |
| float | float32 | 32 | IEEE 754 단정밀도 부동소수점 |
| double | float64 | 64 | IEEE 754 배정밀도 부동소수점 |
| string | string | 가변 | UTF-8 문자열 |
4.2 복합 자료형
IDL은 기본 자료형을 조합한 복합 자료형의 정의를 지원한다.
**구조체(struct)**는 명명된 필드의 순서 집합을 정의하며, ROS2 메시지의 핵심 구성 요소이다. 각 필드는 자료형과 이름의 쌍으로 선언된다.
**배열(array)**은 고정 길이의 동일 자료형 요소 집합이다. IDL에서 float point[3]은 3개의 float 요소로 구성된 고정 배열을 나타낸다.
**시퀀스(sequence)**는 가변 길이의 동일 자료형 요소 집합이다. 상한이 지정된 제한 시퀀스(sequence<float, 100>)와 상한이 없는 무한 시퀀스(sequence<float>)로 구분된다.
**열거형(enum)**은 명명된 상수의 집합을 정의한다. ROS2에서는 메시지 내의 상수(constant) 선언으로 이를 대체하는 경우가 많으나, .idl 형식에서는 표준 열거형을 직접 사용할 수 있다.
5. ROS2 메시지 정의의 실제
5.1 .msg 파일의 문법
ROS2의 .msg 파일은 간결한 행 기반(line-based) 문법을 사용한다. 각 행은 자료형과 필드 이름의 쌍으로 구성되며, 주석은 # 기호로 시작한다. 상수는 자료형 이름=값 형식으로 선언한다.
# 표준 헤더
std_msgs/Header header
# 3차원 위치
float64 x
float64 y
float64 z
# 상태 코드 상수
uint8 STATUS_IDLE=0
uint8 STATUS_ACTIVE=1
uint8 STATUS_ERROR=2
uint8 status
5.2 메시지 정의의 설계 원칙
효과적인 메시지 정의를 위한 설계 원칙은 다음과 같다.
단일 책임 원칙(Single Responsibility Principle): 하나의 메시지는 하나의 논리적 데이터 단위를 표현하여야 한다. 관련 없는 데이터를 하나의 메시지에 결합하는 것은 불필요한 통신 오버헤드와 결합도 증가를 초래한다.
표준 메시지 재사용 원칙: ROS2는 std_msgs, geometry_msgs, sensor_msgs, nav_msgs 등의 표준 메시지 패키지를 제공한다. 표준 메시지가 요구사항을 충족하는 경우 사용자 정의 메시지 대신 표준 메시지를 우선 사용하여야 한다. 이는 패키지 간 호환성을 보장하고 에코시스템 내의 도구 지원을 활용할 수 있게 한다.
자기 설명적(self-descriptive) 필드 명명: 필드 이름은 해당 데이터의 의미를 명확히 전달하여야 한다. snake_case 명명 규칙을 따르며, 물리량의 단위가 모호한 경우 필드 이름에 단위를 포함하거나 주석으로 명시한다.
헤더 포함: 시간 동기화와 좌표계 참조가 필요한 메시지에는 std_msgs/Header 필드를 포함하여야 한다. 헤더에는 타임스탬프(stamp)와 좌표 프레임 식별자(frame_id)가 포함되어 있어, 시간적·공간적 맥락을 제공한다.
5.3 IDL 파일에서의 메시지 정의
OMG IDL 형식을 직접 사용하는 경우, 메시지 정의는 module과 struct 키워드를 사용하여 작성한다. 다음은 동일한 메시지를 IDL 형식으로 정의한 예시이다.
module my_package {
module msg {
struct MyMessage {
std_msgs::msg::Header header;
double x;
double y;
double z;
uint8 status;
};
};
};
IDL 형식은 ROS2 고유 형식에 비하여 문법이 복잡하나, DDS 표준과의 직접적 호환성, 어노테이션 지원, 그리고 보다 정교한 타입 시스템의 활용이 가능하다.
6. IDL과 코드 생성의 관계
6.1 코드 생성의 자동화
IDL에 기반한 코드 생성은 인터페이스 변경 시 수동 코드 수정의 필요성을 제거한다. 메시지 정의 파일을 수정하고 빌드를 실행하면, 직렬화/역직렬화 코드, 언어별 데이터 구조, 타입 지원 함수가 자동으로 재생성된다. 이는 인터페이스 정의와 구현 코드의 일관성을 보장하며, 수동 동기화에 의한 오류를 방지한다.
6.2 다중 언어 지원
IDL의 핵심적 장점은 단일 인터페이스 정의로부터 다수의 프로그래밍 언어에 대한 코드를 생성할 수 있다는 점이다. C++ 노드의 발행자가 전송한 메시지를 Python 노드의 구독자가 수신하는 다중 언어 환경에서, IDL 기반의 코드 생성은 양 언어 간의 데이터 호환성을 자동으로 보장한다. 개발자는 직렬화 형식의 세부 사항을 인지할 필요 없이, 각 언어의 자연스러운 데이터 구조를 통하여 메시지에 접근할 수 있다.
6.3 DDS 벤더 독립성
ROS2의 rosidl 인프라는 DDS 벤더별 타입 지원 플러그인을 통하여 벤더 독립적 인터페이스를 구현한다. 동일한 IDL 정의로부터 Fast DDS, Cyclone DDS, Connext DDS 등 상이한 DDS 구현에 적합한 코드가 생성된다. 이는 ROS2 시스템이 미들웨어 교체에 대하여 투명(transparent)하게 운용될 수 있도록 한다.
7. 메시지 정의에서의 제약 사항
7.1 순환 참조 금지
메시지 정의에서 순환 참조(circular reference)는 허용되지 않는다. 메시지 A가 메시지 B를 필드로 포함하고, 메시지 B가 다시 메시지 A를 필드로 포함하는 구조는 직렬화 크기의 무한 증가를 야기하므로 금지된다.
7.2 상속의 부재
ROS2의 메시지 정의 체계는 객체 지향 프로그래밍의 상속(inheritance) 개념을 지원하지 않는다. 공통 필드를 공유하는 메시지 구조가 필요한 경우, 공통 필드를 별도의 메시지로 정의하고 이를 포함(composition)하는 방식으로 구현한다.
7.3 기본값의 제약
ROS2의 .msg 형식에서는 필드의 기본값(default value) 지정이 제한적으로 지원된다. 기본 자료형에 대해서는 기본값을 지정할 수 있으나, 복합 자료형이나 배열에 대한 기본값 지정은 지원되지 않는다. 이는 언어별 코드 생성기의 구현 복잡도를 고려한 설계적 결정이다.
8. 결론
IDL은 ROS2 통신 인프라의 기반을 이루는 인터페이스 명세 기법이며, 플랫폼 독립적이고 언어 독립적인 데이터 교환을 가능하게 한다. ROS2의 rosidl 파이프라인은 간결한 .msg 형식 또는 표준 .idl 형식의 인터페이스 정의로부터 다중 언어의 코드를 자동 생성하며, 이는 개발 생산성과 인터페이스 일관성을 동시에 확보한다. 메시지 정의 시에는 단일 책임 원칙, 표준 메시지 재사용, 자기 설명적 명명의 원칙을 준수하여 시스템의 모듈성과 상호운용성을 극대화하여야 한다.