quinta-feira, novembro 01, 2012

Motores de Passo: Aperfeiçoando o controle com Arduino e L293D

Vamos agora aperfeiçoar o que vimos no post anterior e operar em "full step" e acrescentar sensores de fim de curso. O driver utilizado continua sendo o L293D.



Full Step

Na operação Full Step, com um motor bipolar, acionamos sempre as duas bobinas do motor, de forma que uma esteja empurrando e a outra puxando. Isto resulta em maior torque e uma operação mais suave. A figura abaixo mostra a tensão aplicada nas bobinas.


Para implementar isto, utilizei um variável (que chamei de fase) que varia ciclicamente de 0 a 3. Para dar um passo basta posicionar as entradas das pontes H conforme o valor atual de fase:
  1. void Passo ()  
  2. {  
  3.   switch (fase)  
  4.   {  
  5.     case 0:  // + -  
  6.       digitalWrite (L293_INP1, HIGH);  
  7.       digitalWrite (L293_INP2, LOW);  
  8.       digitalWrite (L293_INP3, LOW);  
  9.       digitalWrite (L293_INP4, HIGH);  
  10.       break;  
  11.     case 1:  // + +  
  12.       digitalWrite (L293_INP1, HIGH);  
  13.       digitalWrite (L293_INP2, LOW);  
  14.       digitalWrite (L293_INP3, HIGH);  
  15.       digitalWrite (L293_INP4, LOW);  
  16.       break;  
  17.     case 2:  // - +  
  18.       digitalWrite (L293_INP1, LOW);  
  19.       digitalWrite (L293_INP2, HIGH);  
  20.       digitalWrite (L293_INP3, HIGH);  
  21.       digitalWrite (L293_INP4, LOW);  
  22.       break;  
  23.     case 3:  // - -  
  24.       digitalWrite (L293_INP1, LOW);  
  25.       digitalWrite (L293_INP2, HIGH);  
  26.       digitalWrite (L293_INP3, LOW);  
  27.       digitalWrite (L293_INP4, HIGH);  
  28.       break;  
  29.   }  
  30.     delay (DELAY);  
  31. }  
Para andar para frente ou para trás basta incrementar ou decrementar fase, em módulo 4. Para não precisar de divisão, pode ser usando um AND. O incremento fica

fase = (fase + 1) & 3;

O decremento poderia ser feito de outras formas, mas preferi aproveitar algumas propriedades da aritmética modular e usar

fase = (fase + 3) & 3;

Se quiser, experimente a fórmula com fase variando de 0 a 3 e confirme que o resultado varia, respectivamente,  de 3 a 0.

Sensor de Fim de Curso

Minha tentativa inicial foi usar botões simples para detectar quando o carro chega nos extremos. Entretanto, o motor não teve força suficiente para acioná-los. Passei então a usar reed relays acionados por um imã:


Um lado dos sensores é ligado direto a terra e o outro a uma entrada digital. Acionando os resistores de "pullup" internos ao ATmega, o sinal será alto quando o sensor nâo estiver acionado (chave aberta). Quando o sensor é acionado o sinal passa a ser lido em nível baixo.

Calibração

Resolvi não deixar fixo no software qual sensor indica qual extremo e quantos passos existem entre eles. A rotina de calibração obtêm automaticamente estas informações.
  1. void Calibra ()  
  2. {  
  3.   digitalWrite (L293_ENA1, HIGH);  
  4.   digitalWrite (L293_ENA2, HIGH);  
  5.     
  6.   // Afasta dos sensores  
  7.   fase = 0;  
  8.   if (digitalRead(FC1) == LOW)  
  9.   {  
  10.     for (int i = 0; i < 20; i++)  
  11.     {  
  12.       fase = (fase+1) & 3;  
  13.       Passo ();  
  14.     }  
  15.     if (digitalRead(FC1) == LOW)  
  16.     {  
  17.       for (int i = 0; i < 20; i++)  
  18.       {  
  19.         fase = (fase+3) & 3;  
  20.         Passo ();  
  21.       }  
  22.     }  
  23.   }  
  24.   if (digitalRead(FC2) == LOW)  
  25.   {  
  26.     for (int i = 0; i < 20; i++)  
  27.     {  
  28.       fase = (fase+1) & 3;  
  29.       Passo ();  
  30.     }  
  31.     if (digitalRead(FC2) == LOW)  
  32.     {  
  33.       for (int i = 0; i < 20; i++)  
  34.       {  
  35.         fase = (fase+3) & 3;  
  36.         Passo ();  
  37.       }  
  38.     }  
  39.   }  
  40.   
  41.   // Procura o mínimo  
  42.   for (int limite = 10000; limite > 0; limite--)  
  43.   {  
  44.     fase = (fase+3) & 3;  
  45.     Passo();  
  46.     if (digitalRead(FC1) == LOW)  
  47.     {  
  48.       fcMin = FC1;  
  49.       fcMax = FC2;  
  50.       break;  
  51.     }  
  52.     if (digitalRead(FC2) == LOW)  
  53.     {  
  54.       fcMin = FC2;  
  55.       fcMax = FC1;  
  56.       break;  
  57.     }  
  58.   }  
  59.     
  60.   // Procura o maximo  
  61.   posMax = 0;  
  62.   for (int limite = 10000; limite > 0; limite--)  
  63.   {  
  64.     posMax++;  
  65.     fase = (fase+1) & 3;  
  66.     Passo();  
  67.     if (digitalRead(fcMax) == LOW)  
  68.       break;  
  69.   }  
  70.   posAtual = posMax;  
  71.     
  72.   digitalWrite (L293_ENA1, LOW);  
  73.   digitalWrite (L293_ENA2, LOW);  
  74. }  
O código completo pode ser baixado dos arquivos do blog (está no arquivo L293D_Passo3.zip). O vídeo abaixo mostra o teste em funcionamento:








Nenhum comentário: