dopo un periodo di inattività sul forum a causa di mille impegni, sono pronto per realizzare il mio nuovo progetto.
Come da titolo, ho intenzione di automatizzare l'accensione e lo spegnimento delle luci (fari e modalità notte del quadro strumenti).
Per fare questo, manualmente, bisogna chiaramente intervenire sulla rotella del quadro luci, spostando la selezione da "spento" ad "acceso" (o "posizione").
Il mio intervento viene applicato in questa operazione: la rotella viene sempre lasciata su "acceso", dopodiché, sarà un modulo aggiuntivo a decidere se, quando e come accendere/spegnere le luci.
Per fare ciò mi sono affidato ad Arduino; i più smanettoni già sanno di cosa sto parlando, per tutti gli altri, fatevi un giro su Google.
Il concetto è semplice:
- 1) Il modulo viene alimentato dalla 12v della macchina (io ho preso corrente dall'accendisigari)
- 2) Una fotoresistenza verifica la luminosità dell'ambiente
- 3) Se la luminosità ambientale è bassa e le luci sono spente, queste vengono accese
- 4) Se la luminosità ambientale è alta e le luci sono accese, queste vengono spente
Ora, ogni minima variazione di luminosità comporterebbe un'infinita variazione dello stato delle luci, facendole accendere e spegnere ripetutamente.
Per ovviare al problema, ho programmato diversi controlli che permettono al modulo di essere indipendente (ed intelligente ).
Il codice sorgente del modulo è il seguente (ho commentato il più possibile per far capire i vari concetti):
- Codice: Seleziona tutto
int relePin = 7; // DICHIARO IL PIN DEL RELE'
int photoresPin = A5; // DICHIARO IL PIN DELLA FOTORESISTENZA
int lightValue = 0; // DICHIARO IL VALORE DELLA FOTORESISTENZA
int lastLightValue = 0; // DICHIARO IL VALORE DELL'ULTIMA RILEVAZIONE DELLA FOTORESISTENZA
int off2on = 450; // DICHIARO VALORE DI ACCENSIONE (ACCENDO DA 0 A 450)
int on2off = 550; // DICHIARO VALORE DI SPEGNIMENTO (SE ACCESO, SPENGO DA 550 IN SU)
int forceOff = 700; // DICHIARO IL VALORE DI FORZATURA DELLO SPEGNIMENTO
int timer = 0; // DICHIARO IL TIMER
int timerStep = 100; // DICHIARO IL VALORE DI INCREMENTO DEL TIMER IN MILLISECONDI
int loopDelay = 100; // DICHIARO IL TEMPO DI ATTESA TRA UN CICLO E L'ALTRO IN MILLISECONDI
int timeToTurn = timerStep * loopDelay; // DICHIARO IL TEMPO NECESSARIO PER ESEGUIRE IL COMANDO IN MILLISECONDI
int lastLightTimer = 0; // DICHIARO IL TIMER PER IL SALVATAGGIO DELL'ULTIMA RILEVAZIONE
int timeToLastLight = 1000; // DICHIARO IL TEMPO DI ATTESA TRA UN SALVATAGGIO E L'ALTRO DELL'ULTIMA RILEVAZIONE IN MILLISECONDI
boolean debug = false; // DICHIARO SE ESEGUIRE IL DEBUG
boolean lowDebug = false; // DICHIARO SE ESEGUIRE IL DEBUG COMPLETO
boolean lightsOn = false; // DICHIARO LO STATO DELLE LUCI (SPENTE)
boolean firstRun = true; // DICHIARO IL PRIMO AVVIO
void setup() {
if(debug){
Serial.begin(9600);
if(lightsOn)
turn(true); // ACCENDO LUCI
else
Serial.println("LUCI SPENTE");
}
pinMode(relePin, OUTPUT);
pinMode(photoresPin, INPUT);
}
/*
* -- GENERALE --
* LA RILEVAZIONE DELLA LUMINOSITA' VIENE EFFETTUATA OGNI SECONDO.
* SE LE LUCI SONO SPENTE E C'E' POCA LUMINOSITA', LE LUCI VENGONO ACCESE; SE LE LUCI SONO ACCESE E C'E' MOLTA LUMINOSITA', LE LUCI VENGONO SPENTE.
*
* -- TIMER E TIMETOTURN --
* IL RITARDO DI 10 SECONDI PER ESEGUIRE L'AZIONE, E' UTILE NELL'EVITARE CONTINUI CAMBI DI STATO CAUSATI DA VELOCI CAMBI DI LUMINOSITA', COME AD ESEMPIO LE OMBRE DI ALBERI.
* PER ESEGUIRE L'AZIONE DESIDERATA, LA CONDIZIONE SI DEVE VERIFICARE PER ALMENO 10 SECONDI, COSI' DA DECRETARNE UNO STATO PERMANENTE.
*
* -- LIGHTVALUE E LASTLIGHTVALUE --
* MEMORIZZARE L'ULTIMA RILEVAZIONE E CONFRONTARLA CON QUELLA ATTUALE E' UTILE PER VERIFICARE UN CAMBIO DI LUMINOSITA' ESPONENZIALE, COME AD ESEMPIO L'ENTRATA E L'USCITA IN GALLERIA.
* SE LA DIFFERENZA TRA LE DUE CONDIZIONI E' NOTEVOLE, SI PUO' CONSIDERARE NECESSARIO UN CAMBIO DI STATO.
*
* -- NOTE --
* LA DIFFERENZA POTREBBE ESSER CALCOLATA TRAMITE UNA PERCENTUALE RELATIVA ALL'ULTIMA RILEVAZIONE, PIUTTOSTO CHE ALLA SUA META'.
*/
void loop() {
lightValue = analogRead(photoresPin); // CONTROLLO IL VALORE DELLA FOTORESISTENZA
if(!lightsOn && lightValue <= off2on){ // SE LE LUCI SONO SPENTE E LA LUCE AMBIENTE E' INFERIORE O UGUALE AL VALORE DI ACCENSIONE
if(timer < timeToTurn && !firstRun && lightValue > lastLightValue / 2) // SE IL TIMER E' INFERIORE AL TEMPO NECESSARIO PER ESEGUIRE IL COMANDO, NON E' IL PRIMO AVVIO E LA LUCE AMBIENTE E' MAGGIORE DELLA META' DELL'ULTIMA RILEVAZIONE
timer += timerStep; // INCREMENTO IL TIMER
else // SE IL TIMER E' MAGGIORE AL TEMPO NECESSARIO PER ESEGUIRE IL COMANDO, SE E' IL PRIMO AVVIO O SE LA LUCE AMBIENTE E' MINORE DELLA META' DELL'ULTIMA RILEVAZIONE
turn(true); // ACCENDO LUCI
}
else if(lightsOn && lightValue > on2off){ // SE LE LUCI SONO ACCESE E LA LUCE AMBIENTE E' MAGGIORE AL VALORE DI SPEGNIMENTO
if(timer < timeToTurn && !firstRun && lightValue < forceOff) // SE IL TIMER E' INFERIORE AL TEMPO NECESSARIO PER ESEGUIRE IL COMANDO, NON E' IL PRIMO AVVIO E LA LUCE AMBIENTE E' MINORE DEL VALORE DI SPEGNIMENTO FORZATO
timer += timerStep; // INCREMENTO IL TIMER
else // SE IL TIMER E' MAGGIORE AL TEMPO NECESSARIO PER ESEGUIRE IL COMANDO, SE E' IL PRIMO AVVIO O SE LA LUCE AMBIENTE E' MAGGIORE DEL VALORE DI SPEGNIMENTO FORZATO
turn(false); // SPENGO LUCI
}
if((timer > 0 && lightsOn && lightValue < on2off) || (timer > 0 && !lightsOn && lightValue > off2on)) // SE IL TIMER E' MAGGIORE DI 0 MA NON VI SONO LE CONDIZIONI PER VARIARE LO STATO DELLE LUCI
timer = 0; // RESETTO IL TIMER
if(firstRun) // SE E' IL PRIMO AVVIO
firstRun = false; // DISABILITO TALE CONDIZIONE
if(lastLightTimer < timeToLastLight) // SE IL TIMER E' INFERIORE AL TEMPO NECESSARIO PER SALVARE L'ULTIMA RILEVAZIONE
lastLightTimer += timerStep; // INCREMENTO IL TIMER
else{ // SE IL TIMER E' MAGGIORE AL TEMPO NECESSARIO PER SALVARE L'ULTIMA RILEVAZIONE
lastLightValue = lightValue; // IMPOSTO IL VALORE DELL'ULTIMA RILEVAZIONE DELLA FOTORESISTENZA
lastLightTimer = 0; // RESETTO IL TIMER
}
if(debug && lowDebug){
Serial.println(lightValue);
Serial.println(timer);
}
delay(loopDelay);
}
void turn(boolean state){
if(state){ // SE DEVO ACCENDERE LE LUCI
lightsOn = true; // IMPOSTO LO STATO DELLE LUCI COME ACCESO
digitalWrite(relePin, HIGH); // ACCENDO LE LUCI
if(debug)
Serial.println("ACCENDO LUCI");
}
else if(!state){ // SE DEVO SPEGNERE LE LUCI
lightsOn = false; // IMPOSTO LO STATO DELLE LUCI COME SPENTO
digitalWrite(relePin, LOW); // SPENGO LE LUCI
if(debug)
Serial.println("SPENGO LUCI");
}
timer = 0; // RESETTO IL TIMER DOPO LA VARIAZIONE DELLO STATO DELLE LUCI
}
Ovviamente, tutto questo può capirlo chi ha delle basi di elettronica e programmazione; per tutti gli altri, prendetelo come dato di fatto.
Questo fine settimana salderò il circuito per creare il modulo definitivo, specificando meglio i componenti utilizzati per la realizzazione; ora è tutto su breadboard e funziona perfettamente, sono pronto quindi alla saldatura.
Continuerò ad aggiornare il post con tutte le novità; se qualcuno ha qualche suggerimento per migliorare l'argomento di cui all'oggetto, scriva tutto ciò che pensa, sarò felice di discutere ogni eventuale dubbio.
Al prossimo aggiornamento.