
Grazie alla potenza dell'ESP-32 e alla sua relativamente grande memoria è possibile, infatti, dotare ESPertino della parola. L'articolo, infatti, mostra proprio come far parlare la nostra scheda. Le applicazioni pratiche sono le più disparate: dalla voce che scandisce i numeri progressivi all'elimina code al supermercato o al saluto automatico per i clienti che entrano in qualsiasi sito commerciale. Vediamo come si arriva al risultato, passo dopo passo.
Introduzione
Far parlare ESPertino è, certamente, una impresa apparentemente un po' complicata ma che può rivelarsi estremamente utile e divertente. Si poteva pensare, inizialmente, che alla nostra scheda di sviluppo le mancasse solo la parola, per essere completa. Ma non è così, essa può anche parlare, grazie a degli accorgimenti particolari e alla possibilità di modulare opportunamente la tensione di una porta di output. Il dispositivo creato in questo articolo sa dire solo le parole "Uno", "Due" e "Tre" ma è possibile, ovviamente, far riprodurre qualsiasi altra parola o qualsiasi verso degli animali.
Come si riproduce la voce su una porta digitale?
Il suono non è altro che una vibrazione che si propaga grazie alla oscillazione di un mezzo vibrante e, attraverso l'aria, raggiunge le orecchie dell'ascoltatore sotto forma di suono, parola, rumore, musica ed altro. La vibrazione è causata da un evento perturbante come, ad esempio, il movimento delle corde vocali. Nel nostro caso essa è innescata dai diversi livelli di tensione elettrica uscenti da una porta digitale, sfruttando la tecnica del PWM (Pulse with modulation). Guardiamo, per un attimo, la figura 1. Essa rappresenta uno stralcio della forma d'onda che riproduce una parola. Se tutte i vari livelli descritti da tale segnale venissero trasformati in altrettante tensioni elettriche ed inviate ad un altoparlante, si sentirebbe, distintamente, la voce rappresentata. In teoria, se avessimo un potenziometro che potesse modulare con precisione, e molto velocemente, l'andamento grafico di tale segnale, potremmo riprodurre fedelmente il messaggio originale ma ciò, ovviamente, è impossibile. Lasciamo, dunque, che un processore esegua tale lavoro in maniera impeccabile.
Dato che dalla porta digitale possono uscire solo due livelli di tensione (3.3V e 0V) si adotta la tecnica del PWM che, tramite un treno di impulsi opportunamente dimensionato e cadenzato, con l'aggiunta di un filtro passa basso in uscita, genera qualsiasi tensione, nel dominio del tempo, come visibile in figura 2.
Se la larghezza dell'impulso è elevata (prossima al 100% dell'intero periodo) la tensione elettrica generata tenderà verso il massimo, mentre se essa è bassa (prossima allo 0% del periodo) la tensione in uscita tenderà verso il minimo.
Il software necessario per gestire l'intero progetto
Per realizzare il sistema occorrono svariati software, ognuno dei quali si deve occupare di un ben preciso compito. Quelli da noi utilizzati sono i seguenti:
- Audacity: è un potente software gratuito che permette la registrazione audio e il relativo editing;
- MagicPlot: è un fantastico programma per creare grafici dei dati ed eseguire il Curve Fitting e regressioni su tali dati;
- Foglio elettronico: vanno bene sia Microsoft Excel che il Calc di LibreOffice;
- IDE di Arduino con le librerie del modulo ESP32.
Primo passo: registrazione del messaggio
Bene, dopo aver descritto un po' la teoria di funzionamento del sistema, si può passare ad effettuare la registrazione di un brevissimo messaggio. E' opportuno, infatti, che esso risulti il più corto possibile, in modo che sia semplice da gestire e che, soprattutto, occupi poca memoria all'interno di ESPertino. Come esempio da seguire, la nostra parola da registrare sarà "TRE". Colleghiamo, dunque, un microfono al computer e predisponiamo il programma Audacity alla registrazione, premendo il pulsante con il cerchio rosso e registriamo la nostra parola. Alla fine dell'operazione è opportuno ricavare una traccia utile, eliminando ciò che non serve del segnale audio e mantenendo solo la parte della parola, senza inutili pause iniziali o finali. Anche il volume dell'intera forma d'onda (ampiezza) dovrebbe essere innalzato quasi al massimo senza, tuttavia, causare alcuna distorsione. La figura 3 mostra la registrazione eseguita. Si può salvare il messaggio con il nome "tre.wav" all'interno di una cartella appositamente creata per il progetto. E' opportuno che dopo la registrazione, le tracce stereo vengano commutate in mono, sia perché il doppio canale non serve a nulla, sia per ridurre al massimo l'occupazione in memoria. Ovviamente, al posto di Audacity, si può usare un altro software di elaborazione audio equivalente.
Secondo passo: esportazione su file TXT
Il prossimo passo è quello di esportare la forma d'onda in formato TXT. Per questo scopo, perseguito sempre con Audacity, occorre accedere al menù Analizza e scegliere la voce Sample Data Export. La figura 4 mostra tale procedura per l'esportazione. Si consiglia di non modificare le voci richieste.
L'esportazione crea un file di testo simile a quello riportato in figura 5.
Terzo passo: la tabella in MagicPlot
Arrivati a questo punto occorre importare da MagicPlot i dati prima memorizzati in un file di testo. Si apra il programma, si crei una tabella e si incollino i dati del TXT su di essa, come mostrato in figura 6.
Selezionando le due colonne è possibile "tirare fuori" anche il grafico a dispersione, come mostrato in figura 7. In un prossimo futuro articolo, questa operazione risulterà indispensabile per implementare un complesso curve fitting al fine di ricavare una complessa formula matematica che descriva la forma d'onda in questione.
Quarto passo: la preparazione dell'array per ESPertino
Questo passo è molto importante poiché prepara la riga di comando che inizializza un array di ESPertino e lo predispone a contenere tutti i campioni precedentemente digitalizzati. Tale passo potrebbe essere bypassato, se si preferisce digitare a mano migliaia di campioni sull'IDE di Arduino, ma penso che tale sacrificio potrebbe costituire solo una perdita di tempo e produrrebbe sicuramente un lavoro con la presenza di molti errori di battitura. Per questo scopo occorre utilizzare un foglio elettronico nel quale si deve incollare solamente la seconda colonna della tabella di MagicPlot, ossia quella che contiene i dati del campionamento del suono e non i numeri progressivi. Essa sarà memorizzata sulla colonna "A" del foglio elettronico, come si può osservare in figura 8.
Per tutte le righe del foglio, adesso, occorre creare le seguenti formule, in modo da adeguare i vari dati alle esigenze finali del vettore per ESPertino, ossia:
- Nella colonna "B" occorre creare, per tutte le righe dei dati, la formula "=A1*128". Questo serve ad ottenere un intervallo di dati compresi tra -128 e +128, e non tra -1 e +1;
- Nella colonna "C" si deve creare una formula che sommi ad essa un certo valore di soglia tale che in essa non sia presente alcun numero negativo;
- Nella colonna "E" ci deve essere, infine, una formula che accodi, riga per riga, tutti i valori, separati tra loro tramite una virgola. Essa sarà simile a "=E4 & "," & C5";
Guardando l'ultima riga in basso del foglio, si può incollare sull'IDE di Arduino la lunghissima stringa creata (vedi figura 9), contenente il vettore bello e pronto. Occorre solo inserire a mano l'assegnazione ad una variabile e le parentesi graffe di testa e di coda. Un esempio potrebbe essere il seguente:
float vettore3[] = {131.95968,..........................,128.3424}
Si faccia solo attenzione affinché ci siano i punti come separatore decimale e le virgole come separatore degli elementi dell'array.
Collegamenti elettrici
Passiamo adesso alla parte elettronica del progetto. Il cablaggio del sistema è estremamente semplice, come si può constatare grazie alla figura 10. Alla porta IO0 è collegato un piccolo altoparlante (per l'ascolto locale) o un amplificatore audio di bassa frequenza, per un ascolto pubblico. Tra ESPertino e il riproduttore audio c'è un filtro passa basso che ha lo scopo di filtrare le alte frequenze e di non rendere, pertanto, udibile un eventuale fischio di circa 4 Khz. Inoltre il filtro ha anche il compito di nascondere le onde quadre del PWM rendendo analogica, a tutti gli effetti, la tensione uscente (DAC) e produrre, in questo modo, una curva dolce e continua.
Lo sketch
Il listato sorgente non è lungo. Occupano un po' di spazio solamente i vettori, composti da migliaia di elementi numerici. La parte iniziale dello sketch è caratterizzata da tre vettori numerici, abbastanza estesi, contenenti i campioni delle tre parole che deve riprodurre il nostro ESPertino: "Uno", "Due" e "Tre". Il primo vettore contiene 3416 campioni, il secondo ne contiene 4556 e il terzo 2053. La figura 11 mostra le tre relative forme d'onda.
La funzione setup(), eseguita solo una volta, ha il solo compito di configurare la porta zero (IO0) come uscita, alla quale è collegato l'altoparlante.
La funzione loop(), che si ripete all'infinito, contiene tre cicli iterativi identici ma indipendenti tra loro, ognuno dei quali ha il compito di riprodurre la parola. Il ciclo, infatti, esegue una iterazione da zero al limite del vettore che contiene i campioni. In questa fase viene realizzato un riproduttore audio con la tecnica del PWM, in modo che si alternino il periodo attivo e quello passivo dell'onda (il duty cycle è il rapporto tra la durata del segnale "alto" e il periodo totale del segnale) secondo le direttive imposte dai valori contenuti nel vettore. In pratica è generato un treno di impulsi variabile che, in sostanza, ricostruisce fedelmente la forma d'onda originaria.
Dopo la riproduzione di ognuna delle tre parole è prevista una pausa di attesa di un secondo.
[...]
ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 2144 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

In questo articolo le forme d’onda sono descritte attraverso tantissimi valori contenuti in un array. Con questo metodo il programma rischia di diventare troppo lungo e potrebbe non entrare in memoria, specialmente quando i campioni sono di numero troppo elevato. In una delle prossime puntata vedremo come descrivere le forme d’onda utilizzando dei sistemi matematici non lineari.
Ciao e complimenti per l’articolo!
Mi chiedevo, se non fosse stato possibile registrare e quindi campionare l’audio direttamente tramite l’ADC di Espertino per poi scrivere magari i campioni in un file memorizzandolo su di una una microsd per poi essere anche riletti e quindi riprodotti?
Ciao e grazie dei complimenti.
Sto proprio conducendo esperimenti in tal senso,
ma sono sicuro che tra la velocità operativa di ESP32 che la potenza del suo ADC, si potrà campionare voce e suono.
A presto ci saranno info in merito.
CIao
Game over
Sono arrivato troppo tardi. Quindi me ne vado.
Buongiorno Giovanni!
Ho letto il tuo articolo e mi e’ piaciuto molto.
Ho pensato subito ai ragazzi che all’Hackathon di ESPertino al Capus Party hanno proposto il progetto ESPertune.
Durante l’Hackathon, ricordo che parlavamo della possibilità di riprodurre suoni utilizzando il DAC integrato in ESPertino; cosi’ mi sono informato un po’ e ho provato ad usarlo nel progetto che hai proposto in questo articolo.
Anziché utilizzare la tecnica del PWM per “simulare” un livello di tensione su una porta digitale, possiamo generare un livello di tensione vero su una delle due “porte analogiche” di ESPertino (25 e 26). Per farlo si può’ utilizzare la funzione:
void dacWrite(uint8_t pin, uint8_t value)
definita in esp32-hal-dac.h
pin: indica il pin su cui si vuole impostare la tensione (si possono utilizzare solo i pin 25 e 26, marcati come x2 e x3 sulla board di ESPertino)
value: indica il valore della tensione; 0 corrisponde a 0V, 255 corrisponde a 3.3V grossomodo.
Per fare un esempio, Il ciclo che nel tuo progetto dice “UNO” diventa il seguente:
//——–Dice: “UNO”————-
for(int x=0;x<3415;x++) {
// imposta il pin 25 alla tensione desiderata (impiega 5-6 microsecondi)
dacWrite(25, vettore1[x]);
// aspetta 90 microsecondi per rispettare l'intervallo di campionamento.
// (1/11025Hz ~= 90 micosec)
delayMicroseconds(90);
}
Il funzionamento e' semplice:
per ogni campione, imposto la relativa tensione sul "pin analogico" e faccio una pausa prima di passare al campione successivo. Questo perché la funzione dacWrite() e' molto veloce (circa 5-6 microsecondi) ed e' necessario aggiungere una pausa per rispettare l'intervallo di campionamento a cui e' stato acquisito il segnale. Modificando la durata di questa pausa, si rallenta o velocizza la riproduzione del suono generando effetti quantomeno divertenti.
Nonostante il DAC di ESPertino sia a soli 8 bit (può produrre solo 256 livelli di tensione), il suono risultante dall'utilizzo del DAC e' molto più' gradevole rispetto a quello generato con la tecnica del PWM perché elimina molte di quelle armoniche ad alta frequenza cosi' fastidiose all'orecchio.
Nella speranza che questo commento possa essere utile a qualcuno, ti rinnovo i complimenti per i tanti interessanti articoli su ESPertino, che sono sempre ottima fonte di ispirazione.
Grazie mille,
Ivan.
Ciao Ivan.
Fantastico. Grazie 1000 per questo tuo grandioso contributo.
Sarà sicuramente utile a tutti gli utenti di ESPertino.
E forse non ci sarebbe bisogno di prevedere il filtro RC, in quanto il segnale è reale.
Grazie.
C’è una qualche speranza di poter avere Espertino anche per quello che non hanno fatto in tempo a richiederlo?
Buongiorno,
sto sviluppando un progetto utilizzando espertino, dovrei comandare due motori con un segnale PWM , noto però che la funzione analogWrite( pin, dutycicle) non è dichiarata se si compila per espertino.
C’è un qualche trucco per poterla usare?
Ciao Marco83.
Puoi provare con la funzione:
dacWrite(uint8_t pin, uint8_t value);
oppure con la funzione:
ledcWrite(channel, duty);
Saluti
G