Come programmare un theremin in Python su Arduino grazie a VIPER

In questo tutorial, vedremo come programmare un semplice theremin che cambia l'intonazione in base alla distanza della mano da un sensore di prossimità ad infrarossi. In aggiunta si può facilmente variare la lunghezza del "beat" e far lampeggiare due o più LED contemporaneamente... è la magia del multi-threading, è la magia di VIPER!

INTRODUZIONE

 

Il theremin è uno strumento musicale inventato dal fisico russo Lev Sergeevic Termen negli anni '20. A differenza dei comuni strumenti musicali ha due caratteristiche che lo rendono molto interessante per gli amanti della tecnologia: è uno dei primi strumenti musicali ad essere completamente elettronico e può essere suonato senza contatto fisico!

Il funzionamento è abbastanza semplice: due antenne rilevano la posizione nello spazio delle mani dell'esecutore e la parte elettronica dello strumento elabora questa informazione per controllare la frequenza e l'ampiezza del suono emesso. Un suono talmente particolare, che varia dal violoncello-violino fino a raggiungere caratteristiche vocali, da essere stato utilizzato in numerose colonne sonore di vecchi film, tra cui La moglie di FrankensteinUltimatum alla Terra e Qualcuno volò sul nido del cuculo.

In questo tutorial, vedremo come costruire un semplice theremin che cambia l'intonazione in base alla distanza della mano da un sensore di prossimità ad infrarossi (come quello usato in questo vecchio articolo). In aggiunta si può facilmente variare la lunghezza del "beat" e far lampeggiare due o più LED contemporaneamente... è la magia del multi-threading, è la magia di VIPER!

A dispetto dell'apparente complessità, questo progetto richiede una elettronica molto semplice, in quanto il lavoro sporco lo fa VIPER, il nuovo software usato per programmare il theremin.

VIPER (acronimo di VIPER Is Python Embedded in Realtime) è una suite di sviluppo per il design di oggetti interattivi, pronti per il cloud e l'Internet delle Cose (Internet of Things, IoT). Con VIPER creativi, designers e professionisti possono sviluppare in Python per Arduino DUE, ST Nucleo, Particle Core/Photon e tutte le altre più famose piattaforme di prototipazione, usando i paradigmi e le features tipiche della programmazione ad alto livello.

DISCLAIMER

 

Sebbene VIPER sia una piattaforma di sviluppo professionale e performante, questo tutorial mostra come costruire un theremin non-professionale. Comunque, siamo abbastanza fiduciosi che otterrete risultati migliori di Sheldon 😀

Quindi, proseguiamo!

Step 1: Materiale necessario

Avrete bisogno di:

  • 1 x sensore di prossimità ad infrarossi Sharp (GP2Y0A21YK)
  • 2 x resistenze da 1 kΩ
  • 2 x  LED (possibilmente uno rosso e uno verde)
  • 1 x piezo buzzer
  • 1 x potenziometro rotativo
  • 1 x breadboard
  • un po' di cavetti jumper
  • VIPER! Non importa che sistema operativo usiate, VIPER è cross-platform!
  • Arduino DUE o una ST Nucleo o una Particle (conosciuta precedentemente come Spark) Core o Photon. Non importa quale scheda usiate, VIPER è multi-board! Potete trovare tutte le board attualmente supportate in questa sezione della documentazione di VIPER.

Step 2: Assembla il circuito

Multithreaded Blinking Theremin con VIPER

 

  • Un sensore Sharp IR ha 3 pin. Uno serve per l'alimentazione, che nel nostro caso è la 3.3 V. Un altro è per la massa, che connetteremo al pin GND. Infine, c'è un output analogico che varia da 3.1 V  a 0.4 V (che corrispondono a distanze di 10 e 80 cm). Questo pin deve essere collegato ad un pin di input analogico della board. Nel nostro caso, useremo il pin A5.
  • Il piezo buzzer usa uno speciale cristallo che si espande e si contrae in base al segnale elettrico che lo attraversa. Questo genera un suono che possiamo udire. Un pin del buzzer va a massa (GND) mentre l'altro va collegato ad un pin digitale. Nel nostro caso useremo il D7 (o un altro pin con PWM se si usa lo Spark Core, come ad esempio A4).
  • Un potenziometro rotativo ha 3 pin. Connetti un pin esterno a 3.3V e l'altro pin esterno a GND. Il pin centrale avrà quindi un potenziale  che varierà da 0 V a 3.3 V in relazione alla rotazione applicata. Questo pin deve essere collegato ad un pin di input analogico della board. Nel nostro caso, useremo il pin A2.
  • Per costruire il circuito per i LED, connetti una estremità della resistenza al pin D8 (o D7 su Spark Core). Connetti il terminale più lungo del LED (il polo positivo, chiamato anodo) all'altra estremità della resistenza. Connetti  il terminale più corto del LED (il polo negativo, chiamato catodo) a massa (GND).

Step 3: Programma la board con VIPER

VIPER IDE VIPER IDE - "Choose Board"

 

Usare VIPER è molto semplice! Vediamo come fare:

  1. Scarica l'installer per Windows, Linux o iOS dalla pagina di download di VIPER (potrebbero apparire dei messaggi di alert, per favore accetta il "rischio" e vai avanti, è un falso allarme e verrà risolto il prima possibile).
  2. Installalo (ecco un breve tutorial su come installare VIPER) e lancia l'applicazione tramite l'icona apparsa sul desktop.
  3. Crea un utente VIPER attraverso il pulsante dedicato in alto a destra. Controlla la tua mail e verifica il tuo nuovo account cliccando sull'apposito link. Perchè registrarsi? Con un account VIPER puoi: partecipare alla  VIPER community; salvare i tuoi progetti on-line nel VIPER Cloud; ricevere automaticamente gli aggiornamenti!
  4. Connetti la tua board e rinominala come preferisci in modo da poterla riconoscere facilmente in futuro!
  5. Per rendere la board usabile, bisogna Viperizzarla, cioè installare su di essa la VIPER VM (Virtual Machine), attraverso l'apposito pulsante nella topbar del VIPER IDE.
  6. Crea un nuovo progetto, copia il codice che trovi su github, compila lo script e caricalo nella board!

Step 4: Spiegazione del codice

Perchè usare VIPER

Uno dei concetti più difficili da comprendere per chi si avvicina alla programmazione embedded è come gestire diversi task contemporaneamente, cioè come creare una sorta di multitasking. Gli sviluppatori sono spesso frustrati dalle difficoltà incontrate nell'implementazione di questa funzionalità nei microcontrollori.

Per risolvere questi problemi, VIPER supporta gran parte delle features di alto livello di Python, in particolare il multithreading, ma anche moduli, classi, callbacks, timers ed eccezioni, più alcune particolari features relative all'hardware come interrupts, PWM, digital I/O, ecc.

Ogni thread in VIPER è una sorta di processo parallelo che funziona autonomamente sulla board. Per eseguire un thread è necessario definire una funzione di input, che può essere istanziata da vari threads dando la possibilità di scrivere codice molto conciso e riutilizzabile. Più info qui.

Inside the code

Lo script è implementato usando 4 threads che funzionano in parallelo. Un thread istanzia la funzione sampling() che converte e normalizza i segnali analogici acquisiti attraverso un potenziometro e un sensore di prossimità a IR. Due threads sono usati per instanziare una generica funzione di blink() che fa lampeggiare due LED a differenti frequenze. Un altro thread istanzia una generica funzione buzz() che fa suonare un buzzer a differenti frequenze e durata dello sleep (per creare un effetto "beat"), calcolati sulla base dei segnali analogici acquisiti.

Il codice è molto intuitivo e ha un bel po' di commenti che vi aiuteranno a capirne tutti i dettagli. Mi dilungo solo un altro po' per descrivere due aspetti fondamentali e innovativi di VIPER.

1. delay() vs sleep()

In Arduino/Wiring usare la funzione delay() ha un effetto collaterale: interrompe il ciclo di esecuzione di uno "sketch" per il numero di millisecondi assegnato come argomento. Cioè Arduino letteralmente si blocca e non rileva alcun input così come non invia alcun output!

In VIPER la funzione sleep() sospende il thread corrente MA tutti gli altri threads continuano ad essere eseguiti!

2. VIPER built-in functions

La VIPER Virtual Machine estende Python con delle funzioni particolari (built-in functions) in grado di gestire i pin di Input e Output dei microcontrollori. Queste funzioni ricordano quelle tipiche del linguaggio Arduino, ma sono più flessibili. Vediamone alcune:

analogRead() vs adc.read()

La funzione analogRead() è fornita come built-in per facilitare il passaggio da Arduino/Wiring a VIPER.
Comunque, la sintassi preferibile per leggere i valori dai pin analogici in VIPER è:

# import the adc driver
import adc

x = adc.read(pin, samples=1)

Se "samples" è uguale a 1 (o non espresso), la funzione ritorna il valore intero letto sul pin. Se "samples" è maggiore di 1, ritorna una tupla () di interi con dimensione uguale a quella impostata.

analogWrite() vs. pwm.write()

La funzione analogWrite() di Arduino fornisce una semplice interfaccia per la gestione della PWM, impropriamente chiamata "analog output". In particolare, permette di variare il duty cycle dell'onda quadra ma non fornisce nessun controllo sul periodo dell'onda quadra. VIPER, invece, attraverso una sintassi molto semplice, permette di controllare sia il periodo che il duty cycle dell'onda.

Anche qui la funzione analogWrite() è fornita come built-in per facilitare il passaggio da Arduino/Wiring a VIPER. Tuttavia il modo migliore di usare il PWM in VIPER è:

# import the pwm driver
import pwm

pwm.write(pin, period, pulse, time_unit=MILLIS)

Lo stato del pin è periodicamente alternato tra LOW e HIGH in base ai parametri impostati. In particolare:

  •  "period" imposta la durata dell'onda quadra
  •  "pulse" imposta la durata del duty cycle
  •  "time_unit" imposta l'unità di misura di "period" e "pulse"

Step 5: Divertiti!

 

Puoi partire da questo semplice esempio per sviluppare il comportamento che preferisci. Ovviamente ci sono molte possibilità di miglioramento, per esempio:
  • aggiungere un controllo del volume
  • usare la smartSensors library invece di mappare l'input analogico "a mano"

Sentitevi liberi di suggerire le vostre idee, e divertitevi ad infastidire la gente con il vostro nuovo theremin!

PARTECIPA AL VIPER-PRIZE!

Infine vi ricordo che sono aperte le iscrizioni per partecipare al workshop gratuito: Interaction design ed IoT: sviluppare oggetti interattivi con VIPER! Avrà luogo Sabato 25 luglio 2015 dalle 14:00 alle 18:30 presso il FabLab Firenze, in via Renato Fantoni 8.

Iscrivendoti potrai partecipare al #‎VIPERprIZE‬!

Regolamento:
- crea un progetto usando VIPER
- caricalo su Hackster.io (https://www.hackster.io/viper)
- presentalo durante il workshop

Riceverai gratuitamente ‪‎TOIshield‬, uno shield multi-sensor compatibile con le più famose board di prototipazione!

VIPER - TOI Shield

 

Ti aspettiamo!


Luigi F. Cerfeda (@L_F_Cerfeda) - VIPER team

Articolo originale su Instructables (in inglese)

 

Scarica subito una copia gratis
Tags:

12 Commenti

  1. Ernesto Sorrentino 22 Luglio 2015
  2. Ernesto Sorrentino 22 Luglio 2015
  3. lorenzo.acquaviva 22 Luglio 2015
  4. Francesco Francesco 23 Luglio 2015
  5. Luigi Francesco Cerfeda LuigiFrancescoCerfeda 27 Luglio 2015
  6. Francesco Francesco 27 Luglio 2015
  7. Luigi Francesco Cerfeda LuigiFrancescoCerfeda 11 Settembre 2015
  8. Luigi Francesco Cerfeda LuigiFrancescoCerfeda 14 Ottobre 2015
  9. Orazio Aiello 23 Novembre 2015

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend