venerdì 14 maggio 2010

Arduino: dove c'è più luce?


Il primo sketch con Arduino è servito a introdurne solo alcune delle caratteristiche. In questo secondo esempio realizzeremo l'interfacciamento con alcuni dispositivi: un sensore di luce o fotoresistenza e un servocomando. L'obiettivo è quello di farci suggerire da Arduino l'angolazione da cui proviene più luce.
Come avrete già capito il fotoresistore realizzerà per Arduino l'input, il servocomando sposterà invece il sensore facendolo ruotare di 180°. L'output viene realizzato comunicando l'angolo di massima luce rilevato attraverso la porta usb. Dopo la rotazione completa del sensore faremo inoltre puntare il servocomando (con il sensore) nell'angolo misurato.
Il fotoresistore è un componente elettronico la cui resistenza varia al variare della luce che lo colpisce. All'interno del programma faremo riferimento al sensore attraverso la costante SENSORE, che ne indica tra l'altro il pin usato nel collegamento con Arduino. Con la funzione analogRead(SENSORE) avviene la lettura del valore di tensione applicata ai morsetti del fotoresistore. Il valore ritornato è un numero compreso fra 0 e 1023, esso rappresenta intervalli di tensione compresi fra 0 e 5V. Possiamo rimediare la tensione da applicare al sensore direttamente da uno dei pin di Arduino. Se dunque la tensione ai morsetti del sensore è di 2,5V la funzione analogRead(SENSORE) ritornerà il valore 512. Nel circuito ho aggiunto un resistore di pochi ohm per cercare di correggere i valori tornati dal sensore (in maniera tale da farli ricadere in una fascia di valori più distante dall'ultimo valore leggibile).
La comunicazione fra Arduino e il PC avviene attraverso la porta usb. L'inizializzazione della porta seriale è stata già accennata in occasione del primo articolo con Arduino.
Il fotoresistore viene montato sull'albero del servocomando che ruotando sposta dunque il sensore. All'interno del programma faremo riferimento al servocomando attraverso la costante SERVO, passata in fase di setup alla funzione attach dell'oggetto Servo (per indicare su che pin è mappato il motore). Manovrare un servocomando con Arduino è semplice, ecco come fare:
  • dichiarare un oggetto Servo: Servo myservo;
  • mappare il servomotore in fase di setup con la funzione myservo.attach(int pin);
  • spostare il servomotore scrivendo con la funzione myservo.write(int angolo);
Altre funzioni per i servocomandi possono essere trovate a questo indirizzo. Ogni volta che spostiamo il servocomando, prima di impartire allo stesso una nuova posizione occorre dare al motore il tempo di raggiungere quella posizione. Ecco quindi l'importanza dell'istruzione delay(WAIT1)!
Con un ciclo for possiamo orientare il servocomando facendolo muovere di STEP (altra costante del programma) gradi per volta. Questi ultimi due parametri sono in qualche modo legati fra loro, il valore letto dal sensore è cioè influenzato dal precedente valore. In altre parole occorre dare al sensore il tempo di far assestare la lettura. Tuttavia se spostiamo il fotoresistore di pochi gradi per volta possono basatare pochi millisecondi. In tutti gli altri casi occorre introdurre un ritardo dopo ogni spostamento del servomotore.
Quest'ultima osservazione mi ha permesso di correggere un fastidioso difetto che ho riscontrato nel circuito poi provato. Dopo aver completato la scansione il servocomando si sposta nella posizione con più luce (ricordate la descrizione fatta all'inizio?) e vi rimane fino a una nuova scansione (che inizierà non appena termine una funzione di blinking per un led di stato). L'inizio di una nuova scansione provoca la rotazione del servomotore, quindi del sensore, dalla vecchia posizione (quella con più luce) a quella iniziale. Il valore immediatamente letto si porta allora dietro l'influenza dei valori che si alternano ai morsetti del sensore proprio durante questo spostamento. Ecco allora che l'aggiunta di una banale istruzione può correggere il comportamento falsato appena descritto. Se il sensore sta leggendo il valore della prima posizione (il servomotore è quindi a 0°) viene osservata una pausa di WAIT3 secondi (if (position==0) delay(WAIT3)). Questo farà assestare i valori prima di leggerli!
Niente di complicato nell'algoritmo che rileva l'angolo con più luce. Per ogni valore del ciclo for vengono memorizzati i valori letti dal sensore e la posizione del servomotore. Tali valori vengono quindi scartati solo se uno dei successivi valori di tensione, letti dal sensore, supera quello precedentemente memorizzato.

#include

#define SENSORE 0
#define SERVO 11
#define LED 13
#define WAIT1 40
#define WAIT2 1000
#define WAIT3 1000
#define STEP1 1

Servo myservo;
int max_light;
int max_light_position;
int current_light;
int position;

void setup() {
   Serial.begin(9600);
   myservo.attach(SERVO);
   pinMode(LED, OUTPUT);
}

void loop() {
   max_light=0;
   max_light_position=0;
   current_light=0;
   digitalWrite(LED, HIGH);
   for (position=0;position<180;position+=STEP1) {
      myservo.write(position);
      delay(WAIT1);
      if (position==0) delay(WAIT3);
      current_light=analogRead(SENSORE);
      Serial.println(current_light);
      if (current_light>max_light) {
         max_light=current_light;
         max_light_position=position;
      }
   }
   digitalWrite(LED, LOW);
   Serial.print("Massima luce rilevata a: ");
   Serial.print(max_light_position);
   Serial.print(" gradi.\n");
   myservo.write(max_light_position);
   blink(10);
}

void blink(int nBlink) {
   while (nBlink!=0) {
      digitalWrite(LED, HIGH);
      delay(WAIT2/2);
      digitalWrite(LED, LOW);
      delay(WAIT2/2);
      nBlink--;
   }
}


Nessun commento:

Posta un commento