12 Numerazione capitolo

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

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.

Schema del circuito e montaggio

  1. 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.

  2. 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.

  3. 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.

  4. 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.

Schema elettrico

COnnettori
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.

FOrbici e colla

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 AnalogInSerialOut nell’IDE di Arduino, trovi un valore del colpo adatto alla tua configurazione. Qui trovi una spiegazione dettagliata di questo esempio: arduino.cc/analogtoserial

Se 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.

Istruzioni per l'installazione nella scatola 1

Istruzioni per l'installazione nella scatola 2

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.

Lente

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.

Cervello

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;
  }
}