Agora que o temos um servo funcional, que foi produzido nos dois primeiros vídeos desta série Motor de Passo, que tal aumentar o arsenal de controle introduzindo um controle via serial do arduino? Continuando a série, vamos implementar funções de comando para o servo que permitirão não só posicioná-lo, mas também criar ajustes e até mesmo medir sua posição verdadeira.
Características principais
Permite comandos através da
comunicação serial.
Flexibilidade nas
configurações do software, permitindo formas de controle variadas.
Flexibilidade na montagem de
hardware, permitindo variações de motores, drivers e sensores.
Retorno da informação de
posição real através da leitura do sensor.
Montagem
Continuaremos utilizando a
mesma montagem anterior. Mas, deixaremos somente o potenciômetro de leitura do
eixo.
O potenciômetro continuará
funcionando como um sensor da posição atual do eixo. Para isso vamos prender o
eixo do motor ao manípulo do potenciômetro.
Conectaremos o potenciômetro a
entrada analógica A0.
·
O EIXO conectaremos ao pino A0 (fio roxo).
·
A alimentação de 5V (fio verde).
·
A referência GND (fio preto).
ATENÇÃO!!!
Antes de prender o potenciômetro
sensor ao eixo, teste a montagem para verificar se a rotação está ocorrendo no
sentido correto, ou seja, ao comandar um aumento de posição o motor deve girar
no sentido de aumentar o potenciômetro sensor.
Se a rotação estiver ocorrendo
ao contrário, simplesmente inverta a polarização do potenciômetro.
Como o torque do motor de
passo costuma ser alto, ele pode danificar o potenciômetro sensor tentando
levá-lo para uma posição que não pode ser alcançada.
Montagem do circuito
Entendendo o programa (Declarações)
Código – Fonte do Arduino
Declarações Globais:
(constantes)
Começamos definindo constantes
que representarão os pinos D2, D3, D4 e D5 do Arduino. Estes pinos serão os
responsáveis pela transmissão da sequencia de acionamento para o driver.
A constante EIXO refere-se ao
pino A0 utilizado pelo potenciômetro sensor.
// Declaração Global de constantes que representarão os pinos do Arduino const byte INPUT_1 = 2; //Pinos de controle do L298N const byte INPUT_2 = 3; const byte INPUT_3 = 4; const byte INPUT_4 = 5; const byte EIXO = A7; // Potenciômetro do EIXO.
Declarações Globais:
(Variáveis)
Agora veremos que temos novas
variáveis para o controle do Servo Motor de Passo.
inc_dec – Armazena o
incremento/decremento da posição.
retardo_entre_os_passos –
define o retardo para mudança de passo.
tolerancia – define a precisão
do ajuste da posição.
leitura_comando – armazena o
valor da posição alvo recebida pelo comando.
leitura_eixo – armazena o
valor da posição atual do eixo.
passo – armazena o passo atual
da sequencia de passos.
limite_inferior – armazena o
valor usado para definir a posição mínima de ajuste.
limite_superior – armazena o
valor usado para definir a posição máxima de ajuste.
comando_recebido – armazena o
comando recebido pela serial.
recepcao_completa – sinaliza
se a recepção do dado foi completada.
//Variáveis globais int inc_dec = 1; //Valor usado como incremento e decremento da posição (Comandos + e -) int retardo_entre_os_passos = 3; //constante que determinará a retardo entre os passos do ajuste do motor int tolerancia = 1; //constante que determinará uma tolerância mínima para o ajuste int leitura_comando = 510; // Variável que armazena o valor da leitura do COMANDO. int leitura_eixo = 0; // Variável que armazena o valor da leitura do SENSOR DO EIXO. int passo = 0; //Variável que armazena o passo atual. int limite_inferior = 420; //limite inferior para o posicionamento int limite_superior = 620; //limite superior para o posicionamento String comando_recebido = ""; //String que armazena os dados recebido boolean recepcao_completa = false; //sinalizador de dados aguardando leitura
Entendendo o programa (Setup)
Setup()
Na função setup(), ajustamos
os pinos digitais como saídas, o pino analógico como entrada. Então iniciamos a
função Serial. Para a recepção reservamos 200 bytes para o comando recebido
(mais que suficiente).
Lemos a posição inicial do
eixo e executamos uma função que envia pela serial uma mensagem de
configurações atuais e lista de comandos para o usuário.
void setup() { // Ajustando os pinos do Arduino para operarem como saídas digitais pinMode(INPUT_1, OUTPUT); pinMode(INPUT_2, OUTPUT); pinMode(INPUT_3, OUTPUT); pinMode(INPUT_4, OUTPUT); // Ajustando os pinos do Arduino resposáveis pela leitura do potenciômetro pinMode(EIXO, INPUT); //Inicia a comunicação serial Serial.begin(9600); // reserva 200 bytes de buffer para dados recebidos comando_recebido.reserve(200); // Determina sua posição inicial leitura_eixo = analogRead(EIXO); //envia uma mensagem de inicio pela serial mensagem(); }
Entendendo o programa (mensagem)
A função mensagem é uma série
de “prints”, enviados pela serial para tornar mais amigável a manipulação do
programa. Servindo de orientação.
Ela ainda faz uma chamada à
função interpretadora de comando solicitando uma leitura dos valores das
variáveis. Veremos essa função mais a frente.
Observação:
A função mensagem é opcional e
pode ser removida do programa, uma vez que o usuário já esteja acostumado com a
lista de comandos.
void mensagem() { /* Envia pela serial uma mensagem inicial com algumas informações como ajustes do servo e comandos disponíveis. Esta função é opcional. Pode ser retirada do programa sem consequencias */ Serial.println("Servo com Motor de Passo e Controle Serial\n"); Serial.println("Ajustes atuais:"); interpretador("L"); Serial.println(""); Serial.println("Lista de comandos\n"); Serial.println("L - Ler as configuracoes atuais"); Serial.println("A# - Ajusta a posicao para #"); Serial.println("M# - Ajusta para a posicao MEDIA "); Serial.println("R# - Ajusta a rapidez com que os passos sao dados"); Serial.println("S# - Ajusta o valor do limite superior"); Serial.println("I# - Ajusta o valor do limite inferior"); Serial.println("T# - Ajusta o valor de desvio toleravel"); Serial.println("+# - Incrementa o passo em #"); Serial.println("-# - Decrementa o passo em #"); }
Exemplo da mensagem enviada - Informações e Comandos
Entendendo o programa (Loop)
Loop():
Na função loop(), lemos
novamente a posição atual do eixo e em seguida verificamos se existe alguma
recepção completa de dados, usando a variável sinalizadora recepcao_completa.
Se esta variável for verdadeira, passamos o controle do programa para a função
interpretadora do comando. Se não houver repetimos o mesmo processo de ajuste
que fizemos antes utilizando o valor contido na variável leitura_comando como alvo de ajuste e tolerancia como
determinante da precisão do ajuste.
void loop() { //leitura do potenciômetro de posição do eixo leitura_eixo = analogRead(EIXO); // verifica se há dados disponíveis if (recepcao_completa == true) { //Envia o comando recebido para a função que interpretará o comando interpretador(comando_recebido); //reinicia as variáveis de recepção comando_recebido = ""; recepcao_completa = false; } // Avaliação da direção do movimento if (leitura_eixo < (leitura_comando - tolerancia)) { girar(1); //Girar o EIXO no sentido de AUMENTAR a leitura do sensor } if (leitura_eixo > (leitura_comando + tolerancia)) { girar(-1); //Girar o EIXO no sentido de REDUZIR a leitura do sensor } // Aguarde para repetir delay(retardo_entre_os_passos); }
Relembrando, para o cálculo da
posição alvo incluímos um valor que indica a tolerância do posicionamento. Isso
nos permitirá lidar com ruídos na leitura simplesmente aumentando a faixa alvo.
Entendendo o programa (girar)
A função girar funciona da
mesma forma que vimos anteriormente.
girar (int direcao)
A função girar receberá um
parâmetro que indicará para qual lado o motor deverá girar.
Este parâmetro é enviado pela
avaliação dos valores que ocorre no loop, como vimos a pouco.
O valor do parâmetro “direcao”
determinará se o passo deve ser incrementado ou decrementado.
Criamos essa função
separadamente somente para ilustrar melhor o funcionamento do programa.
Poderíamos ter incluído este código diretamente na avaliação que ocorre no
loop.
//Função para girar o motor na direcao avaliada void girar(int direcao) { // Girar INCREMENTANDO o PASSO if (direcao > 0) { passo++; if (passo > 3) { passo = 0; } } //Girar DECREMENTANDO o passo else { passo--; if (passo < 0 ) { passo = 3; } } //Atualiza o passo ajustar_passo(passo); }
Entendendo o programa
(ajustar_passo)
A função ajustar_passo ativa
as bobinas na sequência correta.
//Função para atualização do passo void ajustar_passo (int bobina) { switch (bobina) { //PASSO 1 case 0: digitalWrite(INPUT_1, HIGH); digitalWrite(INPUT_2, LOW); digitalWrite(INPUT_3, LOW); digitalWrite(INPUT_4, LOW); break; ///PASSO 2 case 1: digitalWrite(INPUT_1, LOW); digitalWrite(INPUT_2, HIGH); digitalWrite(INPUT_3, LOW); digitalWrite(INPUT_4, LOW); break; //PASSO 3 case 2: digitalWrite(INPUT_1, LOW); digitalWrite(INPUT_2, LOW); digitalWrite(INPUT_3, HIGH); digitalWrite(INPUT_4, LOW); break; //PASSO 4 case 3: digitalWrite(INPUT_1, LOW); digitalWrite(INPUT_2, LOW); digitalWrite(INPUT_3, LOW); digitalWrite(INPUT_4, HIGH); break; } }
Entendendo o programa (serialEvent)
serialEvent
A função serialEvent() é uma
função do Arduino que dispara automaticamente sempre que um dado é recebido
pela serial.
Note que não precisamos
explicitar nenhuma chamada para esta função pois, uma vez que um dado é recebido,
o fluxo do programa é interrompido e esta função é chamada para manipular os dados
recebidos.
Fazemos isso verificando se há
bytes no buffer de recepção serial do Arduino usando a função
Serial.available(). Enquanto houver, armazenamos cada byte na variável caracter
e adicionamos à variável comando_recebido até que um caractere de nova linha
seja recebido, sinalizando o fim do comando ou até que se esgotem os bytes do
buffer de recepção.
void serialEvent() { /* A função SerialEvent ocorre sempre que um novo byte chegar na entrada RX, interrompendo a execução normal do programa e retornando depois de executada */ while (Serial.available()) { // captura o novo byte recebido e armazena como caracter char caracter = (char)Serial.read(); // adiciona o novo caracter a variável comando_recebido: comando_recebido += caracter; // se o novo caracter recebido é um caracter de nova linha (\n), //então muda o valor do sinalizador de recepção completa para que o //possamos utilizar o comando recebido if (caracter == '\n') { recepcao_completa = true; } } }
Entendendo o programa (Interpretador de comandos)
Cascata de ‘if’...
Interpretador de comandos – Comando “L”
A função interpretadora de
comandos é uma coleção de verificações da primeira letra do comando recebido.
Cada letra representa um comando e os dados seguintes servirão de argumentos
para este comando, isso se houver.
O primeiro comando é o comando
“L” que executa uma leitura de todas as variáveis de controle e as envia para o
usuários através da serial.
//Esta função é responsável pela interpretação de cada comando void interpretador(String comando) { if (comando.startsWith("L")) //LEITURA do estado atual { Serial.println("___________________________"); Serial.print("Posicao (und.): "); Serial.println(leitura_eixo); Serial.print("Retardo entre os passos (ms): "); Serial.println(retardo_entre_os_passos); Serial.print("Tolerancia (und.): "); Serial.println(tolerancia); Serial.print("Limite Inferior (und.): "); Serial.println(limite_inferior); Serial.print("Limite Superior (und.): "); Serial.println(limite_superior); Serial.println("___________________________"); Serial.flush(); }
Interpretador de comandos – Comando “T”
O comando “T” lê o restante
dos bytes da variável comando, após a primeira letra e usa estes valores para
ajustar o valor da variável tolerancia.
Note que usamos o método
.substring para cortar da segunda posição (a contagem das posições das strings
começam em zero), até o comprimento total da variável comando. Para obter o
comprimento usamos o método .length().
Por fim, usamos ainda o método
.toInt() para converter este valor em um inteiro.
//determina o valor da TOLERÂNCIA do ajuste if (comando.startsWith("T")) { //obtém somente o valor do comando recebido e o converte para inteiro tolerancia = comando.substring(1, comando.length()).toInt(); }
Interpretador de comandos – Comando “R”
O comando “R” é responsável
pelo ajuste da variável retardo_entre_os_passos. Este retardo é importante para
controlar a rapidez do movimento. Ela substituiu a variável velocidade que
utilizamos antes (somente mudamos o nome).
O argumento para esse comando
é capturado da mesma forma que o comando anterior.
Depois de recebido o valor,
ele é verificado. O valor deste retardo não pode ser muito pequeno porque faria
o motor pular passos. No nosso caso, o limite é 3 milissegundos.
// Define o RETARDO entre cada mudança de passo if (comando.startsWith("R")) { //obtém somente o valor do comando recebido e o converte para inteiro retardo_entre_os_passos = comando.substring(1, comando.length()).toInt(); /* Verifica se este valor é menor que 3ms. Se a mudança de passos for muito rápida o motor pode não ser capaz de girar e pode perder passos. Se uma valor menor que 3 for recebido, este valor será ignorado e o valor 3 será atribuido. */ if(retardo_entre_os_passos < 3){retardo_entre_os_passos =3;} }
Interpretador de comandos – Comandos “I” e “S”
Os comando “I” e “S” servem
para ajustar o valor das variáveis que controlam os limites do movimento do
servo.
Sendo “I” paro limite inferior
e “S” para o limite superior.
A recepção dos valores ocorre
praticamente da mesma forma que os casos anteriores.
//Define o limite INFERIOR para posicionamento. if (comando.startsWith("I")) { //obtém somente o valor do comando recebido e o converte para inteiro limite_inferior = comando.substring(1, comando.length()).toInt(); /* Verifica se este valor é menor que 0. Como estamos utilizando diretamente a leitura da porta analógica A0 (0 a 1023), este valor não pode ser negativo. */ if(limite_inferior < 0){limite_inferior = 0;} } //Define o limite SUPERIOR para posicionamento if (comando.startsWith("S")) { //obtém somente o valor do comando recebido e o converte para inteiro limite_superior = comando.substring(1, comando.length()).toInt(); /* Verifica se este valor é maior que 1023. Como estamos utilizando diretamente a leitura da porta analógica A0 (0 a 1023), este valor não pode ser maior que 1023. */ if(limite_superior > 1023){limite_superior = 1023;} }
Interpretador de comandos – Comando “M”
O comando “M” calcula o valor
da posição MÉDIA entre os limites SUPERIOR e INFERIOR e atribui este valor a
variável leitura_comando, tornando-se assim o alvo do ajuste.
Após o comando “M” o servo
sempre se posicionará na posição intermediária, entre a posição máxima e mínima
ajustadas.
//Ajusta o servo para uma posição MÉDIA entre os LIMITES if (comando.startsWith("M")) { //Calcula a posição MÉDIA leitura_comando = (limite_superior + limite_inferior) / 2; }
Interpretador de comandos – Comandos “+” e “-”
Os comandos “+” e “-”
incrementam e decrementam, respectivamente, a posição do servo, em passos
definidos pelo valor da variável inc_dec.
O valor desta variável pode
ser ajustado como um argumento destes dois comandos.
Uma vez ajustada, não é
necessário que se envie novamente o valor do incremento ou decremento, a menos
que o intuito seja realmente altera-la.
//INCREMENTA a posição um ajuste além da tolerância if (comando.startsWith("+")) { //obtém somente o valor do comando recebido e o converte para inteiro int temp = comando.substring(1, comando.length()).toInt(); // Verifica se o valor recebido é maior que 0 if(temp > 0){inc_dec = temp;} //Calcula a nova posição leitura_comando = leitura_eixo + inc_dec; /* Verifica se a posição solicitada está dentro do limite SUPERIOR. Se for superado, o valor será ignorado e o valor limite será tomado como novo valor. */ if (leitura_comando > limite_superior) { leitura_comando = limite_superior; } } //DECREMENTA a posição um ajuste além da tolerância if (comando.startsWith("-")) { //obtém somente o valor do comando recebido e o converte para inteiro int temp = comando.substring(1, comando.length()).toInt(); // Verifica se o valor recebido é maior que 0 if(temp > 0){inc_dec = temp;} //Calcula a nova posição leitura_comando = leitura_eixo - inc_dec; /* Verifica se a posição solicitada está dentro do limite INFERIOR. Se for superado, o valor será ignorado e o valor limite será tomado como novo valor. */ if (leitura_comando < limite_inferior) { leitura_comando = limite_inferior; } }
Interpretador de comandos – Comando “A”
O comando “A” é responsável
pelo o AJUSTE da posição do servo. A nova posição é o argumento deste comando.
Se o argumento for omitido, será considerado zero e o servo moverá para a
posição mínima.
//AJUSTA para a posição contida no comando if (comando.startsWith("A")) { //obtém somente o valor do comando recebido e o converte para inteiro leitura_comando = comando.substring(1, comando.length()).toInt(); /* Verifica se a posição solicitada está entre os limites SUPERIOR e INFERIOR. Se algum deles for superado, o valor será ignorado e o valor limite será tomado como novo valor. */ if (leitura_comando > limite_superior) { leitura_comando = limite_superior; } if (leitura_comando < limite_inferior) { leitura_comando = limite_inferior; } } }
Novo suporte para NEMA 17
Arquivo STL para impressora 3D
Arquivos para download:
0 Comentários