Pagine

venerdì 5 febbraio 2010

Multitasking Arduino: millis() -- PARTE 2

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:
  1. Leggere il sensore 1 e il sensore 2
  2. Muovere a seconda della luce i due motori in direzione della luce stessa
  3. Stampare a video le posizioni dei motori e l'intensità di luce rilevata
Alcune precisazioni sono d'obbligo per comprendere appieno il codice:
  1. I motore, per come è progettato, tra un comando e l'altro, desidera circa 15ms di ritardo
  2. Una persona, per leggere correttamente, deve avere un output circa ogni 500-1000ms
  3. 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
Procediamo quindi con lo sketch:
#include  

#define SENSORELUCE1 0

#define
SENSORELUCE2 5

int 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:


#include  

#define
SENSORELUCE1 0
#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){

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();
}
}

Anche queste istruzioni seguono lo stesso ragionamento precedente.
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:

#include  

#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;
letturaluce_time=millis();
}
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"

34 commenti:

  1. 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.
    ti 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

    RispondiElimina
  2. Ciao massimo, mi fa molto piacere che tu stia utilizzando le mie mini-guide.
    Ho 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;
    }
    }

    RispondiElimina
  3. 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.
    Davide Z.

    RispondiElimina
  4. Wow, sono molto contento di questo!!
    Hai una pagina di riferimento del progetto?
    Potresti aprire una pagina su google code :-P

    RispondiElimina
  5. ciao vittorio,

    stavo 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 :)

    RispondiElimina
  6. Ciao Annamaria, è difficile rispondere alla tua domanda senza ulteriori informazioni.
    Se 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.

    RispondiElimina
  7. ciao vittorio,
    grazie 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

    RispondiElimina
  8. Dunque, premetto che non conosco Firmata e tutti i suoi derivati e, purtroppo, non amo particolarmente il Mac come sistema...
    Per 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);
    }

    RispondiElimina
  9. Funziona! grazie mille...ma devo apportare una piccola correzione:
    va 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);
    }

    RispondiElimina
  10. Ciao Annamaria, sono contento questo articoletto ti sia stato utile!!!

    RispondiElimina
  11. Ciao 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?

    Grazie in anticipo

    Saluti

    Antonio

    RispondiElimina
  12. 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

    RispondiElimina
  13. ciao Vittorio ho costruito diversi robottini con sensori vari ma ho un problema :
    vorrei 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

    RispondiElimina
  14. Penso che il problema sia variegato...
    Prima 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.

    RispondiElimina
  15. ciao vittorio
    nn 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 :)

    RispondiElimina
  16. Perchè è un mio errore di trascrizione :-)
    Lo risolvo e grazie a te per la segnalazione

    RispondiElimina
  17. oooops ho visto adesso che sull'articolo stati finiti è corretto!
    cmq ottimi articoli..finalmente ho capito bene la funzione millis()
    spero posterai presto altre guide
    ciao :)

    RispondiElimina
  18. Ciao,
    complimenti è 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.

    RispondiElimina
  19. 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.
    Ho 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.

    RispondiElimina
  20. Ciao Fabio.
    Direi 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!!

    RispondiElimina
  21. Ciao Vittorio.
    Mi 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

    RispondiElimina
    Risposte
    1. Ciao Claudio e grazie per aver scritto.
      Effettivamente trattasi di un errore di trascrizione.
      Graze per la segnalazione!

      Elimina
  22. Grazie Vittorio per la risposta :)

    RispondiElimina
  23. Ciao Vittorio.
    Mi chiedevo, questa istruzione può andare bene anche come antirimbalzo software??
    Secondo me no!!!

    Tu che ne pensi??
    Grazie
    Claudio (quello di prima :))

    RispondiElimina
    Risposte
    1. Ehmmm. Quale istruzione? :-)
      Magari pubblicala su pastebin e poi mandala con link ;-)

      Elimina
  24. Salve
    Sono 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
    }
    }

    RispondiElimina
  25. Salve
    Sono 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
    }
    }

    RispondiElimina
  26. 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()
    Prova a togliere questa impostazione e magari inserire vel = vel+100 e dovresti vedere il servo aumentare velocità

    RispondiElimina
  27. 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.

    RispondiElimina
  28. Salve. 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?

    RispondiElimina
  29. buongiorno,
    leggo 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.

    RispondiElimina
  30. Grazie per la guida,la sto usando per il mio progetto di inseguitore solare autoalimentato.
    Invece 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

    RispondiElimina
  31. Ciao Vittorio e i miei complimenti sulle guide per me importanti visto il mio primo approccio ad arduino.
    Volevo 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

    RispondiElimina
    Risposte
    1. 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