Overview
The Voice Recognition Module V3 (the widely used Elechouse VR3 design) adds offline spoken-command control to your projects. You train it by speaking your own commands — in any language, or even whistles — and it stores each one as a voiceprint record. Up to 80 commands can be saved on the module, with any 7 loaded into the active recognizer at once. When it hears a match, it reports the record number over a simple 9600-baud serial link, and your sketch decides what happens next: lights on, robot forward, lock open.
Everything runs on the module itself — no Wi-Fi, no cloud, no internet. That makes response instant and keeps the hardware simple: power, ground, and two UART wires are all it needs. Sound comes in through the included microphone on the 3.5 mm mono jack (a separate mic header is also broken out on the board), and a row of expansion I/O pins (OUT0-OUT6, IN0-IN2) is available for advanced use. The board runs from 4.5-5.5V and speaks 5V TTL serial, so it pairs natively with classic Arduinos, while 3.3V boards like the ESP32, Raspberry Pi, and Pico just need one resistor divider on the module's TXD line.
Because recognition is speaker-dependent — it matches the voice that trained it — the module is a natural fit for personal projects: voice-controlled robots, hands-free workshop lights, talking props, accessibility switches, and STEM demos. Train clearly, keep background noise down, and recognition accuracy can reach about 99% in a quiet environment.
At a Glance
Specifications
| Parameter | Value |
| Recognition Type | Speaker-dependent (trained to your voice), fully offline |
| Operating Voltage | 4.5V - 5.5V DC |
| Operating Current | < 40 mA |
| Interface | UART, 5V TTL logic |
| Baud Rate | 9600 default (2400 - 38400 configurable) |
| Stored Commands | Up to 80 voiceprint records |
| Active Recognizer | 7 records loaded at once |
| Command Length | Up to 1500 ms per record |
| Recognition Accuracy | Up to ~99% in a quiet environment |
| Audio Input | 3.5 mm mono microphone jack + mic header pins |
| Expansion I/O | OUT0 - OUT6 and IN0 - IN2 headers |
| Board Dimensions | 50 x 31 mm |
Pinout Diagram
Only the four-pin UART header needs wiring for normal use: GND, VCC (5V), RXD, and TXD. Remember the serial crossover — the module's TXD goes to your board's RX pin and RXD to your board's TX. The microphone plugs into the 3.5 mm jack on the right edge, the Winbond W25Q32JV flash chip stores your trained voiceprints so they survive power cycles, and the OUT0-OUT6 / IN0-IN2 headers are optional expansion I/O you can ignore for standard serial projects.
Wiring Guide
Arduino Wiring
The Arduino Uno is the module's home turf: both run 5V logic, so everything connects directly. The sensor sits on a SoftwareSerial port using pins 2 and 3, leaving the hardware serial free for the Serial Monitor.
| Module Pin | Arduino Pin |
|---|---|
| GND | GND |
| VCC | 5V |
| TXD | D2 (SoftwareSerial RX) |
| RXD | D3 (SoftwareSerial TX) |
ESP32 Wiring
Power the module from VIN (5V). The ESP32's GPIO is 3.3V only, so the module's 5V TXD line must pass through a voltage divider before reaching the ESP32's RX pin. The ESP32's 3.3V TX signal is high enough for the module to read directly.
| Module Pin | ESP32 Pin | Details |
|---|---|---|
| GND | GND | |
| VCC | VIN (5V) | Module needs 4.5-5.5V |
| TXD | GPIO 16 (RX2) | Via voltage divider |
| RXD | GPIO 17 (TX2) | 3.3V signal - direct |
Raspberry Pi Wiring
The module connects to the Pi's GPIO UART. Free the port first: sudo raspi-config > Interface Options > Serial Port — answer "No" to the login shell, "Yes" to the serial hardware, then reboot.
| Module Pin | Raspberry Pi Pin | Details |
|---|---|---|
| GND | Pin 6 (GND) | |
| VCC | Pin 2 (5V) | |
| TXD | Pin 10 (GPIO 15, RXD) | Via voltage divider |
| RXD | Pin 8 (GPIO 14, TXD) | 3.3V signal - direct |
Raspberry Pi Pico Wiring
UART0 on GP0/GP1 talks to the module, with 5V power from VBUS while the Pico runs on USB. Like the Pi and ESP32, the Pico needs the module's TXD divided down to 3.3V.
| Module Pin | Pico Pin | Details |
|---|---|---|
| GND | GND (pin 38) | |
| VCC | VBUS (pin 40) | 5V from USB |
| TXD | GP1 (pin 2, UART0 RX) | Via voltage divider |
| RXD | GP0 (pin 1, UART0 TX) | 3.3V signal - direct |
Code Examples
Arduino
Install the Elechouse VoiceRecognitionV3 library (download from the Elechouse GitHub repository and add via Sketch > Include Library > Add .ZIP Library). Train records 0-2 with the bundled vr_sample_train example, then run this sketch.
// Voice Recognition Module V3 - Arduino Example
// Module TXD -> D2, Module RXD -> D3, VCC -> 5V, GND -> GND
// Library: Elechouse VoiceRecognitionV3 (github.com/elechouse/VoiceRecognitionV3)
// Train records 0-2 first with the vr_sample_train example.
#include <SoftwareSerial.h>
#include "VoiceRecognitionV3.h"
VR myVR(2, 3); // RX = D2 (from module TXD), TX = D3 (to module RXD)
uint8_t records[7];
uint8_t buf[64];
void setup() {
Serial.begin(115200);
myVR.begin(9600);
if (myVR.clear() == 0) {
Serial.println("Recognizer cleared.");
} else {
Serial.println("Module not found - check wiring.");
while (1);
}
// Load trained records 0, 1, 2 into the active recognizer
if (myVR.load((uint8_t)0) >= 0) Serial.println("Record 0 loaded");
if (myVR.load((uint8_t)1) >= 0) Serial.println("Record 1 loaded");
if (myVR.load((uint8_t)2) >= 0) Serial.println("Record 2 loaded");
Serial.println("Speak one of your trained commands...");
}
void loop() {
int ret = myVR.recognize(buf, 50);
if (ret > 0) {
// buf[1] holds the record number that was recognized
switch (buf[1]) {
case 0:
Serial.println("Command 0 recognized!");
// digitalWrite(LED_BUILTIN, HIGH); // your action here
break;
case 1:
Serial.println("Command 1 recognized!");
break;
case 2:
Serial.println("Command 2 recognized!");
break;
default:
Serial.println("Record not handled");
}
}
}
ESP32 (Arduino IDE)
// Voice Recognition Module V3 - ESP32 Example (raw protocol)
// Module TXD -> GPIO 16 via divider, Module RXD -> GPIO 17, VCC -> VIN
// Train the records first using an Arduino and the Elechouse library -
// the voiceprints stay stored on the module.
HardwareSerial vrSerial(2); // UART2
void loadRecord(uint8_t rec) {
// Frame: AA | LEN | 30 (load) | record | 0A
uint8_t cmd[5] = {0xAA, 0x02, 0x30, rec, 0x0A};
cmd[1] = 2; // LEN = command + data bytes
vrSerial.write(cmd, 5);
delay(50);
}
void setup() {
Serial.begin(115200);
vrSerial.begin(9600, SERIAL_8N1, 16, 17);
delay(500);
// Load trained records 0-2 into the recognizer
loadRecord(0);
loadRecord(1);
loadRecord(2);
Serial.println("Speak one of your trained commands...");
}
void loop() {
// Recognition frames arrive as: AA | LEN | 0D | data... | 0A
static uint8_t frame[32];
static int pos = -1;
while (vrSerial.available()) {
uint8_t b = vrSerial.read();
if (pos < 0) {
if (b == 0xAA) { pos = 0; frame[pos++] = b; }
} else {
frame[pos++] = b;
if (b == 0x0A || pos >= 32) {
// frame[2] = 0x0D means "voice recognized";
// frame[4] holds the record number
if (pos > 5 && frame[2] == 0x0D) {
Serial.printf("Recognized record #%d\n", frame[4]);
}
pos = -1;
}
}
}
}
Raspberry Pi (Python)
#!/usr/bin/env python3
# Voice Recognition Module V3 - Raspberry Pi Example (raw protocol)
# Module TXD -> GPIO 15 via divider, Module RXD -> GPIO 14, VCC -> 5V
# Setup: sudo raspi-config (disable serial console, enable serial port)
# pip3 install pyserial
# Train the records first with an Arduino - they stay on the module.
import time
import serial
ser = serial.Serial('/dev/serial0', baudrate=9600, timeout=0.1)
def load_record(rec):
# Frame: AA | LEN | 30 (load) | record | 0A
ser.write(bytes([0xAA, 0x02, 0x30, rec, 0x0A]))
time.sleep(0.05)
# Load trained records 0-2 into the active recognizer
for r in (0, 1, 2):
load_record(r)
print('Speak one of your trained commands (Ctrl+C to stop)...')
buffer = bytearray()
try:
while True:
data = ser.read(32)
if data:
buffer.extend(data)
# Complete frames start with 0xAA and end with 0x0A
while 0xAA in buffer and 0x0A in buffer[buffer.index(0xAA):]:
start = buffer.index(0xAA)
end = buffer.index(0x0A, start)
frame = buffer[start:end + 1]
del buffer[:end + 1]
# frame[2] == 0x0D means "voice recognized";
# frame[4] holds the record number
if len(frame) > 5 and frame[2] == 0x0D:
print('Recognized record #{}'.format(frame[4]))
time.sleep(0.02)
except KeyboardInterrupt:
print('Stopped by user')
finally:
ser.close()
Raspberry Pi Pico (MicroPython)
# Voice Recognition Module V3 - Pico MicroPython Example (raw protocol)
# Module TXD -> GP1 via divider, Module RXD -> GP0, VCC -> VBUS
# Train the records first with an Arduino - they stay on the module.
from machine import UART, Pin
import time
uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1), timeout=100)
def load_record(rec):
# Frame: AA | LEN | 30 (load) | record | 0A
uart.write(bytes([0xAA, 0x02, 0x30, rec, 0x0A]))
time.sleep_ms(50)
# Load trained records 0-2 into the active recognizer
for r in (0, 1, 2):
load_record(r)
print("Speak one of your trained commands...")
buffer = bytearray()
while True:
data = uart.read()
if data:
buffer.extend(data)
# Complete frames start with 0xAA and end with 0x0A
while 0xAA in buffer:
start = buffer.index(0xAA)
end = buffer.find(b'\n', start) # 0x0A terminator
if end < 0:
break
frame = buffer[start:end + 1]
del buffer[:end + 1]
# frame[2] == 0x0D means "voice recognized";
# frame[4] holds the record number
if len(frame) > 5 and frame[2] == 0x0D:
print("Recognized record #", frame[4])
time.sleep_ms(20)