Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。
本章将介绍如何通过服务通信的方式实现节点数据交换以及ROS相关指令
0.服务通信概念
在ros中,一个节点想要获取某种服务(例如:一个节点想要获取此时的相机数据,节点就需要向相机发送一个请求,而相机接收到请求后可以根据消息类型将数据类型返回),这就是基本的服务通信使用场景。
以请求响应的方式实现不同节点间的数据交互
我们现阶段也不需要了解具体这代表什么意思,只需要知道:
client客户端/server服务端先后在rosmaster中注册本身信息,然后通过相同话题匹配.
- server 与 client 的启动无先后顺序要求
- server 与 client 都可以有多个
- server 与 client 连接后不再需要rosmaster,也就是说仅在尝试连接的时候需要rosmaster
1.自定义srv消息
srv消息是服务端与客户端之间通信的一个数据载体,可用数据类型与std_msgs里的数据类型一致,但需要自己定义.
步骤大概为以下几步:
- 根据需要定义srv格式消息
- 修改配置文件
- 编译生成中间文件并引用
1.1定义srv格式消息
这是一个自己定义的srv的消息格式
因为要实现的是两个数相加,所以这样定义。
其中—上方为client客户端发送的消息格式,下方为服务端响应的消息格式。
# 客户端请求
int32 num1
int32 num2
---
# 服务端响应
int32 ans
1.2修改配置文件
- 和定义msg类似,也要先修改功能包目录下的package.xml,
其中54行的message_generation是编译时的消息软件包
而59行message_runtime是运行时的消息软件包 -
在CMakeList中找到这些地方并修改
# 1.编译时的依赖包 find_package(catkin REQUIRED COMPONENTS rospy std_msgs message_generation ) # 2.加入自己定义的srv文件名字 add_service_files( FILES Addints.srv ) # 3.编译包时的消息依赖 generate_messages( DEPENDENCIES std_msgs ) # 4.加入message_runtime,但官网没有这一步似乎也可以. catkin_package(**chmod +x py文件** CATKIN_DEPENDS rospy std_msgs message_runtime )
-
编译一下,可以在这个路径中找到刚刚编译完的中间件
之后调用的方法如下:
至于为什么要import * 我们可以先来看看编译完产生的文件是什么样的:# from packagename.srv import *
其产生了一个srv的中间件,出现了三个类,我们之后这三个类都需要使用到,所以一般都是直接import*
2.自定义srv服务通信客户端python实现:
先来分析下作为一个客户端我们需要做什么事:
- 初始化ros节点
- 创建请求对象,设置通信话题
- 请求响应,获得响应结果
import rospy
import lesson3_srv.srv import *
rospy.init_node("sum_client")
client=rospy.ServiceProxy("sum2",Addints)
if(len(sys.argv)!=3):
rospy.logerr("参数不对")
sys.exit(1)
num=int(sys.argv[1])
num2=int(sys.argv[2])
response=client.call(num,num2)
rospy.loginfo("%d",response.ans)
这里先导入了rospy的包以及消息类型,初始化了节点信息与话题。
创建了请求服务的对象,serviceprovy(话题,srv消息)
对传入的参数进行了一个处理
clint.call返回类型为自定义消息类型的格式,call(srv中的参数)最后处理返回的消息
这就是客户端实现,当然还有一些优化内容,等服务端实现完在提
3.自定义srv服务通信服务端python实现:
先来分析下作为一个服务端我们需要做什么事:
- 初始化节点
- 设置订阅话题
- 设置处理消息的回调函数
import rospy
from lesson3_srv.srv import *
def doNum(request):
num1=request.num1
num2=request.num2
sum=num1+num2
response=AddintsResponse()
response.ans=sum
rospy.loginfo("%d %d %d",request.num1,request.num2,response.ans)
return response
rospy.init_node("sum")
server=rospy.Service("sum2",Addints,doNum)
rospy.spin()
这里先导包
然后通过service(话题名称,srv消息类型,回调函数)创建服务对象
刚刚客户端传入的数据,会作为回调函数的参数
先将其取出,之后通过AddintsResponse的方法创建一个返回对象,改变ans后返回此时的返回值是给了客户端
4.优化客户端
这里的客户端有个很小的问题,仅能在服务器启动后进行通信,若服务器没有启动,而先启动了客户端就会出错,ros官方提供了两个解决方法,二者选其一即可
# rospy.wait_for_service(话题名称)
# client.wait_for_service()
所以改进的客户端代码如下:
import rospy
import sys
from lesson3_srv.srv import *
rospy.init_node("sum_client")
client=rospy.ServiceProxy("sum2",Addints)
if(len(sys.argv)!=3):
rospy.logerr("参数不对")
sys.exit(1)
num=int(sys.argv[1])
num2=int(sys.argv[2])
#client.wait_for_service()
rospy.wait_for_service("sum2")
response=client.call(num,num2)
rospy.loginfo("%d",response.ans)
5.启动运行
- 先添加可执行权限 chmod +x py文件
-
之后配置一下CMakeList.txt
catkin_install_python( PROGRAMS scripts/demo01_server.py scripts/demo01_client.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
-
rosrun lesson3_srv demo01_client.py rosrun lesson3_srv demo01_server.py
运行效果:传入2 3 返回值为 5
文章来源:https://www.toymoban.com/news/detail-436639.html
至此服务通信内容结束文章来源地址https://www.toymoban.com/news/detail-436639.html
到了这里,关于【ROS】如何让ROS中节点实现数据交换Ⅱ --服务通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!