Tacogerador PID

Olá Srs!
Tinha alguns projetos passados que fizemos no nosso curso e alguns não tinham funcionado como esperado e estou retomando alguns para praticar, entender melhor a implementação de códigos e melhorar cada vez mais refazendo o que ja tentei. Este era um projeto de um tacogerador, dois motores interligados pelo eixo com um controle PID mostrando as leituras via Serial da tensão gerada com um botões para ligar e desligar. Para os experientes deve ser uma coisa extremamente simples mas para mim que está aprendendo é ainda um pouco dificil. Consegui fazer gerar as leituras de tensão mas não estou conseguindo implementar um botão liga desliga, neste ultimo codigo tentei colocar um liga e outro desliga para ver se conseguia, mas sem sucesso, alguem pode me dizer onde estou errando?

#include <PID_v1.h>

double Setpoint ;                // valor de setpoint desejado
double Input;                    // entrada motor tacogerador
double Output ;                  // motor
double Kp = 0, Ki = 10, Kd = 0;  //PID parametros
int BOTAO1 = 7;               //Botão liga tacogerador
int BOTAO2 = 6;
int LedVerde = 8;                //Led verde tacogerador on
int LedVermelho = 12;            //Led vermelho tacogerador off
int IN1 = 2 ;
int estado_botao1 = 0;    // Declara e inicializa variável para guardar o estado do botao1
int estado_botao2 = 0;    // Declara e inicializa variável para guardar o estado do botao2
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);  //cria instância PID

void setup()
{
  Serial.begin(9600);
  Setpoint = 150;                     //valor para o setpoint
  myPID.SetMode(AUTOMATIC);           //Liga o PID
  myPID.SetTunings(Kp, Ki, Kd);       //Ajusta os valores no PID
  pinMode(BOTAO1, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(BOTAO2, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(LedVerde, OUTPUT);
  pinMode(LedVermelho, OUTPUT);
  pinMode(IN1,OUTPUT);                //pinos motores
  estado_botao1 = 0;  // Atribui ao estado do botao o valor zero (botao nao premido).
  estado_botao2 = 1;  // Atribui ao estado do botao o valor zero (botao nao premido).

}

void loop()
{
  estado_botao1 = digitalRead(BOTAO1); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao1 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao2 = 1;
    digitalWrite(LedVerde, HIGH); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, LOW); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, LOW);
    digitalWrite(IN1,LOW);
    delay(500);
    
   }
  estado_botao2 = digitalRead(BOTAO2); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao2 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao1 = 1;
    digitalWrite(LedVerde, LOW); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, HIGH); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, HIGH);
    digitalWrite(IN1,HIGH);
    delay(500);
   }
    while(estado_botao1 == 0 && estado_botao2 == 1)
    {
    //Lê o valor de entrada. Entrada analógica: 0 a 1024. Mapeia-se para um valor de 0 a 255 conforme é usado para função PWM.
    Input = map(analogRead(0), 0, 1024, 0, 255);  //definido no pino 5 analógico
    //PID calculo
    myPID.Compute();
    //Escreve na saída calculada pela função PID
    analogWrite(3, Output); //motor está definido no pino 3 pwm
    digitalWrite(IN1,HIGH);
    //Envie dados  para plotagem
    Serial.print(Input);
    Serial.print(" ");
    Serial.println( Output);
    Serial.print(" ");
    Serial.println( Setpoint);
    delay(100);
    }
  }

A partir do momento em que o botão1 seja premido e o botão2 não premido, o ciclo WHILE é executado e nunca mais termina porque a condição do WHILE tem variáveis que não são alteradas nesse ciclo infinito.

Uma opção será substituir o ciclo WHILE por uma condição IF, de modo a verificar o estado dos botões em cada ciclo de execução do loop():

void loop()
{
  estado_botao1 = digitalRead(BOTAO1); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao1 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao2 = 1;
    digitalWrite(LedVerde, HIGH); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, LOW); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, LOW);
    digitalWrite(IN1,LOW);
    delay(500);
    
   }
  estado_botao2 = digitalRead(BOTAO2); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao2 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao1 = 1;
    digitalWrite(LedVerde, LOW); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, HIGH); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, HIGH);
    digitalWrite(IN1,HIGH);
    delay(500);
   }

  //while(estado_botao1 == 0 && estado_botao2 == 1) {
  if (estado_botao1 == 0 && estado_botao2 == 1) {
    //Lê o valor de entrada. Entrada analógica: 0 a 1024. Mapeia-se para um valor de 0 a 255 conforme é usado para função PWM.
    Input = map(analogRead(0), 0, 1024, 0, 255);  //definido no pino 5 analógico
    //PID calculo
    myPID.Compute();
    //Escreve na saída calculada pela função PID
    analogWrite(3, Output); //motor está definido no pino 3 pwm
    digitalWrite(IN1,HIGH);
    //Envie dados  para plotagem
    Serial.print(Input);
    Serial.print(" ");
    Serial.println( Output);
    Serial.print(" ");
    Serial.println( Setpoint);
    delay(100);
    }
  }

Então meu amigo, se for apenas para colocar botoes para ligar e desligar leds é tranquilo, ou apenas um codigo para imprimir valores também, consigo entender olhando exemplos disso, mas quando precisa juntar os dois embaralha tudo, daí ou funciona um ou outro, com certeza ja reparou nessa dificuldade que tenho. :grin:
Pelo exemplo de loop que passou, os leds acendem e apagam conforme comando dos botões mas o motor liga e não para, e também na janela serial aparece apenas duas linhas de leitura cada vez que aperto o liga, antes fazia a leitura continuamente no loop.

O código ficou assim:

#include <PID_v1.h>

double Setpoint ;                // valor de setpoint desejado
double Input;                    // entrada motor tacogerador
double Output ;                  // motor
double Kp = 0, Ki = 10, Kd = 0;  //PID parametros
int BOTAO1 = 7;               //Botão liga tacogerador
int BOTAO2 = 6;
int LedVerde = 8;                //Led verde tacogerador on
int LedVermelho = 12;            //Led vermelho tacogerador off
int IN1 = 2 ;
int estado_botao1 = 0;    // Declara e inicializa variável para guardar o estado do botao1
int estado_botao2 = 0;    // Declara e inicializa variável para guardar o estado do botao2
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);  //cria instância PID

void setup()
{
  Serial.begin(9600);
  Setpoint = 150;                     //valor para o setpoint
  myPID.SetMode(AUTOMATIC);           //Liga o PID
  myPID.SetTunings(Kp, Ki, Kd);       //Ajusta os valores no PID
  pinMode(BOTAO1, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(BOTAO2, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(LedVerde, OUTPUT);
  pinMode(LedVermelho, OUTPUT);
  pinMode(IN1,OUTPUT);                //pinos motores
  estado_botao1 = 0;  // Atribui ao estado do botao o valor zero (botao nao premido).
  estado_botao2 = 1;  // Atribui ao estado do botao o valor zero (botao nao premido).

}

void loop()
{
  estado_botao1 = digitalRead(BOTAO1); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao1 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao2 = 1;
    digitalWrite(LedVerde, HIGH); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, LOW); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, LOW);
    digitalWrite(IN1,LOW);
    delay(500);
    
   }
  estado_botao2 = digitalRead(BOTAO2); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao2 == LOW) {   // Verifica a variavel que tem o estado do botao.
    estado_botao1 = 1;
    digitalWrite(LedVerde, LOW); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, HIGH); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, HIGH);
    digitalWrite(IN1,HIGH);
    delay(500);
   }

  //while(estado_botao1 == 0 && estado_botao2 == 1) {
  if (estado_botao1 == 0 && estado_botao2 == 1) {
    //Lê o valor de entrada. Entrada analógica: 0 a 1024. Mapeia-se para um valor de 0 a 255 conforme é usado para função PWM.
    Input = map(analogRead(0), 0, 1024, 0, 255);  //definido no pino 5 analógico
    //PID calculo
    myPID.Compute();
    //Escreve na saída calculada pela função PID
    analogWrite(3, Output); //motor está definido no pino 3 pwm
    digitalWrite(IN1,HIGH);
    //Envie dados  para plotagem
    Serial.print(Input);
    Serial.print(" ");
    Serial.println( Output);
    Serial.print(" ");
    Serial.println( Setpoint);
    delay(100);
    }
  }

Aciono o liga o motor aciona e da duas linhas de plotagem, desligo o botão 2, o led alterna de verde pra vermelho mas o motor não desliga

Leo, à medida que for praticando essas dificuldades vão desaparecendo :wink:

Então o funcionamento dos botões será:

  • Com o motor desligado, ao premir o botão LIGAR, o sistema liga o motor, realiza as leituras e vai mostrando o resultado no monitor série. Isto mantém-se mesmo que o utilizador deixe de premir neste botão LIGAR.
  • Com o motor ligado, ao premir o botão DESLIGAR, o sistema desliga o motor, e já não realiza as leituras.

Será esse o objectivo?

Nesse caso bastará criar uma variável de controlo para a situação de sistema ligado/desligado. Quando o LIGAR é accionado coloca-se essa variável a 1. Quando o DESLIGAR é accionado coloca-se a variável a 0.

Depois as leituras e prints serão realizados apenas no caso de sistema ligado.

Código:

#include <PID_v1.h>

double Setpoint ;                // valor de setpoint desejado
double Input;                    // entrada motor tacogerador
double Output ;                  // motor
double Kp = 0, Ki = 10, Kd = 0;  //PID parametros
int BOTAO1 = 7;               //Botão liga tacogerador
int BOTAO2 = 6;
int LedVerde = 8;                //Led verde tacogerador on
int LedVermelho = 12;            //Led vermelho tacogerador off
int IN1 = 2 ;
int estado_botao1 = 0;    // Declara e inicializa variável para guardar o estado do botao1
int estado_botao2 = 0;    // Declara e inicializa variável para guardar o estado do botao2
int sistema_ligado = 0;    // Declara e inicializa variável para guardar o estado do sistema (ligado:1, desligado:0)

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);  //cria instância PID

void setup()
{
  Serial.begin(9600);
  Setpoint = 150;                     //valor para o setpoint
  myPID.SetMode(AUTOMATIC);           //Liga o PID
  myPID.SetTunings(Kp, Ki, Kd);       //Ajusta os valores no PID
  pinMode(BOTAO1, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(BOTAO2, INPUT_PULLUP);   //define o pino do botao como entrada "INPUT"
  pinMode(LedVerde, OUTPUT);
  pinMode(LedVermelho, OUTPUT);
  pinMode(IN1,OUTPUT);                //pinos motores
  estado_botao1 = 0;  // Atribui ao estado do botao o valor zero (botao nao premido).
  estado_botao2 = 1;  // Atribui ao estado do botao o valor zero (botao nao premido).
  sistema_ligado = 0; // Inicia com o sistema desligado.
}

void loop()
{
  estado_botao1 = digitalRead(BOTAO1); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao1 == LOW) {   // Verifica a variavel que tem o estado do botao.
    sistema_ligado = 1; // Sistema ligado.
    estado_botao2 = 1;
    digitalWrite(LedVerde, HIGH); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, LOW); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, LOW);
    digitalWrite(IN1,LOW);
    delay(500);

  }
  estado_botao2 = digitalRead(BOTAO2); // Le o botao e guarda o respectivo estado numa variavel.
  if (estado_botao2 == LOW) {   // Verifica a variavel que tem o estado do botao.
    sistema_ligado = 0; // Sistema desligado.
    estado_botao1 = 1;
    digitalWrite(LedVerde, LOW); // Liga LED verde se o botao estava premido.
    digitalWrite(LedVermelho, HIGH); // Desliga LED vermelho se o botao estava premido.
    digitalWrite(3, HIGH);
    digitalWrite(IN1,HIGH);
    delay(500);
  }
  //while(estado_botao1 == 0 && estado_botao2 == 1) {
  //if (estado_botao1 == 0 && estado_botao2 == 1) {
  if (sistema_ligado == 1) { // Obtem os valores e mostra-os apenas com o sistema ligado.
    //Lê o valor de entrada. Entrada analógica: 0 a 1024. Mapeia-se para um valor de 0 a 255 conforme é usado para função PWM.
    Input = map(analogRead(0), 0, 1024, 0, 255);  //definido no pino 5 analógico
    //PID calculo
    myPID.Compute();
    //Escreve na saída calculada pela função PID
    analogWrite(3, Output); //motor está definido no pino 3 pwm
    digitalWrite(IN1,HIGH);
    //Envie dados  para plotagem
    Serial.print(Input);
    Serial.print(" ");
    Serial.println( Output);
    Serial.print(" ");
    Serial.println( Setpoint);
    delay(100);
  }
}

Em relação à situação do motor sempre ligado. Pelo código entendi que o motor é ligado ao colocar os pinos IN1 e 3 com o valor lógico LOW. É assim que o motor liga?

Para desligar o motor, basta colocar ambos os pinos IN1 e 3 com o valor lógico HIGH?

Como não conheço esse equipamento não sei o que é necessário para ligar e desligar o motor...

Os pinos IN1 e 3 ligam relés que accionam o motor?

Em relação à situação do motor sempre ligado. Pelo código entendi que o motor é ligado ao colocar os pinos IN1 e 3 com o valor lógico LOW. É assim que o motor liga?

Para desligar o motor, basta colocar ambos os pinos IN1 e 3 com o valor lógico HIGH?

Como não conheço esse equipamento não sei o que é necessário para ligar e desligar o motor...

Os pinos IN1 e 3 ligam relés que accionam o motor?

Então, eu peguei um exemplo da internet e fui editando ele, peguei um exemplo que só fazia a plotagem e tentei implementar os botões. Tentei mudar o IN1 e 3 para HIGH quando aciono o botão desliga mas ele não para, então não tenho certeza se a lógica estava certa, mas deveria ser assim. Fisicamente está com motor na porta 3 e dois leds para indicar ligado e desligado e dois botões par aligar e desligar, deve com o botão liga, acionar o botão e led verde, apagar o vermelho e plotar continuamente os valores de tensão e quando aciono o desliga, para a plotagem e o motor e inverte os leds.

Pesquisei sobre esse equipamento, basicamente parece ser um tacómetro com o princípio de funcionamento de um gerador eléctrico. A velocidade de rotação do eixo é convertida em tensão induzida que pode ser lida pelo conversor analógico/digital do Arduino (ADC).

Suponho que a ideia seja controlar a velocidade do motor usando controlo PID, sendo um dos parâmetros o valor obtido de tensão induzida no tacómetro acoplado ao motor.

Não compreendi o significado dessa situação.

De acordo com o código, o pino 2, com o nome "IN1", está configurado como OUTPUT. Isto ajuda a gerar alguma confusão, chamar um pino de "IN" e configura-lo como OUTPUT...

O pino 3 não está configurado como OUTPUT. Logo, por omissão trata-se de um pino configurado como INPUT (por omissão, ao iniciar estão todos configurados como INPUT).

Se o pino 3 é um pino de OUTPUT o melhor será configura-lo como tal, através de pinMode(3, OUTPUT). Esse pino parece ser usado para gerar PWM para aumentar/diminuir a velocidade do motor? Possivelmente o pino 2 activa/desactiva o motor, e o pino 3 controla a respectiva velocidade? Se assim for, então talvez fosse boa ideia dar-lhes nomes mais adequados, por exemplo:

int pin_motor_on_off = 2 ;
int pin_motor_pwm = 3 ;

E no setup() coloca-los como OUTPUT:

pinMode(pin_motor_on_off,OUTPUT);
pinMode(pin_motor_pwm,OUTPUT);

É feita a leitura analógica do pino 0. Suponho que a saída do tacómetro está ligada à entrada analógica A0? Se assim for, seria boa ideia atribuir-lhe um nome para o código ficar mais perceptível:

int pin_sinal_tacogerador = A0 ;

Ao ler essa entrada analógica podemos usar esse nome em vez do zero:

Input = map(analogRead(pin_sinal_tacogerador), 0, 1024, 0, 255);

O ideal seria podermos visualizar o esquema do circuito, para percebermos como ligar e desligar o motor.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.