Arduino: Lib de precisão para motor de passo



Hoje vou mostrar para você uma biblioteca para driver de motor de passo completa com chaves de fim de curso, movimento dos motores com aceleração e micro passo. Essa Lib, que funciona tanto no Arduino Uno quanto no Arduino Mega, permite que você movimente os motores baseado não somente em número de passos, mas também em milímetros, isso com bastante precisão.


Uma característica importante desta biblioteca é que ela te permite construir sua própria máquina CNC, que não seja necessariamente só o X, Y, mas, também, uma seccionadora, por exemplo, pois não é um GRBL pronto, mas a programação que te possibilita fazer a máquina ideal para você.
Mas, um detalhe! Esse vídeo serve apenas para aqueles que já estão habituados com a programação, ou seja, se você ainda não tem intimidade com a programação do Arduino deve assistir primeiro outros vídeos mais introdutórios que tenho no meu canal. Isso porque, neste vídeo de hoje eu falo de um assunto mais avançado, aproveitando para detalhar melhor a Lib utilizada no vídeo: Motor de passo com aceleração e fim de curso.

Biblioteca StepDriver

Essa biblioteca abrange os três tipos de drivers mais comuns do mercado: A4988, DRV8825 e TB6600. Configura os pinos dos drivers, possibilitando realizar o reset, colocar em modo Sleep, bem como ativar e desativar as saídas do motor atuando no pino Enable. Configura, ainda, as entradas dos pinos de micro passo do driver e as chaves de fim de curso e o nível de ativação das mesmas (alto ou baixo). Também conta com código de movimento do motor com aceleração contínua em mm/s², velocidade máxima em mm/s e velocidade mínima em mm/s.
Para quem assistiu as partes 1 e 2 do vídeo Motor de passo com aceleração e fim de curso, baixe essa nova biblioteca que deixo hoje para download, pois fiz alguma alterações naquele primeiro arquivo a fim de facilitar sua utilização.

Variáveis globais

Para iniciar, mostro exatamente para que serve cada uma das variáveis globais.


Funções – Configuração dos pinos do driver

Aqui descrevo alguns métodos. Defino a configuração da pinagem e os pinos do Arduino como saída.

void DRV8825::pinConfig(int ena, int m0, int m1, int m2, int rst, int slp, int stp, int dir){
    
    ENA = ena;   // Porta ativa (enable) DRV8825
    M0 = m0;   // Porta M0 do DRV8825
    M1 = m1;   // Porta M1 do DRV8825
    M2 = m2;   // Porta M2 do DRV8825
    RST = rst;   // Porta reset do DRV8825
    SLP = slp;   // Porta dormir (sleep) DRV8825
    STP = stp;   // Porta passo(step) do DRV8825
    DIR = dir;               // Porta direção (direction) do DRV8825 
   
    pinMode(RST, OUTPUT); //Define os pinos do arduino como saída 
    pinMode(SLP, OUTPUT);
    pinMode(ENA, OUTPUT);
    pinMode(M0, OUTPUT);
    pinMode(M1, OUTPUT);
    pinMode(M2, OUTPUT);
    pinMode(DIR, OUTPUT);
    pinMode(STP, OUTPUT);
}


Funções – Funções básicas do driver

Trabalhamos nesta parte a configuração do driver e suas funções básicas.

void DRV8825::reset()
{
    digitalWrite(RST, LOW);     // Realiza o reset do DRV8825
    delay (1);                  // Atraso de 1 milisegundo
    digitalWrite(RST, HIGH);    // Libera o reset do DRV8825
    delay (10);                 // Atraso de 10 milisegundos
}

void DRV8825::enable(bool state)
{
 digitalWrite(ENA, !state);// Ativa e dasativa o chip DRV8825 (FALSE = ativa, TRUE = desativa)
 delay (10);               // Atraso de 10 milisegundos
}

void DRV8825::sleep(bool state)
{
 digitalWrite(SLP, !state);// Ativa e dasativa o modo sleep do chip DRV8825 (FALSE = ativa, TRUE = desativa)
 delay (10);    // Atraso de 10 milisegundos
}


Funções – Configuração de passo do motor

Nesta etapa do código configuramos a quantidade de passos por milímetro que o motor deve realizar, bem como a quantidade de passos por volta que este o motor deve realizar.

void DRV8825::stepPerMm(double steps)//Configura a quantidade de passos por milímetro que o motor deve realizar
{
 SPM = steps;
}

void DRV8825::stepPerRound(int steps)//Configura a quantidade de passos por volta que o motor deve realizar
{
 SPR = steps;
}


Funções – Configuração do modo de passo do motor


Essa tabela expõe as definições para configuração do modo de passo do motor. Abaixo coloco alguns exemplos:

void DRV8825::stepConfig(int s) //Configura o modo do passo
{
 SCF = s;

 switch (SCF){
     case 1: FULL();
          break;
     case 2: s1_2();
          break;
     case 4: s1_4();
         break;
        case 8: s1_8();
          break;
        case 16: s1_16();
          break;
        case 32: s1_32();
          break;
        default: FULL();
          break;
      }
}







Funções – Configuração das chaves de fim de curso

Aqui eu tenho que ler os valores inteiros e booleanos. Defino se a chave ativa em alta ou em baixa, tratando ainda do pino de fim de curso máximo bem como mínimo.

void DRV8825::endstopConfig(int emin, int emax, bool level)
{
 EMAX = emax;
 EMIN = emin;
 LVL  = level;
 pinMode(EMAX, INPUT);
 pinMode(EMIN, INPUT);
}


Funções – Leitura das chaves de fim de curso


bool DRV8825::eRead(int pin) {//Lê o nível da chave defim de curso
  if (LVL && digitalRead(pin)) {//Se a chave ativa em nível ALTO
        //E a leitura da chave está ALTA
    return true;//Retorna verdadeiro(chave ativada)
  }
  if (!LVL && !digitalRead(pin))//Se a chave ativa em nível baixo
        //E a leitura da chave está BAIXA
    return true;//Retorna verdadeiro(chave ativada)

  return false;//Se não, retorna falso(chave desativada)
}

Essa parte está diferente da que consta na Lib que disponibilizei na semana passada. Por quê mudei? Pois, criei o eRead para substituir inúmeros IfThenElse aninhados. Então, aqui o eRead vai ler o LVL, o digitalRead(pin) e vai retornar VERDADEIRO. Isso tudo em Alto. Na sequência trabalho com a chave ativa em nível Baixo. Aproveito aqui para te mostrar a tabela “Verdade”.

Na imagem abaixo coloco um diagrama que vai ajudar na compreensão de que, nesta parte do código fonte eu estou movendo em direção Crescente e ainda não bati na chave de fim de curso.

bool DRV8825::canGo(bool direction) {//Determina se o motor pode se mover ou não
  if (direction && eRead(EMAX))
    return false;
  if (!direction && eRead(EMIN))
    return false;
  return true;
}



Agora, nesta imagem abaixo, mostro o motor movendo ainda na direção crescente, mas com o fim de curso máximo ativado. O mecanismo, então, deve interromper o movimento.

Abaixo mostro o mesmo movimento, mas no sentido oposto.

Aqui já com a chave de fim de curso ativada.

Funções – Configuração de movimento

A principal utilidade do método motionConfig é converter mm/s², medida utilizada nas máquinas CNC, para passos, para atender ao controlador de um motor de passo. É nesta parte, portanto, que eu instancio as variáveis para entender os passos e, não, os milímetros.

//Configuracao de movimento: Aceleracao em mm/s^2, Velocidade maxima em mm/s, velocidade minima em mm/s
void DRV8825::motionConfig(double acceleration, double maxSpeed, double minSpeed) {

  ACC = acceleration * SPM; //Converte Aceleração de: mm/s^2 para passos/s^2
  MAX_SPEED = maxSpeed * SPM; //Converte Velocidade máxima de: mm/s para passos/s

  if (minSpeed > maxSpeed) //A velocidade mínima não pode ser maior que a velocidade máxima
    MIN_SPEED = maxSpeed * SPM; //Converte Velocidade máxima de: mm/s para passos/s
  else
    MIN_SPEED = minSpeed * SPM; //Converte Velocidade mínima de: mm/s para passos/s

}


Funções – Função de Movimento

Nesta etapa tratamos do comando que move um passo na direção pretendida em um período em microssegundos. Também configuramos o pino de direção do driver, tempo de delay e direção das chaves de fim de curso.

void DRV8825::motorMove(int period, bool direction) {//Move um passo na direção solicitada em um período de microssegundos
  
  digitalWrite(DIR,direction);

  if (canGo(direction)) {//Verifica se as chaves de fim de curso estão desativadas na direção solicitada

    digitalWrite(STP, HIGH);//Altera o nível da porta STP do driver para nível alto
    delayMicroseconds(period / 2);//Aguarda meio período
    digitalWrite(STP, LOW);//Altera o nível da porta STP do driver para nível baixo
    delayMicroseconds(period / 2);//Aguarda meio período

  }
  else {//se as chaves de fim de curso estão ativadas na direção solicitada

    delayMicroseconds(period);//Aguarda todo o periodo e não move o motor
  }
}


Funções – Função de Movimento – variáveis

Nesta parte configuramos todas as variáveis que envolvem período de velocidade máxima e mínima, distância de trajetória, passos necessários para interromper a trajetória, entre outras.

void DRV8825::motorMoveTo(double distance, bool direction) 
{
  double MIN_SPEED_PERIOD = 1.0 / MIN_SPEED; //Periodo da velocidade mínima = 1/(velocidade mínima)
  double MAX_SPEED_PERIOD = 1.0 / MAX_SPEED; //Periodo da velocidade máxima = 1/(velocidade máxima)
  double ACC_SPEED_PERIOD = MIN_SPEED_PERIOD;//Periodo da velocidade de aceleracao recebe inicialmente o periodo da velocidade mínima
  unsigned long PATH_STEPS = distance * SPM; //Converte a distância da trajetória de milímetros para passos
  long STEPS_TO_STOP = PATH_STEPS / 2; //Passos para parar recebe inicialmente a metade dos passos da trajetória
  double MAX_SPEED_REACHED; //Guarda a veloidade máxima alcançada pelo motor durante a aceleração
  bool flag = true;


Funções – Função de Movimento – Aceleração


for (long i = 0; i < PATH_STEPS; i++) {//Loop responsável por toda a trajetória

    if (i < (PATH_STEPS / 2)) {//Enquanto estiver na primeira metade da trajetória

      if (ACC_SPEED_PERIOD > MAX_SPEED_PERIOD) {//Se o periodo da velocidade de aceleração for maior que a perído da velocidade máxima

        ACC_SPEED_PERIOD = 1.0 / sqrt((MIN_SPEED * MIN_SPEED) + (2.0 * ACC * i));
        //Calcula o periodo de aceleração do motor:
        //                                                                        1
        //Período da velocidade de aceleração =  ------------------------------------------------------------------
        //                                       raiz^2(Velocidade mínima^2 + 2 * aceleracao(em mm/s^2) * passo atual)

        motorMove(1000000 * ACC_SPEED_PERIOD, direction); //Converte o período de aceleração em segundos para microssegundos e move o motor em um passo na direção solicitada

        MAX_SPEED_REACHED = (1 / ACC_SPEED_PERIOD) / SPM;//Converte e guarda o período máximo alcançado para velocidade máxima alacançada: (1/periodo)/passos por mm
      }
      else //Se o periodo da velocidade de aceleração for menor ou igual que a perído da velocidade máxima
      {

Aqui exponho alguns detalhes sobre como chegamos aos dados de aceleração, a qual foi calculada através da equação de Torricelli, pois essa leva em consideração os espaços para trabalhar a aceleração e, não, o tempo. Mas, importante aqui é entender que toda essa equação se resume a apenas uma linha de código.
Identificamos na imagem acima um trapézio porque os RPMs iniciais são péssimos para maioria dos motores de passo. O mesmo ocorre com a desaceleração. Por conta disso, visualizamos um trapézio no período entre a aceleração e desaceleração.


Funções – Função de Movimento – Velocidade Contínua


 else //Se o periodo da velocidade de aceleração for menor ou igual que a perído da velocidade máxima
      {
        if (flag) {//apenas um marcador para que execute a operação apenas uma vez
          STEPS_TO_STOP = i;//Guarda o numero de passos que usados na aceleração
          MAX_SPEED_REACHED = MAX_SPEED;//A velocidade máxima alcançada torna-se a velocidade máxima do motor
          flag = false;
        }
        motorMove(1000000 * MAX_SPEED_PERIOD, direction); //Converte o período de velocidade máxima em segundos para microssegundos e move o motor em um passo na direção solicitada
      }

Aqui guardamos o número de passos usado na aceleração, prosseguimos em velocidade contínua, guardando a velocidade máxima alcançada, o que pode ser conferido na imagem abaixo.


Funções – Função de Movimento – Desaceleração


 else//Enquanto estiver na segunda metade da trajetória
    {
      if (i > PATH_STEPS - STEPS_TO_STOP) {//Determina quando o motor deve desacelerar(passos totais da trajetória menos o número de passos para parar)
        //Calcula o periodo de desaceleração do motor:
        //                                                                                                  1
        //Período da velocidade de aceleração =  ----------------------------------------------------------------------------------------------------------------
        //                                       raiz^2(Velocidade máxima alcançada^2 + 2 * -aceleracao(em mm/s^2) * (passo atual - (passos totais - passo para parar))
        ACC_SPEED_PERIOD = 1.0 / sqrt((MAX_SPEED_REACHED * MAX_SPEED_REACHED) + 2.0 * (ACC * -1.0) * (i - (PATH_STEPS - STEPS_TO_STOP)));
        motorMove(1000000 * ACC_SPEED_PERIOD, direction); //Converte o período de aceleração em segundos para microssegundos e move o motor em um passo na direção solicitada
      }
      else//Se ainda não alcançada a desaceleração
      {
        motorMove(1000000 * MAX_SPEED_PERIOD, direction); //Converte o período de velocidade máxima em segundos para microssegundos e move o motor em um passo na direção solicitada

      }

Aqui temos uma outra equação, desta vez com valor de aceleração negativo. A mesma também é exposta em uma linha de código, que representa, na imagem abaixo, o retângulo identificado como Desaceleração.


Funções – Função de Movimento – Velocidade Contínua


 else//Se ainda não alcançada a desaceleração
      {
        motorMove(1000000 * MAX_SPEED_PERIOD, direction); //Converte o período de velocidade máxima em segundos para microssegundos e move o motor em um passo na direção solicitada

      }
    }
  }
}

Voltamos a velocidade contínua para trabalhar a segunda metade da trajetória, conforme visto abaixo.


Funções – Função de Movimento – Mover Voltas

Nesta parte movemos o motor em um determinado número de voltas na direção pretendida, convertendo o número de voltas em milímetros. Por fim, movemos o motor na direção solicitada.

void DRV8825::motorMoveRounds(int rounds, bool direction)//(voltas, direção)
{
 double distance = (rounds * SPR )/SPM;
 motorMoveTo(distance, direction);
 
}


Gráfico de movimento – Velocidade em função da Posição

Neste gráfico tenho dados que foram extraídos da equação que usamos na parte de Aceleração. Peguei os valores e joguei na serial do Arduino e, desta, para o Excel, o que resultou nesta tabela, que demonstra o avanço do passo.

Gráfico de movimento – Período em função da Posição

Aqui pegamos a posição, em passos, a velocidade e convertemos para período, em microssegundo. Percebemos nesta etapa que o período é inversamente proporcional à velocidade.


Gráfico de movimento – Velocidade em função do Instante

Por fim, temos a velocidade em função do instante e, por conta disso temos uma reta, já que é a velocidade em função do tempo.


Faça o download dos arquivos:

6 comentários:

  1. Parabéns pelo canal e o blog, muito bom o material.
    Só gostaria de informar que o arquivo "http://download.fernandok.com/StepDriver.rar" está corrompido, erro ao abrir.

    ResponderExcluir
    Respostas
    1. O problema era a versão do winrar, atualizei e resolveu.

      Excluir
    2. Que bom que deu certo, amigo! Abraço e até a próxima!

      Excluir
  2. Muito obrigado por compartilhar tanto conhecimento conosco.

    ResponderExcluir
  3. Opa amigo vc faz projeto por encomenda digo código para usar no arduino ou esp8266 nodemcu ?

    ResponderExcluir

Tecnologia do Blogger.