【ROS实战】04-自定义消息并实现ROS服务
【ROS实战】04-自定义消息并实现ROS服务
赵洲洋如何自定义消息并实现ROS服务
本文将介绍如何在 ROS Noetic 中自定义消息,并依托自定义的消息开发一个简单的服务端与客户端进行交互。具体来说,我们将创建一个 ROS 服务,该服务接受两个整数并返回它们的和以及一个格式化的信息。我们还会展示如何通过命令行和 Python 代码调用该服务,步骤包括自定义服务消息、编写服务端和客户端、启动和调用服务等内容。
目标
- 自定义服务消息:我们将创建一个新的服务消息,定义输入输出的格式。
- 编写服务端代码:实现一个服务端,该服务接收两个整数并返回它们的和及一个固定格式的字符串。
- 编写客户端代码:实现一个客户端脚本,向服务端发送请求并接收响应。
- 通过命令行调用服务:展示如何通过命令行调用服务。
开始之前
在开始之前,你需要确保已安装 ROS Noetic,并且拥有一个工作空间(例如 ~/catkin_ws/)。如果你对 ROS 的背景或工作空间的概念不太了解,可以先阅读我专栏中的相关文章:《01-ROS安装详细指南》、《02-ROS架构介绍》和《03-从零实现小车运动控制的 ROS 功能包》。
1 创建 ROS 服务包
首先,我们需要在工作空间中创建一个新的包,并添加所需的依赖项。打开终端并进入工作空间目录:
1 | cd ~/catkin_ws/src |
然后使用 catkin_create_pkg
命令创建一个新的包:
1 | catkin_create_pkg add_two_integers rospy std_msgs |
这里我们创建了一个名为 add_two_integers
的包,并依赖了 rospy
和 std_msgs
两个 ROS 包。
2 定义服务消息
接下来,我们需要定义自定义的服务消息文件。创建一个名为 srv
的文件夹,在其中定义服务消息。
在
add_two_integers
包内创建srv
文件夹:1
mkdir ~/catkin_ws/src/add_two_integers/srv
在新建的
srv
文件夹下创建并编辑服务消息文件AddTwoInts.srv
,内容如下:
1 | int64 a |
这个服务消息文件包含了两个部分:
- 请求部分:包含两个整数
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
,确保它们没有被注释掉,并且和下面的内容一致:
1 | find_package(catkin REQUIRED COMPONENTS |
这些配置告诉 ROS 编译器去生成服务相关的文件。
3.2 修改 package.xml
打开 add_two_integers
中的 package.xml
文件,确保添加了对 message_generation
和 message_runtime
的依赖:
1 | <build_depend>message_generation</build_depend> |
4 编写服务端代码
现在我们来编写服务端代码。在 add_two_integers
包中创建一个名为 add_two_integers_server.py
的文件。
创建服务端脚本:
1
2mkdir -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
,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#!/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 节点并注册服务,等待客户端调用。
为脚本添加执行权限:
1
chmod +x ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_server.py
5 编写客户端代码
接下来我们编写一个客户端脚本,向服务端发送请求并获取响应。
创建客户端脚本:
1
touch ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_client.py
编辑
add_two_integers_client.py
,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#!/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
创建客户端与服务端的通信。它将发送两个整数并接收响应。- 用户输入两个整数后,客户端将输出结果。
为客户端脚本添加执行权限:
1
chmod +x ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_client.py
6 编译和运行
在编写完服务端和客户端代码后,我们需要编译工作空间。
回到工作空间目录并编译:
1
2cd ~/catkin_ws
catkin_make启动 ROS core:
1
roscore
启动服务端节点:
1
2source ~/catkin_ws/devel/setup.bash
rosrun add_two_integers add_two_integers_server.py启动客户端节点:
打开一个新的终端并运行客户端脚本:
1
2source ~/catkin_ws/devel/setup.bash
rosrun add_two_integers add_two_integers_client.py输入两个整数,客户端将显示结果和信息。
1 | $ rosrun add_two_integers add_two_integers_client.py |
7 通过命令行调用服务
首先,通过rosservice list
可以查看当前正在运行的服务列表,这里可以看到我们的服务/add_two_ints
1 | ~/catkin_ws$ rosservice list |
然后我们可以通过命令行调用这个服务。使用以下命令调用服务并传入两个整数。
1 | rosservice call /add_two_ints 10 20 |
返回:
1 | sum: 30 |
命令参数说明:
rosservice call
:这是调用 ROS 服务的命令。/add_two_ints
:这是服务的名称。10 20
:这是请求的参数,表示我们要相加的两个整数。
总结
我们成功地在 ROS Noetic 中自定义了一个服务消息,并实现了一个简单的服务和客户端。本文展示了如何定义服务的输入和输出、编写服务端和客户端代码、启动和调用服务。同时,还展示了如何通过命令行调用服务。希望本教程能帮助你更好地理解 ROS 中的服务机制。