il progetto consiste nell'automazione di un tavolino basso da caffè che cela una tv/monitor all'interno, schermo che va tirato fuori all'occorrenza (configurazioni varie di sistemi audio/video in un sala homecinema).
per capire lo sketch e per chiedervi come migliorarlo aggiungo delle foto che spero chiariscano il funzionamento
il prototipo (tralasciamo l'estetica )
il piano viene mosso da un sistema di pulegge e cinghie, la trazione viene data da un motore passo passo:
la tv viene sollevata con un secondo motore (motore tipo tapparella) che funziona a 220v quindi viene azionato da 2 relè (uno per sollevamento, uno per abbassamento).
ecco cosa sto utilizzando per far funzionare il tutto:
arduino UNO R3
pololu A4988 (per controllare il motore passo passo)
scheda 2 relè 5v
un pò di finecorsa che servono ad identificare i vari stati del sistema
const int stp = 3; //pin 3 a step del driver a4988
const int dir = 2; //pin 2 a direction del driver a4988
const int relepin1 = 8; // pin 8 al relè N.1 (orario)
const int relepin2 = 9; // pin 9 al relè N.2 (antiorario)
//const int ms1 = 4; //microstep 1/8
//const int ms2 = 5; //microstep 1/16
const int pinbuttonstart = 11; //tasto avvio tavolino
const int pinfinecorsapianoaperto = 10;
const int pintvsollevata = 12;
const int pinpianocontrotv = 13;
const int pintvariposo = 7;
const int pinpianochiuso = 6;
//////////////////////////////////////////////////////////////
int valbuttonstart = 0; //conservo lo stato del pinbuttonstart
int vecchiovalbuttonstart = 0; //mi servirà per verificare lo stato precedente del pin buttonstart
int countbuttonstart = 0; //contatore buttonstart
///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
int valfinecorsapianoaperto = 0; //conservo lo stato del pinfinecorsapianoaperto
int vecchiovalfinecorsapianoaperto = 0;
////////////////////////////////////////////////////////////////
int valtvariposo = 0;
int vecchiovaltvariposo = 0;
////////////////////////////////////////////////////////////////
int valtvsollevata = 0;
int vecchiovaltvsollevata = 0;
////////////////////////////////////////////////////////////////
int valpianocontrotv = 0;
int vecchiovalpianocontrotv = 0;
////////////////////////////////////////////////////////////////
int valpianochiuso = 0;
int vecchiovalpianochiuso = 0;
////////////////////////////////////////////////////////////////
// Funzioni //
void orario() {
digitalWrite (dir, LOW); //accende il motore (orario) quindi apre il piano
digitalWrite (stp, HIGH);
delay(10); //definisce la velocità
digitalWrite (stp, LOW);
delay(10);
}
void antiorario() {
digitalWrite (dir, HIGH); //accende il motore (antiorario) quindi chiude il piano
digitalWrite (stp, HIGH);
delay(10); //definisce la velocità
digitalWrite (stp, LOW);
delay(10);
}
void bloccomotore() {
digitalWrite (stp, HIGH); //si arresta il motore
}
void up() {
digitalWrite (relepin1, LOW); //attivo il rele' 1
}
void stopup() {
digitalWrite (relepin1, HIGH); //disattivo il rele' 1
}
void down() {
digitalWrite (relepin2, LOW); //attivo il rele' 2
}
void stopdown() {
digitalWrite (relepin2, HIGH); //disattivo il rele' 2
}
//fine funzioni
void setup() {
Serial.begin(9600);
pinMode (stp, OUTPUT);
pinMode (dir, OUTPUT);
pinMode (relepin1, OUTPUT);
pinMode (relepin2, OUTPUT);
pinMode (pinbuttonstart, INPUT);
pinMode (pinfinecorsapianoaperto, INPUT);
pinMode (pintvsollevata, INPUT);
pinMode (pinpianocontrotv, INPUT);
pinMode (pintvariposo,INPUT);
pinMode (pinpianochiuso, INPUT);
digitalWrite (relepin1, HIGH);
digitalWrite (relepin2, HIGH);
}
void loop() {
///////////////////////////////////////////////////////////////////////////////////
valbuttonstart = digitalRead(pinbuttonstart);
if (valbuttonstart != vecchiovalbuttonstart); { //controllo se il bottone ha cambiato stato
if (valbuttonstart == HIGH) {
if (countbuttonstart<=2) countbuttonstart=countbuttonstart+1;
else countbuttonstart=0;
Serial.print("num di pressioni bottone start: ");
Serial.println(countbuttonstart, DEC);
}
vecchiovalbuttonstart = valbuttonstart;
}
///////////////////////////////////////////////////////////////////////////////////
valtvariposo = digitalRead(pintvariposo); //controllo finecorsa tv a riposo
if (valtvariposo != vecchiovaltvariposo) {
vecchiovaltvariposo = valtvariposo;
}
///////////////////////////////////////////////////////////////////////////////////
valfinecorsapianoaperto = digitalRead(pinfinecorsapianoaperto); //controllo finecorsa p.aperto
if (valfinecorsapianoaperto != vecchiovalfinecorsapianoaperto) {
vecchiovalfinecorsapianoaperto = valfinecorsapianoaperto;
}
///////////////////////////////////////////////////////////////////////////////////
valtvsollevata = digitalRead(pintvsollevata); //controllo finecorsa tv sollevata
if (valtvsollevata != vecchiovaltvsollevata) {
vecchiovaltvsollevata = valfinecorsapianoaperto;
}
///////////////////////////////////////////////////////////////////////////////////
valpianocontrotv = digitalRead(pinpianocontrotv); //controllo finecorsa piano contro tv
if (valpianocontrotv != vecchiovalpianocontrotv) {
vecchiovalpianocontrotv = valpianocontrotv;
}
///////////////////////////////////////////////////////////////////////////////////
valpianochiuso = digitalRead(pinpianochiuso); //controllo finecorsa piano chiuso
if (valpianochiuso != vecchiovalpianochiuso) {
vecchiovalpianochiuso = valpianochiuso;
}
///////////////////////////////////////////////////////////////////////////////////
switch (countbuttonstart) {
case 1:
if (valbuttonstart == 1 && valfinecorsapianoaperto == 0 && valpianocontrotv == 0) {
orario();
Serial.println("apro il piano");
}
if (valfinecorsapianoaperto == 1) {
bloccomotore();
Serial.println("blocco il piano in posizione 'aperto'");
up();
Serial.println("tiro su la tv");
}
if (valtvsollevata == 1 && valfinecorsapianoaperto == 1) {
stopup();
Serial.println("blocco la tv alzata");
antiorario();
Serial.println("riporto il pianetto in battuta alla tv");
}
if (valpianocontrotv == 1 && valtvsollevata == 1) {
bloccomotore();
Serial.println("blocco il piano, il tavolino è aperto");
}
break;
case 2:
if (valpianocontrotv == 1 && valtvsollevata == 1) {
orario();
Serial.println("apro il piano dalla posizione 'tavolino aperto'");
}
if (valfinecorsapianoaperto == 1) {
bloccomotore();
Serial.println("blocco il piano in posizione 'aperto'");
down();
Serial.println("tiro già la tv");
}
if (valtvariposo == 1) {
stopdown();
Serial.println("blocco la tv abbassata");
antiorario();
Serial.println("chiudo il piano");
}
if (valpianochiuso == 1) {
bloccomotore();
Serial.println("blocco il piano, il tavolino è chiuso");
}
break;
} //end switch
} //end loop
non ho ancora fatto il test sulla meccanica, ma pare funzionare tutto, per far funzionare il tutto con un solo pulsante ho messo nello sketch un contatore che conta fino a 2
la prima pressione corrisponde alla fase 1 e la seconda alla fase 2, dopo ogni fase mi servirebbe smettere di alimentare il driver del motore passo passo, che altrimenti continuerebbe (il motore) a produrre un fastidioso sibilo.. c'è un modo per mandare a nanna arduino fino alla successiva pressione del button start? questo dovrebbe far si che si interrompa la corrente dei 3.3v forniti da arduino al driver A4988..
... mi viene quasi da pensare che con un paio di camme e/o guide in una ruota azionatrice sarebbe possibile fare tutto con un solo motore ... pero' la parte meccanica si complicherebbe parecchio ...
In compenso, usando piu di due finecorsa, puoi rendere tutti i movimenti piu fluidi, ad esempio iniziare il sollevamento dello schermo quando il piano ha oltrepassato un punto minimo, mentre ancora si muove, e lo stesso per la chiusura, senza dover aspettare il termine di un'operazione prima di iniziare la successiva, ma queste sono "rifiniture" che non sono certo indispensabili ...
Quello che invece potrebbe aiutare parecchio e' usare delle lunghe molle (oppure mollettoni e cordini d'acciaio su pulegge, oppure anche molle "in torsione" intorno ad un'albero rotante) come "contrappeso", per ridurre il carico del motore durante l'innalzamento dello schermo ad esempio ...
non sono capace di sviluppare meccaniche complicate, non è il mio lavoro eh per quanto riguarda i movimenti "intermedi" posso anche pensarlo ma in realtà potrei risparmiare pochi centimetri di corsa visto che il monitor è un 28"...
@Brunello
in effetti posso provare così, se invece volessi parlare di risparmio energetico potrei addormentare tutto il sistema agendo su arduino?
no, non posso perchè l'asse del motore è da 6.35mm e la puleggia ha il foro da 8mm, quindi il giunto mi serve per raccordare i 2 diametri..
Il giunto é elastico. Visto che non hai cuscinetti sulla puleggia Devi mettere qualcosa di rigido. Devi farti con un tornio una bussola interno 6,15 esterno 8.
O quello, oppure prolunga l'asse della puleggia e metti un secondo punto di appoggio dall'altro lato (staffetta), perche' altrimenti se forza troppo, il giunto che e' flessibile potrebbe piegarsi lateralmente e farti "saltare" la cinghia, o magari rovinarsi meccanicamente ...
Il massimo della sicurezza sarebbero due staffette una prima ed una dopo la puleggia, ma magari ti complicano troppo la vita ...
bravo etemenanki stavo per scrivere appunto questo, è previsto nel modello definitivo un altro punto di appoggio sul lato opposto del motore con annesso cuscinetto! sul prototipo non mi sono impegnato troppo visto che sul modello definitivo avrò una struttura leggermente diversa
comunque il mio problema rimane sempre quello, come posso spegnere arduino e tutto quello che vi è connesso alla fine di ogni fase e riprendere lo sketch alla successiva pressione del button start?
Spegnere Arduino non ha molto senso, perche' non e' un problema di ridurre i consumi ... se il problema e' il rumore prodotto dall'insieme driver/motore, spegni il driver (con il pin enable, come suggerito da Brunello), ma assicurandoti prima che, meccanicamente, il sistema sia stabile in entrambe le posizioni, aperta e chiusa, perche' se disabiliti il driver, il motore non offre piu molta resistenza a livello meccanico, e se qualcuno spinge lo schermo o il piano, potrebbe muoverli ...
e comunque, visto che codesto Stepper lo usi come un normale DC ( vedo che il motore lo fai girare fino al finecorsa ) , forse e' più adatto il secondo,
Un modello completo di riduttore, ti da' più coppia, lo gestisci meglio e anche se lo spegni, il motoriduttore fa si' che rimanga in posizione.
unico problema del motore DC è che non posso regolare la velocità (per quanto ne sappia), significherebbe anche spendere altri soldi
in più col motore passo passo pensavo di realizzare una decelerazione in prossimità dei finecorsa, cosa che non credo sia possibile con i motori DC a meno che non si controllino in corrente e quindi oltre alla velocità si diminuisce la coppia.. sbaglio?
altra cosa che mi hai fatto notare Brunello, è che potrei limitare il numero di passi dello stepper così da utilizzare i finecorsa solo per identificare le posizioni dei vari elementi del magic table.. in tal caso se si rompesse un finecorsa il motore si fermerebbe comunque..
unico problema del motore DC è che non posso regolare la velocità (per quanto ne sappia), significherebbe anche spendere altri soldi :
Informazione errata. Un motore DC si regola tranquillamente in velocità, usando un PWM.
Prendiamo come esempio Questo driver.
Usi solo due pin, uno per il verso di rotazione e l'altro pilotato in PWM per la velocità.
Più è alto il valore di PWM ( da 0 a 255 ) più va' veloce.
E in questo modo puoi gestire anche accelerazioni e decelerazioni, anche se dovresti avere un motore dotato di Encoder, per sapere in che posizione ti trovi.
Invece con uno Stepper puoi teoricamente contare i passi eseguiti , pero' se per qualche motivo perde degli Step il conto va a farsi benedire
Per il discorso di spendere altri soldi... un motore DC costa pure di meno
grazie per le info! per adesso continuo il progetto con lo stepper, un motore DC con motoriduttore che abbia una coppia di almeno 1Nm non costa pochissimo, credo.
Per quanto riguarda il bloccaggio del piano attualmente potrei ingegnare degli incastri non troppo tenaci, così da preservare la posizione del piano da eventuali botte..
vediamo un pò!
per quanto riguarda il pin ENABLE, il modulo dovrebbe spegnersi nel momento in cui lo setto a 0 giusto?