Skip to main content

1. 离线语音转文字(ASR)

1. 离线语音转文字(ASR)1. 概念介绍1.1 “ASR”是什么?1.2 实现原理1. 声学模型2. 语言模型3. 发音词典4. 解码器5. 端到端ASR2. 代码解析关键代码1. 语音处理与识别核心 (largemodel/largemodel/asr.py)2. VAD智能录音 (largemodel/largemodel/asr.py)代码解析3. 实践操作3.1 配置离线ASR功能3.2 启动并测试功能


1. 概念介绍

1.1 “ASR”是什么?

ASR(Automatic Speech Recognition,自动语音识别)是一种将人类的语音信号转化为文本的技术。它广泛应用于智能助手、语音命令控制、电话客服自动化、实时字幕生成等领域。ASR 的目标是让机器能够“听懂”人类的语言,并将其转换为计算机可以处理和理解的形式。

1.2 实现原理

ASR 系统的实现主要依赖于以下几个关键技术组件:

1. 声学模型

  • 声学模型负责将输入的声音信号转换为音素或子词单元。这通常涉及到特征提取步骤,如使用梅尔频率倒谱系数(MFCCs)或滤波器组(Filter Banks)来表示音频信号。
  • 这些特征随后被送入深度神经网络(DNN)、卷积神经网络(CNN)、循环神经网络(RNN)或者更先进的Transformer架构中进行训练,以学习如何从音频特征映射到对应的音素或文字。

2. 语言模型

  • 语言模型用于预测在给定前文条件下下一个最可能出现的词语,从而帮助提高识别准确性。它基于大量的文本数据训练而成,了解哪些词汇序列更有可能出现。
  • 常见的语言模型包括n-gram模型、RNN-based LM以及最近流行的Transformer-based LM等。

3. 发音词典

  • 发音词典提供了单词与它们对应的发音之间的映射关系。这对于连接声学模型和语言模型至关重要,因为它允许系统根据已知的发音规则去理解和匹配听到的声音。

4. 解码器

  • 解码器的任务是在给定声学模型、语言模型和发音词典的情况下,找到最可能的单词序列作为输出。这个过程通常涉及复杂的搜索算法,比如Viterbi算法或者是基于图的搜索方法,用来寻找最优路径。

5. 端到端ASR

  • 随着深度学习的发展,出现了端到端的ASR系统,这些系统试图直接从原始音频信号中学习到文本输出,而不需要显式的声学模型、发音词典和语言模型分离设计。这类系统常常基于序列到序列(Seq2Seq)框架,例如使用注意力机制(Attention Mechanism)或Transformer架构,大大简化了传统ASR系统的复杂度。

总的来说,现代ASR系统通过结合上述各个组件,并利用大规模的数据集和强大的计算资源进行训练,实现了高效准确的人类语音转文字的能力。随着技术的进步,ASR系统的性能也在持续提升,应用场景也日益广泛。


2. 代码解析

关键代码

1. 语音处理与识别核心 (largemodel/largemodel/asr.py)

​ x # From largemodel/largemodel/asr.py def kws_handler ( self ) -> None : if self . stop_event . is_set (): return ​ if self . listen_for_speech ( self . mic_index ): asr_text = self . ASR_conversion ( self . user_speechdir ) # 进行 ASR 转换 / Perform ASR conversion if asr_text == 'error' : # 检查 ASR 结果长度是否小于4个字符 / Check if ASR result length is less than 4 characters self . get_logger (). warn ( "I still don't understand what you mean. Please try again" ) playsound ( self . audio_dict [ self . error_response ]) # 错误响应 / Error response else : self . get_logger (). info ( asr_text ) self . get_logger (). info ( "okay😀, let me think for a moment..." ) self . asr_pub_result ( asr_text ) # 发布 ASR结果 / Publish ASR result else : return ​ def ASR_conversion ( self , input_file : str ) -> str : if self . use_oline_asr : result = self . modelinterface . oline_asr ( input_file ) if result [ 0 ] == 'ok' and len ( result [ 1 ]) > 4 : return result [ 1 ] else : self . get_logger (). error ( f'ASR Error:{result[1]}' ) # ASR error. return 'error' else : result = self . modelinterface . SenseVoiceSmall_ASR ( input_file ) if result [ 0 ] == 'ok' and len ( result [ 1 ]) > 4 : return result [ 1 ] else : self . get_logger (). error ( f'ASR Error:{result[1]}' ) # ASR error. return 'error'

2. VAD智能录音 (largemodel/largemodel/asr.py)

xxxxxxxxxx # From largemodel/largemodel/asr.py def listen_for_speech ( self , mic_index = 0 ): p = pyaudio . PyAudio () # Create PyAudio instance. / 创建PyAudio实例。 audio_buffer = [] # Store audio data. / 存储音频数据。 silence_counter = 0 # Silence counter. / 静音计数器。 MAX_SILENCE_FRAMES = 90 # 30帧*30ms=900ms静音后停止 / Stop after 900ms of silence (30 frames * 30ms) speaking = False # Flag indicating speech activity. / 语音活动标志。 frame_counter = 0 # Frame counter. / 计数器。 stream_kwargs = { 'format' : pyaudio . paInt16 , 'channels' : 1 , 'rate' : self . sample_rate , 'input' : True , 'frames_per_buffer' : self . frame_bytes , } if mic_index ! = 0 : stream_kwargs [ 'input_device_index' ] = mic_index ​ # Prompt the user to speak via the buzzer. / 通过蜂鸣器提示用户讲话。 self . pub_beep . publish ( UInt16 ( data = 1 )) time . sleep ( 0.5 ) self . pub_beep . publish ( UInt16 ( data = 0 )) ​ try : # Open audio stream. / 打开音频流。 stream = p . open ( ** stream_kwargs ) while True : if self . stop_event . is_set (): return False frame = stream . read ( self . frame_bytes , exception_on_overflow = False ) # Read audio data. / 读取音频数据。 is_speech = self . vad . is_speech ( frame , self . sample_rate ) # VAD detection. / VAD检测。 ​ if is_speech : # Detected speech activity. / 检测到语音活动。 speaking = True audio_buffer . append ( frame ) silence_counter = 0 else : if speaking : # Detect silence after speech activity. / 在语音活动后检测静音。 silence_counter += 1 audio_buffer . append ( frame ) # Continue recording buffer. / 持续记录缓冲。 # End recording when silence duration meets the threshold. / 静音持续时间达标时结束录音。 if silence_counter > = MAX_SILENCE_FRAMES : break frame_counter += 1 if frame_counter % 2 == 0 : self . get_logger (). info ( '1' if is_speech else '-' ) # Real-time status display. finally : stream . stop_stream () stream . close () p . terminate () ​ # Save valid recording (remove trailing silence). / 保存有效录音(去除尾部静音)。 if speaking and len ( audio_buffer ) > 0 : # Trim the last silent part. / 裁剪最后静音部分。 clean_buffer = audio_buffer [: \- MAX_SILENCE_FRAMES ] if len ( audio_buffer ) > MAX_SILENCE_FRAMES else audio_buffer with wave . open ( self . user_speechdir , 'wb' ) as wf : wf . setnchannels ( 1 ) wf . setsampwidth ( p . get_sample_size ( pyaudio . paInt16 )) wf . setframerate ( self . sample_rate ) wf . writeframes ( b'' . join ( clean_buffer )) return True

代码解析

ASR(语音转文字)功能由ASRNode节点 (asr.py) 提供。该节点负责音频的录制、转换和发布。

  1. 音频录制 (listen_for_speech):

    • 此函数使用pyaudio库从麦克风捕获音频流。
    • 它集成了webrtcvad库进行语音活动检测(VAD)。函数循环读取音频帧,并使用vad.is_speech()判断每一帧是否包含人声。
    • 当检测到语音时,数据被写入一个缓冲区。当检测到持续的静默(由MAX_SILENCE_FRAMES定义)时,录音停止。
    • 最终,缓冲区中的音频数据被写入一个.wav文件,路径为self.user_speechdir
  2. 后端选择与执行 (ASR_conversion):

    • kws_handler函数在录音成功后调用ASR_conversion函数。
    • 此函数通过读取ROS参数use_oline_asr(一个布尔值)来决定调用哪个后端实现。
    • 若为false,则调用self.modelinterface.SenseVoiceSmall_ASR方法,对应本地识别。
    • 若为true,则调用self.modelinterface.oline_asr方法,对应在线识别。
    • 该函数将音频文件路径作为参数传递给所选的方法,并处理返回的结果。
  3. 结果发布 (asr_pub_result):

    • ASR_conversion返回有效的文本后,kws_handler会调用asr_pub_result函数。
    • 此函数将文本字符串封装在一个std_msgs.msg.String消息中,并通过ROS发布者将其发布到/asr话题。

3. 实践操作

3.1 配置离线ASR功能

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

  1. 打开配置文件 :

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

xxxxxxxxxx asr : #语音节点参数 ros__parameters : # ... use_oline_asr : False # 关键: 必须设置为 False 来启用离线ASR mic_serial_port : "/dev/ttyUSB0" # 麦克风串口别名 mic_index : 0 # 麦克风设备索引 language : 'zh' # asr语言, 'zh' 或 'en' regional_setting : "China"

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

在终端输入 ls /dev/ttyUSB* 来查看语音模块被分配的USB设备号是不是USB0,如果不是的话可以修改配置文件中的0改成自己的设备号数字。

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

同时,需要在 large_model_interface.yaml 中指定离线模型的路径。

在终端打开文件

xxxxxxxxxx vim ~/yahboom_ws/src/largemodel/config/large_model_interface.yaml

找到local_asr_model相关的配置

xxxxxxxxxx # large_model_interface.yaml ## 离线语音识别 (Offline ASR) local_asr_model : "/home/jetson/yahboom_ws/src/largemodel/MODELS/asr/SenseVoiceSmall" # 本地ASR模型路径

3.2 启动并测试功能

  1. 启动命令 :

xxxxxxxxxx ros2 launch largemodel asr_only.launch.py 2. 测试 : 对着麦克风说:你好小亚,它就会回应:I‘m here,然后就可以开始说话了,最后会展示出它收录到的声音被转成了文字打印在了终端。image-20250807154240917