[ROS 2로 시작하는 로봇 프로그래밍]에 기반한 정리글입니다.
ROS에서 사용되는 메시지 통신은 토픽
, 서비스
, 액션
, 파라미터
가 있다. 각 메세지 통신의 목적과 사용 방법이 다르지만, 토픽의 Publish
와 Subscribe
의 개념을 응용한다. ROS 2는 산업용 시장 진입을 위한 표준 방식 사용을 중요하게 생각하였기에 DDS(Data Distrubution Service)
의 RTPS(Real Time Publish Subscribe)
을 사용한다.
DDS는 데이터 분산 시스템
의 줄임말로, ROS 2에서는 데이터 통신을 위한 미들웨어이다. 이 미들웨어는 ISO 7계층 레이어에서 호스트 계층에 해당하는 4~ 7계층에 해당하는데, ROS 2에서는 운영체제와 사용자 애플리케이션 사이의 소프트웨어 계층에서 이를 통해 통신하면서 데이터를 공유할 수 있게 한다.
DDS의 도입으로 메시지 정의 및 직렬화를 쉽고 포괄적으로 다룰 수 있게 되었으며, ROS 2는 통신 프로토콜 DDSI-RTPS
을 채용하여 실시간 데이터 전송을 보장하고 임베디드 시스템에도 사용할 수 있고, 여러 DDS 프로그램 간에 통신할 수 있게 되었다.
또한 노드 간의 데이터 통신을 세부적으로 조정하는 QoS(Quality of Service)
를 설정할 수 있어 TCP처럼 데이터 손실을 방지하여 신뢰도를 높일수도, UDP처럼 통신 속도를 우선하여 사용할 수 있다.
ROS 2는 UDP 기반의 Reliable multicast
가 구현되었는데, 멀티캐스트 도입으로 DDS Global Space에 등록된 토픽들에 대해 Publish, Subscribe를 할 수 있게 되었다. 및 UDP의 신뢰성 문제 또한 QoS
를 통하여 보완, 해결되었다.
DDS는 동적 검색(Dynamic Discovery)
또한 제공하며, 이 덕분에 응용 프로그램은 어떤 토픽이 지정 도메인 영역에 있고, 어떤 노드가 이를 발신하고 수신하는지 알 수 있어 데이터를 주고받을 노드들의 IP 주소와 포트를 따로 구성할 필요가 없다.
아래 그림은 Subscribe
역할의 listener
과, Publish
역할을 하는 talker
노드를 각각 실행한 것이다. 이 두 노드가 실행되었다는 것은 이미 지정된 DDS
, 즉 RMW(ROS Middleware)
를 사용하고 있는 것이다.
$ ros2 run demo_nodes_cpp listener
$ ros2 run demo_nodes_cpp talker
$ rqt_graph
위에서는 RMW에 대해 아무 설정도 하지 않았기에 기본 RMW인 rmw_fastrtps_cpp
가 사용되었다.
만약 RMW를 변경하려면 ROS 2를 지원하는 RMW 중 하나를 RMW_IMPLEMENTATION
으로 변경한다.
아래 사진에서는 두 노드에 서로 다른 RMW를 사용해도 문제없이 통신이 가능함을 보여준다.
$ export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
$ ros2 run demo_nodes_cpp listener
$ export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
$ ros2 run demo_nodes_cpp talker
한편, ROS 2에서는 UDP 멀티캐스트
로 통신이 이루어지기 때문에, 별도의 설정을 하지 않는다면 동일 네트워크의 모든 노드가 연결되게 된다. DDS의 Domain
을 변경하여 이를 방지할 수 있다.
ROS의 RMW에서는 ROS_DOMAIN_ID
라는 환경변수로 Domain을 변경할 수 있다.
노드간의 DOMAIN_ID가 같다면 통신 가능, 다르다면 불가능함을 보여준다.
$ export ROS_DOMAIN_ID=11
$ ros2 run demo_nodes_cpp listener
$ export ROS_DOMAIN_ID=12
$ ros2 run demo_nodes_cpp talker
DDS의 QoS
의 설정도 가능하다. Reliability
설정을 통하여 데이터 통신 옵션을 선택할 수 있다.
demo_nodes_cpp 패키지는 기본적으로 Realibility 설정이 RELIABLE
로 되어있는데, 이는 TCP와 같이 ACK을 매번 확인하여 손실된 데이터가 있다면 재전송받게 되어 잃어버리는 데이터가 없다.
만약 해당 패키지의 Realibility 설정이 BEST_EFFORT
로 되어있는 노드를 사용하고 싶다면 아래와 같은 명령어를 사용한다. 이는 손실되는 데이터가 있을 수 있지만, 손실된 데이터의 재전송으로 인한 끊김도 나타나지 않는다.
$ ros2 run demo_nodes_cpp listener_best_effort
QoS란 쉽게 말해 데이터 통신 옵션으로, ROS 2에서는 TCP와 UDP 통신 방식을 선택적으로 사용할 수 있다.이를 위해 DDS의 QoS를 도입하였고, 이 덕분에 데이터 전송의 실시간성, 대역폭, 지속성, 중복성과 관련된 옵션 등을 QoS를 통해 바꿀 수 있다.
ROS 2에서는 DDS에서 제공하는 22개의 QoS 중에서 History, Reliability, Durability, Deadline, Lifespan, Liveliness를 지원한다. ROS 2에서는 이 중 대표적으로 Reliability가 사용된다.
History
:데이터를 몇 개나 보관할지 결정하는 옵션Reliability
: 데이터 전송에서 속도를 우선하는지 신뢰성을 우선하는지를 결정하는 옵션Durability
: 데이터를 수신하는 Subscribe가 생성되기 전의 데이터를 사용할 것인지에 대한 옵션Deadline
: 정해진 주기 안에 데이터가 발신, 수신되지 않을 경우 이벤트 함수를 실행하는 옵션Lifespan
: 정해진 주기 안에서 수신되는 데이터만 유효 판정하고, 그렇지 않은 데이터는 삭제하는 옵션Liveliness
: 정해진 주기 안에서 노드 혹은 토픽의 생사를 확인하는 옵션ROS 2의 RMW에서 QoS 설정을 쉽게 사용할 수 있도록 많이 사용하는 QoS 설정을 세트로 표현해둔 것을 RMW QoS Profile
라고 한다.
목적에 따라 Default
, Sensor Data
, Service
, Action Status
, Parameters
, Parameter Events
의 6가지로 구분되며, Relibility
, History
, Depth
, Durability
를 설정한다.
https://github.com/ros2/rmw/blob/foxy/rmw/include/rmw/qos_profiles.h
https://github.com/ros2/rcl/blob/master/rcl_action/include/rcl_action/default_qos.h
이를 실제 코드에서 사용하려면 파이썬 기준으로 다음과 같이 임포트한다.
from rclpy.qos import qos_profile_sensor_data
self.sensor_publisher = self.create_publisher(Int8MultiArray, 'sensor', qos_profile_sensor_data)
사용자가 직접 설정하여 새로운 프로파일을 만들 수도 있다.
from rclpy.qos import QoSDurabilityPolicy
from rclpy.qos import QoSHistoryPolicy
from rclpy.qos import QiSOrifuke
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)
이번 포스팅에서는 ROS 2의 데이터 통신을 위한 미들웨어 DDS와, 데이터 통신 옵션인 QoS에 관하여 다뤘다. ROS 2가 채택한 노드간 통신 기법과 옵션들을 자세히 알 수 있었고 RMW 변경 방법과 QoS 프로파일 변경 방법 또한 알 수 있었다.
다음 포스팅에는 ROS 패키지 중 하나인 Turtlesim
을 설치하고 노드를 실행해본다.
멋져요~