• ROS2自学笔记:通信接口


    通信接口是任何通信(话题,服务,动作)的一个规范类型。通信时收发的数据要满足接口要求

    通信接口定义方式:
    1 话题为单向传输,因此只要说明要发送的数据,如:

    int32 x
    int32 y
    
    • 1
    • 2

    话题接口类型为.msg文件
    2 服务为双向传输,要说明请求和应答数据,中间用—隔开:

    int64 a
    int64 b
    ---
    int64 sum
    
    • 1
    • 2
    • 3
    • 4

    服务接口类型为.srv文件
    3 动作要求三部分:目标,结果,反馈:

    // 目标
    bool a
    ---
    // 结果
    bool finish
    ---
    // 反馈
    int32 state
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ROS2官方自带通信接口:
    打开位置:computer->other location->opt->ros->foxy->share
    话题接口(msg):
    在这里插入图片描述
    更简单的办法是使用终端指令

    ros2 interface list

    显示所有接口
    在这里插入图片描述

    查询接口定义

    ros2 interface show (接口名称)

    在这里插入图片描述

    查找某一个功能包里的接口

    ros2 interface package (功能包名称)

    在这里插入图片描述

    在之前学习服务的文章里有一个图像识别并获取位置信息的程序(可见https://blog.csdn.net/Raine_Yang/article/details/125359357?spm=1001.2014.3001.5501)这一程序中实现的通信接口如下:

    bool get
    ---
    int32 x
    int32 y
    
    • 1
    • 2
    • 3
    • 4

    这一接口中请求参数为bool get,应答参数为int32 x, int32 y

    对于自己创建的接口,要在CMakeLists.txt中进行声明,这样编译器会自动将接口文件编译为所需的编程语言

    rosidl_generate_interfaces(${PROJECT_NAME}
    	"srv/GetObjectPosition.srv"
    )
    
    • 1
    • 2
    • 3

    对于创建并声明的接口,在其他程序里只需要import就可以直接使用

    from learning_interface.srv import GetObjectPosition
    
    • 1

    编译器会把接口文件编译为python文件,位置
    dev_ws -> install -> learning_interface -> lib -> python3.8 ->site_packages -> learning_interface -> srv

    自动生成的python文件
    在这里插入图片描述
    C++文件位置:
    dev_ws -> install -> learning_interface -> include -> learning_interface -> srv

    自定义接口实现话题通信图像识别:
    这一次我们修改之前图像识别的示例程序(原程序:https://blog.csdn.net/Raine_Yang/article/details/125349724?spm=1001.2014.3001.5501)

    通信接口:

    int32 x
    int32 y
    
    • 1
    • 2

    发布者:

    import rclpy
    from rclpy.node import Node
    from sensor_msgs.msg import Image
    from learning_interface.msg import ObjectPosition
    from cv_bridge import CvBridge
    import cv2
    import numpy as np
    
    lower_red = np.array([0, 90, 128])
    upper_red = np.array([180, 255, 255])
    
    class ImageSubscriber(Node):
    	def __init__(self, name):
    		super().__init__(name)
    		self.sub = self.create_subscription(Image, 'image_raw', self.listener_callback, 10)
    		self.cv_bridge = CvBridge()
    		self.pub = self.create_publisher(ObjectPosition, 'object_position', 10)
    
    	def object_detect(self, image):
    		hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    		mask_red = cv2.inRange(hsv_img, lower_red, upper_red)
    		contours, hierarchy = cv2.findContours(mask_red, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    
    		for cnt in contours:
    			 if cnt.shape[0] < 150:
    			 	continue
    
    			 (x, y, w, h) = cv2.boundingRect(cnt)
    			 cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)
    			 cv2.circle(image, (int(x + w / 2), int(y + h / 2), 5, (0, 255, 0), -1)
    			 self.objectX = (x + w / 2)
    			 self.objectY = (y + h / 2)
    			 cv2.imshow("object", image)
    			 cv2.waitKey(10)
    
    	
    	def listener_callback(self, data):
    		self.get_logger().info('Receiving video frame')
    		image = self.cv_bridge.imgmsg_to_cv2(data, 'bgr8')
    		self.object_detect(image)
    		position = ObjectPosition()
    		position.x = int(objectX)
    		position.y = int(objectY)
    		self.pub.publish(position)
    
    def main(args=None):
    	rclpy.init(args=args)
    	rclpy.ImageSubscriber("interface_position_pub")
    	rclpy.spin(node)
    	node.destroy_node()
    	rclpy.shutdown()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    1 from learning_interface.msg import ObjectPosition
    引入接口

    2 self.pub = self.create_publisher(ObjectPosition, ‘object_position’, 10)
    创建发布者对象,发布消息类型为ObjectPosition

    3 position = ObjectPosition()
    position.x = int(objectX)
    position.y = int(objectY)
    self.pub.publish(position)
    position实例化一个ObjectPosition接口,该接口参数为两个int值x和y,在这里进行赋值并发布

    订阅者:

    import rclpy
    from rclpy.node import Node
    from std_msgs.msg import String
    from learning_interface.msg import ObjectPosition
    
    class SubscriberNode(Node):
    	def __init__(self, name):
    		super().__init__(name)
    		self.sub = self.create_subscription(ObjectPosition, "object_position", self.listener_callback, 10)
    
    	def listener_callback(self, msg):
    		self.get_logger().info('Target Position: "(%d, %d)"' % (msg.x, msg.y))
    
    
    def main(args=None):
    	rclpy.init(args=args)
    	node = SubscriberNode("interface_position_sub")
    	rclpy.spin(node)
    	node.destroy_node()
    	rclpy.shutdown()
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1 from learning_interface.msg import ObjectPosition
    引入ObjectPosition接口

    2 self.sub = self.create_subscription(ObjectPosition, “object_position”, self.listener_callback, 10)
    创建订阅者对象,接受消息类型为ObjectPosition

  • 相关阅读:
    【面试题 01.09. 字符串轮转】
    vscode忽略某些文件
    SpringCloud 学习笔记(3 / 3)
    web课程设计 基于html+css+javascript+jquery女性化妆品商城
    STM32 CAN过滤器标识符学习笔记
    Win11声卡驱动如何更新?Win11声卡驱动更新方法
    线程安全
    前端研习录(10)——CSS相对定位、绝对定位、固定定位以及Z-index属性、opacity属性讲解及示例说明
    Java-对象到底占多少个字节?计算规则是什么?
    JavaScript数字、数字方法
  • 原文地址:https://blog.csdn.net/Raine_Yang/article/details/125416575