멀티머신 환경 Launch 파일 구성
개요
ROS2에서 멀티머신 환경을 구성할 때, 단일 머신에서 동작하던 Launch 파일을 그대로 사용하는 경우가 많다. 그러나 물리적으로 다른 장치에서 노드가 실행되어야 한다면, Launch 파일 또한 멀티머신 환경에 맞춰 구조를 재설계하거나 수정하는 과정을 거쳐야 한다. 이때 고려해야 할 주요 포인트들은 다음과 같다.
원격 머신에서 노드를 실행할 때 어떻게 통신할 것인가?
ROS_DOMAIN_ID는 어떻게 설정할 것인가?
Launch 파일 안에서 호스트 정보를 어떻게 지정하고, Node 실행 명령을 어떻게 분리할 것인가?
이 장에서는 ROS2 Humble 버전을 기준으로 멀티머신 환경에서 적절히 동작하는 Launch 파일 구조와 설정 방법을 살펴보자.
멀티머신 환경에서의 Launch 파일 구조
멀티머신 환경을 구성하기 위해서는 기본적으로 다음 요소를 파악해야 한다.
멀티머신 환경에서의 ROS 네트워크 설정
ROS_DOMAIN_ID 설정
DDS Discovery 관련 설정(FastDDS, CycloneDDS 등)
SSH 및 원격 명령 실행 메커니즘
원격에서 ROS 패키지를 구동하기 위해 SSH 연결이 필요한 경우
Launch 파일 내 노드 분리 또는 병합 전략
물리적으로 분리된 머신 각각에서 실행될 노드를 어떻게 Launch 파일에 배치할 것인가?
일반적으로 하나의 Launch 파일에서 여러 머신의 노드를 동시에 띄우고자 할 때, SSH 혹은 다른 원격 실행 메커니즘(예: docker-compose, Ansible 등)을 함께 활용한다. ROS2 Humble 버전에서는 기존 ROS1과 달리 roslaunch가 아닌 Python 기반의 launch 패키지를 사용하며, 이를 확장해 여러 머신을 지원한다.
기본 예시
아래는 하나의 Launch 파일에서 두 머신(호스트 이름이 각각 master-computer, slave-computer)에 있는 노드를 각각 실행한다고 가정한 매우 단순화된 예시 구조이다.
간단하게 각 머신에서 동작할 노드를 다음과 같이 구성한다고 하자.
Master 노드: /master_topic을 Publish
Slave 노드: /master_topic을 Subscribe
SSH를 통한 원격 실행 전략
멀티머신 Launch 파일에서 일반적으로 많이 사용하는 전략은 “로컬에서는 launch Python 스크립트를 돌리고, 원격 머신에는 SSH를 통해 ROS2 노드를 실행하라”는 것이다. 이를 위해 Python 코드에서 subprocess 모듈을 사용하거나, ROS2 Launch 패키지 내에서 제공되는 ExecuteProcess 액션을 적절히 사용할 수 있다.
간단한 예시 코드를 보면 다음과 같다.
위 코드에서 ExecuteProcess 액션을 두 번 사용해 로컬 머신과 원격 머신에서 각각의 노드를 실행하도록 지시한다. 이때 원격 머신에서는 ssh user@slave-computer 명령을 통해 연결하며, ROS2 환경 설정을 위해 source /opt/ros/humble/setup.bash를 포함한다.
머신별 ROS_DOMAIN_ID 설정
멀티머신 간 통신을 위해서는 반드시 동일한 ROS_DOMAIN_ID를 사용해야 한다. 이를 Launch 파일 내부에서 제어할 수도 있으나, 대부분은 각 머신의 환경 변수로 설정해둔다.
만약 물리적으로 분리된 두 머신이 서로 다른 네트워크 세그먼트나 방화벽 설정을 가지고 있다면, DDS Discovery가 제한될 수 있다. 이 경우, ROS_DOMAIN_ID 설정뿐 아니라 FASTRTPS_DEFAULT_PROFILES_FILE 혹은 DDS 설정 파일(CycloneDDS.xml 등)을 이용해 Discovery 범위를 조절해야 한다.
Launch 파일에서 SSH 키 기반 인증 활용
멀티머신 환경에서 SSH를 사용해 원격 노드를 실행할 때, 각 노드 실행 시마다 패스워드를 입력해야 하는 불편함을 줄이기 위해 SSH 키 기반 인증을 사용하는 것이 일반적이다. 다음과 같은 절차로 설정할 수 있다.
SSH 키 생성: 로컬 컴퓨터에서 SSH 키를 생성한다.
생성된 공개 키(~/.ssh/id_rsa.pub)를 원격 컴퓨터의 ~/.ssh/authorized_keys에 추가해두면, 이후 패스워드 입력 없이 SSH 접속이 가능해진다.
Launch 파일 내 ExecuteProcess 수정: 위에서 소개한 ssh user@slave-computer ... 구조의 명령어에 대해, 별도의 패스워드 입력이 없어도 실행 가능한다. 이때 로컬 머신에 있는 SSH 에이전트가 정상적으로 동작하며, 원격 머신에서 SSH 키를 허용해야 한다.
로컬 및 원격 머신의 패키지 동기화
ROS2 멀티머신 환경에서는 로컬 머신과 원격 머신 간에 패키지 구조가 동일해야 한다. 예를 들어, my_ros2_pkg라는 패키지를 로컬과 원격 모두에 설치 또는 빌드하여 동일한 버전, 동일한 소스 코드가 배포돼 있어야 노드 실행이 정상적으로 동작한다.
빌드 및 설치: 원격 머신에서도
colcon build를 통해 같은 워크스페이스를 구성하거나, 로컬에서 빌드한 패키지를 원격으로 전송해 놓아야 한다.ROS 버전 일치: 서로 다른 버전의 ROS2(예: Foxy vs Humble)를 혼합 사용하지 않는 것이 좋다. 동일 버전을 사용해야 멀티머신 통신 시 호환 문제가 최소화된다.
Launch 파일에서 매개변수 설정
멀티머신 환경에서 특정 노드에만 적용되는 매개변수(예: IP 주소, 포트 번호, 토픽 이름 등)가 있다면, Launch 파일에서 분기 처리를 해줄 수 있다. 예시 코드는 다음과 같다.
위 예시에서는 slave_ip라는 Launch Argument를 통해 원격 머신 IP 주소를 지정하고, 이를 각각의 노드에서 파라미터로 참조한다. 실제 실행 시에는 다음과 같이 명령어 인자를 전달할 수 있다.
이런 식으로 IP 주소를 유연하게 바꿔가며 Launch 파일을 재사용할 수 있다.
Launch 서브파일 활용
멀티머신 환경에서 노드 수가 많거나 구성이 복잡해지면, 하나의 Launch 파일이 너무 복잡해질 수 있다. 이때 Launch 서브파일(include) 기능을 사용해 로직을 분리할 수 있다.
local_nodes.launch.py로컬 머신에서 실행할 노드를 정의remote_nodes.launch.py원격 머신에서 실행할 노드를 정의 (SSH 등을 포함)
이처럼 구조를 분리하면, 디버깅과 유지보수 측면에서 큰 이점을 얻을 수 있다.
Launch 파일에서 동적 토폴로지 제어
ROS2 멀티머신 환경에서 상황에 따라 원격 노드를 추가/제거해야 하는 시나리오도 있을 수 있다. 예를 들어, 무인 로봇 여러 대를 다루면서 특정 로봇만 선택적으로 Launch하고 싶을 수 있다.
이를 위해 Launch 파일에서 “조건부 실행”을 구현할 수 있다. Python Launch API에서 조건문(IfCondition 등)을 사용하면 특정 Launch 인자(예: robot_id)가 주어진 경우에만 노드를 생성하거나, 아니면 생략하는 로직을 작성할 수 있다.
이 구조를 확장하면 원하는 로봇 ID만 Launch에 포함시키는 동적 토폴로지 제어가 가능한다.
시각적 다이어그램
멀티머신 Launch 구성과 관련한 노드/머신 간 배치를 간단한 다이어그램으로 나타낼 수도 있다. 예를 들어, mermaid를 활용해 다음과 같이 표현할 수 있다.
여기서 A 컴퓨터(로컬)는 Launch 파일을 실행하며, 그 안에서 SSH를 통해 원격 머신 C에서 노드를 실행하게 된다. A와 C는 동일한 ROS_DOMAIN_ID로 설정되어 있어 DDS Discovery가 정상적으로 이루어지는 상태이다.
노드 동기화와 동시 실행 제어
멀티머신 환경에서는 노드가 동시에 실행되어야 하는 경우도 있고, 특정 노드가 준비된 후에 다른 노드를 실행해야 할 수도 있다. 예를 들어, 센서 노드가 먼저 실행되어 데이터가 Publish되기 시작한 다음, 처리 노드를 실행해야 하는 시나리오가 있을 수 있다.
이런 동시 실행 제어는 ROS2의 Launch 액션 중 이벤트(Event)나 조건(Condition)을 활용하여 구현 가능한다. 예를 들어, 아래와 같이 RegisterEventHandler를 사용해 특정 노드의 프로세스가 종료되면 다른 노드를 실행하게 구성할 수 있다.
이처럼 Launch 이벤트를 통해 노드의 실행 순서를 제어할 수 있지만, 멀티머신 환경에서 실제 “동시성” 제어를 위해서는 DDS 측의 QoS 설정(예: Liveliness, Deadline)이나 기타 방법도 함께 고려해야 한다.
노드의 상태 관리와 Lifecycle
ROS2에서 제공하는 Lifecycle Node 기능을 사용하면 노드의 상태를 체계적으로 관리할 수 있다. 멀티머신 환경에서도 Lifecycle 노드 간에 상호 상태 전이를 시도할 수 있지만, 여러 머신에 흩어져 있는 노드들을 일관성 있게 관리하기 위해서는 다음과 같은 사항을 고려해야 한다.
Lifecycle 매니저: 여러 Lifecycle 노드를 동시에 제어할 수 있는 매니저 노드. 이를 멀티머신 환경에서는 로컬 머신에 배치하거나, 별도의 머신(혹은 Container)에서 운용하기도 함.
노드 상태 전이: 원격 머신의 Lifecycle 노드를 활성화(activate)하기 전, 로컬 머신의 Lifecycle 노드도 준비 상태(configure)로 만들어야 하는 경우가 발생할 수 있음. 이를 Launch 파일에서 일괄 처리할 수 있지만, 이벤트 기반(토픽/서비스)를 고려해 로직을 짜야 함.
멀티머신 환경에서의 로깅(Log) 처리
여러 머신에서 동시에 노드가 실행되면, 각 머신의 콘솔 출력이나 로그 파일이 흩어지게 된다. 이를 한 곳에서 모니터링하고 싶다면 아래와 같은 전략을 사용할 수 있다.
ROS2 로깅 기능
--ros-args --log-level debug등으로 로그 레벨을 조정할 수 있으며,RCUTILS_CONSOLE_OUTPUT_FORMAT환경 변수를 통해 출력 형식을 제어할 수 있다.
원격 로그 수집
SSH 포워딩 혹은 syslog, fluentd, ELK(Elasticsearch, Logstash, Kibana) 등을 이용해 원격 머신의 로그를 중앙 서버로 모읍니다.
Launch 파일 내 출력 경로 지정
ExecuteProcess액션에서log_cmd=True나output='log'옵션을 설정해 로그 파일로 저장하도록 할 수 있다.이렇게 저장된 로그 파일을 NFS, sshfs 등으로 로컬 머신에서 접근할 수도 있다.
예시로, 원격 머신 로그를 파일로 저장하는 방법은 다음과 같이 작성할 수 있다.
이 경우, Launch 시스템의 기본 로그 경로(보통 ~/.ros/log 하위)가 사용되거나, ROS_LOG_DIR 환경 변수를 통해 설정된 경로가 사용된다.
멀티머신 환경에서 시간 동기화
ROS2 노드는 메시지에 타임스탬프를 포함하는 경우가 많다. 센서 데이터와 제어 명령 등을 시각적으로 맞추기 위해서, 멀티머신 환경에서는 시계(Clock) 동기화가 중요하다. 대표적으로 다음 방식을 사용할 수 있다.
NTP(Network Time Protocol) 사용
모든 머신이 같은 NTP 서버와 동기화되도록 설정
Chrony 사용
NTP보다 빠른 동기화 속도와 정밀도를 제공
ROS2 Time Source
시스템 클록이 아닌 ROS2 클록을 활용(시뮬레이션 환경 등에서 유용)
만약 타임스탬프가 중요한 고정밀 센서(예: LiDAR)를 여러 머신에 나눠서 Publish/Subscribe한다면, 클록 오차가 1ms 이하 수준으로 관리되는지 점검해야 한다.
보안(SROS2) 고려
ROS2 멀티머신 환경에서는 네트워크 구간이 외부에 노출될 가능성이 있으므로, SROS2를 통해 보안을 강화할 수 있다. SROS2는 DDS 보안(암호화, 인증, 액세스 제어)을 구성하는 툴체인을 제공한다. 멀티머신 Launch 파일에서 SROS2를 적용할 때 주요 포인트는 다음과 같다.
도메인 파티션별 인증서 발급
각 노드가 어떤 도메인에서 동작할지 명시하고, CA(Certificate Authority)로부터 인증서를 생성해두어야 한다.
DDS 보안 설정 파일
<node_name>.xml형태로 노드별 권한을 설정(어떤 토픽에 Publish, Subscribe 가능한지)원격 머신에서도 동일한 설정 파일을 사용해야 함
Launch 파일 내 환경 변수
export ROS_SECURITY_ENABLE=trueexport ROS_SECURITY_STRATEGY=Enforceexport ROS_SECURITY_ROOT_DIRECTORY=/path/to/security_filesSSH 명령으로 노드를 실행할 때도 같은 환경 변수를 적용해야 함
컨테이너(Docker) 기반 멀티머신 구성
물리 머신 간 멀티머신 구성을 넘어, Docker 등 컨테이너 환경에서 여러 컨테이너가 서로 다른 머신 역할을 하도록 설정하는 경우도 있다.
Docker Compose
여러 컨테이너를 동시에 실행하고, 네트워크 브리지를 통해 DDS를 연결
Launch 파일을 컨테이너 내부 혹은 외부에서 실행할 수 있음
ROS2 Humble용 공식 Docker 이미지
ros:humble이미지를 기반으로 각 노드가 들어있는 컨테이너를 만들어 네트워크 포트를 매핑컨테이너별로
ROS_DOMAIN_ID를 동일하게 맞춰야 함
멀티스테이지 빌드
ROS2 환경만 들어있는 베이스 이미지를 빌드 후, 추가로 필요한 패키지를 덧붙여 최종 이미지를 만듦
이 경우도 Launch 파일에 ExecuteProcess를 활용하여 docker exec나 docker-compose up 명령을 사용해 원격 컨테이너에서 노드를 실행하게 설정할 수 있다.
QoS 설정
ROS2에서 노드 간 통신은 DDS를 통해 이루어지며, 각 토픽마다 QoS(품질 보증) 프로파일을 설정할 수 있다. 멀티머신 환경에서는 네트워크 지연(latency)과 패킷 손실률이 단일 머신 환경 대비 높아질 수 있으므로, 적절한 QoS 설정이 필요하다. 예를 들어, 다음과 같은 파라미터들을 조정할 수 있다.
Reliability
Reliable: 손실 없이 전송
Best Effort: 성능 위주로 패킷 손실 허용
Durability
Volatile: 새로운 Subscriber는 이전 메시지를 수신하지 않음
Transient Local: 노드가 실행되기 전의 메시지도 버퍼에 저장했다가 전달
History
Keep Last: 최근 N개 메시지만 보관
Keep All: 모든 메시지를 보관
Depth
History가 Keep Last일 때 유지할 메시지 수
멀티머신 환경에서 센서 데이터처럼 실시간성이 중요한 토픽은 Best Effort / Volatile로 설정해 전송 지연을 줄이고, 제어 명령이나 중요한 상태 변경 메시지는 Reliable / Transient Local로 설정하는 식으로 구성할 수 있다.
네트워크 세분화(Segmentation)와 브릿지
여러 개의 서브넷으로 나뉘어 있는 큰 네트워크 환경에서 ROS2 멀티머신을 구성할 때, DDS Discovery가 제대로 이루어지지 않을 수 있다. 이 경우 다음과 같은 방법을 고려할 수 있다.
DDS 브릿지
FastDDS, CycloneDDS 등에서 제공되는 브릿지나 에이전트를 사용해 서로 다른 서브넷 사이에 메시지를 중계
VPN(Virtual Private Network)
로컬 IP 대역을 통합해 DDS Discovery가 가능한 가상 네트워크 공간을 구성
Multicast 라우팅
DDS Discovery는 멀티캐스트(주로 239.x.x.x 대역)를 사용하는데, 라우터/스위치에서 멀티캐스트 트래픽을 적절히 라우팅해주어야 함
Static Discovery
멀티캐스트가 차단된 환경에서는 DDS 측에서 Static Discovery 파일을 통해 노드 정보를 명시적으로 설정할 수도 있음
이러한 네트워크 세분화 상황을 Launch 파일에서 전부 제어하기는 어렵지만, 원격 노드 실행 시 알맞은 DDS 설정 파일(예: FASTRTPS_DEFAULT_PROFILES_FILE, CYCLONEDDS_URI)을 로드하도록 ExecuteProcess 명령어에 환경 변수를 지정하거나, Launch 인자로 넘길 수 있다.
대규모 멀티머신 환경
로봇 수가 많아지거나, 고성능 서버 여러 대를 묶어 하나의 ROS2 클러스터를 구성하는 상황에서는 Launch 파일의 구성도 상당히 복잡해질 수 있다. 이를 효율적으로 관리하기 위해 아래와 같은 접근 방식을 고려할 수 있다.
템플릿 기반 Launch 파일 자동 생성
Jinja2, Mako 등 템플릿 엔진으로, 노드/머신 구성을 템플릿으로 작성하고 로봇 ID 혹은 머신 IP 리스트를 입력받아 Launch 스크립트를 자동 생성
오케스트레이션 도구 사용
Kubernetes, Docker Swarm 등 컨테이너 오케스트레이션 도구와 ROS2를 결합
Launch 파일 대신 Helm 차트나 Compose 파일 등을 통해 대규모 배포
분산 TF(Transform) 관리
여러 로봇이 동시에 동작할 경우, TF 트리(좌표 변환)를 어떻게 공유할지 계획해야 함
각 로봇마다 네임스페이스를 분리하거나, 마스터 TF 서버를 두어 전역 좌표계를 제공
자동화된 테스트와 CI
멀티머신 환경에서의 Launch 구성은 로컬 테스트보다 훨씬 복잡한다. 이를 자동화하기 위해 CI(Continuous Integration) 환경에서 가상 머신 혹은 Docker 컨테이너 여러 개를 띄워서 멀티머신 상태를 재현할 수 있다.
GitHub Actions, GitLab CI
여러 에이전트(런너)에서 각각의 컨테이너를 구동하고, 네트워크를 연결한 뒤 Launch 파일을 실행
ROS2 Testing Framework
launch_testing패키지를 통해 노드 실행 후 토픽/서비스 결과를 자동 검증
가상 네트워크
CI 환경에서 Docker Network나 mininet 등을 활용해 네트워크 지연 및 패킷 손실을 시뮬레이션
문제 발생 시 트러블슈팅 방법
멀티머신 환경에서는 통신 오류나 노드 실행 실패가 다양한 원인으로 발생할 수 있다. 다음과 같은 접근으로 문제를 진단할 수 있다.
DNS/호스트명 확인
원격 머신에 SSH가 정상적으로 연결되는지,
/etc/hosts설정이 올바른지 확인로컬에서
ping slave-computer명령어가 제대로 동작하는지 점검
ROS_DOMAIN_ID
각 머신에서
echo $ROS_DOMAIN_ID로 동일한지 확인Launch 파일에서 하드코딩되어 다른 값을 쓰지 않는지 점검
ROS2 Discovery 및 토픽 확인
ros2 topic list혹은ros2 node list로 원격 노드가 보이는지 확인보이지 않는다면 DDS 설정 파일이나 네트워크 방화벽 문제를 의심
방화벽 설정
Ubuntu ufw나 CentOS firewalld 등에서 UDP 포트가 차단되지 않았는지 확인
DDS가 사용하는 포트를 열어주거나, VPN을 통해 내부 트래픽으로 우회
SSH 명령 실행 여부
Launch 파일에서 사용 중인 SSH 명령어를 수동으로 입력해 보았을 때 정상 실행되는지 확인
키 인증이 올바르게 설정되었는지 재점검
Launch 구성 최적화 팁
명시적인 로그 레벨
--ros-args --log-level debug형태로 디버그 로그를 켜놓으면 문제 발생 시 유용
분할된 Launch 파일
로컬 노드와 원격 노드를 분리한 뒤, 단계적으로 로깅하면서 문제 구간을 좁힘
대역폭 절약을 위한 QoS
이미지나 레이저 스캔처럼 대용량 토픽은 필요에 따라 압축 노드(image_transport) 등을 사용하는 방안을 고려
SSH 멀티 세션 관리
병렬로 여러 원격 노드에 접속해야 할 때는,
ParallelSubstitution등 고급 Launch 액션을 활용하거나, 별도의 SSH Multiplexing을 설정
Last updated