[ROS2] (17)-Python으로 서비스와 클라이언트 만들기

서비스와 클라이언트 만들기

이전 포스팅에서 만들었던 서비스와 클라이언트 노드를 python으로 만들어보자.

패키지 만들기

먼저, 패키지를 만든다.

$ cd dev_ws/src
$ ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces

--dependenciespackage.xml에 dependency를 추가해준다.

서비스 노드 작성하기

다음으로 dev_ws/src/py_srvcli/py_srvcli 폴더에 service_member_function.py 파일을 만들고, 아래 코드를 붙여넣는다.

$ cd dev_ws/src/py_srvcli/py_srvcli
$ gedit service_member_function.py
from example_interfaces.srv import AddTwoInts

import rclpy
from rclpy.node import Node


class MinimalService(Node):

    def __init__(self):
        super().__init__('minimal_service')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)

    def add_two_ints_callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))

        return response


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

    minimal_service = MinimalService()

    rclpy.spin(minimal_service)

    rclpy.shutdown()


if __name__ == '__main__':
    main()

코드를 보면, 가장 먼저 필요한 패키지를 import 해주고 있다. 다음으로 MinimalService라는 클래스에서 생성자와 callback 함수를 정의해준다.

ros2 run이 노드를 찾을 수 있도록 setup.py 파일에서 'console_scripts': 괄호 안에 아래 내용을 추가한다.

'service = py_srvcli.service_member_function:main',

클라이언트 노드 작성하기

dev_ws/src/py_srvcli/py_srvcli 폴더 안에 client_member_function.py 파일을 만들고, 아래 내용을 붙여넣는다.

import sys

from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node


class MinimalClientAsync(Node):

    def __init__(self):
        super().__init__('minimal_client_async')
        self.cli = self.create_client(AddTwoInts, 'add_two_ints')
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        self.req = AddTwoInts.Request()

    def send_request(self):
        self.req.a = int(sys.argv[1])
        self.req.b = int(sys.argv[2])
        self.future = self.cli.call_async(self.req)


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

    minimal_client = MinimalClientAsync()
    minimal_client.send_request()

    while rclpy.ok():
        rclpy.spin_once(minimal_client)
        if minimal_client.future.done():
            try:
                response = minimal_client.future.result()
            except Exception as e:
                minimal_client.get_logger().info(
                    'Service call failed %r' % (e,))
            else:
                minimal_client.get_logger().info(
                    'Result of add_two_ints: for %d + %d = %d' %
                    (minimal_client.req.a, minimal_client.req.b, response.sum))
            break

    minimal_client.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

클라이언트 노드는 sys.argv로 input 을 받기 위해 sys 모듈을 포함한다. 생성자 내부의 while 문은 클라이언트가 요청하는 서비스가 이용가능한지 확인한다. main 함수의 while 문은 future를 체크해서 응답이 왔는지를 확인한다.

역시 setup.py 파일에서 'console_scripts': 괄호 내에 아래 내용을 추가한다.

'client = py_srvcli.client_member_function:main',

빌드 및 실행하기

dependency를 먼저 확인한다.

$ cd dev_ws
$ rosdep install -i --from-path src --rosdistro foxy -y

빌드한다.

$ cd dev_ws
$ colcon build --packages-select py_srvcli

서비스 노드를 실행한다.

$ source install/setup.bash
$ ros2 run py_srvcli service

클라이언트 노드를 실행하면서 정수를 서버에 넘겨 준다.

$ source install/setup.bash
$ ros2 run py_srvcli client 2 3

이전 포스팅에서 만든 클라이언트 노드도 실행해보자.

$ source install/setup.bash
$ ros2 run cpp_srvcli client 5 10

역시 작성한 언어에 관계 없이 잘 동작하는 것을 확인할 수 있다.

댓글남기기