이번 포스팅에서는 ROS1과 ROS2의 가장 큰 차이점이라고 할 수 있는 DDS 그리고 DDS에 따른 QoS를 살펴보도록 하자.
ROS1과 마찬가지로, ROS2에서는 메시지 통신인 토픽, 서비스, 액션(ROS1 같은 경우에는 최소 Noetic은 가야된다), 파라미터가 있다. ROS1을 사용해보았다면 이러한 메시지 통신들 모두 퍼블리시(publish)와 서브스크라이브(subscribe)를 기본적으로 사용함을 알 수 있다.
그런데 ROS Master에 의해서 각 노드들과 메시지 통신이 관리되었고, 이를 위한 통신 프로토콜로써 TCPROS, UDPROS 등을 사용했던 ROS1과 다르게, ROS2는 DDS(Data Distribution Service)의 RTPS(Real Time Publish Subscribe)를 사용하고 있다.

참고 주소: https://cafe.naver.com/openrt/24031
DDS 도입으로 변화한 ROS2의 특징은 다음과 같다.
💡 변화점
1. IDL(Interface Description Language) 사용을 통한 쉬운 메시지 정의
2. 실시간 데이터 전송 보장
3. 임베디드 시스템에서의 사용
4. Master 없이 동적 노드 탐색 -> 여러 DDS 노드 간 통신 O
5. QoS(Quality of Service) 설정을 통한 커스텀 통신 설정
6. 보안성 강화
한편, DDS의 정의는 다음과 같다.
💡 DDS의 정의
- 데이터 통신을 위한 미들웨어
- 미들웨어 프로토콜(DDSI-RTPS)과 같이 DDS 사양을 만족하는 미들웨어 API가 실체
- ISO 7계층에서 4~7계층 사이에 해당
📌 ISO 7계층이란?
ISO 7계층은 네트워크 프로토콜의 모델을 의미한다.
1. 물리계층(물리적 매체, 전선 등)
2. 데이터링크 계층(Wi-Fi, 이더넷 등)
3. 네트워크 계층(IP 주소할당, 라우팅, 패킷 전달 등)
4. 전송계층(데이터 분할/전송/재조립, TCP와 UDP의 동작 계층)
5. 세션 계층(통신 세션 설정/유지/종료 기능 등)
6. 표현 계층(데이터 형식 정의, 변환)
7. 웅용 계층(사용자가 네트워크에 접근해 특정 서비스 사용)
DDS의 특징은 다음과 같이 정리 가능하다.
💡 DDS 특징
1. 산업 표준
2. 운영체제 독립 -> 윈도우, 리눅스, macOS
3. 언어 독립 -> RMW 미들웨어로 추상화 -> RCL에 따라 다양한 언어 지원
출처: https://github.com/ros2/ros_core_documentation
4. UDP 기반으로 하되, QoS 설정이 가능함
5. 데이터 중심적 기능
6. 동적 노드 검색
- ROS2의 DDS는 동적 노드 검색을 통해 Master가 필요하지 않다.
- ROS2에서는 노드를 DDS의 참여자(participant)로 취급한다.
📌 ROS1의 경우?
ROS1의 경우 MAster에서 노드에 대한 이름 지정 및 등록 서비스를 제공하였고, 이러한 정보를 토대로 Master를 거쳐 각 노드들끼리 직접 연결되어 통신을 수행하였다.
- 쉽게 확장 가능한 아키텍쳐
- 다양한 벤더를 지원하지만, 그럼에도 상호 운용성 보장
- QoS 설정(이에 대해서는 후술)
- 강력한 보안 기능: 산업계 표준인 DDS 보안 사양 도입
기본적으로 ROS2에서 어떤 노드들을 실행해 메시지 통신을 주고받는다는 것 자체가 이미 DDS 통신을 사용하고 있는 것이다.
📌 RMW 변경 방법
RMW를 바꾸고 싶다면, RMW_IMPLEMENTATION 환경변수로 원하는 RMW를 지정한 후 노드를 실행하면 된다.$ export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp지원하는 RMW에는 다음 등이 있다.
1. rmw_connext_cpp
2. rmw_cyclonedds_cpp
3. rmw_fastrtps_cpp
4. rmw_gurumdds_cpp
이렇게 RMW를 바꾸어도 상호운용성이 보장된다.
💡 Domain 변경 방법
ROS2에서는 기본적으로 UDP 멀티캐스트로 통신이 이루어지기 때문에 별도 설정 없이는 동일 네트워크 상의 모든 노드가 연결된다. 이를 방지하기 위해선
1. 서로 다른 네트워크 사용
2. ROS namespace 추가
3. DDS Domain 변경
이 있다.
이 중 Domain 변경이 제일 쉬운데, ROS_DOMAIN_ID 환경변수를 지정해주면 되기 때문이다. 같은 ROS_DOMAIN_ID를 가지고 있는 노드들끼리만 연결될 수 있다.$ export ROS_DOMAIN_ID=11
이번에는 DDS의 QoS에 대해서 알아보자.
💡 QoS
QoS는 쉽게 말하면 DDS 데이터 통신의 옵션이다.
총 22가지 지정 가능한 항목이 있는데 이 중 ROS2에서는 다음 6가지를 많이 사용한다.
1. Reliability
2. History
3. Durability
4. Deadline
5. Lifespan
6. Liveliness
QoS의 22가지 옵션들.
참고링크: https://cafe.naver.com/openrt/24319
이제 ROS2에서 사용하는 QoS 옵션들에 대해서 조금 더 자세히 알아보자.
- 지정 가능한 옵션
- KEEP_LAST : 정해진 메시지 큐 크기만큼만 메시지 보관(depth 매개변수를 통해서 메시지 큐의 크기를 지정)
- KEEP_ALL : 모든 데이터를 보관
- RxO(Requested By Offered)
없음- 사용 예시
rclcpp::QoS(rclcpp::KeepLast(10)); // rclcpp qos_profile = QosProfile(history=QosHistoryPolicy.KEEP_LAST, depth=10) # rclpy
- 지정 가능한 옵션
- BEST_EFFORT : 데이터 송신에 집중, 전송 속도 중시, 데이터 유실 가능
- RELIABLE : 데이터 수신에 집중, 신뢰성 중시, 유실 발생시 재전송을 통해 유실 보완
- RxO
링크: https://cafe.naver.com/openrt/24319- 예시
rclcpp::QoS(rclcpp::KeepAll).best_effort(); // rclcpp qos_profile = QosProfile(reliability=QosReliability.BEST_EFFORT) # rclpy
- 지정 가능한 옵션
데이터를 수신하는 서브스크라이버가 생성되기 전의 데이터를 사용할 것인지 대한 QoS 옵션
- TRANSIENT_LOCAL : subscription이 생기기 전의 데이터 보관
- VOLATILE : subscription이 생성되기 전의 데이터는 무효
- RxO
링크: 상동- 예시
rclcpp::QoS(rclcpp::KeepAll).transient_local(); // rclcpp qos_profile = QosProfile(durability = QosDurabilityPolicy.TRANSIENT_LOCAL) # rclpy
- 지정 가능한 옵션
정해진 주기 안에 데이터가 발신 및 수신되지 않을 경우 EventCallback을 실행시키는 QoS 옵션
- deadline_duration : deadline을 확인하는 주기
- RxO
링크: 상동- 예시
rclcpp::QoS(10).deadline(100ms); // rclcpp qos_profile = QosProfile(depth=10, deadline=Duration(0.1)) # rclpy
- 지정 가능한 옵션
정해진 주기 안에서 수신되는 데이터만 유효 판정하고, 그렇지 않은 데이터는 삭제하는 QoS 옵션
- lifespan_duration : LifeSpan을 확인하는 주기
- RxO
해당 없음- 사용 예시
rclcpp::QoS(10).reliable().transient_local().lifespan(10ms); //rclcpp qos_profile = QoSProfile(lifespan = Duration(0.01)) # rclpy
- 지정 가능한 옵션
정해진 주기 안에서 노드 혹은 토픽의 생사를 확인하는 QoS 옵션
- liveliness : 자동 또는 매뉴얼로 확인할지를 지정하는 옵션, AUTOMATIC, MANUAL_BY_NODE, MANUAL_BY_TOPIC 중 선택
- automatic : 생존성을 관리하는 주체가 DDS 미들웨어
- manual : 생존성을 관리하는 주체가 사용자
- lease_duration : liveliness를 확인하는 주기
- RxO
출처: 상동- 사용예시
// rclcpp rclcpp::QoS qos_profile(10); qos_profile .liveliness(RMW_QOS_POLICY_LIVELINESS_AUTOMATIC) .liveliness_lease_duration(1000ms);# rclpy qos_profile = QosProfile( liveliness=AUTOMATIC, liveliness_lease_duration = Duration(1.0))
이러한 QoS를 기반으로, RMW에서는 QoS 설정을 쉽게 사용할 수 있도록 가장 많이 사용하는 QoS 설정을 세트(set)로 표현해둔 것이 있는데 이를 RMW QoS Profile이라고 한다.

출처: https://cafe.naver.com/openrt/24319
파이썬에서 이러한 세트를 사용하기 위해서는 다음과 같이 import 해야한다.
from rclpy.qos import qos_profile_sensor_data
사용자가 직접 새로운 qos_profile을 설정해서 사용도 가능하다. 파이썬에서는 다음과 같이 import 하고 지정하면 된다.
from rclpy.qos import QoSDurabilityPolicy
from rclpy.qos import QoSHistoryPolicy
from rclpy.qos import QoSProfile
from rclpy.qos import QoSReliabilityPolicy
예를 들어보면 다음과 같다.
QOS_RKL10V = QoSProfile(
reliability = QoSReliabilityPolicy.RELIABLE,
history = QoSHistoryPolicy.KEEP_LAST,
depth = 10,
durability = QoSDurabilityPolicy.VOLATILE)
이후 다음과 같이 사용하면 된다.
self.sensor_publisher = self.create_publisher(Int8MultiArray, 'sensor', QOS_RKL10V)