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

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은 실제 로봇 개발에서 매우 자주 사용됩니다.
대표적인 예는 다음과 같습니다.
| 모바일 로봇 목적지 이동 | 이동 중 경로 상태와 남은 거리를 확인해야 합니다. |
| 로봇팔 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은 반드시 이해해야 하는 핵심 통신 방식입니다.
'강좌 > ROS2' 카테고리의 다른 글
| ROS 2 MultiThreadedExecutor와 Action Server로 Turtlesim 거리 이동 구현하기 (0) | 2026.05.10 |
|---|---|
| ROS2 MultiThread 기초 (0) | 2026.05.10 |
| ROS 2 Action 정의 만들기 (0) | 2026.05.10 |
| ROS2 사용자 정의 메세지 만들기 #3 (0) | 2026.05.09 |
| ROS2 사용자 정의 메세지 만들기 #2 (0) | 2026.05.09 |