ROS机器人入门第六课:服务通信自定义srv

本文介绍了ROS中的服务通信机制,包括定义srv文件、编辑配置文件、自定义服务和客户端调用过程,以及如何在ROS中实现整数求和服务的客户端和服务端编程。
摘要由CSDN通过智能技术生成

ROS机器人入门第六课:服务通信自定义srv

一、服务通信简介

服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。比如如下场景:

机器人巡逻过程中,控制系统分析传感器数据发现可疑物体或人… 此时需要拍摄照片并留存。

在上述场景中,就使用到了服务通信。

  • 一个节点需要向相机节点发送拍照请求,相机节点处理请求,并返回处理结果

与上述应用类似的,服务通信更适用于对时时性有要求、具有一定逻辑处理的应用场景。

  1. 概念

以请求响应的方式实现不同节点之间数据交互的通信模式。

  1. 作用

用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输场景。

  1. 需求

服务通信中,客户端提交两个整数至服务端,服务端求和并响应结果到客户端,请创建服务器与客户端通信的数据载体。

二、流程

srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:

  1. 按照固定格式创建srv文件

  2. 编辑配置文件

  3. 编译生成中间文件

(一)定义srv文件

服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用—分割,具体实现如下:

功能包下新建 srv 目录,添加 xxx.srv 文件,内容:

# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum

在这里插入图片描述

(三)编辑配置文件

  1. package.xml中添加编译依赖与执行依赖
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

在这里插入图片描述
2. CMakeLists.txt编辑 srv 相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

在这里插入图片描述

add_service_files(
  FILES
  AddInts.srv
)

在这里插入图片描述

generate_messages(
  DEPENDENCIES
  std_msgs
)

在这里插入图片描述
注意: 官网没有在 catkin_package 中配置 message_runtime,经测试配置也可以

  1. 编译

Python 需要调用的中间文件(…/工作空间/devel/lib/python3/dist-packages/包名/srv)

在这里插入图片描述
后续调用相关 srv 时,是从这些中间文件调用的

三、服务通信自定义srv调用

需求:

编写服务通信,客户端提交两个整数至服务端,服务端求和并响应结果到客户端。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

  1. 服务端
  2. 客户端
  3. 数据

(一)自定义srv调用流程

  1. 编写服务端实现;
  2. 编写客户端实现;
  3. 为python文件添加可执行权限;
  4. 编辑配置文件;
  5. 编译并执行。
0.vscode配置

需要像之前自定义 msg 实现一样配置settings.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:

{
    "python.autoComplete.extraPaths": [
        "/opt/ros/noetic/lib/python3/dist-packages",
    ]
}
1.客户端

以下是对您提供的ROS Python客户端代码的详细注释:

#! /usr/bin/env python
# - coding: utf-8 -*-

#1.导包
import rospy  # 导入rospy,这是Python版本的ROS客户端库,提供ROS节点的初始化、发布、订阅等功能。
from srv.srv import addnum, addnumRequest, addnumResponse  # 从srv模块导入自定义的服务消息类型。
import sys  # 导入sys模块,这个模块提供了一系列有关Python运行环境的变量和函数。

if __name__ == "__main__":

    # 检查命令行参数,确保提供了正确数量的参数。
    if len(sys.argv) != 3:
        rospy.logerr("请正确提交参数")  # 如果参数数量不对,记录一条错误日志。
        sys.exit(1)  # 退出程序。

    # 2.初始化 ROS 节点
    rospy.init_node("AddInts_Client_p")  # 初始化一个名为"AddInts_Client_p"的ROS节点。

    # 3.创建服务客户端
    client = rospy.ServiceProxy("AddInts", addnum)  # 创建一个服务客户端,用于调用名为"AddInts"的服务。服务类型为addnum。

    # 请求前,等待服务已经就绪。
    # 方式1: 使用rospy.wait_for_service函数等待服务
    # rospy.wait_for_service("addnum")
    # 方式2: 使用ServiceProxy实例的wait_for_service方法等待服务
    client.wait_for_service()

    # 4.发送请求,接收并处理响应
    # 方式1: 直接通过服务客户端传递参数调用服务。
    # resp = client(3,4)
    # 方式2: 创建特定的服务请求对象并调用服务。
    # resp = client(addnumRequest(1,5))
    # 方式3: 创建一个请求对象,设置参数。
    req = addnumRequest()
    # req.num1 = 100  # 设置请求的第一个数字(未使用优化的硬编码值)。
    # req.num2 = 200  # 设置请求的第二个数字(未使用优化的硬编码值)。

    # 优化: 使用命令行参数设置请求对象的属性。
    req.num1 = int(sys.argv[1])  # 将命令行第一个参数转换为整数并赋给请求的num1。
    req.num2 = int(sys.argv[2])  # 将命令行第二个参数转换为整数并赋给请求的num2。

    # 调用服务并等待响应。
    resp = client.call(req)
    # 输出响应结果。
    rospy.loginfo("响应结果:%d", resp.sum)  # 使用rospy.loginfo记录服务调用的结果。

代码中的ROS函数功能如下:

  • rospy.init_node('node_name'):初始化ROS节点,'node_name’是节点的名称。
  • rospy.logerr(msg):记录错误消息。
  • rospy.loginfo(msg, *args):记录信息消息,可传递参数。
  • rospy.ServiceProxy('service', service_type):定义一个服务客户端,'service’是服务名,'service_type’是服务的类型。
  • ServiceProxy.wait_for_service():服务代理实例将等待服务变为可用状态。
  • ServiceProxy.call(srv):调用服务并发送srv请求对象,等待并返回响应。

在ROS中,服务是双向通信,客户端发送请求给服务端,服务端处理请求并返回响应。这种通信方式通常用于不连续的、一次性的数据交换,例如在本例中的整数相加服务。

代码中需要修改的地方

  • from srv.srv import addnum, addnumRequest, addnumResponse:from 包名.srv import 自定义srv文件名, 自定义srv文件名Request , 自定义srv文件名Response
  • client = rospy.ServiceProxy("AddInts", addnum):client = rospy.ServiceProxy(“AddInts”, 自定义srv文件名Request)
  • rospy.wait_for_service("addnum"):rospy.wait_for_service(“自定义srv文件名”)

注意sys.argv[0]是python文件名


当客户端先于服务端启动,会抛出异常

如果要求客户端先于服务端启动,不要抛出异常而是挂起,等待服务启动后,再次发送请求

实现:
ROS中内置了相关函数,这些函数可以判断服务器的状态,如果服务没有启动,那么就让客户端挂起

  • 方式1: 使用rospy.wait_for_service函数等待服务
rospy.wait_for_service("addnum")
  • 方式2: 使用ServiceProxy实例的wait_for_service方法等待服务
client.wait_for_service()

2.服务端

以下是您提供的ROS服务端Python脚本的注释详情:

#! /usr/bin/env python
# - coding: utf-8 -*-

# 1. 导包
import rospy  # 导入rospy模块,提供ROS节点的基本功能。
from srv.srv import addnum, addnumRequest, addnumResponse  # 从srv包导入自定义服务消息类型。

# 定义服务处理函数
def doReq(req):
    # 解析请求数据
    sum = req.num1 + req.num2  # 将请求对象中的num1和num2相加。
    # 记录信息,显示请求的数据。
    rospy.loginfo("提交的数据:num1 = %d, num2 = %d, sum = %d", req.num1, req.num2, sum)

    # 创建响应对象,设置结果,并返回该响应对象。
    resp = addnumResponse(sum)  # 使用相加后的和初始化addnumResponse对象。
    return resp  # 返回响应对象。

if __name__ == "__main__":
    # 2. 初始化 ROS 节点
    rospy.init_node("addints_server_p")  # 初始化一个名为"addints_server_p"的ROS节点。

    # 3. 创建服务对象
    server = rospy.Service("AddInts", addnum, doReq)  # 创建一个名为"AddInts"的服务,指定服务消息类型为addnum,处理函数为doReq。

    # 4. 回调函数处理请求并产生响应
    # 这部分由ROS内部管理,当有服务请求到来时,doReq函数将被调用。

    # 5. spin 函数
    rospy.spin()  # 进入循环,等待服务请求,不会退出直到节点被显式关闭。

ROS函数功能如下:

  • rospy.init_node('node_name'):初始化一个ROS节点,'node_name’是节点的名称。这是ROS程序的起始步骤,注册节点到ROS master。
  • rospy.loginfo(msg, *args):记录日志类型为info的消息,功能类似于打印输出信息,但它同时会发送到ROS系统的日志记录系统中。
  • rospy.Service('service_name', service_type, handler):创建一个新的服务。'service_name’是服务的名称,'service_type’是服务的类型,'handler’是当有请求到来时处理该请求的函数。
  • rospy.spin():使你的节点进入阻塞等待状态,等待并处理回调函数,直到节点被关闭。它通常被用于保持你的程序运行并等待回调函数的触发。

在ROS中服务是一种双向通信方式,当客户端调用服务并发送请求时,服务端会处理这个请求并返回一个响应。您的代码中的doReq函数就是服务端处理请求的回调函数。

3.设置权限

终端下进入 scripts 执行:chmod +x *.py

4.配置 CMakeLists.txt

CMakeLists.txt

catkin_install_python(PROGRAMS
  scripts/AddInts_Server_p.py 
  scripts/AddInts_Client_p.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

在这里插入图片描述

5.执行

流程:

  • 需要先启动服务:rosrun 包名 服务

  • 然后再调用客户端 :rosrun 包名 客户端 参数1 参数2

结果:

会根据提交的数据响应相加后的结果。

在这里插入图片描述

  • 33
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值