ROS2学习笔记|实现订阅消息并朗读的详细步骤
本教程将详细介绍如何使用 ROS 2 实现一个节点订阅另一个节点发布的消息,并将接收到的消息通过 espeakng
库进行朗读的完整流程。以下步骤假设你已经安装好了 ROS 2 环境(以 ROS 2 Humble 为例),并熟悉基本的 Linux 操作。
注意:本文在上一篇的基础之上进阶,所以请先参考上一篇《。。》
编写发布者代码
(直接在上一篇的基础上改的)
1.进入功能包的 Python 代码目录:
cd ~/chapt3/topic_ws/src/demo_python_topic/demo_python_topic
2.创建 Python 脚本文件 novel_pub_node.py
,内容如下:
import rclpy
from rclpy.node import Node
import os
from example_interfaces.msg import Stringclass NovelPubNode(Node):def __init__(self, node_name):super().__init__(node_name)self.get_logger().info(f'{node_name},启动!')self.publisher_ = self.create_publisher(String, 'novel', 10)def publish_novel_from_file(self):workspace_dir = '/home/elf/chapt3/topic_ws'file_path = os.path.join(workspace_dir, 'novel1.txt')self.get_logger().info(f"尝试打开文件: {file_path}")try:with open(file_path, 'r', encoding='utf-8') as file:content = file.read()self.get_logger().info('开始发布小说内容:')msg = String()msg.data = contentself.publisher_.publish(msg)self.get_logger().info('小说内容发布完成')except FileNotFoundError:self.get_logger().error('未找到 novel1.txt 文件,请检查文件是否存在。')except Exception as e:self.get_logger().error(f'读取文件时出现错误:{e}')def main():rclpy.init()node = NovelPubNode('novel_pub')node.publish_novel_from_file()node.destroy_node()rclpy.shutdown()if __name__ == "__main__":main()
解释:
- 导入必要的模块,
rclpy
用于 ROS 2 Python 开发,os
用于文件操作,example_interfaces.msg.String
是消息类型。 NovelPubNode
类继承自Node
,在构造函数中初始化节点并创建发布者。publish_novel_from_file
方法读取指定文件内容,并将其发布到novel
话题。
编写订阅者代码
- 仍在
~/chapt3/topic_ws/src/demo_python_topic/demo_python_topic
目录下,创建 Python 脚本文件novel_sub_node.py
,内容如下:import espeakng import rclpy from rclpy.node import Node from example_interfaces.msg import String from queue import Queue import threading import timeclass NovelSubNode(Node):def __init__(self, node_name):super().__init__(node_name)self.get_logger().info(f'{node_name},启动!')self.novel_queue = Queue()self.novel_subscriber = self.create_subscription(String, 'novel', self.novel_callback, 10)self.speech_thread = threading.Thread(target=self.speak_thread)self.speech_thread.start()def novel_callback(self, msg):self.novel_queue.put(msg.data)def speak_thread(self):speaker = espeakng.Speaker()speaker.voice = 'zh'while rclpy.ok():if self.novel_queue.qsize() > 0:text = self.novel_queue.get()self.get_logger().info(f'朗读:{text}')speaker.say(text)speaker.wait()else:time.sleep(1)def main():rclpy.init()node = NovelSubNode('novel_sub')rclpy.spin(node)rclpy.shutdown()
解释:
- 导入必要的模块,
espeakng
用于语音合成,rclpy
等用于 ROS 2 开发。 NovelSubNode
类继承自Node
,在构造函数中初始化节点、创建订阅者和启动语音线程。novel_callback
方法将接收到的消息放入队列。speak_thread
方法从队列中取出消息并进行语音朗读。
配置setup.py文件
打开 ~/chapt3/topic_ws/src/demo_python_topic/setup.py
文件,在 entry_points
部分添加以下内容:
'console_scripts': ['novel_pub_node = demo_python_topic.novel_pub_node:main','novel_sub_node = demo_python_topic.novel_sub_node:main',
],
解释:console_scripts
用于定义命令行可执行脚本,分别指定了发布者和订阅者节点的可执行入口。
编译工作空间
cd ~/chapt3/topic_ws
colcon build
source install/setup.bash
解释:重新编译工作空间,使新添加或修改的代码生效。编译完成后设置工作空间环境变量。
运行节点
- 打开一个新终端,运行发布者节点:
ros2 run demo_python_topic novel_pub_node
2.再打开一个新终端,运行订阅者节点:
ros2 run demo_python_topic novel_sub_node
此时,订阅者节点会接收到发布者节点发布的消息,并将消息内容通过 espeakng
库进行朗读。