ROS 1 - Nodes vs. Nodelets
ROS 1에서는 코드를 노드 또는 노드렛(nodelet) 으로 작성할 수 있다. 노드는 실행 파일로 빌드되고, 노드렛은 공유 라이브러리로 빌드된 뒤 컨테이너 프로세스가 실행 시 로드한다.
ROS 2 - Unified API (통합 API)
ROS 2에서는 노드렛과 비슷한 방식인 컴포넌트(Component) 로 작성하는 것이 권장된다. 노드와 노드렛이 서로 다른 API를 쓰던 ROS 1의 단점을 없애고, 같은 API로 통일했다.
“자기 main을 쓰는” 노드 스타일도 가능하지만, 일반적인 경우에는 권장하지 않는다.
process layout을 배포 시점에 정하면 다음과 같은 장점이 있다.
- 노드마다 별도 프로세스: 프로세스/장애 격리, 노드 단위 디버깅에 유리.
- 한 프로세스에 여러 노드: 오버헤드 감소, 필요 시 프로세스 내 통신(Intra Process Communication) 으로 효율적 통신.
ros2 launch로 위 동작을 자동화할 수 있다.
Component Container (컴포넌트 컨테이너)
컴포넌트 컨테이너는 한 프로세스 안에서 여러 컴포넌트를 실행 시 로드·관리하는 호스트 프로세스다.
제공되는 일반 컨테이너 종류:
| 컨테이너 | 설명 |
|---|---|
| component_container | SingleThreadedExecutor 하나로 모든 컴포넌트 실행. 가장 일반적. |
| component_container_mt | MultiThreadedExecutor 하나로 컴포넌트 실행. |
| component_container_isolated | 컴포넌트마다 전용 Executor(기본 Single, 옵션 Multi). |
Executor 종류는 Executors 문서 참고. 각 컨테이너 옵션은 Composition 튜토리얼의 Component container types 참고.
Writing a Component (컴포넌트 작성)
컴포넌트는 공유 라이브러리로만 빌드되므로 main 함수가 없다. 보통 rclcpp::Node를 상속하고, 스레드를 직접 제어하지 않으므로 생성자에서 긴 작업·블로킹을 하지 말고, 타이머로 주기 작업을 하거나 퍼블리셔·구독·서버·클라이언트를 만든다.
컴포넌트로 인식되려면 rclcpp_components 패키지의 매크로로 자기 등록해야 한다. 라이브러리가 프로세스에 로드될 때 이 등록 덕분에 컴포넌트를 찾을 수 있다(진입점 역할). 그리고 인덱스에 등록해 도구에서 찾을 수 있게 해야 한다.
add_library(talker_component SHARED src/talker_component.cpp)
rclcpp_components_register_nodes(talker_component "composition::Talker")
컨테이너가 컴포넌트를 찾으려면, 해당 워크스페이스를 source한 셸에서 컨테이너를 실행하거나 launch해야 한다.
CMake Registration Macros (등록 매크로)
| 매크로 | 용도 |
|---|---|
| rclcpp_components_register_node | 컴포넌트 등록 + 독립 실행 파일 생성. 컴포지션과 단독 실행 둘 다 쓰고 싶을 때. PLUGIN, EXECUTABLE 인자. |
| rclcpp_components_register_nodes | 컴포넌트만 등록, 실행 파일은 만들지 않음. 런타임에 컨테이너가 로드할 순수 컴포넌트 라이브러리용. |
Using Components (컴포넌트 사용)
가장 흔한 세 가지 방식:
- 일반 컨테이너 프로세스를 띄운 뒤, 컨테이너가 제공하는 load_node 서비스를 호출해 패키지명·라이브러리명으로 컴포넌트를 로드. CLI 도구로 같은 서비스를 호출해도 된다.
- 컴파일 시점에 노드가 정해진 커스텀 실행 파일을 만들어 여러 노드를 한 프로세스에 넣기. 각 컴포넌트에 헤더가 필요하다.
- 런치 파일에서
ros2 launch로 컨테이너 프로세스를 만들고, 그 안에 여러 컴포넌트를 로드.
실습은 공식 Composition 튜토리얼/데모를 참고하면 된다.