乐鑫Esp32学习之旅15 认识本地离线语音唤醒识别框架 esp-skainet ,实现较低成本的硬件语音本地识别控制。


  • 本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途。如有不对之处,请留言,本人及时更改。

1、 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 “Hellow World”。
2、 巧用eclipes编辑器,官方教程在在Windows下搭建esp32开发环境,打印 “Hellow World”。
3、 认识基本esp32的GPIO接口,开始点亮您的第一盏 LED和中断回调实现按键功能 。
4、体会esp32的强大的定时器功能, 实现定时2s闪烁一盏LED灯。
5、接触实践esp32的pwm宽度脉冲功能, 实现呼吸效果闪烁一盏LED灯。
6、smartConfig和微信airKiss在esp32的实现,一键配网轻松快捷连接路由器。
7、利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。
8、esp32上实现本地 UDP 客户端和服务端角色,在局域网内实现通讯。
9、esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。
10、乐鑫esp32 SDK编程利用rmt驱动ws2812七彩灯,实现彩虹渐变效果。
11、入门 乐鑫esp-adf 音频框架开发,esp32造一个蓝牙耳机,实现切换歌曲,获取歌曲信息等功能。
12、开源一个微信公众号airkiss配网esp32以及局域网发现功能的工程,分享一个airkiss配网小工具。
13、esp32 内置 dns 服务器,无需外网访问域名返回指定网页。
14、esp32 sdk编程实现门户强制认证,连接esp32热点之后,自动强制弹出指定的登录界面。
15、认识本地离线语音唤醒识别框架 esp-skainet ,实现较低成本的硬件语音本地识别控制。
16、学习本地语音唤醒离线识别框架 esp-skainet ,如何修改唤醒词? 如何自定义命令词?如何做意图动作?
17、全网首发,乐鑫esp32 sdk直连京东微联·小京鱼 · IoT开放平台,实现叮咚音响语音智能控制。


在这里插入图片描述

一、前言


      记得最早一次听到语音识别的芯片是 科大讯飞的,那时候公司确实做出来一个本地离线识别的产品,但是后面就不再做了,我问了问主管,说是成本太高了!

      后来,我去科大讯飞官网看了看开发板,貌似1600rmb一个开发板,不过那时候是 2017年的事情了,现在就不知道行情了;不过在某宝看到语音识别模块倒是一堆的,注意是模块,叫你串口通讯或者写txt文档进去,不开放二次开发;也许也有二次开发的,但是入门门槛高,价格就不菲了;

      上个月,我在乐鑫的公众号看到了语音唤醒框架 esp-skainet,那时候,仅仅支持 esp-lyart 开发板,我立刻去某宝买了一个,等了足足一个星期,终于到手了,很高兴,轻松地实现了本地语音识别;

      也许,如何使用乐鑫的产品在某些人说来是很轻松的,但是群里依然有人会问我可以实现语音控制吗?这里,我就详细为大家做一个笔记,或者你认为是一个教程也无妨!但,足够帮到您的开发,我认为这个博文就是有价值的!!


二、框架是基于什么算法的


      首先,必须知道 ESP-Skainet 是乐鑫自研推出的智能语音助手,目前支持唤醒词识别和命令词识别。

      它以最便捷的方式支持基于乐鑫的 ESP32 芯片的唤醒词识别和命令词识别应用程序的开发。使用 ESP-Skainet,您可以轻松构建唤醒词识别和命令词识别应用程序。


2.1 疑问:唤醒词支持哪几个?可以自定义吗?

答: 目前,官网文档是唤醒词仅仅开放了如下几个:“Hi,乐鑫”,“你好小智”,“你好小鑫”,“hi,Jeson”但是目前为止,我在开发过程中看到代码仅仅有:“Hi,乐鑫”,“你好小智” 开放,没看到其他唤醒词,可能是因为还没全部放在开源代码中吧。 但是,这足够我们使用开发了!如需自定义唤醒词,比如 “Hi,靓仔”,但是需要商务合作申请!

2.2 疑问:支持自定义命令词吗?比如识别 “我要开飞机”

答:嗯嗯!支持自定义命令词,目前官方示范是 中文命令词,这点我觉得很 nice,别说你要开飞机,你要放大炮开火箭识别都没问题,但是:仅仅支持 100个命令词;


2.3 算法模型 WakeNet 和 识别模型 MultiNet

      既然是语音唤醒,本地识别,就离不开算法模型和识别模型,而ESP-Skainet 是基于乐鑫又一个仓库 esp_sr 为基础的。而 esp_sr 提供语音识别相关方向算法模型,目前主要包括三个模块:

  • 唤醒词识别模型 WakeNet
  • 语音命令识别模型 MultiNet
  • 声学算法:AEC(Acoustic Echo Cancellation), VAD(Voice Activity Detection), AGC(Automatic Gain Control), NS(Noise Suppression)
2.3.1 唤醒词识别

      唤醒词模型 WakeNet,致力于提供一个低资源消耗的的高性能模型,支持类似“Alexa”,“天猫精灵”,“小爱同学”等唤醒词的识别。

      目前乐鑫免费开放“Hi,乐鑫”等唤醒词。如果用户需要其它唤醒词,乐鑫提供有唤醒词定制服务,具体可参考 乐鑫语音唤醒词定制流程

2.3.2 语音命令识别

      命令词识别模型 MultiNet ,致力于提供一个灵活的离线语音命词识别框架。用户可方便根据需求自定义语音命令,无需重新训练模型。

      目前模型支持类似“打开空调”,“打开卧室灯”等中文命令词识别,自定义语音命令词最大个数为 100。

      英文命令词定义将在下一版提供支持。


三、开发板、编译、体验


3.1 开发板选择?

      因为是 esp32 芯片开发,不得不有 esp32 芯片开发基础!仓库代码已经支持了2个开发板分别是:esp-lyart-miniesp-lyart v4.3 ,在某宝有得卖,不得不吐槽,mini板子价格还更贵一丢丢,哈哈!

  • esp-lyart-mini 官网旗舰店购买传送门:点击
  • esp-lyart v4.3 官网旗舰店购买传送门:点击

      上面开发板的最大区别是一个是单麦的,一个是双麦的;更多不同,自行去查询;下面再贴出二者的介绍文档!

  • esp-lyart-mini 官网介绍文档:点击
  • esp-lyart v4.3 官网介绍文档:点击

3.2 拉取代码和指定idf路径

     首先,不管是linux或者windows,你得有 make 环境,自行搭建,或者看我环境搭建的博文;现在也支持 cmake 了,编译更快!

     拉取代码,git操作克隆,这个操作拉取了 idf 工程和skainet示范,但是过程可能需要十几分钟,因为GitHub在国外,没办法,耐心等待吧!

git clone --recursive https://github.com/espressif/esp-skainet.git

      指定依赖的idf编译为 esp-skainet 里面的 idf ,比如这样:

export IDF_PATH=“E:/Espressif/Esp32/esp-idf/home/XuHongYss/esp-idf-3.1/esp-skainet/esp-idf”


3.3 编译 “垃圾分类” 识别工程


      最近国家提倡的“垃圾分类” 很流行,下面,带领大家走一个垃圾分类的识别工程 garbage_classification;

      下面我通过配置,选择开发板为 esp-lyart v4.3
在这里插入图片描述

      然后,就开始编译吧;下面我是 windows平台,端口是27;耐心等待编译!

make flash monitor ESPPORT=COM27

在这里插入图片描述

      然后,对开发板说 “Hi,乐鑫” ,这时候,指示灯会亮起来,说明唤醒成功,之后说 “篮球”,它会对应的播放:“湿垃圾” 、 “干垃圾”

在这里插入图片描述


      本地能识别的词语列表,可以看到是一个一个词语的拼音,我已经注释如下:

---------------------SPEECH COMMANDS---------------------
Command ID0, phrase 0: wei sheng zhi   //卫生纸
Command ID0, phrase 1: shi zhi jin     //湿纸巾
Command ID0, phrase 2: shi pin dai     //食品袋
Command ID0, phrase 3: can jin zhi     //餐巾纸
Command ID0, phrase 4: niao bu shi     //尿不湿
Command ID0, phrase 5: mao sha         //毛纱  
Command ID0, phrase 6: mao fa          //毛发
Command ID0, phrase 7: yi ci xing can ju  //一次性餐具
Command ID0, phrase 8: jiu mao jin       //旧毛巾
Command ID0, phrase 9: tao ci zhi pin    //陶瓷制品
Command ID0, phrase 10: bei ke     //贝壳
Command ID0, phrase 11: fa jiao  //发胶
Command ID0, phrase 12: sao ba  //扫把
Command ID0, phrase 13: da huo ji //打火机
Command ID1, phrase 14: gua zi ke  //瓜子壳
Command ID1, phrase 15: cha ye zha  //茶叶渣
Command ID1, phrase 16: ji rou   //鸡肉
Command ID1, phrase 17: cai ye   //菜叶
Command ID1, phrase 18: gua guo pi  //瓜果皮
Command ID1, phrase 19: sheng fan sheng cai  //剩饭剩菜
Command ID1, phrase 20: zhong yao yao zha   //中药药渣
Command ID1, phrase 21: bing gan   //饼干
Command ID1, phrase 22: yu mi   //玉米
Command ID1, phrase 23: ji gu tou   //鸡骨头
Command ID1, phrase 24: xi hong shi  //西红柿
Command ID1, phrase 25: hua sheng ke   //花生壳
Command ID2, phrase 26: niu kou dian chi  //纽扣电池
Command ID2, phrase 27: guo qi yao pin    //过期药品
Command ID2, phrase 28: lao shu yao    //老鼠药
Command ID2, phrase 29: fei yao pin   //非药品
Command ID2, phrase 30: fei you qi  //废油漆
Command ID2, phrase 31: you qi tong   //油漆桶
Command ID2, phrase 32: ying guang deng    //荧光灯
Command ID2, phrase 33: sha chong ji   //杀虫剂
Command ID3, phrase 34: su liao ping   //塑料瓶
Command ID3, phrase 35: yi la guan   //易拉罐
Command ID3, phrase 36: kuai di zhi xiang  //快递纸箱
Command ID3, phrase 37: jiu bao zhi   //旧报纸
Command ID3, phrase 38: guan tou he  //罐头盒
Command ID3, phrase 39: ying su liao   //硬塑料
Command ID3, phrase 40: bao zhuang zhi  //包装纸
Command ID3, phrase 41: jiu tie guo   //旧铁锅
Command ID3, phrase 42: lan qiu  //篮球
Command ID3, phrase 43: bo li hu  //玻璃壶
Command ID3, phrase 44: jiu wan ju  //旧玩具
---------------------------------------------------------

      那么它是如何识别是干垃圾还是湿垃圾的呢?可从上面看到,有个 ID0 、ID1 、ID2 、ID3 ,而在代码中,我们这样处理:

void speech_commands_action(int command_id)
{
    printf("Commands ID: %d.\n", command_id);
    switch (command_id) {
    case 0:
        iot_dac_audio_play(playlist[0].data, playlist[0].length, portMAX_DELAY);
        printf("干垃圾(Residual Waste)\n");
        break;
    case 1:
        iot_dac_audio_play(playlist[1].data, playlist[1].length, portMAX_DELAY);
        printf("湿垃圾(Household Food Waste)\n");
        break;
    case 2:
        iot_dac_audio_play(playlist[2].data, playlist[2].length, portMAX_DELAY);
        printf("有害垃圾(Hazardous Waste)\n");
        break;
    case 3:
        iot_dac_audio_play(playlist[3].data, playlist[3].length, portMAX_DELAY);
        printf("可回收垃圾(Recyclable Waste)\n");
        break;
    default:
        break;
    }
}

      好了,目前就先这样带领大家入门,下篇会给大家介绍如何自定义命令词,比如“我要开火车”、“开灯”,然后做出指定的动作,比如开灯,关灯,敬请期待!!也欢迎加群讨论!!

另外,不要把我的博客作为学习标准,我的只是笔记,难有疏忽之处,如果有,请指出来,也欢迎留言哈!

  • 玩转esp8266带你飞、加群付费QQ群,不喜的朋友勿喷勿加:434878850
  • esp8266源代码学习汇总(持续更新,欢迎star):https://github.com/xuhongv/StudyInEsp8266
  • esp32源代码学习汇总(持续更新,欢迎star):https://github.com/xuhongv/StudyInEsp32
  • 关注下面微信公众号二维码,干货多多,第一时间推送!
发布了152 篇原创文章 · 获赞 785 · 访问量 79万+

猜你喜欢

转载自blog.csdn.net/xh870189248/article/details/102984768