当前位置: 首页 > news >正文

【ROS实战】04-自定义消息并实现ROS服务

如何自定义消息并实现ROS服务

本文将介绍如何在 ROS Noetic 中自定义消息,并依托自定义的消息开发一个简单的服务端与客户端进行交互。具体来说,我们将创建一个 ROS 服务,该服务接受两个整数并返回它们的和以及一个格式化的信息。我们还会展示如何通过命令行和 Python 代码调用该服务,步骤包括自定义服务消息、编写服务端和客户端、启动和调用服务等内容。

目标

  1. 自定义服务消息:我们将创建一个新的服务消息,定义输入输出的格式。
  2. 编写服务端代码:实现一个服务端,该服务接收两个整数并返回它们的和及一个固定格式的字符串。
  3. 编写客户端代码:实现一个客户端脚本,向服务端发送请求并接收响应。
  4. 通过命令行调用服务:展示如何通过命令行调用服务。

开始之前

在开始之前,你需要确保已安装 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 的包,并依赖了 rospystd_msgs 两个 ROS 包。

2 定义服务消息

接下来,我们需要定义自定义的服务消息文件。创建一个名为 srv 的文件夹,在其中定义服务消息。

  1. add_two_integers 包内创建 srv 文件夹:

    mkdir ~/catkin_ws/src/add_two_integers/srv
    
  2. 在新建的srv文件夹下创建并编辑服务消息文件 AddTwoInts.srv,内容如下:

int64 a
int64 b
---
int64 sum
string info

这个服务消息文件包含了两个部分:

  • 请求部分:包含两个整数 ab,表示我们要相加的两个数字。
  • 响应部分:包含整数 sum,表示两个数字的和,以及字符串 info,准备同步返回一个格式化的信息(例如:“10 + 20 = 30”)。

3 修改 CMakeLists.txtpackage.xml

为了使 ROS 知道我们要生成服务消息,必须在 CMakeLists.txtpackage.xml 中进行相应的配置。

3.1 修改 CMakeLists.txt

打开 add_two_integers中的CMakeLists.txt 文件并找到find_package, add_service_filesgenerate_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_generationmessage_runtime 的依赖:

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

4 编写服务端代码

现在我们来编写服务端代码。在 add_two_integers 包中创建一个名为 add_two_integers_server.py 的文件。

  1. 创建服务端脚本:

    mkdir -p ~/catkin_ws/src/add_two_integers/scripts
    touch ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_server.py
    
  2. 编辑 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 节点并注册服务,等待客户端调用。
  3. 为脚本添加执行权限:

    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
    
  2. 编辑 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 创建客户端与服务端的通信。它将发送两个整数并接收响应。
    • 用户输入两个整数后,客户端将输出结果。
  3. 为客户端脚本添加执行权限:

    chmod +x ~/catkin_ws/src/add_two_integers/scripts/add_two_integers_client.py
    

6 编译和运行

在编写完服务端和客户端代码后,我们需要编译工作空间。

  1. 回到工作空间目录并编译:

    cd ~/catkin_ws
    catkin_make
    
  2. 启动 ROS core:

    roscore
    
  3. 启动服务端节点:

    source ~/catkin_ws/devel/setup.bash
    rosrun add_two_integers add_two_integers_server.py
    
  4. 启动客户端节点:

    打开一个新的终端并运行客户端脚本:

    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 中的服务机制。

相关文章:

  • Java 锁机制详解:用“厕所门”和“防盗门”轻松理解多线程同步
  • delphi intraweb 警告框
  • bluecode-数字增殖问题
  • CPU 4核8个逻辑处理器
  • 微服务集成测试 -华为OD机试真题(A卷、JavaScript)
  • 洛谷题单2-P5717 【深基3.习8】三角形分类-python-流程图重构
  • 页面加载过多图片导致卡顿——解决方案详解
  • 【蓝桥杯】单片机设计与开发,速成备赛
  • idea打包Plugin ‘org.springframework.boot:spring-boot-maven-plugin:’ not found
  • 【奇点时刻】GPT-4o新生图特性深度洞察报告
  • QT之QML(简单示例)
  • Three.js 实现 3D 数学欧拉角
  • 第六天 - os/subprocess模块 - 系统进程管理 - 练习:服务状态监控脚本
  • Qt远程连接数据库,注册,登录
  • 2025年江苏省职业院校技能大赛 (高职组)大数据应用开发赛项任务书 (样题)
  • 大语言模型智体的综述:方法论、应用和挑战(下)
  • C#高级:利用LINQ进行实体列表的集合运算
  • 基于SpringBoot的网上订餐系统(源码+数据库+万字文档+开题报告+ppt)
  • 核心知识——Spark核心数据结构:RDD
  • Libevent TCP开发指南
  • 以色列媒体:哈马斯愿意释放部分人员换取两个月停火
  • 幼儿园教师拍打孩子额头,新疆库尔勒教育局:涉事教师已被辞退
  • 美国务卿会见叙利亚外长,沙特等国表示将支持叙利亚重建
  • 《制止滥用行政权力排除、限制竞争行为规定(修订草案征求意见稿)》公开征求意见
  • “朱雀玄武敕令”改名“周乔治华盛顿”?警方称未通过审核
  • 河南信阳:对违规吃喝问题不遮丑不护短,露头就打、反复敲打