Skip to content

Commit 4d90ff0

Browse files
added examples for Edge Impulse microphone inference and Blynk integration
1 parent d1bd0ad commit 4d90ff0

File tree

2 files changed

+385
-0
lines changed

2 files changed

+385
-0
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
An example sketch for Edge Impulse trained model inference for Audio scene classification
3+
4+
Copyright (c) 2021 Seeed technology co., ltd.
5+
Author : Dmitry Maslov
6+
Create Time : January 2021
7+
Change Log :
8+
9+
The MIT License (MIT)
10+
11+
Permission is hereby granted, free of charge, to any person obtaining a copy
12+
of this software and associated documentation files (the "Software"), to deal
13+
in the Software without restriction, including without limitation the rights
14+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
copies of the Software, and to permit persons to whom the Software is
16+
furnished to do so, subject to the following conditions:
17+
18+
The above copyright notice and this permission notice shall be included in
19+
all copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27+
THE SOFTWARE.
28+
*/
29+
30+
// If your target is limited in memory remove this macro to save 10K RAM
31+
#define EIDSP_QUANTIZE_FILTERBANK 0
32+
33+
/* Includes ---------------------------------------------------------------- */
34+
#include <audio_scene_mfe_conv1d_v1_inference.h>
35+
36+
/** Audio buffers, pointers and selectors */
37+
typedef struct {
38+
int16_t *buffer;
39+
uint8_t buf_ready;
40+
uint32_t buf_count;
41+
uint32_t n_samples;
42+
} inference_t;
43+
44+
static inference_t inference;
45+
static signed short sampleBuffer[2048];
46+
unsigned int sampling_period_us = round(600000 * (1.0 / 16000));
47+
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
48+
49+
/**
50+
* @brief Arduino setup function
51+
*/
52+
void setup()
53+
{
54+
// put your setup code here, to run once:
55+
Serial.begin(115200);
56+
57+
Serial.println("Edge Impulse Inferencing Demo");
58+
59+
// summary of inferencing settings (from model_metadata.h)
60+
ei_printf("Inferencing settings:\n");
61+
ei_printf("\tInterval: %.2f ms.\n", (float)EI_CLASSIFIER_INTERVAL_MS);
62+
ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
63+
ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16);
64+
ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));
65+
66+
if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) {
67+
ei_printf("ERR: Failed to setup audio sampling\r\n");
68+
return;
69+
}
70+
}
71+
72+
/**
73+
* @brief Arduino main function. Runs the inferencing loop.
74+
*/
75+
void loop()
76+
{
77+
78+
ei_printf("Recording...\n");
79+
80+
bool m = microphone_inference_record();
81+
if (!m) {
82+
ei_printf("ERR: Failed to record audio...\n");
83+
return;
84+
}
85+
86+
ei_printf("Recording done\n");
87+
88+
signal_t signal;
89+
signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
90+
signal.get_data = &microphone_audio_signal_get_data;
91+
ei_impulse_result_t result = { 0 };
92+
93+
EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
94+
if (r != EI_IMPULSE_OK) {
95+
ei_printf("ERR: Failed to run classifier (%d)\n", r);
96+
return;
97+
}
98+
99+
// print the predictions
100+
ei_printf("Predictions ");
101+
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
102+
result.timing.dsp, result.timing.classification, result.timing.anomaly);
103+
ei_printf(": \n");
104+
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
105+
ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
106+
}
107+
#if EI_CLASSIFIER_HAS_ANOMALY == 1
108+
ei_printf(" anomaly score: %.3f\n", result.anomaly);
109+
#endif
110+
}
111+
112+
/**
113+
* @brief Printf function uses vsnprintf and output using Arduino Serial
114+
*
115+
* @param[in] format Variable argument list
116+
*/
117+
void ei_printf(const char *format, ...) {
118+
static char print_buf[1024] = { 0 };
119+
120+
va_list args;
121+
va_start(args, format);
122+
int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
123+
va_end(args);
124+
125+
if (r > 0) {
126+
Serial.write(print_buf);
127+
}
128+
}
129+
130+
131+
/**
132+
* @brief Init inferencing struct and setup/start PDM
133+
*
134+
* @param[in] n_samples The n samples
135+
*
136+
* @return { description_of_the_return_value }
137+
*/
138+
static bool microphone_inference_start(uint32_t n_samples)
139+
{
140+
inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t));
141+
142+
if(inference.buffer == NULL) {
143+
return false;
144+
}
145+
146+
inference.buf_count = 0;
147+
inference.n_samples = n_samples;
148+
inference.buf_ready = 0;
149+
pinMode(WIO_MIC, INPUT);
150+
151+
return true;
152+
}
153+
154+
/**
155+
* @brief Wait on new data
156+
*
157+
* @return True when finished
158+
*/
159+
static bool microphone_inference_record(void)
160+
{
161+
inference.buf_ready = 0;
162+
inference.buf_count = 0;
163+
164+
if (inference.buf_ready == 0) {
165+
for(int i = 0; i < 8001; i++) {
166+
inference.buffer[inference.buf_count++] = map(analogRead(WIO_MIC), 0, 1023, -32768, 32767);
167+
delayMicroseconds(sampling_period_us);
168+
169+
if(inference.buf_count >= inference.n_samples) {
170+
inference.buf_count = 0;
171+
inference.buf_ready = 1;
172+
break;
173+
}
174+
}
175+
}
176+
177+
return true;
178+
}
179+
180+
/**
181+
* Get raw audio signal data
182+
*/
183+
static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr)
184+
{
185+
numpy::int16_to_float(&inference.buffer[offset], out_ptr, length);
186+
187+
return 0;
188+
}
189+
190+
/**
191+
* @brief Stop PDM and release buffers
192+
*/
193+
static void microphone_inference_end(void)
194+
{
195+
free(inference.buffer);
196+
}
197+
198+
#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_MICROPHONE
199+
#error "Invalid model for current sensor."
200+
#endif
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
An example sketch for Edge Impulse trained model inference for Audio scene classification and Blynk push notifications
3+
4+
Copyright (c) 2021 Seeed technology co., ltd.
5+
Author : Dmitry Maslov
6+
Create Time : January 2021
7+
Change Log :
8+
9+
The MIT License (MIT)
10+
11+
Permission is hereby granted, free of charge, to any person obtaining a copy
12+
of this software and associated documentation files (the "Software"), to deal
13+
in the Software without restriction, including without limitation the rights
14+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
copies of the Software, and to permit persons to whom the Software is
16+
furnished to do so, subject to the following conditions:
17+
18+
The above copyright notice and this permission notice shall be included in
19+
all copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27+
THE SOFTWARE.
28+
*/
29+
30+
31+
// If your target is limited in memory remove this macro to save 10K RAM
32+
#define EIDSP_QUANTIZE_FILTERBANK 0
33+
#define BLYNK_PRINT Serial
34+
35+
/* Includes ---------------------------------------------------------------- */
36+
#include <audio_scene_mfe_conv1d_v1_inference.h>
37+
#include <rpcWiFi.h>
38+
#include <WiFiClient.h>
39+
#include <BlynkSimpleWioTerminal.h>
40+
41+
/** Audio buffers, pointers and selectors */
42+
typedef struct {
43+
int16_t *buffer;
44+
uint8_t buf_ready;
45+
uint32_t buf_count;
46+
uint32_t n_samples;
47+
} inference_t;
48+
49+
static inference_t inference;
50+
static signed short sampleBuffer[2048];
51+
unsigned int sampling_period_us = round(600000 * (1.0 / 16000));
52+
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
53+
54+
char auth[] = "token";
55+
char ssid[] = "ssid";
56+
char pass[] = "password";
57+
58+
void infer()
59+
{
60+
ei_printf("Recording...\n");
61+
62+
bool m = microphone_inference_record();
63+
if (!m) {
64+
ei_printf("ERR: Failed to record audio...\n");
65+
return;
66+
}
67+
68+
ei_printf("Recording done\n");
69+
70+
signal_t signal;
71+
signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
72+
signal.get_data = &microphone_audio_signal_get_data;
73+
ei_impulse_result_t result = { 0 };
74+
75+
EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
76+
if (r != EI_IMPULSE_OK) {
77+
ei_printf("ERR: Failed to run classifier (%d)\n", r);
78+
return;
79+
}
80+
81+
// print the predictions
82+
ei_printf("Predictions ");
83+
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
84+
result.timing.dsp, result.timing.classification, result.timing.anomaly);
85+
ei_printf(": \n");
86+
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
87+
ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
88+
}
89+
if (result.classification[1].value > 0.6) { Blynk.notify("Dog is barking"); }
90+
if (result.classification[2].value > 0.6) { Blynk.notify("Glass breaking"); }
91+
if (result.classification[3].value > 0.6) { Blynk.notify("Shots fired"); }
92+
}
93+
94+
void setup()
95+
{
96+
// put your setup code here, to run once:
97+
Serial.begin(115200);
98+
Blynk.begin(auth, ssid, pass);
99+
Serial.println("Edge Impulse Inferencing Demo");
100+
101+
// summary of inferencing settings (from model_metadata.h)
102+
ei_printf("Inferencing settings:\n");
103+
ei_printf("\tInterval: %.2f ms.\n", (float)EI_CLASSIFIER_INTERVAL_MS);
104+
ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
105+
ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16);
106+
ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));
107+
108+
if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) {
109+
ei_printf("ERR: Failed to setup audio sampling\r\n");
110+
return;
111+
}
112+
}
113+
114+
void loop()
115+
{
116+
Blynk.run();
117+
infer();
118+
}
119+
120+
void ei_printf(const char *format, ...) {
121+
static char print_buf[1024] = { 0 };
122+
123+
va_list args;
124+
va_start(args, format);
125+
int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
126+
va_end(args);
127+
128+
if (r > 0) {
129+
Serial.write(print_buf);
130+
}
131+
}
132+
133+
static bool microphone_inference_start(uint32_t n_samples)
134+
{
135+
inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t));
136+
137+
if(inference.buffer == NULL) {
138+
return false;
139+
}
140+
141+
inference.buf_count = 0;
142+
inference.n_samples = n_samples;
143+
inference.buf_ready = 0;
144+
pinMode(WIO_MIC, INPUT);
145+
146+
return true;
147+
}
148+
149+
static bool microphone_inference_record(void)
150+
{
151+
inference.buf_ready = 0;
152+
inference.buf_count = 0;
153+
154+
if (inference.buf_ready == 0) {
155+
for(int i = 0; i < 8001; i++) {
156+
inference.buffer[inference.buf_count++] = map(analogRead(WIO_MIC), 0, 1023, -32768, 32767);
157+
delayMicroseconds(sampling_period_us);
158+
159+
if(inference.buf_count >= inference.n_samples) {
160+
inference.buf_count = 0;
161+
inference.buf_ready = 1;
162+
break;
163+
}
164+
}
165+
}
166+
167+
while(inference.buf_ready == 0) {
168+
delay(10);
169+
}
170+
171+
return true;
172+
}
173+
174+
static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr)
175+
{
176+
numpy::int16_to_float(&inference.buffer[offset], out_ptr, length);
177+
178+
return 0;
179+
}
180+
181+
182+
static void microphone_inference_end(void)
183+
{
184+
free(inference.buffer);
185+
}

0 commit comments

Comments
 (0)