3. 개발 PC 환경
3.9네트워크 설정
지금까지의 실습은 VM 한 대 안에서 끝났습니다. 하지만 실제 로봇은 다른 컴퓨터이고 로봇과 내 VM이 통신하려면 같은 네트워크에서 서로를 찾아야 합니다. 이 장은 그 바탕을 만듭니다.
ROS2는 네트워크로 통신합니다
1.8장에서 본 것처럼 ROS2 노드들은 DDS라는 통신 계층으로 서로를 찾고 메시지를 주고받습니다. 같은 컴퓨터 안에서도 네트워크 방식으로 통신하기 때문에, 같은 네트워크에 연결된 컴퓨터끼리는 별도 설정 없이 서로의 노드를 발견합니다. 편리하지만 두 가지 문제가 생깁니다.
- VM의 가상 네트워크 구성이 잘못되면, 로봇과 내 VM이 서로를 찾지 못합니다.
- 한 교실에서 모두가 같은 네트워크를 쓰면, 남의 노드가 내
ros2 topic list에 섞여 보입니다.
앞의 문제는 VM 네트워크 모드로, 뒤의 문제는 ROS_DOMAIN_ID로 해결합니다.
VM 네트워크 모드
VM의 가상 네트워크 카드를 어떻게 연결하느냐에 따라 VM이 접근하는 범위가 달라집니다.
VirtualBox
VirtualBox 공식 매뉴얼 기준의 연결 가능 여부입니다. (확인 시점: 2026년 10월)
| 모드 | VM → 호스트 | 호스트 → VM | VM ↔ VM | VM → LAN/인터넷 | LAN → VM |
|---|---|---|---|---|---|
| NAT (기본) | 가능 | 포트 포워딩 필요 | 불가 | 가능 | 포트 포워딩 필요 |
| NAT 네트워크 | 가능 | 포트 포워딩 필요 | 가능 | 가능 | 포트 포워딩 필요 |
| 브리지 어댑터 | 가능 | 가능 | 가능 | 가능 | 가능 |
| 호스트 전용 | 가능 | 가능 | 가능 | 불가 | 불가 |
- NAT: VM이 호스트를 통해 인터넷에 나가는 방식입니다. 설정이 필요 없어 가장 편하지만 밖에서 VM으로 들어오는 접속이 막힙니다. 로봇이 내 VM을 찾지 못하므로 로봇 통신에는 맞지 않습니다.
- NAT 네트워크: NAT에 더해 같은 NAT 네트워크의 VM끼리 통신할 수 있습니다. 가상의 사설망 안에서만 실습할 때 쓸 수 있습니다.
- 브리지 어댑터: VM이 호스트의 물리 네트워크 카드를 통해 공유기에 직접 연결된 것처럼 동작합니다. 공유기가 VM에 별도의 IP를 줍니다. 로봇과 같은 공유기에 연결되어 있으면 서로 통신할 수 있습니다. 로봇 통신에는 보통 이 모드를 씁니다.
- 호스트 전용: VM과 호스트 PC 사이에서만 통신합니다. 외부와는 단절됩니다.
어떤 모드를 쓰나요?
| 상황 | 권장 모드 |
|---|---|
| 인터넷만 되면 되는 VM 단독 실습 (1~2장) | NAT (기본값 그대로) |
| 실제 로봇 또는 다른 컴퓨터와 ROS2 통신 | 브리지 |
| VM 두 대끼리 통신 테스트 | 브리지 (또는 VirtualBox의 NAT 네트워크) |
브리지가 항상 좋은 것은 아닙니다. VM이 공유기에서 별도 IP를 받아 외부에 노출되므로 공용 네트워크에서는 신경 써야 합니다. 또한 네트워크 환경(회사, 학교 네트워크)이 VM의 추가 MAC 주소를 막는 경우도 있습니다.
브리지 설정 방법
VirtualBox: VM을 종료한 뒤 VM의 설정 → 네트워크 → 어댑터 1에서 "다음에 연결됨"을 브리지 어댑터로 바꾸고 이름에서 호스트가 실제로 쓰는 네트워크 카드(유선 또는 Wi-Fi)를 고릅니다.
Wi-Fi 브리지 주의
VirtualBox 공식 매뉴얼에 따르면 대부분의 무선 어댑터는 promiscuous 모드를 지원하지 않아서 VirtualBox가 패킷의 MAC 주소를 바꿔치기하는 방식으로 우회합니다. 그래서 유선보다 불안정할 수 있습니다. 실제로는 이런 문제가 자주 보고됩니다. (환경에 따라 다릅니다.)
- 브리지로 설정했는데 VM이 IP를 받지 못함
- 학교, 회사 공유기가 한 기기당 하나의 MAC만 허용하거나, 기기 간 통신을 막음(client isolation, AP isolation)
- 연결은 되는데 ROS2 노드가 서로 보이지 않음 (아래 "발견 실패" 참고)
가능하면 유선 연결을 쓰거나 교실에 교육용 전용 공유기를 두는 것이 가장 확실합니다.
IP 주소와 연결 확인
VM 설정을 바꾼 뒤에는 VM을 켜고 터미널에서 IP를 확인합니다.
ip a
사용 중인 인터페이스(enp0s3, ens33처럼 en으로 시작하는 이름이 흔합니다)의 inet 줄에 IP 주소가 나옵니다. 모드별로 IP 모양이 다릅니다.
- NAT (VirtualBox):
10.0.2.x. VirtualBox 매뉴얼에 따르면 NAT 모드에서 VM이 호스트에 접근할 때는10.0.2.2를 씁니다. - 브리지: 공유기가 준 주소. 호스트 PC와 같은 대역(예:
192.168.0.x)이어야 합니다.
간단히 보려면 다음 명령도 있습니다.
hostname -I
ip route | grep default
두 번째 명령의 via 뒤가 공유기(게이트웨이) 주소입니다. 연결 확인은 ping으로 합니다. -c 3은 3번만 보내고 끝내라는 뜻입니다.
ping -c 3 <공유기 또는 상대 컴퓨터의 IP>
ping -c 3 8.8.8.8
OVA를 처음 가져온 상태(NAT)의 VM에서 실행한 화면입니다. 위 두 ip 명령과 게이트웨이 ping을 한 번에 실행했습니다.
- ① 인터페이스
enp0s3의 주소10.0.2.15: NAT 모드의 모양입니다. 브리지로 바꾸면 이 자리에 공유기가 준 주소가 나옵니다. - ②
default via 10.0.2.2: 게이트웨이. NAT에서는 호스트를 가리키는10.0.2.2입니다. - ③ 게이트웨이로 보낸
ping이0% packet loss로 끝났습니다.
0% packet loss가 나오면 연결된 상태입니다. 단계별로 확인하면 어디서 막히는지 알 수 있습니다.
| 확인 | 실패했다면 |
|---|---|
| 공유기(게이트웨이)에 ping | VM의 네트워크 모드와 어댑터 선택을 다시 확인 |
인터넷(8.8.8.8)에 ping | 공유기의 인터넷 연결 확인 |
| 상대 컴퓨터(로봇)에 ping | 같은 공유기에 연결됐는지, 같은 대역 IP인지, 상대 방화벽 확인 |
ROS_DOMAIN_ID
ROS_DOMAIN_ID는 일종의 번호표입니다. 같은 네트워크에서 ROS2 노드끼리 서로 보이는 범위를 이 번호가 정합니다. 같은 번호끼리만 서로를 발견합니다. 설정하지 않으면 기본값은 0입니다.
왜 교실에서 서로 달라야 하나
모든 학생이 기본값 0을 쓰면, 옆 사람의 talker가 내 ros2 topic list에 나타나고 내가 보낸 /cmd_vel이 다른 사람의 로봇을 움직일 수 있습니다. 그래서 학생(또는 조)마다 서로 다른 번호를 배정합니다. 로봇 한 대와 그것을 조종하는 PC는 같은 번호를 써야 합니다.
유효 범위
ROS2 공식 문서(Humble)에 따르면 도메인 ID는 0부터 232까지 쓸 수 있지만 간단하게 0~101을 권장합니다. 운영체제가 임시로 쓰는 포트 범위와 겹치지 않게 하기 위해서입니다. Linux 기준으로 안전한 값은 0~101과 215~232입니다. 이 교육에서는 0~101 중에서 배정합니다.
설정 방법
현재 터미널에만 적용 (확인용):
export ROS_DOMAIN_ID=30
echo $ROS_DOMAIN_ID
항상 적용하려면 ~/.bashrc에 추가합니다. 공식 문서의 방법입니다. (3.4장의 >>, > 주의사항을 기억하세요.)
echo "export ROS_DOMAIN_ID=30" >> ~/.bashrc
source ~/.bashrc
- ①
echo $ROS_DOMAIN_ID가30을 출력합니다. - ②
printenv | grep ROS의ROS_DOMAIN_ID=30: 이 터미널의 ROS 환경변수 목록에 들어갔습니다. - ③
ROS_LOCALHOST_ONLY=0: 값이0이면 꺼진 상태입니다. 설정하지 않으면ROS_DOMAIN_ID는 비어 있고 기본값0으로 동작합니다.
30 자리에는 강사가 배정한 번호를 씁니다. 노드를 실행하기 전에 설정해야 하고 이미 실행 중인 노드는 번호가 바뀌지 않습니다. 같은 컴퓨터의 터미널끼리도 번호가 다르면 서로 보이지 않습니다. 번호를 바꾼 뒤 새 터미널에서 확인하세요.
ROS_LOCALHOST_ONLY
ROS_LOCALHOST_ONLY=1로 설정하면 노드가 자기 컴퓨터 안(localhost)에서만 통신하고 네트워크로 나가지 않습니다. ROS2 Humble 공식 환경 설정 문서에 있는 환경변수입니다. 문서는 이 변수를 교실처럼 여러 사람이 같은 네트워크를 쓸 때 다른 사람과 섞이지 않게 하는 용도로 안내합니다.
export ROS_LOCALHOST_ONLY=1
혼자 VM 안에서 연습할 때 유용하지만 로봇이나 다른 컴퓨터와 통신할 때는 반드시 꺼야 합니다. 이 값이 켜져 있으면 노드가 바깥과 통신하지 않아 "연결은 되는데 아무것도 안 보이는" 원인이 됩니다.
unset ROS_LOCALHOST_ONLY
printenv | grep ROS_LOCALHOST_ONLY # 비어 있거나 ROS_LOCALHOST_ONLY=0 이어야 함
Humble의 setup.bash는 이 변수를 0으로 채워 줍니다. 그래서 unset한 뒤에도 새 터미널에서는 ROS_LOCALHOST_ONLY=0이 출력될 수 있고, 이것은 꺼진 상태입니다. 1이 나오면 켜진 것입니다.
~/.bashrc에 export ROS_LOCALHOST_ONLY=1을 넣었다면 그 줄도 지워야 합니다. 새 터미널에서 다시 확인하세요.
노드 발견과 그것이 실패하는 이유
ROS2 노드는 시작할 때 네트워크에 "나 여기 있어요" 라고 알리고 다른 노드의 알림을 받아 서로를 발견합니다. 기본 구현에서는 이 알림에 UDP 멀티캐스트를 씁니다. (Humble의 기본 DDS 구현은 Fast DDS입니다.) 그래서 멀티캐스트가 막힌 네트워크에서는 ping이 되어도 서로의 노드가 보이지 않습니다.
대표적인 원인은 다음과 같습니다.
| 원인 | 설명 |
|---|---|
| VM이 NAT 모드 | 밖에서 VM으로 들어오는 트래픽이 막히고 멀티캐스트도 전달되지 않음 |
| Wi-Fi 공유기 설정 | 기기 간 통신 차단(client/AP isolation), 멀티캐스트 차단 또는 제한 |
| VM의 Wi-Fi 브리지 | 앞서 본 MAC 주소 문제로 불안정 |
ROS_DOMAIN_ID 불일치 | 번호가 다르면 서로 보이지 않음 |
ROS_LOCALHOST_ONLY=1 | 로컬에서만 통신 |
| 방화벽 | Ubuntu의 ufw가 켜져 있으면 UDP 트래픽이 차단될 수 있음 |
| 서로 다른 서브넷 | 두 컴퓨터가 다른 대역(예: 192.168.0.x와 192.168.1.x)에 있음 |
점검 순서
ROS2 CLI에는 멀티캐스트 통신을 직접 테스트하는 도구가 있습니다. 두 컴퓨터에서 각각 실행합니다.
# 컴퓨터 A
ros2 multicast receive
# 컴퓨터 B
ros2 multicast send
한 VM에서 터미널 두 개로 실행하면 이렇게 나옵니다. 받는 쪽을 먼저 켜 두고 보냅니다.
- ① 보내는 쪽(
send): 멀티캐스트 UDP 한 개를 보냈다는 문구 - ② 받는 쪽(
receive)이 기다리는 중 - ③ 받는 쪽의
Received from 주소:포트: 'Hello World!': 멀티캐스트가 통과한 것입니다.
A에서 B가 보낸 메시지가 출력되면 멀티캐스트가 통과한다는 뜻입니다. 안 나오면 네트워크(공유기, VM 모드)의 문제입니다. 그 밖의 점검은 다음 순서로 합니다.
echo $ROS_DOMAIN_ID # 두 컴퓨터가 같은 값인가
printenv | grep ROS_LOCALHOST_ONLY # 비어 있거나 =0 이어야 함
sudo ufw status # Status: inactive 이면 방화벽은 원인이 아님
ros2 doctor --report # 네트워크 설정 요약 (3.10장에서 자세히)
실습: 두 컴퓨터에서 talker와 listener
ROS2 기본 데모 노드를 이용합니다. 컴퓨터 A는 내 VM, 컴퓨터 B는 옆 사람의 VM(또는 같은 PC에서 만든 두 번째 VM)입니다. 두 VM 모두 브리지 모드로 설정합니다. 로봇이 아직 없어도 로봇과 통신하는 것과 같은 구조를 연습할 수 있습니다.
준비 (두 컴퓨터 모두)
- 네트워크 모드가 브리지인지 확인하고
ip a로 IP를 확인합니다. 두 IP는 같은 대역이어야 합니다. - A에서 B로, B에서 A로
ping -c 3이 되는지 확인합니다. ROS_LOCALHOST_ONLY가 꺼져 있는지 확인합니다.
테스트 1: 같은 도메인 번호 (통신되어야 함)
두 컴퓨터 모두 같은 번호를 설정합니다. (다른 팀과 겹치지 않는 번호로 하세요.)
export ROS_DOMAIN_ID=77
컴퓨터 A에서:
ros2 run demo_nodes_cpp talker
컴퓨터 B에서:
ros2 run demo_nodes_py listener
B에서 I heard: [Hello World: 1] 같은 로그가 나오면 두 컴퓨터가 서로를 발견해 통신하고 있습니다. B에서 ros2 topic list와 ros2 node list도 실행해 A의 /chatter와 /talker가 보이는지 확인하세요.
테스트 2: 다른 도메인 번호 (통신되지 않아야 함)
B의 listener를 끄고 B에서만 번호를 바꿔 다시 실행합니다.
export ROS_DOMAIN_ID=78
ros2 run demo_nodes_py listener
이번에는 I heard가 나오지 않아야 합니다. 번호가 다르면 서로 다른 세계라는 점을 이 실험으로 확인합니다.
한 VM에서도 터미널마다 번호를 다르게 하면 같은 결과를 볼 수 있습니다. 아래 화면은 77번에서 talker를 켜 두고 listener를 77번과 78번으로 각각 실행한 것입니다.
- ① 같은 번호 77:
I heard: [Hello World: …]가 올라옵니다. - ② 다른 번호 78: 5초 동안 아무것도 받지 못하고
timeout이 끝냈습니다(Terminated). - ③ 77번
ros2 node list에는/talker가 보입니다. - ④ 78번
ros2 node list는 비어 있습니다. 확인을 마치면 B의 번호를 원래대로 돌려 두세요.
안 될 때
위 "점검 순서"를 따라 ros2 multicast부터 확인하세요. 같은 PC에서 만든 두 VM인데도 안 된다면 Wi-Fi 브리지 문제일 가능성이 높습니다. 호스트가 유선으로 연결되어 있다면 유선 어댑터로 브리지를 바꿔 보세요.
한눈에 정리
- 로봇과 통신하려면 VM 네트워크를 브리지 모드로 한다. NAT는 밖에서 VM으로 들어오는 접속이 막혀 맞지 않다.
- IP는
ip a, 연결은ping -c 3 <IP>로 확인한다. 같은 대역인지 본다. ROS_DOMAIN_ID는 같은 번호끼리만 서로 보이는 번호표다. 권장 범위는 0~101이고 교실에서는 학생(조)마다 다르게 배정한다.ROS_LOCALHOST_ONLY=1은 로컬 전용이다. 로봇과 통신할 때는 꺼야 한다.- 노드 발견은 멀티캐스트에 의존하므로 Wi-Fi, VM 설정에 따라 실패할 수 있다.
ros2 multicast send/receive로 확인한다. - 두 컴퓨터 테스트는 같은 번호에서
talker/listener가 통신되고, 다른 번호에서는 통신되지 않는 것으로 확인한다.
확인 문제
Q1. VM이 NAT 모드일 때 로봇과 ROS2 통신이 잘 안 되는 이유는?
NAT 모드에서는 외부(로봇)에서 VM으로 들어오는 접속이 포트 포워딩 없이는 막히고 노드 발견에 쓰는 멀티캐스트도 전달되지 않기 때문입니다. 브리지 모드로 바꿔 VM이 같은 공유기에 직접 연결되게 해야 합니다.
Q2. 두 컴퓨터가 서로 ping은 되는데 ros2 topic list에 상대 노드가 보이지 않습니다. 확인할 것을 세 가지 말해 보세요.
- 두 컴퓨터의
ROS_DOMAIN_ID가 같은지 ROS_LOCALHOST_ONLY가 꺼져 있는지- 멀티캐스트가 통과하는지 (
ros2 multicast send/receive), 그리고 Wi-Fi 공유기의 기기 간 통신 차단이나 방화벽 여부
Q3. 교실의 모든 학생이 ROS_DOMAIN_ID를 기본값(0)으로 두면 어떤 일이 생길 수 있나요? 권장되는 번호 범위는?
다른 학생의 노드와 토픽이 내 목록에 섞여 보이고 내 명령(/cmd_vel 등)이 다른 학생의 로봇에 전달될 수 있습니다. 학생(조)마다 서로 다른 번호를 배정하고 권장 범위는 0~101입니다.
다음 장
다음 장에서는 지금까지 만든 개발환경이 제대로 갖춰졌는지 체크리스트로 한꺼번에 점검하고, ros2 doctor로 환경 문제를 진단해 봅니다.