ROS2 액션 서버와 클라이언트 간의 통신에서, 액션의 상태 관리와 피드백 처리는 중요한 부분이다. 액션의 상태 관리는 클라이언트가 액션의 진행 상태를 추적하고, 결과를 받을 수 있도록 하기 위한 메커니즘을 제공한다. 피드백 처리는 액션이 완료되기 전까지 중간 진행 상황을 클라이언트에게 전달하는 기능이다.

상태 관리

액션의 상태 관리는 상태 머신으로 구현되며, 액션이 진행 중 어떤 상태에 있는지를 나타낸다. 일반적으로 액션은 다음과 같은 상태를 갖는다:

상태 전이

액션의 상태 전이는 서버에서 클라이언트로 전달되며, 클라이언트는 이를 수신하여 액션의 현재 상태를 이해할 수 있다. 상태 전이는 다음과 같은 흐름으로 이루어진다:

stateDiagram-v2 state [*] --> ACCEPTED : 액션 요청 수락 ACCEPTED --> EXECUTING : 액션 실행 EXECUTING --> SUCCEEDED : 액션 성공 EXECUTING --> ABORTED : 액션 실패 EXECUTING --> CANCELING : 취소 요청 CANCELING --> CANCELED : 취소 성공 CANCELING --> EXECUTING : 취소 실패

이 상태 전이는 액션 클라이언트가 액션 서버에 상태 업데이트를 요청할 때마다 발생하며, 클라이언트는 액션의 진행 상태를 실시간으로 추적할 수 있다.

상태 관리 구현

ROS2에서 액션의 상태 관리는 GoalHandle을 통해 이루어진다. GoalHandle은 액션 서버가 클라이언트로부터 받은 요청을 처리하는 동안 액션의 상태를 추적하는 역할을 한다.

rclcpp_action::GoalHandle<MyAction>::SharedPtr goal_handle;
goal_handle->succeed();
goal_handle->abort();
goal_handle->cancel();

GoalHandle은 위와 같은 메서드를 통해 상태 전이를 제어할 수 있으며, 각각의 메서드는 액션의 상태를 SUCCEEDED, ABORTED, CANCELING으로 전환한다.

피드백 처리

피드백은 액션 서버가 액션이 실행 중일 때 클라이언트에게 중간 진행 상황을 전달하는 기능이다. 피드백은 비동기적으로 전달되며, 클라이언트는 이를 수신하여 액션이 얼마나 진행되었는지 파악할 수 있다.

피드백 메시지는 액션 정의에서 미리 지정된 형태로 전달된다. 예를 들어, 진행률을 전달하는 피드백 메시지를 정의하려면, 다음과 같이 액션 정의 파일에서 피드백을 명시한다:

# 액션 정의 파일 (MyAction.action)
int32 progress
---
bool result
---
int32 feedback

이 정의에 따라, 피드백 메시지는 progress라는 변수로 클라이언트에게 전달되며, 서버에서는 피드백을 주기적으로 전송할 수 있다.

auto feedback = std::make_shared<MyAction::Feedback>();
feedback->progress = 50;  // 50% 진행
goal_handle->publish_feedback(feedback);

피드백 메시지는 위와 같이 주기적으로 클라이언트로 전송되며, 클라이언트는 이를 비동기적으로 수신하여 액션의 진행 상황을 실시간으로 확인할 수 있다.

피드백 수신

ROS2 클라이언트 측에서는 피드백을 비동기적으로 수신할 수 있도록 콜백 함수를 등록한다. 이 피드백 콜백 함수는 액션 서버로부터 피드백 메시지를 받을 때마다 실행된다. 클라이언트는 액션의 중간 결과를 피드백으로 받아 처리할 수 있다.

피드백 콜백 등록

클라이언트에서 피드백을 수신하기 위해서는 액션 클라이언트 객체를 생성할 때 피드백 콜백을 등록해야 한다. 피드백 콜백은 액션 서버가 전송한 피드백 메시지를 처리하는 역할을 한다.

auto feedback_callback = [](rclcpp_action::ClientGoalHandle<MyAction>::SharedPtr,
                            const std::shared_ptr<const MyAction::Feedback> feedback) {
    RCLCPP_INFO(rclcpp::get_logger("rclcpp_action"), "현재 진행 상황: %d", feedback->progress);
};

auto goal_options = rclcpp_action::Client<MyAction>::SendGoalOptions();
goal_options.feedback_callback = feedback_callback;
auto goal_handle_future = action_client->async_send_goal(goal_msg, goal_options);

이 코드에서 feedback_callback 함수는 서버로부터 피드백을 받을 때 실행된다. 여기서 feedback->progress는 액션의 진행률을 나타내는 값으로, 서버에서 전달된 정보를 기반으로 출력할 수 있다.

피드백의 중요성

피드백 처리는 장기적으로 실행되는 액션의 경우 매우 유용하다. 예를 들어, 로봇이 긴 경로를 따라 이동하는 액션을 수행할 때 클라이언트는 피드백을 통해 로봇의 현재 위치를 지속적으로 추적할 수 있다. 또한, 피드백은 클라이언트가 특정 조건에서 액션을 취소하거나 다른 작업을 준비할 수 있도록 실시간 정보를 제공한다.

피드백 처리와 상태 관리의 차이점

액션의 상태 관리는 액션이 어떤 상태에 있는지를 추적하는 반면, 피드백 처리는 액션이 진행 중일 때 클라이언트에게 중간 정보를 제공하는 역할을 한다. 상태 관리는 상태 전이와 관련된 이벤트 중심으로 이루어지며, 피드백은 주기적으로 혹은 필요에 따라 클라이언트에게 보내진다.

상태 전이와 피드백의 동시 처리

상태 전이와 피드백은 독립적으로 발생할 수 있으며, 둘 다 액션 클라이언트에서 동시에 관리된다. 예를 들어, 액션이 "EXECUTING" 상태에 있을 때 피드백이 주기적으로 클라이언트로 전송될 수 있으며, 상태가 "SUCCEEDED"로 전환될 때 더 이상 피드백이 전송되지 않는다.

피드백 메시지의 직렬화와 역직렬화

ROS2에서 피드백 메시지는 통신의 효율성을 위해 직렬화(serialization) 과정을 거쳐 전송된다. 직렬화는 데이터가 네트워크를 통해 전송될 수 있는 형식으로 변환되는 과정이다. 이 후, 클라이언트 측에서 수신된 피드백 메시지는 역직렬화(deserialization)를 통해 원래의 구조로 복원된다.

피드백 메시지의 직렬화는 ROS2 내부에서 자동으로 처리되며, 사용자가 이를 직접적으로 다룰 필요는 없다. 하지만 성능 최적화나 사용자 정의 메시지 타입을 사용할 경우 직렬화/역직렬화 과정을 이해하는 것이 중요할 수 있다.

ROS2의 기본 통신 시스템인 DDS(Data Distribution Service)는 피드백 메시지의 직렬화/역직렬화를 담당하며, 효율적인 전송을 위해 미리 정의된 데이터 타입에 따라 처리된다. 각 메시지 타입은 ROS2의 IDL(Interface Definition Language) 파일에서 정의된 구조를 기반으로 직렬화된다.

사용자 정의 메시지의 직렬화

사용자가 정의한 피드백 메시지는 action 파일에서 정의한 구조에 따라 직렬화된다. 예를 들어, 다음과 같이 사용자 정의 피드백 메시지를 정의할 수 있다:

# 사용자 정의 액션 파일 (CustomAction.action)
string message
int32 progress
---
bool result
---
int32 feedback_value

이 메시지 구조는 DDS 시스템에서 직렬화되어 클라이언트로 전송된다. 사용자가 정의한 피드백 필드(feedback_value 등)는 클라이언트가 이를 해석할 수 있도록 직렬화된 형태로 전송되며, 클라이언트는 이를 역직렬화하여 원래의 데이터를 복원한다.

피드백 메시지의 구조 최적화

피드백 메시지의 구조를 최적화하여 네트워크 통신의 효율성을 높일 수 있다. 예를 들어, 너무 큰 데이터를 피드백 메시지로 보내면 네트워크 대역폭을 많이 차지할 수 있다. 따라서 피드백 메시지는 최소한의 필요한 정보만 포함하여 전송하는 것이 중요하다.

피드백 메시지의 예

다음은 로봇의 경로를 따라가는 액션의 피드백 메시지 예제이다. 이 경우, 로봇의 현재 위치와 목표까지의 남은 거리를 피드백 메시지로 전송할 수 있다.

auto feedback = std::make_shared<MyAction::Feedback>();
feedback->progress = 75;  // 75% 완료
feedback->current_position = {1.0, 2.0, 3.0};  // 로봇의 현재 위치
goal_handle->publish_feedback(feedback);

이와 같이 피드백 메시지는 액션의 현재 상태에 대한 중요한 정보를 클라이언트로 전달하는 역할을 한다.

피드백 처리에서의 지연 문제

피드백 처리는 실시간 시스템에서 중요한 역할을 하지만, 피드백 전송 시 발생할 수 있는 지연 문제는 고려해야 할 사항이다. 네트워크 상태나 시스템 자원의 부하에 따라 피드백 메시지가 클라이언트에 도달하는 시간이 지연될 수 있다.

이러한 지연 문제를 해결하기 위해 ROS2의 QoS(Quality of Service) 정책을 적절하게 설정하여 피드백 전송의 신뢰성과 효율성을 높일 수 있다. QoS 설정을 통해 피드백 메시지의 신속한 전송을 보장하거나, 네트워크 대역폭이 부족할 때 메시지를 드롭하지 않도록 설정할 수 있다.

QoS 설정을 통한 피드백 최적화

ROS2에서 QoS(Quality of Service)는 노드 간 통신의 신뢰성과 성능을 조절하는 중요한 요소이다. 피드백 처리 시 QoS 설정을 통해 피드백 메시지가 안정적이고 효율적으로 전송되도록 최적화할 수 있다. QoS 설정은 ROS2의 퍼블리셔와 서브스크라이버 간의 통신 품질을 제어하는 데 사용된다.

QoS 프로파일의 주요 파라미터

ROS2에서 QoS는 여러 프로파일로 정의되며, 주로 다음과 같은 파라미터를 설정할 수 있다:

QoS 설정 예시

피드백 메시지 전송 시 QoS를 최적화하기 위해 설정할 수 있다. 예를 들어, 피드백 메시지를 신속하게 처리해야 한다면 BEST_EFFORT 모드를 선택하여 네트워크 상태에 따라 최선의 노력을 다해 메시지를 전송할 수 있다. 반면, 중요한 피드백 메시지가 반드시 도착해야 한다면 RELIABLE 모드를 사용하여 신뢰성을 높일 수 있다.

rclcpp::QoS qos_profile(10);  // 메시지 히스토리 10개 유지
qos_profile.reliability(RMW_QOS_POLICY_RELIABILITY_RELIABLE);  // 신뢰성 보장
qos_profile.durability(RMW_QOS_POLICY_DURABILITY_VOLATILE);  // 최신 메시지만 처리
feedback_publisher_ = this->create_publisher<MyAction::Feedback>("feedback_topic", qos_profile);

이 설정을 통해 피드백 메시지가 안정적으로 전송될 수 있도록 QoS를 최적화할 수 있다.

피드백 전송 주기 조절

피드백 메시지의 전송 주기를 적절하게 조정하는 것도 중요하다. 피드백 메시지를 너무 자주 전송하면 네트워크 부하가 커질 수 있으며, 너무 늦게 전송하면 클라이언트가 실시간 진행 상황을 파악하기 어려워질 수 있다.

따라서 피드백 전송 주기는 액션의 성격과 시스템의 요구 사항에 맞게 조절되어야 한다. 예를 들어, 로봇이 이동하는 동안 매초 피드백을 전송하는 것이 적절할 수 있지만, 매우 긴 시간 동안 진행되는 작업이라면 피드백을 덜 빈번하게 보내는 것이 더 효율적일 수 있다.

rclcpp::TimerBase::SharedPtr feedback_timer = this->create_wall_timer(
  std::chrono::milliseconds(1000),  // 매 1초마다 피드백 전송
  [this]() {
    auto feedback = std::make_shared<MyAction::Feedback>();
    feedback->progress = this->get_progress();  // 현재 진행률
    goal_handle_->publish_feedback(feedback);
  });

위 코드에서는 1초마다 피드백을 전송하도록 타이머를 설정하였다. 이를 통해 피드백 전송 주기를 조절할 수 있다.

피드백 처리의 실제 사례

피드백 처리는 다양한 로봇 응용 프로그램에서 유용하게 사용된다. 예를 들어, 로봇이 목표 지점으로 이동하는 동안 피드백을 통해 현재 위치와 진행 상황을 실시간으로 클라이언트에게 전송할 수 있다. 이러한 피드백을 받은 클라이언트는 로봇의 상태를 모니터링하고, 필요시 액션을 취소하거나 조정할 수 있다.

다음은 이동 경로 추적에서 피드백을 활용하는 예이다:

feedback->current_position = {x, y, z};  // 현재 위치
feedback->remaining_distance = calculate_remaining_distance(goal_position, current_position);
goal_handle_->publish_feedback(feedback);

이와 같이, 피드백 메시지를 통해 로봇의 현재 상태와 목표까지의 남은 거리를 클라이언트에 전달할 수 있다.