Go Down

Topic: Pilotare due motori passo passo in base a due sensori IR (Read 877 times) previous topic - next topic

Sergio_A

Fine settimana impegnatissimo ma ci sono ancora!

Stasera ho deciso di infilarmi nello sketch per modificarlo inserendo le parti riguardanti i sensori ultrasonici.
Mi sono informato un po'su internet a questi indirizzi trovandoli molto interessanti:

http://www.settorezero.com/wordpress/il-sensore-ad-ultrasuoni-hc-sr04/

http://www.adrirobot.it/sonar/HC-SR04/Sensore_sonar_HC-SR04.htm

Poi ho cercato qualche applicazione di tale componente per visualizzare lo sketch e capirne la logica...
la logica di funzionamento, a grandi linee, l'ho capita ma ho serie difficoltà ad inserirlo nel mio sketch:

Code: [Select]
////////////////////////////////////////////////

//ARDUINO ROBOT EVITA OSTACOLI CON HC-SR04

//Autore Fancello Salvatore

//Per maggiori info: http://www.progettiarduino.com

/////////////////////////////////////////////////

 int MOTORD=8;
 int MOTORS=9;
#define echoPin 2 // Pin che riceve la pulsazione echo
#define trigPin 3

void setup(){
  Serial.begin(9600);
pinMode(MOTORD,OUTPUT);
pinMode(MOTORS,OUTPUT);
pinMode(echoPin, INPUT);// setto echopin come input
pinMode(trigPin, OUTPUT);// setto trigger come output
}
void loop(){
 
 
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  int distance = pulseIn(echoPin, HIGH);       
  distance= distance/58;                       
   Serial.println(distance);
   // se ho un ostacolo a 25 cm di distanza gira a destra tenedo ferma la ruota destra
  if((distance<25)&&(distance!=0)){  // a volte arrivano degli zeri e quelli non li devo prendere in considerazione
  digitalWrite(MOTORS,HIGH); // accendo un motore e spengo l'altro così posso girare
  digitalWrite(MOTORD,LOW);
  delay(500);
  }
   else{ // vado dritto
  digitalWrite(MOTORS,HIGH);
  digitalWrite(MOTORD,HIGH);
 
  }
 
}


La parte che a me interessa ovviamente è quella inerente al "loop" la quale , se non ho capito male, manda un segnale attraverso il trig  per 10 microsecondi con una pausa di 2 microsecondi. Il segnale di risposta viene captato da echo "distance" e diviso per 58; tale concetto collima perfettamente con la formula letta sui siti soprastanti.

A questo punto, ho deciso di cambiare lo schema elettrico, in modo da identificare i pin da utilizzare (vedi allegato).

Poi, preso dall'entusiasmo, incomincio a modificare lo sketch, arrivo nelle vicinanze del loop e... Aiuto!
Vorrei provare, ma per imparare, devo capire come far lavorare Arduino sia con i sensori IR che quelli Ultrasonici.

Per ora sono a questo punto:

Code: [Select]
#define DIRD 2         //direzione motore destra
#define STEPD 3        //pin di step motore destra
#define IRD 4          //sensore IR a destra
#define ULTRECHOD 5    //sensore ultrasuoni echo destro
#define ULTRTRIGD 6    //sensore ultrasuoni trig destro
#define DIRS 7         //direzione motore sinistra
#define STEPS 8        //pin di step motore sinistra
#define IRS 9          //sensore IR sinistra
#define ULTRECHOS 10   //sensore ultrasuoni echo sinistro
#define ULTRTRIGS 11   //sensore ultrasuoni trig sinistro
#define LAMA 12        //rele di controllo motore lama
#define INTERVALLO 8   //durata del movimento generale 8 * 100 (ritorno) = 800 passi per 1/2 giro ritorno = 200 per un giro completo
 
int rilevamentoIRD = HIGH;
int rilevamentoIRS = HIGH;

int ritorno = 100;     //durata della rotazione senza controllare nuovamente (variabile perche nel programma il robot potra adattarlo in base alle condizioni)
int velo = 10;         //velocita movimento da 1 a 100 ritardo step successivi
int i;

void setup()
 {
  Serial.begin(9600);  //inizio della trasmissione seriale (serve soprattutto a noi per capire a che punto del programma si trova)
  Serial.print("Mi sono acceso correttamente.");
  delay(500);

  pinMode(DIRD, OUTPUT);
  pinMode(STEPD, OUTPUT);
  pinMode(IRD, INPUT);
  pinMode(ULTRECHOD INPUT);
  pinMode(ULTRTRIGD OUTPUT);
  pinMode(DIRS, OUTPUT);
  pinMode(STEPS, OUTPUT);
  pinMode(IRS, INPUT);
  pinMode(ULTRECHOS INPUT);
  pinMode(ULTRTRIGS OUTPUT);
  pinMode(LAMA, OUTPUT);
 }
 
void loop() {
  rilevamentoIRD = digitalRead(IRD); //rileva la condizione del sensore laterala destro
  rilevamentoIRS = digitalRead(IRS); //rileva la condizione del sensore laterale sinistro
 
    if(rilevamentoD == HIGH && rilevamentoS == HIGH) { //se sentrambi non rilevano ostacoli
      Serial.print("\nVia libera!");
      for(i=0;i<ritorno;i++) {//aggiunta perchè mancante quando va dritto
        step(true, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso discorde manderanno avanti o indietro il robot!
   }
  }
  else {
    if(rilevamentoD == LOW && rilevamentoS == HIGH) {//se il sensore destro rileva un ostacolo
      Serial.print("\nOstacolo a destra!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(false, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
      }
    }
    if(rilevamentoS == LOW && rilevamentoD == HIGH) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nOstacolo a sinistra!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(true, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
      }
    }
    if(rilevamentoS == LOW && rilevamentoD == LOW) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nRetromarcia!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(false, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi faranno indietreggiare il robot!
      }
    } 
  }
}

void step(boolean dirAttualeD, boolean dirAttualeS, int steps,int velo) {//velo 1 ... 100
  digitalWrite(DIRD, dirAttualeD); //invia al driver destro la direzione attuale
  digitalWrite(DIRS, dirAttualeS); //invia al driver sinistro la direzione attuale
  for(int i=0; i<steps; i++) {//ATTENZIONE: durante il ciclo non controlla i sensori!
    digitalWrite(STEPD, HIGH);
    digitalWrite(STEPS, HIGH);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
    digitalWrite(STEPD, LOW);
    digitalWrite(STEPS, LOW);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
  }
}


Ringrazio tanto Paolo per la sua pazienza e aspetto pazientemente qualche indicazione da chiunque ne sia interessato.

Grazie

PaoloF_60

Sergio tu mi ringrazi, ma non hai letto attentamente il mio messaggio precedente e non hai guardato attentamente il codice che ti ho allegato con tutti i commenti del caso.

Se avessi letto attentamente ti ho già spiegato nel dettaglio come funziona il sensore, non solo ti ho anche spiegato quali sono i tempi di funzionamento del sensore e come fare a mantenerli brevi.

I tempi di funzionamento io li ho misurati con l' oscilloscopio perchè in giro su internet non li trovi mica.

Unica cosa che non ti ho spiegato, ma lo faccio adesso, è perchè ho usato la pulseInLong al posto della pulseIn.

Sono due funzioni simili che fanno la stessa cosa, misurano la durata di un impulso sul piedino X con un timeout di default di 1S (secondo).

Qundi se non usi il timeout potresti fare misure della durata di un secondo che sono troppo lunghe.
Inoltre non ti interessa sapere che hai un ostacolo a due metri di distanza.
Quindi imposti timeout breve, se l' ostacolo è a più di 25 cm non ti serve saperlo.

La pulseIn funziona con gli interrupt disabilitati.

La pulseInLong funziona con gli interrupt abilitati.

Le due misure le fai all' inizio del loop principale e il controllo per come te l' ho scritto io lo fai insieme
a quelli degli altri sensori ... devi solo verificare se > 0 per come ti ho scritto la misura col timeout.

Quindi per il codice

Code: [Select]


//definizione variabili e pin

long timed=0;//misura sensore destro
long times=0;//misura sensore sinistro

#define trigerd 6//triger sensore destro
#define echod 5//echo sensore destro

#define trigers 11//triger sensore sinistro
#define echos 10//echo sensore sinistro

void setup() {

//istruzioni da aggiungere al setup

pinMode(trigerd,OUTPUT);
pinMode(trigers,OUTPUT);
pinMode(echod,INPUT);
pinMode(echos,INPUT);

digitalWrite(trigerd,LOW);//inizializzo basso
digitalWrite(trigers,LOW);

}//fine setup

void loop() {

//istruzioni da aggiungere al loop

ultraRead_D();//la funzione imposta la variabile timed
ultraRead_S();//la funzione imposta la variabile times

//i controlli diventano

if((rilevamentoD == HIGH && timed==0) && (rilevamentoS == HIGH && times==0)) {
//se sentrambi non rilevano ostacoli

if((rilevamentoD == LOW || timed > 0 ) && (rilevamentoS == HIGH && times==0)) {
//se il sensore destro rileva un ostacolo

if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && times==0)) {
//se il sensore sinistro rileva un ostacolo

if((rilevamentoS == LOW || times > 0) && (rilevamentoD == LOW || timed > 0)) {
//se entrambi i sensori rilevano un ostacolo

}//fine loop

//funzioni ultraRead_X

void ultraRead_S() {

  digitalWrite(trigers,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(trigers,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  times=pulseInLong(echos,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}


void ultraRead_D() {

  digitalWrite(trigerd,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(trigerd,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  timed=pulseInLong(echod,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}






Sergio_A

Eccomi,
ho dovuto aspettare l'arrivo dei sensori HC-SR04 e successivamente modificare l'impianto per effettuare prove di funzionamento.

Dovete scusarmi... a volte mi faccio prendere dall'entusiasmo e trascuro le informazioni che con molta pazienza mi trasmettete.

La mia inesperienza, purtroppo, non mi ha permesso di assimilare ancora i concetti pulseln e pulselnLong perché non conosco il significato di interrupt. Non capisco anche quale tipo di misura devo effettuare quando si parla di >0... devo forse diminuire il tempo alla funzione:

Code: [Select]
timed=pulseInLong(echo,HIGH,2000);//misura l' impulso alto su echo se > 2mS restituisce 0
 
per cosi diminuire o aumentare la distanza di riferimento?

Ho eseguito le modifiche allo sketch precedente come illustrato nel messaggio precedente (spero di averlo fatto correttamente) e ho riscontrato alcuni problemi:

. Quando alimento Arduino una parte dell'alimentazione sembra alimentare i due motori passo passo
  (non capisco perché visto che l'impianto è pressoché identico tranne che per i due sensori HC-SR04)

. Alimentando con i 12V i motori passo passo, i quali hanno una rotazione interrotta per un attimo
  impercettibile ogni mezzo secondo circa; la rotazione opposta sull'asse è corretta;

. Testando i sensori IR destro e sinistro, da seriale e rotazione dei motori, tutto ok (rotazione a destra,
  rotazione a sinistra, retomarcia);

. Testando i sensori HC-SR04: sensore di destra ok (ostacolo a destra), entrambi  ok (retromarcia),
  sensore di sinistra blocca entrambi i motori.

Lo sketch è:

Code: [Select]
#define DIRD 2         //direzione motore destra
#define STEPD 3        //pin di step motore destra
#define IRD 4          //sensore IR a destra
#define ECHOD 5        //echo sensore destro
#define TRIGERD 6       //triger sensore destro
#define DIRS 7         //direzione motore sinistra
#define STEPS 8        //pin di step motore sinistra
#define IRS 9          //sensore IR sinistra
#define ECHOS 10       //echo sensore sinistro
#define TRIGERS 11     //triger sensore sinistro
#define LAMA 12        //rele di controllo motore lama
#define INTERVALLO 8   //durata del movimento generale 8 * 100 (ritorno) = 800 passi per 1/2 giro ritorno = 200 per un giro completo
 
long timed=0;//misura sensore destro
long times=0;//misura sensore sinistro

int rilevamentoD = HIGH;
int rilevamentoS = HIGH;

int ritorno = 100;//durata della rotazione senza controllare nuovamente (variabile perche nel programma il robot potra adattarlo in base alle condizioni)
int velo=10;//velocita movimento da 1 a 100 ritardo step successivi
int i;

void setup()
 {
  Serial.begin(9600);  //inizio della trasmissione seriale (serve soprattutto a noi per capire a che punto del programma si trova)
  Serial.print("Mi sono acceso correttamente.");
  delay(500);

  pinMode(DIRD, OUTPUT);
  pinMode(STEPD, OUTPUT);
  pinMode(IRD, INPUT);
  pinMode(DIRS, OUTPUT);
  pinMode(STEPS, OUTPUT);
  pinMode(IRS, INPUT);
  pinMode(LAMA, OUTPUT);
  pinMode(TRIGERD, OUTPUT);
  pinMode(TRIGERS, OUTPUT);
  pinMode(ECHOD, INPUT);
  pinMode(ECHOS, INPUT);

  digitalWrite(TRIGERD,LOW);  //inizializzo basso
  digitalWrite(TRIGERS,LOW);
   
 }
 
void loop() {
 
  ultraRead_D();  //la funzione imposta la variabile timed
  ultraRead_S();  //la funzione imposta la variabile times

  rilevamentoD = digitalRead(IRD); //rileva la condizione del sensore destro
  rilevamentoS = digitalRead(IRS); //rileva la condizione del sensore sinistro
 
    if((rilevamentoD == HIGH && timed==0) && (rilevamentoS == HIGH && times==0)) { //se sentrambi non rilevano ostacoli
      Serial.print("\nVia libera!");
      for(i=0;i<ritorno;i++) {//aggiunta perchè mancante quando va dritto
        step(true, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso discorde manderanno avanti o indietro il robot!
   }
  }
  else {
    if((rilevamentoD == LOW || timed > 0 ) && (rilevamentoS == HIGH && times==0)) {//se il sensore destro rileva un ostacolo
      Serial.print("\nOstacolo a destra!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(false, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
      }
    }
    if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && times==0)) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nOstacolo a sinistra!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(true, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
      }
    }
    if((rilevamentoS == LOW || times > 0) && (rilevamentoD == LOW || timed > 0)) {//se entrambi i sensori rilevano un ostacolo
      Serial.print("\nRetromarcia!");
      for(i=0; i<ritorno; i++) {//ripeti ritorno-1 volte la funzione senza ricontrollare i sensori
        step(false, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi faranno indietreggiare il robot!
      }
    } 
  }
}

void step(boolean dirAttualeD, boolean dirAttualeS, int steps,int velo) {//velo 1 ... 100
  digitalWrite(DIRD, dirAttualeD); //invia al driver destro la direzione attuale
  digitalWrite(DIRS, dirAttualeS); //invia al driver sinistro la direzione attuale
  for(int i=0; i<steps; i++) {//ATTENZIONE: durante il ciclo non controlla i sensori!
    digitalWrite(STEPD, HIGH);
    digitalWrite(STEPS, HIGH);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
    digitalWrite(STEPD, LOW);
    digitalWrite(STEPS, LOW);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
  }
}

void ultraRead_S() {

  digitalWrite(TRIGERS,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERS,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  times=pulseInLong(ECHOS,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}


void ultraRead_D() {

  digitalWrite(TRIGERD,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERD,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  timed=pulseInLong(ECHOD,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}




Spero di non aver tralasciato nulla delle informazioni precedentemente trasmesse e aspetto con pazienza un vostro gradito aiuto.

Grazie

PaoloF_60

Code: [Select]


if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && times==0)) {//se il sensore sinistro rileva un ostacolo



per errore ho scritto times dove (rilevamentoD == HIGH && timeD == 0) col rilevamentoD devo usare timeD


ma tempo fa non si era parlato di togliere le for i=0 i<RITORNO ...

per i motori e le alimentazioni al momento non ho capito cosa succede correggi come ti ho detto sopra
per risolvere il problema del sensore hc poi rivediamo il tutto.

Quote
Non capisco anche quale tipo di misura devo effettuare quando si parla di >0... devo forse diminuire il tempo alla funzione:
Intendi timeX > 0 ? Se una times imposta il valore superiore a 0 hai un ostacolo a meno di 35cm
Imposta il valore 0 quando la distanza è maggiore di 35cm la distanza è determinata da 2000
come valore di timeout della pulsIn. Non serve variare questo valore piuttosto se superiore a 0
posso verificare la distanza dividendo il valore di timex / 58 quindi decido se sterzare o attendere
avvicinandomi all' ostacolo.

Sergio_A

Eccomi,
modifiche effettuate e problema alimentazione sembrerebbe risolto.

All'impianto ho tolto l'alimentazione dei 5V dati da Arduino e ho mantenuto invece quelli dei 12V; se non ho capito male l'alimentazione di 12V che fornisco alle schede EasyDriver servono sia ai motori che all'alimentazione della scheda stessa.

Per quanto riguarda i sensori tutto funziona regolarmente tranne per quanto riguarda la velocità dei motori in quanto girano più lentamente con una vibrazione alla quale ho risolto modificando INTERVALLO da 8 a 24
e int velo da 10 a 8 (spero di non aver fatto una cavolata).

Devi scusarmi, ma temo ancora di non aver capito dove devo intervenire per variare la distanza muro robot determinata dai due sensori HC.

Code: [Select]
#define DIRD 2         //direzione motore destra
#define STEPD 3        //pin di step motore destra
#define IRD 4          //sensore IR a destra
#define ECHOD 5        //echo sensore destro
#define TRIGERD 6       //triger sensore destro
#define DIRS 7         //direzione motore sinistra
#define STEPS 8        //pin di step motore sinistra
#define IRS 9          //sensore IR sinistra
#define ECHOS 10       //echo sensore sinistro
#define TRIGERS 11     //triger sensore sinistro
#define LAMA 12        //rele di controllo motore lama
#define INTERVALLO 24   //durata del movimento generale 8 * 100 (ritorno) = 800 passi per 1/2 giro ritorno = 200 per un giro completo
 
long timed=0;//misura sensore destro
long times=0;//misura sensore sinistro

int rilevamentoD = HIGH;
int rilevamentoS = HIGH;

int ritorno = 100;//durata della rotazione senza controllare nuovamente (variabile perche nel programma il robot potra adattarlo in base alle condizioni)
int velo=8;//velocita movimento da 1 a 100 ritardo step successivi
int i;

void setup()
 {
  Serial.begin(9600);  //inizio della trasmissione seriale (serve soprattutto a noi per capire a che punto del programma si trova)
  Serial.print("Mi sono acceso correttamente.");
  delay(500);

  pinMode(DIRD, OUTPUT);
  pinMode(STEPD, OUTPUT);
  pinMode(IRD, INPUT);
  pinMode(DIRS, OUTPUT);
  pinMode(STEPS, OUTPUT);
  pinMode(IRS, INPUT);
  pinMode(LAMA, OUTPUT);
  pinMode(TRIGERD, OUTPUT);
  pinMode(TRIGERS, OUTPUT);
  pinMode(ECHOD, INPUT);
  pinMode(ECHOS, INPUT);

  digitalWrite(TRIGERD,LOW);  //inizializzo basso
  digitalWrite(TRIGERS,LOW);
   
 }
 
void loop() {
 
  ultraRead_D();  //la funzione imposta la variabile timed
  ultraRead_S();  //la funzione imposta la variabile times

  rilevamentoD = digitalRead(IRD); //rileva la condizione del sensore destro
  rilevamentoS = digitalRead(IRS); //rileva la condizione del sensore sinistro
 
    if((rilevamentoD == HIGH && timed==0) && (rilevamentoS == HIGH && times==0)) { //se sentrambi non rilevano ostacoli
      Serial.print("\nVia libera!");
     
        step(true, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso discorde manderanno avanti o indietro il robot!
   
  }
  else {
    if((rilevamentoD == LOW || timed > 0 ) && (rilevamentoS == HIGH && times==0)) {//se il sensore destro rileva un ostacolo
      Serial.print("\nOstacolo a destra!");
     
        step(false, false, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && timed==0)) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nOstacolo a sinistra!");
     
        step(true, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0) && (rilevamentoD == LOW || timed > 0)) {//se entrambi i sensori rilevano un ostacolo
      Serial.print("\nRetromarcia!");
     
        step(false, true, INTERVALLO,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi faranno indietreggiare il robot!
     
    } 
  }
}

void step(boolean dirAttualeD, boolean dirAttualeS, int steps,int velo) {//velo 1 ... 100
  digitalWrite(DIRD, dirAttualeD); //invia al driver destro la direzione attuale
  digitalWrite(DIRS, dirAttualeS); //invia al driver sinistro la direzione attuale
  for(int i=0; i<steps; i++) {//ATTENZIONE: durante il ciclo non controlla i sensori!
    digitalWrite(STEPD, HIGH);
    digitalWrite(STEPS, HIGH);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
    digitalWrite(STEPD, LOW);
    digitalWrite(STEPS, LOW);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
  }
}

void ultraRead_S() {

  digitalWrite(TRIGERS,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERS,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  times=pulseInLong(ECHOS,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}


void ultraRead_D() {

  digitalWrite(TRIGERD,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERD,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  timed=pulseInLong(ECHOD,HIGH,2000);
  //misura l' impulso alto su echo se > 2mS restituisce 0 e torna dopo 2mS
 
}





PaoloF_60

sono stato molto impegnato e lontano da casa e pc e non ho potuto risponderti prima.

Ti ricordo che ciò che hai chiamato INTERVALLO sono effettivi passi motore. Nel tuo caso 1/8 di passo.
con un valore di 24 chiedi di fare 24/8 = 3 passi tieni presente che un giro completo sono 200 x 8 passi.
Cambierei la variabile INTERVALLO assegnandogli il nome PASSI per chiarezza.

La velocità invece è data dal tempo di pausa fra un passo e l' altro.

Per quanto riguarda i sensori ad ultrasuoni, la misura della distanza dal muro è proporzionale alla durata dell' impulso generato sul piedino echo del sensore. In particolare la distanza in cm vale durata/58 circa.

Il timeout della pulseIn o pulseInLong di default è di un secondo. La pulseiIn è bloccante, vale a dire che come una delay finchè non è terminata la misura o non scade il timeout il programma rimane bloccato sulla pulseIn. Quindi calcolando in 400cm la massima distanza misurabile dal sensore il timeout massimo che dovremmo imporre vale 400 x 58 = 23200uS. Quindi in questo caso il tempo necessario alla pulseIn per
fornire una risposta quando fuori portata sarebbe di 23mS. Con il timeout imposto a 2000 abbiamo una misura di circa 35cm, quando la misura è maggiore di 35cm la pulseIn va in timeout prima equindi termina restituendo 0 come risultato. Per rilevare distanze maggiori devi allungare il timeout della funzione. se ad esempio imponi 4000 la distanza massima rilevata sara 4000/58 = 68 cm circa.
Imponendo 5800 la distanza massima sarà circa 1 metro. E la pulseIn durerà circa 5ms se il muro è a più di 1 metro di distanza.

Spero di averti chiarito nel migliore dei modi come funziona la pulseIn è perchè mi sembra inutile misurare distanze troppo lunghe e quindi perchè ho utilizzato 2000 come valore di timeout.

Questo mantiene la durata della pulseIn abbastanza breve 2 mS circa anche quando non ci sono ostacoli entro i 35 cm.

Sergio_A

Ho svolto alcune prove e ho capito come interagire sul programma per variare la distanza rilevabile dai sensori HC; ho variato il valore 2000 uS (58/2000=35cm circa) a 1044 (58/1044=18cm) in maniera di avvicinarmi il più possibile al muro permettendo una manovra.

Fino a qui tutto ok.

Quello che ho notato invece è che dopo aver tolto tutti i cicli "for" i motori passo passo non hanno più una rotazione lineare ma tendono a vibrare, un movimento a scatti molto brevi e quando effettuano l'inversione di rotazione rallentano.

Se non ho interpretato male quello che ho letto riguardo ai motori, la variabile velo è il tempo tra un passo e l'altro, mentre la variabile che abbiamo chiamato "PASSI" è il numero che, per il valore "ritorno", determina i passi che il motore deve fare, quindi determinare il 1/2 (800 passi) giro oppure il giro completo (1600 passi).

PaoloF_60

Per il sensore HC OK tieni presente solo una cosa il sensore impiega circa 500uS per emettere il suo treno di impulsi e misurare la distanza.
 
Nella pulseIn il timeout può verificarsi per due situazioni,

1) il segnale non va al livello previsto entro il tempo di timeout, nel nostro caso alto.
2) il segnale non torna al livello precedente entro il tempo di timeout, nel nostro caso basso.

Noi stiamo sfruttando la 2 per limitare la distanza su cui lavora il sensore, e ridurre il tempo di misura.
Ma per la 1 non puoi usare timeout inferiori a 500/600 uS rischieremmo di andare in timeout prima che il sensore alzi il segnale echo, perdendo tutte le misure.

IO direi che un timeout pari a 1000  va benissimo, se poi ti vuoi avvicinare maggiormente al muro
puoi valutare la misura effettiva rilevata dal sensore.

Quando la distanza è > 0 puoi verificare se > di 5 x 58 = 290 ad esempio questo ti porta a 5cm dal muro.

Per quanto riguarda i passi motore tutto OK ... 1600 ottavi di passo per un giro.
Credo che i tuoi 24 passi siano pochi, credo che aumentandoli avrai un movimento più regolare,
partirei con valori almeno di 80 che sarebbero 10 passi interi pari ad una rotazione di 18 gradi.

Sergio_A

Grazie Paolo,

ho provato a misurare la distanza effettiva rilevata dai sensori impostando a 1mS ed ho riscontrato che è leggermente inferiore rispetto alla formula impiegata; nel nostro caso, utilizzando la formula, la distanza è di 18 cm scarsi mentre nella realtà è di 8,5 cm circa.

Code: [Select]
#define DIRD 2         //direzione motore destra
#define STEPD 3        //pin di step motore destra
#define IRD 4          //sensore IR a destra
#define ECHOD 5        //echo sensore destro
#define TRIGERD 6      //triger sensore destro
#define DIRS 7         //direzione motore sinistra
#define STEPS 8        //pin di step motore sinistra
#define IRS 9          //sensore IR sinistra
#define ECHOS 10       //echo sensore sinistro
#define TRIGERS 11     //triger sensore sinistro
#define LAMA 12        //rele di controllo motore lama
#define PASSI 80        //durata del movimento generale 8 * 100 (ritorno) = 800 passi per 1/2 giro ritorno = 200 per un giro completo
 
long timed=0;//misura sensore destro
long times=0;//misura sensore sinistro

int rilevamentoD = HIGH;
int rilevamentoS = HIGH;

int ritorno = 200;//durata della rotazione senza controllare nuovamente (variabile perche nel programma il robot potra adattarlo in base alle condizioni)
int velo=10;//velocita movimento da 1 a 100 ritardo step successivi
int i;

void setup()
 {
  Serial.begin(9600);  //inizio della trasmissione seriale (serve soprattutto a noi per capire a che punto del programma si trova)
  Serial.print("Mi sono acceso correttamente.");
  delay(500);

  pinMode(DIRD, OUTPUT);
  pinMode(STEPD, OUTPUT);
  pinMode(IRD, INPUT);
  pinMode(DIRS, OUTPUT);
  pinMode(STEPS, OUTPUT);
  pinMode(IRS, INPUT);
  pinMode(LAMA, OUTPUT);
  pinMode(TRIGERD, OUTPUT);
  pinMode(TRIGERS, OUTPUT);
  pinMode(ECHOD, INPUT);
  pinMode(ECHOS, INPUT);

  digitalWrite(TRIGERD,LOW);  //inizializzo basso destro
  digitalWrite(TRIGERS,LOW);  //inizializzo basso sinistro
   
 }
 
void loop() {
 
  ultraRead_D();  //la funzione imposta la variabile timed
  ultraRead_S();  //la funzione imposta la variabile times

  rilevamentoD = digitalRead(IRD); //rileva la condizione del sensore destro
  rilevamentoS = digitalRead(IRS); //rileva la condizione del sensore sinistro
 
    if((rilevamentoD == HIGH && timed==0) && (rilevamentoS == HIGH && times==0)) { //se sentrambi non rilevano ostacoli
      Serial.print("\nVia libera!");
     
        step(true, false, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso discorde manderanno avanti o indietro il robot!
   
  }
  else {
    if((rilevamentoD == LOW || timed > 0 ) && (rilevamentoS == HIGH && times==0)) {//se il sensore destro rileva un ostacolo
      Serial.print("\nOstacolo a destra!");
     
        step(false, false, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && timed==0)) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nOstacolo a sinistra!");
     
        step(true, true, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0) && (rilevamentoD == LOW || timed > 0)) {//se entrambi i sensori rilevano un ostacolo
      Serial.print("\nRetromarcia!");
     
        step(false, true, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi faranno indietreggiare il robot!
       
       
    } 
  }
}

void step(boolean dirAttualeD, boolean dirAttualeS, int steps,int velo) {//velo 1 ... 100
  digitalWrite(DIRD, dirAttualeD); //invia al driver destro la direzione attuale
  digitalWrite(DIRS, dirAttualeS); //invia al driver sinistro la direzione attuale
  for(int i=0; i<steps; i++) {//ATTENZIONE: durante il ciclo non controlla i sensori!
    digitalWrite(STEPD, HIGH);
    digitalWrite(STEPS, HIGH);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
    digitalWrite(STEPD, LOW);
    digitalWrite(STEPS, LOW);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
  }
}

void ultraRead_S() {

  digitalWrite(TRIGERS,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERS,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  times=pulseInLong(ECHOS,HIGH,1000);
  //misura l' impulso alto su echo se > 1mS restituisce 0 e torna dopo 1mS
 
}


void ultraRead_D() {

  digitalWrite(TRIGERD,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERD,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  timed=pulseInLong(ECHOD,HIGH,1000);
  //misura l' impulso alto su echo se > 1mS restituisce 0 e torna dopo 1mS
 
}




In questo momento il prototipo è statico e non posso verificare il comportamento reale... però volevo fare una modifica all'attuale retromarcia prima di far appoggiare le ruote a terra; per esempio:
  • Retomarcia per 3 secondi;
  • Rotazione a destra per 2 secondi.


Da profano, ho pensato a uno dei primi sketch creati per imparare, tipo il blink led, dove alla prima condizione di stato HIGH crei un ritardo (delay) di tot secondi e poi passi alla condizione di stato LOW per poi ritornare alla precedente sempre dopo un ritardo di tot secondi... ma con scarsi risultati.

Come posso far fare una seri di operazioni ad Arduino ad una determinata condizione?

Grazie

PaoloF_60

Ciao Sergio e scusami ancora per il ritardo di questa mia risposta, ho fatto una verifica ulteriore dei sensori ed in effetti il timeout da 1ms non permette di rilevare distanze superiori agli 8 cm circa. Colpa mia non mi sono ricordato che il sensore misura il tempo in cui il segnle va e torna come per un radar, quindi la lunghezza dell' impulso e doppia rispetto alla distanza da misurare. Quindi il timeout va raddoppiato.
Forse c' è anche qualche stranezza della pulsein a generare questo comportamento. Qui un link al datasheet del sensore https://www.electroschematics.com/wp-content/uploads/2013/07/HCSR04-datasheet-version-1.pdf

Ho verificato che con timeout a 2000 rilevo le distanze fino a 15/16cm regolarmente anche se la durata dell' impulso è la metà del timeout. Vedi testo allegato.

Per quanto rigurda la retromarcia perchè farla a tempo ? Generalmente ti muovi a passi non a tempo.

Quindi tot passi indietro e tot passi a destra.

Sergio_A

E' sempre un piacere rivedere un tuo post anche dopo mesi... d'altronde questo è un hobby non un lavoro, lo stress non è ammesso.

Effettivamente avevo preso la strada sbagliata: perché il tempo quando invece lavoro con i passi?

Ecco la modifica allo sketch anche se ancora ad oggi non posso provarlo con ruote a terra, quindi non so la distanza percorsa in retromarcia e i gradi di rotazione:

Code: [Select]
#define DIRD 2         //direzione motore destra
#define STEPD 3        //pin di step motore destra
#define IRD 4          //sensore IR a destra
#define ECHOD 5        //echo sensore destro
#define TRIGERD 6      //triger sensore destro
#define DIRS 7         //direzione motore sinistra
#define STEPS 8        //pin di step motore sinistra
#define IRS 9          //sensore IR sinistra
#define ECHOS 10       //echo sensore sinistro
#define TRIGERS 11     //triger sensore sinistro
#define LAMA 12        //rele di controllo motore lama
#define PASSI 80       //durata del movimento generale 8 * 100 (ritorno) = 800 passi per 1/2 giro ritorno = 200 per un giro completo
#define RETRO 8000     //durata della retromarcia
#define ROTAZIONE 4000 //durata della rotazione
 
long timed=0;//misura sensore destro
long times=0;//misura sensore sinistro

int rilevamentoD = HIGH;
int rilevamentoS = HIGH;

int ritorno = 200;//durata della rotazione senza controllare nuovamente (variabile perche nel programma il robot potra adattarlo in base alle condizioni)
int velo=10;//velocita movimento da 1 a 100 ritardo step successivi
int i;

void setup()
 {
  Serial.begin(9600);  //inizio della trasmissione seriale (serve soprattutto a noi per capire a che punto del programma si trova)
  Serial.print("Mi sono acceso correttamente.");
  delay(500);

  pinMode(DIRD, OUTPUT);
  pinMode(STEPD, OUTPUT);
  pinMode(IRD, INPUT);
  pinMode(DIRS, OUTPUT);
  pinMode(STEPS, OUTPUT);
  pinMode(IRS, INPUT);
  pinMode(LAMA, OUTPUT);
  pinMode(TRIGERD, OUTPUT);
  pinMode(TRIGERS, OUTPUT);
  pinMode(ECHOD, INPUT);
  pinMode(ECHOS, INPUT);

  digitalWrite(TRIGERD,LOW);  //inizializzo basso destro
  digitalWrite(TRIGERS,LOW);  //inizializzo basso sinistro
   
 }
 
void loop() {
 
  ultraRead_D();  //la funzione imposta la variabile timed
  ultraRead_S();  //la funzione imposta la variabile times

  rilevamentoD = digitalRead(IRD); //rileva la condizione del sensore destro
  rilevamentoS = digitalRead(IRS); //rileva la condizione del sensore sinistro
 
    if((rilevamentoD == HIGH && timed==0) && (rilevamentoS == HIGH && times==0)) { //se sentrambi non rilevano ostacoli
      Serial.print("\nVia libera!");
     
        step(true, false, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso discorde manderanno avanti o indietro il robot!
   
  }
  else {
    if((rilevamentoD == LOW || timed > 0 ) && (rilevamentoS == HIGH && times==0)) {//se il sensore destro rileva un ostacolo
      Serial.print("\nOstacolo a destra!");
     
        step(false, false, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0 ) && (rilevamentoD == HIGH && timed==0)) {//se il sensore sinistro rileva un ostacolo
      Serial.print("\nOstacolo a sinistra!");
     
        step(true, true, PASSI,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
     
    }
    if((rilevamentoS == LOW || times > 0) && (rilevamentoD == LOW || timed > 0)) {//se entrambi i sensori rilevano un ostacolo
      Serial.print("\nRetromarcia!");
     
        step(false, true, RETRO,velo);      //ATTENZIONE: i motori sono opposti sullo stesso asse quindi faranno indietreggiare il robot!
        step(false, false, ROTAZIONE,velo); //ATTENZIONE: i motori sono opposti sullo stesso asse quindi le rotazioni in senso concorde faranno ruotare il robot!
       
    } 
  }
}

void step(boolean dirAttualeD, boolean dirAttualeS, int steps,int velo) {//velo 1 ... 100
  digitalWrite(DIRD, dirAttualeD); //invia al driver destro la direzione attuale
  digitalWrite(DIRS, dirAttualeS); //invia al driver sinistro la direzione attuale
  for(int i=0; i<steps; i++) {//ATTENZIONE: durante il ciclo non controlla i sensori!
    digitalWrite(STEPD, HIGH);
    digitalWrite(STEPS, HIGH);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
    digitalWrite(STEPD, LOW);
    digitalWrite(STEPS, LOW);
    delayMicroseconds(3200/velo);//doppio ritardo fra step min 32uS puo' essere abbassato fino a 8uS
  }
}

void ultraRead_S() {

  digitalWrite(TRIGERS,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERS,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  times=pulseInLong(ECHOS,HIGH,1000);
  //misura l' impulso alto su echo se > 1mS restituisce 0 e torna dopo 1mS
 
}


void ultraRead_D() {

  digitalWrite(TRIGERD,HIGH);//impulso di triger al sensore
  delayMicroseconds(10);//temporizzo a 10uS
  digitalWrite(TRIGERD,LOW);
 
 /*misuro impulso uscita con timeout a 2000 limito la massima distanza a 25cm circa
   *e riduco il tempo di misurazione altrimenti il timeout della pulsin sarebbe 1S
   *in questo modo otterò misure fina a 25cm oppure 0 se la distanza è > 25cm per
   *tanto sarà molto semplice testare il sensore con if distanza > 0 ostacolo da evitare*/

  timed=pulseInLong(ECHOD,HIGH,1000);
  //misura l' impulso alto su echo se > 1mS restituisce 0 e torna dopo 1mS
 
}




Per quanto riguarda i sensori concordo pienamente... infatti portando il valore a 2000 (2mS) la distanza  raddoppia.

Grazie Paolo!

Go Up