【ROS实战】04-自定义消息并实现ROS服务
如何自定义消息并实现ROS服务
本文将介绍如何在 ROS Noetic 中自定义消息,并依托自定义的消息开发一个简单的服务端与客户端进行交互。具体来说,我们将创建一个 ROS 服务,该服务接受两个整数并返回它们的和以及一个格式化的信息。我们还会展示如何通过命令行和 Python 代码调用该服务,步骤包括自定义服务消息、编写服务端和客户端、启动和调用服务等内容。
目标
- 自定义服务消息:我们将创建一个新的服务消息,定义输入输出的格式。
- 编写服务端代码:实现一个服务端,该服务接收两个整数并返回它们的和及一个固定格式的字符串。
- 编写客户端代码:实现一个客户端脚本,向服务端发送请求并接收响应。
- 通过命令行调用服务:展示如何通过命令行调用服务。
开始之前
在开始之前,你需要确保已安装 ROS Noetic,并且拥有一个工作空间(例如 ~/catkin_ws/)。如果你对 ROS 的背景或工作空间的概念不太了解,可以先阅读我专栏中的相关文章:《01-ROS安装详细指南》、《02-ROS架构介绍》和《03-从零实现小车运动控制的 ROS 功能包》。
1 创建 ROS 服务包
首先,我们需要在工作空间中创建一个新的包,并添加所需的依赖项。打开终端并进入工作空间目录:
cd ~/catkin_ws/src
然后使用 catkin_create_pkg
命令创建一个新的包:
catkin_create_pkg add_two_integers rospy std_msgs
这里我们创建了一个名为 add_two_integers
的包,并依赖了 rospy
和 std_msgs
两个 ROS 包。
2 定义服务消息
接下来,我们需要定义自定义的服务消息文件。创建一个名为 srv
的文件夹,在其中定义服务消息。
-
在
add_two_integers
包内创建srv
文件夹:mkdir ~/catkin_ws/src/add_two_integers/srv
-
在新建的
srv
文件夹下创建并编辑服务消息文件AddTwoInts.srv
,内容如下:
int64 a
int64 b
---
int64 sum
string info
这个服务消息文件包含了两个部分:
- 请求部分:包含两个整数
a
和b
,表示我们要相加的两个数字。 - 响应部分:包含整数
sum
,表示两个数字的和,以及字符串info
,准备同步返回一个格式化的信息(例如:“10 + 20 = 30”)。
3 修改 CMakeLists.txt
和 package.xml
为了使 ROS 知道我们要生成服务消息,必须在 CMakeLists.txt
和 package.xml
中进行相应的配置。
3.1 修改 CMakeLists.txt
打开 add_two_integers
中的CMakeLists.txt
文件并找到find_package
, add_service_files
和generate_messages
,确保它们没有被注释掉,并且和下面的内容一致:
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
message_generation
)
add_service_files(
FILES
AddTwoInts.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
这些配置告诉 ROS 编译器去生成服务相关的文件。
3.2 修改 package.xml
打开 add_two_integers
中的 package.xml
文件,确保添加了对 message_generation
和 message_runtime
的依赖:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
4 编写服务端代码
现在我们来编写服务端代码。在 add_two_integers
包中创建一个名为 add_two_integers_server.py
的文件。
-
创建服务端脚本:
mkdir -p ~/catkin_ws/src/add_two_integers/scripts touch ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_server.py
-
编辑
add_two_integers_server.py
,内容如下:#!/usr/bin/env python3 import rospy from add_two_integers.srv import AddTwoInts, AddTwoIntsResponse # 处理服务请求的函数 def handle_add_two_ints(req): # 计算两个整数的和 result = req.a + req.b # 格式化字符串信息 info = "{} + {} = {}".format(req.a, req.b, result) rospy.loginfo(info) # 返回结果和信息 return AddTwoIntsResponse(result, info) # 启动服务端节点 def add_two_ints_server(): rospy.init_node('add_two_ints_server') # 初始化 ROS 节点 rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints) # 注册服务 rospy.loginfo("Ready to add two integers.") # 服务启动的提示 rospy.spin() # 保持节点运行 if __name__ == "__main__": add_two_ints_server() # 启动服务
代码解释:
handle_add_two_ints
:这个函数处理客户端请求,它计算两个整数的和,并返回结果和一个格式化的字符串。add_two_ints_server
:这个函数初始化 ROS 节点并注册服务,等待客户端调用。
-
为脚本添加执行权限:
chmod +x ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_server.py
5 编写客户端代码
接下来我们编写一个客户端脚本,向服务端发送请求并获取响应。
-
创建客户端脚本:
touch ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_client.py
-
编辑
add_two_integers_client.py
,内容如下:#!/usr/bin/env python3 import rospy from add_two_integers.srv import AddTwoInts # 客户端调用服务的函数 def add_two_ints_client(a, b): # 等待服务可用 rospy.wait_for_service('add_two_ints') try: # 创建 ServiceProxy 对象 add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts) # 调用服务并返回响应 response = add_two_ints(a, b) return response.sum, response.info except rospy.ServiceException as e: print("Service call failed: %s" % e) if __name__ == "__main__": rospy.init_node('add_two_ints_client') # 获取用户输入 a = int(input("Enter first integer: ")) b = int(input("Enter second integer: ")) # 调用服务并打印结果 sum_result, info = add_two_ints_client(a, b) print(f"Result: {sum_result}, Info: {info}")
代码解释:
add_two_ints_client
:该函数通过ServiceProxy
创建客户端与服务端的通信。它将发送两个整数并接收响应。- 用户输入两个整数后,客户端将输出结果。
-
为客户端脚本添加执行权限:
chmod +x ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_client.py
6 编译和运行
在编写完服务端和客户端代码后,我们需要编译工作空间。
-
回到工作空间目录并编译:
cd ~/catkin_ws catkin_make
-
启动 ROS core:
roscore
-
启动服务端节点:
source ~/catkin_ws/devel/setup.bash rosrun add_two_integers add_two_integers_server.py
-
启动客户端节点:
打开一个新的终端并运行客户端脚本:
source ~/catkin_ws/devel/setup.bash rosrun add_two_integers add_two_integers_client.py
输入两个整数,客户端将显示结果和信息。
$ rosrun add_two_integers add_two_integers_client.py
Enter first integer: 1
Enter second integer: 1
Result: 2, Info: 1 + 1 = 2
7 通过命令行调用服务
首先,通过rosservice list
可以查看当前正在运行的服务列表,这里可以看到我们的服务/add_two_ints
~/catkin_ws$ rosservice list
/add_two_ints
然后我们可以通过命令行调用这个服务。使用以下命令调用服务并传入两个整数。
rosservice call /add_two_ints 10 20
返回:
sum: 30
info: "10 + 20 = 30"
命令参数说明:
rosservice call
:这是调用 ROS 服务的命令。/add_two_ints
:这是服务的名称。10 20
:这是请求的参数,表示我们要相加的两个整数。
总结
我们成功地在 ROS Noetic 中自定义了一个服务消息,并实现了一个简单的服务和客户端。本文展示了如何定义服务的输入和输出、编写服务端和客户端代码、启动和调用服务。同时,还展示了如何通过命令行调用服务。希望本教程能帮助你更好地理解 ROS 中的服务机制。