Skip to content

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 

Repository files navigation

πŸŽ™οΈ Photon 2 Voice Command

Offline keyword spotting and relay control with Particle Photon 2 and Edge Impulse

Particle Edge Impulse C++

Roni Bandini β€” Buenos Aires, Argentina β€” September 2023

Photon 2 Voice Command is an Edge Machine Learning experiment that lets a Particle Photon 2 control an external device by recognizing a spoken keyword.

A PDM MEMS microphone continuously captures audio at 16 kHz. An Edge Impulse keyword-spotting model runs locally on the Photon 2 and, when the target class exceeds an 80% confidence threshold, toggles a relay connected to D3.

The inference itself runs on the microcontroller; no cloud audio processing is required.


✨ Features

  • πŸŽ™οΈ PDM digital microphone input
  • 🧠 Edge Impulse keyword spotting
  • πŸ”¬ MFCC audio processing
  • ⚑ On-device continuous inference
  • 🎯 80% detection threshold
  • πŸ”„ Voice-controlled relay toggle
  • πŸ“‘ Particle Photon 2
  • 🧩 Particle Workbench / Visual Studio Code workflow
  • 🐳 Optional Docker build process
  • 🌐 Public Edge Impulse project

πŸ—οΈ Architecture

flowchart LR
    VOICE["πŸ—£οΈ Voice Command"]
    MIC["πŸŽ™οΈ PDM Microphone"]
    P2["Particle Photon 2"]
    MFCC["MFCC"]
    ML["🧠 Edge Impulse"]
    CHECK{"Target > 80%?"}
    RELAY["⚑ Relay D3"]
    MACHINE["βš™οΈ External Device"]

    VOICE --> MIC
    MIC --> P2
    P2 --> MFCC
    MFCC --> ML
    ML --> CHECK
    CHECK -->|"Yes"| RELAY
    RELAY --> MACHINE
Loading

The microphone stream is processed continuously on the Photon 2.


🧠 Particle Photon 2

The project uses the Particle Photon 2, based on the P2 module.

Specification Value
MCU Realtek RTL8721DM
CPU Arm Cortex-M33
Clock 200 MHz
User application space 2 MB
RAM available to applications 3 MB
Flash file system 2 MB
Wi-Fi 2.4 + 5 GHz
Bluetooth BLE 5
Battery support LiPo charger / JST-PH

The additional memory compared with earlier Particle boards makes the Photon 2 suitable for embedded ML workloads.

Official documentation:

πŸ‘‰ Photon 2 Datasheet


πŸŽ™οΈ PDM Microphone

The original build uses the PDM MEMS microphone included with Particle's Edge ML Kit.

Connections:

PDM Microphone Photon 2
GND GND
3V 3V3
CLK A0
DAT A1
SEL Not connected

The Photon 2 exposes PDM clock and data on these pins.

The source initializes audio as signed 16-bit data at:

Microphone_PDM::instance()
    .withOutputSize(
        Microphone_PDM::OutputSize::SIGNED_16
    )
    .withRange(
        Microphone_PDM::Range::RANGE_32768
    )
    .withSampleRate(16000)
    .init();

So the audio pipeline operates at:

16,000 samples / second
16-bit signed samples

⚑ Relay

Relay wiring:

Relay Photon 2
GND GND
VCC VCC
Signal D3

Firmware:

pinMode(3, OUTPUT);

The original relay module uses active-low logic.

Machine OFF

digitalWrite(3, HIGH);

Machine ON

digitalWrite(3, LOW);

At startup:

int machineOn = 0;

digitalWrite(3, HIGH);

so the machine begins in the OFF state.


🎯 Detection Threshold

The current source uses:

float detectionLimit = 0.8;

A target classification therefore has to exceed:

80%

before the relay state is changed.

The relevant logic is:

if (
    strstr(
        result.classification[ix].label,
        "muted"
    )
    &&
    result.classification[ix].value >
        detectionLimit
) {

The relay then toggles:

if (machineOn == 1) {
    digitalWrite(3, HIGH);
    machineOn = 0;
}
else {
    digitalWrite(3, LOW);
    machineOn = 1;
}

🏷️ Keyword Naming

There are three names associated with the project artifacts.

Tutorial

The official Edge Impulse tutorial describes training:

machine
background

Current public Edge Impulse project

The current public dataset exposes:

turnoff
background

Current main.cpp

The code checks:

muted

This comes from the Particle β€œYou’re Muted” ML example used as the basis for the Photon 2 implementation.

Before compiling a newly exported model, change:

"muted"

to the actual target label used in that model.

For example:

if (
    strstr(
        result.classification[ix].label,
        "turnoff"
    )
    &&
    result.classification[ix].value >
        detectionLimit
)

Particle reference:

πŸ‘‰ You're Muted β€” Particle Machine Learning Tutorial


🧠 Edge Impulse Model

Public project:

πŸ‘‰ Photon 2 Keyword Spotting β€” Edge Impulse Project #288386

The current public project contains:

Parameter Value
Samples 60
Audio collected 1 minute
Sample rate 16 kHz
Classes background, turnoff
Validation accuracy 100%
Test accuracy 100%

The Edge Impulse dashboard currently has a different target selected for its generic performance estimate, so the latency shown there should not be interpreted as measured Photon 2 latency.


πŸ”¬ Original Training Workflow

The original tutorial recorded two long samples:

Target keyword
Background sound

The recordings were split into:

1000 ms

segments.

Impulse configuration:

Parameter Value
Window size 1000 ms
Window increase 500 ms
Processing block Audio MFCC
Learning block Classification (Keras)

Workflow:

flowchart LR
    VOICE["πŸŽ™οΈ Voice Samples"]
    BG["πŸ”Š Background"]
    SPLIT["1-second Samples"]
    MFCC["MFCC Features"]
    NN["Keras Classifier"]
    LIB["Particle Library"]
    P2["Photon 2"]

    VOICE --> SPLIT
    BG --> SPLIT
    SPLIT --> MFCC
    MFCC --> NN
    NN --> LIB
    LIB --> P2
Loading

Complete tutorial:

πŸ‘‰ Recognize Voice Commands with the Particle Photon 2 β€” Edge Impulse


πŸ”„ Continuous Audio Inference

The application uses:

#define EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW 4

With the original:

1000 ms model window

this means each inference slice represents approximately:

250 ms

The application calls:

run_classifier_continuous(
    &signal,
    &result,
    debug_nn
);

rather than waiting for separate one-second recordings.

Conceptually:

flowchart LR
    AUDIO["πŸŽ™οΈ Continuous Audio"]
    S1["250 ms"]
    S2["250 ms"]
    S3["250 ms"]
    S4["250 ms"]
    MODEL["🧠 1 s Model Window"]
    RESULT["Classification"]

    AUDIO --> S1
    AUDIO --> S2
    AUDIO --> S3
    AUDIO --> S4

    S1 --> MODEL
    S2 --> MODEL
    S3 --> MODEL
    S4 --> MODEL

    MODEL --> RESULT
Loading

πŸ”„ Runtime Flow

flowchart TD
    START["Power On"]
    OFF["βš™οΈ Relay OFF"]
    MIC["πŸŽ™οΈ Capture PDM Audio"]
    ML["🧠 Continuous Inference"]
    CHECK{"Target > 0.8?"}
    STATE{"Machine state?"}
    ON["Relay LOW β†’ ON"]
    STOP["Relay HIGH β†’ OFF"]

    START --> OFF
    OFF --> MIC
    MIC --> ML
    ML --> CHECK

    CHECK -->|"No"| MIC
    CHECK -->|"Yes"| STATE

    STATE -->|"OFF"| ON
    STATE -->|"ON"| STOP

    ON --> MIC
    STOP --> MIC
Loading

πŸ› οΈ Hardware

Component Quantity
Particle Photon 2 1
PDM MEMS microphone 1
Single-channel relay module 1
Breadboard 1
Jumper wires Several
USB-C cable 1

The microphone used in the original build came from the Particle Edge ML Kit.

Particle Machine Learning resources:

πŸ‘‰ Particle Machine Learning


πŸ’» Development Environment

Unlike most Arduino projects in this repository collection, the Photon 2 application is built using:

πŸ‘‰ Visual Studio Code

with:

πŸ‘‰ Particle Workbench

Particle Workbench provides:

  • Device OS toolchains
  • Local compilation
  • Cloud compilation
  • Device flashing
  • Particle library management
  • C++ IntelliSense

πŸš€ Build and Install

1. Clone the Repository

git clone \
https://github.com/ronibandini/Photon2VoiceCommand.git

cd Photon2VoiceCommand

Repository:

πŸ‘‰ github.com/ronibandini/Photon2VoiceCommand

Main source:

πŸ‘‰ main.cpp


2. Install Particle Workbench

Install:

πŸ‘‰ Visual Studio Code

then:

πŸ‘‰ Particle Workbench

Particle Workbench runs on:

Windows
Linux
macOS

3. Export the Edge Impulse Model

Open:

πŸ‘‰ Edge Impulse Project #288386

or create your own keyword project.

Then:

Deployment
β†’ Particle Library
β†’ Build

Unzip the downloaded project.


4. Import the Project

In VS Code:

Ctrl/Cmd + Shift + P

select:

Particle: Import Project

and choose:

project.properties

Replace the generated:

src/main.cpp

with:

πŸ‘‰ main.cpp


5. Check the Model Header

The repository currently includes:

#include \
<Photon_2_Keyword_keyword_spotting_inferencing.h>

The exact header name depends on the Edge Impulse export.

If your project generates another name, replace this include accordingly.


6. Check the Target Label

The current repository looks for:

"muted"

Replace it with the class contained in your exported model.

For the current public project, that is:

"turnoff"

7. Configure the Device

The original documented configuration is:

Device OS: 5.5.0
Platform:   P2

Particle uses the P2 platform target for both P2 and Photon 2 builds.

Current Photon 2 documentation requires Device OS 5.0.0 or later.


8. Install the PDM Library

If Workbench reports that the microphone library is missing:

Particle:
Install Library

install:

Microphone_PDM@0.0.2

9. Flash

From the Particle Command Palette:

Particle:
Flash Application & Device (local)

Serial debug output runs at:

115200 baud

Startup:

Particle Photon 2 voice operated machine
Roni Bandini, September 2023

Machine is off

🐳 Docker Build

The original project documentation also includes a Docker workaround for the:

Argument list too long

build error.

Example for Device OS 5.5.0:

docker pull \
particle/buildpack-particle-firmware:5.5.0-p2

Build:

docker run \
  --name=photon2-build \
  -v /absolute/project/path:/input \
  -v /absolute/project/path:/output \
  -e PLATFORM_ID=32 \
  particle/buildpack-particle-firmware:5.5.0-p2

The output is:

firmware.bin

Then flash through Particle CLI.

Particle build documentation:

πŸ‘‰ Particle Firmware Build Options


πŸ“ Repository Structure

The repository is deliberately minimal:

Photon2VoiceCommand/
β”‚
β”œβ”€β”€ main.cpp
└── README.md
  • πŸŽ™οΈ main.cpp β€” PDM capture, Edge Impulse inference and relay control
  • πŸ“– README.md β€” original installation notes

The trained model itself is hosted through Edge Impulse rather than stored directly in this repository.


πŸŽ₯ Demo

▢️ Particle Photon 2 Voice Command Demo β€” YouTube


🌐 External References

🧠 Edge Impulse Expert Network

Complete official tutorial covering circuit, dataset acquisition, MFCC processing, training, deployment and Particle Workbench setup:

πŸ‘‰ Recognize Voice Commands with the Particle Photon 2


🧠 Public Edge Impulse Project

Dataset and trained keyword-spotting model:

πŸ‘‰ Photon 2 Keyword Spotting β€” Project #288386


⚑ Particle

Photon 2 hardware:

πŸ‘‰ Photon 2 Datasheet

Development environment:

πŸ‘‰ Particle Workbench

Machine Learning:

πŸ‘‰ Particle Machine Learning

Original code base used as a reference:

πŸ‘‰ You're Muted β€” Particle


πŸ”— Related GitHub Projects

🎧 Reggaeton Be Gone

Audio classification with Edge Impulse followed by a physical/network action when the target audio class is detected.

πŸ‘‰ github.com/ronibandini/reggaetonBeGone

πŸ“š Reading Time

Audio TinyML on Arduino Nano 33 BLE Sense for detecting the sound of paper page turns.

πŸ‘‰ github.com/ronibandini/ReadingTime

🧍 BTFall

TinyML event recognition with local inference and an external physical/reporting workflow.

πŸ‘‰ github.com/ronibandini/BTFall

🚦 TI AM62A AI Traffic Light

Edge Impulse inference linked to physical relay/traffic-light control.

πŸ‘‰ github.com/ronibandini/TIAM62AITrafficLight


πŸ“• Contracultura Maker

Contracultura Maker is a book by Roni Bandini about maker culture, experimental electronics, AI, physical computing and technological autonomy.

πŸ“‚ Contracultura Maker β€” GitHub repository

πŸ“• Download Contracultura Maker PDF


πŸ“¬ Contact

Roni Bandini Maker Β· AI Developer Β· Writer Buenos Aires, Argentina


Built with πŸŽ™οΈ + Photon 2 + Edge Impulse + keyword spotting.

Releases

Packages

Contributors

Languages