서비스의 개념
ROS2에서 서비스(Service)는 서버-클라이언트 통신 패턴을 따르는 구조로, 요청(request)과 응답(response)의 흐름을 기반으로 동작한다. 서비스는 특정한 작업을 요청하는 클라이언트와, 그 요청을 처리하고 응답을 반환하는 서버로 이루어져 있다.
서비스 흐름 다이어그램
서비스의 특징
- 단일 요청/응답 구조: 서비스는 요청이 들어오면 서버가 요청을 처리하고 그에 대한 응답을 반환하는 방식으로 동작한다. 이때 클라이언트는 응답을 받을 때까지 대기할 수 있으며, 서버에서 응답을 줄 때까지 클라이언트는 다른 작업을 수행하지 못할 수 있다.
- 동기적 통신: 서비스 호출은 일반적으로 동기적이며, 이는 클라이언트가 응답을 기다리면서 요청을 처리하는 동안 차단(blocking)될 수 있음을 의미한다.
서비스의 사용 예시:
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
void add(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;
}
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = rclcpp::Node::make_shared("add_two_ints_server");
auto service = node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add);
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
이 코드에서 서비스 서버는 두 정수를 더한 값을 클라이언트에게 반환하는 간단한 작업을 수행한다. 클라이언트는 해당 서비스에 요청을 보내고, 서버는 요청을 처리한 후 응답을 클라이언트에게 보내는 구조이다.
액션의 개념
액션(Action)은 서비스와 유사하게 클라이언트-서버 통신을 기반으로 하지만, 비동기 작업을 처리하는 데 더 적합하다. 액션은 긴 시간이 소요될 수 있는 작업을 처리하기 위해 설계되었으며, 중간에 피드백(feedback)을 제공할 수 있다. 또한, 작업이 진행 중인 상태에서 취소할 수 있는 기능을 제공한다.
액션 흐름 다이어그램
액션의 특징
- 비동기적 통신: 액션은 비동기적으로 동작하며, 클라이언트는 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있다.
- 피드백 제공: 액션은 작업이 진행 중인 동안 클라이언트에게 피드백을 제공할 수 있다. 이는 클라이언트가 현재 작업 상태를 실시간으로 확인할 수 있도록 해준다.
- 취소 가능성: 클라이언트는 작업을 요청한 후 작업이 끝나기 전에 해당 작업을 취소할 수 있다. 이 기능은 작업이 오래 걸리거나 더 이상 필요하지 않을 때 유용하다.
액션의 사용 예시:
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/action/fibonacci.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
class FibonacciActionServer : public rclcpp::Node
{
public:
using Fibonacci = example_interfaces::action::Fibonacci;
using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;
explicit FibonacciActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
: Node("fibonacci_action_server", options)
{
using namespace std::placeholders;
this->action_server_ = rclcpp_action::create_server<Fibonacci>(
this,
"fibonacci",
std::bind(&FibonacciActionServer::handle_goal, this, _1, _2),
std::bind(&FibonacciActionServer::handle_cancel, this, _1),
std::bind(&FibonacciActionServer::handle_accepted, this, _1));
}
private:
rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;
rclcpp_action::GoalResponse handle_goal(
const rclcpp_action::GoalUUID & uuid,
std::shared_ptr<const Fibonacci::Goal> goal)
{
RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order);
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}
rclcpp_action::CancelResponse handle_cancel(
const std::shared_ptr<GoalHandleFibonacci> goal_handle)
{
RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
return rclcpp_action::CancelResponse::ACCEPT;
}
void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
{
using namespace std::placeholders;
std::thread{std::bind(&FibonacciActionServer::execute, this, _1), goal_handle}.detach();
}
void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
{
RCLCPP_INFO(this->get_logger(), "Executing goal");
// 실제 Fibonacci 계산 수행
}
};
이 코드는 피보나치 수열을 계산하는 액션 서버를 구현한 예시이다. 작업이 진행되는 동안 피드백을 제공하고, 클라이언트가 필요할 때 작업을 취소할 수 있다.
서비스와 액션의 차이점
1. 동기 vs 비동기
서비스는 동기적인 통신 방식이다. 클라이언트는 서버에 요청을 보낸 후 응답을 받을 때까지 기다려야 한다. 이 방식은 짧은 시간에 완료되는 작업에 적합하지만, 긴 시간이 걸리는 작업에서는 효율적이지 않을 수 있다.
반면 액션은 비동기적인 통신 방식을 지원한다. 클라이언트는 요청을 보낸 후 작업이 완료되기 전에도 다른 작업을 수행할 수 있으며, 작업이 진행 중인 동안 피드백을 받을 수 있다.
이를 수식으로 표현하면, 서비스의 경우 다음과 같이 클라이언트가 차단되는 동기적인 흐름이 발생한다.
반면에 액션의 경우 비동기적으로 피드백을 제공하며 작업을 완료하는 구조이다.
2. 피드백 제공 여부
서비스는 요청과 응답이 한 번에 이루어지기 때문에 중간에 피드백을 제공하지 않는다. 클라이언트는 요청을 보낸 후 완료된 응답을 받기 전까지 작업 진행 상태를 알 수 없다.
반면, 액션은 작업이 완료되기 전에도 작업의 진행 상태를 클라이언트에게 피드백으로 제공할 수 있다. 이 기능은 긴 시간이 소요되는 작업에서 클라이언트가 현재 진행 상태를 확인할 수 있도록 돕는다.
3. 작업의 취소
서비스는 클라이언트가 요청을 보낸 후에는 취소할 수 없다. 서버는 클라이언트의 요청을 모두 처리한 후에 응답을 반환한다.
반면에 액션은 작업이 진행되는 도중에 클라이언트가 작업을 취소할 수 있는 기능을 제공한다. 이 기능은 클라이언트가 작업을 더 이상 필요로 하지 않거나 다른 우선순위가 발생했을 때 유용하다.
4. 사용 목적
서비스는 상대적으로 빠르게 끝나는 작업에 적합하다. 예를 들어, 두 수의 덧셈과 같은 계산 작업은 서비스로 처리하기에 적합하다. 반면, 액션은 긴 시간이 걸리거나 중간 피드백이 필요한 작업에 적합하다. 예를 들어, 로봇이 목적지로 이동하는 동안 여러 경로를 탐색하고 현재 진행 상황을 계속해서 클라이언트에게 알리는 작업은 액션으로 처리하는 것이 더 적합하다.
5. 상태 관리
서비스는 요청과 응답만을 처리하며, 상태를 관리하지 않는다. 즉, 요청이 완료되면 상태가 유지되지 않는다.
반면, 액션은 요청이 들어온 후 작업의 상태를 관리할 수 있다. 작업이 완료되기 전, 진행 중인 상태를 계속해서 업데이트할 수 있으며, 이 상태는 피드백을 통해 클라이언트에게 전달될 수 있다.
서비스와 액션의 비교
항목 | 서비스 | 액션 |
---|---|---|
통신 방식 | 동기 | 비동기 |
작업 시간 | 짧은 시간의 작업에 적합 | 긴 시간의 작업에 적합 |
피드백 | 없음 | 작업의 중간 피드백 제공 |
취소 기능 | 없음 | 작업 취소 가능 |
사용 사례 | 즉각적인 센서 값 조회, 간단한 명령 | 로봇의 복잡한 동작, 시간이 많이 소요되는 작업 |
이와 같이, 서비스와 액션은 각기 다른 특성과 사용 시나리오를 가지고 있으며, 이를 적절히 활용함으로써 ROS2에서의 다양한 통신 요구를 만족시킬 수 있다.
서비스와 액션의 선택 기준
서비스와 액션 중 어느 것을 사용할지 결정할 때는 작업의 성격과 요구 사항을 고려해야 한다. 만약 작업이 상대적으로 짧은 시간 내에 완료되고, 클라이언트가 응답을 받을 때까지 대기하는 방식이 적합하다면 서비스가 더 적절하다. 그러나 작업이 긴 시간이 걸리거나 중간에 상태를 확인할 필요가 있거나, 작업을 중도에 취소할 가능성이 있다면 액션이 더 적합할 것이다.
사례 비교
- 서비스 예시: 로봇의 특정 센서 값을 요청하는 작업은 서비스로 처리하는 것이 적합하다. 요청에 대한 응답은 빠르게 완료되며, 중간에 피드백을 제공할 필요가 없다.
- 액션 예시: 로봇의 경로 계획이나 이동 작업은 액션으로 처리하는 것이 적합하다. 이동 중에 현재 위치나 진행 상태를 피드백으로 제공할 수 있고, 중간에 경로를 변경하거나 취소할 수 있는 유연성이 필요하다.