ROS话题和服务(topic就像UDP,service就像TCP)

2023-05-16

看这张图怎么感觉服务有种TCP的味道,可靠连接,三次握手,话题像UDP,发出去我就不管了。看来服务不单单是我请求你响应那么简单,还得保证我收到。

 

摘自:https://blog.csdn.net/moshuilangting/article/details/86484042

ROS话题和服务

墨水兰亭 2019-01-16 15:22:36 3858 收藏 25

分类专栏: 人工智障

版权

基本概念:

ROS中有四种通信方式:Topic(话题)、Service(服务)、Parameter Serivce(参数服务器)、Actionlib(动作库)。

所谓通信,ros中每个程序包是一个node(节点),通信就是节点与节点间的数据传输,在这里简要介绍一下话题与服务

话题与服务的简单比较
Topic话题Service服务

节点A——>话题T (节点A发布话题T)

话题T——>节点B (节点B订阅话题T)

节点A——>服务节点S (节点A请求服务S)

服务节点S<——节点A (服务S响应节点A)

异步通讯   

A发了朋友圈,B刷朋友圈的时候看到了

A发布话题,B订阅话题,朋友圈是话题T

同步通讯 

A发了朋友圈,并让S去给A点赞,S点赞完告诉A。

A请求S点赞,B响应A的请求。A是客户端节点,S是服务节点

话题内容的数据格式——msg

服务的通信数据格式——srv
用于连续高频的数据发布和接收:雷达测障碍物、里程计等用于偶尔调用的功能或执行某一项功能:拍照、语言识别等

实现:

在catkin_ws下我们创建一个新的ros包

 
  1. cd catkin_ws

  2. catkin_create_pkg h_h std_msgs rospy roscpp

这条命令的意思是,切换到catkin_ws目录下,创建ROS包(roscreate-pkg),包的名称是h_h,带有std_msgs rospy roscpp三个依赖项,会在src下生成h_h的文件夹,h_h文件夹下有include、src两个文件夹和CMakeLists.txt、package.xml两个文件

在表格中提到了数据格式,msg和srv。在实现话题通信和服务通信之前,先来看一看msg数据格式。

使用msg:

步骤:建立.msg文件——修改package.xml——修改CMakeLists.txt——编译

建立.msg文件:

 
  1. cd ~/catkin_ws/src/h_h //创建的包的目录下

  2. mkdir msg //新建msg文件夹

  3. touch abc.msg //建立abc.msg的文件

双击打开abc.msg(记住这个名字) 定义数据类型,举例:

字符串的s,浮点型的x,浮点型的y。

修改package.xml:

我们打开h_h文件夹下的package.xml文件,将下面两句话取消注释:

 
  1. <build_depend>message_generation</build_depend>

  2. <exec_depend>message_runtime</exec_depend>

第一句用于build(构建)、第二句用于exec(执行)。

有效的package.xml文件:

 
  1. <?xml version="1.0"?>

  2. <package format="2">

  3. <name>h_h</name>

  4. <version>0.0.0</version>

  5. <description>The h_h package</description>

  6.  
  7. <maintainer email="jtl@todo.todo">jtl</maintainer>

  8.  
  9. <license>TODO</license>

  10.  
  11. <build_depend>message_generation</build_depend>

  12. <exec_depend>message_runtime</exec_depend>

  13. <buildtool_depend>catkin</buildtool_depend>

  14. <build_depend>roscpp</build_depend>

  15. <build_depend>rospy</build_depend>

  16. <build_depend>std_msgs</build_depend>

  17. <build_export_depend>roscpp</build_export_depend>

  18. <build_export_depend>rospy</build_export_depend>

  19. <build_export_depend>std_msgs</build_export_depend>

  20. <exec_depend>roscpp</exec_depend>

  21. <exec_depend>rospy</exec_depend>

  22. <exec_depend>std_msgs</exec_depend>

  23.  
  24. <export>

  25.  
  26. </export>

  27. </package>

修改CMakeLists.txt:

同样在h_h文件夹下,打开CMakeLists.txt,取消一些注释并添加:

 
  1. find_package(catkin REQUIRED COMPONENTS

  2. roscpp

  3. rospy

  4. std_msgs

  5. message_generation ##新添加

  6. )

 
  1. add_message_files( ##取消注释

  2. FILES ##取消注释

  3. abc.msg ##新添加,就是我们新建的.msg文件

  4. )

 
  1. generate_messages( ##取消注释

  2. DEPENDENCIES ##取消注释

  3. std_msgs ##取消注释

  4. )

 
  1. catkin_package(

  2. CATKIN_DEPENDS message_runtime roscpp rospy std_msgs #取消注释,添加message_runtime

  3. )

编译:修改完package.xml和CMakeLists.txt,我们回到catkin_ws 目录下进行编译(catkin_make)

 
  1. cd ~/catkin_ws

  2. catkin_make

话题发布和订阅实现:

我们在h_h文件夹下,新建test文件夹

 
  1. roscd h_h/

  2. mkdir test

  3. cd test

在test文件夹下新建talker.py

 
  1. #!/usr/bin/env python

  2. #coding=utf-8

  3.  
  4. import rospy #添加rospy的库

  5. from std_msgs.msg import String #系统的std_msgs文件夹下有已经定义的String类,没用到

  6. from h_h.msg import * #h_h文件夹下msg文件夹下,abc.msg,这句话就是把abc加载进来

  7.  
  8. def talker():

  9. #节点发布‘detection’话题,使用了abc类型,queue_size 是缓存的长度

  10. pub = rospy.Publisher('detection',abc,queue_size=10)

  11. #初始化节点 'talker' ,anonymous=True用于保证节点名称唯一

  12. rospy.init_node('talker', anonymous=True)

  13. rate = rospy.Rate(1) # 1hz

  14. while not rospy.is_shutdown(): #循环发送

  15. #rospy.get_time() 获得时间

  16. hello_str = "hello world %s" % rospy.get_time()

  17. #打印日志信息表

  18. rospy.loginfo(hello_str)

  19. x=1.0

  20. y=2.0

  21. #话题发布了三个参数

  22. pub.publish(hello_str,x,y)

  23. #速率控制

  24. rate.sleep()

  25.  
  26. if __name__ == '__main__':

  27. try:

  28. talker()

  29. except rospy.ROSInterruptException:

  30. pass

代码中有注释,这里详细说一下参数的传递,我们之前在h_h/msg/文件夹下建立了abc.msg,在头文件中加载abc,然后在pub=rospy.Publisher('detection',abc,queue_size=10)中第一次提到了abc,我们发布话题需要有abc类型的参数传递。

最后在pub.publish(hello_str,x,y)中向外发布了三个参数hello_str,x,y,记得我们在abc.msg中填入了什么?string s,float32 x,float32 y。所以publish发布的三个参数正好对应abc.msg中的参数。

在test文件夹下新建listener.py

 
  1. #!/usr/bin/env python

  2. #coding=utf-8

  3.  
  4. import rospy #添加rospy的库

  5. from std_msgs.msg import String #系统的std_msgs文件夹下有已经定义的String类,没用到

  6. from h_h.msg import * #h_h文件夹下msg文件夹下,abc.msg,这句话就是把abc加载进来

  7.  
  8. def callback(data):

  9. #参数传递,data中就是abc.msg中的参数

  10. rospy.loginfo('I heard %s', data.s)

  11. print(data.x,data.y)

  12.  
  13. def listener():

  14. #初始化节点'listener',保证节点唯一,因此可以有多个listener.py可以同时运行

  15. rospy.init_node('listener', anonymous=True)

  16. #节点订阅detection’话题,使用了abc类型,调用callback函数

  17. rospy.Subscriber('detection', abc, callback)

  18. #rospy.spin()简单保持你的节点一直运行,直到程序关闭

  19. rospy.spin()

  20.  
  21.  
  22. if __name__ == '__main__':

  23. listener()

我们来看一下运行结果:

分别在三个终端中输入

roscore
rosrun h_h talker.py
rosrun h_h listener.py

结果如图:

我们可以看到在talker中 ,打印了日志信息,在listener中打印了日志信息,也输出了data.x和data.y。

使用srv:

这一步与msg的方法极其相似:

步骤:建立.srv文件——修改package.xml——修改CMakeLists.txt——编译

建立.srv文件:

 
  1. cd ~/catkin_ws/src/h_h //创建的包的目录下

  2. mkdir srv //新建srv文件夹

  3. touch qq.srv //建立qq.srv的文件

双击打开qq.srv(同样记住这个名字) 定义数据类型,举例:

注意有float32 a 和float32 b,中间‘---’,下面是float32 Sum和string qq。简单说明一下:

srv类型的数据传递是双向的,上面部分a和b是客户端传递给服务器的数据,‘---’ 的下面部分是服务器回传给客户端的数据。

修改xml文件同msg类型的一模一样;

修改CMakeLists.txt同msg类型的类似,唯一的不同点是不需要add_message_files而需要add_service_files

 
  1. add_service_files( #取消注释

  2. FILES #取消注释

  3. qq.srv #添加,我们新建的.srv文件

  4. )

当然如果msg类型和srv类型都有,则这两个都需要,CMakeLists.txt 如下。

 
  1. cmake_minimum_required(VERSION 2.8.3)

  2. project(h_h)

  3.  
  4. find_package(catkin REQUIRED COMPONENTS

  5. roscpp

  6. rospy

  7. std_msgs

  8. message_generation

  9. )

  10.  
  11. ## Generate messages in the 'msg' folder

  12. add_message_files(

  13. FILES

  14. abc.msg

  15. )

  16.  
  17. ## Generate services in the 'srv' folder

  18. add_service_files(

  19. FILES

  20. qq.srv

  21. )

  22.  
  23.  
  24.  
  25. ## Generate added messages and services with any dependencies listed here

  26. generate_messages(

  27. DEPENDENCIES

  28. std_msgs

  29. )

  30.  
  31. catkin_package(

  32. CATKIN_DEPENDS message_runtime roscpp rospy std_msgs

  33. )

  34.  
  35. include_directories(

  36. ${catkin_INCLUDE_DIRS}

  37. )

  38.  

编译:修改完package.xml和CMakeLists.txt,我们回到catkin_ws 目录下进行编译(catkin_make)

 
  1. cd ~/catkin_ws

  2. catkin_make

服务请求和响应的实现:

同样在test文件夹下,新建h_h_server.py:

 
  1. #!/usr/bin/env python

  2. #coding=utf-8

  3.  
  4. #加载h_h.srv文件夹下的内容,即qq.srv

  5. from h_h.srv import *

  6. import rospy

  7.  
  8.  
  9. NAME = 'add_two_ints_server'

  10. def add_two_ints(req):

  11. #从客户端读入req,req.a和req.b对应了qq.srv中的a和b

  12. print("Returning [%s + %s = %s]" % (req.a, req.b, (req.a + req.b)))

  13. sum = req.a + req.b

  14. q='1234567'

  15. #从服务器返回两个参数给客户端,sum和q是qq.srv中的Sum和qq

  16. return qqResponse(sum,q)

  17.  
  18. def add_two_ints_server():

  19. rospy.init_node(NAME) #初始化一个节点

  20. #构建一个服务,add_two_ints 是服务的名称,qq是参数(qq.srv),add_two_ints是调用函数

  21. s = rospy.Service('add_two_ints', qq, add_two_ints)

  22. print "Ready to add Two Ints"

  23. # 保持运行

  24. rospy.spin()

  25.  
  26. if __name__ == "__main__":

  27. add_two_ints_server()

新建h_h_clinet.py:

 
  1. #!/usr/bin/env python

  2. #coding=utf-8

  3. import sys

  4. import os

  5.  
  6. from h_h.srv import *

  7. import rospy

  8.  
  9. ## add two numbers using the add_two_ints service

  10. ## @param x int: first number to add

  11. ## @param y int: second number to add

  12.  
  13. def add_two_ints_client(x, y):

  14. #等待服务

  15. rospy.wait_for_service('add_two_ints')

  16. try:

  17. #创建服务的处理句柄,即客户端调用'add_two_ints'服务,qq是参数数据格式

  18. add_two_ints = rospy.ServiceProxy('add_two_ints', qq)

  19.  
  20. print("Requesting %s+%s" % (x, y))

  21.  
  22. # simplified style,简单方式,将两个参数传给服务器,返回resp1是服务器的返回值

  23. resp1 = add_two_ints(x, y)

  24.  
  25. # formal style 正式的方式,resp2是服务器的返回值

  26. resp2 = add_two_ints.call(qqRequest(x, y))

  27.  
  28. #校验

  29. if not resp1.Sum == (x + y):

  30. raise Exception("test failure, returned sum was %s" % resp1.Sum)

  31. if not resp2.Sum == (x + y):

  32. raise Exception("test failure, returned sum was %s" % resp2.Sum)

  33.  
  34.  
  35. #返回值,resp1.Sum 对应qq.srv中的Sum,并没有返回resp1.qq

  36. return resp1.Sum

  37. except rospy.ServiceException, e:

  38. print("Service call failed: %s" % e)

  39.  
  40.  
  41. def usage():

  42. return "%s [x y]" % sys.argv[0]

  43.  
  44.  
  45. if __name__ == "__main__":

  46. #rosrun时候的输入附带参数

  47. argv = rospy.myargv()

  48. if len(argv) == 1:

  49. import random

  50. x = random.randint(-50000, 50000)

  51. y = random.randint(-50000, 50000)

  52. elif len(argv) == 3:

  53. try:

  54. x = int(argv[1])

  55. y = int(argv[2])

  56. except:

  57. print usage()

  58. sys.exit(1)

  59. else:

  60. print usage()

  61. sys.exit(1)

  62. print ("%s + %s = %s" % (x, y, add_two_ints_client(x, y)))

我们来看一下运行结果:

分别在三个终端中输入

roscore
rosrun h_h h_h_server.py 
rosrun h_h h_h_clinet.py 

结果如图:

在clinet中请求了两次服务器的响应(简单方法和正式方法),服务器的程序每运行一个clinet要运算两次。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS话题和服务(topic就像UDP,service就像TCP) 的相关文章

  • Asp.net core 2.0条件服务或条件连接字符串

    我正在使用 Asp net core 2 0 开发 Web api 现在我需要的是使用不同的连接字符串 这些字符串将在用户的标头中指定 我以前见过这个 不是直接关于这个问题 app Use async context next gt if
  • 如何在 Docker-Compose 中一起使用主机网络和任何其他用户定义的网络?

    我想将 Docker Compose 文件中定义的两个 Docker 容器相互连接 app and db 其中之一 app 也应该连接到host网络 容器应连接到通用的用户定义网络 appnet or default 使用嵌入式DNS来自
  • C# - 从客户端检查 TCP/IP 套接字状态

    我想为我的 TCP IP 客户端类提供 CheckConnection 函数 以便我可以检查是否发生了错误 我自己的客户端断开连接 服务器断开连接 服务器卡住等 我有类似的东西 bool isConnectionActive false i
  • 如何模拟 TCP/IP 错误?

    在多层应用程序上 我需要模拟各种 TCP IP 错误来测试一些重新连接代码 有谁知道我可以使用什么工具 基于 Windows 来实现此目的 谢谢 Scapy http secdev org projects scapy 允许您控制数据包的各
  • 为什么通过UdpClient发送会导致后续接收失败?

    我正在尝试创建一个 UDP 服务器 它可以向所有向其发送消息的客户端发送消息 真实情况要复杂一些 但最简单的方法是将其想象为一个聊天服务器 之前发送过消息的每个人都会收到其他客户端发送的所有消息 所有这一切都是通过UdpClient 在单独
  • 如何在我的类型类中访问我的服务(DependencyInjection)?

    我创建了一个服务 DependencyInjection 并在控制器上将其用作 this gt get service name gt someMethod 我想知道如何在我的表单类上使用它 这是我的课程示例形式 namespace Com
  • OSGi 应用程序设计 - 我是否滥用服务框架? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 在我们正在开发的应用程序中 我有一个供数据提供程序组件实现的通用接口 并且我将这些提供程序作为服务连接起来 我的一位同事建议 最好只创建一项可以
  • AngularJS 服务 http 成功函数使用错误的“this”范围

    a 的成功函数 http put无权访问this内部调用的服务的范围 我需要在 PUT 请求的回调中更新服务的属性 这是我在服务中尝试做的事情的简化示例 var myApp angular module myApp function rou
  • 使用 STUN 打孔

    我目前正在尝试通过 Internet 发送 UDP 消息 并且必须为端点 A 和 B 都位于 NAT 后面 设置防火墙 为此 我想使用 STUN 服务器进行打孔 当 A 创建对 STUN 服务器的请求 例如 私有 85 1 1 12 600
  • Python套接字模块:Recv()数据响应被切断

    解释 我目前正在尝试使用 python 脚本控制智能电源板 为了实现这一点 我使用了带有套接字模块的 TCP 连接 大约 75 的情况下 我会得到我正在寻找的响应 数据 并且一切都运行良好 然而 大约 25 的情况下 响应会以完全相同的长度
  • 在 Golang Server 中接受持久的 tcp 连接

    我正在尝试使用 Go 并且想创建一个 TCP 服务器 我可以通过 telnet 访问该服务器 发送命令并接收响应 const CONN HOST localhost CONN PORT 3333 CONN TYPE tcp func mai
  • 您可以bind()和connect() UDP连接的两端吗

    我正在编写一个点对点消息队列系统 它必须能够通过 UDP 运行 我可以任意选择一侧或另一侧作为 服务器 但这似乎不太正确 因为两端都从另一端发送和接收相同类型的数据 是否可以绑定 和连接 两端 以便它们只能彼此发送 接收 这似乎是一种非常对
  • 多个Android IntentService可以同时运行吗?

    据我了解 一个IntentService一次只能处理一个 Intent 因为它共享一个工作线程来完成所有工作 但如果我有多个IntentService在我的应用程序中 它们可以并行运行 还是都共享单个工作线程 但是如果我的应用程序中有多个
  • F1 2019 UDP解码

    我目前正在为 F1 方向盘开发自己的显示器 F1 2019 由codemasters提供 通过UDP发送数据 该数据存储在字节数组中 我在解码返回的数组时遇到一些问题 问题是我得到了很多信息 但我不知道如何处理它们 我将向您介绍我所尝试过的
  • ZeroMQ可以用来接受传统的套接字请求吗?

    我正在尝试使用 ZeroMQ 重写我们的旧服务器之一 现在我有以下服务器设置 适用于 Zmq 请求 using var context ZmqContext Create using var server context CreateSoc
  • 使用 Boost.Asio 进行广播的问题

    如果问题之前已得到解答 我提前表示歉意 但我已经搜索并没有找到任何对我有帮助的东西 正如问题标题所示 我正在尝试将包从服务器广播到一组侦听任何消息的客户端 客户端将计算一秒钟内收到的消息数 服务器端的事情是这样的 class Server
  • 无法从 AsyncTask 启动服务

    我正在尝试从 AsyncTask 启动服务 但看不到它的启动 我还在清单文件中添加了服务 这里是代码 protected Integer doInBackground Void values throws InterruptedExcept
  • 如何使用一个凉亭同时创建两个地图?

    如下图所示 现在我的gazebo正在运行2个slam gmapping包 首先是 turtlebot slam gmapping 发布到 map 主题 第二个是 slam gmapping 发布到与第一个相同的 map 主题 我想创建一个新
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

    我在过去的两天里阅读了每一篇StackOverflow问题和答案 以及googling当然 关于印地TCP and UDP协议 以便决定在我的用户应用程序和 Windows 服务之间的通信方法中应该使用哪一种 从我目前所看到的来看 UDP是
  • 尝试从 C# 服务查询 IIS 时出现异常

    我从使用 C 编写的 Windows 服务调用以下代码 try ServerManager m new ServerManager if m null SiteCollection sites m Sites I get exception

随机推荐