- 서비스(Service)는 노드 간의 요청-응답(Request-Response) 통신 패턴을 구현하는 방법
서비스는 일반적으로 하나의 노드에서 특정 작업을 수행하고, 그 결과를 요청한 노드에 반환
서비스(Service)란?
- 서비스 서버(Service Server): 서비스 요청을 받고 처리한 후 응답을 반환
- 서비스 클라이언트(Service Client): 서비스 서버에 요청을 보내고 응답을 기다림
create_service
사용법
create_service
함수는 ROS 2 노드 내에서 서비스 서버를 생성하는 데 사용
- 이 함수를 사용하여 서비스 타입, 서비스 이름, 콜백 함수를 지정하여 서비스 서버를 설정할 수 있습니다.
매개변수
- srv_type: 서비스 타입을 나타냅니다. 이는 서비스의 요청과 응답 메시지 구조를 정의하는 클래스입니다.
- service_name: 서비스의 이름입니다. 이 이름은 ROS 2 네트워크 내에서 서비스를 고유하게 식별하는 데 사용됩니다.
- callback: 서비스 요청이 들어올 때 호출될 함수입니다. 이 콜백 함수는 요청을 받고 적절한 응답을 반환해야 합니다.
- callback_group (선택적): 콜백이 실행될 콜백 그룹입니다. 이 인자는 선택적이며, 지정하지 않을 경우 기본 콜백 그룹이 사용됩니다.
- qos_profile (선택적): 서비스의 Quality of Service(QoS) 프로필입니다. 이 인자는 선택적이며, 지정하지 않을 경우 기본 QoS 설정이 사용됩니다.
코드 예시
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts
class MyServiceServer(Node):
def __init__(self):
super().__init__('my_service_server')
self.service = 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
return response
rclpy.init()
node = MyServiceServer()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
- 이 예시에서,
MyServiceServer
노드는 AddTwoInts
서비스 타입으로 add_two_ints
서비스를 생성합니다. add_two_ints_callback
함수는 요청을 처리하고 응답합니다.
create_client
사용법
create_client
함수는 ROS 2 노드 내에서 서비스 클라이언트를 생성하는 데 사용됩니다.
- 이 함수를 사용하여 서비스 타입과 서비스 이름을 지정하여 서비스 클라이언트를 설정할 수 있습니다.
매개변수
- srv_type: 서비스 타입을 나타냅니다. 이는 클라이언트가 사용할 서비스의 요청과 응답 메시지 구조를 정의하는 클래스입니다.
- service_name: 클라이언트가 연결할 서비스의 이름입니다. 이 이름은 서비스 서버와 일치해야 합니다.
- qos_profile (선택적): 서비스의 Quality of Service(QoS) 프로필입니다. 이 인자는 선택적이며, 지정하지 않을 경우 기본 QoS 설정이 사용됩니다.
- callback_group (선택적): 클라이언트 콜백이 실행될 콜백 그룹입니다. 이 인자는 선택적이며, 지정하지 않을 경우 기본 콜백 그룹이 사용됩니다.
코드 예시
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts
class MyServiceClient(Node):
def __init__(self):
super().__init__('my_service_client')
self.client = self.create_client(AddTwoInts, 'add_two_ints')
while not self.client.wait_for_service(timeout_sec=1.0):
self.get_logger().info('서비스가 활성화될 때까지 기다리는 중...')
self.req = AddTwoInts.Request()
def send_request(self):
self.req.a = 10
self.req.b = 20
self.future = self.client.call_async(self.req)
rclpy.init()
node = MyServiceClient()
node.send_request()
while rclpy.ok():
rclpy.spin_once(node)
if node.future.done():
try:
response = node.future.result()
except Exception as e:
node.get_logger().info('서비스 호출 중 에러 발생: %r' % (e,))
else:
node.get_logger().info('결과: %d' % (response.sum))
break
node.destroy_node()
rclpy.shutdown()
함수 설명
1. self.client.wait_for_service(timeout_sec=1.0)
- 함수는 서비스 클라이언트가 특정 서비스가 사용 가능해질 때까지 대기하는 데 사용됩니다.
- 이 함수는 지정된 시간 동안 서비스가 활성화될 때까지 기다립니다.
- 목적:
서비스 클라이언트가 서비스 요청을 보내기 전에, 해당 서비스 서버가 활성화되어 있고 준비되었는지 확인하는 데 사용
- 파라미터
timeout_sec
:
- 이 파라미터는 함수가 서비스의 사용 가능 여부를 확인하는 데 대기할 최대 시간(초 단위)을 지정합니다.
- 지정된 시간 동안 서비스가 활성화되지 않으면 함수는
False
를 반환합니다.
- 응용:
- 서비스 서버가 아직 준비되지 않았을 때 클라이언트가 서비스 요청을 보내는 것을 방지하기 위해 사용
2. self.client.call_async(self.req)
- 서비스 클라이언트가 서비스 서버에 비동기적으로 서비스 요청을 보내는 데 사용
- 이 함수는 서비스 요청을 서버에 전송하고 즉시 반환
- 서버의 응답은 비동기적으로 처리
- 목적: 비동기 서비스 요청을 보내어, 서비스 요청의 처리와 응답이 클라이언트의 나머지 처리 흐름을 차단하지 않도록 함
- 파라미터
self.req
: 이는 서비스 요청을 나타내는 객체입니다. 이 객체는 서비스 타입에 따라 정의된 데이터 구조를 포함합니다.
- 반환 값:
- 이 함수는
Future
객체를 반환합니다.
- 이
Future
객체를 사용하여 서비스 응답의 완료 상태와 결과를 나중에 확인할 수 있습니다.
- 응용:
- 서비스 클라이언트가 서비스 요청을 보내고, 그 동안 다른 작업을 계속 진행할 수 있도록 합니다.
- 응답은
Future
객체를 통해 나중에 처리됩니다.
self.srv_cli.call(req)
- 결론적으로,
call
메서드는 동기적으로 서비스 요청을 처리하고, call_async
메서드는 비동기적으로 처리합니다.
- 비스 클라이언트가 서비스 서버에 동기적으로 서비스 요청을 보내는 데 사용됩니다.
- 동작 방식: 이 메서드는 서비스 요청을 서버에 보내고 서버로부터 응답을 받을 때까지 실행을 차단합니다. 즉, 응답이 도착할 때까지 프로그램의 실행이 멈추게 됩니다.
- 사용 상황: 요청의 결과를 즉시 필요로 하고, 요청 처리 시간이 짧은 경우에 적합합니다. 또한 프로그램의 다른 부분이 요청의 결과에 의존적인 경우에도 사용됩니다.