跳到主要内容

2. 离线文字转语音(TTS)

2. 离线文字转语音(TTS)1. 概念介绍1.1 “TTS”是什么?1.2 实现原理简述1. 文本分析2. 语言处理3. 语音合成4. 声音波形生成2. 代码解析关键代码1. TTS 初始化与调用 (largemodel/largemodel/model_service.py)2. TTS 后端实现 (largemodel/utils/large_model_interface.py)代码解析3. 实践操作3.1 配置离线TTS功能3.2 启动并测试功能4. 常见问题与解决方案4.1 播放问题问题1:程序运行正常,没有报错,但听不到任何声音。


1. 概念介绍

1.1 “TTS”是什么?

TTS技术是一种将书面文本转化为人类可听的语音输出的技术。它使得计算机能够“朗读”文字内容,广泛应用于无障碍阅读、智能助手、导航系统、教育软件等多个领域。通过TTS,用户可以听到由机器生成的自然流畅的人声,极大地提升了信息获取的便捷性和灵活性。

1.2 实现原理简述

TTS系统的实现主要包括以下几个关键步骤和技术:

1. 文本分析

  • 在这一阶段,输入的文本首先会被进行预处理,包括但不限于去除无关字符、标准化标点符号和大小写、分词以及识别数字等特殊符号并将其转换为相应的单词形式。
  • 同时,还需要对文本进行语言学分析,例如确定每个词的发音(这通常需要使用发音词典)、重音位置、语调模式以及句子结构等。

2. 语言处理

  • 此步骤主要关注于如何根据上下文正确地发音和调整语调。例如,“read”这个词在不同的时态下有不同的发音(过去式/过去分词发音为/red/,而其他情况发音为/riːd/)。因此,需要一个强大的语言模型来理解这些细微差别。
  • 这里也会涉及到韵律建模,即决定哪些部分应该被强调,语速应该是快还是慢,以及整个句子的情感色彩等。

3. 语音合成

  • 经过前面两个阶段处理后的文本信息会被送入语音合成引擎中,该引擎负责生成实际的声音波形。
  • 传统的TTS系统采用拼接合成方法,即从预先录制好的语音片段数据库中选择合适的单元进行拼接以形成完整的句子。这种方法虽然可以产生高质量的语音,但受限于数据库中的样本。
  • 现代的TTS系统更多地依赖于参数合成或神经网络合成(如WaveNet, Tacotron等),这些方法可以直接从文本预测语音特征,并生成连续的声音信号。特别是基于深度学习的方法,它们能更好地捕捉语音的细微变化,从而生产出更加自然流畅的声音。

4. 声音波形生成

  • 最终,生成的声音波形会被进一步处理,以确保其质量符合预期的标准,比如调整音量、均衡频率响应等。
  • 之后,这些音频数据就可以通过扬声器或其他音频播放设备播放出来,供人们聆听。

随着人工智能和机器学习技术的发展,尤其是深度学习的应用,TTS系统不仅在准确性方面有了显著提高,在自然度和情感表达上也取得了长足的进步,使得机器生成的语音越来越接近真实人声。

2. 代码解析

关键代码

1. TTS 初始化与调用 (largemodel/largemodel/model_service.py)

​ x # From largemodel/largemodel/model_service.py class LargeModelService ( Node ): def __init__ ( self ): # ... self . system_sound_init () # ... ​ def init_param_config ( self ): # ... self . declare_parameter ( 'useolinetts' , False ) self . useolinetts = self . get_parameter ( 'useolinetts' ). get_parameter_value (). bool_value if self . useolinetts : self . tts_out_path = os . path . join ( self . pkg_path , "resources_file" , "tts_output.mp3" ) else : self . tts_out_path = os . path . join ( self . pkg_path , "resources_file" , "tts_output.wav" ) ​ def system_sound_init ( self ): """Initialize TTS system""" model_type = "oline" if self . useolinetts else "local" self . model_client . tts_model_init ( model_type , self . language ) self . get_logger (). info ( f'TTS initialized with {model_type} model' ) ​ def _safe_play_audio ( self , text_to_speak : str ): """ Synthesizes and plays all non-empty messages only in non-text chat mode. """ if not self . text_chat_mode and text_to_speak : try : self . model_client . voice_synthesis ( text_to_speak , self . tts_out_path ) self . play_audio_async ( self . tts_out_path ) except Exception as e : self . get_logger (). error ( f"Safe audio playback failed: {e}" )

2. TTS 后端实现 (largemodel/utils/large_model_interface.py)

xxxxxxxxxx # From largemodel/utils/large_model_interface.py class model_interface : # ... def tts_model_init ( self , model_type = 'oline' , language = 'zh' ): if model_type == 'oline' : if self . tts_supplier == 'baidu' : self . token = self . fetch_token () self . model_type = 'oline' elif model_type == 'local' : self . model_type = 'local' if language == 'zh' : tts_model = self . zh_tts_model tts_json = self . zh_tts_json elif language == 'en' : tts_model = self . en_tts_model tts_json = self . en_tts_json self . synthesizer = piper . PiperVoice . load ( tts_model , config_path = tts_json , use_cuda = False ) ​ def voice_synthesis ( self , text , path ): if self . model_type == 'oline' : if self . tts_supplier == 'baidu' : # ... (Baidu TTS implementation) pass elif self . tts_supplier == 'aliyun' : # ... (Aliyun TTS implementation) pass elif self . model_type == 'local' : with wave . open ( path , 'wb' ) as wav_file : wav_file . setnchannels ( 1 ) wav_file . setsampwidth ( 2 ) wav_file . setframerate ( self . synthesizer . config . sample_rate ) self . synthesizer . synthesize ( text , wav_file )

代码解析

文字转语音(TTS)功能由LargeModelService节点发起调用,由model_interface类提供具体实现。其设计通过参数配置来切换不同的后端服务。

  1. 初始化流程 (model_service.py):

    • LargeModelService初始化时,init_param_config函数会从ROS参数服务器读取布尔值useolinetts
    • system_sound_init函数根据useolinetts的值,决定向self.model_client.tts_model_init方法传递'local''oline'字符串。
    • large_model_interface.py中,tts_model_init方法根据接收到的字符串参数,执行相应的初始化逻辑。如果是'local',则使用piper.PiperVoice.load加载本地模型文件。
  2. 合成与播放流程 (model_service.py):

    • 当需要语音播报时,_safe_play_audio函数被调用。
    • 该函数首先调用self.model_client.voice_synthesis方法,并传入需要转换的文本和目标音频路径self.tts_out_path
    • voice_synthesis方法执行完毕并生成音频文件后,_safe_play_audio接着调用self.play_audio_async来异步播放该文件。
  3. 后端实现选择 (large_model_interface.py):

    • voice_synthesis方法是TTS功能的后端分发中心。它内部通过检查在初始化时设置的self.model_type属性值来选择执行路径。
    • 如果self.model_type'local',代码块会使用Python的wave库打开一个WAV文件,设置其头部参数(声道、采样位宽、采样率),然后调用self.synthesizer.synthesize方法将文本合成的音频流直接写入该文件。
    • 如果self.model_type'oline',则会进入针对不同云服务商(如Baidu, Aliyun)的逻辑分支。
    • 这种结构将上层节点的调用(“说这段话”)与下层具体的合成技术(使用哪个库、调用哪个API)分离开来。

3. 实践操作

3.1 配置离线TTS功能

要启用离线TTS,需要正确配置yahboom.yamllarge_model_interface.yaml,并确保本地模型正确放置。

  1. 打开主配置文件 :

xxxxxxxxxx vim ~/yahboom_ws/src/largemodel/config/yahboom.yaml 2. 修改/确认以下关键配置 :

xxxxxxxxxx model_service : #模型服务器节点参数 ros__parameters : language : 'zh' #大模型接口语言 useolinetts : False #是否使用在线语音合成(True使用在线,False使用离线) regional_setting : "China"

useolinetts 这里要确保是False才能使用本地模型。

语言选择zh是中文,en是英语。

  1. 打开模型接口配置文件 :

xxxxxxxxxx vim ~/yahboom_ws/src/largemodel/config/large_model_interface.yaml 4. 确认离线模型路径 :

xxxxxxxxxx # large_model_interface.yaml ## 离线语音合成 (Offline TTS) # 中文TTS模型 zh_tts_model : "/home/jetson/yahboom_ws/src/largemodel/MODELS/tts/zh/zh_CN-huayan-medium.onnx" zh_tts_json : "/home/jetson/yahboom_ws/src/largemodel/MODELS/tts/zh/zh_CN-huayan-medium.onnx.json" ​ # 英文TTS模型 en_tts_model : "/home/jetson/yahboom_ws/src/largemodel/MODELS/tts/en/en_US-libritts-high.onnx" en_tts_json : "/home/jetson/yahboom_ws/src/largemodel/MODELS/tts/en/en_US-libritts-high.onnx.json"

3.2 启动并测试功能

  1. 启动TTS节点 : 运行下面的命令:

xxxxxxxxxx ros2 launch largemodel tts_only.launch.py

image-20250807165129463

  1. 发送待合成的文本 : 打开一个新的终端,运行下面的命令就可以发布一条语音播报的消息:

xxxxxxxxxx ros2 topic pub \--once /tts_text_input std_msgs/msg/String '{data: "语音合成测试成功"}' 3. 测试 : 如果一切正常,你应该能从你的扬声器中听到机器人用合成的语音说出“语音合成测试成功”。


4. 常见问题与解决方案

4.1 播放问题

问题1:程序运行正常,没有报错,但听不到任何声音。

解决方案 :

  1. 检查音频输出 :确认你的系统音频输出设备选择正确,且音量不是静音。可以尝试播放一个普通的音乐文件来测试硬件。

  2. 设置中的Sound,要把Balance保持在中间位置

image-20250807155119783