ROS 2에서는 DDS(Data Distribution Service)를 기반으로 노드 간 통신이 이루어지며, 데이터 통신의 세부적인 옵션을 사용자가 직접 설정할 수 있다. 이러한 통신 설정을 QoS(Quality of Service)라고 한다.
쉽게 말하면 QoS는 ROS 2에서 데이터를 어떻게 주고받을 것인지 정하는 통신 옵션이다.
ROS 1에서는 TCPROS를 기반으로 통신했지만, ROS 2에서는 DDS의 QoS를 활용하여 데이터의 신뢰성, 통신 속도, 데이터 보관, 지속성 등을 상황에 맞게 설정할 수 있다.
QoS는 Publisher와 Subscriber를 생성할 때 설정할 수 있으며, 어떤 QoS를 선택하느냐에 따라 데이터 통신의 특성이 달라진다.
DDS에서는 다양한 QoS 정책을 제공하며, ROS 2에서는 그중 주요한 QoS 설정을 사용할 수 있다.
대표적인 QoS 정책은 다음과 같다.
이러한 QoS 설정을 조합하여 통신 환경과 데이터의 특성에 맞는 통신 방식을 구성할 수 있다.
History는 통신 과정에서 데이터를 몇 개까지 보관할지를 결정하는 QoS 옵션이다.
정해진 메시지 큐 크기만큼의 데이터만 보관한다.
이때 depth는 메시지 큐의 크기를 의미하며, KEEP_LAST를 사용할 때 적용된다.
예를 들어 다음과 같이 설정할 수 있다.
qos_profile = QoSProfile(
history=QoSHistoryPolicy.KEEP_LAST,
depth=10
)
위 설정에서는 최근 데이터 10개를 보관한다.
가능한 모든 데이터를 보관하는 방식이다. 실제 메시지 큐의 크기는 사용하는 DDS 구현체에 따라 달라질 수 있다.
Reliability는 데이터 전송에서 속도와 신뢰성 중 무엇을 우선할지 결정하는 옵션이다.
데이터를 빠르게 전달하는 것을 우선한다.
네트워크 상태 등에 따라 데이터가 유실될 수 있지만, 빠른 데이터 전달이 중요한 상황에서 사용할 수 있다.
데이터의 신뢰성을 우선한다.
데이터가 유실되는 경우 재전송 등을 통해 수신을 보장하는 방식이다.
Python에서는 다음과 같이 설정할 수 있다.
qos_profile = QoSProfile(
reliability=QoSReliabilityPolicy.BEST_EFFORT
)
Publisher와 Subscriber의 Reliability 설정에 따라 통신 가능 여부도 달라지므로, 서로 호환되는 QoS 설정을 사용하는 것이 중요하다.
Durability는 Subscriber가 생성되기 전에 Publisher가 발행한 데이터를 어떻게 처리할지 결정하는 옵션이다.
Subscriber가 생성되기 전에 발행된 데이터도 보관하여 이후 생성된 Subscriber가 사용할 수 있도록 한다.
Subscriber가 생성되기 전에 발행된 데이터는 유효하지 않은 것으로 처리한다.
Python에서는 다음과 같이 설정할 수 있다.
qos_profile = QoSProfile(
durability=QoSDurabilityPolicy.TRANSIENT_LOCAL
)
Deadline은 정해진 주기 안에 데이터가 발신 또는 수신되지 않았을 경우 이를 감지하는 QoS 옵션이다.
예를 들어 다음과 같이 100ms의 Deadline을 설정할 수 있다.
rclcpp::QoS(10).deadline(100ms);
Python에서는 다음과 같이 설정한다.
qos_profile = QoSProfile(
depth=10,
deadline=Duration(0.1)
)
Publisher와 Subscriber가 설정한 Deadline 조건에 따라 통신 가능 여부가 결정된다.
Lifespan은 데이터가 일정 시간 동안만 유효하도록 설정하는 QoS 옵션이다.
정해진 시간 안에 수신되는 데이터만 유효한 것으로 판단하고, 시간이 지난 데이터는 삭제한다.
예를 들어 C++에서는 다음과 같이 설정할 수 있다.
rclcpp::QoS(10)
.reliable()
.transient_local()
.lifespan(10ms);
Python에서는 다음과 같이 설정할 수 있다.
qos_profile = QoSProfile(
lifespan=Duration(0.01)
)
Liveliness는 정해진 주기 안에서 Node 또는 Topic이 정상적으로 동작하고 있는지를 확인하는 QoS 옵션이다.
Liveliness 방식은 다음 세 가지로 구분된다.
AUTOMATICMANUAL_BY_NODEMANUAL_BY_TOPIC또한 lease_duration을 통해 Liveliness를 확인하는 주기를 설정할 수 있다.
Python에서는 다음과 같이 설정할 수 있다.
qos_profile = QoSProfile(
liveliness=AUTOMATIC,
liveliness_lease_duration=Duration(1.0)
)
ROS 2에서는 자주 사용하는 QoS 설정을 미리 조합한 RMW QoS Profile을 제공한다.
대표적으로 다음과 같이 구분된다.
| Profile | Reliability | History | Depth | Durability |
|---|---|---|---|---|
| Default | RELIABLE | KEEP_LAST | 10 | VOLATILE |
| Sensor Data | BEST_EFFORT | KEEP_LAST | 5 | VOLATILE |
| Service | RELIABLE | KEEP_LAST | 10 | VOLATILE |
| Action Status | RELIABLE | KEEP_LAST | 1 | TRANSIENT_LOCAL |
| Parameters | RELIABLE | KEEP_LAST | 1,000 | VOLATILE |
| Parameter Events | RELIABLE | KEEP_LAST | 1,000 | VOLATILE |
목적에 따라 자주 사용하는 QoS 설정을 Profile 형태로 제공하기 때문에 상황에 맞는 QoS를 쉽게 적용할 수 있다.
RMW에서 제공하는 기본 Profile 외에도 사용자가 직접 User QoS Profile을 만들어 원하는 설정을 사용할 수 있다.
먼저 QoS 관련 모듈을 가져온다.
from rclpy.qos import QoSDurabilityPolicy
from rclpy.qos import QoSHistoryPolicy
from rclpy.qos import QoSProfile
from rclpy.qos import QoSReliabilityPolicy
이후 원하는 QoS 설정으로 QoSProfile을 생성한다.
QOS_RKL10V = QoSProfile(
reliability=QoSReliabilityPolicy.RELIABLE,
history=QoSHistoryPolicy.KEEP_LAST,
depth=10,
durability=QoSDurabilityPolicy.VOLATILE
)
생성한 QoS Profile은 Publisher를 생성할 때 사용할 수 있다.
self.sensor_publisher = self.create_publisher(
Int8MultiArray,
'sensor',
QOS_RKL10V
)
이처럼 직접 QoS Profile을 정의하면 통신 목적에 맞춰 Reliability, History, Depth, Durability 등을 자유롭게 조합할 수 있다.
이번 학습에서는 ROS 2의 QoS(Quality of Service)에 대해 알아보았다.
QoS는 ROS 2의 DDS 통신에서 데이터가 전달되는 방식을 세부적으로 설정하는 기능으로, History, Reliability, Durability, Deadline, Lifespan, Liveliness 등의 다양한 정책을 제공한다.
또한 ROS 2에서 제공하는 RMW QoS Profile과 사용자가 직접 설정하는 User QoS Profile을 통해 Publisher와 Subscriber의 통신 특성을 목적에 맞게 구성할 수 있다는 것을 확인했다.
결국 QoS는 단순히 데이터를 주고받는 것을 넘어 데이터의 신뢰성, 속도, 보관, 유효 시간 및 통신 상태 등을 상황에 맞게 조절하기 위한 ROS 2의 중요한 기능이라고 볼 수 있다.