×

运行水龙头报警器开源分享

消耗积分:0 | 格式:zip | 大小:0.21 MB | 2023-02-06

张旭

分享资料个

描述

概述

记忆力减退只是老年带来的许多不愉快经历中的一小部分,这些问题可能对老年人的舒适度和安全感产生深远影响。痴呆症是与老年人相关的最常见的神经系统问题之一。想象一下老年人把水龙头开着的情况。可能随之而来的那种水害简直是难以想象的。更不用说许多安全问题,例如触电和溺水。此外,有时孩子甚至大人在使用后会忘记关掉水龙头。它还会增加您每月的用水费用。在这个项目中,我已经构建了一个支持物联网的设备的概念验证,它可以使用声音传感器检测正在运行的水龙头,并可以通过蜂鸣器发出警报并可以选择向您发送电子邮件。

硬件设置

我正在使用带有内置麦克风的 i.MX RT1010 开发板。另外,我正在使用 PCF85063AT-ARD 实时时钟 (RTC) Shield。在 i.MX RT1010 开发板接头顶部安装 PCF85063AT-ARD 后,无法访问主板上的其他引脚,但 PCF85063AT-ARD 具有外部 I2C 引脚,可用于连接其他 I2C 外设。我使用 M5Stack Atom Lite(ESP32 开发板)进行 Wifi 连接,使用 SSD1306 OLED 显示器显示预测标签。此外,Grove 无源蜂鸣器连接到 M5Stack Atom Lite 以发出警报。

img_0155_Xt38Wd9bhD.jpeg?auto=compress%2Cformat&w=740&h=555&fit=max
 

我构建了一个自定义子板,用于将 M5Stack Atom Lite 和 OLED 显示器安装到 PCF85063AT-ARD I2C 接头连接器上。

img_0156_IuRtDdDN9d.jpeg?auto=compress%2Cformat&w=740&h=555&fit=max
 

连接图可以在原理图部分找到。您可以在图像(下图)中看到最终设置,它非常整洁紧凑。

img_0160_9UxIgC24zD.jpeg?auto=compress%2Cformat&w=740&h=555&fit=max
 

开发环境设置

对于固件的开发,我正在使用 MCUXpresso 集成开发环境,

安装后打开 MCUXpresso IDE 并在快速启动面板中单击新建项目链接。在 Device selection 页面中,选择evkmimxrt1010并单击Next按钮。

screen_shot_2021-06-22_at_10_28_46_2NocEWGB3z.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

我选择了 C++ 项目,因为 Tensorflow Lite 和 Edge Impulse SDK 库中的大部分代码库都使用 C++。此外,我在“驱动程序”选项卡中选择了sai-edma ,因为我们将使用同步音频接口 (SAI) 进行音频捕获。

screen_shot_2021-06-22_at_10_31_05_sAzA2f0RSR.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

Components中选择提供音频编解码控制接口的codec_wm8960_adapter 。

screen_shot_2021-06-22_at_10_31_19_rGXr8yqfsd.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

PCF85063AT-ARD RTC 和 SSD1306 OLED 库

目前,MCUXpresso SDK 中没有可用于 PCF85063AT-ARD RTC Shield 和 SSD1306 OLED 的库,因此我使用数据表和 Arduino 库中现有代码库的一些帮助编写了一个。除了准确的实时时钟外,PCF85063AT-ARD 还具有闹钟和倒数计时器功能。我们将在项目中使用倒数计时器和时钟功能。

Tensorflow Lite 模型创建

我们将使用 Edge Impulse Studio 来训练和构建 Tensorflow Lite 模型。我们正在使用预建数据集来检测水龙头是否基于音频运行。它包含在以下两个类别中从麦克风以 16KHz 采样的 15 分钟数据:

  • Faucet - 水龙头正在运行,具有各种后台活动。
  • 噪音 - 只是背景活动。

我们可以使用 Edge Impulse CLI 上传器将此数据集导入 Edge Impulse Studio 项目。请按照此处的说明安装 Edge Impulse CLI:https://docs.edgeimpulse.com/docs/cli-installation。数据集可以从这里下载:https://cdn.edgeimpulse.com/datasets/faucet.zip。

$ unzip faucet.zip
$ cd faucet
$ edge-impulse-uploader --clean
$ edge-impulse-uploader --category training faucet/training/*.cbor
$ edge-impulse-uploader --category testing faucet/testing/*.cbor

系统将提示您输入用户名、密码和要添加数据集的项目。上传完成后我们可以在数据采集页面看到数据。

screen_shot_2021-06-22_at_13_09_00_n8EwfspRRT.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

Impulse Design > Create Impulse页面中,我们可以添加处理块和学习块。我们选择了 MFCC 作为处理块,它使用 Mel 频率倒谱系数从音频信号中提取特征,对于学习块,我们选择了神经网络 (Keras),它从数据中学习模式,并将这些模式应用于新数据以识别音频。

screen_shot_2021-06-22_at_13_10_53_ilCNHwuHmJ.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

现在我们需要在 Impulse Design > MFCC 页面中生成特征。我们可以使用默认参数。

screen_shot_2021-06-22_at_13_17_26_jNlZZ2rABz.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

单击“保存参数”按钮后,页面将重定向到“生成特征”页面,我们可以在此处开始生成特征,这需要几分钟时间。特征生成后,我们可以在特征资源管理器中看到输出。

screen_shot_2021-06-22_at_13_20_16_Wh0ilyeJaZ.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

现在我们可以转到 Impulse Design > NN Classifier 页面,我们可以在其中定义神经网络架构。我们正在使用适用于音频分类的一维卷积网络。

screen_shot_2021-06-22_at_13_21_02_YugqfjT1zD.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

完成架构后,我们可以开始训练,这需要几分钟才能完成。我们可以在下面看到准确率和混淆矩阵。

screen_shot_2021-06-22_at_13_24_41_DC1pWYo5WW.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

对于这么小的数据集,89.3% 的准确率已经不错了,所以我们将使用这个模型。目前 Edge Impulse Studio 不支持 i.MX RT1010 MCU,因此我们需要在部署页面中选择创建库> C++ 库并单击构建按钮来下载 C++ 库包。构建完成后,将下载到本地计算机,我们可以将库包解压缩并移动到 MCUXpresso 项目源目录。

移植 Edge Impulse 库

i.MX RT1010 MCU 没有开箱即用的支持,因此我们需要移植它。在 MIMXRT1011_Faucet_Alarm_Project/source/edge-impulse-sdk/porting/ei_classifier_porting.h 中,在文件末尾添加以下行。

#ifndef EI_PORTING_IMXRT1010
#ifdef CPU_MIMXRT1011DAE5A
#define EI_PORTING_IMXRT1010 1
#else
#define EI_PORTING_IMXRT1010 0
#endif

我们需要在 porting/imxrt1010 目录下添加两个文件。

1. 移植/imxrt1010/ ei_classifier_porting.cpp

#include "../ei_classifier_porting.h"
#if EI_PORTING_IMXRT1010 == 1
#include 
#include 
#include 
#include "clock_config.h"
#include "board.h"

#define EI_WEAK_FN __attribute__((weak))

extern "C" {
  volatile uint32_t g_systickCounter;
  volatile uint32_t g_millis_counter;
  void SysTick_Handler(void)
  {
    if (g_systickCounter != 0U)
    {
      g_systickCounter--;
    }
    g_millis_counter++;
  }
}

void SysTick_DelayTicks(uint32_t n)
{
  g_systickCounter = n;
  while (g_systickCounter != 0U) { }
}

EI_WEAK_FN EI_IMPULSE_ERROR ei_run_impulse_check_canceled() {
  return EI_IMPULSE_OK;
}

EI_WEAK_FN EI_IMPULSE_ERROR ei_sleep(int32_t time_ms) {
  SysTick_DelayTicks(time_ms);
  return EI_IMPULSE_OK;
}

uint64_t ei_read_timer_ms() {
  return (uint64_t)g_millis_counter;
}

uint64_t ei_read_timer_us() {
  return ei_read_timer_ms() * 1000UL;
}

/**
* Printf function uses vsnprintf and output using Arduino Serial
*/
__attribute__((weak)) void ei_printf(const char *format, ...) {
  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}
__attribute__((weak)) void ei_printf_float(float f) {
  ei_printf("%f", f);
}
__attribute__((weak)) void *ei_malloc(size_t size) {
  return malloc(size);
}
__attribute__((weak)) void *ei_calloc(size_t nitems, size_t size) {
  return calloc(nitems, size);
}
__attribute__((weak)) void ei_free(void *ptr) {
  free(ptr);
}
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C"
#endif
__attribute__((weak)) void DebugLog(const char* s) {
  ei_printf("%s", s);
}
#endif // EI_PORTING_IMXRT1010 == 1

2. 移植/imxrt1010/debug_log.cpp

#include "../ei_classifier_porting.h"
#if EI_PORTING_IMXRT1010 == 1
#include "tensorflow/lite/micro/debug_log.h"
#include 
#include 
// On IMXRT1010, we set up a serial port and write to it for debug logging.
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C"
#endif // defined(__cplusplus) && EI_C_LINKAGE == 1
void DebugLog(const char* s) {
  ei_printf("%s", s);
}
#endif // EI_PORTING_IMXRT1010

流程图

下面给出应用流程图。

flow_chart_u0DqBc9EcP.jpg?auto=compress%2Cformat&w=740&h=555&fit=max
 

使用 i.MX RT1010 FlexRAM

i.MXRT1010 有限的 128 KB 内存分为 32 KB 存储区。由于内存溢出,编译失败。由于我们使用双缓冲来捕获音频数据;第一个缓冲区用于音频采样过程,用新的样本数据填充缓冲区,第二个缓冲区用于推理过程,从缓冲区中获取样本数据,提取特征并运行推理。所以它需要更多的内存。如果我们构建固件,它会显示以下错误。

错误:arm-none-eabi/bin/ld:MIMXRT1011_Faucet_Alarm_Project.axf 部分“.bss”不适合区域“SRAM_DTC”。

Memory region  Used Size Region Size %age Used
BOARD_FLASH:   289968 B  16 MB        1.73%
SRAM_DTC:      49840 B   32 KB        152.10%
SRAM_ITC:      0 B       32 KB        0.00%
SRAM_OC:       0 B       32 KB        0.00%
NCACHE_REGION: 0 B       32 KB         0.00%

多亏了 FlexRAM,我们可以通过以下步骤重新配置 SRAM_DTC 以增加堆内存大小。在“快速入门”面板中,单击“编辑项目设置”。在设置窗口中,选择C/C++ build > Settings > MCU C++ Linker > Managed Linker Script ,然后在大小字段中将默认堆值从 2 KB (0x800) 更改为 20 KB (0x5000)。单击应用和保存按钮以保存设置。

screen_shot_2021-06-22_at_12_38_48_r22LtGG7a1.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

此外,在主代码中,通过在__DATA(RAM3) 前加上前缀来修改占用大量内存的缓冲区变量的声明,以便将数据放置在 OCRAM 内存区域中。

__DATA(RAM3) static inference_t inference;
__DATA(RAM3) static signed short sampleBuffer[EI_CLASSIFIER_SLICE_SIZE>>1];

重建项目后,我们可以在输出中看到所有内存区域都在其限制范围内。

Memory region  Used Size Region Size %age Used
BOARD_FLASH:   309988 B  16 MB       1.85%
SRAM_DTC:      28268 B   32 KB       86.27%
SRAM_ITC:      0 B       32 KB       0.00%
SRAM_OC:       20012 B   32 KB       61.07%
NCACHE_REGION: 0 B       32 KB       0.00%

引脚配置

WM8960 编解码器 IC 使用 LPI2C1。对于 PCF85063AT-ARD,我们将在 GPIO_AD_01 和 GPIO_AD_02 上配置 LPI2C2 (SCL/SDA),它们是通过 I2C 连接到 PCF85063AT IC 的接头上的引脚。此外,OLED 显示器和 ESP32 I2C 从设备将通过该 LPI2C2 总线连接。

Quickstart Panel > MCUExpresso Config Tools >> Open Pins中,我们可以配置引脚。

screen_shot_2021-06-22_at_14_22_41_Y4JHaIo8Aw.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

一一点击GPIO_AD_01和GPIO_AD_02,分配LPI2C2_SCL和LPI2C2_SCL。之后,从顶部菜单中选择 ConfigTools > Update Code 以生成代码。

screen_shot_2021-06-22_at_14_19_55_9wPkxsrz5C.png?auto=compress%2Cformat&w=740&h=555&fit=max
 

生成的代码保存在 board/pin_mux.c 文件中,该文件不正确且无法运行。因此,在从 NXP 论坛获得帮助后,我们需要修改生成的代码,如下所示。

void BOARD_InitPins(void) 
{
    CLOCK_EnableClock(kCLOCK_Iomuxc);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_01_LPI2C2_SDA, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_02_LPI2C2_SCL, 1U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_02_LPI2C2_SCL, 0xD8B0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_01_LPI2C2_SDA, 0xD8B0U); 
}

构建 i.MXRT1010 固件

克隆项目存储库。

$ cd ~
$ git clone https://github.com/metanav/MIMXRT1011_Faucet_Alarm.git

在 MCUXpresso IDE 中打开项目。Quickstart 面板中单击Build链接。构建完成后,点击Quickstart panel > Debug来烧录并运行项目。

构建 ESP32 固件

我们还需要构建和闪存 M5Stack Atom Lite (ESP32) 以提供 Wifi 和蜂鸣器功能。

$ cd ~/MIMXRT1011_Faucet_Alarm/esp32_i2c_slave_ntp_smtp
$ idf.py build
$ idf.py -b 1500000 -p /dev/tty.usbserial-5D52E80CAC flash

请根据您的操作系统更改上面的 usb 串口设备路径。ESP32 在地址 0x19 运行一个 FreeRTOS 应用程序作为 I2C 从设备。MCUExpresso 项目中的主要应用程序连接到此 I2C 从设备以获取 NTP 时间以在启动时设置 PCF85063AT RTC,启用/禁用蜂鸣器并发送电子邮件警报消息。

设备上推理

使用带有增强型直接内存访问 (eDMA) 控制器的同步音频接口 (SAI) 捕获音频。DSP 应用程序中的音频 MFCC 模块从音频信号中提取系数并作为输入发送到模型。该模型将音频预测为水龙头或噪音,并在 OLED 屏幕上显示输出。出于演示目的,我们将水龙头运行警报阈值保持在 25 个连续水龙头运行检测阈值后,它将通过 I2C 向 ESP32 发送消息触发蜂鸣器,并在接下来的 10 秒内使用 PCF85063AT-ARD 启动倒计时器。一旦触发倒计时,就会向 ESP32 发送一条消息以启动电子邮件发送过程。

推理演示

 

现场演示

 

结论

如果用更多的音频数据训练模型,可以提高模型的准确性。此外,板载麦克风数据有一些噪音和低增益,这可以通过修改某些设置来解决,或者可以使用外部数字麦克风来获得更好的性能。我要感谢 NXP 为这个项目提供免费硬件。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !