Il sito per chi ama smanettare con Arduino, Raspberry Pi & Co.
Vettura Automatica & Manuale 2

Vettura Automatica & Manuale 2

by

Benvenuti in questo nuovo tutorial dove andremo a creare un vettura con arduino che si guida in modo autonomo e allo stesso tempo possiamo pilotarla in manuale da remoto tramite una applicazione Android.

Puntata II: Creazione sketch per la macchinina.

Salve a tutti prima di tutto vorrei fare una premessa di seguito troverete solo le parti principali dello sketch di Arduino. Per avere il codice intero cliccate qui .

Benvenuti alla seconda puntata del tutorial per costruire una macchinina che si autopiloti, ma che può anche essere pilotata da manuale tramite applicazione Android. In questa puntata andremo a vedere come creare lo sketch ovvero il programma che verrà eseguita dalla nostra scheda Arduino.

Partiamo subito col dire che il programma è suddiviso in funzioni, le funzioni principali sono:

  • setup(): La funzione setup è una funzione base di arduino che viene eseguita una volta solo all’ accensione della scheda, qui di solito viene inizializzato il programma, definendo modalità dei pin, creazione di comunicazioni seriali ecc..
  • loop(): La funzione loop è la seconda funzione base di arduino. A differenza della prima questa viene eseguita in modo infinito ovvero una volta che arriva al suo termine essa riparte la sue esecuzione dall’inizio
  • automatico(): Questa funzione ha il compito di gestire la vettura in modo che non abbia collisioni con ostacoli cambiando rotta prima che vi si schianti.
  • manuale(): Questa funzione serve per pilotare i motori, ovvero serve per pilotare i 2 motori che andranno a muovere la nostra macchinina. Questa funzione entra in gioco soltanto quando andremo a pilotare la vettura tramite applicazione android
  • sch04(): Funzione che ci restituisce la distanza dell’ ostacolo in cm (centimetri);

setup()

Come precedentemente detto qui andremo a inizializzare i pin di arduino e la comunicazione seriale.

void setup() {
   pinMode(key,OUTPUT);//key per il bluetooth serve per configuralo
   pinMode(btLed,OUTPUT);//notifica la ricezione di qualcosa
   digitalWrite(key,HIGH);//attiva key ma serve solo in fase iniziale
   //inizializzazione porta seriale definendo il baud
   Serial.begin(38400);
   Serial.println("Type AT commands!");
   // SoftwareSerial "com port"
   mySerial.begin(38400);   
}

loop()

Come detto prima il loop è una funzione che viene ripetuta ogni volta che viene completata. Qui c’è la gestione delle priorità tra manuale e automatico (dando la precedenza al comando in manuale) e la letture dallo stream del bluetooth.

la funzione commandToInt() è una funzione scritta da me che ci trasforma il comando in carattere in un numero intero, invece la funzione StrToInt() è una funzione che trasforma una stringa con un valore numerico in numero intero. Queste funzioni le troverete nel link a inizio pagina insieme al resto del codice dell’ intero progetto

void loop(){
  // legge se il bluetooth è avviabile
  if (mySerial.available()) 
  { 
    digitalWrite(btLed,HIGH); // accende led rosso
    while(mySerial.available()){
      //leggo i valori ricevuti dal bluetooth
      command += (char)mySerial.read();
    }
    Icommand=commandToInt(command);//converte comando in int
    Serial.println(Icommand);
    Serial.println(command);
    switch (Icommand){
        case 1:
          partenza = true;//flag per la partenza 
        break;
        case 2:
          partenza = false;//flag per lo stop
        break;
        case -1:
          if (partenza){
            //converte la stringa in intero
            Idirection=StrToInt(command);
            manuale(Idirection);  
          }
          else{stopAuto();}//ferma la macchinina
        break;
     }
     command = ""; // svuoto la variabile
  }
  else{
    //nessun segnale da bluetooth
    digitalWrite(btLed,LOW); //spengo il led
    if (partenza)
      automatico();
    else
      stopAuto();    
  }
  /* manda l' input scritto dall' utente al bluetooth per comando
   * AT i comandi AT servono per configurare il bluetooth*/
  if (Serial.available()){
    delay(10); // The DELAY!
    mySerial.write(Serial.read());
  }
  //delay di sincronizzazione con l' app
  delay(100);
}//chiuso loop

Automatico()

Nella funzione Automatico vengono gestite le collisioni. Il suo funzionamento è semplice, esso fa partire la macchinina in avanti e fa una misura dell’ ostacolo tramite la funzione sch04() che ritorna la distanza in centimetri. Poi fa un piccolo controllo se l’oggetto si trova a una distanza inferiore di 20 cm esso si ferma e fa marcia indietro per 0,3 secondi poi esegue una misurazione sia a destra che a sinistra e con un altro controllo verifica dove ha più spazio per far manovra e cambiare direzione.

void automatico (){
    Serial.println("AUTOMATICO");
    long front,left,right;
    //richiamo la funzione del sensore, ritorna la distanza in cm
    front = sch04(TRIG1,ECHO1);
    delay(100);
    motor1.setSpeed(205); //imposto velocità                                                                        
    motor2.setSpeed(235); //imposto velocità                                                               
    motor1.run(FORWARD);  //parametro->direzione                         
    motor2.run(FORWARD);
    
    if(front<20){ 
      while(stato){         
        motor1.run(BACKWARD); 
        motor2.run(BACKWARD);
        delay(300);
        left=sch04(TRIG2,ECHO2);
        delay(100);
        right=sch04(TRIG3,ECHO3);
        delay(100);
        if(left>right){
          //giro a destra e continuo la marcia
          motor1.run(BACKWARD); 
          motor2.run(FORWARD);
          delay(500);
          stato=false;  
        }
        else{
          if(left<right){
            //giro a sinistra e continuo la marcia
            motor1.run(FORWARD); 
            motor2.run(BACKWARD);
            delay(500);
            stato=false;  
          }
          else{stato=true;}
        }
      }
    }
    stato=true;
}// chiuso automatico

manuale(int direct)

Questa funzione consiste tutto in uno switch. infatti tramite android noi manderemo alla nostra scheda Arduino un valore tra uno e otto (1-8), questi valori corrispondono rispettivamente a una direzione che può intraprendere la nostra macchina. Come si nota dal codice non viene usato nessun sensore per controllare la distanza con l’ ostacolo, infatti quando si è manuale la macchina diventa completamente “cieca”. “FRONT” e tutte le altre direzioni sono delle costanti intere. Il parametro che inseriamo in questa funzione è il valore della direzzione letto con il bluetooth.

void manuale(int direct){
    Serial.println("MANUALE");
    switch (direct){
      case FRONT:                              //3
          motor1.setSpeed(205);                                                                         
          motor2.setSpeed(240);
          motor1.run(FORWARD);                           
          motor2.run(FORWARD);
      break;
      case LEFT_FRONT:                        //2  
          motor1.setSpeed(120);                                                                         
          motor2.setSpeed(235);
          motor1.run(FORWARD);                            
          motor2.run(FORWARD);
      break;
      case LEFT:                             //1
          motor1.setSpeed(175);                                                                         
          motor2.setSpeed(195);
          motor1.run(BACKWARD);                            
          motor2.run(FORWARD);
      break;
      case BOTTOM_LEFT:                      //8
          motor1.setSpeed(120);                                                                         
          motor2.setSpeed(235);
          motor1.run(BACKWARD);                            
          motor2.run(BACKWARD);
      break;
      case BOTTOM:                           //7
          motor1.setSpeed(205);                                                                        
          motor2.setSpeed(235);
          motor1.run(BACKWARD);                           
          motor2.run(BACKWARD);
      break;
      case RIGHT_BOTTOM:                     //6
          motor1.setSpeed(235);                                                                         
          motor2.setSpeed(135);
          motor1.run(BACKWARD);                            
          motor2.run(BACKWARD);
      break;
      case RIGHT:                           //5
          motor1.setSpeed(175);                                                                         
          motor2.setSpeed(195);
          motor1.run(FORWARD);                           
          motor2.run(BACKWARD);
      break;
      case FRONT_RIGHT:                    //4
          motor1.setSpeed(235);                                                                         
          motor2.setSpeed(135);
          motor1.run(FORWARD);                           
          motor2.run(FORWARD);
      break;
    default://il bluetoothj ha avito qualche problema e ha ricevuto un valore non corretto
      Serial.println("errore di codice");
    break;
  }  
}//chiuso manuale

sch04(int trigPin, int echoPin)

Come valore in ingresso gli andremo a metterci il pin del trig e dell’ echo del sensore che vorremo utilizzare. Questa funzione invia un segale alto per 10 microsecondi poi attiva il pin echo in input e con la funzione pulseIn misura la durata dell’ impulso restituendoci quanto tempo chi ha messo il segnale ad arrivare fino all’ ostacolo e tornare indietro. La funzione microsecondsToCentimeters trasforma il tempo impiegato dal segnale in una distanza espressa in centimetri.

long microsecondsToCentimeters(long microseconds){
  //la velocità del suono è 340 m/s o 29 millisecondi per centimetro.
  // nel calcolo viene diviso per 2 perché il la distanza rilevata è pari allo spazioe dell' andata e del ritorno del suono
  return microseconds / 29 / 2;
}
//fnzione per trovare la distanza
long sch04(int trigPin, int echoPin ){
  long duration, cm;
  //emissione del suono
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
 
  //ricezione del suono
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);

  //conversione del tempo in spazio
  cm = microsecondsToCentimeters(duration);
  //feedback su monitor seriale
  switch (trigPin){
    case TRIG2:
      Serial.print("left");
      break;
      
    case TRIG1:
      Serial.print("front");
      break;
      
    case TRIG3:
      Serial.print("right");
      break;
  }
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  
  //ritorno il valore
  
  return cm;
}

Qui si conclude la seconda puntata di questo progetto, vi invito a commentare se vi serve aiuto o non vi è chiaro qualche passaggio. A breve uscirà la terza puntata, dove andremo a parlare del Software lato Android dove andremo a pilotare la nostra vettura progettata con arduino in modalità manuale. Inoltre vi invito, se vi siete persi il primo tutorial, a riprenderlo: Puntata I: Costruzione hardware con Arduino.

Ti è rimasta una domanda o un dubbio?

Iscriviti e chiedi nella community

4 commenti su “Vettura Automatica & Manuale 2

  1. Ciao sono Livio,
    sono solo due mesi che uso Arduino Mega, ho automatizzato un vecchio prototipo di macchina costruito 9 anni fa, che schiva gli ostacoli, con tre sensori a ultrasuoni identici al tuo progetto, ma il comando dei motori è ancora con transistor e relè, ho appena ricevuto la scheda motore da te utilizzata.
    Io riscotro due problemi, quando il locale dove la faccio girare è molto grande entra in panico perchè il sensore anteriore non legge più la distanza e sul pannello LCD 20×2 che ho installato per visualizzare le distanze legge 9 (ma non è reale) e quindi non lascia partire il mezzo, che esegue alcune manovre a destra o asinistra fino quando non visualizza un oggetto a distanza inferiore ai 4 metri.
    Quando il mezzo arriva davanti ad una colonna o a una parete con una inclinazione tra 15° e 45° non rileva l’ostacolo e sbatte, anche se io i due sensori laterali li ho installati a 15° rispetto al mezzo.
    Ho pensato di installare anteriormente un sensore IRF, spero che questo possa evitare il problema.
    Ciao e grazie se vorrai darmi un suggerimento in merito.

    1. Ciao Livio, scusa se ti rispondo con questo ritardo ma in questo periodo ho avuto qualche problema. Comunque, prima di tutto proviamo a risolvere il problema della lettura della distanza troppo elevata, dovresti prendere il valore della distanza (quando è troppo elevata) e stamparlo sul monitor seriale. Poi in base cosa ti restituisce vedi come gestire, dovrebbe bastare qualche controllo. Inoltre per il valore sbagliato nel pannello potresti risolvere con con un carattere (a tua scelta) che indica un errore di lettura, che può a sua volta essere causato da una distanza troppo elevata e troppo ravvicinata.
      I sensori laterali non centrano con il problema di quello frontale, l’ unica cosa che mi viene in mente è che forse non tieni acceso abbastanza il trig (in giro su internet c’è chi lo tiene acceso per 5 microsecondi e mi ricordo che feci dei test e notai che e volte il sensore non funzionava correttamente di conseguenza ho provato ad aumentare fino a 10 notando un miglioramento). inoltre per quanto riguarda le pareti la lettura rimane un po più confusa perché il segnale viene un minimo deviato.
      Una ultima cosa, cos’ è il sensore IRF ?? scusa la mia ignoranza ma come sensore non lo mai visto/sentito 😀

      Spero di esserti stato di aiuto, se non è chiaro qualcosa non esitare a contattarmi qui nei commenti o anche su G+ o FB.

  2. Ciao sono Livio,
    sono solo due mesi che uso Arduino Mega, ho automatizzato un vecchio prototipo di macchina costruito 9 anni fa, che schiva gli ostacoli, con tre sensori a ultrasuoni identici al tuo progetto, ma il comando dei motori è ancora con transistor e relè, ho appena ricevuto la scheda motore da te utilizzata.
    Io riscotro due problemi, quando il locale dove la faccio girare è molto grande entra in panico perchè il sensore anteriore non legge più la distanza e sul pannello LCD 20×2 che ho installato per visualizzare le distanze legge 9 (ma non è reale) e quindi non lascia partire il mezzo, che esegue alcune manovre a destra o asinistra fino quando non visualizza un oggetto a distanza inferiore ai 4 metri.
    Quando il mezzo arriva davanti ad una colonna o a una parete con una inclinazione tra 15° e 45° non rileva l’ostacolo e sbatte, anche se io i due sensori laterali li ho installati a 15° rispetto al mezzo.
    Ho pensato di installare anteriormente un sensore IRF, spero che questo possa evitare il problema.
    Ciao e grazie se vorrai darmi un suggerimento in merito.

    1. Ciao Livio, scusa se ti rispondo con questo ritardo ma in questo periodo ho avuto qualche problema. Comunque, prima di tutto proviamo a risolvere il problema della lettura della distanza troppo elevata, dovresti prendere il valore della distanza (quando è troppo elevata) e stamparlo sul monitor seriale. Poi in base cosa ti restituisce vedi come gestire, dovrebbe bastare qualche controllo. Inoltre per il valore sbagliato nel pannello potresti risolvere con con un carattere (a tua scelta) che indica un errore di lettura, che può a sua volta essere causato da una distanza troppo elevata e troppo ravvicinata.
      I sensori laterali non centrano con il problema di quello frontale, l’ unica cosa che mi viene in mente è che forse non tieni acceso abbastanza il trig (in giro su internet c’è chi lo tiene acceso per 5 microsecondi e mi ricordo che feci dei test e notai che e volte il sensore non funzionava correttamente di conseguenza ho provato ad aumentare fino a 10 notando un miglioramento). inoltre per quanto riguarda le pareti la lettura rimane un po più confusa perché il segnale viene un minimo deviato.
      Una ultima cosa, cos’ è il sensore IRF ?? scusa la mia ignoranza ma come sensore non lo mai visto/sentito 😀

      Spero di esserti stato di aiuto, se non è chiaro qualcosa non esitare a contattarmi qui nei commenti o anche su G+ o FB.

Lascia un commento

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