1261.28 ROS2 서비스(Service) 통신의 원리
1. 서비스 통신의 정의와 개념
ROS2에서 서비스(Service)는 요청-응답(Request-Response) 패턴을 구현하는 동기적 양방향 통신 메커니즘이다. 서비스 통신에서는 클라이언트(Client)가 요청(Request) 메시지를 서버(Server)에 전달하고, 서버가 해당 요청을 처리한 후 응답(Response) 메시지를 클라이언트에 반환한다. 이 통신 방식은 원격 프로시저 호출(Remote Procedure Call, RPC)의 개념을 로봇 미들웨어 환경에 적용한 것으로, 일회성 연산 요청, 매개변수 조회, 시스템 구성 변경 등 명확한 입출력 관계를 필요로 하는 상호작용에 적합하다.
토픽 통신이 발행자에서 구독자로의 단방향 데이터 스트림을 형성하는 것과 대조적으로, 서비스 통신은 클라이언트와 서버 간의 명시적인 요청-응답 쌍(Pair)을 통해 양방향 데이터 교환을 수행한다.
2. 서비스 인터페이스의 구조
2.1 .srv 파일의 형식
ROS2 서비스의 인터페이스는 .srv 파일을 통해 정의된다. .srv 파일은 세 개의 하이픈(---)을 구분자로 하여 요청 부분과 응답 부분으로 나뉜다.
# 요청(Request) 필드
int64 a
int64 b
---
# 응답(Response) 필드
int64 sum
위 예시에서 클라이언트는 두 개의 정수를 요청 메시지로 전달하고, 서버는 그 합계를 응답 메시지로 반환한다. .srv 파일은 빌드 과정에서 rosidl 도구 체인에 의해 언어별 소스 코드로 자동 변환되며, C++에서는 <패키지명>::srv::<서비스명>::Request와 <패키지명>::srv::<서비스명>::Response 구조체가, Python에서는 동일한 명칭의 클래스가 생성된다.
2.2 메시지 타입과 서비스 타입의 관계
서비스 타입은 요청 메시지 타입과 응답 메시지 타입의 쌍으로 구성되며, 이 두 메시지 타입은 하나의 서비스 정의 내에서 결합된다. ROS2의 기본 서비스 타입으로는 std_srvs/srv/Trigger(빈 요청, 성공 여부와 메시지 반환), std_srvs/srv/SetBool(부울 값 설정과 결과 반환) 등이 제공된다.
3. 서비스 통신의 동작 원리
3.1 DDS 기반 구현 메커니즘
ROS2의 서비스 통신은 DDS(Data Distribution Service) 미들웨어의 토픽 통신을 기반으로 구현된다. 하나의 서비스는 내부적으로 두 개의 DDS 토픽을 사용한다.
- 요청 토픽(Request Topic): 클라이언트에서 서버로 요청 메시지를 전달하는 토픽
- 응답 토픽(Response Topic): 서버에서 클라이언트로 응답 메시지를 반환하는 토픽
이 두 토픽의 이름은 서비스 이름으로부터 자동으로 생성되며, DDS의 RELIABLE 신뢰성 정책과 VOLATILE 내구성 정책이 기본으로 적용된다. 요청과 응답의 대응 관계는 각 메시지에 포함된 고유 식별자(Sequence Number 및 Client GUID)를 통해 유지된다.
3.2 서비스 검색과 연결 수립
서비스 서버가 생성되면 DDS 검색(Discovery) 메커니즘을 통해 해당 서비스의 가용성이 네트워크 상의 참여자에게 통지된다. 서비스 클라이언트는 service_is_ready() 메서드를 통해 서버의 존재 여부를 확인할 수 있으며, wait_for_service() 메서드를 통해 서버가 활성화될 때까지 대기할 수 있다.
3.3 요청-응답 흐름
서비스 통신의 요청-응답 흐름은 다음과 같은 단계를 거친다.
- 클라이언트가 요청 메시지를 생성하고 서비스 호출을 수행한다.
- 요청 메시지가 요청 토픽을 통해 서버의 DDS
DataReader에 전달된다. - 서버의 실행자(Executor)가 요청 수신을 감지하고, 등록된 콜백 함수를 호출한다.
- 서버의 콜백 함수가 요청을 처리하고 응답 메시지를 생성한다.
- 응답 메시지가 응답 토픽을 통해 클라이언트의 DDS
DataReader에 전달된다. - 클라이언트가 응답 메시지를 수신하고, 결과를 처리한다.
4. 서비스 서버의 기본 구조
rclcpp에서 서비스 서버는 Node::create_service<>() 템플릿 메서드를 통해 생성된다.
auto service = this->create_service<example_interfaces::srv::AddTwoInts>(
"add_two_ints",
std::bind(&ClassName::handle_service, this,
std::placeholders::_1, std::placeholders::_2)
);
서비스 콜백 함수는 요청 객체와 응답 객체를 매개변수로 전달받으며, 응답 객체의 필드를 채워 넣는 방식으로 결과를 반환한다.
void handle_service(
const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{
response->sum = request->a + request->b;
}
5. 서비스 클라이언트의 기본 구조
서비스 클라이언트는 Node::create_client<>() 메서드를 통해 생성되며, async_send_request() 메서드를 통해 비동기적으로 요청을 전달한다.
auto client = this->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");
auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
request->a = 5;
request->b = 3;
auto future = client->async_send_request(request);
반환되는 std::shared_future 객체를 통해 응답의 도착을 대기하거나, 콜백 함수를 등록하여 비동기적으로 응답을 처리할 수 있다.
6. 서비스 통신의 특성
6.1 일대일 통신 구조
서비스 통신은 본질적으로 하나의 클라이언트 요청에 대해 하나의 서버가 응답하는 일대일(One-to-One) 구조를 따른다. 동일한 서비스 이름으로 복수의 서버가 등록된 경우, 클라이언트의 요청이 어떤 서버에 전달되는지는 DDS 구현체의 동작에 의존하며, 이는 비결정적(Non-deterministic) 동작을 유발할 수 있다. 따라서, 하나의 서비스 이름에 대해 하나의 서버만 등록하는 것이 설계 원칙이다.
6.2 상태 비보존(Stateless) 특성
서비스 호출은 각 요청이 독립적으로 처리되는 상태 비보존(Stateless) 특성을 기본으로 한다. 서버는 이전 요청의 이력이나 클라이언트의 정체성에 의존하지 않고, 수신된 요청 자체만으로 처리를 수행한다. 다만, 서버 구현 내부에서 상태를 유지하는 것은 개발자의 재량에 따라 가능하다.
6.3 시간적 결합
토픽 통신과 달리 서비스 통신은 클라이언트와 서버 간의 시간적 결합(Temporal Coupling)이 존재한다. 서버가 비활성 상태이거나 네트워크에 존재하지 않는 경우, 클라이언트의 요청은 처리되지 못하며 응답을 수신할 수 없다. 이러한 시간적 의존성은 서비스 통신의 설계 시 반드시 고려하여야 하는 제약 사항이다.
7. 서비스 통신의 적용 영역
서비스 통신은 다음과 같은 사용 사례에 적합하다.
- 매개변수 조회 및 설정: 노드의 구성 매개변수를 외부에서 조회하거나 변경하는 경우
- 일회성 연산 요청: 좌표 변환 연산, 경로 계산, 지도 데이터 요청 등 단발성 연산의 수행
- 시스템 상태 변경: 노드의 활성화·비활성화, 센서의 보정(Calibration) 실행 등 시스템 구성의 변경
- 진단 및 모니터링: 노드의 건강 상태(Health Status) 확인, 통계 정보 조회
이러한 사용 사례는 공통적으로 명확한 요청-응답 관계가 존재하며, 응답의 도착이 후속 처리의 전제 조건이 되는 상호작용이다.
8. 참고 문헌
- Open Robotics, “ROS 2 Documentation: Humble Hawksbill,” https://docs.ros.org/en/humble/, 2022.
- OMG, “Data Distribution Service (DDS) Specification, Version 1.4,” Object Management Group, 2015.
- Birrell, A. D., Nelson, B. J., “Implementing Remote Procedure Calls,” ACM Transactions on Computer Systems, Vol. 2, No. 1, pp. 39–59, 1984.
- Maruyama, Y., Kato, S., Azumi, T., “Exploring the Performance of ROS2,” Proceedings of the 13th International Conference on Embedded Software (EMSOFT), 2016.