08.服务端
8、服务端
上节课我们说到了客户端请求服务,然后服务端提供服务,这节课我们就来说说服务端是如何实现提供服务的。
8.1、C++语言实现
8.1.1、实现步骤
1)、初始化ROS节点
2)、创建Server实例
3)、循环等待服务请求,进入回调函数
4)、在回调函数中完成服务的功能处理,并且反馈应答数据
8.1.2、切换至~/catkin_ws/src/learning_server/src目录下,新建一个.cpp文件,命名为turtle_vel_command_server,把下边代码粘贴在里边
turtle_vel_command_server.cpp
x /** * 该例程将执行/turtle_vel_command服务,服务数据类型std_srvs/Trigger */ #include <ros/ros.h> #include <geometry_msgs/Twist.h> #include <std_srvs/Trigger.h> ros::Publisher turtle_vel_pub ; bool pubvel = false ; // service回调函数,输入参数req,输出参数res bool pubvelCallback ( std_srvs::Trigger::Request & req , std_srvs::Trigger::Response & res ) { pubvel = ! pubvel ; ROS_INFO ( "Do you want to publish the vel?: [%s]" , pubvel == true ? "Yes" : "No" ); // 打印客户端请求数据 // 设置反馈数据 res . success = true ; res . message = "The status is changed!" ; return true ; } int main ( int argc , char ** argv ) { ros::init ( argc , argv , "turtle_vel_command_server" ); ros::NodeHandle n ; // 创建一个名为/turtle_vel_command的server,注册回调函数pubvelCallback ros::ServiceServer command_service = n . advertiseService ( "/turtle_vel_command" , pubvelCallback ); // 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度8 turtle_vel_pub = n . advertise < geometry_msgs::Twist > ( "/turtle1/cmd_vel" , 8 ); ros::Rate loop_rate ( 10 ); // 设置循环的频率 while ( ros::ok ()) { ros::spinOnce (); // 查看一次回调函数队列 // 判断pubvel为True,则发布小海龟速度指令 if ( pubvel ) { geometry_msgs::Twist vel_msg ; vel_msg . linear . x = 0.6 ; vel_msg . angular . z = 0.8 ; turtle_vel_pub . publish ( vel_msg ); } loop_rate . sleep (); //按照循环频率延时 } return 0 ; }
1)、程序流程图

2)、在CMakelist.txt中配置,build区域下,添加如下内容
xxxxxxxxxx add_executable(turtle_vel_command_server src/turtle_vel_command_server.cpp) target_link_libraries(turtle_vel_command_server ${catkin_LIBRARIES})
3)、工作空间目录下编译代码
xxxxxxxxxx cd ~/catkin_ws catkin_make source devel/setup.bash #需要配置环境变量,否则系统无法找到运行程序
4)、运行程序
xxxxxxxxxx roscore rosrun turtlesim turtlesim_node rosrun learning_server turtle_vel_command_server
5)、运行效果截图

6)、程序说明
首先,运行小海龟这个节点后,可以在终端输入rosservice list,查看当前的服务有哪些,结果如下

然后,我们再运行turtle_vel_command_server程序,再输入rosservice list,会发现多了个turtle_vel_command_server,如下图所示

然后,我们通过在终端输入rosservice call /turtle_vel_command_server调用这个服务,会发现小海龟做圆周运动,再次调用服务的话,小海龟停止了运动。这是因为在服务回调函数里边,我们把pubvel的值做了反转,然后反馈回去,主函数就会判断pubvel的值,如果是True就发布速度指令,为False则不发布指令。
8.2、python语言实现
8.2.1、切换至~/catkin_ws/src/learning_server目录下,新建一个script文件夹,切进去,新建一个py文件,命名为turtle_vel_command_server,把下边代码粘贴在里边
turtle_vel_command_server.py
xxxxxxxxxx #!/usr/bin/env python # -*- coding: utf-8 -*- # 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger import rospy import thread , time from geometry_msgs . msg import Twist from std_srvs . srv import Trigger , TriggerResponse pubvel = False ; turtle_vel_pub = rospy . Publisher ( '/turtle1/cmd_vel' , Twist , queue_size = 8 ) def pubvel_thread (): while True : if pubvel : vel_msg = Twist () vel_msg . linear . x = 0.6 vel_msg . angular . z = 0.8 turtle_vel_pub . publish ( vel_msg ) time . sleep ( 0.1 ) def pubvelCallback ( req ): global pubvel pubvel = bool ( 1 \- pubvel ) rospy . loginfo ( "Do you want to publish the vel?[%s]" , pubvel ) # 显示请求数据 return TriggerResponse ( 1 , "Change state!" ) # 反馈数据 def turtle_pubvel_command_server (): rospy . init_node ( 'turtle_vel_command_server' ) # ROS节点初始化 # 创建一个名为/turtle_command的server,注册回调函数pubvelCallback s = rospy . Service ( '/turtle_vel_command' , Trigger , pubvelCallback ) # 循环等待回调函数 print "Ready to receive turtle_pub_vel_command." thread . start_new_thread ( pubvel_thread , ()) rospy . spin () if __name__ == "__main__" : turtle_pubvel_command_server ()
1)、程序流程图

2)、运行程序
xxxxxxxxxx roscore rosrun turtlesim turtlesim_node rosrun learning_server turtle_vel_command_server.py
3)、程序运行效果和程序说明与C++实现的效果一致。