# ROS\_DOMAIN\_ID를 활용한 구분 전략

#### ROS\_DOMAIN\_ID의 개념

ROS2에서 네트워크 상의 노드들이 서로 통신하기 위해서는 DDS(Datay Distribution Service)를 통해 데이터가 교환된다. DDS 계층에서 “도메인(Domain)”이라는 논리적 구분 개념을 사용하여 특정 도메인 안에 속한 노드끼리만 서로를 인식하고 통신할 수 있다. 바로 이때 활용되는 것이 `ROS_DOMAIN_ID`이다. `ROS_DOMAIN_ID`를 서로 다르게 설정하면 동일 물리 네트워크 안에 있더라도 논리적으로 통신을 분리할 수 있고, 반대로 동일하게 설정하면 하나의 도메인으로 묶여서 상호 통신이 가능해진다.

#### 도메인 ID를 통한 네트워크 분리 예시

* 사내에서 개발 PC와 실험용 로봇이 여러 대 있는 경우
* 하나의 네트워크 망 안에서 서로 영향을 주고받지 않도록 프로젝트별로 구분해야 하는 경우
* 로컬호스트(개발용)와 원격 시스템(실험용)을 동시에 돌리면서 서로 간섭을 최소화하려는 경우

예를 들어 사내 네트워크의 IP 대역대가 동일하고, 물리적으로도 같은 스위치에 연결되어 있다면, 기본적으로 설정을 하지 않을 경우 모든 ROS2 노드들은 `ROS_DOMAIN_ID=0` (기본값)으로 인식되어 서로 브로드캐스트를 수행한다. 그런데 이를 구분하고 싶다면 아래와 같이 각 그룹별로 도메인 ID를 명시적으로 할당할 수 있다.

```bash
# 예: 사무실 로봇A용 도메인 (Domain ID = 10)
export ROS_DOMAIN_ID=10
# 예: 사무실 로봇B용 도메인 (Domain ID = 20)
export ROS_DOMAIN_ID=20
# 예: 개발용 PC - 테스트 도메인 (Domain ID = 30)
export ROS_DOMAIN_ID=30
```

이렇게 서로 다른 도메인 ID를 사용하면, 물리 네트워크는 동일하더라도 노드 간 트래픽이 서로 격리된다.

#### 도메인 ID 설정 범위

ROS2가 DDS를 통해 통신할 때, 사용 가능한 도메인 ID는 일반적으로 0부터 232 미만의 정수 범위를 갖는다.

즉, $0 \leq D\_{ID} < 2^{32}$ 의 범위: 다만 DDS 구현체마다 지원 범위가 다를 수 있으므로 지나치게 큰 수를 사용하기보다는, 프로젝트에서 관리하기 쉽도록 적당한 양의 정수 범위(예: 0\~1000 안팎) 내에서 할당하는 것이 일반적이다.

#### 멀티머신 환경에서 ROS\_DOMAIN\_ID의 활용성

멀티머신 환경에서 여러 대의 로봇, 여러 대의 센서 노드, 그리고 여러 대의 개발 워크스테이션이 동시에 같은 네트워크에 연결될 수 있다. 모든 장비가 하나의 도메인 ID만 사용하면 시스템 규모가 커질수록 브로드캐스트되는 트래픽 역시 기하급수적으로 증가해 불필요한 오버헤드가 발생한다. 더불어 서로 다른 프로젝트이거나, 동시 테스트가 불가능하도록 격리해야 하는 상황이 발생할 수 있다. 이때 `ROS_DOMAIN_ID`를 달리 설정하면 별개의 ROS2 네임스페이스를 물리 계층 수준에서 분리하여, 각 그룹 간 통신을 차단하거나 선택적으로 허용할 수 있다.

간단한 예로, 두 대의 로봇이 같은 IP 대역을 공유하면서도 서로 독립적으로 작동해야 한다면, 로봇 A는 `ROS_DOMAIN_ID=1`, 로봇 B는 `ROS_DOMAIN_ID=2`와 같이 설정해줄 수 있다. 이렇게 하면, 로봇 A와 B는 같은 스위치, 같은 무선 공유기에 연결되어 있더라도 노드 간 상호 인식이 일어나지 않는다.

#### 시스템 구성 시 유의사항

1. **도메인 ID 충돌 방지**: 여러 팀원이 서로 다른 환경에서 작업할 때, 혹은 로컬에서 작동 중인 ROS2 노드가 이미 특정 도메인을 점유하고 있을 때, 원하는 도메인 ID를 쓰려면 충돌을 피해야 한다. 예를 들어 회사 표준으로 도메인 ID의 사용 범위를 미리 정의해 두면 충돌을 예방할 수 있다.
2. **변수 관리의 일관성**: 도메인 ID를 `~/.bashrc`나 `~/.zshrc` 등의 셸 초기화 스크립트에 넣어두어, 터미널을 새로 열 때마다 자동으로 설정되도록 하면 편리하다. 다만, 여러 프로젝트를 오가며 작업하는 경우에는 설정을 수동으로 바꾸거나, 프로젝트별로 스크립트를 달리 관리할 필요가 있다.
3. **RMW 구현체 간 호환성**: ROS2에서 사용하는 RMW(Robot Middleware) 구현체가 `rmw_fastrtps_cpp`, `rmw_cyclonedds_cpp` 등 여러 종류가 있는데, 도메인 ID 설정 방식이 DDS 구현체마다 조금씩 다를 수 있다. 보통은 `ROS_DOMAIN_ID` 환경 변수를 통해 자동으로 인식하지만, 특정 DDS 구현체는 별도의 설정 파일(xml 등)에서 도메인 ID를 관리하기도 하므로 주의해야 한다.

#### ROS\_DOMAIN\_ID와 ROS2 네임스페이스 개념 비교

ROS2에서는 노드를 논리적으로 구분하기 위한 “네임스페이스(namespace)”와 물리적으로 통신을 분리하기 위한 “도메인 ID(domain ID)”가 별도로 존재한다. 둘 다 노드와 토픽 등 리소스를 구분하는 데 사용되지만, 그 적용 계층과 분리 목적이 다르다.

* **네임스페이스**: ROS2 계층에서 노드, 토픽, 액션, 파라미터 등의 이름공간을 구분하기 위한 로직적 스코프 개념
* **도메인 ID**: DDS 계층에서 브로드캐스트 스코프 자체를 분할하기 위한 물리적 격리 개념

네임스페이스는 로봇 내부에서 동일 도메인 내 다양한 컴포넌트들의 충돌을 방지하기 위한 것이라면, 도메인 ID는 서로 다른 로봇이나 시스템이 네트워크를 공유할 때 트래픽 충돌을 회피하기 위해 DDS 레벨에서 패킷 브로드캐스트를 차단하는 장치로 이해할 수 있다.

#### Domain ID가 다른 노드 간 통신

서로 다른 도메인 ID를 가진 노드는 DDS Discovery 단계에서 서로를 전혀 인식하지 못한다. 물리적으로 같은 IP 대역 안에 있다고 하더라도, DDS 패킷이 도메인별로 나뉘어 브로드캐스트(혹은 멀티캐스트)되기 때문이다. 따라서 다음과 같은 상황이 발생한다.

**토픽 자동 검색 불가능**: 예컨대 로봇 A가 `ROS_DOMAIN_ID=5`로 동작 중이고, 로봇 B가 `ROS_DOMAIN_ID=10`으로 동작 중이라면, 둘은 아무리 같은 토픽 이름을 사용해도 서로 간 트래픽을 주고받을 수 없다.

ROS2 CLI 명령어 영향:

로봇 A의 도메인 ID가 5일 때,

```
$ros2 topic list
```

등의 명령은 도메인 5번 내부의 토픽만 보여준다.

```bash
# 로봇 A 터미널
export ROS_DOMAIN_ID=5
ros2 topic list
# => Domain 5 안의 토픽만 확인 가능
```

반대로 로봇 B 터미널에서

```
$ros2 topic list
```

를 수행하면 도메인 10번의 토픽만 확인할 수 있다.

```bash
# 로봇 B 터미널
export ROS_DOMAIN_ID=10
ros2 topic list
# => Domain 10 안의 토픽만 확인 가능
```

#### Domain ID가 같은 노드 간 통신 시 주의사항

만약 여러 로봇이나 여러 센서가 동일 도메인 ID를 공유한다면, 서로의 노드를 발견하고 토픽을 자유롭게 송수신할 수 있다. 이때 생길 수 있는 이슈는 다음과 같다.

1. **토픽 이름 충돌** 동일 토픽 이름을 사용하는 노드가 여러 개 있을 경우, 멀티플블(Pub/Sub)이 섞여서 의도하지 않은 데이터가 수신될 수 있다. 이를 방지하려면 네임스페이스를 분리하거나, 노드 이름을 고유하게 설정해주어야 한다.
2. **브로드캐스트 트래픽 증가** 도메인 ID가 하나이면, 네트워크 상에 존재하는 모든 노드가 서로를 브로드캐스트/멀티캐스트로 탐색한다. 노드 수가 많아질수록 네트워크 부담이 커지므로, 프로젝트 규모에 따라 도메인 ID를 적절히 나누는 것이 좋다.
3. **QoS 충돌** 서로 다른 노드가 같은 토픽을 출판·구독하면서 QoS(Quality of Service) 설정이 상충되면 통신 불일치가 발생할 수 있다. 도메인으로 물리적 격리를 하지 않으면, QoS 설정 이슈가 나타날 가능성이 높아진다.

#### 도메인 ID 분산 구성 사례

동시에 여러 로봇을 운영하는 환경을 예로 들어, 다음과 같이 도메인을 구성할 수 있다.

* **도메인 1**: AGV(Automated Guided Vehicle) 그룹
* **도메인 2**: 드론(Drone) 그룹
* **도메인 3**: 원격 센서 그룹 (CCTV, Laser Sensor 등)
* **도메인 4**: 개발/시뮬레이션 PC

이렇게 구성해두면, AGV가 네트워크 트래픽으로 드론이나 원격 센서에게 영향을 주지 않게 된다. 또한 각 그룹 내에서만 자유롭게 통신하므로 충돌을 줄일 수 있다. 단, 필요에 따라 특정 그룹 간 통신이 필요하다면, ‘멀티 도메인 브리지(Multi-Domain Bridge)’ 등을 고려해야 한다.

#### 멀티 도메인 브리지(Multi-Domain Bridge)

도메인이 다른 노드 간에도 데이터를 전달해야 할 때, ROS2는 본래 도메인이 다르면 바로 통신이 불가능하다. 이를 우회하기 위해 “Bridge” 노드가 양쪽 도메인에 동시에 참가하여, 양 방향으로 메시지를 중계해주는 전략을 사용할 수 있다.

간단히 표현하면,

* 브리지 노드는 도메인 $D\_a$에도 참가하고, 동시에 도메인 $D\_b$에도 참가한다.
* $D\_a$에서 발행된 메시지를 브리지 노드가 구독한 뒤, 같은 메시지를 $D\_b$ 쪽으로 재발행한다.
* 반대 방향도 동일하게 구성해 양방향 통신을 실현할 수 있다.

예시 스크립트 구조(개념 예시):

```bash
# 브리지 노드 구동(또는 별도 프로세스로 실행)
# Pseudocode
ros2 run my_bridge_pkg domain_bridge_node \
  --domain_a 5 \
  --domain_b 10 \
  --topic /example_topic
```

이런 식으로 `domain_bridge_node`가 도메인 5와 10에 모두 참여해, `/example_topic`에 대한 메시지를 상호 중계한다. 실제로는 브리지 노드를 직접 작성하거나 `ros2 domain bridge` 기능을 활용할 수 있다.

#### Domain ID 설정이 DDS Discovery에 미치는 영향

DDS Discovery 과정에서 Participant는 자신이 속한 도메인 ID 정보를 패킷에 포함하여 전송한다. 같은 도메인 ID를 가진 Participant만이 서로를 식별하고, 토픽·서비스 정보를 교환한다. 도메인 ID가 서로 다르면 Discovery 패킷을 무시하도록 구현되어 있다.

또한 DDS 벤더(예: Fast-DDS, CycloneDDS, ConnextDDS)에 따라 Discovery 방식이 다를 수 있지만, 기본적으로는 동일 도메인 ID 안에서 멀티캐스트를 통해 Participant를 탐색한다. 도메인 ID가 다르면 아예 패킷을 수신하지 않거나, 수신하더라도 잘못된 도메인으로 간주하여 폐기한다.

#### ROS\_DOMAIN\_ID와 RMW 설정 파일

일부 DDS 구현체는 별도의 XML 설정 파일을 요구하거나, 환경 변수가 아닌 자체 파라미터로 도메인 ID를 관리할 수 있다. 이를테면 CycloneDDS의 경우, `$ROS\_DOMAIN\_ID`를 인식하는 동시에 `~/.config/cyclonedds/cyclonedds.xml` 파일에 설정된 도메인 ID를 우선시하는 식으로 동작할 수도 있다. 따라서 특정 RMW를 사용할 때는 환경 변수와 설정 파일이 충돌하지 않도록 주의해야 한다.

#### Docker 컨테이너에서의 ROS\_DOMAIN\_ID

ROS2를 Docker 컨테이너로 구동하는 경우, 기본적으로 호스트와 동일한 네트워크 인터페이스를 공유하거나, 컨테이너끼리 별도의 브리지 네트워크를 구성할 수 있다. 이때 `ROS_DOMAIN_ID` 역시 다음과 같은 전략을 고려해야 한다.

**호스트와 같은 도메인 사용 시**: 컨테이너 내부에서 `ROS_DOMAIN_ID`를 호스트와 동일하게 설정하면, 컨테이너가 호스트의 네트워크와 거의 동일한 환경에서 동작한다. 호스트의 노드와 컨테이너의 노드가 상호 통신해야 한다면 이렇게 설정하는 편이 간편하다.

```bash
docker run -it \
    --network host \
    -e ROS_DOMAIN_ID=10 \
    ros2_humble_image
```

이 경우 호스트와 컨테이너가 동일 도메인 ID에서 Discovery가 이루어지고, 같은 토픽을 공유하게 된다.

**컨테이너별로 분리된 도메인 사용 시**: 하나의 물리 호스트에서 여러 컨테이너를 띄운 뒤, 각각 다른 로봇 애플리케이션을 구동해야 할 때, 각 컨테이너마다 `$ROS\_DOMAIN\_ID`를 달리 설정하면 쉽게 통신이 분리된다.

```bash
# 컨테이너1: Domain ID=10
docker run -it \
    --network host \
    -e ROS_DOMAIN_ID=10 \
    ros2_humble_image

# 컨테이너2: Domain ID=20
docker run -it \
    --network host \
    -e ROS_DOMAIN_ID=20 \
    ros2_humble_image
```

이렇게 하면 컨테이너1과 컨테이너2는 서로 물리적으로 같은 호스트에 올라가 있지만, DDS 레벨에서 트래픽이 격리된다.

1. **브리지 네트워크 사용 시 주의사항** Docker에서 자체 브리지 네트워크를 사용할 경우, `--network host` 옵션과는 달리 컨테이너가 호스트와 IP 대역을 공유하지 않는다. 이때 DDS 멀티캐스트 패킷이 전달되지 않을 수도 있으므로, 필요한 경우 방화벽 설정이나 네트워크 라우팅을 별도로 구성해야 할 수 있다. 도메인 ID가 격리 역할을 하더라도, Docker 네트워크 수준의 통신이 제대로 열려 있어야 서로 노드를 찾을 수 있다.

#### 네트워크 레벨 보안과 방화벽 고려

멀티머신 환경에서 ROS2 통신은 주로 UDP 포트를 활용하는데, DDS 구현체마다 기본적으로 사용하는 포트 범위가 정해져 있다. 도메인 ID를 분리해도, 방화벽이나 네트워크 라우터 수준에서 다음 사항을 고려해야 한다.

1. **포트 열기** CycloneDDS, Fast-DDS 등은 멀티캐스트와 UDP 포트를 여러 개 사용한다. 해당 포트가 방화벽에 막혀 있으면, 도메인 ID가 같아도 Discovery가 되지 않는다.
2. **멀티캐스트 라우팅** VLAN이나 서브넷으로 네트워크가 나뉘어 있을 때, 멀티캐스트 라우팅 설정이 되어 있지 않으면 같은 도메인 ID를 사용해도 노드를 발견하지 못할 수 있다. 도메인 분리는 DDS 계층의 논리적 기능이므로, 물리 네트워크 내 멀티캐스트 트래픽이 허용되어야 한다.

#### 멀티머신 시나리오에서 Domain ID 설정 예

다음은 사내 로봇 연구실을 예시로 한 도메인 ID 설정 시나리오이다.

* **Domain ID 1**: SLAM 연구팀 (실내 지도 생성 및 자율주행 테스트)
* **Domain ID 2**: 협동 로봇 제어팀 (공장 로봇팔, 이동 로봇 간 협업)
* **Domain ID 3**: 시뮬레이션 & DevOps (Gazebo/IGN 등 시뮬레이터 활용)
* **Domain ID 4**: 알고리즘 검증 및 ML/AI 테스트 (Sensor Fusion, Object Detection 등)

각 팀은 물리적으로 같은 사무실 공유 Wi-Fi를 사용하더라도 서로 다른 Domain ID로 분리한다. 테스트가 필요한 경우 특정 팀의 Domain ID에 일시적으로 합류해볼 수 있다. 혹은 실제 로봇이 아닌 시뮬레이션만 단독으로 진행할 때는 Domain ID를 격리해, 실제 로봇 네트워크를 건드리지 않고 실험을 진행할 수 있다.
