ROS高效入门第六章 -- 自定义ROS服务,编写python server+client样例

本文介绍了如何使用Python在ROS中编写自定义服务,包括基于turtlesim繁殖多个小乌龟的客户端、实现两个整数求和的自定义服务以及控制小乌龟转向的服务器和客户端。每个示例都详细阐述了创建服务包、编写服务接口、客户端调用和服务响应的过程,并提供了相应的CMakeLists.txt和launch文件。
摘要由CSDN通过智能技术生成

1 资料

本章节是本人 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/python
catkin_create_pkg spawn_turtle turtlesim roscpp rospy

mkdir launch scripts
touch launch/start.launch scripts/spawn_turtle.py

(2)编写spawn_turtle.py

#! /usr/bin/env python3
import rospy
import math
from turtlesim.srv import Spawn, SpawnRequest

def 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

<launch>
<node
    pkg="turtlesim"
    type="turtlesim_node"
    name="turtlesim"
    required="true"
/>
<node
    pkg="spawn_turtle"
    type="spawn_turtle.py"
    name="spawn_turtle_node"
    output="screen"
/>
</launch>

(5)编译并运行

cd ~/catkin_ws
catkin_make --source src/python/spawn_turtle/
source devel/setup.bash
roslaunch spawn_turtle start.launch

在这里插入图片描述

2.2 自定义服务,写server+client,实现两个整数求和

(1)此例主要是演示如何自定义服务,实现的功能很简单:client向server发送两个整数,server返回整数和。创建srv_self软件包和文件:

cd ~/catkin_ws/src/python
catkin_create_pkg srv_self message_generation rospy roscpp std_msgs message_runtime
mkdir launch srv scripts
touch launch/start.launch srv/AddTwoInts.srv scripts/server.py scripts/client.py

(2)编写AddTwoInts.srv,server.py和client.py
AddTwoInts.srv

int64 a
int64 b
---
int64 sum

server.py

#! /usr/bin/env python3

import rospy
// 导入AddTwoInts和对应的AddTwoIntsResponse,除此之外,还有AddTwoIntsRequest
from srv_self.srv import AddTwoInts, AddTwoIntsResponse
// 服务的回调函数,参数为AddTwoIntsRequest,返回是AddTwoIntsResponse
def 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 resp

def 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 python3

import rospy
import random
from 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

<launch>
<node
    pkg="srv_self"
    type="server.py"
    name="add_server"
    respawn="true"
    output="screen"
/>
<node
    pkg="srv_self"
    type="client.py"
    name="add_client"
    required="true"
    output="screen"
/>
</launch>

(5)编译并运行

cd ~/catkin_ws
catkin_make --source src/python/srv_self/
source devel/setup.bash
roslaunch srv_self start.launch

在这里插入图片描述

2.3 基于turtlesim,写server+client,控制小乌龟转向

(1)本样例基于turtlesim,client向server申请修改全局控制量forward,server收到后,根据修改后的forward,向turtlesim_node发送新的运动命令,最终实现控制小乌龟转向。
创建toggle_forward软件包和文件:

cd ~/catkin_ws/src/python
catkin_create_pkg toggle_forward turtlesim geometry_msgs std_srvs roscpp rospy
mkdir launch scripts
touch launch/start.launch scripts/toggle_server.py scripts/toggle_client.py

(2)编写toggle_server.py和toggle_client.py
toggle_server.py

#! /usr/bin/env python3

import rospy
from geometry_msgs.msg import Twist
from std_srvs.srv import Empty, EmptyResponse
// 定义全量变量g_forward 
g_forward = True

def 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 python3
import rospy
from std_srvs.srv import Empty, EmptyRequest

def 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

<launch>
<node
    pkg="turtlesim"
    type="turtlesim_node"
    name="turtlesim"
    required="true"
/>
<node
    pkg="toggle_forward"
    type="toggle_server.py"
    name="toggle_forward_server"
    output="screen"
/>
<node
    pkg="toggle_forward"
    type="toggle_client.py"
    name="toggle_forward_client"
    output="screen"
/>
</launch>

(5)编译并运行

cd ~/catkin_ws
catkin_make --source src/python/toggle_forward/
source devel/setup.bash
roslaunch toggle_forward start.launch

在这里插入图片描述

3 总结

本文中的例子放在了本人的github上: ros_src

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值