• UFRJ Nautilus

Controle PID utilizando Arduino

Atualizado: há 5 dias


Como comandar um robô para que ele mantenha uma posição e orientação embaixo da água? Neste post veremos como podemos utilizar um controlador PID para resolver este e outros problemas de robótica.


Existem diferentes algoritmos de controle que podemos utilizar em nossos sistemas, provavelmente o mais comum algoritmo de controle fechado é o PID. Para criar uma intuição desse algoritmo, primeiro precisamos pensar o que é um controle fechado. Vamos pensar no caso de um condutor dirigindo em um terreno sinuoso. O motorista deseja manter seu veículo na velocidade da via, esse desejo do controlador, iremos chamar de “setpoint”, o motorista controla a aceleração do carro, que iremos chamar de planta utilizando o acelerador e freio, o motorista também consegue observar as mudanças que o freio e o acelerador fazem no estado do carro utilizando o velocímetro.


Este é provavelmente o exemplo mais simples e cotidiano que temos de um sistema de controle fechado, onde o condutor utiliza a observação do sistema, nesse caso o carro para atuar no mesmo, utilizando o freio e o acelerador. O diagrama para este sistema seria:



Agora que já sabemos o que é um sistema de controle fechado, ou realimentado, podemos apresentar o PID, sigla para Proporcional, Integrativo, Derivativo. Esse controlador irá utilizar o valor atual do erro (proporcional), a integral do erro (integrativo) e a derivada do erro (derivativo) para computar uma saída que iremos usar para atuar em nosso sistema, o diagrama para este sistema é o seguinte:



A equação que descreve a saída deste diagrama no tempo é a seguinte:

Iremos implementar este controlador com o objetivo de controlar a velocidade de um motor DC utilizando arduino.


Para implementarmos esse controlador, iremos utilizar a versão discreta da equação acima, substituindo a integral por um somatório e discretizando o cálculo da variação do erro.



Nosso circuito consiste de um motor que desejamos controlar, com um encoder, sensor capaz de medir a velocidade do motor e um potenciômetro que iremos utilizar para escolher a velocidade que desejamos para o motor.


Implementação do controlador:

// Mapeamento Hardware
#define PWM_OUT       3
#define ENCODER_A 2
#define POT_IN A0

int output;           // define a saída de pwm
int speed;            // velocidade do motor
int lastError = 0;    // declara o último erro
int setpoint;         // declara o setpoint
int error = 0;        // erro atual
int I_error = 0;      // ganho integral
int D_error = 0;      // ganho derivativo
float KP = 0.1;       // constante proporcional
float KI = 0.0001;    // constante integrativa
float KD = 0.001;     // constante derivativa


void setup() {
  Serial.begin(9600);              // inicia a comunicação serial
  
  pinMode(ENCODER_A, INPUT);      // define o encoder para enviar dados
  pinMode(POT_IN, INPUT);     // define o potenciômetro para enviar dados e controlar o valor de set point
  pinMode(PWM_OUT, OUTPUT);          // define a porta 3 para envio de sinal PWM para controle de velocidade
 
  output = 10;              // define um valor inicial para pwm_valor 
  analogWrite(PWM_OUT, output);   // controla o valor pwm através da saida porta 3
  }

void loop() {
   // calcula o valor de set point apartir da leitura analógica do potenciometro
   
  setpoint = map(analogRead(POT_IN), 0,1023,0,600);  
 
  // realiza a leitura do encoder e transforma o valor dos pulsos em velocidade
  
  speed = 19.1*((60*1000*10) / pulseIn(ENCODER_A, HIGH)); 
 
  error = setpoint - speed; // calcula o valor do erro
 
  I_error += error; // somatorio do erro
  D_error = lastError - error; // variação do erro
  // como esse loop vai ser chamado regularmente, podemos 
  // supor que dt é constante e não incluilo nas contas acima.
  // dt está junto de KP, KI, KD, de forma implicita.
 
  // Implementação do Algorítimo PID
  
  output += KP*error + KI*I_error + KD*D_error;     
 
  // limita a saida do controle para os valores vãlidos de pwm (10-255)
  output = constrain(output, 10, 255);
 
  // envia o sinal para o "motor"
  analogWrite(PWM_OUT, output);
 
  // imprime os valores de speed e setpoint.
  // valores em RPM
  // utilize a função de gráficos do monitor serial!  
  Serial.print(speed);     
  Serial.print(",");
  Serial.println(setpoint);  
}

Note que como desejamos controlar a velocidade de um motor, quando o motor estiver na velocidade igual ao setpoint, o código iria enviar um sinal nulo para o motor, levando-o a desacelerar, e assim se afastar do setpoint, para resolver este problema, somamos a saída anterior do controlador a nova saída, assim quando o erro se aproximar de 0, o controlador continuará enviando o sinal que leva o motor à velocidade desejada.


Outra modificação que realizamos na implementação acima, é a exclusão dos termos relacionados ao tempo, pois estamos chamando o controlador dentro do loop com um intervalo de tempo aproximadamente constante, assim, se dt é constante podemos realizar as seguintes simplificações:

Essas simplificações economizam

ciclos de processamento do nosso arduino, além de facilitarem a implementação do código!


Projeto do tinkercad: https://www.tinkercad.com/things/47ocvb7eAXp


Escrito por Vitor Pavani



0 comentário

Posts recentes

Ver tudo