Go Down

Topic: Problema controllo stepper motor mediante encoder ottico (Read 1 time) previous topic - next topic

nininfarina

ciao a tutti! premetto col dire che ho iniziato ad interfacciarmi con il mondo Arduino da poco più di un mese per via della mia passione per il modellismo dinamico e quindi come è giusto che sia mi son scontrato con il mio primo piccolo grande problema.

Ad onor del vero come primo progettino ho deciso di cimentarmi nella realizzazione di un modellino che non ha propriamente le sembianze di una macchina o di una barca ma, più banalmente, ho pensato di sfruttare uno stepper motor unipolare ed uno switch ottico ( che avevo casa in disuso ) per poter iniziare ad imparare a controllare il funzionamento del motore.

Ingredienti HW: Arduino UNO, stepper motor unipolare, switch ottico modello OPB830W, ULN2003A ( per pilotare il motore ).
ingredienti SW: Dato che quotidianamente ho a che fare con segnali EMG ( potenziali elettrici generati dai muscoli ) ho scritto uno script matlab che rilevasse gli istanti di attivazione presenti nel mio segnale e in output ho ottenuto un segnale ad onda quadra di ampiezza pari a  0 ed 1 in base se il potenziale d'azione sia sotto o sopra soglia. Ho quindi salvato il vettore contenente questo segnale ad onda quadra pronto per darlo in pasto ad arduino.

Ho fatto il cablaggio di tutto il mio circuito e scritto uno sketch su Arduino per far si che il motore ruoti in senso orario quando il segnale in ingresso è a valore pari a 1 e poi ruoti in senso antiorario appena il segnale torni a 0.

Fin qui sembrerebbe tutto funzionare ( IMPORTANTE: il segnale ad onda quadra è inviato direttamente da Matlab ad Arduino ) il problema però è che non riesco ad imporre un controllo sulla rotazione del motore mediante il mio encoder "artigianale" ( in quanto è uno switch ottico con rotella dotata di finestratura ).

OBIETTIVO: far si che il motore parta dalla sua condizione di equilibrio e CONTI i passi che fa e che se il contatore arriva ad un certo valore ( esempio max 15 passi ) lui si FERMI anche se il segnale in ingresso è ancora a 1 e quindi gli imporrebbe di continuare a ruotare.
Mi piacerebbe anche valutare la velocità di rotazione.

PROBLEMA RISCONTRATO: arduino legge correttamente il segnale ricevuto dallo switch ottico ma il motore continua a girare a suo piacere pur avendogli imposto l obbligo di ascoltare lo switch ottico. ( ovviamente ho sbagliato nella compilazione dello sketch ma non ho grandi competenze nel campo ). DOMANDA: la mia rotella è dotata di una sola finestrella e quindi ottengo un segnale ALTO ( 1 ) solo in coincidenza di esso e per il resto solo 0 --> ma anche se è a zero posso contare quante volte va a zero per contare i passi giusto??  ( non vorrei il problema fosse anche qui ).

SKETCH:

Code: [Select]
/*dichiarazione delle variabili*/
char str[50]="stringa";   // massima lunghezza stringa è di 49 char elementi più 1 di terminazione per un totale di 50x8 bit così inizializzandola preparo arduino a riservargli un certo spazio di memoria
int i=0;   
double val=0;
float msv = 0;
int delaySerial=50;
int pinMotFwd1=8;
int pinMotFwd2=9;
int pinMotRwd1=10;
int pinMotRwd2=11;
int encoderIn=3;
int motMinFast=400;//sono dei delay tra un cambio e l'altro di polarizzazione
int motMaxFast=5;
int motStatus=0;
int maxStepNum=8;//il numero di step per volta che farà il motore è 2
volatile int scan=0;


void setup()
{
  Serial.begin(9600); //apertura porta seriale con baudrate
  pinMode(pinMotFwd1,OUTPUT);
  pinMode(pinMotFwd2,OUTPUT);
  pinMode(pinMotRwd1,OUTPUT);
  pinMode(pinMotRwd2,OUTPUT);
  pinMode(encoderIn,INPUT);

  for (i=0;i<50;i++)//inizializzo stringa per sicurezza ( i da 0 al 50 elemento della stringa )
    {
      str[i]=' '; 
    }
  maxStepNum=maxStepNum/2;
  digitalWrite(encoderIn,LOW);
 
}

void loop()

  attachInterrupt(1,atRiseIn,RISING);
  motor_rwd(100);
}



void motor_fwd(int a)
{
  if(a < motMinFast && a > motMaxFast)
  {
    digitalWrite(pinMotFwd1,HIGH);
    digitalWrite(pinMotFwd2,LOW);
    digitalWrite(pinMotRwd1,LOW);
    digitalWrite(pinMotRwd2,LOW);
    delay(a);
    motStatus++;
   
    digitalWrite(pinMotFwd1,LOW);
    digitalWrite(pinMotFwd2,HIGH);
    digitalWrite(pinMotRwd1,LOW);
    digitalWrite(pinMotRwd2,LOW);
    delay(a);
    motStatus++;
   
  }
  else
  {
    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
  }
}


void motor_rwd(int a)
{
  if(a < motMinFast && a > motMaxFast)
  {
    digitalWrite(pinMotFwd1,LOW);
    digitalWrite(pinMotFwd2,LOW);
    digitalWrite(pinMotRwd1,HIGH);
    digitalWrite(pinMotRwd2,LOW);
    delay(a);
    motStatus--;
   
    digitalWrite(pinMotFwd1,LOW);
    digitalWrite(pinMotFwd2,LOW);
    digitalWrite(pinMotRwd1,LOW);
    digitalWrite(pinMotRwd2,HIGH);
    delay(a);
    motStatus--;
  }
  else
  {
    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
  }
}

void atRiseIn()
{
  detachInterrupt(1);
  while(1)
  {
    if(motStatus > maxStepNum)
   {
     motStatus=0;
     break;
   }
    if(Serial.available() > 0)     // se non c'è alcun valore sul buffer ( nella comunicazione tra matlab ed arduino ) non fa nulla di questo   ciclo...se invece c'è un qualsiasi valore entra nell'if
      {
        i=0;
        while(Serial.available() >0 )   // uso un while perchè non so quanti elementi ho sul buffer
        {
          str[i]=Serial.read();i++;     // scrive il primo char del buffer nell'elemento i della stringa e poi incrementa i di 1
          delay(delaySerial);
        }
        str[i]='\0';   
       
        val=atof(str);   
   
        if( val > 0) msv = 100;  // se val che fornisce matlab è >0 scrivi MSV=100  ( è un controllo per vedere se avviene la comunicazione )
        else  msv = 0;             // SENNò scrivi 0
       
        Serial.println(msv);   // manda sul buffer seriale ( così lo stampa nel vettore MSV di matlab il quale lo plotta quando terminato )
       
        delay(delaySerial);   // così do il tempo a matlab di fare i suoi processi
   
        motor_fwd(msv);
      }
  }
}


grazie mille e scusate la lunghezza del messaggio ma ho cercato di essere il più esaustivo possibile

Go Up