通过ROS2服务通信完成图片传输功能(C++和python代码都有)然后再使用python调用YOLOV8模型识别图片后传输

1、创建项目,ROS2项目创建过程省略。

2、创建服务通信自定义图片信息

2.1服务通信自定义包创建

2.1.1进入项目的src目录下执行下面语句创建server_demo包  

ros2 pkg create --build-type ament_cmake server_demo

2.1.2在server_demo目录下创建srv文件夹,并创建一个Myimage.srv文件,并文件中添加(srv文件首字母必须要大写,而且文件名不可以有特殊符号)

sensor_msgs/Image client_image
---
sensor_msgs/Image server_image

2.2编辑CMakeLists.txt和package.xml文件

2.2.1CMakeLists.txt文件添加以下内容

find_package(sensor_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
  "srv/Myimage.srv"
  DEPENDENCIES sensor_msgs
)

如图所示

 2.2.2package.xml文件添加以下内容

  <build_depend>rosidl_default_generators</build_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

如图所示

2.3编译服务通信自定义包

3.C++的客户端和服务端创建

3.1创建C++的服务通信的包

ros2 pkg create cpp_service --build-type ament_cmake --dependencies rclcpp std_msgs server_demo --node-name server_cpp

为了方便我直接创建包的时候添加了--node-name server_cpp顺便把server_cpp文件也生成

3.2服务端代码

server_cpp文件的代码如下        

#include "rclcpp/rclcpp.hpp"
#include "server_demo/srv/myimage.hpp"
#include "opencv2/opencv.hpp"
#include "cv_bridge/cv_bridge.h"
#include "std_msgs/msg/string.hpp"
using server_demo::srv::Myimage;
using std::placeholders::_1;
using std::placeholders::_2;
using namespace std::chrono_literals;

// 3.定义节点类;
class MinimalService: public rclcpp::Node{
  public:
    MinimalService():Node("minimal_service"){
      // 3-1.创建服务端;
      server = this->create_service<Myimage>("image_test",std::bind(&MinimalService::appect, this, _1, _2));
      RCLCPP_INFO(this->get_logger(),"image_test 服务端启动完毕,等待请求提交...");
    }
  private:
    rclcpp::Service<Myimage>::SharedPtr server;
    // 3-2.处理请求数据并响应结果。
    void appect(const Myimage::Request::SharedPtr  req,const Myimage::Response::SharedPtr res){
       cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(req->client_image, sensor_msgs::image_encodings::BGR8); //获取客户端的图片
       cv::Mat img1= cv_ptr->image;
       cv::Mat img= cv::imread("/home/ubuntu/project/image_publish/src/1.jpg",1);//读取传给客户端的照片
       sensor_msgs::msg::Image::SharedPtr msg=cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", img).toImageMsg();
       cv::resize(img1, img1, cv::Size(img.size().width,img.size().height));
       cv::imshow("server",img1);
       cv::waitKey(25000);
       res->server_image = *msg; //发送服务器的图片
       cv::destroyAllWindows();
  
    }
};

int main(int argc, char const *argv[])
{
  // 2.初始化 ROS2 客户端;
  rclcpp::init(argc,argv);

  // 4.调用spin函数,并传入节点对象指针;
  auto server = std::make_shared<MinimalService>();
  rclcpp::spin(server);

  // 5.释放资源。
  rclcpp::shutdown();
  return 0;
}

3.3客户端代码

在cpp_service/src目录下创建一个client_cpp.cpp的文件编写客户端的代码

#include "cv_bridge/cv_bridge.h"
#include "rclcpp/rclcpp.hpp"
#include "server_demo/srv/myimage.hpp"
#include "opencv2/opencv.hpp"
#include "cv_bridge/cv_bridge.h"
using server_demo::srv::Myimage;
using namespace std::chrono_literals;

// 3.定义节点类;
class MinimalClient: public rclcpp::Node{
  public:
    MinimalClient():Node("minimal_client"){
      // 3-1.创建客户端;
      client = this->create_client<Myimage>("image_test");
      RCLCPP_INFO(this->get_logger(),"客户端创建,等待连接服务端!");
    }
    // 3-2.等待服务连接;
    bool connect_server(){
      while (!client->wait_for_service(1s))
      {
        if (!rclcpp::ok())
        {
          RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"强制退出!");
          return false;
        }

        RCLCPP_INFO(this->get_logger(),"服务连接中,请稍候...");
      }
      return true;
    }
    // 3-3.组织请求数据并发送;
    rclcpp::Client<Myimage>::FutureAndRequestId send_request(sensor_msgs::msg::Image image1){
      auto request = std::make_shared<Myimage::Request>();
      request->client_image = image1;
      return client->async_send_request(request);
    }


  private:
    rclcpp::Client<Myimage>::SharedPtr client;
};

int main(int argc, char ** argv)
{
  // 2.初始化 ROS2 客户端;
  rclcpp::init(argc,argv);
  // 4.创建对象指针并调用其功能;
  auto client = std::make_shared<MinimalClient>();
  bool flag = client->connect_server();
  if (!flag)
  {
    RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"服务连接失败!");
    return 0;
  }
  cv::Mat img= cv::imread("/home/ubuntu/project/image_publish/src/3.jpg",1);
  sensor_msgs::msg::Image::SharedPtr img1 = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", img).toImageMsg();
  auto response = client->send_request(*img1);

  // 处理响应
  if (rclcpp::spin_until_future_complete(client,response) == rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_INFO(client->get_logger(),"请求正常处理");
    
      cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(response.get()->server_image, sensor_msgs::image_encodings::BGR8);
      cv::Mat s_img= cv_ptr->image;
      cv::resize(s_img, s_img, cv::Size(s_img.size().width,s_img.size().height));
      cv::imshow("client",s_img);
      cv::waitKey(5000);
      cv::destroyAllWindows();

  } else {
    RCLCPP_INFO(client->get_logger(),"请求异常");
  }

  // 5.释放资源。
  rclcpp::shutdown();
  return 0;
}

3.4编辑CMakeList.txt

文件添加内容如下框中的地方

cmake_minimum_required(VERSION 3.8)
project(cpp_service)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(server_demo REQUIRED)
find_package(cv_bridge REQUIRED)  #cv_brige为图片传输的重要包需要添加
find_package(OpenCV REQUIRED)

add_executable(server_cpp src/server_cpp.cpp)
target_include_directories(server_cpp PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
target_compile_features(server_cpp PUBLIC c_std_99 cxx_std_17)  # Require C99 and C++17
ament_target_dependencies(
  server_cpp
  "rclcpp"
  "std_msgs"
  "server_demo"
  "cv_bridge"
)

add_executable(client_cpp src/client_cpp.cpp)
target_include_directories(client_cpp PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
target_compile_features(client_cpp PUBLIC c_std_99 cxx_std_17)  # Require C99 and C++17
ament_target_dependencies(
  client_cpp
  "rclcpp"
  "std_msgs"
  "server_demo"
  "cv_bridge"
)
target_link_libraries(client_cpp ${OpenCV_LIBS})
target_link_libraries(server_cpp ${OpenCV_LIBS})
install(TARGETS client_cpp
  DESTINATION lib/${PROJECT_NAME})

install(TARGETS server_cpp
  DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

3.5测试结果如下

服务端接收的图片

客户端接收的图片

4.python的客户端和服务端创建及调用YOLO模型

python的客户端和服务端的如下并完成调用yolo模型进行识别,调用yolo模型我这里使用的是

ultralytics进行调用,ultralytics安装下载请自行百度

4.1创建python的服务通信包

执行以下语句创建python的包

ros2 pkg create py_server --build-type ament_python --dependencies rclpy std_msgs server_demo

4.2创建客户端和服务端的代码文件

在py_server目录下新建一个client_py.py和server_py.py文件

4.3python服务端代码

server_py.py的代码如下

import rclpy
from rclpy.node import Node
from ultralytics import YOLO
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
import numpy as np
from server_demo.srv import Myimage
# 3.定义节点类;
class MinimalService(Node):

    def __init__(self):
        super().__init__('minimal_service_py')
        # 3-1.创建服务端;
        self.srv = self.create_service(Myimage,'image_test', self.add_two_ints_callback)
        self.get_logger().info("服务端启动!")

    # 3-2.处理请求数据并响应结果。
    def add_two_ints_callback(self, request, response):
        bridge = CvBridge()
        img =bridge.imgmsg_to_cv2(request.client_image, "bgr8")
        results = model(img)
        # 获取框
        #boxes = results[0].boxes.xywh.cpu()
        # track_ids = results[0].boxes.id.int().cpu().tolist()
        # 在帧上展示结果
        annotated_frame = results[0].plot()
        bridge = CvBridge()
        image_message  = bridge.cv2_to_imgmsg(annotated_frame,encoding="bgr8")
        response.server_image = image_message
        return response


def main():
    # 2.初始化 ROS2 客户端;
    rclpy.init()
    global model
    model = YOLO('/home/ubuntu/weights/yolov8n.pt') #调用yolo官方模型
    # 4.调用spin函数,并传入节点对象;
    minimal_service = MinimalService()
    rclpy.spin(minimal_service)
    # 5.释放资源。
    rclpy.shutdown()


if __name__ == '__main__':
    main()

4.4python客户端代码

client_py.py的代码如下

import sys
import rclpy
import cv2
from rclpy.node import Node
from cv_bridge import CvBridge, CvBridgeError
from ultralytics import YOLO
from sensor_msgs.msg import Image
import numpy as np
from server_demo.srv import Myimage
# 3.定义节点类;
class MinimalClient(Node):
  
    def __init__(self):
        super().__init__('minimal_client_py')
       
        # 3-1.创建客户端;
        self.cli = self.create_client(Myimage, 'image_test')
        self.req = Myimage.Request()
        # 3-2.等待服务连接;
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('服务连接中,请稍候...')
         

    # 3-3.组织请求数据并发送;
    def send_request(self):
      
        img = cv2.imread('/home/ubuntu/project/image_publish/src/3.jpg')
    
        bridge = CvBridge()
        image_message  = bridge.cv2_to_imgmsg(img,encoding="bgr8")
        self.req.client_image =image_message
        self.future = self.cli.call_async(self.req)
 


def main():
    # 2.初始化 ROS2 客户端;
    rclpy.init()
    # 4.创建对象并调用其功能;
    minimal_client = MinimalClient()
    minimal_client.send_request()
    # 处理响应
    rclpy.spin_until_future_complete(minimal_client,minimal_client.future)
    try:
        response = minimal_client.future.result()

    except Exception as e:
        minimal_client.get_logger().info(
            '服务请求失败:%r' % (e,))
       
    else:
        bridge = CvBridge()
        cv_img = bridge.imgmsg_to_cv2(response.server_image, "bgr8")
        cv2.imshow("YOLOv8 Tracking", cv_img)
        minimal_client.get_logger().info('响应成功')
        cv2.waitKey(5000)
        cv2.destroyAllWindows()
    # 5.释放资源。
    rclpy.shutdown()


if __name__ == '__main__':
    main()

4.5setup.py文件编辑

setup.py文件内容添加如下

 'client_py = py_server.client_py:main',
  'server_py = py_server.server_py:main'

4.6运行结果

5.CPP客户端给Python服务端传图的结果如下

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值