提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
本系列文章为看古月居教学笔记博客,根据笔者自身水平进行注释,可参考https://book.guyuehome.com/
ros2的话题实现了节点间数据的单向传输,但是异步通信机制无法知道订阅者是否收到了数据(类似于UDP ),而服务能实现节点间你问我答的同步通信效果。
简单的说,服务基于调用和响应模型,而不是话题的发布者-订阅者模型。话题允许节点订阅数据流得到不断更新,而服务对具体调用的客户端提供数据。
提示:以下是本篇文章正文内容,下面案例可供参考
一、服务通信是什么?
很多时候,只有在某些情况下才会需要节点提供信息,此时由一个节点发送一个请求信息,另一个节点反馈一个应答,这样的通信机制在ros中称为服务(service)。
从服务的实现机制上看,这种你问我答的形式类似浏览器使用的客户端/服务器(C/S)模型,是一种一对多的通信模型。
ros2使用.srv文件定义请求好应答数据结构(服务接口)
二、代码实现
1.python实现
服务器节点实现
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-提供加法器的服务器处理功能
"""
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from learning_interface.srv import AddTwoInts # 自定义的服务接口
class adderServer(Node): # 继承Node类
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.adder_callback) # 创建服务器对象(接口类型、服务名、服务器回调函数)
def adder_callback(self, request, response): # 创建回调函数,执行收到请求后对数据的处理
response.sum = request.a + request.b # 完成加法求和计算,将结果放到反馈的数据中
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b)) # 输出日志信息,提示已经完成加法求和计算
return response # 反馈应答信息
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = adderServer("service_adder_server") # 创建ROS2节点对象并进行初始化
rclpy.spin(node) # 循环等待ROS2退出
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
在服务通信中,服务器端用到了回调函数,而在话题通信中却是订阅者使用回调函数,这是因为服务端不知道客户端什么时候会发送请求,而订阅者不知道自己什么时候会收到信息,因此二者用到了回调函数机制。
客户端实现
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-发送两个加数,请求加法器计算
"""
import sys
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from learning_interface.srv import AddTwoInts # 自定义的服务接口
class adderClient(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.client = self.create_client(AddTwoInts, 'add_two_ints') # 创建服务客户端对象(服务接口类型,服务名)
while not self.client.wait_for_service(timeout_sec=1.0): # 循环等待服务器端成功启动
self.get_logger().info('service not available, waiting again...')
self.request = AddTwoInts.Request() # 创建服务请求的数据对象
def send_request(self): # 创建一个发送服务请求的函数
self.request.a = int(sys.argv[1])
self.request.b = int(sys.argv[2])
self.future = self.client.call_async(self.request) # 异步方式发送服务请求
def main(args=None):
rclpy.init(args=args) # ROS2 Python接口初始化
node = adderClient("service_adder_client") # 创建ROS2节点对象并进行初始化
node.send_request() # 发送服务请求
while rclpy.ok(): # ROS2系统正常运行
rclpy.spin_once(node) # 循环执行一次节点
if node.future.done(): # 数据是否处理完成
try:
response = node.future.result() # 接收服务器端的反馈数据
except Exception as e:
node.get_logger().info(
'Service call failed %r' % (e,))
else:
node.get_logger().info( # 将收到的反馈信息打印输出
'Result of add_two_ints: for %d + %d = %d' %
(node.request.a, node.request.b, response.sum))
break
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
服务接口定义 :AddTwoInts.srv
int64 a # 第一个加数
int64 b # 第二个加数
---
int64 sum # 求和结果
客户端对象在初始化时就要传入对应的服务器端名称,及相同的服务接口类型,进行绑定操作。且调用node.future.result()会自动更新服务端反馈的接口对象,因此我们并不需要知道消息是如何发出和被接收的。
2.cpp实现
代码如下(示例):
int64 a # 第一个加数
int64 b # 第二个加数
--- #---表示之后的为响应结构
int64 sum # 求和结果
该处使用的url网络请求的数据。
三、效果
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。