添加对门铃的连接
使用简单的 AI 检测门铃声音
项目介绍
本教程的目标是为未连接的门铃添加功能。例如,我们将检测门铃何时响起以发送消息。
我们将以完全非侵入性的方式进行,这意味着我们将只使用门铃发出的声音。我们不会拆卸任何东西。我们将使用 NanoEdge AI Studio(免费工具)自动创建一个 AI 模型,该模型能够对门铃是否响起或只是背景噪音进行分类。
别担心,您不需要 AI 知识即可遵循本教程:)
计划如下:
- 设置
- 收集麦克风数据
- 创建分类模型
- 在我们的Arduino代码中添加模型
设置:
首先,我们需要将麦克风连接到Arduino板。
使用跳线连接:
- OUT(麦克风)到 A0(板)
- GND 到板上的一个 GND
- VCC 至 3.3v
确保您有一根 USB 数据线将主板连接到 PC。
然后我们需要将麦克风靠近门铃发出声音的部分!
在Arduino IDE中:
确保您选择了正确的 COM 端口:工具>端口,然后选择正确的端口。
选择正确的电路板:
- Arduino Renesas UNO R4 > 开发板的工具>板 > Arduino UNO R4 WIFI
- 如果没有找到它,请单击“Tools > Boards > Boards Manager…”,查找 UNO R4 并安装软件包
收集麦克风数据
我们使用具有非常高数据速率的数字麦克风。
我们将通过从麦克风收集值的缓冲区来收集音乐的卡盘,并通过每收集 1 个值仅保留 32 个值来降低数据速率。
我们收集音乐的缓冲区并记录单个音符以对其进行分类。即使对于人类来说,也无法通过从歌曲中随机提取一个音符来识别歌曲。
为此,请执行以下操作:
- 定义 A0 的AMP_PIN,因为我们的麦克风使用 A0 引脚发送数据
- 我们定义了一个名为 neai_buffer 的缓冲区来储存收集的值
- 在我们的例子中,缓冲区的大小为 1024 (SENSOR_SAMPLE)
- 我们在 setup() 中初始化串行
- 我们创建一个 get_microphone_data() 来收集来自麦克风的数据缓冲区。我们只得到 1/32 的值
- 我们仅在检测到声音 400 时才调用该函数>以避免任何不可能是门铃声音的随机噪声。根据您的设备,您可能需要降低它。
- 我们打印缓冲区以通过串行发送。
代码:
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 1024 //buffer size
#define AXIS 1 //microphone is 1 axis
#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
/* Prototypes ----------------------------------------------------------*/
void get_microphone_data(); //function to collect buffer of sound
/* Global variables ----------------------------------------------------------*/
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
int const AMP_PIN = A0; // Preamp output pin connected to A0
/* Setup function ----------------------------------------------------------*/
void setup() {
Serial.begin(115200);
delay(10);
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
if (analogRead(A0)> 400){
get_microphone_data();
}
}
/* Functions declaration ----------------------------------------------------------*/
void get_microphone_data()
{
static uint16_t temp = 0; //stock values
int sub = 0; //increment to downsample
//while the buffer is not full
while (neai_ptr < SENSOR_SAMPLES) {
//we only get a value every DOWNSAMPLE (32 in this case)
if (sub > DOWNSAMPLE) {
/* Fill neai buffer with new accel data */
neai_buffer[neai_ptr] = analogRead(AMP_PIN);
/* Increment neai pointer */
neai_ptr++;
sub = 0; //reset increment
}
else {
//we read the sample even if we don't use it
//else it is instantaneous and we don't downsample
temp = analogRead(AMP_PIN);
}
sub ++;
}
//print the buffer values to send them via serial
for (uint16_t i = 0; i < SENSOR_SAMPLES; i++) {
Serial.print(neai_buffer[i]);
Serial.print(" ");
}
Serial.print("\n");
neai_ptr = 0; //reset the beginning position
}
NanoEdge AI 工作室
这里的目标是使用 NanoEdge 创建一个异常检测项目。我们希望将门铃检测为“标称”,而将其他所有内容检测为“异常”行为。为此,请执行以下操作:
- 打开 NanoEdge
- 创建异常检测项目
- 选择Arduino R4 WIFI板作为目标(其他板兼容)
- 选择麦克风 1 轴作为传感器
- 单击“下一步”
然后,我们将收集每首音乐的数据。在名义步骤中:
- 单击 ADD SIGNAL
- 然后从串行 (USB)
- 然后单击 START/STOP 收集数据(确保选择了正确的 COM 端口)
- 多次记录门铃响起 (x100)。避免空缓冲区(如果需要,请暂停)
- 单击“继续”,然后单击“导入”
- 如果需要,请重命名文件
对于异常步骤,您想收集您家中可能发生的所有其他声音(孩子们玩耍的声音、狗的声音、钢琴声、作品声、吸尘声等)。例如,您可以记录每分钟发生的事情(在 get_microphone_data() 函数之后的数据记录代码中添加延迟)。
我所做的是,我使用了Youtube上的多个“房屋背景噪音”视频。
一旦你拥有了你想要的一切,就去基准测试步骤。
你拥有的歌曲越多,它就会变得越难,所以从简单开始。
- 点击 NEW BENCHMARK
- 选择所有歌曲,然后单击“开始”
基准测试将寻找最佳模型并对数据进行预处理,以找到能够对歌曲进行分类的模型。
我得到了一个很好的基准分数,它在模拟器中按预期工作。
在仿真器中,当被要求提供新的学习信号时,这意味着播放标称声音(门铃),以便可以重新训练模型。
然后进入编译步骤:
- 选中页面底部的“包括基准测试中的知识”框
- 单击编译,填写小表格并保存您的 AI 库 (.zip)。
在这里,我们使用在基准测试中学到的知识。您可以选择不包含这些知识,而是直接在微控制器上重新训练模型。更多信息请见:
$ https://wiki.st.com/stm32mcu/wiki/AI:NanoEdge_AI_Library_for_anomaly_detection_(AD)$
将 NanoEdge 模型集成到我们的代码中
现在我们有了异常检测库,我们需要将其添加到Arduino代码中:
- 打开得到的.zip,有一个Arduino文件夹,里面有另一个zip
- 在Arduino IDE中导入库:Sketch > Include library > Add .ZIP library…,然后选择Arduino文件夹中的.zip
如果您已经在ARDUINO IDE中使用了NANOEDGE AI库:
转到 Document/Arduino/Library 并删除 NanoEdge 的。然后按照上面的说明导入新库。
重要:
如果由于RAM而出现错误,则可能是由于NanoEdge中的库。回到 NanoEdge 中的 VALIDATION STEP,选择一个较小的库(单击右侧的表冠),然后在 Arduino IDE 中编译并替换它。
要使用 NanoEdge,非常简单:
- 使用 neai_anomalydetection_init() 检查是否一切正常
- 包括要“训练”的模型的知识
- 使用 neai_anomalydetection_detect 进行运行检测
如果相似度为 100,则表示我们的信号与标称数据(门铃声)有 100% 相似,如果为 0,则我们有 0% 的机会成为标称数据。
因此,我们将阈值设置为 90,以打印我们正在检测到门铃声。
/* Setup function ———————————————————-*/
void setup() {
Serial.begin(115200);
delay(10);
/* Initialize NanoEdgeAI AI */
neai_code = neai_anomalydetection_init();
if (neai_code != NEAI_OK) {
Serial.print(“Not supported board.\n”);
} else {
neai_anomalydetection_knowledge(knowledge);
}
}
/* Infinite loop ———————————————————-*/
void loop() {
if (analogRead(A0) > 400) {
get_microphone_data();
neai_anomalydetection_detect(neai_buffer, &similarity);
Serial.println(similarity);
if (similarity > 90){
Serial.println(“Doorbell ringing!”);
//do the stuff you want
}
}
}
走得更远
现在您可以检测到门铃响起,由您继续,这里有一些想法:
- 检测到时,使用板子的 WiFi 发送消息或电子邮件:$ https://www.youtube.com/watch?v=KwFyCGYuV6Q $
- 创建托管在服务器上的仪表板并使用 WiFi 发送更新:$ https://www.youtube.com/watch?v=32VcKyI0dio $
感谢您阅读:)
CODE
数据记录器代码
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 1024 //buffer size
#define AXIS 1 //microphone is 1 axis
#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
/* Prototypes ----------------------------------------------------------*/
void get_microphone_data(); //function to collect buffer of sound
/* Global variables ----------------------------------------------------------*/
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
int const AMP_PIN = A0; // Preamp output pin connected to A0
/* Setup function ----------------------------------------------------------*/
void setup() {
Serial.begin(115200);
delay(10);
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
if (analogRead(A0)> 400){
get_microphone_data();
}
}
/* Functions declaration ----------------------------------------------------------*/
void get_microphone_data()
{
static uint16_t temp = 0; //stock values
int sub = 0; //increment to downsample
//while the buffer is not full
while (neai_ptr < SENSOR_SAMPLES) {
//we only get a value every DOWNSAMPLE (32 in this case)
if (sub > DOWNSAMPLE) {
/* Fill neai buffer with new accel data */
neai_buffer[neai_ptr] = analogRead(AMP_PIN);
/* Increment neai pointer */
neai_ptr++;
sub = 0; //reset increment
}
else {
//we read the sample even if we don't use it
//else it is instantaneous and we don't downsample
temp = analogRead(AMP_PIN);
}
sub ++;
}
//print the buffer values to send them via serial
for (uint16_t i = 0; i < SENSOR_SAMPLES; i++) {
Serial.print(neai_buffer[i]);
Serial.print(" ");
}
Serial.print("\n");
neai_ptr = 0; //reset the beginning position
}
主代码
需要 NEAI 库,请按照教程操作
/* Libraries ----------------------------------------------------------*/
#include "NanoEdgeAI.h"
#include "knowledge.h"
/* Defines ----------------------------------------------------------*/
#define SENSOR_SAMPLES 1024 //buffer size
#define AXIS 1 //microphone is 1 axis
#define DOWNSAMPLE 32 //microphone as a very high data rate, we downsample it
/* Prototypes ----------------------------------------------------------*/
void get_microphone_data(); //function to collect buffer of sound
/* Global variables ----------------------------------------------------------*/
static uint16_t neai_ptr = 0; //pointers to fill for sound buffer
static float neai_buffer[SENSOR_SAMPLES * AXIS] = {0.0}; //souhnd buffer
int const AMP_PIN = A0; // Preamp output pin connected to A0
/* NEAI PART*/
uint8_t neai_code = 0; //initialization code
uint8_t similarity; // Point to id class (see argument of neai_classification fct)
/* Setup function ----------------------------------------------------------*/
void setup() {
Serial.begin(115200);
delay(10);
/* Initialize NanoEdgeAI AI */
neai_code = neai_anomalydetection_init();
if (neai_code != NEAI_OK) {
Serial.print("Not supported board.\n");
} else {
neai_anomalydetection_knowledge(knowledge);
}
}
/* Infinite loop ----------------------------------------------------------*/
void loop() {
if (analogRead(A0) > 400) {
get_microphone_data();
neai_anomalydetection_detect(neai_buffer, &similarity);
Serial.println(similarity);
if (similarity > 90){
Serial.println("Doorbell ringing!");
//do stuff you want
}
}
}
/* Functions declaration ----------------------------------------------------------*/
void get_microphone_data()
{
static uint16_t temp = 0; //stock values
int sub = 0; //increment to downsample
//while the buffer is not full
while (neai_ptr < SENSOR_SAMPLES) {
//we only get a value every DOWNSAMPLE (32 in this case)
if (sub > DOWNSAMPLE) {
/* Fill neai buffer with new accel data */
neai_buffer[neai_ptr] = analogRead(AMP_PIN);
/* Increment neai pointer */
neai_ptr++;
sub = 0; //reset increment
}
else {
//we read the sample even if we don't use it
//else it is instantaneous and we don't downsample
temp = analogRead(AMP_PIN);
}
sub ++;
}
neai_ptr = 0; //reset the beginning position
}