서비스의 개념

ROS2에서 서비스(Service)는 서버-클라이언트 통신 패턴을 따르는 구조로, 요청(request)응답(response)의 흐름을 기반으로 동작한다. 서비스는 특정한 작업을 요청하는 클라이언트와, 그 요청을 처리하고 응답을 반환하는 서버로 이루어져 있다.

서비스 흐름 다이어그램

sequenceDiagram participant Client participant Service_Server Client->>Service_Server: Request Service_Server-->>Client: Response

서비스의 특징

서비스의 사용 예시:

#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)을 제공할 수 있다. 또한, 작업이 진행 중인 상태에서 취소할 수 있는 기능을 제공한다.

액션 흐름 다이어그램

sequenceDiagram participant Client participant Action_Server Client->>Action_Server: Request Action_Server-->>Client: Feedback Action_Server-->>Client: Feedback Action_Server-->>Client: Result

액션의 특징

액션의 사용 예시:

#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 비동기

서비스는 동기적인 통신 방식이다. 클라이언트는 서버에 요청을 보낸 후 응답을 받을 때까지 기다려야 한다. 이 방식은 짧은 시간에 완료되는 작업에 적합하지만, 긴 시간이 걸리는 작업에서는 효율적이지 않을 수 있다.
반면 액션은 비동기적인 통신 방식을 지원한다. 클라이언트는 요청을 보낸 후 작업이 완료되기 전에도 다른 작업을 수행할 수 있으며, 작업이 진행 중인 동안 피드백을 받을 수 있다.

graph TD subgraph Service A[클라이언트] --> B[요청] B --> C[서버] C --> D[응답] D --> A end subgraph Action E[클라이언트] --> F[요청] F --> G[서버] G --> H[피드백] H --> E G --> I[응답] I --> E end

이를 수식으로 표현하면, 서비스의 경우 다음과 같이 클라이언트가 차단되는 동기적인 흐름이 발생한다.

\text{Client\_Request} \xrightarrow{\text{동기}} \text{Server\_Response}

반면에 액션의 경우 비동기적으로 피드백을 제공하며 작업을 완료하는 구조이다.

\text{Client\_Request} \xrightarrow{\text{비동기}} \text{Server\_Feedback} \xrightarrow{\text{비동기}} \text{Server\_Completion}

2. 피드백 제공 여부

서비스는 요청과 응답이 한 번에 이루어지기 때문에 중간에 피드백을 제공하지 않는다. 클라이언트는 요청을 보낸 후 완료된 응답을 받기 전까지 작업 진행 상태를 알 수 없다.
반면, 액션은 작업이 완료되기 전에도 작업의 진행 상태를 클라이언트에게 피드백으로 제공할 수 있다. 이 기능은 긴 시간이 소요되는 작업에서 클라이언트가 현재 진행 상태를 확인할 수 있도록 돕는다.

3. 작업의 취소

서비스는 클라이언트가 요청을 보낸 후에는 취소할 수 없다. 서버는 클라이언트의 요청을 모두 처리한 후에 응답을 반환한다.
반면에 액션은 작업이 진행되는 도중에 클라이언트가 작업을 취소할 수 있는 기능을 제공한다. 이 기능은 클라이언트가 작업을 더 이상 필요로 하지 않거나 다른 우선순위가 발생했을 때 유용하다.

4. 사용 목적

서비스는 상대적으로 빠르게 끝나는 작업에 적합하다. 예를 들어, 두 수의 덧셈과 같은 계산 작업은 서비스로 처리하기에 적합하다. 반면, 액션은 긴 시간이 걸리거나 중간 피드백이 필요한 작업에 적합하다. 예를 들어, 로봇이 목적지로 이동하는 동안 여러 경로를 탐색하고 현재 진행 상황을 계속해서 클라이언트에게 알리는 작업은 액션으로 처리하는 것이 더 적합하다.

5. 상태 관리

서비스는 요청과 응답만을 처리하며, 상태를 관리하지 않는다. 즉, 요청이 완료되면 상태가 유지되지 않는다.
반면, 액션은 요청이 들어온 후 작업의 상태를 관리할 수 있다. 작업이 완료되기 전, 진행 중인 상태를 계속해서 업데이트할 수 있으며, 이 상태는 피드백을 통해 클라이언트에게 전달될 수 있다.

서비스와 액션의 비교

항목 서비스 액션
통신 방식 동기 비동기
작업 시간 짧은 시간의 작업에 적합 긴 시간의 작업에 적합
피드백 없음 작업의 중간 피드백 제공
취소 기능 없음 작업 취소 가능
사용 사례 즉각적인 센서 값 조회, 간단한 명령 로봇의 복잡한 동작, 시간이 많이 소요되는 작업

이와 같이, 서비스와 액션은 각기 다른 특성과 사용 시나리오를 가지고 있으며, 이를 적절히 활용함으로써 ROS2에서의 다양한 통신 요구를 만족시킬 수 있다.

서비스와 액션의 선택 기준

서비스와 액션 중 어느 것을 사용할지 결정할 때는 작업의 성격과 요구 사항을 고려해야 한다. 만약 작업이 상대적으로 짧은 시간 내에 완료되고, 클라이언트가 응답을 받을 때까지 대기하는 방식이 적합하다면 서비스가 더 적절하다. 그러나 작업이 긴 시간이 걸리거나 중간에 상태를 확인할 필요가 있거나, 작업을 중도에 취소할 가능성이 있다면 액션이 더 적합할 것이다.

사례 비교