Baixe o app para aproveitar ainda mais
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
Compartilhar