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; } }
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.
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:
9 Comentários
Ficou bem detalhado! Parabéns!
ResponderExcluirParabéns pelo canal e o blog, muito bom o material.
ResponderExcluirSó gostaria de informar que o arquivo "http://download.fernandok.com/StepDriver.rar" está corrompido, erro ao abrir.
O problema era a versão do winrar, atualizei e resolveu.
ExcluirQue bom que deu certo, amigo! Abraço e até a próxima!
ExcluirMuito obrigado por compartilhar tanto conhecimento conosco.
ResponderExcluirOpa amigo vc faz projeto por encomenda digo código para usar no arduino ou esp8266 nodemcu ?
ResponderExcluirBoa noite Koyanagi,
ResponderExcluirParabéns pela Biblioteca. pretendo testá-la.
Se pretende aumentar sua divulgação, sugiro que disponibilize-a no GitHub e transforme-a em Arduino oficial. Informando também o
Veja um exemplo = https://github.com/Stan-Reifel/FlexyStepper
Abraços e obrigado.
Gustavo Murta
Informando também o tipo de licença de uso.
ExcluirObrigado.
Gustavo Murta
Olá Fernando tudo bem tenho um Arduino uno com uma sheild com driver a4988 quero fazer um sistema com um botão ligado para controlar o motor de passo para um lado até chegar no fim de curso 0 e quando desligar o botão ele vire para outro lado até chegar no fim de curso 1 entendeu se puder me ajudar fico grato
ResponderExcluir