文章目录
前言
记录一下ROS学习中的话题通信,我用的Ubuntu是16.04对应的ROS版本是kinetic。
一、服务通信
服务通信是基于请求响应模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A,可以理解为:节点A是你自己,节点B是保洁公司,当你需要人帮你打扫卫生的话你就去打电话给保洁公司一个请求,保洁公司就会响应你的请求。
二、ROS中代码实现与文件配置
1. 服务通信自定义srv
1.创建srv文件并定义信息格式
1在功能包下创建srv文件夹,并在文件下创建以 .srv结尾的文件
2.服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用—分割
2.功能包下package.xml中添加编译依赖与执行依赖
与话题通信类似在package.xml中添加编译依赖与执行依赖
3.功能包下CMakeLists.txt编辑 srv 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
#这里的是编译功能包依赖的package
add_service_files(
FILES
AddInts.srv
)
#添加自己定义的srv文件
generate_messages(
DEPENDENCIES
std_msgs
)
#编译自定义的srv文件需要依赖于std_msgs
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES plunmbing_server_client
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
#执行时依赖
)
最后在当前功能包所在的工作空间下执行一下
catkin_make
2.客户端代码实现
编写完代码在文件所在的地址下打开终端输入chmod +x 文件名来给py文件添加可执行权限
#! /usr/bin/env python
# _*_ coding:utf-8 _*_
import rospy
from plunmbing_server_client.srv import *
import sys
"""
客户端:组织并提交请求,处理服务端响应
1.导包
2.初始化ROS节点
3.创建客户端对象
4.组织请求数据,并发布请求
5.处理响应
优化实现:
可以在执行节点时,动态传入参数
问题:
客户端先于服务端启动,会抛出异常
客户端先于服务端启动,不要抛出异常而是挂起,等待服务启动以后,再发送请求
ROS中内置了相关函数,这些函数可以判断服务器的状态,如果服务器没有启动,那么
就让客户端挂起
解决:
client.wait_for_service()
rospy.wait_for_service("dasao")
"""
if __name__ == "__main__":
if len(sys.argv)!= 3:
rospy.logerr("传入的参数个数不对")
sys.exit(1)
# 2.初始化ROS节点 (节点名)
rospy.init_node("zwt")
# 3.创建客户端对象 (话题名,数据类型)
client = rospy.ServiceProxy("dasao",AddInts)
# 4.组织请求数据,并发布请求
#解析键盘传入的参数
num1 = int(sys.argv[1])
num2 = int(sys.argv[2])
#等待服务启动
#client.wait_for_service()
rospy.wait_for_service("dasao")
response = client.call(num1,num2)
# 5.处理响应
rospy.loginfo("响应的数据:sum=%d",response.sum)#
服务端代码实现
编写完代码在文件所在的地址下打开终端输入chmod +x 文件名来给py文件添加可执行权限
#! /usr/bin/env python
# _*_ coding:utf-8 _*_
# 第二行代码,编译中文不会报错
import rospy
from plunmbing_server_client.srv import *
"""
服务端:解析客户端请求,产生响应。
1.导包
2.初始化ROS节点
3.创建服务端对象
4.处理逻辑(回调函数)
5.spin()
"""
#回调函数:处理请求产生响应
def donum(request):
#解析提交的两个整数
num1 = request.num1
num2 = request.num2
#求和
sum = num1 + num2
#将结果封装进响应
response = AddIntsResponse()
response.sum = sum
rospy.loginfo("服务器处理的数据:num1=%d,num2=%d,sum=%d",num1,num2,sum)
return response
if __name__ == "__main__":
# 2.初始化ROS节点
rospy.init_node("zsl")
# 3.创建服务端对象 (话题名,话题类型,回调函数)
server = rospy.Service("dasao",AddInts,donum)
rospy.loginfo("服务已经启动了")
# 4.处理逻辑(回调函数)
# 5.spin()
rospy.spin()
1.通过程序实现客户端与服务端通信
1.先运行roscore
2.运行 服务端程序 rosrun 功能包名 文件名
3.运行 客户端程序 rosrun 功能包名 文件名
4.实验结果如下所示
2.用rosserver通过终端向服务端发送数据
1.先运行roscore
2. 运行 服务端程序 rosrun 功能包名 文件名
3.再新打开一个终端输入 rosserver回车可以看到rosserver的使用
4.使用rosserver list列出服务的哪些话题,可以看到我们服务端程序里写的dasao
5.输入rosserver call dasao(daosao后有一个空格)后按下tab键补全,然口控制左右键向服务端发送的数据,按下回车
6.实验结果