Un esempio pratico: inseguitore di luce
Nell'articolo precedente abbiamo visto la funzione millis() ed il suo utilizzo.In questo post si vuole evidenziare con un esempio i passaggi da seguire per passare da uno sketch con il delay() ad uno con il millis().
Lo scenario
Per cercare di spiegare meglio il tutto partiamo con un esempio pratico.Si immagini di avere due sensori di luce a distanza di pochi centimetri e posizionati a 90 gradi.
In mezzo a loro due servo motori che ruotano rispetto ciascuno di essi a seconda che la luce sia puntata verso un sensore o verso l'altro.
Questo sistema simula, in piccolo, il funzionamento di un inseguitore solare di pannelli fotovoltaici...
Primo sketch con delay...
Il primo esperimento è stato effettuato con il metodo classico usando il delay().Prima di rappresentare il codice ricapitoliamo le esigenze:
- Leggere il sensore 1 e il sensore 2
- Muovere a seconda della luce i due motori in direzione della luce stessa
- Stampare a video le posizioni dei motori e l'intensità di luce rilevata
- I motore, per come è progettato, tra un comando e l'altro, desidera circa 15ms di ritardo
- Una persona, per leggere correttamente, deve avere un output circa ogni 500-1000ms
- Nell'articolo si da per scontato che il lettore conosca arduino, i fondamenti della sua programmazione e il collegamento di sensori analogici e componenti di base
#include
#define SENSORELUCE1 0
#define SENSORELUCE2 5int letturaluce1=0;
int letturaluce2=0;
Servo servo1; //crea l'oggetto per il controllo del primo servo
Servo servo2; //crea l'oggetto per il controllo del secondo servo
int posservo1; //immagazzina la posizione del primo servo
int posservo2; //immagazzina la posizione del secondo servo
void setup(){
pinMode (SENSORELUCE1, INPUT);
pinMode (SENSORELUCE2, INPUT);
servo1.attach(9); //attaches the first servo on pin 9 to the servo object
servo2.attach(10); //attaches the second servo on pin 10 to the servo object
Serial.begin(9600);
}
void loop(){
letturaluce1=analogRead(SENSORELUCE1);
posservo1= analogRead(letturaluce1); // reads the value of the light sensor 1 (value between 0 and 1023)
posservo1=map(posservo1,0,1023,0,179); // scale it to use it with the servo (value between 0 and 180)
servo1.write(posservo1); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
letturaluce2=analogRead(SENSORELUCE2);
posservo2= analogRead(letturaluce2); // reads the value of the light sensor 2 (value between 0 and 1023)
posservo2=map(posservo2,0,1023,0,179); // scale it to use it with the servo (value between 0 and 180)
servo2.write(posservo2); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
Serial.print("Sensore 1: ");
Serial.println(letturaluce1,DEC);
Serial.print("Posizione motore 1: ");
Serial.println(posservo1,DEC);
Serial.print("Sensore 2: ");
Serial.println(letturaluce2,DEC);
Serial.print("Posizione motore 2: ");
Serial.println(posservo2,DEC);
Serial.print("Differenza: ");
Serial.println(letturaluce1-letturaluce2);
delay(1000); //solo per facilitare la lattura dei dati
}
Lo sketch funziona correttamente ma a causa dei continui delay() inserit che, abbiamo visto nelle precisazioni precedenti sono indispensabili, rende il programma macchinoso.
In particolare si riscontrano i seguenti problemi:
- Se la luce cambia posizione velocemente, i servomotori non riescono a seguirla. Questo avviene perchè non aspettano solo 15ms tra un comando e il successivo bensì 1030ms (1000ms per la lettura e 15+15 per ciascun motore); si pensi se si inserissero altri elementi... il tempo si dilaterebbe aumentando questo probelma in maniera esponenziale.
- Il movimento dei motori risulta a scatti ed estremamente impreciso. Ciò avviene perchè tra un comando e il successivo non passano 15ms (necessari al corretto funzionamento del motore ed impercettibili per l'occhio umano) bensì, come abbiamo visto al punto prima 1030ms (che per l'occhio umano risultano ben identificabili)
- Un altro problema importante è che la lettura del sensore non è sempre molto accurata e può variare anche sensibilmente da una rilevazione alla successiva. In questo modo si genera un movimento "confuso" dei motori che rilevano valori anche molto discordanti da una volta all'altra
Il sistema risulta, nel suo complesso, lento a reagire ed estremamente impreciso oltre a dare una sensazione di scatto continuo.
Provate per credere :-)
Da queste "anomalie" nasce la necessità di modificare lo sketch e rendere il sistema più preciso e reattivo.
In particolare i primi due problemi verranno eliminati utilizzando la funzione millis() al posto del delay().
Il terzo problema al contrario con una media di rilevazioni come spiegato di seguito.
Vediamo quindi il codice seguente:
#includeSENSORELUCE1 0
#define
#define SENSORELUCE2 5
int letturaluce1=0;
int letturaluce2=0;
int luce1;
int luce2;
int luce1temp;
int luce2temp;
Servo servo1; //crea l'oggetto per il controllo del primo servo
Servo servo2; //crea l'oggetto per il controllo del secondo servo
int posservo1;
int posservo2;
Fino a questo punto il programma non subisce alcuna modifica rispetto la versione precedente.
Le variabili prima dichiarate continuano a presentarsi anche in questo caso.
Successivamente, però, si dichiarano le variabili-tempo presentate nel precedente articolo.
Ad ogni variabile-tempo viene associato un evento.
int k;
unsigned long time;
unsigned long servotime1;
unsigned long servotime2;
unsigned long letturadati;
unsigned long letturaluce_time;
time è la variabile che contiene "lo scorrere" del tempo; servotime1 e 2 rappresentano gli eventi associati al movimento dei motori; letturadati e lettura_luce rappresentano gli eventi associati alla lettura dei due sensori di luce.
La variabile k servirà come contatore per evitare le letture dei sensori "sballate".
Questo problema è stato anticipato prima; l'algoritmo che ci viene in aiuto, infatti, sarà semplicemente fare "x" letture consecutive e farne la media.
Considerando che arduino fa 16 milioni di operazioni al secondo, anche facendo 20 letture a distanza di 5ms, ogni frazione di secondo avremmo una rilevazione molto accurata del valore di luce circostante ed il calcolo della media smorza eventuali picchi anomali nei rilevamenti.
void setup(){
pinMode (SENSORELUCE1, INPUT);
pinMode (SENSORELUCE2, INPUT);
servo1.attach(9);
servo2.attach(10);
Serial.begin(9600);time=millis();
servotime1=millis();
servotime2=millis();
letturadati=millis();
letturaluce_time=millis();
k=0;
luce1=0;
luce2=0;
luce1temp=0;
luce2temp=0;
}
void loop(){
time=millis();
if(time>letturaluce_time+5){
luce1=analogRead(SENSORELUCE1);
luce2=analogRead(SENSORELUCE2);
k=k+1;
luce1temp=luce1temp+luce1;
luce2temp=luce2temp+luce2;
}
Come spiegato nell'articolo precedente, si associa l'evento ad un if.
Ogni 5ms si effettua una lettura di entrambi i sensori ma nel frattempo il programma continua a "girare" senza nessun impedimento.
if(k=20){
k=0;
letturaluce1=luce1temp/20;
letturaluce2=luce2temp/20;
luce1temp=0;
luce2temp=0;
}
Questo if risolve il problema della poca accuratezza nella misura.
Come detto due paragrafi fa, si effettuano k letture (in tal caso 20 ma nessuno vieta di aumentare o diminuire questo valore) al termine delle quali si effettua una media e si azzera il valore di k.
I valori di riferimento saranno sempre letturaluce1 e letturaluce2 che varieranno il proprio valore ogni 20 misure.
if(time>servotime1+15){
posservo1= letturaluce1;
posservo1=map(posservo1,0,1023,0,179); //scala il valore da usare tra 0 e 180.
servo1.write(posservo1); //imposta la posizione del servo1
servotime1=millis();
}
if(time>servotime2+15){
posservo2= letturaluce2;
posservo2=map(posservo2,0,1023,0,179);//scala il valore da 0 a 180
servo2.write(posservo2); // imposta la posizione del servo2.
servotime2=millis();
}
Queste istruzioni dovrebbero essere chiare dopo la lettura del precedente articolo.
In entrambi i casi si rileva la intensità della luce, si posiziona il servo corrispondente rimappando il valore con la funzione map e si "azzerano" le variabile-tempo servotime1 e servotime2 assegnando loro il numero di millisecondi correnti.
if(time>letturadati+3000){Anche queste istruzioni seguono lo stesso ragionamento precedente.
Serial.print("Sensore 1: ");
Serial.println(letturaluce1,DEC);
Serial.print("Posizione motore 1: ");
Serial.println(posservo1,DEC);
Serial.print("Sensore 2: ");
Serial.print(letturaluce2,DEC);
Serial.print("Posizione motore 2 : ");
Serial.println(posservo2,DEC);
Serial.print("Differenza: ");
Serial.println(letturaluce1-letturaluce2);
letturadati=millis();
}
}
In questo caso, addirittura, possiamo permetterci il lusso di "aspettare" 3000ms e non solo 1000ms tra una scrittura e la successiva (rendendo il tutto più leggibile all'utente finale) perchè il programma non si blocca ma continua a girare ed eseguire le azioni.
Tutto questo rende il movimento dei servo motori estremamente fluido.
L'osservatore non vedrà alcuno scatto e noterà anche una dinamica del sistema estremamente veloce con un "inseguimento" della luce decisamente reattivo.
Il programma nel suo complesso è decisamente utilizzabile.
Tuttavia presenta ancora un piccolo problemino: è lungo...
La lunghezza del codice proposto si può risolvere, come vedremo nel prossimo articolo con la programmazione a stati finiti.
Argomento precedente: "Multitasking Arduino: millis() -- PARTE 1"
Riporto il codice dell'intero sketch visto in questo articolo per facilitare il lettore che volesse testarlo:
#includeletturaluce_time=millis();
#define SENSORELUCE1 0
#define SENSORELUCE2 5
int letturaluce1=0;
int letturaluce2=0;
int luce1;
int luce2;
int luce1temp;
int luce2temp;
Servo servo1;
Servo servo2;
int posservo1;
int posservo2;
int k;
unsigned long time;
unsigned long servotime1;
unsigned long servotime2;
unsigned long letturadati;
unsigned long letturaluce_time;
void setup(){
pinMode (SENSORELUCE1, INPUT);
pinMode (SENSORELUCE2, INPUT);
servo1.attach(9);
servo2.attach(10);
Serial.begin(9600);
time=millis();
servotime1=millis();
servotime2=millis();
letturadati=millis();
letturaluce_time=millis();
k=0;
luce1=0;
luce2=0;
luce1temp=0;
luce2temp=0;
}
void loop(){
time=millis();
if(time>letturaluce_time+5){
luce1=analogRead(SENSORELUCE1);
luce2=analogRead(SENSORELUCE2);
k=k+1;
luce1temp=luce1temp+luce1;
luce2temp=luce2temp+luce2;
}
if(k=20){
k=0;
letturaluce1=luce1temp/20;
letturaluce2=luce2temp/20;
luce1temp=0;
luce2temp=0;
}
if(time>servotime1+15){
posservo1= analogRead(letturaluce1); // reads the value of the light sensor 1 (value between 0 and 1023)
posservo1=map(posservo1,0,1023,0,179); // scale it to use it with the servo (value between 0 and 180)
servo1.write(posservo1); // sets the servo position according to the scaled value
servotime1=millis();
}
if(time>servotime2+15){
posservo2= analogRead(letturaluce2); // reads the value of the light sensor 2 (value between 0 and 1023)
posservo2=map(posservo2,0,1023,0,179); // scale it to use it with the servo (value between 0 and 180)
servo2.write(posservo2); // sets the servo position according to the scaled value
servotime2=millis();
}
if(time>letturadati+3000){
Serial.print("Sensore 1: ");
Serial.println(letturaluce1,DEC);
Serial.print("Posizione motore 1: ");
Serial.println(posservo1,DEC);
Serial.print("Sensore 2: ");
Serial.println(letturaluce2,DEC);
Serial.print("Posizione motore 2: ");
Serial.println(posservo2,DEC);
Serial.print("Differenza: ");
Serial.println(letturaluce1-letturaluce2);
letturadati=millis();
}
}
Argomento precedente: "Multitasking Arduino: millis() -- PARTE 1"
Argomento successivo: "Ardino e programmare a stati finiti"
ciaooo Vittorio grazie al tuo codice sto usando un sensore ad effetto hall e vorrei fare un acquisizione di 40 campioni ma nn riesco a capire perchè non memorizza i campioni.
RispondiEliminati posto il codice che ho scritto.
#define sensorhall 1 // Pin analogico 1 per leggere il sensore ad effetto hall
unsigned long time;
unsigned long letturadati;
unsigned long letturasensorhall;
int k=0;
float Vref=2.95 ;//tensione si riferimento a corrente nulla
float sensibilita = 0.2;
float guadagno=22.2 ;
float correntemotore;
float mediatensione = 0;// media corrente
float mediatensionetemp=0;
float mediatensione1=0;
float tensione;
void setup(){
Serial.begin(9600);
pinMode (sensorhall, INPUT);
time=millis(); //millis() mi serve per mandare la temperatua sulla seriale ogni 3 secondi vedi funzione misurotemperatura ();
letturasensorhall=millis();
}
void loop(){
time=millis();
while(time>letturasensorhall+1000)
{
tensione= analogRead(sensorhall);
k=k+1;
mediatensionetemp=tensione+mediatensionetemp;
//
// if(k=40){
// k=0;
mediatensione=mediatensionetemp/40;
mediatensione=mediatensione * 5/1024 ;
correntemotore=((Vref- mediatensione)/(sensibilita *guadagno));
Serial.print("mediatensionetemp=");
Serial.println(mediatensionetemp);
Serial.print("Corrente Motore=");
Serial.println(correntemotore);
Serial.print("Media Tensione=");
Serial.println(mediatensione);
mediatensionetemp=0;
}
// mediatensione=0;
letturasensorhall=millis();
}
}
grazie
Ciao massimo, mi fa molto piacere che tu stia utilizzando le mie mini-guide.
RispondiEliminaHo provato a modificare il codice che aveva qualche imprecisione.
In particolare, ho notato che usando la "politica" del millis(), cicli come while e/o for devono sparire dal codice perchè sostituiti dal millis()+secondi...
Non ho testato il seguente codice ma dovrebbe funzionare.
Facci sapere:
void loop(){
time=millis();
if(time>letturasensorhall+25){
tensione= analogRead(sensorhall);
k=k+1;
mediatensionetemp=tensione+mediatensionetemp;
letturasensorhall=millis();
}
if(k=40){
k=0;
mediatensione=mediatensionetemp/40;
mediatensione=mediatensione * 5/1024 ;
correntemotore=((Vref- mediatensione)/(sensibilita *guadagno));
Serial.print("mediatensionetemp=");
Serial.println(mediatensionetemp);
Serial.print("Corrente Motore=");
Serial.println(correntemotore);
Serial.print("Media Tensione=");
Serial.println(mediatensione);
mediatensionetemp=0;
}
}
Complimenti per la chiarezza della guida, mi ha permesso di migliorare il funzionamento del VU-METER come barra grafica su display LCD del mio arduino destinato ad essere il controllo del mio Preamplificatore.
RispondiEliminaDavide Z.
Wow, sono molto contento di questo!!
RispondiEliminaHai una pagina di riferimento del progetto?
Potresti aprire una pagina su google code :-P
ciao vittorio,
RispondiEliminastavo facendo alcune ricerche per trovare uno sketch che mi permetta di ricevere il segnale proveniente da due fotoresistenze ed inviarlo a Max Msp.
Per adesso sono riuscita a ricevere il segnale solo da un sensore, utilizzando lo sketch "standard firmata"e maxuino.
ho aggiunto il secondo sensore, ma non ricevo nessun segnale :(
Come fare? Premetto che sono neofita di arduino&co.
Spero tu possa aiutarmi, grazie in anticipo :)
Ciao Annamaria, è difficile rispondere alla tua domanda senza ulteriori informazioni.
RispondiEliminaSe sei riuscita a ricevere il segnale da una fotoresistenza, non dovrebbero esserci problemi a riceverne da due.
Il collegamento della prima deve essere identico a quello della seconda ma su un altro PIN di tipo analogico.
Ovviamente lo skecth deve prendere in considerazione i PIN corretti in entrambi i casi.
ciao vittorio,
RispondiEliminagrazie per aver risposto :)
il circuito è corretto...
quindi credo che il problema sia lo sketch.
un annetto fa avevo provato a fare la stessa cosa utizzando lo sketch SimpleAnalogFirmata, fornito tra gli esempi di arduino, e andava.
ho riprovato adesso ma con snow leopard e arduino 17 simple analog non va, non ottengo neanche un segnale.
Allora ho provato con Standar firmata, e almeno un segnale lo riceve (anche se su standard firmata ci sono stringhe di codice che non occorrono).
penso che serva molto meno di cosi :)
ma ho provato anche con gli sketch sul sito di arduino, e non va.
ho provato anche con lo sketch che hai fornito in questa pagina (togliendo le stringhe che non mi occorrono), ma non legge nessun segnale.
standard firmata è l'unico che ho provato e che riceve il segnale, ma non so dove intervenire per fargli leggere analog 0 e analog 1.
spero di essere stata + chiara, grazie mille
Dunque, premetto che non conosco Firmata e tutti i suoi derivati e, purtroppo, non amo particolarmente il Mac come sistema...
RispondiEliminaPer quanto riguarda il rilevamento di un segnale analogico basta una singola istruzione.
Prova a fare uno sketch semplice semplice. Ovviamente SENSORELUCE1 e SENSORELUCE1 devono avere un valore rispettivo ai tuoi PIN.
Se questo sketch funziona allora è un problema del tuo sketch altrimenti è da ricercarsi altrove.
Facci sapere ok?
#define SENSORELUCE1 0
#define SENSORELUCE2 5
int luce1;
int luce2;
void setup(){
pinMode (SENSORELUCE1, INPUT);
pinMode (SENSORELUCE2, INPUT);
luce1=0;
luce2=0;
}
void loop(){
luce1=analogRead(SENSORELUCE1);
luce2=analogRead(SENSORELUCE2);
Serial.print("Sensore 1: ");
Serial.println(letturaluce1,DEC);
Serial.print("Sensore 2: ");
Serial.println(letturaluce2,DEC);
delay(30);
}
Funziona! grazie mille...ma devo apportare una piccola correzione:
RispondiEliminava scritto solo "luce1" anzichè "letturaluce1", altrimenti il codice non viene uploadato!!
grazie ancora :)
#define SENSORELUCE1 0
#define SENSORELUCE2 5
int luce1;
int luce2;
void setup(){
pinMode (SENSORELUCE1, INPUT);
pinMode (SENSORELUCE2, INPUT);
luce1=0;
luce2=0;
}
void loop(){
luce1=analogRead(SENSORELUCE1);
luce2=analogRead(SENSORELUCE2);
Serial.print("Sensore 1: ");
Serial.println(luce1,DEC);
Serial.print("Sensore 2: ");
Serial.println(luce2,DEC);
delay(30);
}
Ciao Annamaria, sono contento questo articoletto ti sia stato utile!!!
RispondiEliminaCiao Vittorio,complimenti per la guida è molto utile ed intuitiva,ultimamente vorrei costruire un conta giri con bargraph su LCD grafico 128x64 ma ho qualche difficoltà a costruire il bargraph,avresti qualche esempio dove prendere spunto?
RispondiEliminaGrazie in anticipo
Saluti
Antonio
Sinceramente non ho mai usato un display grafico ma potresti pensare di scrivere una funzione con due parametri: la posizione della barra e l'altezza; la funzione "scurisce" tutti i punti intermedi
RispondiEliminaciao Vittorio ho costruito diversi robottini con sensori vari ma ho un problema :
RispondiEliminavorrei tramite un sensore tipo microfono far partire il mio robot e all'arrivo di un secondo suono spegnerlo ad un terzo farlo ripartire e cosi via ai qualche idea ciao e grazie.
Roberto
Penso che il problema sia variegato...
RispondiEliminaPrima di tutto non ho capito se i suoni devono essere di differente tonalità o la medesima tonalità in momenti successivi.
Supponendo il secondo caso che è anche quello più semplice, è necessario anche che non ci sia "rumore" di fondo altrimenti diventa problematico il tutto....
Con queste due condizioni non penso ci siano grossi problemi a rilevare il suono con il microfono e con gli stati dirgli di partire o fermarsi.
Con "spegnerlo" intendi "fermarlo" o proprio farlo andare in "standby"? Questo potrebbe essere un problema risolvibile con un interrupt.
ciao vittorio
RispondiEliminann sono riuscito a capire una cosa..
come fa ad interrogare i sensori della luce ad ogni ciclo di 5 millisecondi se nn si resetta alla fine del ciclo il tempo?
letturaluce_time=millis();
grazie in anticipo :)
Perchè è un mio errore di trascrizione :-)
RispondiEliminaLo risolvo e grazie a te per la segnalazione
oooops ho visto adesso che sull'articolo stati finiti è corretto!
RispondiEliminacmq ottimi articoli..finalmente ho capito bene la funzione millis()
spero posterai presto altre guide
ciao :)
Ciao,
RispondiEliminacomplimenti è da poco che mi sono avvicinato al mondo Arduino e questi sono senza dubbio fra i più interessanti articoli che abbia letto, spero tu continuerai su questa strada.
salve, sto svolgendo un lavoro di tesi. Dovrei mettere a punto un sistema che mi permetta di gestire contemporaneamente un timer per l'accensione/spagnimento di una pompa mentre effettuo una lettura da dei sensori di temp.
RispondiEliminaHo scritto i programmini per i due singoli comandi ma ho difficoltà a farli eseguire parallelamente. Purtroppo non è il mio settore questo, la tesi è di ing. meccanica, però cerco di darmi da fare con un minimo di programmazione.
Grazie mille in aticipo
Fabio.
Ciao Fabio.
RispondiEliminaDirei che questi articoli fanno decisamente per te!
In questo modo riesci a fare sia la lettua sia la gestione delle operazioni della pompa proprio grazie al millis().
In bocca al lupo per la tesi!!
Ciao Vittorio.
RispondiEliminaMi chiamo Claudio.
Sono passato ora allo studio di Arduino.
Non capisco una cosa...come fa a funzionare l' if(k=20)? Da quello che so, un solo = assegna un valore, due ==, fa un confronto con un'altro valore...
Grazie
Claudio
Ciao Claudio e grazie per aver scritto.
EliminaEffettivamente trattasi di un errore di trascrizione.
Graze per la segnalazione!
Grazie Vittorio per la risposta :)
RispondiEliminaCiao Vittorio.
RispondiEliminaMi chiedevo, questa istruzione può andare bene anche come antirimbalzo software??
Secondo me no!!!
Tu che ne pensi??
Grazie
Claudio (quello di prima :))
Ehmmm. Quale istruzione? :-)
EliminaMagari pubblicala su pastebin e poi mandala con link ;-)
Salve
RispondiEliminaSono Carlo da Chioggia innanzitutto complimenti per questi ottimi tutorial.
Volevo applicare la funzione millis() per controllare la velocità di un servo senza interrompere il programma.
Lo sketch sembra funzionare in realtà variando vel non accade nulla il servo si muove sempre alla stessa velocità rallentata.
Non riesco a venirne fuori non capisco dove sbaglio avrebbe qualche consiglio?
Grazie
Carlo
#include
Servo Dito;// definisco oggetto servo
int Interut = 4;//Interuttore per muovere il servo
int Ineteruttore = 0;//Interuttore per muovere il servo
int pos_serv =0;// variabile dove scrivo la posizione del servo
int conta = 0 ;//Variabile per incremento posizione servo
int verif = 0;//debug
int diff = 0;//debug
int vel= 90;// variabile per modificare la velovita del servo
unsigned long startTime = 0;//Variabile di riferimento per lo scorrere del tempo velocita Servo
unsigned long startTime1 = 0;//Variabile di riferimento per lo scorrere del tempo velocita Servo
//---------------------------------------------------------
void setup()
{
Dito.attach(9); //Definisco il pin del controllo servo
pinMode (Interut , INPUT);
Serial.begin (9600);// Inizializo la seriale
}
//---------------------------------------------------------
void loop(){
Serial.print ( "Verif ");//Controllo posizione ServoSulla variabile diff
Serial.println (verif);//Controllo posizione Servo
Serial.print ( "Conta ");//Controllo posizione Servo
Serial.println (conta);//Controllo posizione Servo
Serial.print ( "Diff-------- ");//Controllo posizione Servo
Serial.println (diff);//Controllo posizione Servo
if (vel = 0){Dito.write (150);}
diff = millis() - startTime ;
Ineteruttore = digitalRead(Interut);// Leggo la posizione del interuttore
if (Ineteruttore == HIGH ) {
if ( (millis() - startTime) > vel ){//variando il parametro vel vorrei modificare la
verif = 0;//debug
conta = conta +1;
Dito.write (conta);
startTime = millis();
if ( conta > 150) { conta =150; }//Limito la corsa del servo
}
}
else{
conta = 50;
Dito.write (conta);
verif = 1;//debug
}
}
Salve
RispondiEliminaSono Carlo da Chioggia innanzitutto complimenti per questi ottimi tutorial.
Volevo applicare la funzione millis() per controllare la velocità di un servo senza interrompere il programma.
Lo sketch sembra funzionare in realtà variando vel non accade nulla il servo si muove sempre alla stessa velocità rallentata.
Non riesco a venirne fuori non capisco dove sbaglio avrebbe qualche consiglio?
Grazie
Carlo
#include
Servo Dito;// definisco oggetto servo
int Interut = 4;//Interuttore per muovere il servo
int Ineteruttore = 0;//Interuttore per muovere il servo
int pos_serv =0;// variabile dove scrivo la posizione del servo
int conta = 0 ;//Variabile per incremento posizione servo
int verif = 0;//debug
int diff = 0;//debug
int vel= 90;// variabile per modificare la velovita del servo
unsigned long startTime = 0;//Variabile di riferimento per lo scorrere del tempo velocita Servo
unsigned long startTime1 = 0;//Variabile di riferimento per lo scorrere del tempo velocita Servo
//---------------------------------------------------------
void setup()
{
Dito.attach(9); //Definisco il pin del controllo servo
pinMode (Interut , INPUT);
Serial.begin (9600);// Inizializo la seriale
}
//---------------------------------------------------------
void loop(){
Serial.print ( "Verif ");//Controllo posizione ServoSulla variabile diff
Serial.println (verif);//Controllo posizione Servo
Serial.print ( "Conta ");//Controllo posizione Servo
Serial.println (conta);//Controllo posizione Servo
Serial.print ( "Diff-------- ");//Controllo posizione Servo
Serial.println (diff);//Controllo posizione Servo
if (vel = 0){Dito.write (150);}
diff = millis() - startTime ;
Ineteruttore = digitalRead(Interut);// Leggo la posizione del interuttore
if (Ineteruttore == HIGH ) {
if ( (millis() - startTime) > vel ){//variando il parametro vel vorrei modificare la
verif = 0;//debug
conta = conta +1;
Dito.write (conta);
startTime = millis();
if ( conta > 150) { conta =150; }//Limito la corsa del servo
}
}
else{
conta = 50;
Dito.write (conta);
verif = 1;//debug
}
}
Da cosa mi sembra di capire, la velocità del servo sarà leggermente più veloce ogni 90ms e soltato per 1ms: ciò vuol dire che non ti accorgi della differenza ad occhio. Ciò dipende dal if (millis()-startTime)>vel) dove imposti starTime = millis()
RispondiEliminaProva a togliere questa impostazione e magari inserire vel = vel+100 e dovresti vedere il servo aumentare velocità
Salve. ho letto con attenzione questo sistema di inseguitore solare che ho realizzato con circuiti diversi (operazionali e circuito a ponte) ma ho utilizzato un solo motore che può girare sia in senso orario che anti orario per cui non capisco proprio questo esempio con due motori perché un servo non può girare in entrambi i sensi ?. E comunque in pratica come gestire due motori qual' è lo schema pratico di montaggio di un simile sistema a due motori. Saluti E.
RispondiEliminaSalve. Ciò che vorrei sapere è: quando millis finisce lo spazio in memoria, si resetta automaticamente ed in seguito io devo resettare le altre variabili, o arduino si blocca?
RispondiEliminabuongiorno,
RispondiEliminaleggo con piacere questo post e lo trovo molto utile,
però ho da fare una considerazione sulla "durata" di un istruzione, mi spiego meglio.
essendo presente un servomotore, il suo programma funziona molto bene con la funzione millis in quanto il servomotore si muove di pochi passi ad ogni controllo del sensore.
se ammettiamo invece che il servomotore in un altro progetto si debba spostare mettiamo di 90 gradi( e quindi il codice sia inserito in un ciclo for) questo ciclo duri ammettiamo come esempio 20ms.
in questo caso siccome il ciclo dura 20 ms il programma deve in ogni caso aspettare il termine del ciclo for indipendentemente dal delay inserito o millis inserito e quindi non può controllare la variabile sensore ogni 5 ms.
mi dica se è sbagliato il ragionamento nel caso.
la ringrazio per l'articolo che mi ha fatto riflettere.
Grazie per la guida,la sto usando per il mio progetto di inseguitore solare autoalimentato.
RispondiEliminaInvece di servi,no deciso di usare dei passo passo impopolari con uln2003.
Qui nasce un problema è non riesco a capire da cosa dipenda:
Pur usando millis() i passo passo non lavorano assieme o quasi ma prima uno e poi l'altro.
Nessuno dei due "finisce il duo lavoro" ma lo eseguono frammentato per cosi dire.
Qualche idea/suggerimento su quale possa essere la causa e un'eventuale soluzione?
Vorrei avere un movimento più fluido senza ricorrere a più arduino.
GrazieDD
Ciao Vittorio e i miei complimenti sulle guide per me importanti visto il mio primo approccio ad arduino.
RispondiEliminaVolevo chiederti se il millis() può essere utile per il io primo progettino.
Vorrei leggere nr 2 sensori umidità terreno a determinate ore della notte ed eventualmente azionare una pompa qualora il valore fosse sotto la soglia critica.
Avevo pensato di inserire un fotoresistore che al di sotto del valore minio azioni il sensore di umidità per nr 3 letture a distanza di qualche minuto e ripeterlo circa 6 ore nell'arco della nottata.
Grazie in anticipo
Dino
Ciao, il millis va benissimo ma tieni conto che serve per fare un "multitasking" o almeno... per simularlo. Da cosa mi descrivi penso che un semplice delay come spiegano nelle guide di base vada benissimo.
Elimina