눈부신 햇빛, 싱그러운 바람, 찰랑거리는 파도소리
우리 인간은 다양한 감각들을 가지고 있다. 이 감각들을 인지하고 느끼기 위해서는 셀 수 없을 정도의 감각기관들을 통해 신호들이 전달된다.
만약 로봇이 현실 세계에서 우리 인간과 함께 밀접하게 활동한다고 생각해보자. 얼마나 많은 센서를 달게될까?
물론 아직 로봇이나 자율주행차는 인간의 감각 기관 개수에 비해 현저히 적은 개수의 센서들만 장착할 것이다. 하지만 그렇다고 미래에도 로봇이 여전히 적은 개수의 센서만 달 것이라고 단정할 수 있을까?
ROS가 뭔지 보러 왔는데 갑자기 이게 무슨소리일까?
바로 이러한 문제를 해결하기 위해 ROS가 나왔기 때문이다.
ROS란?
15년도 더 전에 로봇에 많은 양의 센서가 있지 않더라도 각 센서의 종류와 다양성 때문에 많은 로봇 소프트웨어 개발자들이 고통을 받았다.
이런 문제를 해결하기 위해 센서 단을 아주 신경쓰지 않고도 개발할 수 있도록 도와주는 도구가 탄생했다.
그게 바로 ROS다.
ROS는 'Robot Operating System' 의 약자인데 이름처럼 OS(운영체제)가 아니다.
로봇 소프트웨어 개발에 사용하는 프레임워크이고 라이브러리와 같은 도구이다.
ROS 왜 쓸까?
ROS가 만들어진 배경을 위에서 설명했지만 왜 사용하는지 좀 더 구체적으로 설명하고자 한다.
나는 ROS를 사용해보면서 이것이 객체 간의 메시지 통신 구조를 제공해주는 객체지향 프레임워크라고 이해했다.
객체지향 프레임워크
ROS에는 노드(Node)라는 객체 단위가 있다.(좀 더 자세히는 밑에서 설명하겠다.) 또한, 노드 간의 메시지 통신 인터페이스를 제공해준다.
이를 이용하면 복잡한 로봇 시스템을 노드라는 객체들이 협력하는 세상으로 단순화 시킬 수 있는 것이다. 그러면 수많은 센서들이 있어도 노드로 추상화를 시켜 복잡도를 낮출 수 있다.
예를 들어, 로봇 전방에 달린 레이더에서 실시간으로 데이터가 나오는데 기존에는 레이더에서 데이터를 수집하는 코드를 직접 보고 다뤄야 한다.
하지만 ROS를 이용하면 노드라는 객체로 추상화 시켜서 다른 노드로 그 데이터들을 전달하기만 하면 된다.
세부적으로 센서를 다루는 부분을 고려하지 않을 수 있으므로 개발 속도 향상과 유지 보수 개선에 도움을 준다.
객체지향적인 메시지 통신 구조
위에서 ROS의 핵심 개념에 대해 설명했지만 노드가 무엇이고 어떠한 인터페이스를 제공해주는지 간략하게나마 알아보자.
노드
노드(Node)는 특정한 목표를 수행하는 객체이자 프로세스이다.
(JS를 써본 사람들이라면 Node.js와 헷갈릴 수 있으니 유의하자.)
노드가 수행하는 특정 목표는 예를 들어 바퀴의 모터를 제어, 카메라 영상 데이터 처리, 레이더 데이터를 수집하고 전달하는 것 등이 될 수 있다.
각 노드가 하는 일의 크기는 정해진게 아니라서 개발자의 구현에 달려있다. 하나의 노드가 하는 일이 너무 많아져 내부 복잡도가 높아지지 않도록 유의해야하고 또 노드를 너무 세분화하여 시스템 전체적인 복잡도가 높아지지 않도록 유의해야한다.
이런 복잡도를 적절하게 잘 관리할 줄 아는 것이 잘하는 개발자의 실력이 아닌가 싶다.
토픽
토픽(Topic)은 한마디로 비유하자면 구독 시스템이다.
나는 ROS를 쓰면서 이 개념이 가장 신기하고 흥미로웠다.
이 구독 시스템에서는 발행자(Publisher)와 구독자(Subscriber)가 있다. 어떤 노드든 각 역할을 수행할 수 있다.
발행자가 특정 토픽에 센서 데이터를 담은 메시지를 발행하면 그 데이터가 필요한 어떠한 노드든 구독자가 되어 그 토픽을 구독해서 메시지를 읽을 수 있다.
특정한 센서에는 계속해서 데이터가 쏟아져 나오는데 그 센서를 담당하는 노드가 매번 지정된 노드들에게 일일이 보내기는 힘들지 않겠는가. ROS는 이 부분을 추상화 시켜서 그냥 데이터를 한 곳에다가 놓을테니 필요한 노드들은 알아서 가져가는 식으로 기능을 제공해줬다.
서비스
서비스(Service)는 노드에서 제공하는 함수 혹은 메서드와 같다. 노드 간에 요청과 응답이 이루어진다.
마치 C++에서 클래스의 멤버함수와 비슷하다. 여기서는 ROS가 제공하는 구조대로 사용해야하는게 다르지만 말이다.
특정 서비스에 대해서 요청자 노드가 응답자 노드에게 서비스를 요청하면 응답자 노드는 그 기능을 수행하고 요청자 노드에게 응답을 보내주는 식이다.
사실 정확하게 말하면 서비스에 대해 각 노드별로 Service Client와 Server가 있어서 수행한다. 아래 이미지를 보면 이해가 수월할 것이다.
액션
액션(Action)은 크게 보면 모니터링이 가능한 하나의 서비스이다. 토픽과 서비스를 조합해서 제공한다.
토픽과 서비스에 대해 이해가지 않았다면 머리만 복잡해질 수 있으므로 건너 뛰어도 된다.
액션에서는 요청자 노드가 Goal을 요청하면 응답자 노드가 그 액션을 수행하기 시작한다.
액션을 수행하는 동안 관련 데이터를 보여주는 Feedback 토픽을 계속해서 발행한다. 이를 통해 요청자 노드는 물론 다른 노드도 응답자 노드가 어떠한 상태인지 모니터링할 수 있다.
응답자 노드가 액션 수행을 끝냈다면 결과 상태에 따라 Result로 요청자 노드에게 응답한다.
여기서 액션을 관점으로 Goal과 Result를 각각 요청과 응답으로 썼는데 정확하게 말하면 Goal과 Result에 대해 각각 서비스를 요청한 것이다. 아래 그림을 보면 이해가 쉬울 것이다.
ROS2 얘는 또 뭐야?
여기까지 ROS의 객체지향적인 개념과 그에 필요한 인터페이스들에 대해서 설명해보았다.
그런데 사실 ROS는 그냥 ROS가 있고 ROS2도 있다.
처음 구현하는 많은 프로그램들이 그렇듯 ROS도 초기 설계에서의 한계를 피할 수는 없었다.
ROS가 인기가 많아지자 산업계에서도 활용을 했다. 하지만 ROS가 초기에 설계할 때 고려하지 못한 것들이 문제가 되었다. (예를들면 표준화)
ROS2는 이를 개선하고자 산업계에서의 확장성을 고려하여 다시 설계하여 구현한 것이다.
기존 ROS의 개념은 유지하고 패키지나 안전성들을 개선했기 때문에 위에서 설명한 개념이 ROS2에서 달라지는 것이 없다.
위에서 설명한 것들은 ROS 생태계 전체적으로 통용되는 개념이라는 것으로 이해해주길 바란다.
참고로 앞으로 기존 ROS는 새로운 버전이 나오지 않고 현재 마지막 버전이 2025년 까지 지원된다고 한다.
ROS2는 계속해서 새로운 버전이 나올 것이므로 (보통 새로운 Ubuntu 버전에 맞춰서 나옴) 관심있는 분들이라면 미래를 대비해서 ROS2도 알아보자.
마무리
이 글에서 객체지향 구조와 인터페이스를 중심으로 ROS 개념에 대해서 설명을 했다.
특정 로봇 뿐만 아니라 드론, 이동식 플랫폼 등 다양한 센서가 결합된 기기라면 ROS를 활용할 수 있다.
ROS의 특징에 대해서 흥미가 갔다면 실제 로봇이 없어도 튜토리얼에서 귀여운(?) 거북이를 통해서 배워볼 수 있으므로 진행해보자.
이후에 rviz와 같은 시뮬레이션 세상에서도 구현한 로봇 소프트웨어를 확인할 수도 있다.