通信接口是任何通信(话题,服务,动作)的一个规范类型。通信时收发的数据要满足接口要求
通信接口定义方式:
1 话题为单向传输,因此只要说明要发送的数据,如:
int32 x
int32 y
话题接口类型为.msg文件
2 服务为双向传输,要说明请求和应答数据,中间用—隔开:
int64 a
int64 b
---
int64 sum
服务接口类型为.srv文件
3 动作要求三部分:目标,结果,反馈:
// 目标
bool a
---
// 结果
bool finish
---
// 反馈
int32 state
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
这一接口中请求参数为bool get,应答参数为int32 x, int32 y
对于自己创建的接口,要在CMakeLists.txt中进行声明,这样编译器会自动将接口文件编译为所需的编程语言
rosidl_generate_interfaces(${PROJECT_NAME}
"srv/GetObjectPosition.srv"
)
对于创建并声明的接口,在其他程序里只需要import就可以直接使用
from learning_interface.srv import GetObjectPosition
编译器会把接口文件编译为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
发布者:
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 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 from learning_interface.msg import ObjectPosition
引入ObjectPosition接口
2 self.sub = self.create_subscription(ObjectPosition, “object_position”, self.listener_callback, 10)
创建订阅者对象,接受消息类型为ObjectPosition