Robot autonomo con Arduino

Salve a tutti, è la prima volta che scrivo su questo forum. non è da molto tempo che mi diletto con arduino ma ultimamente ho avuto alcuni problemi con la programmazione del mio primo robot.
prima dell'ultima modifica il robot utilizzava solo due motoriduttori controllati con l293 e un sensore ad ultrasuoni hc-sr04. il robottino si muoveva e quando trovava un'ostacolo ad una certa distanza tornava indietro e provava a girare, provava..
Poi ho pensato, con l'utilizzo di un servomotore potrei semplificare di gran lunga le cose, facendo in modo che quando il robot è vicino all'ostacolo, si guarda intorno e trova "una via di fuga". Qui i problemi: non riesco a far leggere correttamente la distanza tramite il sensore ultrasuoni.

Questo è lo sketch ancora in fase di lavorazione:

#define ECHOPIN 6                            // Pin to receive echo pulse
#define TRIGPIN 7                            // Pin to send trigger pulse
int motor1_pin1 = 2;
int motor1_pin2 = 3;
int motor2_pin1 = 4;
int motor2_pin2 = 5;
int distance = 0;
int distanceleft = 0;
int distancefront = 0;
int distanceright = 0;
int pos = 0;
#include <Servo.h> 
Servo myservo;  

void setup ()
{
  Serial.begin(9600);
  myservo.attach(9);
  pinMode(ECHOPIN, INPUT);
  pinMode(TRIGPIN, OUTPUT);
  pinMode(motor1_pin1,OUTPUT);
  pinMode(motor1_pin2,OUTPUT);
  pinMode(motor2_pin1,OUTPUT);
  pinMode(motor2_pin2,OUTPUT);

}
void ultrasuoni() {
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  int distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0; 
  return;
}

void loop()
{
  myservo.write(15);
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  int distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0; 
    
  distanceleft = distance;
  Serial.print(distanceleft);
  Serial.print("  ");
  delay(2000);
  
   myservo.write(90);
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0; 
  
   distancefront = distance;
  Serial.print(distancefront);
  Serial.print("  ");
  delay(2000);
  
  myservo.write(165);
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0; 
    
  distanceright = distance;
  Serial.print(distanceright);
  Serial.print("  ");
  delay(2000);
  
   }

Vorrei fare in modo di evitare di ripetere la parte di codice che fa funzionare il sensore ultrasuoni, ma ho avuto dei problemi nel farlo..
Attendo vostre notizie.

Simone

Hai creato la routine Ultrasuoni (il return finale è inutile), ma non la usi nel Loop!

P.S.: prima che Leo, il nostro moderatore, ti castri, inserisci il codice con l'apposito TAG "#" :smiley:

ho creato la routine ultrasuoni si, ma non la uso perchè usandola mi da le distanze "0" invece ripetendo funziona...

La funzione pulseIn restituisce il tempo in microsecondi: ti conviene usare una variabile long o meglio unsigned long al posto della int che arriva al massimo a 32767.

Ho cambiato un pò il funzionamento, anche dopo aver letto di altri robot online.
Ecco il nuovo sketch funzionante:

#include <Servo.h> 
#define motor1_pin1 2
#define motor1_pin2 3
#define motor2_pin1 4
#define motor2_pin2 5
#define ECHOPIN 6                            // Pin to receive echo pulse
#define TRIGPIN 7                            // Pin to send trigger pulse
#define fariled 8
int distance = 0;
int distanceleft = 0;
int distanceright = 0;
int object= 35;


Servo myservo;  

void setup ()
{
  Serial.begin(9600);
  myservo.attach(9);
  pinMode(ECHOPIN, INPUT);
  pinMode(TRIGPIN, OUTPUT);
  pinMode(fariled, OUTPUT);
  pinMode(motor1_pin1,OUTPUT);
  pinMode(motor1_pin2,OUTPUT);
  pinMode(motor2_pin1,OUTPUT);
  pinMode(motor2_pin2,OUTPUT);

}

void loop()
{
  myservo.write(90);
  delay(200);
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  int distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0; 
  
  if (distance > object) {
    avanti();
  }
  if (distance <= object) {
    trovastrada();
  }
}

void avanti() {
  digitalWrite(fariled,HIGH);
  digitalWrite(motor1_pin1,HIGH);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,HIGH);
  digitalWrite(motor2_pin2,LOW); 
  digitalWrite(fariled,LOW);
  return;
}

void trovastrada() {
  fermati();
  retro();
  guardasinistra();
  guardadestra();
  if( distanceleft < distanceright)  {
    girasinistra();
  }
  else                               {
    giradestra();
  }
}
   
void retro() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,HIGH);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,HIGH); 
  delay(500);
  fermati();
  return;
}

void fermati() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,LOW);
  delay(500); 
  return;
}

void ultrasuoni() {
  digitalWrite(TRIGPIN, LOW);                   // Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(TRIGPIN, HIGH);                  // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);                   // Send pin low again
  distance = pulseIn(ECHOPIN, HIGH);        // Read in times pulse
  distance= distance/58;    // Calculate distance from time of pulse
  if (distance <0 or distance >500) distance=0;
}

void guardasinistra(){
  myservo.write(30);
  delay(500);
  ultrasuoni();
  distanceleft = distance;
  Serial.print(distanceleft);
  Serial.print("  ");
  myservo.write(90);
  delay(500);
  return;  
}

void guardadestra(){
  myservo.write(150);
  delay(500);
  ultrasuoni();
  distanceright = distance;
  Serial.print(distanceright);
  Serial.print("  ");
  myservo.write(90);
  delay(500);
  return;  
  
}
void girasinistra() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,HIGH);
  digitalWrite(motor2_pin1,HIGH);
  digitalWrite(motor2_pin2,LOW);
  delay(500);
  fermati();
  return;
}

void giradestra() {
  digitalWrite(motor1_pin1,HIGH);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,HIGH);
  delay(500);
  fermati();
  return;
  
}

Se qualcuno ha altri suggerimenti, li accetterò voltentieri.

Simone

perchè utilizzi return? il suo utilizzo in un metodo (funzione) void è descritta come opzionale, è possibile utilizzarla in quelle situazioni che ne cessitano l'uscita dalla funzione stessa.
essendo void () questa funzione non restituisce nessuna variabile.
l'istruzione return la puoi utilizzare ad esempio nella funzione ultrasuoni la quale non dovrà essere void ma bensì long; quindi

int triggerPort = 7;
int echoPort = 6;

long ultrasuoni(){
   digitalWrite(triggerPort, LOW);
  digitalWrite(triggerPort, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPort, LOW);
  long durata = pulseIn (echoPort, HIGH);
  long distanza= 0.034*durata / 2;
  //delay(500);
  Serial.print( "durata: " );
  Serial.print( durata );
  Serial.print( " , " );
  Serial.print( "distanza: " );
 
  //dopo 38ms è fuori dalla portata del sensore
  if( durata > 38000 ) Serial.println( "fuori portata");
     else { Serial.print( distanza );
     Serial.println( "cm" );
   }
  return distanza;// l'istruzione return fornisce la variabile alla quale è assegnato la distanza in cm dall'ostacolo
}

Grazie per il consiglio, ma cosa cambia tra void () che non restituisce nessuna variabile
e long () ??
ho notato che così è molto più preciso...
Grazie ancora.

il metodo void, se ci fai caso è il solito metodo utilizzato per definire il metodo setup e/o loop, questo tipo di metodo (funzione) esegue il codice e basta.
Se tu vuoi creare una funzione che ti restituisca un valore ad esempio funzione somma

int Somma(){
int a=5;
int b=6;
int S= a+b;
return s;
}
ma non è finita qua; potresti aver bisogno di inviare alla funzione dei valori da sottoporre alla funzione, torniamo alla funzione somma.
int  Somma(int a, int b){    //in questo caso nel richiamare la funzione sarà necessario passare anche i valori di a e b 
int s = a + b;
return s;
}

la precisione che hai riscontrato è data dal fatto che è stata utilizzata una variabile long che prende 4 byte ma ti permette di sfruttare valori che vanno da -2147483648 a 2147483647 e quindi un valore maggiore che non int ceh arriva a +/- 32768

ho sistemato un attimino lo sketch ed ecco come si presenta ora:

#define motor1_pin1 2
#define motor1_pin2 3
#define motor2_pin1 4
#define motor2_pin2 5
#define echopin 6                            // Pin to receive echo pulse
#define trigpin 7                            // Pin to send trigger pulse
int distance = 0;
int timepuls = 0;
int distanceleft = 0;
int distanceright = 0;
int object= 30;
#include <Servo.h> 
Servo myservo; 

void setup ()
{
  myservo.attach(8);
  pinMode(echopin, INPUT);
  pinMode(trigpin, OUTPUT);
  pinMode(motor1_pin1,OUTPUT);
  pinMode(motor1_pin2,OUTPUT);
  pinMode(motor2_pin1,OUTPUT);
  pinMode(motor2_pin2,OUTPUT);

}

void loop()
{
  myservo.write(90);
  delay(200);
  ultrasuoni();
 
  if (distance > object) {
    avanti();
  }
  if (distance <= object) {
    trovastrada();
  }
}

void avanti() {
  digitalWrite(motor1_pin1,HIGH);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,HIGH);
  digitalWrite(motor2_pin2,LOW); 
  }

void trovastrada() {
  fermati();
  retro();
  guardasinistra();
  guardadestra();
  if( distanceleft < distanceright)  {
    girasinistra();
  }
  else                               {
    giradestra();
  }
}
   
void retro() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,HIGH);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,HIGH); 
  delay(500);
  fermati();
  return;
}

void fermati() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,LOW);
  delay(500); 
  return;
}

long ultrasuoni(){
  digitalWrite(trigpin, LOW);
  digitalWrite(trigpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin, LOW);
  long timepuls = pulseIn (echopin, HIGH);
  long distance= 0.034*timepuls / 2;
  
  if (timepuls > 38000) distance=450;
return distance;
}


void guardasinistra(){
  myservo.write(30);
  delay(500);
  ultrasuoni();
  distanceleft = distance;
  myservo.write(90);
  delay(500);
  
}

void guardadestra(){
  myservo.write(150);
  delay(500);
  ultrasuoni();
  distanceright = distance;
  myservo.write(90);
  delay(500);
}

void girasinistra() {
  digitalWrite(motor1_pin1,LOW);
  digitalWrite(motor1_pin2,HIGH);
  digitalWrite(motor2_pin1,HIGH);
  digitalWrite(motor2_pin2,LOW);
  delay(500);
  fermati();  
}

void giradestra() {
  digitalWrite(motor1_pin1,HIGH);
  digitalWrite(motor1_pin2,LOW);
  digitalWrite(motor2_pin1,LOW);
  digitalWrite(motor2_pin2,HIGH);
  delay(500);
  fermati();  
}

Così è corretto?
Una cosa per vedere se ho capito bene, il metodo void lancia le istruzioni contenute in esso, se uso invece long o int restituisce per forza un valore (sempre a seconda delle istruzioni date)?

Da una prima lettura veloce sembra prioprio di si.
esatto, ti ho proposto la funzione somma, per farti capire il funzionamneto.

una funzione somma con void potrebbe essere così :

void Somma(){
int a= 1;
int b=2;
int s=a+b; // esegue la somma
println(s); //stampa il risultato a video
}

ma in questo modo eseguiresti sempre la somma tra a e b cioè : 1+2
invece attraverso int, long, string, char, float, bolean e tanti altri tipi di variabli puoi inviare dei valori che saranno processati dalla funzione e ti sarà restituito un valore.

per fartela breve il compilatore deve sapere che tipo di dato verrà assegnato alla variabile che si è creata (inizializzata) perchè deve mettere a disposizione di quella variabile la parte di memoria necessaria.
Spero di avrti chiarito la differenza, comunque ti consiglio vivamente di acquistare o scaricare una guida di programmazione C ti sarà utile sempre, anche quando avrai una perfetta dimestichezza con la programmazione.
Le funzioni vengono utilizzate per eseguire delle parti di codice a piacimento quando è necessario e magari ripetutamente.

Mi permetto di aggiungere dei dettagli... (mi sto affacciando adesso alla programmazione di Arduino e a bazzicare per questo forum... per cui non conosco il codice di Arduino in se ma se non è molto differente da altri linguaggi di programmazione dovrebbe essere uguale)
nel creare una "funzione" hai diverse possibilità:

void Somma(){
int a= 1;
int b=2;
int s=a+b; // esegue la somma
println(s); //stampa il risultato a video
}

in questo caso crei una funzione che non ritorna alcun risultato con valori già prefissati.

void Somma(int a, int b){
int s=a+b; // esegue la somma
println(s); //stampa il risultato a video
}

in questo caso crei una funzione che non ritorna alcun risultato ma i valori glieli fornisci tramite il richiamo alla funzione

Somma(7, 3);
int Somma(){
int a= 1;
int b=2;
int s=a+b; // esegue la somma
return s;
}

In questo caso la funzione ti ritorna una variabile int utilizzabile nel tuo codice utilizzando però dei valori fissi

int miaSomma = Somma();
int Somma(int a, int b){
int s=a+b; // esegue la somma
return s;
}

In questo caso la funzione ti ritorna una variabile int utilizzabile nel tuo codice utilizzando i valori che gli passi nel richiamo alla funzione

int primaSomma = Somma(3,7);
int secondaSomma = Somma(2,5)

Come vedi se utilizzi una funzione void puoi stampare un valore a schermo o modificare un solo valore se invece utilizzi una funzione con ritorno puoi adattarla ad ogni variabile che necessiti...