ROS2服务通信

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本系列文章为看古月居教学笔记博客,根据笔者自身水平进行注释,可参考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提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值