Buscar

prática6_andre_henrique_murillo

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

pratica6experiencia1e2.ino
#include <LiquidCrystal.h>
#include <MsTimer2.h>
LiquidCrystal lcd(8,9,4,5,6,7);
#define encoder0PinA 20
#define encoder0PinB 21
int encoder0Pulses = 0;
float velocidade;
int IN1=44;
int IN2=45;
int step=10;
int val=50;
#define keyup 1
#define keydown 2
void flash(){
 velocidade=(encoder0Pulses);
 encoder0Pulses=0;
 }
void motorInput(float input)
{
 if (input<0){
 input=max(input,-100);
 float v_map=map(input,-1.0,100,0,255);
 analogWrite(IN1,(int)v_map);
 analogWrite(IN2,0);
 }
 else{
 input=min(input,100);
 float v_map=map(input,-1.0,100,0,255);
 analogWrite(IN2,(int)v_map);
 analogWrite(IN1,0);
 }
}
void setup() {
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(20,OUTPUT);
MsTimer2::set(25,flash);
MsTimer2::start();
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH); // turn on ... pull-up resistor
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH); // turn on ... pull-up resistor
attachInterrupt(digitalPinToInterrupt(encoder0PinA), doEncoder_ExpandedA, CHANGE);
Serial.begin (9600);
Serial.println("Serial Started!!!");
}
void keypadRead(){
 int keyValue;
 int analogKey=analogRead(0);
 if(analogKey<200){
 keyValue=1;
 val=val+step;
 }
 else if(analogKey<400){
 keyValue=1;
 val=val-step;
 }
}
void loop() {
 digitalWrite(IN1,HIGH);
 digitalWrite(IN2,LOW);
 delay(2000);
digitalWrite(IN1,LOW);
 digitalWrite(IN2,HIGH);
 delay(2000);
Serial.println(encoder0Pulses);
Serial.println(velocidade);
delay(250);
}
void doEncoder() {
if (digitalRead(encoder0PinA) == true) {// if (digitalRead(encoder0PinA) == ... digitalRead(encoder0PinB)) {
encoder0Pulses++;
 }
 }
void doEncoder_ExpandedA() {
if (digitalRead(encoder0PinA) == HIGH) { // found a ... low-to-high on channel A
if (digitalRead(encoder0PinB) == LOW) { // check ... channel B to see which way
// encoder is turning
encoder0Pulses = encoder0Pulses - 2; // CCW
}
else {
encoder0Pulses = encoder0Pulses + 2; // CW
}
}
else // found ... a high-to-low on channel A
{
if (digitalRead(encoder0PinB) == LOW) { // check ... channel B to see which way
// encoder is turning
encoder0Pulses = encoder0Pulses + 2; // CW
}
else {
encoder0Pulses = encoder0Pulses - 2; // CCW
}
}
}
pratica6experiencia3e4.ino
#include <MsTimer2.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define encoder0PinA 20
#define encoder0PinB 21
#define keyUp 1
#define keyDown 2
#define keyRight 0
#define keyLeft 3
#define keySelect 4
#define analogPin A8
int encoder0Pulses = 0;
float pos_angular = 0;
float omega_RPM = 0;
float omega_RPM_anterior=0;
float omega_RPM_filtrado=0;
float alpha=0.9;
float temp = 0;
int val = 0;
int keyValue = 0;
int step = 10;
int pwmPin = 44;
int valpwm = 0;
float input = 0;
float veloc = 0;
int pin1 = 44;
int pin2 = 45;
void setup() {
 lcd.begin(16, 2);
 pinMode(pin1, OUTPUT);
 pinMode(pin2, OUTPUT);
 pinMode(pwmPin, OUTPUT);
 pinMode(13, OUTPUT);
 MsTimer2::set(25, flash);
 MsTimer2::start();
 pinMode(encoder0PinA, INPUT);
 digitalWrite(encoder0PinA, HIGH); // turn on pull-up resistor
 pinMode(encoder0PinB, INPUT);
 digitalWrite(encoder0PinB, HIGH); // turn on pull-up resistor
 attachInterrupt(digitalPinToInterrupt(encoder0PinA), doEncoder_ExpandedA, CHANGE);
 attachInterrupt(digitalPinToInterrupt(encoder0PinB), doEncoder_ExpandedB, CHANGE);
 
 Serial.begin(9600);
 Serial.println("Serial Started!!!");
}
void displayMenu1() {
// Imprime o Menu 1 na tela do LCD
lcd.clear();
lcd.setCursor(0,0);
lcd.print("[RPM]: ");
lcd.print(omega_RPM);
lcd.setCursor(0,1);
lcd.print("[PWM]: ");
lcd.print(input);
}
void loop() {
 keyPadRead();
 pwm();
 pos_angular = encoder0Pulses * 0.15;
 Serial.print (omega_RPM_filtrado);
 Serial.print (",");
 Serial.println(omega_RPM);
 displayMenu1();
 motorInput(input);
 delay(250);
}
void motorInput(float input)
{
 if (input < 0)
 {
 input = max(input, -100);
 float v_map = map(input * -1, 0, 100, 0, 255);
 analogWrite(pin1, (int)v_map);
 analogWrite(pin2, 0);
 }
 else
 {
 input = min(input, 100);
 float v_map = map(input, 0, 100, 0, 255);
 analogWrite(pin2, (int)v_map);
 analogWrite(pin1, 0);
 }
}
void flash() {
 static bool output = false;
 digitalWrite(13, output); // Define o estado do LED no pino 13 de acordo com o valor da variavel "output".
 output = !output; // Inverte o valor da variavel "output" usando o operador "!".
 val = analogRead(analogPin);
 
 temp = 0.025*encoder0Pulses;
 omega_RPM = temp*40;
 omega_RPM_filtrado=alpha*omega_RPM_anterior+((1-alpha)*omega_RPM);
 omega_RPM_anterior=omega_RPM;
 encoder0Pulses = 0;
}
void doEncoder_ExpandedA() {
 if (digitalRead(encoder0PinA) == HIGH) { // found a low-to-high on channel A
 if (digitalRead(encoder0PinB) == LOW) { // check channel B to see which way
 // encoder is turning
 encoder0Pulses = encoder0Pulses - 1; // CCW
 
 }
 else {
 encoder0Pulses = encoder0Pulses + 1; // CW
 
 }
 }
 else { // found a high-to-low on channel A
 if (digitalRead(encoder0PinB) == LOW) { // check channel B to see which way
 // encoder is turning
 encoder0Pulses = encoder0Pulses + 1; // CW
 
 }
 else {
 encoder0Pulses = encoder0Pulses - 1; // CCW
 
 }
 }
}
void doEncoder_ExpandedB() {
 if (digitalRead(encoder0PinB) == HIGH) { // found a low-to-high on channel A
 if (digitalRead(encoder0PinA) == LOW) { // check channel B to see which way
 // encoder is turning
 encoder0Pulses = encoder0Pulses + 1; // CCW
 
 }
 else {
 encoder0Pulses = encoder0Pulses - 1; // CW
 
 }
 }
 else { // found a high-to-low on channel A
 if (digitalRead(encoder0PinA) == LOW) { // check channel B to see which way
 // encoder is turning
 encoder0Pulses = encoder0Pulses - 1; // CW
 
 }
 else {
 encoder0Pulses = encoder0Pulses + 1; // CCW
 
 }
 }
}
void keyPadRead()
{
 // Realiza a leitura do teclado do LCD Keypad Shield
 int analogKey = analogRead(0);
 if (analogKey < 80)
 {
 keyValue = 0;
 }
 else if (analogKey < 200)
 {
 keyValue = 1;
 valpwm = valpwm + step;
 input = input + step;
 }
 else if (analogKey < 400)
 {
 keyValue = 2;
 valpwm = valpwm - step;
 input = input - step;
 }
 else if (analogKey < 600)
 {
 keyValue = 3;
 }
 else if (analogKey < 800)
 {
 keyValue = 4;
 }
}
void pwm()
{
 valpwm = constrain(valpwm, 0, 255); // Limita o valor de valpwm entre 0 e 255
 analogWrite(pwmPin, valpwm);
 }
Relatorio.pdf
Laboratório de Controle e Servomecanismo
Prática 6: Medição da posição e velocidade angular de um motor CC.
ANDRÉ LUÍS CORELIANO (RA:745948)
HENRIQUE CRAVEIRO D’ANTONIO (RA:791375)
MURILLO JOSÉ SUDAHIA GODOY (RA:789974)
TURMA C
12/08/2023
1 Descrição do experimento
A prática 6 serviu para aprender sobre como o microcontrolador Arduino pode ser
usado para controlar a velocidade e o sentido de rotação de um motor CC, através do uso
de uma ponte H e de um encoder, através de um botão e um display LCD. É importante
salientar que os códigos feitos durante a aula foram enviados junto a esse relatório por
meio de uma pasta .zip na plataforma ava.
2 Execução do experimento
2.1 Experiência 1
2.1.1 Código 1
Figura 1 - Contagem de pulsos por volta
1)b) 1 volta marcou 592 pulsos.
1
Figura 2 - encoder
1)c) O encoder possui 600 pulsos por revolução.
1)d) A contagem do arduino multiplica por 1. É possı́vel multiplicar por 4, basta
mudar o passo pra 4. A vantagem de multiplicar o PPR do encoder por 4 na contagem de
pulsos é aumentar a resolução angular e a precisão da detecção de movimento.
1)e) Bibliotecas e Inicializações:
O código começa importando as bibliotecas LiquidCrystal e MsTimer2 para lidar
com o display LCD e a temporização, respectivamente. Um objeto LiquidCrystal é inici-
alizado para controlar o display LCD, conectando-o
aos pinos 8, 9, 4, 5, 6 e 7. Variáveis
globais e constantes são definidas para configurações de pinos, valores iniciais e constan-
tes de controle.
Função flash():
Esta função é chamada a cada 25 ms pelo temporizador MsTimer2. Ela lê o valor
atual de encoder0Pulses, que parece ser usado para calcular a velocidade do motor. A
velocidade é armazenada na variável velocidade e o contador é resetado.
Função motorInput(float input):
Essa função controla a direção e a velocidade do motor CC com base na entrada
input. Se input é negativo, o motor gira em uma direção; se positivo, gira na direção
2
oposta. Os valores de entrada são mapeados para valores de saı́da PWM para controlar a
velocidade do motor através dos pinos IN1 e IN2 da Ponte H L298.
Função setup():
Configuração inicial do programa, onde os modos dos pinos, interrupções e tempo-
rizador são configurados. Os pinos IN1 e IN2 são definidos como saı́das. A função de
interrupção doEncoderExpandedA é anexada ao pino encoder0PinA (pino 20) para lidar
com o encoder incremental.
Função loop():
O loop principal do programa. Primeiro, o motor é acionado em uma direção por
2 segundos, depois na direção oposta por 2 segundos. A contagem de pulsos do encoder
(encoder0Pulses) e a velocidade atual (velocidade) são impressas no Serial Monitor a cada
250 ms. Funções de Interrupção doEncoder() e doEncoderExpandedA(): Essas funções
lidam com as interrupções geradas pelo encoder incremental. Elas contam os pulsos do
encoder e determinam a direção do movimento.
2)b) Utilizando o encoder expanded a contagem deu 1205 pulsos por revolução. A
contagem do arduino multiplica por 2, e é possı́vel multiplicar por 4, basta mudar o passo
para 2.
2)c)
Figura 3 - código multiplicando por 4 o ppr
3
Explicação do código: Inclui a biblioteca LiquidCrystal.h. Define os pinos para os
canais A e B do encoder (encoder0PinA e encoder0PinB). Declara variáveis globais para
contar pulsos (encoder0Pulses) e pulsos multiplicados por 4 (encoder0PulsesMultiplied).
No setup(), configura os pinos como entradas com pull-up interno habilitado. Anexa
as funções de interrupção doEncoderA e doEncoderB aos pinos dos canais A e B, res-
pectivamente. No loop principal (loop()), você pode executar o código principal da sua
aplicação. Neste exemplo, apenas imprimimos o valor de encoder0PulsesMultiplied. A
função doEncoderA() é chamada quando ocorre uma interrupção no canal A. Ela atualiza
encoder0Pulses de acordo com o padrão dos pulsos do encoder e, em seguida, multiplica
o valor por 4. A função doEncoderB() é chamada quando ocorre uma interrupção no canal
B. Ela também atualiza encoder0Pulses de acordo com o padrão dos pulsos do encoder e
multiplica o valor por 4.
3)a) Inclui a biblioteca LiquidCrystal.h. Define os pinos para os canais A e B do
encoder (encoder0PinA e encoder0PinB). Declara variáveis globais para contar pulsos
(encoder0Pulses) e a posição angular em graus (currentPositionDegrees). Define a cons-
tante PPR para representar os pulsos por revolução do encoder. No setup(), configura
os pinos como entradas com pull-up interno habilitado e anexa a função de interrupção
doEncoder ao pino do canal A. No loop principal (loop()), você pode executar o código
principal da sua aplicação. Neste exemplo, apenas imprimimos a posição angular em
graus. A função doEncoder() é chamada quando ocorre uma interrupção no canal A do
encoder. Ela atualiza encoder0Pulses de acordo com o padrão dos pulsos do encoder e,
em seguida, chama updatePosition() para atualizar a posição angular. A função upda-
tePosition() calcula a posição angular em graus com base na contagem de pulsos e na
constante PPR.
2.2 Experiência 2
2.2.1 Código 2
1)a) Inclui as bibliotecas LiquidCrystal.h e MsTimer2.h. Define os pinos para os
canais A e B do encoder (encoder0PinA e encoder0PinB). Declara variáveis globais
para a contagem de pulsos (encoder0Pulses) e a última contagem de pulsos (lastEnco-
der0Pulses). Define a constante PPR para representar os pulsos por revolução do encoder.
No setup(), configura os pinos como entradas com pull-up interno habilitado e anexa a
função de interrupção doEncoder ao pino do canal A. Inicia o Serial Monitor para impri-
4
mir a saı́da. Configura o temporizador MsTimer2 para chamar a função doTimer a cada
25 ms. No loop principal (loop()), você pode executar o código principal da sua aplicação
(caso necessário). A função doEncoder() lida com a contagem de pulsos do encoder como
nas versões anteriores. A função doTimer() é chamada a cada 25 ms pelo temporizador
MsTimer2. Ela calcula a variação de pulsos desde o último chamado, calcula a velocidade
angular em RPM com base na fórmula fornecida e a imprime no Serial Monitor.
Quando a base de tempo aumenta o delta N aumenta, e quando o delta N aumenta
o erro percentual diminui.
2.3 Experiência 3
2.1.3 Código 3
1)a) Bibliotecas e Inicializações:
As bibliotecas MsTimer2.h e LiquidCrystal.h estão incluı́das. Um objeto Liquid-
Crystal é inicializado para controlar o LCD Keypad Shield conectando-o aos pinos 8, 9,
4, 5, 6 e 7. Diversas variáveis globais e constantes são definidas para configurações de
pinos, valores iniciais e cálculos.
Configuração do Hardware e Interrupção:
No setup(), o LCD é configurado, assim como os pinos utilizados para o motor,
PWM, LED indicador e os canais A e B do encoder. A função attachInterrupt é usada para
associar as funções doEncoder-ExpandedA e doEncoder-ExpandedB aos pinos dos canais
A e B do encoder, respectivamente. Função displayMenu1(): Essa função é responsável
por exibir informações no LCD. Ela mostra a velocidade angular em RPM (omega-RPM)
e o valor do PWM (input).
Loop Principal:
No loop principal (loop()), as seguintes operações ocorrem: A função keyPadRead()
lê o teclado do LCD Keypad Shield e atualiza a variável input e o valor de PWM valpwm.
A função pwm() é chamada para ajustar o sinal PWM com base em valpwm. O valor da
posição angular (pos-angular) é calculado com base na contagem de pulsos do encoder.
As variáveis omega-RPM, omega-RPM-anterior e omega-RPM-filtrado são atualizadas
usando uma média ponderada (alpha) da velocidade angular em RPM. As funções dis-
playMenu1() e motorInput(input) são chamadas. Um atraso de 250 ms é inserido.
Função motorInput(float input):
Controla a direção e a velocidade do motor CC com base na entrada input. Confi-
5
gura os sinais nos pinos pin1 e pin2 da Ponte H L298.
Função flash():
Essa função é chamada a cada 25 ms pelo temporizador MsTimer2. Ela lê o valor
do encoder, calcula a velocidade angular em RPM (omega-RPM) e a média ponderada
da velocidade filtrada (omega-RPM-filtrado). Funções de Interrupção doEncoder Expan-
dedA() e doEncoder ExpandedB():
Essas funções lidam com as interrupções geradas pelos canais A e B do encoder.
Elas atualizam a contagem de pulsos do encoder com base no padrão dos pulsos.
Função keyPadRead():
Lê o teclado do LCD Keypad Shield e atualiza a variável keyValue para diferentes
valores dependendo da tecla pressionada.
Função pwm():
Limita o valor de valpwm entre 0 e 255 e aplica o PWM no pino especificado
(pwmPin).
2.3 Experiência 4
2.1.3 Código 4
1)a) O valor selecionado para alpha pelo grupo foi de 0,9. Esse valor foi o que
melhor filtrou o sinal.
1)b)
Figura 4 - serial ploter do filtro passa baixa
2.2 Pós-Laboratório
6
Com códigos implementados que alteram a velocidade e o sentido de rotação de um
motor CC, com a velocidade do motor sendo visualizada no display LCD não há dificul-
dade em media a posição e a velocidade angular do motor a partir deles. Nas experiências
1 e 2 utilizou-se códigos no arduino para medir a posição angular e a visualizar no dis-
play. Na experiência 3 foi utilizada a base de tempo para alterar o sentido e a velocidade
de rotação. Na experiência 4 foi utilizado um filtro passa baixa, que permite a passagem
de baixas frequências, para suavizar o sinal da velocidade angular do motor.
3 Avaliação dos resultados do experimento
A prática ocorreu de maneira satisfatória, visto que os códigos feitos pelo grupo
foram executados da maneira esperada.
4 Análise crı́tica e discussão
A dificuldade encontrada durante a execução dessa prática foi a falta de experiência
do grupo em programar com o arduino. Apesar disso a prática ocorreu de maneira satis-
fatória, de modo que todos os códigos exigidos foram executados de maneira coerente.
Além disso foi possı́vel aplicar de maneira prática, conceitos estudados na parte teórica
da disciplina, controlando a velocidade e o sentido do motor CC através de um botão e
um encoder, ambos programados em arduino.
5 Outras informações
Nessa prática foi solicitado um pré-laboratório. As respostas do pré-laboratório são:
1) Um encoder incremental é um dispositivo utilizado para medir a posição, movi-
mento ou rotação de um eixo ou objeto. É geralmente composto por um disco rotativo
acoplado ao eixo cujo movimento você deseja medir. O disco possui padrões ou mar-
cas em sua superfı́cie que são interpretados pelo sensor do encoder. Existem dois tipos
principais de padrões usados em encoders incrementais: padrões ópticos e magnéticos.
2) A quadratura de um encoder incremental refere-se ao processo de gerar dois con-
juntos de sinais elétricos defasados em 90 graus um do outro. Esses sinais são conhecidos
7
como canais A e B, e são usados para determinar a direção e a contagem precisa do mo-
vimento do encoder. O processo de quadratura é fundamental para obter informações
detalhadas sobre o movimento, especialmente em velocidades mais altas ou quando a
direção precisa ser determinada.
3) Uma interrupção em um microcontrolador é um mecanismo que permite ao pro-
cessador interromper temporariamente sua execução normal para lidar com um evento
externo ou uma condição especial que requer atenção imediata. Em vez de esperar ativa-
mente ou verificar constantemente se ocorreu algum evento, o processador pode ser con-
figurado para responder automaticamente a eventos especı́ficos por meio de interrupções.
Quando uma interrupção ocorre, o processador suspende temporariamente a execução
do código atual, salva o estado atual (registradores e posição no código), executa o código
de tratamento da interrupção (chamado de ”rotina de serviço de interrupção”) e, em se-
guida, restaura o estado anterior e continua a execução normal do programa.
No Arduino MEGA, que é uma placa baseada em microcontrolador ATmega2560,
os pinos que podem ser utilizados como interrupções externas são os pinos de E/S di-
gitais 2 a 13 e 21 a 29. No total, são 8 pinos que podem ser configurados para receber
interrupções externas.
4) A função attachInterrupt() é uma função em linguagem Arduino usada para con-
figurar uma interrupção externa em um pino especı́fico. Ela permite que você especifique
uma função (chamada de ”Interrupt Service Routine”ou ISR) que será executada sempre
que ocorrer uma interrupção no pino especificado.
5) Motor CC —> encoder —> Arduino Mega.
6) Motor CC —> encoder —> Ponte H L 298 —> Arduino Mega.
6 Referências
Nessa prática não foram utilizadas referências bibliográficas.
8

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?

Continue navegando