Tutorial · Iniciante · 18 min de leitura
Como ajustar um controlador PID: guia prático
Ajuste um controlador PID passo a passo: comece pelo ganho proporcional, adicione derivativo e integral na ordem correta e evite windup integral.
Um controlador PID converte o erro entre onde um sistema está e onde você quer que ele esteja em uma correção. Ele tem três termos — proporcional, integral e derivativo — e o ajuste consiste em escolher a intensidade da ação de cada um. A maneira confiável de fazer isso é um termo por vez, em uma ordem fixa, observando a resposta após cada alteração. Você pode acompanhar no simulador de controlador PID.
Comece com o ganho proporcional
Defina os ganhos integral e derivativo como zero. Aumente o ganho proporcional (Kp) até o sistema responder rapidamente a uma alteração da referência. Se for pouco, a reação será lenta; se for demais, haverá sobrepasso e oscilação. Pare quando a resposta for rápida, mas apenas levemente oscilante — esse é seu ponto de trabalho para adicionar os outros termos.
Uma regra útil: P fornece velocidade. Ele reage ao erro no momento e a nada mais.
Adicione o derivativo para controlar o sobrepasso
Agora aumente o ganho derivativo (Kd). A ação derivativa responde à velocidade de variação do erro, portanto atua como freio à medida que o sistema se aproxima da referência. É isso que elimina o sobrepasso e as oscilações deixados pelo controle puramente proporcional.
Adicione apenas um termo derivativo suficiente para eliminar a oscilação. Excesso de ganho faz o controlador saltar, porque o termo derivativo amplifica qualquer ruído presente na medição. Se o sinal estiver ruidoso, filtre-o antes da derivação ou dependa mais dos termos proporcional e integral.
Adicione o integral por último
Os termos proporcional e derivativo juntos ainda podem deixar um pequeno erro constante — o sistema para pouco antes da referência. O termo integral (Ki) corrige isso: ele acumula o erro ao longo do tempo e continua empurrando até que o desvio desapareça.
Aumente o ganho integral lentamente e somente se permanecer um erro em regime permanente reproduzível. O termo integral é o mais lento e o mais fácil de exagerar, portanto até uma pequena parcela já produz um efeito significativo.
Fique atento ao windup integral
O windup integral é a falha clássica do PID. Quando o atuador satura — um motor já na velocidade máxima, uma válvula completamente aberta — o sistema não consegue responder, mas o termo integral continua acumulando erro. Quando o erro finalmente muda de sentido, toda a ação armazenada é liberada de uma vez e o sistema apresenta um sobrepasso acentuado.
Evite-o limitando o integrador (pare de somar valores a ele enquanto a saída estiver saturada) ou por retro-cálculo (back-calculation, reduza o integrador usando a diferença entre a saída solicitada e a entregue). Uma limitação simples:
float candidateIntegral = integral + error * dt;
float raw = kp * error + ki * candidateIntegral + kd * derivative;
float output = constrain(raw, outputMin, outputMax);
if (raw == output) integral = candidateIntegral; // only accumulate when not saturated
Mantenha a temporização do ciclo precisa
Todos os três termos dependem de um passo de tempo consistente. Em um microcontrolador, um delay() longo no ciclo adiciona tempo morto que torna o termo derivativo inútil, por maior que seja seu valor, e distorce o termo integral. Execute o ciclo rapidamente e em intervalos constantes e passe o tempo real decorrido para o cálculo.
Chegue perto rapidamente: ponto de partida de Ziegler–Nichols
Aumentar P até encontrar a oscilação não é apenas um teste de consistência — fornece um número a partir do qual é possível calcular todo o ajuste. Defina I e D como zero e aumente P até a saída oscilar de forma constante, sem crescer nem decair, e registre duas coisas:
Ku— o ganho proporcional no qual isso acontece (o ganho crítico)Tu— o período da oscilação, em segundos
Depois:
| Controlador | Kp |
Ki |
Kd |
|---|---|---|---|
| Somente P | 0.5 Ku |
— | — |
| PI | 0.45 Ku |
0.54 Ku / Tu |
— |
| PID (clássico) | 0.6 Ku |
1.2 Ku / Tu |
0.075 Ku Tu |
| PID (sem sobrepasso) | 0.2 Ku |
0.4 Ku / Tu |
0.066 Ku Tu |
Esses valores são um ponto de partida, não uma resposta. A linha clássica é deliberadamente agressiva e normalmente produz um sobrepasso de 20–40%, o que é aceitável para um motor e inaceitável para um braço robótico perto de uma mesa. A última linha troca velocidade de resposta por chegada sem sobrepasso.
O benefício do método é substituir três incógnitas por duas medições. Vinte
minutos para encontrar Ku e Tu deixam você mais perto do que uma tarde de tentativas, e você pode
ajustar por intuição a partir de um ponto sensato.
Tome o derivativo da medição, não do erro
Esta é uma alteração de uma linha que corrige o problema mais comum relacionado ao termo D.
Quando a referência dá um salto, o erro dá um salto com ela. O derivativo de um salto é enorme por um instante, portanto o controlador comanda uma correção abrupta por um motivo que não tem relação com a física — nada se moveu, você apenas pediu algo diferente. Em um robô, isso provoca um solavanco brusco toda vez que a referência muda.
// Derivative kick: the setpoint step goes straight into the output.
float derivative = (error - lastError) / dt;
// Derivative on measurement: the setpoint contributes nothing at all.
float derivative = -(measurement - lastMeasurement) / dt;
O sinal é invertido porque o erro é setpoint − measurement; portanto, derivar a medição
em vez do erro exige negação. Quando a referência é constante, as duas formas são matematicamente
idênticas; quando ela muda, somente a segunda se comporta bem.
Use o derivativo sobre a medição, a menos que você tenha um motivo específico para não fazer isso. Raramente o salto do derivativo é desejável.
Filtre o derivativo, ou D amplificará o ruído
A derivação amplifica conteúdo de alta frequência, e o ruído dos sensores é de alta frequência por definição. Um sinal com variação de ±2 contagens, amostrado a cada 10 ms, produz uma estimativa derivativa que varia em ±200 contagens por segundo — valor que o termo D converte em comandos de motor.
Normalmente, as pessoas concluem que D é inútil e o definem como zero. O problema real está antes:
// A first-order filter on the derivative term only.
// alpha = dt / (tau + dt); tau is the filter time constant in seconds.
const float tau = 0.05f; // 50 ms
const float alpha = dt / (tau + dt);
dFiltered += alpha * (dRaw - dFiltered);
Escolher tau é uma troca: se for pequeno, o ruído permanece; se for grande, D atua sobre
informação que já está desatualizada, exatamente o que D existe para evitar. Comece com três a
cinco vezes o período do seu ciclo e aumente somente até os solavancos cessarem.
Um controlador completo
Tudo acima, em um único lugar:
struct Pid {
float kp, ki, kd;
float outMin, outMax;
float tau; // derivative filter time constant
float integral = 0;
float lastMeasurement = 0;
float dFiltered = 0;
bool primed = false;
};
float pidUpdate(Pid &c, float setpoint, float measurement, float dt) {
if (dt <= 0) return 0;
const float error = setpoint - measurement;
// Derivative on measurement, low-pass filtered.
if (!c.primed) { c.lastMeasurement = measurement; c.primed = true; }
const float dRaw = -(measurement - c.lastMeasurement) / dt;
const float alpha = dt / (c.tau + dt);
c.dFiltered += alpha * (dRaw - c.dFiltered);
c.lastMeasurement = measurement;
// Provisional integral, committed only if the output does not saturate.
const float candidate = c.integral + error * dt;
const float raw = c.kp * error + c.ki * candidate + c.kd * c.dFiltered;
const float out = constrain(raw, c.outMin, c.outMax);
if (raw == out) c.integral = candidate; // conditional integration
return out;
}
Três elementos fazem a diferença entre um controlador que funciona em um robô e outro que funciona apenas em um livro didático: derivativo sobre a medição, derivativo filtrado e integração condicional, que impede o acúmulo do integrador enquanto o atuador está saturado.
Diagnosticando pela forma da resposta
É possível nomear quase todo defeito de ajuste apenas pela curva de resposta:
| O que você observa | O que significa | O que alterar |
|---|---|---|
| Sobe devagar e nunca chega | P baixo demais, sem I | Aumente P; adicione I se permanecer um desvio |
| Estabiliza sempre antes do alvo | Não há termo integral | Adicione I lentamente |
| Ultrapassa uma vez e depois estabiliza | P levemente alto, sem D | Adicione D |
| Ultrapassa repetidamente com oscilações decrescentes | P alto demais | Reduza P ou adicione D |
| Oscila para sempre com amplitude constante | P no ganho crítico | Você encontrou Ku — divida por dois |
| A oscilação cresce | P acima de Ku |
Reduza imediatamente |
| Saída rápida, irregular e instável | D atuando sobre ruído | Filtre o derivativo ou o sensor |
| Dá trancos fortes sempre que a referência muda | Salto do derivativo | Use o derivativo sobre a medição |
| Passa muito longe após um movimento grande | Windup integral | Use integração condicional ou limite o integrador |
| Funcionava ontem e está lento hoje | A planta mudou — normalmente a bateria | Os ganhos são propriedades da planta, não do código |
A última linha merece destaque porque não é um defeito. Os ganhos descrevem uma planta específica, e a planta inclui a carga da bateria, a massa do chassi, a superfície e a temperatura da caixa de engrenagens. Um ajuste perfeito com baterias novas ficará lento com baterias gastas, porque o mesmo ciclo de trabalho agora produz menos torque. As soluções usadas em sistemas profissionais são um ciclo de velocidade por baixo (de modo que o controlador comanda velocidade, não ciclo de trabalho) ou escalonamento de ganhos (vários ajustes, selecionados pela condição de operação).
Tempo do ciclo, quantificado
Tanto I quanto D são calculados em relação ao tempo decorrido, portanto um ciclo executado sempre que termina calcula os dois com base em um valor falso.
| Comportamento do ciclo | Efeito no controlador |
|---|---|
| Intervalo fixo | Tudo funciona como projetado |
Variável, mas com dt medido e passado como argumento |
Também correto — esta é a resposta prática |
Variável, com dt assumido como constante |
I acumula incorretamente; D se transforma em ruído |
Contém um delay() |
Tempo morto — nenhum valor de D compensa |
Meça dt com micros() e passe-o como argumento. Isso não custa nada, continua válido quando a duração do
ciclo muda conforme recursos são adicionados e elimina toda uma categoria de mistérios durante o ajuste.
Se também for possível deixar o ciclo rápido, faça — um controlador que amostra a 20 Hz está agindo sobre
informações com até 50 ms, e nenhum ganho corrige informações desatualizadas. Remover chamadas a delay()
normalmente leva um primeiro robô de 20 Hz para várias centenas de hertz, e o acompanhamento melhora sem
alterar nenhum ganho.
Experimente você mesmo
Abra o simulador de controlador PID, defina os ganhos I e D como zero e siga esta ordem. Observe como o sobrepasso, o tempo de acomodação e o erro em regime permanente respondem a cada termo isoladamente. Depois que a forma ficar clara aqui, a mesma intuição será transferível para um motor, aquecedor ou ciclo de direção no simulador de seguidor de linha.
Explore o grafo
Faz parte destas montagens
Projetos e caminhos de aprendizagem que incluem este tutorial.
Leitura complementar