zoukankan      html  css  js  c++  java
  • ROS之服务

    服务(service)是另一种在节点之间传递数据的方法,服务其实就是同步的跨进程函数调用,它能够让一个节点调用运行在另一个节点中的函数。

    我们就像之前消息类型一样定义这个函数的输入/输出。服务端(提供服务的节点)定义了一个回调函数来处理服务的请求,并声明这个服务。

    客服端(进行服务请求的节点)通过一个本地的代理调用这个服务。

    服务一般只是做哪些偶尔会做的事,或这当你需要同步的响应的时候,服务的回调函数中的计算应该较短,并能够在有限的时间中完成。

    定义服务

    例:WordCount.srv

    string words
    ---
    uint32 count

    创建一个服务的第一步是定义服务调用的是输入和输出,定义服务文件就像消息定义文件一样,服务定义文件只是一个消息类型列表,这些类型可以是内建的。

    文件中首先是服务调用的输入。直接使用ros内建的string类型,三个小短线(---)表示输入的末尾和输出的开始,我使用一个32位的无符号整数(uint32)作为输出,

    这个包含服务定义的文件叫做WordCount.srv并且保存在包目录的一个叫做srv的子目录中(这个目录可以自己设置)

    一旦写好文件了定义文件,我们就需要运行catkin_make来创建我们在与服务交互的时候真正会用到的代码和类定义,就像我们创建消息一样。

    需要在package.xml文件中调加一些东西来表示对rospy和消息生成系统的依赖。如下

    <build_depend>rospy</build_depend>
    <evec_depend>rospy</exec_depend>
    
    <build_depend>message_generation</build_depend>
    <exec_depend>message_runtime</exec_depend>

    需要修改CMakeLists.txt文件

    其他修改和前面话题修改的一样,不同的是

    需要在CMakeLists.txt文件中使用add_service_files()告诉那些服务定义文件需要编译

    add_service_files(
         FILES
        WordCount.srv
    )

    最后要确保我们的服务定义文件的依赖已经被声明了,使用CMakeLists.txt文件中的generate_message()调用.

    generation_message(
        DEPENDENCIES
        std_msgs
    )

    当所有的这些都完成了,运行catkin_make来生成三个类;WordCount、WordCountRequest和WordCountResponse.

    然后使用rossev show WordCount命令可以检测服务的定义

    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rossrv show WordCount
    [basic/WordCount]:
    string words
    ---
    uint32 count

    使用rossrv list 命令可查看所有提供服务的包

    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rossrv list
    basic/WordCount
    control_msgs/QueryCalibrationState
    control_msgs/QueryTrajectoryState
    control_toolbox/SetPidGains
    controller_manager_msgs/ListControllerTypes
    controller_manager_msgs/ListControllers
    controller_manager_msgs/LoadController
    controller_manager_msgs/ReloadControllerLibraries
    controller_manager_msgs/SwitchController
    controller_manager_msgs/UnloadController
    diagnostic_msgs/AddDiagnostics
    diagnostic_msgs/SelfTest
    dynamic_reconfigure/Reconfigure
    gazebo_msgs/ApplyBodyWrench
    gazebo_msgs/ApplyJointEffort
    gazebo_msgs/BodyRequest
    gazebo_msgs/DeleteLight
    gazebo_msgs/DeleteModel
    gazebo_msgs/GetJointProperties
    gazebo_msgs/GetLightProperties
    gazebo_msgs/GetLinkProperties
    gazebo_msgs/GetLinkState
    gazebo_msgs/GetModelProperties
    gazebo_msgs/GetModelState
    gazebo_msgs/GetPhysicsProperties
    gazebo_msgs/GetWorldProperties
    gazebo_msgs/JointRequest
    gazebo_msgs/SetJointProperties
    gazebo_msgs/SetJointTrajectory
    gazebo_msgs/SetLightProperties
    gazebo_msgs/SetLinkProperties
    gazebo_msgs/SetLinkState
    gazebo_msgs/SetModelConfiguration
    gazebo_msgs/SetModelState
    gazebo_msgs/SetPhysicsProperties
    gazebo_msgs/SpawnModel
    laser_assembler/AssembleScans
    laser_assembler/AssembleScans2
    map_msgs/GetMapROI
    map_msgs/GetPointMap
    map_msgs/GetPointMapROI
    map_msgs/ProjectedMapsInfo
    map_msgs/SaveMap
    map_msgs/SetMapProjections
    nav_msgs/GetMap
    nav_msgs/GetPlan
    nav_msgs/SetMap
    nodelet/NodeletList
    nodelet/NodeletLoad
    nodelet/NodeletUnload
    polled_camera/GetPolledImage
    roscpp/Empty
    roscpp/GetLoggers
    roscpp/SetLoggerLevel
    roscpp_tutorials/TwoInts
    rospy_tutorials/AddTwoInts
    rospy_tutorials/BadTwoInts
    sensor_msgs/SetCameraInfo
    std_srvs/Empty
    std_srvs/SetBool
    std_srvs/Trigger
    tf/FrameGraph
    tf2_msgs/FrameGraph
    topic_tools/DemuxAdd
    topic_tools/DemuxDelete
    topic_tools/DemuxList
    topic_tools/DemuxSelect
    topic_tools/MuxAdd
    topic_tools/MuxDelete
    topic_tools/MuxList
    topic_tools/MuxSelect
    turtlesim/Kill
    turtlesim/SetPen
    turtlesim/Spawn
    turtlesim/TeleportAbsolute
    turtlesim/TeleportRelative

    实现服务

    下面举一个例子(一个简单的实现了单词计数服务的服务端程序)

    例:service_server.py

     1 #!/usr/bin/env python
     2 import rospy
     3 from basic.srv import WordCount,WordCountResponse
     4 
     5 def count_words(request):
     6     return WordCountResponse(len(request.words.split()))
     7 rospy.init_node('service_server')
     8 service=rospy.Service('word_count',WordCount,count_words)              
     9 rospy.spin()

    第一.首先需要导入catkin生成的代码:

    from basic.src import WordCount,WordCountResponse

    注意需要同时导入WordCount和WordCountRseponse.

    第二.回调函数只接受一个WordCountRequest类型的参数并返回一个WordCountResponse类型的值:

    def count_words(request):

          return WordCountResponse(len(request.words.split()))

    WordCountResponse的构造函数接受与服务定义文件中的类型相匹配的参数。

    第三.我们声明这个服务,并且给他一个名字(word_count)和一个类型(WordCount),同时指定实现这一服务的回调函数:

    service=rospy.Service('word_count',WordCount,count_words)

    最后,我们调用rospy.spin(),将程序的执行转交给ros,只有当节点即将要退出的时候才会返回。

    使用rospy.spin()是一种方便的方式来保证节点直到需要退出的时候才退出。

    检查一切是否工作正常

    首先在一个终端运行:roscore

    然后在另一个终端运行服务节点:rosrun basic service_server.py

    另一个终端查看服务:rosservice list

    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rosservice list
    /rosout/get_loggers
    /rosout/set_logger_level
    /service_server/get_loggers
    /service_server/set_logger_level
    /word_count

    使用服务

    使用时都需要运行服务节点: rosrun basic service_server.py

    使用服务最简单的方式使用rosservice命令直接调用它,对于我们这个单词计数服务,如下

    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rosservice call word_count 'one two three'
    count: 3

    这个命令使用的是call子命令,服务名字,以及参数。尽管这种方式允许我们调用服务并确认他在正常工作,但是他不如直接运行在另一个节点中调用有用。

    我们创建一个客服端节点

    例:service_client.py

     1 #!/usr/bin/env python
     2 import rospy
     3 from basic.srv import WordCount
     4 import sys
     5 
     6 rospy.init_node('service_client')
     7 
     8 rospy.wait_for_service('word_count')
     9 
    10 word_counter =rospy.ServiceProxy('word_count',WordCount)
    11 
    12 words=''.join(sys.argv[1:])
    13 
    14 word_count=word_counter(words)
    15 
    16 print words,'->',word_count.count  

    首先等待服务端声明这个服务:rospy.wait_for_service('word_count')

    如果我们尝试在服务被声明之前使用它,这个调用会失败,并抛出异常,这是话题和服务的一个主要区别。即使一个人话题还没声明,我们也可以订阅他,一旦服务被声明,我们可以给他配置一个本地代理;

    word_counter= rospy.ServiceProxy('word_count',WordCount)

    我们需要指定服务的名字(word_count)和类型(WordCount)

    然后使用catkin_make命令和source devel/setup.bash命令编译并配置文件

    再运行服务节点和客服端节点

    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rosrun basic service_server.py 
    qqtsj@qqtsj-Nitro-AN515-51:~/catkin_ws/src/basic$ rosrun basic service_client.py 'one two three five'
    one two three five -> 4

    服务就实现了

    小结

    在这之前,已经学会话题发布和订阅消息,现在已经了解了关于服务的一切内容,这是ROS中的第二种的主要通信机制。服务只是进程间的同步调用并且允许显示的节点间双向通信。

    服务一般只是做哪些偶尔会做的事,或这当你需要同步的响应的时候,服务的回调函数中的计算应该较短,并能够在有限的时间中完成。

  • 相关阅读:
    五十四:CSS3之背景与渐变之渐变
    五十三:CSS3之背景与渐变之背景
    五十二:CSS3之圆角、边框、边界图片
    五十一:CSS3之基本选择器之伪元素
    五十:CSS3之基本选择器之CSS权重
    四十九:CSS3之基本选择器之伪类选择器之结构类之nth选择器
    四十八:CSS3之基本选择器之伪类选择器之UI元素状态伪类
    四十七:CSS3之基本选择器之伪类选择器之动态伪类
    四十六:CSS3之基本选择器新增加的属性选择器
    四十五:CSS3之基本选择器新增加的4种选择器
  • 原文地址:https://www.cnblogs.com/tanshengjiang/p/11783959.html
Copyright © 2011-2022 走看看