本章节是本人 ROS高效入门第五章 – 自定义ROS服务,编写C++ server+client样例 的姊妹篇,使用 python 编写同样的三个样例,建议对比阅读,主要参考资料是一样的: (1)《机器人操作系统(ROS)浅析》[美] Jason M. O’Kane 著 肖军浩 译,第8章 (2)ros Tutorials 初级教程的10,14~16节: ros Tutorials 本系列博客汇总:ROS高效入门系列。
2 正文 2.1 基于turtlesim,写一个客户端,申请繁殖多个小乌龟(1)第一个样例基于turtlesim实现,只编写一个client,向turtlesim的/spawn服务发送请求,申请繁殖多个小乌龟。 创建spawn_turtle软件包和相关文件:
cd ~/catkin_ws/src/pythoncatkin_create_pkg spawn_turtle turtlesim roscpp rospymkdir launch scriptstouch launch/start.launch scripts/spawn_turtle.py(2)编写spawn_turtle.py
#! /usr/bin/env python3import rospyimport mathfrom turtlesim.srv import Spawn, SpawnRequestdef main(): rospy.init_node("spawn_turtle") // 建立client句柄,等待/spawn服务 client = rospy.ServiceProxy("spawn", Spawn) rospy.wait_for_service("spawn") for i in range(10): try: req = SpawnRequest() req.x = 1 + i req.y = 1 + i req.theta = math.pi/2 req.name = "Leo%s" %i// 调用服务/spawn,传入req,返回resp resp = client(req) rospy.loginfo("spawned a turtle name %s" %resp.name) // 服务调用失败,用异常捕捉 except rospy.ServiceException as e: rospy.loginfo("service call fail: %s" %e)if __name__ == "__main__": main()(3)编写CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)project(spawn_turtle)find_package(catkin REQUIRED COMPONENTS roscpp rospy turtlesim)catkin_package()include_directories( ${catkin_INCLUDE_DIRS})catkin_install_python(PROGRAMS scripts/spawn_turtle.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})(4)编写start.launch
(5)编译并运行
cd ~/catkin_wscatkin_make --source src/python/spawn_turtle/source devel/setup.bashroslaunch spawn_turtle start.launch 2.2 自定义服务,写server+client,实现两个整数求和(1)此例主要是演示如何自定义服务,实现的功能很简单:client向server发送两个整数,server返回整数和。创建srv_self软件包和文件:
cd ~/catkin_ws/src/pythoncatkin_create_pkg srv_self message_generation rospy roscpp std_msgs message_runtimemkdir launch srv scriptstouch launch/start.launch srv/AddTwoInts.srv scripts/server.py scripts/client.py(2)编写AddTwoInts.srv,server.py和client.py AddTwoInts.srv
int64 aint64 b---int64 sumserver.py
#! /usr/bin/env python3import rospy// 导入AddTwoInts和对应的AddTwoIntsResponse,除此之外,还有AddTwoIntsRequestfrom srv_self.srv import AddTwoInts, AddTwoIntsResponse// 服务的回调函数,参数为AddTwoIntsRequest,返回是AddTwoIntsResponsedef add(req): resp = AddTwoIntsResponse() resp.sum = req.a + req.b rospy.loginfo("server: receive a = %ld, b = %ld, return sum = %ld" %(req.a, req.b, resp.sum)) return respdef main(): rospy.init_node("add_server") // 建立server句柄,发布/add_ints服务,数据类型是AddTwoInts srv = rospy.Service("add_ints", AddTwoInts, add) rospy.loginfo("ready to add ints..") rospy.spin()if __name__ == "__main__": main()client.py
#! /usr/bin/env python3import rospyimport randomfrom srv_self.srv import *def main(): rospy.init_node("add_client") // 建立client句柄,调用/add_ints服务 client = rospy.ServiceProxy("add_ints", AddTwoInts) rospy.wait_for_service("add_ints") rate = rospy.Rate(1) while not rospy.is_shutdown(): try: req = AddTwoIntsRequest() req.a = random.randint(1, 100) req.b = random.randint(1, 100) // 调用服务 resp = client(req) rospy.loginfo("client: send a = %ld, b = %ld, receive sum = %ld" %(req.a, req.b, resp.sum)) except rospy.ServiceException as e: rospy.loginfo("service call fail: %s" %e) rate.sleep()if __name__ == "__main__": main()(3)编写CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)project(srv_self)find_package(catkin REQUIRED COMPONENTS message_generation roscpp rospy std_msgs)add_service_files( FILES AddTwoInts.srv)generate_messages( DEPENDENCIES std_msgs)catkin_package()include_directories( ${catkin_INCLUDE_DIRS})catkin_install_python(PROGRAMS scripts/server.py scripts/client.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})(4)编写start.launch
(5)编译并运行
cd ~/catkin_wscatkin_make --source src/python/srv_self/source devel/setup.bashroslaunch srv_self start.launch 2.3 基于turtlesim,写server+client,控制小乌龟转向(1)本样例基于turtlesim,client向server申请修改全局控制量forward,server收到后,根据修改后的forward,向turtlesim_node发送新的运动命令,最终实现控制小乌龟转向。 创建toggle_forward软件包和文件:
cd ~/catkin_ws/src/pythoncatkin_create_pkg toggle_forward turtlesim geometry_msgs std_srvs roscpp rospymkdir launch scriptstouch launch/start.launch scripts/toggle_server.py scripts/toggle_client.py(2)编写toggle_server.py和toggle_client.py toggle_server.py
#! /usr/bin/env python3import rospyfrom geometry_msgs.msg import Twistfrom std_srvs.srv import Empty, EmptyResponse// 定义全量变量g_forward g_forward = Truedef toggleForward(req): global g_forward // g_forward 取反 g_forward = not g_forward fwd = "forward" if g_forward else "rotate" rospy.loginfo("now receiveing: %s" %fwd) // 返回空的EmptyResponse(不能像cpp中那样,返回true,运行会出错) return EmptyResponse()def main(): global g_forward rospy.init_node("toggle_server") // 建立server句柄,监听 /toggle_forward 服务 srv = rospy.Service("toggle_forward", Empty, toggleForward) pub = rospy.Publisher("turtle1/cmd_vel", Twist, queue_size=10) rate = rospy.Rate(2) while not rospy.is_shutdown(): msg = Twist() // 根据 g_forward 值,调整小乌龟运动方向 msg.linear.x = 1.0 if g_forward else 0.0 msg.angular.z = 0.0 if g_forward else 1.0 pub.publish(msg) rate.sleep() rospy.spin()if __name__ == "__main__": main()toggle_client.py
#! /usr/bin/env python3import rospyfrom std_srvs.srv import Empty, EmptyRequestdef main(): rospy.init_node("toggle_client") client = rospy.ServiceProxy("toggle_forward", Empty) rospy.wait_for_service("toggle_forward") rate = rospy.Rate(2) while True: try: // 发送空的服务申请 req = EmptyRequest() resp = client(req) rospy.loginfo("send toggle cmd") except rospy.ServiceException as e: rospy.loginfo("send toggle cmd failed: %s" %e) rate.sleep()if __name__ == "__main__": main()(3)编写CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)project(toggle_forward)find_package(catkin REQUIRED COMPONENTS geometry_msgs roscpp rospy std_srvs turtlesim)catkin_package()include_directories( ${catkin_INCLUDE_DIRS})catkin_install_python(PROGRAMS scripts/toggle_server.py scripts/toggle_client.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})(4)编写start.launch
(5)编译并运行
cd ~/catkin_wscatkin_make --source src/python/toggle_forward/source devel/setup.bashroslaunch toggle_forward start.launch 3 总结