Ubuntu ROS 실습(33)

zeusqoi·5일 전

개인공부 - ubuntu

목록 보기
52/57

이번 실습에서는 ROS 2에서 Service 통신을 Python으로 구현하는 방법을 실습했다.
operator 노드가 Service Client로 연산자를 요청하고, calculator 노드가 Service Server로 요청을 받아 계산 결과를 반환하는 과정을 직접 확인했다.


1. Service Client / Service Server

ROS 2의 Service는 서비스 요청(Request)과 서비스 응답(Response)을 주고받는 방식으로 통신한다.

이번 실습에서는 다음과 같은 구조로 구성되어 있다.

  • operator → Service Client
  • calculator → Service Server
  • 서비스 이름 → arithmetic_operator
  • 서비스 타입 → ArithmeticOperator

operator 노드는 +, -, *, / 중 하나의 연산자를 요청값으로 보내고, calculator 노드는 Topic을 통해 저장하고 있던 a, b 값을 이용하여 계산한 뒤 결과를 응답값으로 반환한다.

operator
(Service Client)
      │
      │ Request
      ▼
arithmetic_operator
      │
      ▼
calculator
(Service Server)
      │
      │ Response
      ▼
operator

2. Service Server 코드 확인

먼저 calculator.py에서 Service Server 부분을 확인했다.

sed -n '70,130p' ~/robot_ws/src/ros2-seminar-examples/topic_service_action_rclpy_example/topic_service_action_rclpy_example/calculator/calculator.py

get_arithmetic_operator() 함수에서는 서비스 요청으로 전달받은 연산자를 가져온다.

def get_arithmetic_operator(self, request, response):
    self.argument_operator = request.arithmetic_operator

    self.argument_result = self.calculate_given_formula(
        self.argument_a,
        self.argument_b,
        self.argument_operator)

    response.arithmetic_result = self.argument_result

request에는 서비스 요청값이 들어오고, response에는 서비스 응답값을 저장한다.

요청받은 연산자와 기존에 저장된 argument_a, argument_b를 이용하여 계산한 후 결과를 response.arithmetic_result에 저장한다.


3. Service Server 생성

Service Server는 create_service()를 이용하여 생성되어 있다.

grep -n -A6 "create_service" ~/robot_ws/src/ros2-seminar-examples/topic_service_action_rclpy_example/topic_service_action_rclpy_example/calculator/calculator.py

확인한 코드는 다음과 같다.

self.arithmetic_service_server = self.create_service(
    ArithmeticOperator,
    'arithmetic_operator',
    self.get_arithmetic_operator,
    callback_group=self.callback_group)

각 항목은 다음과 같다.

  • ArithmeticOperator → 서비스 타입
  • arithmetic_operator → 서비스 이름
  • get_arithmetic_operator → 서비스 요청 시 실행되는 콜백 함수
  • callback_group → 콜백 그룹 설정

즉, operator에서 서비스 요청이 들어오면 get_arithmetic_operator() 함수가 실행된다.


4. 사칙연산 처리

calculate_given_formula() 함수에서는 전달받은 연산자에 따라 계산을 수행한다.

if operator == ArithmeticOperator.Request.PLUS:
    self.argument_result = a + b
elif operator == ArithmeticOperator.Request.MINUS:
    self.argument_result = a - b
elif operator == ArithmeticOperator.Request.MULTIPLY:
    self.argument_result = a * b
elif operator == ArithmeticOperator.Request.DIVISION:
    self.argument_result = a / b

따라서 서비스 요청값에 따라 다음과 같이 계산된다.

PLUS      → +
MINUS     → -
MULTIPLY  → *
DIVISION  → /

나눗셈 과정에서 0으로 나누는 경우에는 ZeroDivisionError를 처리하도록 구성되어 있다.


5. Service Client 코드 확인

다음으로 operator.py에서 Service Client 코드를 확인했다.

sed -n '1,80p' ~/robot_ws/src/ros2-seminar-examples/topic_service_action_rclpy_example/topic_service_action_rclpy_example/arithmetic/operator.py

Operator 클래스는 Node를 상속하고 operator라는 이름의 노드로 생성된다.

class Operator(Node):

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

Service Client는 다음과 같이 생성되어 있다.

self.arithmetic_service_client = self.create_client(
    ArithmeticOperator,
    'arithmetic_operator')

Service Server와 동일하게 ArithmeticOperator 타입과 arithmetic_operator라는 서비스 이름을 사용한다.


6. Service Server 연결 확인

Service Client에서는 서버가 실행되어 있는지 확인하기 위해 wait_for_service()를 사용한다.

while not self.arithmetic_service_client.wait_for_service(timeout_sec=0.1):
    self.get_logger().warning(
        'The arithmetic_operator service not available.')

서비스 서버가 실행될 때까지 0.1초 간격으로 확인한다.


7. 서비스 요청 보내기

send_request() 함수에서는 실제 서비스 요청을 생성한다.

def send_request(self):
    service_request = ArithmeticOperator.Request()
    service_request.arithmetic_operator = random.randint(1, 4)
    futures = self.arithmetic_service_client.call_async(
        service_request)
    return futures

먼저 ArithmeticOperator.Request()를 이용해 요청 객체를 생성한다.

그 다음 random.randint(1, 4)를 이용하여 1~4 중 하나를 선택하고 arithmetic_operator에 저장한다.

마지막으로 call_async()를 이용하여 Service Server에 요청을 보낸다.


8. Calculator 노드 실행

이제 실제 Service 통신을 확인하기 위해 calculator 노드를 실행했다.

source ~/robot_ws/install/setup.zsh
ros2 run topic_service_action_rclpy_example calculator

calculator 노드는 기존 Topic Subscriber와 함께 Service Server 역할도 수행한다.


9. Operator 노드 실행

새로운 터미널에서 operator 노드를 실행했다.

source ~/robot_ws/install/setup.zsh
ros2 run topic_service_action_rclpy_example operator

실행하면 operator에서 랜덤하게 연산자를 선택하여 calculator에 Service Request를 보낸다.

calculator는 저장된 argument_a, argument_b와 전달받은 연산자를 이용해 계산한 후 결과를 반환한다.


10. Service 결과 확인

operator 터미널에서 계산 결과가 출력되는 것을 확인했다.

[INFO]: Result: ...

또한 operator에서 Enter를 입력하면 다음 Service Request가 실행되어 새로운 계산 결과가 계속 출력되는 것을 확인했다.

즉, 한 번의 요청으로 끝나는 것이 아니라 다음과 같이 반복적으로 Service 통신이 이루어졌다.

Request
   ↓
calculator 계산
   ↓
Response
   ↓
Result 출력
   ↓
Enter
   ↓
다음 Request

PPT에서도 operator가 서비스 요청을 보내고 calculator가 계산한 결과를 반환하는 과정을 동일하게 설명하고 있다.


11. Service 목록 확인

마지막으로 ROS 2에 등록된 Service를 확인했다.

source ~/robot_ws/install/setup.zsh
ros2 service list

실행 결과에서 다음 Service를 확인했다.

/arithmetic_operator

이를 통해 arithmetic_operator Service가 ROS 2에 정상적으로 등록되어 있는 것을 확인했다.


마무리

이번 실습에서는 ROS 2의 Service Client와 Service Server 통신을 Python으로 구현하고 실제로 실행해 보았다.

operator
(Service Client)
      │
      │ 연산자 Request
      ▼
/arithmetic_operator
      │
      ▼
calculator
(Service Server)
      │
      │ 계산 결과 Response
      ▼
operator

operator 노드가 랜덤하게 연산자를 선택하여 Service Request를 보내고, calculator 노드가 a, b와 연산자를 이용하여 계산한 후 결과를 반환하는 과정을 확인했다.

또한 ros2 service list 명령어를 통해 /arithmetic_operator Service가 정상적으로 등록된 것도 확인했다.

0개의 댓글