ROS 2

ROS 2 Tutorials : Writing a simple service and client (Python)

정지홍 2025. 1. 15. 18:28

Writing a simple service and client (Python) — ROS 2 Documentation: Jazzy documentation

 

Writing a simple service and client (Python) — ROS 2 Documentation: Jazzy documentation

Inside the ros2_ws/src/py_srvcli/py_srvcli directory, create a new file called service_member_function.py and paste the following code within: 2.2 Add an entry point To allow the ros2 run command to run your node, you must add the entry point to setup.py (

docs.ros.org

 

Goal

  • python으로 service와 client node를 만들어서 실행하기.

 

Background

  • services는 이용하여 nodes와 communicate할때 사용한다.
    • nodes는 client node에게 request data를 보낸다. 구리고 service node가 이에 대해서 responds를 한다.
    • request와 response에 대한 구조는 .srv 파일이 한다.
  • 이번에 할 튜토리얼은 간단한 덧셈 시스템이다.
    • 하나의 node가 2개의 숫자의 합을 구해달라는 requests를 보낼 것이며, 다른 하나는 결과를 responds한다.

 

Tasks

  • 1. 우선 terminal을 열어서 ros2 명령어가 잘되는지 확인. 그리고 ros2_ws 디렉토리로 이동한다.
  • 2. package는 src 디렉토리 안에 있어야한다. 루트에 있으면 안된다.
    • ros2_ws/src에 들어가서 아래를 입력하자.
    • --dependencies 인수는 필요한 종속성 라인을 package.xml에 자동으로 추가한다.
      example_interfaces는 요청과 응답을 구성하는 데 필요한 .srv 파일을 포함한 패키지이다.
ros2 pkg create --build-type ament_python --license Apache-2.0 py_srvcli --dependencies rclpy example_interfaces

위와 같이 입력하면...
py_srvcli 가 생김

  • 3. package.xml을 업데이트 하자.
    • --dependencies를 package를 만들때 사용했으니, package.xml에 dependencies를 수동으로 추가할 필요는 없다.
    • 하지만, 항상 그랬듯이 package.xml에 설명 , 관리자 이메일 , 이름등을 추가하자. 
  • 4.  setup.py도 똑같이 업데이트
    • maintainer , maintainer_email , description , license 등등...
  • 5. ros2_ws/src/py_srvcli/py_srvcli에 들어가서 service_member_function.py라는 파일을 만들어서 작성하자.
# ros2 서비스 인터페이스 addTwoInts를 가져온다. 
# 이는 두개의 정수를 입력받아서 이들의 합을 반환하는 서비스 메시지 타입이다.
from example_interfaces.srv import AddTwoInts
import rclpy
# node class를 가져온다. node는 ros2에서 통신의 기본 단위이다.
from rclpy.node import Node

# 해당 클래스는 ROS 2 node를 상속받아서 service node를 구현한다.
class MinimalService(Node):
# 부모 클래스node를 초기화하면서 노드 이름을 minimal_srvice라고 설정한다.
# add_two_ints라는 이름의 service를 생성한다. 이 서비스 타입은 AddTwoInts 타입이며, 
#                                     요청이 들어오면 add_two_ints_callback함수를 호출함.
    def __init__(self):
        super().__init__('minimal_service')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
# 이는 request가 들어오면 받은 정수 a+b의 결과를 response에 저장함
    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():
    rclpy.init()

    minimal_service = MinimalService()

    rclpy.spin(minimal_service)

    rclpy.shutdown()


if __name__ == '__main__':
    main()

 

  • 6. add entry point
    • ros2_ws/src/py_srvcli 디렉토리의 setup.py도 수정

  • 7. 다음에는 service_member_function.py가 있던 디렉토리로 가서 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')
        # 서비스가 실행중인지 확인함. 실행중이 아니라면 1초 간격으로 확인함.
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        # AddTwoInts 타입의 요청request 객체를 생성
        self.req = AddTwoInts.Request()
	# service request를 전송하는 함수
    def send_request(self, a, b):
        self.req.a = a
        self.req.b = b
        return self.cli.call_async(self.req)


def main():
	# ros 2 client node를 실행하는 메인 함수
    rclpy.init()
    minimal_client = MinimalClientAsync()
    future = minimal_client.send_request(int(sys.argv[1]), int(sys.argv[2]))
    # furture 객체가 완료될 때 까지 node를 실행하며 대기함.
    rclpy.spin_until_future_complete(minimal_client, future)
    # future의 결과를 가져옴.
    response = future.result()
    minimal_client.get_logger().info(
        'Result of add_two_ints: for %d + %d = %d' %
        (int(sys.argv[1]), int(sys.argv[2]), response.sum))

    minimal_client.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()
  • 8. 이것도 entry_point에 추가한다.

  • 9. root로 가서 의존성을 체크하자.
rosdep install -i --from-path src --rosdistro jazzy -y

  • 10. 빌드 
colcon build --packages-select py_srvcli

  • 11. 실행
source install/setup.bash
ros2 run py_srvcli service

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

 

 

 

summary

  • 위에서 2개의 node를 만들어서 request와 respond로 data를 다루는 service를 만들었다.
  • 그리고 여기에 그들의 의존성과 실행가능한 패키지들도 수정해보았다.