Chapter 28. ROS2 노드(Node) 아키텍처 및 퍼블리셔-서브스크라이버 콜백 시스템 기초

Chapter 28. ROS2 노드(Node) 아키텍처 및 퍼블리셔-서브스크라이버 콜백 시스템 기초

자율 에이전트 드론을 구성하는 수많은 하드웨어 센서 체계와 고성능 비행 제어 알고리즘은 단일 거대 프로그램 블록(Monolithic Architecture)으로 통합되어 컴파일될 수 없다. 이러한 한계를 극복하기 위해 ROS2는 전체 소프트웨어 시스템을 기능적으로 완전한 독립성을 가진 최소 컴퓨팅 실행 단위인 노드(Node)들로 분할하는 컴포넌트 기반 소프트웨어 아키텍처(Component-Based Software Architecture) 원리를 채택하고 있다. 본 장에서는 ROS2 시스템의 기초 원자 단위인 노드의 내부 구조를 조명하고, 다수의 노드가 비동기적으로 상호작용하여 정보를 교섭하기 위한 퍼블리셔(Publisher)와 서브스크라이버(Subscriber) 통신 모델의 이론적 프레임워크 및 콜백(Callback) 연산 메커니즘을 엄밀하게 확립한다.

1. ROS2 노드(Node)의 아키텍처와 객체 지향 철학

ROS2 아키텍처에서 노드란 단일 기능적 목적을 수행하는 독립적인 컴퓨팅 프로세스(Process) 또는 특정 프로세스 메모리 영역 위에서 점유되는 실행 인스턴스(Instance)를 지칭한다. 일례로 라이다(LiDAR) 센서의 로우 데이터를 획득하는 관측 노드, 획득한 데이터를 해석하여 시각적 주행 거리(Visual-Inertial Odometry)를 도출하는 추정 노드, 그리고 최종적으로 BLDC 모터의 PWM 제어 신호를 방출하는 구동 노드가 논리적, 물리적으로 분산되어 각자의 메인 제어 쓰레드 루프를 점유한다.

노드 아키텍처는 프로그래밍 언어의 층위에서 그 자체로 객체 지향적(Object-Oriented) 캡슐화 특성을 지니며, rclcpp::Node 또는 rclpy.node.Node와 같은 라이브러리의 기본 부모 클래스를 상속받아 파생 클래스로 구현된다. 이 노드 클래스 공간 내부에는 시스템 수명 주기(Life Cycle) 관리 리소스와 미들웨어 통신을 조율하는 네트워크 인터페이스 포인터가 완벽하게 은닉(Information Hiding)되어 있다. 특히 ROS2에서는 특정 단일 메모리 프로세스 주소 공간 내에 여러 개의 노드 런타임을 즉시 병렬 인스턴스화할 수 있도록 지원하는 컴포넌트(Component) 지향 런타임을 제공함으로써, 스레드 간 프로세스 레벨 통신(IPC)의 영경계 성능(Zero-copy Performance) 최적화 트랜잭션을 도모한다.

2. 퍼블리셔-서브스크라이버 구조의 분산 데이터망 동기화

물리적으로 분산된 이기종 노드들이 협력하여 거대한 자율 통제 에이전트를 형성하기 위해, ROS2는 DDS(Data Distribution Service) 통신 규격에 논리적으로 대응하는 퍼블리셔(Publisher)와 서브스크라이버(Subscriber) 비동기 메시지 프로토콜을 전역적으로 사용한다.

이 아키텍처는 토픽(Topic)이라고 명명된 문자열 기반의 추상화된 논리적 데이터 버스 이름 공간(Namespace)을 핵심 통신 매개체로 삼는다. 전면 카메라 영상과 같은 대용량 센서 스트림 데이터를 외부로 생산하는 노드는 퍼블리셔 객체로 구동되어 특정 토픽명(예: /camera_front/image_raw)의 파이프라인 위로 데이터를 지속적으로 발행(Publish)한다. 반대로 해당 프레임을 소비하여 객체 검출(Object Detection) 연산을 수행해야 하는 비전 딥러닝 노드는 서브스크라이버 객체로서 동일한 문자열 식별자를 가진 토픽망을 구독(Subscribe)한다.

이 통신 구조가 도출해 내는 핵심적인 학술적 성과는 데이터의 생산 모듈과 소비 모듈 쌍방이 서로 상대방의 네트워크 IP 주소, 런타임 생존 활성화 여부, 혹은 물리적 위치를 전혀 몰라도 시스템이 성립하는 시공간적 느슨한 결합(Temporal and Spatial Loose Coupling) 관계의 실현에 있다. 즉, 데이터를 수신하는 서브스크라이버 노드가 런타임에 일시적으로 붕괴되더라도 데이터를 발행하는 퍼블리셔의 스레드 연산 루틴에는 단 1밀리초의 지연 오버헤드조차 전가되지 않는 강력한 상태 독립성을 물리적으로 보장한다.

3. 이벤트 구동형(Event-driven) 콜백 시스템 역학

이러한 서브스크라이버 통신 수신망 구조는 고전적인 동기형의 무한 상태 감시(Polling) 루프 방식이 아닌, 이벤트 구동형 비동기 콜백(Event-driven Callback) 계층 아키텍처에 의해 엄격하게 제어 및 파견(Dispatch)된다. 미들웨어를 거쳐 새로운 토픽 메시지가 프로세서의 네트워크 소켓 수신 큐(Queue) 버퍼에 도달하면, 노드 컨텍스트에 등록된 런타임 이그제큐터(Executor)가 운영체제의 백그라운드 스레드망에서 이를 즉각 탐지하고, 대기 중이던 서브스크라이버의 람다 혹은 멤버 콜백 함수를 비동기적으로 문맥 스위치 파견 호출한다.

// 서브스크라이버 멤버 콜백 맵핑 모델의 C++ 클래스 추상화 예시
class PerceptionNode : public rclcpp::Node {
public:
    PerceptionNode() : Node("perception_agent_node") {
        // 퍼블리셔를 통해 외부 메시지 스트림이 인입될 때마다 반응할 수신 콜백 함수의 비동기적 런타임 바인딩
        subscription_ = this->create_subscription<sensor_msgs::msg::Image>(
            "/camera_front/image_raw", 10,
            std::bind(&PerceptionNode::camera_image_processor_callback, this, std::placeholders::_1));
    }

private:
    void camera_image_processor_callback(const sensor_msgs::msg::Image::SharedPtr msg) const {
        // 이벤트 드리븐 구조에 의한 센서 패킷 수신 인터럽트와 동기화된 메모리 포인터 연산 수행
        RCLCPP_INFO(this->get_logger(), "고해상도 프레임 객체 수신 시스템 타임스탬프: %d", msg->header.stamp.sec);
    }
    rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_;
};

이러한 고차원 콜백 맵핑 시스템을 관통함으로써, 제어 엔지니어는 하위 이더넷 인터페이스 포트나 프로토콜 패킷 시퀀스를 직접 구현하는 전산 소모를 일소하고, 학술적인 메인 비즈니스 임무 알고리즘 개발에만 자원을 투입할 수 있다. 콜백 함수 체인은 자율 에이전트의 런타임 큐 내부에서 외부 시스템 데이터의 발생 트리거 패턴에 철저하게 종속되어 다발적으로 수행된다. 따라서 해당 블록 내부 로직의 수행 시간이 센서 데이터 인입 주기보다 길어질 경우, 심각한 통신 큐 버퍼 파손(Queue overflow)과 물리적 제어 시차(Phase Delay) 결함표가 시스템 차원에 산출될 수 있음을 수학적으로 주의 깊게 런타임 모델링하여야 한다.