更新时间:2025-06-30 11:02:48下载pdf
Wukong AI 硬件开发框架在 T5 芯片/模组上,支持内置语音唤醒算法,用户可以通过特定的唤醒词来唤醒设备。目前默认支持三种唤醒词:“你好涂鸦”、“小智同学”、“Hey, Tuya”(英文)。
如果想定义个性化的唤醒词,目前需要通过涂鸦来定制。您可以联系您的涂鸦商务,提交需求,并沟通具体的项目细节和计划。
内置语音唤醒算法需要硬件的支持。设计音频回采电路,将喇叭播放的声音通过回采电路输入到回声消除算法(AEC),以保障唤醒词在喇叭播放声音的时候正常工作。
关于音频回采电路,您可以参考以下硬件方案:
内置语音唤醒算法目前工作在涂鸦语音子系统中,尚未对外开放。您只需要设置 TY_AI_TOY_CFG_DEFAULT
的 trigger_mode
为 TY_AI_TRIGGER_MODE_WAKEUP
或者 TY_AI_TRIGGER_MODE_FREE
即自动支持,无需关心其原理以及具体如何使用。
// 交互类型定义
typedef enum {
TY_AI_TRIGGER_MODE_HOLD, // 长按触发模式
TY_AI_TRIGGER_MODE_ONE_SHOT, // 单次按键,回合制对话模式
TY_AI_TRIGGER_MODE_WAKEUP, // 关键词唤醒模式
TY_AI_TRIGGER_MODE_FREE, // 关键词唤醒和自由对话模式
} TY_AI_TRIGGER_MODE_E;
// 设置工作模式为关键词唤醒模式
#define TY_AI_TOY_CFG_DEFAULT { \
.audio_trigger_pin = TUYA_GPIO_NUM_12, \
.spk_en_pin = TUYA_GPIO_NUM_28, \
.led_pin = TUYA_GPIO_NUM_1, \
.trigger_mode = TY_AI_TRIGGER_MODE_WAKEUP, \
.audio_cfg = TY_AI_AUDIO_CFG_DEF \
}
唤醒算法目前在 CPU1
上运行,接收 VAD
算法判断有人声的数据之后进行唤醒词识别,并将识别成功的通过 IPC(核间通信)
发送给 CPU0
,用于唤醒设备进行交互(未来功能会修改,修改时会再更新此文档)。
如果您有语音处理的经验,想要使用自己的唤醒算法,可以按照以下步骤:
确认是否支持自定义 KWS
,查看 vendor/T5/t5_os/projects/tuya_app/main/app_main.c
文件中 main
函数;如果当前 SDK
版本不支持,可以自行修改这段代码。
int main(void)
{
...
extern OPERATE_RET tuya_ipc_init(void);
tuya_ipc_init();
#if (CONFIG_SYS_CPU1)
if (tuya_asr_enable()) {
bk_printf("tuya_asr_init\r\n");
extern VOID_T tkl_system_psram_malloc_force_set(BOOL_T enable);
extern BOOL_T tuya_asr_enable(VOID_T);
extern VOID _tuya_asr_int(VOID_T);
tkl_system_psram_malloc_force_set(TRUE);
// FIXME: set cpu freq to 480M only for asr
bk_pm_module_vote_cpu_freq(PM_DEV_ID_DECODER, PM_CPU_FRQ_480M);
_tuya_asr_init();
} else {
bk_printf("user_asr_init\r\n");
extern VOID_T tkl_system_psram_malloc_force_set(BOOL_T enable);
extern VOID user_asr_int(VOID_T);
tkl_system_psram_malloc_force_set(TRUE);
// FIXME: set cpu freq to 480M only for asr
bk_pm_module_vote_cpu_freq(PM_DEV_ID_DECODER, PM_CPU_FRQ_480M);
user_asr_init();
}
extern void tkl_fs_init(void);
tkl_fs_init();
// xTaskCreate(__fs_test, "fs_test", 4096, NULL, 6, (TaskHandle_t * const )&__fs_test_handle);
#endif
...
}
修改 tuya_asr_enable
函数,关闭涂鸦唤醒词算法,自行在语音处理流程中添加唤醒算法。
BOOL_T tuya_asr_enable(VOID_T)
{
return FALSE;
}
添加唤醒库。如果您自定的唤醒词是以 lib
的形式集成,需要修改 vendor/T5/tuyaos/tuyaos_adapter/CMakelist.txt
,在文件末尾新增两行,将 lib
链接到程序中。注意,需要按照您的库的实际存放位置来修改名称。
add_prebuilt_library(user_asr.a "$ENV{ARMINO_PATH}/../../tuyaos/tuyaos_adapter/include/asr/user/user_asr.a")
target_link_libraries(${COMPONENT_LIB} INTERFACE user_asr.a)
实现自己的 user_asr_init
入口,以下代码供参考,实际实现需要按照自己的 KWS
算法实际情况进行修改。
typedef struct {
uint8_t type;
int len;
char *data;
} user_asr_msg_data_t;
// ASR 消息队列句柄
static TKL_QUEUE_HANDLE user_asr_msg_queue;
// 目前语音数据需要从 0 核发送到 1 核,此函数接收 0 核数据,并发送给 ASR 消息队列间
VOID_T user_asr_cpu1_event(VOID *buf, UINT_T len, VOID *args)
{
OPERATE_RET rt;
struct ipc_msg_s *send_msg = (struct ipc_msg_s *)buf;
user_asr_msg_data_tmsg_data;
memcpy(&msg_data, &send_msg->buf[0], sizeof(user_asr_msg_data_t));
if (msg_data.type == 1) {
void *p_buff = (void *)tkl_system_psram_malloc(msg_data.len);
if (p_buff != NULL) {
memset(p_buff, 0, msg_data.len);
*(void **)msg_data.data = p_buff;
}
} else {
rt = tkl_queue_post(user_asr_msg_queue, &msg_data, 0);
if (rt != OPRT_OK) {
bk_printf("tkl_queue_post failed %d\n", rt);
}
}
}
// 唤醒状态要从 1 核发送到 0 核
OPERATE_RET user_asr_event(uint8_t event)
{
struct ipc_msg_s send_msg = {0};
send_msg.type = TKL_IPC_TYPE_ASR;
send_msg.buf[0] = event;
return tkl_asr_send((UINT8_T *)&send_msg, sizeof(send_msg));
}
// KWS 处理线程,这里提供参考,实际需要自行实现
int user_asr_main(void)
{
// 此段代码需要自行、按需实现 -- begin
int ret = user_kws_init(user_parameters);
if (ret!= OPRT_OK) {
bk_printf("Fail to initial user asr%d.\n", ret);
goto __err_exit;
}
UINT_T timeout = TKL_QUEUE_WAIT_FROEVER;
while (1)
{
int rt = tkl_queue_fetch(user_asr_msg_queue, &msg_data, timeout);
if (rt != OPRT_OK) {
bk_printf("")
continue;
}
// 组织数据,输入到 KWS 库,这里提供一个参考,实际需要自行实现
user_ks_OneFrame(user_parameters, //accepting 20ms pcm stream
(W16*)(mic_data + i * FRAME_SZ_BYTE),
&user_result);
// 判断检测结果,按需实现
if (user_result!= 0) { //check wakeup
// 判断是否命中了自定义唤醒词
// 自行实现
// 发送 ASR 事件
mic_data_len = 0;
timeout = TKL_QUEUE_WAIT_FROEVER;
user_asr_event(1);
// 重置算法状态,按需实现
user_kws_init(user_parameters);
break;
}
// 此段代码需要自行、按需实现 -- end
}
}
// 初始化,如果算法线程主函数名修改,则自行替换
VOID user_asr_init(VOID_T)
{
tkl_asr_init(user_asr_cpu1_event, NULL);
tkl_queue_create_init(&user_asr_msg_queue, sizeof(asr_msg_data_t), 500);
tkl_thread_create_in_psram(&sg_hrd_hdl, "user_asr", 1024*4, 4, user_asr_main, NULL);
}
如果您语音处理经验丰富,能够完全使用自己的语音前端处理的算法,可以自行进行 AEC、VAD 算法替换。
在开发过程遇到问题,可以到 TuyaOS 开发者论坛 联网单品开发版块 发帖咨询。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈