代码

import rclpy
from rclpy.node import Node
from chapt4_interfaces.srv import FaceDetector
import face_recognition
import cv2
from ament_index_python.packages import get_package_share_directory # 获取功能包share目录绝对路径
import os
from cv_bridge import CvBridge
import time

class FaceDetectClientNode(Node):
    def __init__(self):
        super().__init__('face_detect_client_node')
        self.brige = CvBridge()
        self.default_image_path = os.path.join(get_package_share_directory('demo_py_service'), 'resource', 'default.jpeg')
        self.get_logger().info('人脸检测客户端已启动')

        self.client =self.create_client(FaceDetector,'face_detect')
        self.image =cv2.imread(self.default_image_path)


    def send_request(self):
        # 1.判断服务端是否在线
        while self.client.wait_for_service(timeout_sec=1.0) is False:
            self.get_logger().info('服务端未启动,等待中...')

        # 2.构造请求
        request = FaceDetector.Request()
        request.image = self.brige.cv2_to_imgmsg(self.image)

        # 3.发送请求并等待处理完成
        future = self.client.call_async(request) # 现在的future并没有包含响应结果,需要等待服务端处理完成后才会把响应结果放入future中
        def result_callback(future):
            response = future.result() # 获取响应结果
            self.get_logger().info(f'接收到相应,共:{response.number}张人脸,耗时:{response.use_time:.4f}秒')
            self.show_response(response)
        future.add_done_callback(result_callback)
        # while not future.done():
            # time.sleep(1.0) # 休眠线程,等待服务端处理完成,造成当前线程无法再接受来自服务端的响应结果,导致永远无法获取响应结果,即future.done()永远为False
            # rclpy.spin_until_future_complete(self,future) # 让当前线程可以接受来自服务端的响应结果,直到服务端处理完成,future.done()为True


    def show_response(self,response):
        for i in range(response.number):
            top = response.top[i]
            right = response.right[i]
            bottom = response.bottom[i]
            left = response.left[i]
            cv2.rectangle(self.image,(left,top),(right,bottom),(255,0,0),4)

        cv2.imshow('Face Detection',self.image)
        cv2.waitKey(0) # 也是阻塞函数,会导致spin无法正常运行


def main():
    rclpy.init()
    node = FaceDetectClientNode()
    node.send_request()
    rclpy.spin(node)
    rclpy.shutdown()

其中需要注意的是

        cv2.imshow('Face Detection',self.image)
        cv2.waitKey(0) # 也是阻塞函数,会导致spin无法正常运行

show不要放到for循环里,不然会出现只有1个框。还有就是如果使用time.sleep(1.0)会导致rclpy.spin(node)也进入休眠,本来使用ROS2中的rclpy.spin_until_future_complete(self,future)休眠线程,但是会遇到问题:rclpy.spin_until_future_complete又创建了一个临时的executor,然后这个节点被加到了两个executor(main函数里面的和回调函数里面临时创建的),好像是未定义的行为。会导致随着调用次数等待响应逐时增加(py版本),疑似jazzy的bug
所以有更好的选择,也就是使用回调函数

        def result_callback(future):
            response = future.result() # 获取响应结果
            self.get_logger().info(f'接收到相应,共:{response.number}张人脸,耗时:{response.use_time:.4f}秒')
            self.show_response(response)
        future.add_done_callback(result_callback)