这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 有奖活动 » 在K230DBOX上实现多时段语音提示功能

共1条 1/1 1 跳转至

在K230DBOX上实现多时段语音提示功能

助工
2026-08-07 13:45:29     打赏

K230D BOX开发板上配有麦克风音频信号采集电路见图1和图2所示。它可进行音频录制及保存,其存储介质则是TF卡,文件格式则为wav

image.png

1 麦克风电路

image.png

2 音频采集电路

由于开发板上未配置扬声器,故需要由接口来进入,见图3所示。

image.png

3 连接扬声器 

利用其音频播放功能与RTC相结合,则可实现多时段语音提示功能。

实现该功能的程序为:

from libs.PipeLine import ScopedTiming
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
from media.pyaudio import *                     # 音频模块
from media.media import *
from media.display import *                     # 导入display模块,使用display相关接口
from media.sensor import *                      # 软件抽象模块,主要封装媒体数据链路以及媒体缓冲区
from machine import Pin
from machine import FPIOA
import media.wave as wave                       # wav音频处理模块
import nncase_runtime as nn                     # nncase运行模块,封装了kpu(kmodel推理)和ai2d(图片预处理加速)操作
import ulab.numpy as np                         # 类似python numpy操作,但也会有一些接口不同
import aidemo                                   # aidemo模块,封装ai demo相关前处理、后处理等操作
import time                                     # 时间统计
import struct                                   # 字节字符转换模块
import gc                                       # 垃圾回收模块
import os,sys                                   # 操作系统接口模块
from machine import RTC
#import uos,sys
 
# 构建RTC对象
rtc = RTC()
 
rtc.datetime((2026, 8, 4, 2, 8, 0, 0, 0))
print(rtc.datetime()) #打印时间
 
f=0
y=1
 
DISPLAY_WIDTH = ALIGN_UP(640, 16)
DISPLAY_HEIGHT = 480
 
# 自定义关键词唤醒类,继承自AIBase基类
class KWSApp(AIBase):
    def __init__(self, kmodel_path, threshold, debug_mode=0):
        super().__init__(kmodel_path)  # 调用基类的构造函数
        self.kmodel_path = kmodel_path  # 模型文件路径
        self.threshold=threshold
        self.debug_mode = debug_mode  # 是否开启调试模式
        self.cache_np = np.zeros((1, 256, 105), dtype=np.float)
 
    # 自定义预处理,返回模型输入tensor列表
    def preprocess(self,pcm_data):
        pcm_data_list=[]
        # 获取音频流数据
        for i in range(0, len(pcm_data), 2):
            # 每两个字节组织成一个有符号整数,然后将其转换为浮点数,即为一次采样的数据,加入到当前一帧(0.3s)的数据列表中
            int_pcm_data = struct.unpack("<h", pcm_data[i:i+2])[0]
            float_pcm_data = float(int_pcm_data)
            pcm_data_list.append(float_pcm_data)
        # 将pcm数据处理为模型输入的特征向量
        mp_feats = aidemo.kws_preprocess(fp, pcm_data_list)[0]
        mp_feats_np = np.array(mp_feats).reshape((1, 30, 40))
        audio_input_tensor = nn.from_numpy(mp_feats_np)
        cache_input_tensor = nn.from_numpy(self.cache_np)
        return [audio_input_tensor,cache_input_tensor]
 
    # 自定义当前任务的后处理,results是模型输出array列表
    def postprocess(self, results):
        with ScopedTiming("postprocess", self.debug_mode > 0):
            logits_np = results[0]
            self.cache_np= results[1]
            max_logits = np.max(logits_np, axis=1)[0]
            max_p = np.max(max_logits)
            idx = np.argmax(max_logits)
            # 如果分数大于阈值,且idx==1(即包含唤醒词),播放回复音频
            if max_p > self.threshold and idx == 1:
                return 1
            else:
                return 0
 
if __name__ == "__main__":
    # 实例化FPIOA
    fpioa = FPIOA()
    # 设置Pin63为GPIO63
    fpioa.set_function(63, FPIOA.GPIO63)
    # 实例化功放控制引脚
    spk_sd = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
    # 拉低使能
    spk_sd.value(0)
 
    os.exitpoint(os.EXITPOINT_ENABLE)
    nn.shrink_memory_pool()
    # 设置模型路径和其他参数
    kmodel_path = "/sdcard/examples/kmodel/kws.kmodel"
    # 其它参数
    THRESH = 0.5                # 检测阈值
    SAMPLE_RATE = 16000         # 采样率16000Hz,即每秒采样16000次
    #SAMPLE_RATE =  22050
    CHANNELS = 1                # 通道数 1为单声道,2为立体声
    FORMAT = paInt16            # 音频输入输出格式 paInt16
    CHUNK = int(0.3 * 16000)    # 每次读取音频数据的帧数,设置为0.3s的帧数16000*0.3=4800
    img = image.Image(640, 480, image.RGB888)
    Display.init(Display.ST7701, width=640, height=480, to_ide=True)
 
    # 初始化音频预处理接口
    fp = aidemo.kws_fp_create()
    # 初始化音频流
    p = PyAudio()
    p.initialize(CHUNK)
    MediaManager.init()    #vb buffer初始化
    # 用于采集实时音频数据
    input_stream = p.open(format=FORMAT,channels=CHANNELS,rate=SAMPLE_RATE,input=True,frames_per_buffer=CHUNK)
    # 用于播放回复音频,K230D BOX无扬声器,需要外接扬声器
    output_stream = p.open(format=FORMAT,channels=CHANNELS,rate=SAMPLE_RATE,output=True,frames_per_buffer=CHUNK)
    # 初始化自定义关键词唤醒实例
    kws = KWSApp(kmodel_path,threshold=THRESH,debug_mode=0)
 
    img.clear()
    #img.draw_string(0, 20, "多时段语音提示器", color=( 255,255, 0), scale=4)
    #img.draw_string_advanced(500, 50, 30, "OK", color = (0, 0, 0))
    Display.show_image(img)
 
    try:
        while True:
                    u=rtc.datetime()
                    #img.draw_string(60, 150, str(u[4])+":"+str(u[5])+":"+str(u[6]), color=( 255,0, 0), scale=4)
                    if(u[5]== 0 and u[6]==10):
                        img.draw_string(60, 150, str(u[4])+":"+str(u[5])+":"+str(u[6])+" OK", color=( 255,0, 0), scale=4)
                        reply_wav_file = "/sdcard/examples/utils/ts1.wav"
                        f=1
                        y=1
 
                    if(u[5]==0 and u[6]==20):
                        img.draw_string(60, 200, str(u[4])+":"+str(u[5])+":"+str(u[6])+" OK", color=( 255,0, 0), scale=4)
                        reply_wav_file = "/sdcard/examples/utils/ts2.wav"
                        f=2
                        y=1
 
                    if(u[5]==0 and u[6]==30):
                        img.draw_string(60, 250, str(u[4])+":"+str(u[5])+":"+str(u[6])+" OK", color=( 255,0, 0), scale=4)
                        reply_wav_file = "/sdcard/examples/utils/ts3.wav"
                        f=3
                        y=1
 
                        #img.draw_string(60, 150, "8: 0:6  ", color=( 200,200,200), scale=4)
                        #img.draw_string(60, 200, "8: 0:10 ", color=( 200,200,200), scale=4)
                        #img.draw_string(60, 250, "8: 0:15 ", color=( 200,200,200), scale=4)
                        #f=1
                        #time.sleep(1) #延时1秒
                        #print("====Detected XiaonanXiaonan!====")
                    if((f==1 or f==2 or f==3) and (y==1)):
                        wf = wave.open(reply_wav_file, "rb")
                        wav_data = wf.read_frames(CHUNK)
                        while wav_data:
                            output_stream.write(wav_data)
                            wav_data = wf.read_frames(CHUNK)
                        time.sleep(1) # 时间缓冲,用于播放回复声音
                        y=0
                        wf.close()
 
                    img.clear()
                    t=0
                    for t in range(0,639):         # 画线输出
                        img.draw_circle(t, 60,1, color = (255, 255, 255))   # 画点
                        img.draw_circle(t, 440,1, color = (255, 255, 255))  # 画点
                    img.draw_string(100, 10, "[timer contrl]", color=( 0,255,0), scale=4)
                    img.draw_string(60, 80, "time:"+str(u[4])+":"+str(u[5])+":"+str(u[6]), color=(255,255,0), scale=4)
 
                    if f==1:
                        img.draw_string(60, 150, "8: 0:10   OK", color=(200,200,200), scale=4)
                    if f==2:
                        img.draw_string(60, 150, "8: 0:10   OK", color=(200,200,200), scale=4)
                        img.draw_string(60, 200, "8: 0:20   OK", color=(200,200,200), scale=4)
                    if f==3:
                        img.draw_string(60, 150, "8: 0:10   OK", color=(200,200, 200), scale=4)
                        img.draw_string(60, 200, "8: 0:20   OK", color=(200,200,200), scale=4)
                        img.draw_string(60, 250, "8: 0:30   OK", color=(200,200,200), scale=4)
                    Display.show_image(img)
    except Exception as e:
        sys.print_exception(e)                  # 打印异常信息
    except KeyboardInterrupt as e:
        print("user stop: ", e)
    except BaseException as e:
        print(f"Exception {e}")
 
    finally:
        input_stream.stop_stream()
        output_stream.stop_stream()
        input_stream.close()
        output_stream.close()
        p.terminate()
        # deinit display
        Display.deinit()
        os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
        MediaManager.deinit()              # 释放vb buffer
        aidemo.kws_fp_destroy(fp)
        kws.deinit()                       # 反初始化

经程序运行,其测试效果见图4所示,说明其符合预期要求。

image.png

4 界面形式

演示视频:



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]