实现服务通讯的服务端Server的编程实现
主要给海龟发送速度指令,通过topic发,Service实现;Client发布request来控制Server是不是给海龟发指令让其动起来,Client相当于让海龟运动及停止的开关,发布request,海龟就运动,再发布一个request,海龟停止;Server端来接收开关的指令并且完成topic海龟运动指令的发送;这里用到的Service名称(自定义的一个Service名字)为turtle_command ,关于Service的数据类型的定义,用到的是ros中针对服务的标准的一个定义,叫做Trigger,相当于是一个触发,触发这样一个信号,是运动还是停止的触发信号,我们通过Server一端收到触发信号之后来控制海龟是不是要去发送Twist这样一个速度指令,同时要去反馈一个response,告诉Client一端其请求是否已经执行成功,这时就可以通过Client一端知道海龟的运动状态,以上是该讲要去实现的服务模型
这里Server的实现里面既会包含Service的Server一端的实现,同时也会包含一个发布者publisher的实现,有两部分内容

第一步,创建服务器代码(C++例)

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

将课件代码/learning_service/src里的turtle_command_server.cpp代码文件放置于catkin_ws/src/learning_service/src里

turtle_command_server.cpp代码文件

/*** 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger* Trigger是触发的一个信号*/#include <ros/ros.h>  //ROS头文件
#include <geometry_msgs/Twist.h>  //给海龟去发布速度指令Twist Topic这样一个头文件
#include <std_srvs/Trigger.h>  //用到的服务数据类型头文件ros::Publisher turtle_vel_pub;   //创建一个全局的publisher头文件
bool pubCommand = false;   //定义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");// 设置反馈数据//同时要给Client这一端反馈一个应答数据,告诉数据执行成功还是失败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,后面是初始化的内容,如Service名字叫turtle_command(自己定义的),同时Service里的server这一端的处理跟我们在topic话题通讯当中的subscriber订阅者的处理有点像,并不知道数据什么时候进来,一样需要一个回调函数的处理来处理request的请求,commandCallback即为回调函数。一旦Server端收到request进来后,立刻跳到回调函数里,在回调函数里做针对server的处理,比如要让海龟动起来,就需要在commandCallback 里让海龟动起来//创建一个Service的serverros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);// 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10//创建一个topic的publisher,主要是给海龟发布速度指令让海龟能动起来turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);// 循环等待回调函数//发布日志信息ROS_INFO("Ready to receive turtle command.");// 设置循环的频率,一秒钟10HZros::Rate loop_rate(10);while(ros::ok()){// 查看一次回调函数队列,是否有消息进入ros::spinOnce();// 如果标志为true,则发布速度指令,则对应的海龟仿真器里的海龟就会动起来;如果标志为false,就不会有任何的数据发出,海龟就不会发生任何运动;标志位是在commandCallback里做处理的,所以注意,如果Client这一端有请求request发出之后,Server端收到请求就会立刻跳到回调函数里来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;
}//回顾整个流程,初始化,创建句柄,创建一个server,之后等待server turtle_command的调用,一旦有request进来,立刻跳到commandCallback里做处理;一进来现对标志位取反,然后标志位在while循环中做判断,如果标志位是true,就会让海龟动,如果标志位是false,海龟就会停止运动       关键要去注意的一点是server的创建和server里的commandCallback里的机制跟topic里的subscriber订阅者有点类似;commandCallback里由两部分内容,一个request一个response专门针对请求内容和应答内容,只不过这里的Trigger,他的request是空的内容

小插入:通过rossrv show std_srvs/Trigger命令行看一下Trigger的定义
可见该service定义较简单,因为涉及到request和response两个部分数据,因此通过—做一个区隔,—之上是request内容,—之下是response内容
所以,这里可见发送的request内容是空的,这里的response就是success,message用于告诉Client一端发生了什么

第二步,配置服务器代码编译规则

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

将该两行代码粘贴至CMakeLists.txt文件,Install前,上一次所添加编译规则下
第一句,把turtle_command_server.cpp的代码编译成turtle_command_server这样一个可执行文件
第二句,添加链接库

第三步,编译并运行服务器

cd ~/catkin_ws //回到工作空间根目录下
catkin_make //用该指令去做编译
source devel/setup.bash //设置环境变量,可通过一些方法减去该步骤,跳过
roscore
rosrun turtlesim turtlesim_node //运行仿真器
rosrun learning_service turtle_command_server //运行刚才创建的server端

rosservice call /turtle_command “{}” //然后通过终端发送Client这样一个请求,请求server来让它让海龟动起来

turtle_command刚刚在程序里已经写好的service的服务的名字;看service的数据内容是怎样的,rosservice call /turtle_command后双击tab键补全“{}”,刚刚说过 request请求是空的,大括号里的内容就是request的内容是空的
回车后海龟动起来,同时收到server反馈回来的应答数据


Client相当于海龟的开关,发送一次运动,再次发送,停止,反复如此

rosrun learning_service turtle_command_server处显示收到的指令,yes是海龟动,no是海龟停止

接下来是python实现内容,代码流程一样
创建服务器代码

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

将课件代码/learning_service/scripts里的turtle_command_server.py代码文件复制放置于catkin_ws/src/learning_service/scripts里

turtle_command_server.py代码文件

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将执行/turtle_command服务,服务数据类型std_srvs/Triggerimport rospy
import thread,time
from geometry_msgs.msg import Twist
from std_srvs.srv import Trigger, TriggerResponse#定义两个全局变量,一是标志位,一个是Publisher用来发布运动指令的
pubCommand = False;
turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)#在刚刚的C++程序里,调用ros::spinOnce();查询一次队列,看队列里有没有数据,有的话进入回调函数,没有则跳出来继续执行while循环里的程序。但是ros::spinOnce()在ros的python的接口里面是没有实现的,所以在python里面需要通过一个多线程的机制来去实现类似于ros::spinOnce()+if判断标志位这样一个功能    所以多了这样一个程序,他是一个线程,主要来实现判断if pubCommand 是true或者false,true则发送海龟运动指令,false则跳过
def command_thread():   while True:if pubCommand:vel_msg = Twist()vel_msg.linear.x = 0.5vel_msg.angular.z = 0.2turtle_vel_pub.publish(vel_msg)time.sleep(0.1)def commandCallback(req):global pubCommandpubCommand = bool(1-pubCommand)#在commandCallback里会对全局标志位做取反,接下来显示request的数据,同时反馈应答数据# 显示请求数据rospy.loginfo("Publish turtle velocity command![%d]", pubCommand)# 反馈数据  success即是1;另外一个是messagereturn TriggerResponse(1, "Change turtle command state!")def turtle_command_server():# ROS节点初始化rospy.init_node('turtle_command_server')# 创建一个名为/turtle_command的server,注册回调函数commandCallback#通过调用rospy中的Service来创建服务的名字turtle_command,服务的数据类型Trigger,以及一旦有服务进来的commandCallbacks = rospy.Service('/turtle_command', Trigger, commandCallback)# 循环等待回调函数print "Ready to receive turtle command."#创建一个新的线程来启动def command_thread():  部分程序   同时启动spin,一个死循环,不能判断上面这些内容,所以在其之前单独起了一个线程去判断;在spin中会不断循环来看是否有request进来,一旦有则进入commandCallbackthread.start_new_thread(command_thread, ())rospy.spin()if __name__ == "__main__":turtle_command_server()#先进入该函数

ROS入门-12.服务端Server的编程实现相关推荐

  1. 【RK3399Pro学习笔记】十、ROS服务端Server的编程实现

    目录 如何实现一个服务器 C++ 编写程序 配置CMakeLists.txt 编译并运行 python 创建并编写脚本 运行 平台:华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件 ...

  2. ROS系统 实现客户端Client和服务端Server

    服务编程流程: 创建服务器 创建客户端 添加编译选项 运行可执行程序 实现客户端Clien 创建功能包 cd ~/catkin_ws/src catkin_create_pkg learning_se ...

  3. java项目_好程序员Java分享从入门到服务端项目开发的过程

    好程序员Java分享从入门到服务端项目开发的过程,对于打算入门或者刚刚入门学习Java的人来说,刚开始接触这门学科,往往会觉得不知所措,也会觉得很迷茫.结合前人经验,就从入门到进阶对于Java的学习而 ...

  4. 天龙八部服务器列表文件,天龙八部服务端server目录脚本说明.doc

    文档介绍: 天龙八部服务端 server 目录脚本说明天龙八部服务端 Server 目录脚本功能说明: /Server/Config Account.txt 测试帐号/Server/Config Al ...

  5. 天龙八部服务器列表文件,天龙八部服务端Server目录脚本功能说明

    天龙八部服务端Server目录脚本功能说明 本文出处:网游动力作者:本站发布时间:2008-11-06阅读次数: tlbbServerConfigNotifyDate.txt 公告 tlbbServe ...

  6. C# 客户端Client与服务端Server通信

    C# 客户端Client与服务端Server通信 服务端配置 服务端要先启动,等待客户端请求连接 客户端配置 客户端测试**(切记一定要先开启服务端,不然不能保证连接)**

  7. TCP多进程并发服务端 Linux socket编程入门(2)

    这里很简单的使用了fork()函数,在执行了fork()以后的所有代码都会由子进程和父进程同时执行. 他们同时拥有相同的资源(两份拷贝),所以在子进程执行的过程中,子进程需要先close掉listen ...

  8. Java的HTTP服务端响应式编程

    传统的Servlet模型走到了尽头 传统的Java服务器编程遵循的是J2EE的Servlet规范,是一种基于线程的模型:每一次http请求都由一个线程来处理. 线程模型的缺陷在于,每一条线程都要自行处 ...

  9. ROS入门-13.服务数据的定义与使用

    前面我们已经学习到了spawn和Trigger两种在ROS中已经定义好的服务数据类型的使用方式,当已经定义好的服务数据不能满足我们需求时,就需要根据自己需求来定义一个服务数据的类型并使用 之前在自定义 ...

最新文章

  1. linux和windows中insert语句注意
  2. python清除字符串中间空格的方法
  3. python 讲课_Python语言
  4. 英国电信公司沃达丰遭到网络攻击
  5. DebugView使用笔记
  6. AptanaStudio3+PHP程序远程调试的方法和步骤
  7. 买房,有多少人帮助过你?
  8. 数据交换-电路/报文/分组交换
  9. virtualbox+vagrant快速创建虚拟机
  10. VUE router-view 页面布局 (嵌套路由+命名视图)
  11. 计算机网络 校园网规划,校园网络规划与设计方案
  12. 自然语言处理(八)——语言模型性能评价
  13. 细节至上——Splus微博设计之界面篇(转)
  14. IBM P系列小型机HMC默认IP地址
  15. macbook linux 双系统,Mac双系统切换及设置技巧
  16. Guava学习之Splitter
  17. uva10859 Placing Lampposts
  18. 数据结构 | 二叉树 先根、中根、后根遍历的非递归算法
  19. 微信小程序开发需要什么前提条件?
  20. 关于U盘的镜像经营模式

热门文章

  1. html 文件动态加载.PDI 流程图
  2. ArcGIS服务器的feature图层限制
  3. 【jquery】 随笔记录
  4. eclipse项目两个红点
  5. java 过滤器filter使用案例
  6. 关于fsockopen pfsockopen函数被禁用的解决方法
  7. c#使用Transactions类完成多个数据库的事务操作
  8. Metro UI 的设计感悟
  9. AutoItLibrary安装和常见问题解决
  10. 解决 OpenCV with CUDA 编译提示缺少 nvcuvid.h 的问题