본문으로 바로가기

ROS2 Action Server 만들기 #2

category 강좌/ROS2 2026. 5. 10. 02:56

1. Feedback 기능 추가하기

 

이 코드는 Action Server의 기본 구조만 확인하는 코드입니다.

 

아직 다음 기능은 없습니다.

1. Goal 값 사용 안 함
2. turtlesim 이동 안 함
3. Feedback 발행 안 함
4. 실제 이동 거리 계산 안 함
5. Result 값 직접 설정 안 함
6. Cancel 처리 없음
 

 

그래서 실행해도 거북이는 움직이지 않습니다.
다만 Action Server가 정상적으로 Goal을 받고 성공 응답을 반환하는지는 확인할 수 있습니다.

 

 

 

Action의 핵심은 작업이 진행되는 동안 중간 상태를 계속 받을 수 있다는 점입니다.


이를 확인하기 위해 Feedback을 발행하는 코드를 추가합니다.

 

import rclpy as rp
from rclpy.action import ActionServer
from rclpy.node import Node
import time

from my_first_package_msgs.action import DistTurtle


class DistTurtleServer(Node):

    def __init__(self):
        super().__init__('dist_turtle_action_server')

        self._action_server = ActionServer(
            self,
            DistTurtle,
            'dist_turtle',
            self.execute_callback
        )

    def execute_callback(self, goal_handle):
        feedback_msg = DistTurtle.Feedback()

        for n in range(10):
            feedback_msg.remained_dist = float(10-n)
            goal_handle.publish_feedback(feedback_msg)
            time.sleep(0.5)

        goal_handle.succeed()

        result = DistTurtle.Result()
        return result


def main(args=None):
    rp.init(args=args)

    dist_turtle_action_server = DistTurtleServer()
    rp.spin(dist_turtle_action_server)

    dist_turtle_action_server.destroy_node()
    rp.shutdown()


if __name__ == '__main__':
    main()

 

 

추가된 핵심 코드는 다음입니다.

 

import time
 
지연시간 사용을 위해 time을 import 합니다.
 
 
 
 

 

 

feedback_msg = DistTurtle.Feedback()
 

 

Feedback 메시지 객체를 생성합니다.

 

 

 

for n in range(10):
 

 

0부터 9까지 반복하면서 Feedback을 보냅니다.

 
feedback_msg.remained_dist = float(10-n)
 

 

remained_dist 필드에 10-n 값을 넣습니다.

 
goal_handle.publish_feedback(feedback_msg)
 

 

Action Client 쪽으로 Feedback을 발행합니다.

 
time.sleep(0.5)
 

 

Feedback이 너무 빠르게 출력되지 않도록 0.5초씩 대기합니다.

 

 

 

 

최종 소스는 아래와 같습니다.

 

import rclpy as rp
from rclpy.action import ActionServer
from rclpy.node import Node
import time

from my_first_package_msgs.action import DistTurtle


class DistTurtleServer(Node):

    def __init__(self):
        super().__init__('dist_turtle_action_server')

        self._action_server = ActionServer(
            self,
            DistTurtle,
            'dist_turtle',
            self.execute_callback
        )

    def execute_callback(self, goal_handle):
        feedback_msg = DistTurtle.Feedback()

        for n in range(10):
            feedback_msg.remained_dist = float(10-n)
            goal_handle.publish_feedback(feedback_msg)
            time.sleep(0.5)

        goal_handle.succeed()

        result = DistTurtle.Result()
        return result


def main(args=None):
    rp.init(args=args)

    dist_turtle_action_server = DistTurtleServer()
    rp.spin(dist_turtle_action_server)

    dist_turtle_action_server.destroy_node()
    rp.shutdown()


if __name__ == '__main__':
    main()

 

 

2. Feedback 확인하기

 

서버를 다시 빌드하고 실행합니다.

 

cd ~/ros2_study
colcon build
source install/setup.bash

또는 

sl

ros2 run my_first_package dist_turtle_action_server

 

 

 

다른 터미널에서 Feedback 옵션을 붙여 Goal을 보냅니다.

 

ros2 action send_goal --feedback /dist_turtle my_first_package_msgs/action/DistTurtle "{linear_x: 0, angular_z: 0, dist: 0}"

 

 

정상적으로 실행되면 다음과 같이 Feedback이 반복 출력됩니다.

 

 

 

 

마지막에는 Goal이 성공 상태로 종료됩니다.

Goal finished with status: SUCCEEDED

 

 

 

6. 여기서 중요한 개념 정리

 

이번 실습에서 핵심은 단순히 코드를 입력하는 것이 아닙니다.


Action이 왜 필요한지 이해하는 것이 더 중요합니다.

 

Service는 다음과 같은 상황에 적합합니다.

요청 → 즉시 응답
 

 

예를 들면 “거북이를 하나 생성해 주세요” 같은 작업입니다.

 

반면 Action은 다음과 같은 상황에 적합합니다.

요청 → 작업 진행 → 중간 상태 확인 → 최종 결과
 

 

예를 들면 “거북이를 5m 이동시켜 주세요” 같은 작업입니다.
이동하는 동안 남은 거리, 현재 상태, 진행률 등을 계속 확인할 수 있어야 하므로 Action이 더 적합합니다.

 

 

 

7. 실제 로봇 시스템에서의 활용

 

ROS 2 Action은 실제 로봇 개발에서 매우 자주 사용됩니다.

 

대표적인 예는 다음과 같습니다.

                      작업                                                                   Action이 적합한 이유
모바일 로봇 목적지 이동 이동 중 경로 상태와 남은 거리를 확인해야 합니다.
로봇팔 Pick & Place 동작 시간이 길고 실패 가능성이 있습니다.
드론 Waypoint 이동 목표점까지 이동하면서 위치 오차를 계속 확인해야 합니다.
자동 충전 도킹 접근 중 상태와 최종 성공 여부가 필요합니다.
그리퍼 동작 열림/닫힘 완료 여부를 결과로 받을 수 있습니다.

 

특히 드론이나 모바일 로봇에서는 단순 명령보다 Action 구조가 훨씬 안정적입니다.


예를 들어 드론에게 “목표 좌표까지 이동”을 명령하면, 이동 중 현재 위치, 남은 거리, 도착 여부, 실패 원인을 계속 확인할 수 있습니다.

 

 

 

8. 실습 시 자주 발생하는 오류

 

a. Action 인터페이스를 찾을 수 없는 경우

 
ros2 interface show my_first_package_msgs/action/DistTurtle
 

 

명령에서 에러가 나면 보통 다음 중 하나입니다.

1. action 파일명이 잘못됨
2. CMakeLists.txt에 action 파일 등록 누락
3. package.xml에 action_msgs 의존성 누락
4. colcon build 후 source install/setup.bash 미실행
 
 
 

b. ros2 run에서 실행 파일을 찾지 못하는 경우

 
ros2 run my_first_package dist_turtle_action_server
 

 

실행이 안 된다면 setup.py의 entry_points를 확인해야 합니다.

 
'dist_turtle_action_server = my_first_package.dist_turtle_action_server:main'
 

 

파일명, 패키지명, 함수명이 하나라도 틀리면 실행되지 않습니다.

 

 

c. Feedback이 안 보이는 경우

 

Goal 전송 시 반드시 --feedback 옵션을 붙여야 합니다.

 
ros2 action send_goal --feedback /dist_turtle my_first_package_msgs/action/DistTurtle "{linear_x: 0, angular_z: 0, dist: 0}"
 

 

옵션이 없으면 Feedback을 서버에서 보내고 있어도 터미널에는 보이지 않습니다.

 

 

 

9. 정리

 

이번 글에서는 ROS 2 Action의 기본 구조를 직접 만들어 보았습니다.


Action 정의 파일을 만들고, 이를 빌드한 뒤 Python Action Server에서 Goal을 수신하고 Feedback을 발행하는 과정까지 확인했습니다.

 

이번 예제에서는 실제 turtlesim 이동 제어까지 구현하지는 않았지만, Action Server의 핵심 구조는 모두 포함되어 있습니다.

 

다음 단계에서는 /turtle1/cmd_vel 토픽을 발행하고 /turtle1/pose 토픽을 구독하여, 사용자가 입력한 거리만큼 실제로 거북이를 이동시키는 Action Server로 확장할 수 있습니다.

즉, 이번 실습은 단순 예제가 아니라 실제 로봇 제어 구조의 기초입니다.


ROS 2에서 장시간 수행되는 작업, 중간 상태 확인이 필요한 작업, 취소 가능한 작업을 설계할 때 Action은 반드시 이해해야 하는 핵심 통신 방식입니다.

 

728x90
728x90