Grove Vision AI V2之语音控制LED
一、说明
利用开发板的麦克风、LED、关键字识别模型实现语音控制开发板LED点亮和熄灭,当识别到"on"语音时点亮LED,识别到“off”语音时熄灭LED。
二、程序开发
结合kws_pdm_record和gpio例程开发。
1、创建文件
将kws_pdm_record例程拷贝一份,重命名为kws_led,linux环境下可以执行以下命令:
cp -a kws_pdm_record/ kws_led/
再将部分文件重命名:
2、增加一个APP类型
打开kws_led.mk文件,修改内容:
APPL_DEFINES += -DKWS_PDM_RECORD#-DTFLM_NOTZ
改为
APPL_DEFINES += -DKWS_LED#-DTFLM_NOTZoverride LINKER_SCRIPT_FILE := $(SCENARIO_APP_ROOT)/$(APP_TYPE)/kws_pdm_record.sct
改为
override LINKER_SCRIPT_FILE := $(SCENARIO_APP_ROOT)/$(APP_TYPE)/kws_led.sctoverride LINKER_SCRIPT_FILE := $(SCENARIO_APP_ROOT)/$(APP_TYPE)/kws_pdm_record.ld
改为
override LINKER_SCRIPT_FILE := $(SCENARIO_APP_ROOT)/$(APP_TYPE)/kws_led.ld
打开Seeed_Grove_Vision_AI_Module_V2/EPII_CM55M_APP_S/app/main.c,增加内内容:
#ifdef KWS_LED
#include "kws_led.h"/* main entry */
int main(void)
{board_init();kws_led_app();return 0;
}
#endif
3、编写代码
将kws_led.h改为如下内容:
#ifndef KWS_LED_H
#define KWS_LED_H#define APP_BLOCK_FUNC() do { \__asm volatile("b ."); \
} while (0)int kws_led_app(void);#endif /* KWS_LED_H_ */
修改kws_led.c文件内容:
#include "kws_pdm_record.h"
改为
#include "kws_led.h"int kws_pdm_record_app(void)
改为
int kws_led_app(void)
三、过程分析
1、音频数据采集
hx_drv_pdm_dma_lli_transfer((void *) audio_buf[w_buf_idx], BLK_NUM, QUARTER_SECOND_MONO_BYTES, 0);
函数用于启动DMA(Direct Memory Access)传输,将音频缓冲区的数据传输到处理单元。
2、模型加载
cv_kws_init(true, true, KWS_FLASH_ADDR);
函数初始化关键词唤醒系统,设置为实时模式和唤醒模式,并指定唤醒词模型在闪存中的地址。
3、主循环
cv_kws_run(&algoresult_kws_pdm_record, temp_buf, AUDIO_LEN, kws_processing_callback);
循环运行关键词唤醒检测函数,传入音频数据和回调函数,用于处理检测结果。
四、识别结果
kws_led_app()函数中调用cv_kws_run()识别采集的音频数据中是否包含关键字,并传入参数algoresult_kws_pdm_record用于保存识别结果,但是cv_kws_run()函数中未将识别结果赋值给algoresult_kws_pdm_record参数。
参数algoresult_kws_pdm_record的类型struct_kws_algoResult的定义在Seeed_Grove_Vision_AI_Module_V2/EPII_CM55M_APP_S/library/spi_ptl/spi_protocol.h文件中,定义如下:
#define KWS_MAX_LABEL_SIZE 9typedef struct
{double m_normalisedVal;char m_label[KWS_MAX_LABEL_SIZE];uint32_t m_labelIdx;
}struct_kws_algoResult;
成员说明:
m_normalisedVal:识别结果置信度;
m_label:存放识别到的标签;
m_labelIdx:标签的序号;
1、保存识别结果
修改cv_kws_run()函数中的内容,增加保存识别结果的代码:
将
if(vecResults[0].normalisedVal >= threshold)
{xprintf("Label: %s " , vecResults[0].label.c_str());xprintf("Score: %d %", static_cast<int>(vecResults[0].normalisedVal * 100));xprintf("Label Index: %d \n" , vecResults[0].labelIdx);
}
else
{xprintf("None \n");
}
改为
if(vecResults[0].normalisedVal >= threshold)
{algoresult_kws_pdm_record->m_normalisedVal = vecResults[0].normalisedVal;strcpy(algoresult_kws_pdm_record->m_label, vecResults[0].label.c_str());algoresult_kws_pdm_record->m_labelIdx = vecResults[0].labelIdx;xprintf("Label: %s " , vecResults[0].label.c_str());xprintf("Score: %d %", static_cast<int>(vecResults[0].normalisedVal * 100));xprintf("Label Index: %d \n" , vecResults[0].labelIdx);
}
else
{algoresult_kws_pdm_record->m_normalisedVal = 0;xprintf("None \n");
}
2、处理识别结果
修改kws_led_app()函数中的代码,将
if (r_buf_idx > 0) {cv_kws_run(&algoresult_kws_pdm_record, temp_buf, AUDIO_LEN,kws_processing_callback);} else {// Skip processing for the first iterationxprintf("Skipping first buffer processing\n");
}
改为
if (r_buf_idx > 0) {if( cv_kws_run(&algoresult_kws_pdm_record, temp_buf, AUDIO_LEN, kws_processing_callback) == true ){if( algoresult_kws_pdm_record.m_normalisedVal > 0 ){xprintf("kws_led_app Label: %s " , algoresult_kws_pdm_record.m_label);xprintf("kws_led_app Score: %d %", algoresult_kws_pdm_record.m_normalisedVal * 100 );xprintf("kws_led_app Label Index: %d \n" , algoresult_kws_pdm_record.m_labelIdx); if( strcmp( algoresult_kws_pdm_record.m_label, "on") == 0 ) {hx_drv_gpio_set_out_value(GPIO20, GPIO_OUT_HIGH); //LED ON.}else if( strcmp( algoresult_kws_pdm_record.m_label, "off") == 0 ){hx_drv_gpio_set_out_value(GPIO20, GPIO_OUT_LOW); //LED OFF.}} }} else {// Skip processing for the first iterationxprintf("Skipping first buffer processing\n");
}
应用中再次打印识别结果,并加入根据识别到的关键字点亮或关闭LED的代码。
五、LED初始化
在代码pinmux_init();之前加入LED初始化代码:
// The pin of GPIO20 is defined by the user application.
hx_drv_scu_set_SEN_D2_pinmux(SCU_SEN_D2_PINMUX_GPIO20);
// Initialize GPIO_GROUP_2
hx_drv_gpio_init(GPIO_GROUP_2, HX_GPIO_GROUP_2_BASE);
// set GPIO20 as output mode with default output high level
hx_drv_gpio_set_output(GPIO20, GPIO_OUT_HIGH);
六、编译
1、指定APP_TYPE
将Seeed_Grove_Vision_AI_Module_V2/EPII_CM55M_APP_S/makefile中的APP_TYPE赋值为kws_led:
APP_TYPE = kws_led
2、导入编译工具的环境变量
export PATH="$HOME/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin/:$PATH"
3、编译
cd到EPII_CM55M_APP_S目录,然后执行make clean,再执行make:
cd EPII_CM55M_APP_S
make clean
make
如果之前编译过其它应用,必须执行make clean,不然编译会失败。