Progetto azionamento servo ad ogni impulso

Buongiorno ragazzi, causa probabilmente la mia poca esperienza ho realizzato questo banale sketch nel quale vorrei fare assumere al servo la posizione 90° (a partire dalla posizione 0°) e farlo tornare a 0° nel minore tempo possibile e, senza utilizzare la funzione delay, nel momento in cui premo il pulsante.
Ho solo un problema: non riesco a far compiere al servo il ciclo 0°(posizione partenza)->90°(posizione intermedia)->0°(posizione finale) nel momento in cui premo il pulsante anche solo per qualche ms.
Come mi consigliate di modificare lo sketch?

#include<Servo.h> //includo la libreria servo
Servo myservo; //definisco il servo
unsigned long previousMillis=0; //salvo l'ultimo instante che (pos) è stat modificata
unsigned long interval=145; //intervallo con il quale si vuole far variare (pos)
int pos=0; //pongo pos = 0;
int button=7; //definisco il pulsante sul pin 7 
int val=0; //pongo val = 0
void setup()
{myservo.attach(9); //definisco il pin al quale è attaccato il servo
pinMode(button,INPUT);} //definisco il pulsante come pin di IMPUT
void loop()
{readbutton ();
movetheservo ();}
//leggo il pusante (pin 7)
void readbutton()
{val=digitalRead(button);}
//muovo il servo a seconda della condizione del pin 7 
void movetheservo()
{if (val==1)
{if(millis()-previousMillis>interval)
{previousMillis=millis();
if(pos==0)
pos=90;
else
pos=0;
myservo.write(pos);}}}

Ciao! Il codice va inserito nei tag code il pulsante “</>” dell’editor! Quindi modifica il tuo post e inserisci il codice nei tag code.

Il programma come si comporta in questo momento, cosa fa il servo? Tieni presente che il servo ha la sua
velocità di movimento, quindi non puoi passare da una posizione all’altra col tempo che vuoi tu.

Come programma avrei da ridire, sopratutto le tue funzioni per leggere il pulsante e per eseguire la posizione del servo, le funzioni servono per suddividere un programma in sottoprogrammi più semplici
“quindi per risolvere di volta in volta problemi più piccoli invece di un unico grande problema”. Ma le tue funzioni sono fatte di una sola riga o poche righe, per cui non è necessario creare delle funzioni, la funzione per leggere il pulsante in pratica crei una funzione per richiamarne un altra, non ha senso.

Ciao, hai ragione, ho modificato il post inserendo il codice nel tag code.
Probabilmente si, ci sarà molto da ridire sul programma, purtroppo l’esperienza per dei programmi così articolati ancora devo farmela; ora il servo se tengo premuto il pulsante entra nel suo loop e effettua un 90->0 di continuo.
Sono partito da uno sketch molto semplice per dei servi che ho modificato togliendo e sostituendo delay con millis al quale ho poi “attaccato” nel vero senso della parola la lettura del pulsante per eseguire il loop.

#include<Servo.h>
Servo myservo;
unsigned long previousMillis=0; 
unsigned long interval=145;
int pos=0;
void setup()
{myservo.attach(9);}
void loop()
{if(millis()-previousMillis>interval)
{previousMillis=millis();
if(pos==0)
pos=90;
else
pos=0;
myservo.write(pos);}}/code]

Domanda, perché non vuoi usare un delay(145)? è un intervallo cosi piccolo che se anche dovresti fare altre cose nel programma non dovrebbe crearti problemi.

Quindi adesso va come vorresti? E se no come vorresti che vada?

Provato anche con delay, il risultato non cambia perché purtroppo il programma scritto in quel modo fa uno spostamento da 0 a 90 con una sola pressione del pulsante, se il pulsante viene premuto il ciclo va in loop e il servo fa 0->90->0->90,…finchè non mollo il pulsante. Che sia il caso di mettere un contatore?
Il primo sketch l’ho riscritto sistemandolo un po’.

 #include<Servo.h>
Servo myservo;
unsigned long previousMillis=0; 
unsigned long interval=145; 
int pos=0; 
int button=7;  
void setup()
{myservo.attach(9);
myservo.write(0); 
pinMode(button,INPUT);}
void loop()
{if(digitalRead(button)==HIGH)
if(millis()-previousMillis>interval)
{previousMillis=millis();
if(pos==0)
pos=90;
else
pos=0;
myservo.write(pos);}}/code]

Perdono se sono ignorante ma non capisco ancora che cosa fa il programma e che cosa vuoi che faccia. Potresti per favore comunicare almeno la seconda cosicché si possa correggere il codice che tu attualmente stai utilizzando, oppure scriverne uno nuovo, a seconda delle necessità, che consenta ad Arduino di fare quanto desideri.
in breve che cosa vuoi ottenere?
la risposta a tale domanda sarebbe utile maggiormente se fornita in lingua italiana e non in codice Arduino senza parlare di quanto il codice attuale stia facendo. Questo perché come legge dalla seconda frase per programmare Bisogna saper descrivere e io quello che vuoi fare non lo ho ancora compreso appieno.
Chiedo perdono se sono parso arrabbiato o se ho offeso in qualche modo non era mia intenzione.

Nessuno problema, non serve che ti scusi, ho capito cosa vuoi dire.
In pratica immagina di vedere uno sportello in un condotto comandato da un servo; lo sportello quando il servo è su 0 gradi risulta chiuso, quando è aperto è perché il servo è a 90 gradi.
Nel momento in cui premo il pulsante, vorrei che lo sportello si aprisse e chiudesse nel minor tempo possibile, senza che io debba tener premuto il pulsante per far compiere tutto il ciclo.
Ora invece, se premo il pulsante per un istante, ottengo che lo sportello si apre, ma non si chiude, cosa che ottengo ciclicamente se tengo premuto il pulsante.

quindi il tuo programma deve fare:

loop
se pulsante premuto (eventuale debounce pulsante)
comanda servo da 0 a 90
comanda servo da 90 a 0
fine se
fine loop

Esatto Patrick, vorrei che ad ogni pressione del pulsante corrisponda un ciclo del servo inteso come 0->90 90->0. Ora purtroppo il ciclo varia a seconda di quanto tengo premuto il pulsante...ho pensato anche io a un denounce, ma volevo implementarlo sistemato questo primo problema

il programma è molto semplice e ti basta scrivere 4 -5 righe :wink:
il problema è che il loop viene eseguito in qualche frazione di secondo e quindi se tieni pigiato il pulsante (senza nessun controllo) il ciclo viene ripetuto all'infinito. Detto questo o ci metti una pausa prima di ricominciare il loop (1 secondo dovrebbe essere sufficente), oppure introduci una variabile che controlli che quando l'azione è cominciata non deve più ripeterla fino a quando il pulsante non cambia stato. Per questo potresti dare un'occhiata proprio ai programmi di esempio relativi al debounce :wink:

Una roba tipo

if (digitalRead (pulsante))
{
servomwrite (90);
servo.write (0);
}

Meno di così non ci puoi mettere
Chiaramente con questo sistema non consideri se il pulsante è rimasto premuto forse è appena stato premuto ma consideri soltanto che attualmente sia premuto se ti servisse che il sistema ricordi se il pulsante è stato premuto e in tal caso attenda il rilascio senza agire ti sarà necessario usare una variabile di appoggio per ricordarti se ho già effettuato l'operazione.

non sono un professionista,ma posso intromettermi per buttare un'idea e vedere se ho capito?

if (digitalRead (pulsante==LOW) && (step==0))
{
servomwrite (90);
servo.write (0);
step=1;
}
if (digitalRead (pulsante==HIGH) && (step==1))
{
step=0;
}

acuplush:
posso intromettermi per buttare un'idea e vedere se ho capito?

Yes! Hai scritto una perfetta macchina a stati:

  • 'step' è la variabile di stato
  • le digitalRead sono gli eventi da "catturare"
  • le cose tra parentesi graffe sono le azioni da compiere al verificarsi degli eventi
    In questo modo puoi effettuare delle operazioni una singola volta al verificarsi di un evento.

L'unica cosa che manca è una pausa tra le due servo.write per dare il tempo al servo di muoversi, e una pausa di debounce al rilascio del pulsante. In questo caso specifico vanno bene anche delle semplici delay.

Silente:
Una roba tipo

if (digitalRead (pulsante))

{
servomwrite (90);
servo.write (0);
}



Meno di così non ci puoi mettere
Chiaramente con questo sistema non consideri se il pulsante è rimasto premuto forse è appena stato premuto ma consideri soltanto che attualmente sia premuto se ti servisse che il sistema ricordi se il pulsante è stato premuto e in tal caso attenda il rilascio senza agire ti sarà necessario usare una variabile di appoggio per ricordarti se ho già effettuato l'operazione.

Grazie Silente, purtroppo già provato così, ma giustamente causa "lentezza" del servo senza un delay o una funzione millis, il servo si sposta di qualche grado "tremando"

if (digitalRead (pulsante==LOW) && (step==0))

solo un appunto...

digitalRead (pulsante==LOW)

questo non funziona :slight_smile:

digitalRead (pulsante)==LOW

così va meglio :wink:

MartinoMsp:
Grazie Silente, purtroppo già provato così, ma giustamente causa “lentezza” del servo senza un delay o una funzione millis, il servo si sposta di qualche grado “tremando”

Perdono, ma non capisco quale sia il problema. Se serve mettere un delay()…metti un delay()<faccina_che_ride_e_che_non_so_come_si_mette/>
Credo sia chiaro dove va (indizio, appena sotto ogni servo.write())
Se il problema è che non sai di quanto serve la soluzione mi pare semplice: scoprilo mediante test.
Per facilitarti la vita ecco i passi che devi fare per creare un proto esempio di test a partire da quel programma.

1) creare una variabile globale (sopra la setup()) di tipo int che cominci da 0
2) inserire nella setup{} Serial.begin (9600); e seguire con quello che già fa.
3) modificare la loop() dallo stato attuale a:

servo.write(90);
servo.write (0);

4) inserire dopo ognuno dei servo.write una delay () con per parametro (tra le tonde) la variabile creata
5)variabilecreata+=10: (e va bene così)
6)Serial.println (variabilecreata);
7)inserire un delay decente (tipo 1 secondo o più)
8)compilare e caricare.
9)aprire il monitor seriale dell'ide (dovrebbe essere sotto il menù strumenti)

Il programma NON considera il pulsante, ma ogni “delay decente” tempo fa andare il motore a 90 e poi a 0, aspettando un tempo sempre crescente, ogni volta più grande di 10 millisecondi rispetto al precedente. Tale tempo viene mostrato u seriale.
Osservando il motore quando si ottiene un risultato desiderabile ci si annota l’ultimo numero uscito su seriale, che sarà la durata del delay da aggiungere al programma base

Ho già fatto diverse prove per capire fino a che valore minimo di ms posso spingermi in uno sketch abbastanza base, con la tipologia di servo che ho, considerando un alimentazione di 7,4v è di circa 22 ms.
Se non voglio utilizzare un delay è solamente una mia scelta, anche perché con la funzione millis e lo sketch allegato alla fine di questo messaggio ho “risolto” questo ostacolo, mi manca solo da implementare una funzione di debounce come parlava Patrick_M qualche post fa (per evitare il il ripetersi del ciclo ripetuto finchè il tasto è premuto) ma devo ragionarci un po’ su guardando l’esempio dell’IDE.Suggerimenti? :o
Per quanto riguarda lo sketch suggerito da acuplush e Claudio_FF devo provarlo a buttarlo giù appena ho un attimo, Grazie a entrambi! :slight_smile: :slight_smile:

#include<Servo.h>
Servo myservo;
unsigned long previousMillis=0; 
unsigned long interval=145; 
int pos=0; 
int button=7;  
void setup()
{myservo.attach(9);
myservo.write(0); 
pinMode(button,INPUT);}
void loop()
{if(digitalRead(button)==HIGH)
if(millis()-previousMillis>interval)
{previousMillis=millis();
if(pos==0)
pos=90;
else
pos=0;
myservo.write(pos);}}/code]

Forse "button" necessita di essere input_pullup se è un semplice contatto

Non credo sai, dovrei dichiararla input_pullup nel momento in cui non ci sia nessuna resistenza di pullup esterna e dovessi usare la resistenza interna di arduino. Ora sto usando una resistenza da 10k esterna :slight_smile: