Ubuntu ROS 실습(8)

zeusqoi·4일 전

개인공부

목록 보기
27/42

이번 실습에서는 ROS 2에서 DDS를 실제로 어떻게 사용하는지 확인해 보았다.

앞서 ROS 2의 통신 미들웨어로 DDS를 사용한다는 내용을 정리했는데, 이번에는 직접 RMW 구현체를 변경해 보고, 노드 간 통신을 확인하고, ROS Domain ID와 QoS 설정까지 실습해 보았다.


1. RMW 구현체 확인

ROS 2에서는 애플리케이션이 DDS를 직접 사용하는 것이 아니라, 중간에 RMW(ROS Middleware) 계층을 사용한다.

전체적인 구조를 간단하게 나타내면 다음과 같다.

ROS 2 Node
    ↓
rclcpp / rclpy
    ↓
RMW
    ↓
DDS 구현체
    ↓
네트워크

따라서 같은 ROS 2 프로그램을 실행하더라도 어떤 RMW 구현체를 선택하느냐에 따라 실제 통신을 담당하는 DDS 구현체가 달라질 수 있다.

이번 실습에서는 먼저 rmw_cyclonedds_cpp를 사용해 보았다.


2. Cyclone DDS 사용

먼저 ROS 2 환경을 불러왔다.

source /opt/ros/humble/setup.zsh

그리고 RMW 구현체를 Cyclone DDS로 설정했다.

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

현재 설정된 값을 확인하면 다음과 같이 나온다.

echo $RMW_IMPLEMENTATION
rmw_cyclonedds_cpp

Cyclone DDS 실행 중 발생한 문제

처음 listener를 실행했을 때는 다음과 같은 오류가 발생했다.

RMW implementation not installed

구체적으로는 librmw_cyclonedds_cpp.so 공유 라이브러리를 찾지 못한다는 내용이었다.

즉, 환경 변수로 Cyclone DDS를 사용하도록 지정했지만 실제로 해당 RMW 패키지가 설치되어 있지 않은 상태였다.

이후 필요한 패키지를 설치하고 다시 실행했다.

설치 과정에서는 다음과 같은 패키지들이 설정되는 것을 확인할 수 있었다.

ros-humble-cyclonedds
ros-humble-rmw-cyclonedds-cpp

설치가 완료된 후 다시 환경을 불러오고,

source /opt/ros/humble/setup.zsh
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

다시 listener를 실행했다.

ros2 run demo_nodes_cpp listener

정상적으로 실행되면서 다음과 같이 메시지를 수신했다.

[listener]: I heard: [Hello World: 1]
[listener]: I heard: [Hello World: 2]
[listener]: I heard: [Hello World: 3]

따라서 Cyclone DDS를 사용하는 환경에서도 ROS 2 노드 간 통신이 정상적으로 이루어지는 것을 확인할 수 있었다.


3. rqt_graph로 노드와 토픽 확인

다음으로 ROS 2에서 실제 노드와 토픽이 어떻게 연결되어 있는지 확인하기 위해 rqt_graph를 실행했다.

rqt_graph

실행 결과 다음과 같은 그래프가 나타났다.

현재 실행 중인 노드는 다음과 같이 구성되어 있다.

/talker
   │
   │ /chatter
   ↓
/listener

/talker 노드는 /chatter 토픽으로 메시지를 발행하고, /listener 노드는 해당 토픽을 구독한다.

즉,

Publisher
   ↓
/chatter
   ↓
Subscriber

구조로 통신하고 있는 것이다.

앞서 DDS의 Dynamic Discovery에 대해 공부했는데, rqt_graph를 통해 실제 실행 중인 ROS 2 시스템에서 노드와 토픽이 연결되어 있는 모습을 직접 확인할 수 있었다.


4. Fast DDS로 RMW 변경

이번에는 RMW 구현체를 Cyclone DDS에서 다른 DDS 구현체로 변경해 보았다.

ROS 2에서는 하나의 DDS 구현체만 사용하는 것이 아니라 여러 RMW 구현체를 선택해서 사용할 수 있다.

이번에는 Fast DDS에 해당하는 다음 RMW 구현체를 사용했다.

export RMW_IMPLEMENTATION=rmw_fastrtps_cpp

현재 설정을 확인하면,

echo $RMW_IMPLEMENTATION

다음과 같이 출력된다.

rmw_fastrtps_cpp

이후 다시 talker를 실행했다.

ros2 run demo_nodes_cpp talker

정상적으로 다음과 같은 메시지가 출력되었다.

[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [talker]: Publishing: 'Hello World: 2'
[INFO] [talker]: Publishing: 'Hello World: 3'

Cyclone DDS를 사용할 때와 마찬가지로 talker가 메시지를 발행하는 것을 확인할 수 있었다.

이를 통해 ROS 2에서는 애플리케이션 코드를 변경하지 않고도 RMW 설정을 통해 사용하는 DDS 구현체를 변경할 수 있다는 것을 확인했다.


5. ROS Domain ID 변경

다음으로 ROS_DOMAIN_ID를 변경해 보았다.

ROS 2에서는 같은 네트워크에 여러 ROS 시스템이 존재할 수 있기 때문에, 서로 다른 시스템의 노드가 무조건 모두 통신하면 문제가 발생할 수 있다.

이를 구분하기 위해 ROS 2에서는 Domain ID를 사용할 수 있다.

이번 실습에서는 다음과 같이 Domain ID를 설정했다.

export ROS_DOMAIN_ID=12

그리고 설정된 값을 확인했다.

echo $ROS_DOMAIN_ID

결과는 다음과 같다.

12

이후 동일한 Domain ID 환경에서 listener를 실행했다.

ros2 run demo_nodes_cpp listener

talker에서 발행한 메시지를 listener가 정상적으로 수신하는 것을 확인할 수 있었다.

[listener]: I heard: [Hello World: 35]
[listener]: I heard: [Hello World: 36]
[listener]: I heard: [Hello World: 37]

즉, talker와 listener가 동일한 ROS Domain에서 통신하고 있는 것이다.

ROS_DOMAIN_ID를 사용하는 이유

간단하게 생각하면 Domain ID는 ROS 2 시스템의 통신 영역을 구분하는 역할을 한다.

예를 들어,

Domain 12

/talker  ─────→  /listener

처럼 같은 Domain에 속한 노드들은 서로 검색하고 통신할 수 있다.

반대로 서로 다른 Domain에 속한 노드들은 기본적으로 같은 ROS 시스템처럼 통신하지 않는다.

따라서 하나의 네트워크에서 여러 ROS 2 시스템을 운용할 때 서로 다른 시스템을 분리하는 데 활용할 수 있다.


6. QoS와 BEST_EFFORT 실습

마지막으로 QoS 설정을 확인했다.

ROS 2의 QoS(Quality of Service)는 데이터를 어떤 방식으로 전달할 것인지 설정할 수 있는 기능이다.

그중 이번 실습에서는 Reliability와 관련된 설정을 확인했다.

Reliability에는 대표적으로 다음 두 가지가 있다.

RELIABLE
BEST_EFFORT

RELIABLE

RELIABLE은 메시지가 안정적으로 전달되도록 하는 방식이다.

네트워크 상황 등에 따라 메시지 전달에 문제가 발생했을 때 재전송 등을 통해 전달을 보장하는 방향으로 동작한다.

BEST_EFFORT

BEST_EFFORT는 메시지를 최대한 빠르게 전달하는 것을 우선한다.

따라서 일부 메시지가 손실되더라도 다시 전달을 보장하지 않는다.

센서 데이터처럼 최신 데이터가 중요하고 일부 데이터가 손실되더라도 계속 새로운 데이터가 들어오는 상황에서는 BEST_EFFORT가 사용될 수 있다.

이번 실습에서는 listener_best_effort를 실행했다.

ros2 run demo_nodes_cpp listener_best_effort

그리고 talker에서 계속 메시지를 발행하도록 실행했다.

ros2 run demo_nodes_cpp talker

실행 결과 listener에서 다음과 같이 메시지를 수신하는 것을 확인할 수 있었다.

[listener]: I heard: [Hello World: 39]
[listener]: I heard: [Hello World: 40]
[listener]: I heard: [Hello World: 41]
...
[listener]: I heard: [Hello World: 73]

이번 실습에서는 실제 네트워크 패킷 손실 상황을 만들어 BEST_EFFORT와 RELIABLE의 차이를 직접 비교한 것은 아니지만, QoS 설정에 따라 Subscriber의 통신 특성이 달라질 수 있다는 것을 확인했다.


마무리

이번 실습에서는 앞에서 개념으로만 공부했던 DDS와 RMW를 실제 ROS 2 환경에서 직접 확인해 보았다.

이번 실습을 전체적으로 정리하면 ROS 2의 통신 구조는 다음과 같이 볼 수 있다.

ROS 2 Node
    ↓
rclcpp
    ↓
RMW
    ↓
DDS 구현체
    ↓
네트워크

ROS 2에서는 RMW 계층을 통해 실제 사용하는 DDS 구현체를 선택할 수 있으며, 이번 실습에서는 Cyclone DDS와 Fast DDS를 각각 사용해 보았다.

ROS 2
  │
  ├── RMW Cyclone DDS
  │
  └── RMW Fast DDS

실제로 환경 변수만 변경하여 다음과 같이 RMW 구현체를 선택할 수 있었다.

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

또는

export RMW_IMPLEMENTATION=rmw_fastrtps_cpp

또한 ROS_DOMAIN_ID를 설정하여 ROS 2의 통신 영역을 지정할 수 있었고,

export ROS_DOMAIN_ID=12

QoS에서는 Reliability와 같은 통신 특성을 설정할 수 있다는 것도 확인했다.

0개의 댓글