Normalmente sistemas de controle são utilizados para associar a informação lida nos sensores, com a ação que vai ser desenvolvida pelo robô. Quanto melhor o controlador, melhor o desempenho do robô.
Dito isto, devemos tentar melhorar nosso sistema de controle a fim de obter um melhor resultado, e para tal, um bom algoritmo de início é o de Proporcional Integrativo e Derivativo (PID). Esse é um típico programa de malha fechada, onde a saídas dependem das entradas. Como o próprio nome exclama, o programa se constitui de 3 partes: a proporcional, a integrativa e a derivativa. O proporcional faz com que a saida seja proporcional ao erro. A integral é a somatória de todos os erros para ajudar na velocidade de resposta. E o derivativo mede a variação dos erros com o passar do tempo. Cada um desses valores é multiplicado por uma constante diferente que se adapta as suas condições de sistema.
Mas o que isso realmente significa?
Para melhor entendimento, tomemos o exemplo de um carrinho que tem que ficar a uma distância de 10m de uma parede, normalmente isso seria uma tarefa simples: basicamente olhariamos a distância do carrinho à parede e julgariamos pra qual direção o carrinho deve caminhar:
Se distância>10 então vá para frente
Senão vá para trás
Bem, o algoritmo parece funcionar ok para o problema apresentado, contudo, devemos analisar a estabilidade do sistema: sistemas como esse são muito instáveis. Qualquer mudança no estado estacionário pode levar a um movimento perpétuo de vai e vem em torno da situação de equilíbrio. E é aí que entra o sistema de controle, ele é o responsável por atenuar as respostas aos motores e providenciar uma melhor solução para o problema.
Como fazer isso?
Bem, pare esse problema em específico, podemos utilizar apenas o P do PID e já obteremos uma resposta mil vezes melhor, veja:
A ideia do programa é fazer uma resposta interativa com os dados coletados: nós temos uma informação muito mais específica do que somente saber se a distância é maior ou menor que 10. Sendo assim, devemos dar uma resposta aos motores dependendo da informação dos sensores, ou seja, a saída para os motores deve ser proporcional ao erro das leituras:
E(t)=DistDesejada-DistAtual
U(t)=E(t)×Kp
Assim, a resposta vai ser incrivelmente mais satisfatória e o sistema vai funcionar muito melhor.
Agora vamos entender como funciona as outras partes do controlador:
O integrativo serve para somar os pequenos erros com o passar do tempo, para que assim o sistema consiga corrigir até os menores detalhes, por exemplo, se o carrinho estivesse a 10,001m da parede, por causa do proporcional(Kp), ele iria ficar parado, e aí entra o Ki que vai somando esses pequenos erros até o sistema ter erro acumulado suficiente para tomar uma ação, assim este controlador se torna, além de eficiente, muito preciso em suas ações. Outro uso do Ki é quando seu sistema precisa voltar muito rápido para o setPoint, pois a cada instante que o erro continua diferente de zero a resposta continua aumentando.
Já o derivativo (Kd) mede a taxa de variação do erro com o tempo, isso auxilia a medida que promove uma resposta uniforme do sistema, ou seja, ele atenua grandes perturbações do sistema visto que ele aumenta a resposta da saída se o sistema for perturbado.
Assim, a fórmula final da saída do controlador em função do tempo obedece a seguinte equação:
Formula geral:
Segue código para auxiliar o entendimento. O código é referente a aplicação deste controlador em um robô segue linhas convencional, com o intuito de melhorar exponencialmente a resposta do robô.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void PID_SegueLinha(){ | |
int error = Estado_Atual() - setPoint; | |
I+=error; | |
int motorSpeed = KP * error + KD * (error - lastError) + KI*I; | |
lastError=error; | |
int m1Speed = M1 + motorSpeed; | |
int m2Speed = M2 - motorSpeed; | |
if (m1Speed < 0) m1Speed = 0; // Determina o limite inferior | |
if (m2Speed < 0) m2Speed = 0; // Determina o limite inferior | |
if (m1Speed > MMAX) m1Speed = MMAX; // Determina o limite superior | |
if (m2Speed > MMAX) m2Speed = MMAX; // Determina o limite superior | |
Motor1(m1Speed); | |
Motor2(m2Speed); | |
} |