1261.24 ROS2 토픽의 발행자(Publisher) 구조

1. 발행자의 역할과 위치

ROS2에서 발행자(Publisher)는 토픽 통신의 데이터 생산 측(data production side)을 담당하는 통신 종단점이다. 발행자는 노드(Node) 내부에 생성되며, 지정된 토픽 이름과 메시지 타입에 대한 데이터 발행 기능을 제공한다. 하나의 노드는 복수의 발행자를 생성할 수 있으며, 각 발행자는 상이한 토픽에 데이터를 발행할 수 있다.

발행자는 ROS2 통신 스택에서 응용 계층과 DDS DataWriter 사이를 매개하는 구성 요소로, 응용 코드에서 생성한 메시지 객체를 DDS 전송 계층에 전달하는 역할을 수행한다.

2. 발행자의 생성

2.1 rclcpp에서의 생성

C++ 클라이언트 라이브러리(rclcpp)에서 발행자는 노드 객체의 create_publisher 메서드를 통해 생성된다. 이 메서드는 세 가지 매개변수를 요구한다.

첫째, 토픽 이름(topic name)이다. 문자열로 지정되며, 네임스페이스와 결합되어 최종 토픽 경로가 결정된다.

둘째, QoS 프로파일(QoS profile)이다. 메시지 전달의 신뢰성, 이력 깊이(history depth), 내구성 등의 통신 특성을 지정한다.

셋째, 메시지 타입은 템플릿 매개변수(template parameter)로 지정된다.

생성된 발행자 객체는 std::shared_ptr로 관리되며, 노드의 생명주기 동안 유지된다.

2.2 발행자 옵션 (Publisher Options)

rclcpp::PublisherOptions 구조체를 통해 발행자의 세부 동작을 설정할 수 있다. 주요 설정 항목은 다음과 같다.

  • 콜백 그룹(Callback Group): 발행 관련 이벤트가 처리될 콜백 그룹을 지정한다.
  • 이벤트 콜백(Event Callbacks): QoS 위반 이벤트(예: Deadline 위반, Liveliness 변경) 발생 시 호출될 콜백을 등록할 수 있다.
  • 프로세스 내 통신(Intra-Process Communication): 동일 프로세스 내의 통신에서 제로 카피 전달을 활성화하는 옵션을 설정할 수 있다.

3. 발행자의 내부 구조

3.1 계층적 구조

발행자의 내부는 다음의 계층으로 구성된다.

rclcpp::Publisher<MsgT>
    ↓
rcl_publisher_t (C 구조체)
    ↓
rmw_publisher_t (미들웨어 추상 계층)
    ↓
DDS DataWriter (DDS 구현체)

rclcpp::Publisher<MsgT>는 타입 안전성(type safety)을 제공하는 C++ 래퍼(wrapper)이며, 내부적으로 rcl_publisher_t C 구조체를 통해 rmw 계층에 접근한다. rmw 계층은 DDS 구현체의 DataWriter를 추상화하여, DDS 구현체에 독립적인 인터페이스를 제공한다.

3.2 DDS DataWriter와의 매핑

각 ROS2 발행자는 하나의 DDS DataWriter에 대응한다. DDS DataWriter는 다음의 기능을 수행한다.

  • 직렬화된 데이터의 전송 관리
  • QoS 정책의 적용(신뢰성, 내구성, 기한 등)
  • 구독자와의 매칭(matching) 관리
  • 전송 버퍼 관리

4. 메시지 발행 과정

메시지의 발행은 발행자 객체의 publish 메서드를 호출함으로써 이루어진다. 이 과정의 내부 흐름은 다음과 같다.

  1. 메시지 구성: 응용 코드에서 메시지 객체를 생성하고 필드 값을 설정한다.
  2. publish 호출: 발행자의 publish 메서드에 메시지 객체를 전달한다.
  3. 프로세스 내 전달 (해당 시): 프로세스 내 통신이 활성화되어 있고 동일 프로세스 내에 구독자가 존재하는 경우, 메시지의 포인터가 직접 전달된다.
  4. 직렬화: 메시지가 CDR(Common Data Representation) 형식으로 직렬화된다.
  5. DDS DataWriter에 전달: 직렬화된 데이터가 DDS DataWriter의 write 연산에 전달된다.
  6. 네트워크 전송: DDS 전송 계층이 데이터를 구독자에게 전송한다.

publish 메서드는 비차단(non-blocking) 연산이다. 즉, 메서드 호출은 데이터를 DDS 전송 버퍼에 기록한 후 즉시 반환하며, 구독자의 수신 여부를 대기하지 않는다.

5. 발행 주기의 제어

발행자의 발행 주기는 일반적으로 타이머(timer)에 의해 제어된다. ROS2의 create_wall_timer 메서드를 사용하여 고정 주기의 타이머를 생성하고, 타이머 콜백 함수 내에서 publish를 호출하는 것이 표준적인 패턴이다.

발행 주기 T는 다음의 조건을 만족하여야 한다.

T > \tau_{\text{msg\_gen}} + \tau_{\text{ser}} + \tau_{\text{write}}

여기서 \tau_{\text{msg\_gen}}은 메시지 생성 시간, \tau_{\text{ser}}는 직렬화 시간, \tau_{\text{write}}는 DDS 쓰기 시간이다. 발행 주기가 이 하한보다 짧으면 메시지 누락이 발생할 수 있다.

6. 발행자의 QoS 설정

발행자에 적용 가능한 주요 QoS 정책은 다음과 같다.

QoS 정책설명일반적 설정
Reliability전달 보장 수준Reliable 또는 Best Effort
Durability메시지 보존 정책Volatile 또는 Transient Local
History메시지 이력 보존 방식Keep Last(N) 또는 Keep All
Deadline발행 주기 상한응용 요구에 따라 설정
Lifespan메시지 유효 기간응용 요구에 따라 설정
Liveliness발행자 생존 선언 방식Automatic 또는 Manual

센서 데이터와 같이 최신 값이 중요한 경우에는 Best Effort + Keep Last(1)의 조합이, 명령 전달과 같이 전달 보장이 중요한 경우에는 Reliable + Keep Last(적절한 깊이)의 조합이 적합하다.

7. 발행자의 생명주기

발행자의 생명주기는 이를 소유하는 노드의 생명주기에 종속된다. 노드가 소멸되면 해당 노드에 속한 모든 발행자도 함께 소멸된다. 관리형 노드(Managed Node)의 경우, 노드의 생명주기 상태(state)에 따라 발행자의 활성화와 비활성화가 제어될 수 있다.

발행자의 구조와 동작 원리에 대한 정확한 이해는 효율적인 데이터 발행 전략의 수립과 통신 성능 최적화를 위한 기초가 된다.