• ROS1学习笔记:服务中的Service和Client(ubuntu20.04)


    参考B站古月居ROS入门21讲:
    客户端Client的编程实现
    服务端Server的编程实现
    基于VMware Ubuntu 20.04 Noetic版本的环境


    服务(Service)是节点之前同步通信的一种方式,允许客户端(Client)节点发布请求(Request),由服务端(Server)节点处理后反馈应答(Response)。

    一、小乌龟例程中的服务

    小乌龟例程提供了不少设置功能,这些设置都以服务的形式提供。在小乌龟例程运行状态下,使用如下命令查看系统中的服务列表:

    rosservice list
    
    • 1

    在这里插入图片描述
    可以使用代码或终端对列表中的服务进行调用。例如使用以下命令调用"/spawn"服务新生一只小乌龟:

    rosservice call /spawn "x: 1.0
    y: 5.0
    theta: 0.0
    name: 'turtle2'" 
    
    • 1
    • 2
    • 3
    • 4

    服务的请求数据是新生小乌龟的位置、姿态以及名称,调用成功后仿真器中就会诞生一只新的小乌龟。如图所示:
    在这里插入图片描述
    终端会打印服务反馈的应答数据,即新小乌龟的名称,如图所示:
    在这里插入图片描述
    从小乌龟仿真例程中的服务可以看到,服务一般分为服务端(Server)和客户端(Client)两个部分,Client负责发布请求数据,等待Server处理;Server负责处理相应的功能,并且返回应答数据。
    我们来分析一下小海龟仿真器服务模型中的客户端和服务器:

    Sever是小海龟仿真器/turtlesimClient端产生Request的请求,发给Server端。Server端收到Request请求后产生一只小海龟,反馈一个ResponseClient小海龟产生是否成功。Service的名称为/spawn,中间传输消息的数据结构为turtlesim::SpawnServer端本身是进行模拟海龟运动的命令端,它的实现是通过给海龟发送速度(Twist)的指令,来控制海龟运动(本身通过Topic实现)。

    在这里插入图片描述

    Client相当于海龟运动的开关,其发布Request来控制Server端。 通过自定义名为 /turtle_commandService实现,中间传输消息的数据类型为std_srvs::Trigger(一种针对服务标准std_srvs下的数据定义)来通信。Trigger意为触发,通过Trigger信号来触发Server端的运动指令。Server端接收这个Trigger信号后,可控制其是否要给海龟发送Twist指令,同时给Client端发送Response反馈告诉它海龟的运动状态。

    在这里插入图片描述

    整个节点之间的通讯是在ROS Master下进行的。

    二、创建功能包

    在本节我们将创建一个新的功能包,名字为learning_service,并创建依赖,复制下面命令即可:

    cd ~/catkin_ws/src
    catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim
    
    • 1
    • 2

    在这里插入图片描述

    三、创建Client代码

    如何实现一个客户端Client?

    • 初始化ROS
    • 创建一个Client实例
    • 发布服务请求数据
    • 等待Server处理之后的应答结果

    3.1 以C++为例

    将代码turtle_spawn.cpp拷贝进src文件夹下:
    完整代码为:

    /***********************************************************************
    Copyright 2020 GuYueHome (www.guyuehome.com).
    ***********************************************************************/
    
    /**
     * 该例程将请求/spawn服务,服务数据类型turtlesim::Spawn
     */
    
    #include 
    #include 
    
    int main(int argc, char** argv)
    {
        // 初始化ROS节点
    	ros::init(argc, argv, "turtle_spawn");
    
        // 创建节点句柄
    	ros::NodeHandle node;
    
        // 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    	ros::service::waitForService("/spawn");
    	ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
    
        // 初始化turtlesim::Spawn的请求数据
    	turtlesim::Spawn srv;
    	srv.request.x = 2.0;
    	srv.request.y = 2.0;
    	srv.request.name = "turtle2";
    
        // 请求服务调用
    	ROS_INFO("Call service to spwan turtle[x:%0.6f, y:%0.6f, name:%s]", 
    			 srv.request.x, srv.request.y, srv.request.name.c_str());
    
    	add_turtle.call(srv);
    
    	// 显示服务调用结果
    	ROS_INFO("Spwan turtle successfully [name:%s]", srv.response.name.c_str());
    
    	return 0;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3.1.1 配置Client代码编译规则

    配置CMakeLists.txt编译规则:

    • 设置需要编译的代码和生成的可执行文件;
    • 设置链接库;

    将以下代码复制进去:

    add_executable(turtle_spawn src/turtle_spawn.cpp)
    target_link_libraries(turtle_spawn ${catkin_LIBRARIES})
    
    • 1
    • 2

    在这里插入图片描述

    3.1.2 编译整个工作空间

    cd ~/catkin_ws
    catkin_make
    
    • 1
    • 2

    编译完成后能看到/debel/lib/learning_service目录下新生成的可执行文件:
    在这里插入图片描述

    3.1.3 配置环境变量

    之前已经配置过。

    3.1.4 执行代码

    roscore
    
    • 1
    rosrun turtlesim turtlesim_node
    
    • 1
    rosrun learning_service turtle_spawn
    
    • 1

    可以看到生成了第二只小海龟。
    在这里插入图片描述

    3.2 以Python为例

    将代码turtle_spawn.py拷贝进新建立的scripts文件夹下(别忘了开启执行权限),完整代码为:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    ########################################################################
    ####          Copyright 2020 GuYueHome (www.guyuehome.com).          ###
    ########################################################################
    
    # 该例程将请求/spawn服务,服务数据类型turtlesim::Spawn
    
    import sys
    import rospy
    from turtlesim.srv import Spawn
    
    def turtle_spawn():
    	# ROS节点初始化
        rospy.init_node('turtle_spawn')
    
    	# 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
        rospy.wait_for_service('/spawn')
        try:
            add_turtle = rospy.ServiceProxy('/spawn', Spawn)
    
    		# 请求服务调用,输入请求数据
            response = add_turtle(2.0, 2.0, 0.0, "turtle2")
            return response.name
        except rospy.ServiceException as e:
            print(f"Service call failed: {e}")
    
    if __name__ == "__main__":
    	#服务调用并显示调用结果
        print(f"Spwan turtle sucessfully [name:{turtle_spawn()}]")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3.2.1 配置Client代码编译规则

    打开CMakeLists.txt文件,配置Python代码编译规则:
    在这里插入图片描述

    3.2.2 编译整个工作空间

    cd ~/catkin_ws
    catkin_make
    
    • 1
    • 2

    3.2.3 配置环境变量

    之前已经配置过。

    3.2.4 执行代码

    roscore
    
    • 1
    rosrun turtlesim turtlesim_node
    
    • 1
    rosrun learning_service turtle_spawn.py
    
    • 1

    在这里插入图片描述

    四、创建Server代码

    如何实现一个服务器端Server?

    • 初始化ROS
    • 创建一个Server实例
    • 循环等待服务请求,进入回调函数
    • 在回调函数中完成服务功能的处理,并反馈应答数据

    4.1 以C++为例

    将代码turtle_command_server.cpp拷贝进src文件夹下:
    完整代码为:

    /***********************************************************************
    Copyright 2020 GuYueHome (www.guyuehome.com).
    ***********************************************************************/
    
    /**
     * 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger
     */
     
    #include 
    #include 
    #include 
    
    ros::Publisher turtle_vel_pub;
    bool pubCommand = false;
    
    // service回调函数,输入参数req,输出参数res
    bool commandCallback(std_srvs::Trigger::Request  &req,
             			std_srvs::Trigger::Response &res)
    {
    	pubCommand = !pubCommand;
    
        // 显示请求数据
        ROS_INFO("Publish turtle velocity command [%s]", pubCommand==true?"Yes":"No");
    
    	// 设置反馈数据
    	res.success = true;
    	res.message = "Change turtle command state!";
    
        return true;
    }
    
    int main(int argc, char **argv)
    {
        // ROS节点初始化
        ros::init(argc, argv, "turtle_command_server");
    
        // 创建节点句柄
        ros::NodeHandle n;
    
        // 创建一个名为/turtle_command的server,注册回调函数commandCallback
        ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);
    
    	// 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
    	turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
    
        // 循环等待回调函数
        ROS_INFO("Ready to receive turtle command.");
    
    	// 设置循环的频率
    	ros::Rate loop_rate(10);
    
    	while(ros::ok())
    	{
    		// 查看一次回调函数队列
        	ros::spinOnce();
    		
    		// 如果标志为true,则发布速度指令
    		if(pubCommand)
    		{
    			geometry_msgs::Twist vel_msg;
    			vel_msg.linear.x = 0.5;
    			vel_msg.angular.z = 0.2;
    			turtle_vel_pub.publish(vel_msg);
    		}
    
    		//按照循环频率延时
    	    loop_rate.sleep();
    	}
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    在回调函数中给Client端的反馈数据res是与Trigger相对应的,我们可以查看一下Trigger的数据结构。可以使用rossrv指令查看service中的数据类型:

    rossrv show std_srvs/Trigger
    
    • 1

    在这里插入图片描述

    4.1.1 配置Server代码编译规则

    配置CMakeLists.txt编译规则:

    • 设置需要编译的代码和生成的可执行文件;
    • 设置链接库;

    将以下代码复制进去:

    add_executable(turtle_command_server src/turtle_command_server.cpp)
    target_link_libraries(turtle_command_server ${catkin_LIBRARIES})
    
    • 1
    • 2

    在这里插入图片描述

    4.1.2 编译整个工作空间

    cd ~/catkin_ws
    catkin_make
    
    • 1
    • 2

    4.1.3 配置环境变量

    之前已经配置过。

    4.1.4 执行代码

    roscore
    
    • 1
    rosrun turtlesim turtlesim_node
    
    • 1
    rosrun learning_service turtle_command_server
    
    • 1

    可以看到服务端已经启动了,如下图所示:
    在这里插入图片描述
    接着我们再打开一个终端,输入以下命令使得小海龟动起来(可以通过tab键进行补全):

    rosservice call /turtle_command "{}"
    
    • 1

    在这里插入图片描述
    再输入一遍rosservice call /turtle_command "{}"这个命令,小海龟就会停下来了:
    在这里插入图片描述

    4.2 以Python为例

    将代码turtle_command_server.py拷贝进新建立的scripts文件夹下(别忘了开启执行权限),完整代码为:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    ########################################################################
    ####          Copyright 2020 GuYueHome (www.guyuehome.com).          ###
    ########################################################################
    
    # 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger
    
    import rospy
    import _thread,time
    from geometry_msgs.msg import Twist
    from std_srvs.srv import Trigger, TriggerResponse
    
    pubCommand = False;
    turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
    
    def command_thread():	
    	while True:
    		if pubCommand:
    			vel_msg = Twist()
    			vel_msg.linear.x = 0.5
    			vel_msg.angular.z = 0.2
    			turtle_vel_pub.publish(vel_msg)
    			
    		time.sleep(0.1)
    
    def commandCallback(req):
    	global pubCommand
    	pubCommand = bool(1-pubCommand)
    
    	# 显示请求数据
    	rospy.loginfo("Publish turtle velocity command![%d]", pubCommand)
    
    	# 反馈数据
    	return TriggerResponse(1, "Change turtle command state!")
    
    def turtle_command_server():
    	# ROS节点初始化
        rospy.init_node('turtle_command_server')
    
    	# 创建一个名为/turtle_command的server,注册回调函数commandCallback
        s = rospy.Service('/turtle_command', Trigger, commandCallback)
    
    	# 循环等待回调函数
        print("Ready to receive turtle command.")
    
        _thread.start_new_thread(command_thread, ())
        rospy.spin()
    
    if __name__ == "__main__":
        turtle_command_server()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在回调函数中给Client端的反馈数据res是与Trigger相对应的,我们可以查看一下Trigger的数据结构。可以使用rossrv指令查看service中的数据类型:

    rossrv show std_srvs/Trigger
    
    • 1

    在这里插入图片描述

    4.2.1 配置Server代码编译规则

    打开CMakeLists.txt文件,配置Python代码编译规则:

    在这里插入图片描述

    4.2.2 编译整个工作空间

    cd ~/catkin_ws
    catkin_make
    
    • 1
    • 2

    4.2.3 配置环境变量

    之前已经配置过。

    4.2.4 执行代码

    roscore
    
    • 1
    rosrun turtlesim turtlesim_node
    
    • 1
    rosrun learning_service turtle_command_server.py
    
    • 1

    可以看到服务端已经启动了,如下图所示:
    在这里插入图片描述

    接着我们再打开一个终端,输入以下命令使得小海龟动起来(可以通过tab键进行补全):

    rosservice call /turtle_command "{}"
    
    • 1

    在这里插入图片描述

    再输入一遍rosservice call /turtle_command "{}"这个命令,小海龟就会停下来了:
    在这里插入图片描述

  • 相关阅读:
    DASCTF X GFCTF 2022十月挑战赛 - pwn
    氨基修饰/偶联/功能化/接枝二氧化钛,NH2-TiO2,TiO2-NH2
    次时代摸鱼骚操作:人在办公室轻松观看家里电脑上的4k电影(移动端公网访问本地群辉存储视频文件)
    C# TCP通讯大族激光打标机
    【ShardingSphere】单实例模式创建分片表、广播表、单表
    C++ Day04 this指针,友元函数,重载
    基于ssm框架的毕业设计管理系统毕业设计源码211633
    Echarts热力/散点/面积地图和高德amap不得不说的故事
    pytorch+sklearn实现数据加载
    第五篇 《随机点名答题系统》——抽点答题详解(类抽奖系统、在线答题系统、线上答题系统、在线点名系统、线上点名系统、在线考试系统、线上考试系统)
  • 原文地址:https://blog.csdn.net/weixin_56197703/article/details/126993972