发作品签到
标准版

【训练营_进阶班】esp32语音助手

工程标签

7.9k
0
0
12

简介

1.采用esp32作为主控芯片 2.离线语音识别(支持语音唤醒) 3.手机APP控制 两个继电器和板载小灯(阿里云的云智能APP)

简介:1.采用esp32作为主控芯片 2.离线语音识别(支持语音唤醒) 3.手机APP控制 两个继电器和板载小灯(阿里云的云智能APP)

开源协议

GPL 3.0

创建时间:2020-08-06 16:53:50更新时间:2021-10-04 16:47:13

描述

芯片的选择

为什么选择esp32,因为我觉得它性能强悍,双核架构,240MHZ主频,有强大的算力,支持我进行离线语音识别。

本项目没有使用额外的语音识别模块,就一个麦克风采集声音,esp32用来解析和分析音频数据。

板子的踩的坑

我是第一次画在工厂打出来样品的板子,真的感谢立创EDA,给提供这么好的平台,知道了强电不能敷铜等等等。真的是我技术不到家的原因,我原本焊上去5个灯,结果就亮了两个,我把剩下的三个拆了,可能我拆坏了,把这三个灯调换下位置,还是不会亮,最后我果断把后三个灯拆了,后续会把这三个灯珠补齐。

硬件的设计

1.主要的IC

1.ESP32-WROOM                    一款乐鑫研发的32位芯片,内置WIFI,蓝牙,240HZ的主频等等

2.MSM261S4030H0R                一个I2S接口的麦克风,用来进行语音输入

3.CP2102N-A01-GQFN28R            一个USB下载芯片

4.WS2812E                                5个LED灯珠(主要是考虑esp32内置了RMT发射器,发送的波形 刚好满足 WS2812的时序)

5.AMS1117-3.3_C347222            5V转3.3V

6.HK4100F-DC5V-SHG               继电器

........

还有就不一一列举了

2.硬件的整体框架

整个板子的主控是ESP32。

GPIO18             产生RMT波形,发送到WS2812,从而点亮LED灯。

GPIO32 33 25  是esp32的I2S接口,接到麦克风对应的引脚

GPIO4 16          接入继电器,用来驱动强电

GPIO0  EN脚    外接了两个键盘

剩下的都是一些下载电路,和电源部分

软件的设计

1.开发环境

Ubuntu18.0.4

Vscode

esp-idf 3.2

2.环境的搭建

由于开发环境是在Linux平台下编译的,所以我选择了Ubuntu,可以从乐鑫的官方文档中,
看到安装步骤,一步一步搭建,

具体的网址-->:https://docs.espressif.com/projects/esp-idf/zh_CN/v3.3.2/get-started/linux-setup.html

**第一步 :**就是获取工具链,eps32的架构是xtensa架构的,所以需要下载交叉编译的编译器,连接器等等,获取完工具链把它添加到环境变量。

**第二步:**就是获取esp-idf了,由于国内的网络环境,从github获取代码比较慢,可以去采取合理的方法下载,注意克隆仓库的时候要加 --recursive 这个参数,如:

git clone -b v3.3.2 --recursive https://github.com/espressif/esp-idf.git

这个参数是克隆全部的,不然会造成克隆过来的仓库不完整。

下来把esp-idf的路径,添加到环境变量。

运行

python -m pip install --user -r $IDF_PATH/requirements.txt

安装python库,因为idf有些驱动是用python写的脚本。

第三步: 获取阿里云的SDK,不过我没用去阿里云获取,我在乐鑫的仓库中发现了,他们完成了底层的硬件接口和阿里云飞燕平台对接的库,运行:

git clone https://github.com/espressif/esp-ali-smartliving.git

编译 ali-smartliving-device-sdk-c 库

在 esp-ali-smartliving 目录下执行:

cd ali-smartliving-device-sdk-c
make reconfig (选择SDK平台,选择esp32)
make menuconfig (选择相关功能配置,默认不需要修改,该步骤可以省略)
make (生成相关头文件和库文件)

乐鑫还给了示例工程,我是在工程是进行修改。

第四步: 安装Vscode ,Vscode免费,有强大的插件功能,Vscode也发行了Linux版本,用来开发esp32我感觉是最好的选择。



**这几步下来,所有一切东西全部免费开源,不用担心版权原因。**

总的来说在Linux下环境搭建比较麻烦,不像Keil之类的IDE,通过自己一步一步设置编译工具链,一步步下来,那种感觉是在Keil之类的IDE是感受不到的。

3.软件的整体架构

1. 阿里云对生活物联网平台提供了SDK,本软件整体架构就是基于阿里云的SDK和乐鑫的esp-idf。

2.esp32是基于 freeRTOS操作系统,这就方便了我们以任务的形式 进行并发执行。

下图是我画的大概流程,两个任务,期中主任务分布着某些小任务


![image.png](//image.lceda.cn/pullimage/tBbnRFHuLPaeAtV61zdj5TaGNM5XJ5K1d8vbd2xW.png)

语音识别的固件来源与乐鑫音频开发框架esp-adf,可以进行离线语音识别,支持语音唤醒,

乐鑫的语音识别,乐鑫提拱了,编译好的库,这些库都是乐鑫自己训练好的库,CNN卷积神经网络,大量训练而来的,这里感谢乐鑫提供的库。

说:嗨乐鑫,进入唤醒模式,LED灯会以呼吸灯的形式闪烁,表示进入语音监听模式,说出命令,从而控制开发板,如果5s之内没反应,恢复以前的状态,重新进入语音监控模式。


![image.png](//image.lceda.cn/pullimage/JUclccJz0zOuV1nPdAUaBt7TDtjnHB7vql4W0lIT.png)

图画的比较丑

阿里云监控数据,就不画图了,大致就是解析Json数据,执行相对应的命令。阿里云的SDK里面有专门的API提供调用。

外设的驱动设计:

外设有WS2812  麦克风 和继电器

WS2812 这个驱动我搞了好久,把有关RMT部分都放在ws2812.c文件下了,都把它封装成结构体的形式,提供调用,

struct led_strip_s {


    esp_err_t (*get_hsv)(led_strip_t *strip, uint32_t *h, uint32_t *s, uint32_t *v);



    esp_err_t (*get_rgb)(led_strip_t *strip, uint32_t *red, uint32_t *green, uint32_t *blue);



    esp_err_t (*set_hsv)(led_strip_t *strip, uint32_t h, uint32_t s, uint32_t v);



    esp_err_t (*set_rgb)(led_strip_t *strip, uint32_t red, uint32_t green, uint32_t blue);



    esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);



    esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);



    esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);



    esp_err_t (*del)(led_strip_t *strip);

};
// 通过调用这个函数得到一个结构体
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);

下面举个简单的例子
/******example*******/
led_strip_t *g_leds = led_strip_new_rmt_ws2812(&strip_config);  // 得到led的结构体
g_leds->g_leds->set_hsv(g_leds, h, s, v);   // 调用这个函数设置 灯的hsv属性

通过这样设计灯的驱动,操作更简单,便于以后增加和删除功能,代码的灵活性大大提高

麦克风,esp-idf框架下有I2S的库,直接调用,音频部分还要进行,一部分滤波,具体的代码,我是参考esp-adf里面的

static void i2s_init(void)

{

    i2s_config_t i2s_config = {

        .mode = I2S_MODE_MASTER | I2S_MODE_RX,           // the mode must be set according to DSP configuration

        .sample_rate = 16000,                            // must be the same as DSP configuration

        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,    // must be the same as DSP configuration

        .bits_per_sample = 32,                           // must be the same as DSP configuration

        .communication_format = I2S_COMM_FORMAT_I2S,

        .dma_buf_count = 3,

        .dma_buf_len = 300,

        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,

    };

    i2s_pin_config_t pin_config = {

        .bck_io_num = BOARD_DMIC_I2S_SCK,  // IIS_SCLK

        .ws_io_num = BOARD_DMIC_I2S_WS,    // IIS_LCLK

        .data_out_num = -1,                // IIS_DSIN

        .data_in_num = BOARD_DMIC_I2S_SDO  // IIS_DOUT

    };

    i2s_driver_install(1, &i2s_config, 0, NULL);

    i2s_set_pin(1, &pin_config);

    i2s_zero_dma_buffer(1);

}

继电器 只用到了 GPIO的输出功能,同样esp-idf里面有驱动 :包含 #include "driver/gpio.h"


 gpio_config_t io_conf;

    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
通过调用 
   gpio_set_level(GPIO_OUTPUT_IO_16, leavel); 就可以进行很简单的GPIO控制

ESP32分区表的划分

esp32把FLASH的空间进行了划分,具体有关分区表的介绍,参考:https://docs.espressif.com/projects/esp-idf/zh_CN/v3.3.2/api-guides/partition-tables.html

文档中有详细的介绍。我们把四元组的信息,烧录在flash的指定位置。

我用的这个模组,是4M的flash,因为要进行语音识别,所以nvs要分的大一点,下一个存的是wifi信息,我还预留了两个OTA升级的空间,不过这个空间太小了,用不上,最后一个是存储阿里云生活物联网平台的四元组信息。

下面代码,就是我的分区表,第一个分区很大,因为要进行语音识别要很大的空间,最后一个分区,存入的是四元组的信息。

factory,  app,  factory, ,        3840K
nvs,      data, nvs,     ,        0x4000,
otadata,  data, ota,     ,        0x2000,
phy_init, data, phy,     ,        0x1000,
ota_0,    app,  ota_0,   ,        0x1000,
ota_1,    app,  ota_1,   ,        0x1000,
fctry,    data, nvs,     ,        0x4000

烧录四元组到flash

mass_mfg 目录中有一参考配置:single_mfg_config.csv,请拷贝成自己的配置文件,如 my_single_mfg_config.csv。

cp single_mfg_config.csv my_single_mfg_config.csv

使用自己的 ProductKey、ProductSecret、DeviceName、DeviceSecret 对 my_single_mfg_config.csv 进行修改:
key,type,encoding,value
aliyun-key,namespace,,
DeviceName,data,string,config
DeviceSecret,data,string,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh
ProductKey,data,string,a10BnLLzGv4
ProductSecret,data,string,pVfLpS1u3A9JM0go
将 config,dsj3RuY74pgCBJ3zczKz1LaLK7RGApqh,a10BnLLzGv4,pVfLpS1u3A9JM0go 修改为你对应的值。

修改完成后,使用如下命令生成对应的 NVS 分区:
$IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input my_single_mfg_config.csv --output my_single_mfg.bin --size 0x4000
下载
针对 esp32:
$IDF_PATH/components/esptool_py/esptool/esptool.py write_flash 0x003f1000 my_single_mfg.bin
注:0x003f1000 这个地址,是存放四元组的起始地址,一定要算对,要跟分区表一致,否则会造成配网失败

手机配网

在阿里云生活物联网平台创建产品,具体就是那一套过程,在这块i要注意一点,采用这个东西配网,要选择一键配网

image.png

然后采用二维码扫描的方式配网,这个二维码的入口在这个地方。扫描这个二维码,一键配网

image.png

配网完成,在手机上可以看见这样,就可以用手机控制了

image.png




实用性

我觉得,后期可以买个灯罩 把板子罩起来,放在桌子上,继电器可以外接,控制个风扇啥的。



这个并不完全依赖网络,当网络断开的时候,可以离线控制,方便了使用者使用,后续我会加入OTA升级,实现远程升级

8.26
我发现跑个离线神经网络占了flash的四分之三大小,就剩1M的空间,根本不够存放OTA升级的固件,所以要想OTA升级和离线识别共用,就需要增大flash的容量大小,或许有什么方法能裁剪,我再看看。

设计图

原理图

BOM

IDNameDesignatorFootprintQuantity
1K4-6×6_SMDKEY2,KEY1KEY-SMD_4P-L6.0-W6.0-P3.90-LS10.02
2SK-12D02-VG5SW1SW-TH_SK-12D02VG31
3MSM261S4030H0RU8MIC_QFN81
4LED-0805_RLED1LED0805_RED1
5HEADER-16P-2.54J2,J1H16-2.542

附件

序号文件名称下载次数
1
代码解释编译下载.mp4
410
2
ALI_Demo.zip
69
3
作品演示.mp4
477
克隆工程
添加到专辑
0
0
分享
侵权投诉

工程成员

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航