
12 - KNOCK LOCK
CREA LA TUA SERRATURA SEGRETA PER TENERE LONTANI GLI OSPITI INDESIDERATI!
Scopri: input con un piezo, scrivere le funzioni
Tempo: 1 ORA Livello: ■ ■ ■ ■ □ Basato sui progetti: 1, 2, 3, 4, 5
Il piezo, che hai usato per riprodurre suoni nei progetti theremin e tastiera musicale, può anche essere utilizzato come dispositivo di ingresso. Quando è collegato a 5V, il sensore può rilevare le vibrazioni misurabili dagli ingressi analogici di Arduino. Avrai bisogno di collegare una resistenza di alto valore (come 1 mega ohm) come riferimento a massa per far funzionare tutto correttamente.

INGREDIENTI
Servomotore
Piezo
Pulsante
LED (Rosso, Giallo, Verde)
Resistenza da 10 Kilo Ohm
Resistenza da 220 Ohm (x3)
Resistenza da 1 Mega Ohm
Condensatore da 100 uF
Piedini del connettore a pettine (3 piedini)
Quando il piezo viene premuto contro una superficie solida in grado di vibrare, come un tavolo in legno, Arduino può percepire l’intensità del colpo. Utilizzando queste informazioni puoi contare quante volte è stato bussato in un intervallo prestabilito. Nel codice è possibile monitorare il numero di colpi e vedere se corrispondono alle tue impostazioni.
Un interruttore ti permetterà di bloccare il motore in posizione. Alcuni LED ti daranno lo stato: un LED rosso indica che la scatola è chiusa a chiave, un LED verde indica che è sbloccata e un LED giallo permette di sapere se è stato ricevuto un colpo valido.
Scriverai anche una funzione che ti consente di sapere se il colpo è troppo forte o troppo leggero. Scrivere funzioni consente di risparmiare tempo riutilizzando il codice invece di riscriverlo molte volte. Le funzioni possono avere dei parametri e restituire valori. In questo caso, fornirai alla funzione il volume del colpo. Se è nell’intervallo giusto, incrementi una variabile.
È possibile costruire anche solo il circuito, ma è molto più divertente se lo si utilizza come strumento per chiudere a chiave qualcosa. Se hai una scatola di legno o di cartone puoi tagliarci dei fori e utilizzare il servomotore per aprire e chiudere un chiavistello, tenendo le persone lontane dalle tue cose.
COSTRUISCI IL CIRCUITO
Ci sono molte connessioni sulla scheda, assicurati di tenere traccia di come sono collegate le cose.

Collega l’alimentazione e la massa su entrambi i lati della breadboard. Posiziona il pulsante sulla breadboard e collega una estremità a 5V. Collega l’altro lato dell’interruttore a massa attraverso una resistenza da 10 kilo ohm. Collega questo punto di incrocio al piedino digitale 2 di Arduino.
Collega i fili dal piezo alla breadboard. Collega un filo all’alimentazione. Se il piezo ha un filo rosso o uno contrassegnato con un «+», è quello da collegare all’alimentazione. Se il piezo non indica la polarità, allora si può collegare in entrambi i modi. Collega l’altra estremità del piezo al piedino analogico 0 di Arduino. Colloca una resistenza da 1 mega ohm tra la massa e l’altro filo. Valori di resistenza più bassi rendono il piezo meno sensibile alle vibrazioni.
Collega i LED, connettendo i catodi (piedino corto) a massa, e mettendo una resistenza da 220 ohm in serie con gli anodi. Attraverso le loro rispettive resistenze, collega il LED giallo al piedino digitale 3 di Arduino, il LED verde al piedino digitale 4 e il LED rosso al piedino digitale 5.
Inserisci i piedini del connettore a pettine nel connettore del servomotore (vedi la Fig. 3). Collega il filo rosso all’alimentazione e quello nero a massa. Metti un condensatore elettrolitico da 100 uF tra l’alimentazione e la massa per compensare eventuali irregolarità nella tensione e assicurati di aver collegato correttamente la polarità del condensatore. Collega il cavo dei dati del servo al piedino 9 di Arduino.


Fig.3: Il servomotore è dotato di un connettore femmina, quindi hai bisogno di aggiungere piedini maschi per collegarlo alla breadboard.
IL CODICE
La libreria Servo
Come nel progetto “Indicatore d’umore”, è necessario importare la libreria Servo e creare un’istanza per utilizzare il motore.
#include <Servo.h>
Servo myServo;
Costanti utili
Crea le costanti per dare un nome ai tuoi ingressi e uscite.
const int piezo = A0;
const int switchPin = 2;
const int yellowLed = 3;
const int greenLed = 4;
const int redLed = 5;
Variabili per memorizzare i valori
Crea le variabili per memorizzare i valori dell’interruttore e del piezo.
int knockVal;
int switchVal;
Soglie di rilevamento
Crea delle costanti da usare come soglie per i livelli minimo e massimo dei colpi.
const int quietKnock = 10;
const int loudKnock = 100;
Variabili per lo stato di blocco
La variabile locked ti consente di sapere se la serratura è chiusa o no. Il boolean è un tipo di dato che può solo essere vero (1) o falso (0). Dovresti iniziare con la serratura sbloccata.
L’ultima variabile globale contiene il numero di colpi validi che hai rilevato.
boolean locked = false;
int numberOfKnocks = 0;
Imposta la direzione dei piedini
Nel setup(), attacca il servo al piedino 9.
Imposta i piedini del LED come uscite e i piedini dell’interruttore come ingressi.
void setup(){
myServo.attach(9);
pinMode(yellowLed, OUTPUT);
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
pinMode(switchPin, INPUT);
Serial.begin(9600);
Sblocco
Avvia la comunicazione seriale con il computer in modo da poter controllare il volume del colpo, lo stato corrente del blocco e quanti colpi mancano allo sblocco. Accendi il LED verde, muovi il servo nella posizione di sblocco e stampa lo stato attuale sul monitor seriale indicando che il circuito è nella posizione sbloccata.
digitalWrite(greenLed, HIGH);
myServo.write(0);
Serial.println("The box is unlocked!");
}
Controlla l’interruttore
Nel loop(), per prima cosa verifica se la scatola è bloccata o no. Questo determina ciò che accade nel resto del programma. Se è bloccata, leggi il valore dell’interruttore.
void loop(){
if(locked == false){
switchVal = digitalRead(switchPin);
Blocco
Se l’interruttore è chiuso (lo stai premendo), modifica la variabile locked a true, indicando che il blocco è innestato. Spegni il LED verde e accendi il LED rosso. Se non hai acceso il monitor seriale, questo è un utile feedback visivo per informarti dello stato del blocco. Sposta il servo in posizione di blocco e stampa un messaggio sul monitor seriale che indica che la scatola è bloccata. Aggiungi un ritardo in modo che la serratura abbia tempo per cambiare posizione.
if(switchVal == HIGH){
locked = true;
digitalWrite(greenLed,LOW);
digitalWrite(redLed,HIGH);
myServo.write(90);
Serial.println("The box is locked!");
delay (1000);
}
}
Controlla il sensore del colpo
Se la variabile locked è vera, ed è attivo il blocco, leggi l’intensità della vibrazione del piezo e memorizzala in knockVal.
if(locked == true){
knockVal = analogRead(piezo);
Conta solo i colpi validi
L’istruzione successiva verifica se hai meno di tre colpi validi e se ci sono vibrazioni sul sensore. Se questi sono entrambi veri, controlla per vedere se il colpo corrente è valido o no e incrementa la variabile numberOfKnocks. Qui chiami la funzione checkForKnocks(). Scriverai la funzione una volta che hai finito il loop(), ma sai già che stai per chiedere se si tratta di un colpo valido perciò passa knockVal come parametro. Dopo aver verificato il risultato della funzione, stampa il numero di colpi di cui hai ancora bisogno.
if(numberOfKnocks < 3 && knockVal > 0){
if(checkForKnock(knockVal) == true){
numberOfKnocks++;
}
Serial.print(3-numberOfKnocks);
Serial.println("more knocks to go");
}
Sblocco (verifica finale)
Controlla se hai tre o più colpi validi. In questo caso, cambia la variabile locked su falso e sposta il servo nella posizione di sblocco. Attendi pochi millesimi di secondi per dargli tempo di muoversi e modifica lo stato dei LED verde e rosso. Stampa un messaggio di stato sul monitor seriale, indicando che la scatola è sbloccata.
if(numberOfKnocks >= 3){
locked = false;
myServo.write(0);
delay(20);
digitalWrite(greenLed,HIGH);
digitalWrite(redLed,LOW);
Serial.println("The box is unlocked!");
}
}
}
Definisci una funzione per verificare la validità dei colpi
È ora di scrivere la funzione checkForKnock(). Quando la stai scrivendo, hai bisogno di indicare se restituirà un valore o no. Se non hai intenzione di restituire un valore, lo dichiari come tipo void, simile alle funzioni loop() e setup(). Se vuoi restituire un valore, è necessario dichiarare quale tipo avrà (int, long, float, etc.). In questo caso, verifica se il colpo è valido (vero) o no (falso). Dichiara la funzione come tipo boolean.
boolean checkForKnock(int value){
Controlla la validità dei colpi
Questa particolare funzione verificherà un numero (la tua variabile knockVal) per vedere se è valido o no. Per passare questa variabile alla funzione, crea un parametro quando dichiari la funzione.
Nella funzione, ogni volta che ti riferisci a value conterrà il numero ricevuto come argomento dal programma principale.
A questo punto value è impostato al valore della variabile knockVal. Controlla se value è maggiore del colpo debole e inferiore del colpo forte.
if(value > quietKnock && value < loudKnock){
Indica se il colpo è valido
Se il valore è tra questi due, è un bussare valido. Fai lampeggiare una volta il LED giallo e stampa il valore del colpo sul monitor seriale.
digitalWrite(yellowLed, HIGH);
delay(50);
digitalWrite(yellowLed, LOW);
Serial.print("Valid knock of value ");
Serial.println(value);
La funzione restituisce true o false
Per informare il programma principale dell’esito del confronto, utilizza il comando return, che termina anche la funzione: una volta eseguito, si ritorna al programma principale.
Se value è fuori dall’intervallo previsto, stampa il valore sul monitor seriale e la funzione restituisce false.
return true;
}
else {
Serial.print("Bad knock value ");
Serial.println(value);
return false;
}
}
USALO
Quando colleghi il circuito ad Arduino, apri il monitor seriale. Dovresti vedere accendersi il LED verde e il servo si sposta nella posizione di sblocco.
Il monitor seriale dovrebbe stampare «The box is unlocked!». Probabilmente senti che il piezo fa un piccolo clic quando viene alimentato.
Prova a bussare delicatamente e forte per vedere quale intensità del colpo attiva la funzione. Saprai che sta funzionando quando il LED giallo lampeggia e il monitor seriale ti dice che hai ricevuto un colpo valido e il suo valore. Ti permette anche di sapere il numero di colpi che mancano per sbloccare la scatola.
Una volta raggiunto il giusto numero di colpi, la luce rossa si spegne, la luce verde si accende, il servo si sposta di 90 gradi e il monitor seriale ti informa che il blocco è disinnestato.

I valori per il colpo ideale possono variare da quelli dell’esempio. Questo dipende da un certo numero di variabili, come il tipo di superficie su cui è fissato il sensore e come è fissato. Utilizzando il monitor seriale e l’esempio
AnalogInSerialOutnell’IDE di Arduino, trovi un valore del colpo adatto alla tua configurazione. Qui trovi una spiegazione dettagliata di questo esempio: arduino.cc/analogtoserialSe inserisci il progetto in una scatola, è necessario fare i fori per i LED e l’interruttore. Avrai anche bisogno di fare un fermo in cui inserire il servomotore. È utile avere un foro per farci passare il cavo USB per scoprire il grado di sensibilità ai colpi del nuovo ambiente. Potresti aver bisogno di riorganizzare la breadboard e Arduino o saldare i LED e l’interruttore per renderli accessibili dall’esterno del contenitore. La saldatura è un processo di unione di due o più componenti metallici con una lega che viene fusa sulla giunzione. Se non hai mai saldato prima, chiedi a qualcuno che ha esperienza di aiutarti o fai un po” di pratica sul filo di scarto prima di tentare con i componenti di questo progetto. La saldatura è una connessione permanente, quindi assicurati di poter hackerare ciò che stai usando. Guarda arduino.cc/soldering per una buona spiegazione di come saldare.


1. Taglia 2 fori nella scatola: uno su un lato e uno sul coperchio. Posiziona il servo nella scatola in modo che il braccio possa muoversi dentro e fuori i fori quando la scatola è chiusa.
2. Fissa il servo in una posizione con del nastro adesivo in modo che il braccio possa ruotare facilmente attraverso la fessura che hai fatto.

Scrivere le proprie funzioni non solo permette di controllare il flusso del codice più facilmente, ma aiuta anche a mantenerlo leggibile quando i progetti diventano sempre più grandi. Nel corso del tempo, più codice scrivi e più troverai funzioni che è possibile riutilizzare in diversi progetti, rendendo il processo più veloce e vicino al tuo stile di programmazione.

Questo esempio conta semplicemente il giusto numero di colpi, non importa quanto tempo è necessario. Si può fare un progetto più complesso creando un timer con la funzione
millis(). Usa il timer per identificare se il colpo accade in un determinato periodo di tempo. Guarda di nuovo il progetto della clessidra digitale per un esempio di come funziona un timer. Non sei limitato a trovare i colpi in un intervallo specifico. Puoi rilevare schemi complessi di colpi in base alla quantità di vibrazioni e di tempo. C’è una serie di esempi online su come effettuare questa operazione, cerca «Arduino knock lock» per scoprirli.
Gli elementi piezo possono essere utilizzati come ingressi quando sono collegati come divisori di tensione con una resistenza di valore elevato. Progettare una funzione è un modo semplice per scrivere codice che può essere riutilizzato per compiti specifici.
CODICE COMPLETO
/*
Arduino Starter Kit example
Project 12 - Knock Lock
This sketch is written to accompany Project 12 in the Arduino Starter Kit
Parts required:
- 1 megohm resistor
- 10 kilohm resistor
- three 220 ohm resistors
- piezo
- servo motor
- push button
- one red LED
- one yellow LED
- one green LED
- 100 uF capacitor
created 18 Sep 2012
by Scott Fitzgerald
Thanks to Federico Vanzati for improvements
https://store.arduino.cc/genuino-starter-kit
This example code is part of the public domain.
*/
// import the library
#include <Servo.h>
// create an instance of the Servo library
Servo myServo;
const int piezo = A0; // pin the piezo is attached to
const int switchPin = 2; // pin the switch is attached to
const int yellowLed = 3; // pin the yellow LED is attached to
const int greenLed = 4; // pin the green LED is attached to
const int redLed = 5; // pin the red LED is attached to
// variable for the piezo value
int knockVal;
// variable for the switch value
int switchVal;
// variables for the high and low limits of the knock value
const int quietKnock = 10;
const int loudKnock = 100;
// variable to indicate if locked or not
bool locked = false;
// how many valid knocks you've received
int numberOfKnocks = 0;
void setup() {
// attach the servo to pin 9
myServo.attach(9);
// make the LED pins outputs
pinMode(yellowLed, OUTPUT);
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
// set the switch pin as an input
pinMode(switchPin, INPUT);
// start serial communication for debugging
Serial.begin(9600);
// turn the green LED on
digitalWrite(greenLed, HIGH);
// move the servo to the unlocked position
myServo.write(0);
// print status to the Serial Monitor
Serial.println("the box is unlocked!");
}
void loop() {
// if the box is unlocked
if (locked == false) {
// read the value of the switch pin
switchVal = digitalRead(switchPin);
// if the button is pressed, lock the box
if (switchVal == HIGH) {
// set the locked variable to "true"
locked = true;
// change the status LEDs
digitalWrite(greenLed, LOW);
digitalWrite(redLed, HIGH);
// move the servo to the locked position
myServo.write(90);
// print out status
Serial.println("the box is locked!");
// wait for the servo to move into position
delay(1000);
}
}
// if the box is locked
if (locked == true) {
// check the value of the piezo
knockVal = analogRead(piezo);
// if there are not enough valid knocks
if (numberOfKnocks < 3 && knockVal > 0) {
// check to see if the knock is in range
if (checkForKnock(knockVal) == true) {
// increment the number of valid knocks
numberOfKnocks++;
}
// print status of knocks
Serial.print(3 - numberOfKnocks);
Serial.println(" more knocks to go");
}
// if there are three knocks
if (numberOfKnocks >= 3) {
// unlock the box
locked = false;
// move the servo to the unlocked position
myServo.write(0);
// wait for it to move
delay(20);
// change status LEDs
digitalWrite(greenLed, HIGH);
digitalWrite(redLed, LOW);
Serial.println("the box is unlocked!");
numberOfKnocks = 0;
}
}
}
// this function checks to see if a detected knock is within max and min range
bool checkForKnock(int value) {
// if the value of the knock is greater than the minimum, and larger
// than the maximum
if (value > quietKnock && value < loudKnock) {
// turn the status LED on
digitalWrite(yellowLed, HIGH);
delay(50);
digitalWrite(yellowLed, LOW);
// print out the status
Serial.print("Valid knock of value ");
Serial.println(value);
// return true
return true;
}
// if the knock is not within range
else {
// print status
Serial.print("Bad knock value ");
Serial.println(value);
// return false
return false;
}
}