1.编程环境VScode
下载连接:Visual Studio Code - Code Editing. Redefined
Ubuntu系统需要下载.deb文件
用终端打开文件所在目录
cd ~/下载

安装VScode
sudo dpkg -i ./code_1.100.2-1747260578_amd64.deb
# code_1.100.2-1747260578_amd64.deb为文件名
sudo:提升权限,允许对系统文件进行修改
dpkg:调用 Debian 包管理工具。
-i:表示“install”(安装),指定要执行的操作为安装软件包
2.话题
2.1创建工作空间
创建文件夹
mkdir text1
进入文件夹目录
cd text1
当前文件夹下启动VScode
code ./

在当前目录下创建文件夹topic/src

调出VScode在text1下的终端
ros2 pkg create topic_ws --build-type ament_python --license Apache-2.0 --dependencies rclpy example_interfaces
ros2 pkg create是固定的
topic_ws:功能包名字
--build-type ament_python :功能包类型为python
--license Apache-2.0 :功能包许可用Apache-2.0
--dependencies rclpy example_interfaces:添加依赖项rclpy和example_interfaces
生成目录表如下:

回到topic/src目录下终端构建功能包(终端输入):
colcon build
colcon 是一个用于构建和测试 ROS 工作空间的工具。
build 是 colcon 的一个子命令,用于构建工作空间中的包。
2.2发布者
在src/topic_ws文件夹下创建python文件topic_pub.py(python文件是以.py结尾)
代码:
# 导入ROS2 Python客户端库
import rclpy
# 从rclpy.node模块导入Node类,用于创建ROS2节点
from rclpy.node import Node
# 导入requests库,用于发送HTTP请求获取网络资源
import requests
# 导入ROS2标准消息类型String
from example_interfaces.msg import String
# 导入Python标准库中的Queue,用于线程间通信
from queue import Queue
# 定义小说发布节点类,继承自Node类
class NovelPubNode(Node):
def __init__(self, node_name): # 节点初始化方法
super().__init__(node_name) # 调用父类Node的初始化方法
# 打印节点启动日志信息
self.get_logger().info(f'{node_name},启动')
# 创建一个先进先出(FIFO)队列,用于存储小说文本行
self.topic_queue = Queue()
# 创建一个发布者,发布到'novel'话题,消息类型为String,队列大小为10
self.topic_pubulisher = self.create_publisher(String,'novel',10)
# 创建一个定时器,每5秒触发一次timer_callback回调函数
self.create_timer(5, self.timer_callback)
# 定时器回调函数
def timer_callback(self):
# 检查队列中是否有待发布的消息
if self.topic_queue.qsize() > 0:
# 从队列中获取一行文本
line = self.topic_queue.get()
# 创建一个String消息对象
msg = String()
# 将文本行存入消息的data字段
msg.data = line
# 发布消息到'novel'话题
self.topic_pubulisher.publish(msg)
# 打印发布日志
self.get_logger().info(f'发布了:{msg}')
# 下载小说文本方法
def download(self, url):
# 发送GET请求获取URL内容
response = requests.get(url)
# 设置响应内容的编码为UTF-8(确保正确处理中文字符)
response.encoding = 'utf-8'
# 获取响应文本内容
text = response.text
# 打印下载信息(URL和文本长度)
self.get_logger().info(f'下载{url},{len(text)}')
# 按行分割文本并存入队列
for line in text.splitlines():
self.topic_queue.put(line)
# 主函数
def main():
# 初始化ROS2 Python客户端库
rclpy.init()
# 创建小说发布节点实例
node = NovelPubNode('novel_pub')
# 下载指定URL的小说文本
node.download('http://0.0.0:8000/斗破苍穹.txt')
# 保持节点运行,等待回调函数执行
rclpy.spin(node)
# 关闭ROS2 Python客户端库
rclpy.shutdown()
在setup.py中进行申明
'topic_pub = topic_ws.topic_pub:main'
打开新的终端启动一个基于当前目录的静态文件 Web 服务器,默认监听 0.0.0.0:8000(所有 网络接口,端口 8000)
python3 -m http.server
网络上随意下载一节小说包,命名放在text1空间下

构建功能包
colcon build
为当前终端会话加载 ROS 工作空间的环境变量和功能包路径
source install/setup.bash
用ros2运行
ros2 run topic_ws topic_pub # ros2运行topic_ws文件下的topic_pub可执行文件
2.3订阅者
先在安装python3-pip
sudo apt install python3-pip
pip3 install espeakng
sudo apt install espeak-ng
若在pip3 install espeakng部分报错error: externally-managed-environment,则需要虚拟环境能够创建独立的 Python 环境,可有效避免系统环境受到影响
# 安装python3.12-venv
sudo apt install python3.12-venv
# 创建虚拟环境
python3 -m venv myenv
# 激活虚拟环境
source myenv/bin/activate
# 在虚拟环境里安装包
pip install espeakng
# 使用完毕后停用虚拟环境
deactivate
我用Ubuntu24.04.2不知道为什么会报错没有独立的python环境,之前有用ubuntu22则不会报错。
在src/topic_ws文件夹下创建python文件topic_sub.py
import espeakng
# 导入ROS2 Python客户端库
import rclpy
# 从rclpy.node模块导入Node类,用于创建ROS2节点
from rclpy.node import Node
# 导入requests库,用于发送HTTP请求获取网络资源
import requests
# 导入ROS2标准消息类型String
from example_interfaces.msg import String
# 导入Python标准库中的Queue,用于线程间通信
from queue import Queue
import threading
import time
# 定义小说订阅节点类,继承自ROS2的Node基类
# 该节点负责订阅小说文本消息并通过语音合成朗读出来
class NovelSubNode(Node):
def __init__(self, node_name): # 节点初始化方法
super().__init__(node_name) # 调用父类Node的初始化方法
# 打印节点启动日志信息
self.get_logger().info(f'{node_name},启动')
# 创建一个先进先出(FIFO)队列,用于存储待朗读的小说文本行
# 使用队列的目的是解耦消息接收和语音合成处理,避免阻塞主线程
self.topic_queue = Queue()
# 创建一个订阅者,订阅名为'novel'的话题,消息类型为String
# 当接收到新消息时,调用novel_callback方法处理
self.topic_subscriber = self.create_subscription(
String,
'novel',
self.novel_callback,
10 # 消息队列大小,当消息处理不及时时最多缓存10条
)
# 创建并启动语音处理线程
# 该线程独立于ROS2主循环,专门负责语音合成和朗读
self.topic_thread = threading.Thread(target=self.speake_thread)
self.topic_thread.start()
# 话题回调函数,当接收到新的小说文本消息时被调用
def novel_callback(self, msg):
# 将接收到的文本消息放入队列
self.topic_queue.put(msg.data)
# 语音处理线程的主函数
def speake_thread(self):
# 初始化espeak-ng语音合成器
speaker = espeakng.Speaker()
# 设置中文语音,这里正常可以使用'zh',但我查询发现没有zh这个包,且'zh'朗读的听不清是否是中文
# 使用'cmn-latn-pinyin'语音,它支持中文拼音输入
# 若系统没有该语音,可能需要额外安装中文语音包
speaker.voice = 'cmn-latn-pinyin'
# 线程主循环,只要ROS2系统正常运行就持续执行
while rclpy.ok():
# 检查队列中是否有待处理的文本
if self.topic_queue.qsize() > 0:
# 从队列中取出一行文本
text = self.topic_queue.get()
# 记录日志,显示当前正在朗读的文本
self.get_logger().info(f'朗读:{text}')
# 使用语音合成器朗读文本
speaker.say(text)
# 等待当前文本朗读完成
speaker.wait()
else:
# 队列为空时休眠1秒,避免CPU空转
time.sleep(1)
# 主函数,程序入口点
def main():
# 初始化ROS2 Python客户端库
rclpy.init()
# 创建小说订阅节点实例
node = NovelSubNode('novel_sub')
# 进入节点的主循环,等待回调函数执行
# 该函数会阻塞,直到节点被关闭
rclpy.spin(node)
# 节点关闭后,清理ROS2资源
rclpy.shutdown()
在setup.py中进行申明
'topic_sub = topic_ws.topic_sub:main'
构建功能包
colcon build
为当前终端会话加载 ROS 工作空间的环境变量和功能包路径
source install/setup.bash
用ros2运行
ros2 run topic_ws topic_sub # ros2运行topic_ws文件下的topic_pub可执行文件
完成以上操作则可以完成小说发布,用户订阅朗读小说的功能
1172

被折叠的 条评论
为什么被折叠?



