EduRobot UNO – Come costruire il vostro primo Arduino Robot – Lezione 3

banner-edurobot-uno-lezione3 Diamo movimento al nostro robot Se siete arrivati fino a questo punto avete aggiunto alle vostre competenze l’uso dei servomotori e dei sensori ad ultrasuoni. Combiniamo queste due abilità sarete in grado di movimentare il vostro robot facendogli evitare ostacoli. Incominciamo con unire il codice per governare i servomotori e il sensore ad ultrasuoni che avete utilizzato:

#include <Servo.h>

// creazione degli oggetti servo
Servo MotoreSinistro;
Servo MotoreDestro;

const int periodoStampaSuSeriale = 250;       // stampa sulla Serial Monitor ogni 1/4 di secondo
unsigned long ritardoSuSeriale = 0;

const int periodoLoop = 20;          // un periodo di 20 ms = una frequenza di 50Hz
unsigned long ritardoLoop = 0;

// specifica i pin di trig e echo usati per il sensore ad ultrasuoni
const int TrigPin = 8;
const int EchoPin = 9;

int distanza;
int durata;

void setup()
{
  Serial.begin(9600);     // configurazione dei pin Arduino a cui colleghiamo il sensore
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);

  MotoreSinistro.attach(11);
  MotoreDestro.attach(10);
}

void loop()
{
    printOutput(); // stampa un messaggio di debug sulla Serial Monitor
    if(millis() - ritardoLoop >= periodoLoop)
    {
        letturaSensoreUltrasuoni(); // legge e memorizza la distanza misurata
        ritardoLoop = millis();
    }
}

void letturaSensoreUltrasuoni()
{
    digitalWrite(TrigPin, HIGH);
    delayMicroseconds(10);                  // mantiene alto il trigger per almeno 10us
    digitalWrite(TrigPin, LOW);
    durata = pulseIn(EchoPin, HIGH);
    distanza = (durata/2)/29;
}

void printOutput()
{
    if((millis() - ritardoSuSeriale) > periodoStampaSuSeriale)
    {
        Serial.print("distanza: ");
        Serial.print(distanza);
        Serial.print("cm: ");
        Serial.println();
        ritardoSuSeriale = millis();
    }
}

A questo punto bisogna comprendere come poter decidere cosa fare nel momento in cui di fronte al robot è presente un ostacolo. Sappiamo che:

  1. se non vi sono ostacoli di fronte al robot allora bisogna andare avanti
  2. se è presente un ostacolo di fronte al robot, bisogna svoltare a sinistra (è una possibile scelta, bisogna comunque svoltare)

Incominciamo con aggiungere al nostro robot una funzione che chiameremo azioneRobot() che viene eseguita all’interno del loop e consente di verificare quale azione effettuare (andare avanti o girare di 90°) Definiamo due variabili di stato che saranno utilizzate per decidere se far andare avanti il robot oppure farlo ruotare a sinistra.

// definizione degli stati
#define VAI_AVANTI  0
#define GIRA_SX     1

int stato = VAI_AVANTI;   // 0 = vai avanti (DEFAULT), 1 = gira a sinistra

Utilizzeremo un’istruzione if per decidere che azione far eseguire al robot:

  if(stato == VAI_AVANTI) // non viene rilevato nessun ostacolo
  {
...
  }
  else if(stato == GIRA_SX) // viene rilavato un ostacolo, il robot gira a sinistra
  {
 ...
  }

impostiamo per default lo stato a VAI_AVANTI in questo modo appena accendiamo il robot viene eseguita immediatamente il corpo della prima if. Bisognerà successivamente verificare se di fronte viene rilevato un ostacolo se ciò avviene è necessario cambiare direzione modificando lo stato in GIRA_SX

if(stato == VAI_AVANTI) // non viene rilevato nessun ostacolo
  {
...
  }
  else if(stato == GIRA_SX) // viene rilavato un ostacolo, il robot gira a sinistra
  {
...
  }

Nel caso non venga rilevato nessun ostacolo la condizione della prima if risulta vera e l’azione da far compiere al robot è quella di proseguire in avanti, aggiungiamo quindi al corpo della prima if il seguente codice:

if(distanza > minimaDistanza || distanza < 0)
// non è presente nessun ostacolo di fronte al sensore
// nota: la distanza rileata può assumere valori negativi se non è presente nessun ostacolo di fronte
// si è stabilito una rilevazione minima dell’ostacolo pari a 'minimaDistanza'
    {
      // vai avanti
      MotoreDestro.write(180);
      MotoreSinistro.write(0);
    }
    else // se ci sono oggetti di fronte gira a sinistra
    {
      stato = GIRA_SX;
    }

nell’if viene verificato se la distanza misurata è maggiore della minimaDistanza (al di sotto del quale bisogna cambiare direzione) o la distanza misurata è minore di zero, situazione che si verifica nel caso in cui non è presente nessun ostacolo di fronte. Se la condizione dell’if risulta vera il robot deve proseguire il suo cammino:

// vai avanti
MotoreDestro.write(180);
MotoreSinistro.write(0);

nel caso in cui la condizione dell’if non sia vera bisogna cambiare lo stato in GIRA_SX Aggiungiamo il codice indispensabile per fa girare a sinistra di 90° il nostro robot:

unsigned long tempoInizioRotazione = millis(); // memorizziamo l'istante in cui incomincia la rotazione
    while((millis()-tempoInizioRotazione) < tempoRotazioneSx) // il robot ruota a sinistra fino a quando non sono passati 1,1 secondi
    {
      // gira a sinistra
      MotoreDestro.write(180);
      MotoreSinistro.write(180);
    }
    stato = VAI_AVANTI;

la variabile globale tempoRotazioneSx (che vedremo inizializzata ad inizio sketch nel programma definitivo) avrà un valore di 1100 millisecondo, tempo (da me misurato. Voi potreste misurare tempi diversi) necessario per effettuare una rotazione di 90°. Questo valore di tempo sarà da calibrare, perché sarà funzione dell’attrito delle ruote e dei supporti del robot sulla superficie su cui si muove, ma anche dalla carica della batteria, sarà quindi indispensabile predisporre uno sketch aggiuntivo per effettuare la calibrazione (impostare la rotazione di 90°). La variabile tempoInizioRotazione impostata al valore millis() permette di memorizzare il momento di inizio rotazione ed effettuare un controllo del raggiungimento del tempo necessario per effettuare una rotazione di 90°. La condizione del while sarà vera fino a quando non sono trascorsi 1100 millesecondi in tal caso viene eseguito il corpo del while, cioè rotazione a sinistra

// gira a sinistra
MotoreDestro.write(180);
MotoreSinistro.write(180);

Trascorso il tempo necessario per effettuare la rotazione di 90° viene modificato lo stato in VAI_AVANTI, in questo modo al successivo loop verrà eseguita la prima if ed il nostro robot proseguirà in avanti. Unendo tutte le parti otterremo il seguente codice:

#include <Servo.h>

// creazione degli oggetti servo
Servo MotoreSinistro;
Servo MotoreDestro;

const int periodoStampaSuSeriale = 250;       // stampa sulla Serial Monitor ogni 1/4 di secondo
unsigned long ritardoSuSeriale = 0;

const int periodoLoop = 20;          // un periodo di 20 ms = una frequenza di 50Hz
unsigned long ritardoLoop = 0;

// specifica i pin di trig e echo usati per il sensore ad ultrasuoni
const int TrigPin = 8;
const int EchoPin = 9;

int distanza;               // distanza rilevata dal sensore
int durata;                 // durata dell'eco rilevata dal sensore ad ultrasuoni
int minimaDistanza = 10;    // distanza di soglia a cui il robot deve cambiare direzione
unsigned long tempoRotazioneSx = 1100;  // 1,1 secondi (circa) per effettuare una rotazione di 90°
                                        // variare questo valore in funzione nel caso la rotazione non sia perfettamente di 90°

// definizione degli stati
#define VAI_AVANTI  0
#define GIRA_SX     1

int stato = VAI_AVANTI;   // 0 = vai avanti (DEFAULT), 1 = gira a sinistra

void setup()
{
  Serial.begin(9600);     // configurazione dei pin Arduino a cui colleghiamo il sensore
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);

  MotoreSinistro.attach(11);
  MotoreDestro.attach(10);
}


void loop()
{
    printOutput(); // stampa un messaggio di debug sulla Serial Monitor
    
    if(millis() - ritardoLoop >= periodoLoop)
    {
        letturaSensoreUltrasuoni(); // legge e memorizza la distanza misurata
        
        azioneRobot();
        
        ritardoLoop = millis();
    }
}

void azioneRobot()
{
  if(stato == VAI_AVANTI) // non viene rilevato nessun ostacolo
  {
    if(distanza > minimaDistanza || distanza < 0) 
    // non è presente nessun ostacolo di fronte al sensore
    // nota: la distanza rileata può assumere valori negativi se non è presente nessun ostacolo di fronte 
    {
      // vai avanti
      MotoreDestro.write(180);
      MotoreSinistro.write(0);
    }
    else // se ci sono oggetti di fronte gira a sinistra
    {
      stato = GIRA_SX;
    }
  }
  else if(stato == GIRA_SX) // viene rilavato un ostacolo, il robot gira a sinistra
  {
    unsigned long tempoRotazioneSx = 1100;         // ci voglion circa 1,1 secondi per ruotare di 90°
    unsigned long tempoInizioRotazione = millis(); // memorizziamo l'istante in cui incomincia la rotazione
    
    while((millis()-tempoInizioRotazione) < tempoRotazioneSx) // il robot ruota a sinistra fino a quando non sono passati 1,1 secondi { // gira a sinistra MotoreDestro.write(180); MotoreSinistro.write(180); } stato = VAI_AVANTI; } } void letturaSensoreUltrasuoni() { digitalWrite(TrigPin, HIGH); delayMicroseconds(10); // mantiene alto il trigger per almeno 10us digitalWrite(TrigPin, LOW); durata = pulseIn(EchoPin, HIGH); distanza = (durata/2)/29; } void printOutput() { if((millis() - ritardoSuSeriale) > periodoStampaSuSeriale)
    {
        Serial.print("distanza: ");
        Serial.print(distanza);
        Serial.print("cm: ");
        Serial.println();
        
        ritardoSuSeriale = millis();
    }
}

Esercizio 1
Costruire uno sketch che permetta di valutare il tempo necessario per effettuare una rotazione di 90° del robot.

Esercizio 2
Aggiungere al robot un piezo con in serie un resistore da 180 Ohm, collegare ad un pin digitale e far emettere un suono ogni volta che il robot rileva un ostacolo.

Esercizio 3
Aggiungere al suono richiesto al passo 2 aggiungere un suono continuo di durata pari al tempo di rotazione del robot.

Esercizio 4
Aggiungere ad intervalli casuali un cambio direzione del robot

Esercizio 5
Aggiungere ad intervalli casuali un cambio di direzione casuale del robot

Esercizio 6
Realizzare uno sketch che ad intervalli casuali effettui un controllo della distanza dall’ostacolo più vicino a 45° a sinistra e a 45° a destra rispetto alla direttrice di movimento e movimenti il robot nella direzione in cui vi è una distanza maggiore dell’ostacolo.

Esercizio 7
Sostituire il sensore ad ultrasuoni con due LDR e realizzare un robot inseguitore di luce, ovvero un robot che si muove verso la fonte di luce a maggior intensità.

Esercizio 8
Alla funzionalità dell’esercizio 7 far in modo che rilevata una intensità luminosa in un intervallo fissato, il robot incominci a ruotare sul proprio asse.

Esercizio 9
Aggiungere nuovamente il sensore ad ultrasuoni insieme ai due sensori di luce (LDR) e realizzare un inseguitore di luce che nella ricerca della zona a maggior luminosità eviti gli ostacoli.

Questa voce è stata pubblicata in arduino e contrassegnata con , , , , , . Contrassegna il permalink.

10 risposte a EduRobot UNO – Come costruire il vostro primo Arduino Robot – Lezione 3

  1. arnaldo scrive:

    Gentilissimo Professore,
    Non sono uno studente ma la seguo con grande interesse e stima per il suo qualificatissimo lavoro.
    Sono soltanto un appassionato di Arduino.
    Volevo segnalare che nel listato finale occorre aggiungere le funzioni printOutput() e void letturaSensoreUltrasuoni()…altrimenti non compila.
    E’ giusto quello che riferisco?
    Attendo con interesse gli ulteriori sviluppi del progetto Robot con le sue chiare spiegazioni.
    Un cordiale saluto.
    Arnaldo

    • admin scrive:

      Salve Arnaldo, grazie per la segnalazione.

      Perdana l’errore, nel copiare ed incollare dagli esempi precedenti ho dimenticato di includere l’ultima parte, ho sistemato.

      Grazie ancora.
      Saluti.

  2. Fortuna Antonio scrive:

    buon giorno prof. lei e’ molto bravo , io sono un’appassionato di Arduino
    e sto cercando di fare qualche progetto , ho appena fatto il progetto di lettore di
    distanza con i sersori di ultrasuoni HC-SR04
    mi piacerebbe fare un progetto che legga gli ultrasuoni che invio per la misura
    della distanza , e’ possibile , lei ha gia’ fatto qualcosa ?
    ringraziandola
    cordiali saluti

    • admin scrive:

      Ciao.

      Grazie 🙂
      Nella lezione che hai appena letto su EduRobot viene spiegato come usare il sensore ad ultrasuoni. Il valore della distanza che viene rilevata puoi leggerla sulla Serial Monitor, ma se vuoi puoi utilizzare un display esterno su cui visualizzare la misura. Per sapere come utilizzare un display guarda l’articolo: Appunti su Arduino: pilotare un display LCD.
      Saluti.

  3. Davide Y. scrive:

    Salve, vorrei ringraziarla per queste 3 fantastiche lezioni e volevo chiedere dove devo collegare i due fili della batteria da 9V

  4. Simone scrive:

    Caro Prof. Maffucci,
    in primis la volevo ringraziare per queste lezione e per le altre che ha condiviso su questo sito; sono state di grande aiuto per un progetto che sto facendo per la mia tesi su un rover autonomo e che eviti ostacoli. Ho seguito alla lettera le istruzioni e il codice, senza aver avuto ancora il tempo di testarlo sul mio robot, pero’ ho notato che dei due servo, quando li collego ad arduino, se ne muove solo uno (quello di sinistra). Ho controllato piu’ volte che tutto sia collegato in maniera opportuna ma alla fine mi ritrovo sempre con lo stesso risultato. Sto sbagliando qualcosa o e’ normale che sia cosi’?
    Sono alle prime armi e ho avuto poco tempo per approfondire l’argomento, quindi ho cercato di raggiungere il risultato nel minor tempo possibile perche’ ho una scadenza molto vicina, quindi e’ probabile che qualcosa mi sia sfuggito.
    La ringrazio ancora, le sue spiegazioni passo passo sono state di grandissimo aiuto.
    Saluti

    Simone

  5. walter scrive:

    salve, vorrei un’informazione, mi da errore: exit status 1 expected unqualified-id before ‘if… cosa dovrei fare?

  6. Paolo scrive:

    Ho fatto il robottino come ha fatto lei, ma è normale che dopo un po’ di utilizzo esso impazzisce e continua a ruotare su se stesso?

Rispondi a admin Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.