Estou tentando controlar um fader motorizado (potenciômetro linear deslizante) usando um Arduino.
O controle PID fornece bons resultados para "pular" para uma posição-alvo específica, mas rastrear rampas é um problema, não é nada suave. O movimento é muito instável, não importa o que eu tente.
Aqui está um gráfico da posição de referência, da posição medida e da saída do motor ao rastrear uma rampa:
E aqui está um vídeo desse mesmo teste.
Em sistemas comerciais, parece muito mais suave, veja isso .
Detalhes :
O fader do motor é um RSA0N11M9A0K dos Alpes . Para controlá - lo, estou usando uma ponte H ST L293D , alimentada por uma fonte de alimentação regulada de 10 V DC ( XL6009 ).
No UNO do Arduino (ATmega328P), estou usando os pinos 9 e 10, com uma frequência PWM de 31.372 kHz para torná-lo inaudível (Timer1 com um pré-calibrador de 1,TCCR1B = (TCCR1B & 0b11111000) | 0b001
).
O potenciômetro é conectado entre o terra e 5V, com o limpador indo para ADC0, como de costume.
O controlador :
estou usando um controlador PID simples com anti-corda, que é atualizado a uma taxa de 1 kHz (Ts = 1e-3 s):
float update(int16_t input) {
int16_t error = setpoint - input;
int16_t newIntegral = integral + error;
float output = k_p * error
+ k_i * newIntegral * Ts
+ k_d * (input - previousInput) / Ts;
if (output > maxOutput)
output = maxOutput;
else if (output < -maxOutput)
output = -maxOutput;
else
integral = newIntegral;
previousInput = input;
return output;
}
A saída do controlador é um valor de -127 a 127. A saída PWM é gerada da seguinte maneira:
const int8_t knee = 48;
uint8_t activation(int8_t val) {
if (val == 0)
return 0;
else {
return map(val, 0, 127, 2 * knee, 255);
}
}
void writeMotor(int8_t val) {
if (val >= 0) {
analogWrite(forward, activation(val));
digitalWrite(backward, 0);
} else {
analogWrite(backward, activation(-val));
digitalWrite(forward, 0);
}
}
Adicionei 48 ao sinal PWM de 7 bits, porque é aí que o motor começa a se mover a 31 kHz e, em seguida, escalono-o para um número de 8 bits (porque é isso que a analogWrite
função espera):
O que eu tentei :
tentei adicionar um filtro EMA à entrada, ao sinal de controle e ao componente derivado do controlador PID, mas sem sucesso. Também tentei abaixar a resolução da entrada analógica, usando a histerese para impedir que ela alternasse entre dois valores quando estacionária. Isso não parece afetar nada. Aumentar o tempo para 10 ms também não parece ajudar.
Também tentei fazer uma identificação do sistema no MATLAB e tentei ajustá-lo no Simulink (seguindo este série de vídeos ). Consegui um modelo com um ajuste de 91%, mas não sabia como lidar com as não linearidades de entrada e saída do modelo MATLAB, como elas afetam o ajuste do PID e como implementá-lo no Arduino.
A última coisa que tentei é fazer dois controladores diferentes: um para grandes saltos na posição de referência e outro para pequenos erros ao rastrear uma rampa. Isso parece ajudar um pouco, porque então eu posso aumentar o coeficiente integral no rastreamento, sem aumentar o overshoot ao pular.
No entanto, aumentando o ganho integral (e proporcional), o motor agora está sempre fazendo alguma coisa, mesmo quando deve estar parado e a referência não muda. (Ele realmente não se move, mas você pode senti-lo vibrando.)
Não tenho praticamente nenhum ganho derivativo, porque aumentá-lo acima de 1e-4 parece torná-lo ainda mais instável e não percebo nenhuma diferença entre 0 e 1e-4.
Meu palpite é que ele precisa de mais energia para superar o atrito estático, então o atrito dinâmico é menor, então ele ultrapassa, então aciona o motor para trás, fazendo com que ele pare novamente, então ele precisa superar o atrito estático novamente, dispara para a frente novamente , etc.
Como os controladores comerciais superam esse problema?
Minha formação :
estou no meu terceiro ano de bacharelado em engenharia elétrica, segui cursos de teoria de controle, processamento de sinal digital, controle LQR etc., por isso tenho alguma formação teórica, mas estou tendo problemas para aplicar todas essas este sistema do mundo real.
Edit :
Eu testei as medições do sensor de malha aberta, como o laptop2d recomendou, e estou bastante surpreso com os resultados: Em altas frequências PWM, existem picos desagradáveis nas leituras. Em 490 Hz, não há nenhum.
E isso está em um ciclo de trabalho constante, então não consigo imaginar que tipo de ruído recebo quando o motor está invertendo a direção muito rapidamente.
Portanto, terei que encontrar uma maneira de filtrar esse ruído antes de começar a trabalhar no controlador novamente.
Edit 2 :
Usar um filtro de média móvel exponencial não foi suficiente para filtrar o ruído.
Eu tentei com pólos em 0,25, 0,50 e 0,75. Postes pequenos não tiveram muito efeito, e postes maiores adicionaram muita latência, então tive que diminuir os ganhos para mantê-lo estável, resultando em pior desempenho geral.
Adicionei um capacitor de 0,1 µF no potenciômetro (entre o limpador e o terra), e isso parece limpá-lo.
Por enquanto, funciona bem o suficiente. Enquanto isso, estou lendo o artigo publicado por Tim Wescott .
Obrigado a todos por sua ajuda.
This device is suitable for use in switching applications at frequencies up to 5 kHz.
Mas as características elétricas na página 3 sugerem um máximo absoluto de 690kHz se você adicionar todos os atrasos. (linhas de fundo 4) Pessoalmente, eu iria muito mais devagar do que isso, mas acho que 31kHz deveria ser adequado ... se não fosse a nota na página 1.Respostas:
Um sistema de controle é tão bom quanto seu sensor, execute o loop aberto do sensor e remova a entrada de controle. Crie sua própria entrada no sensor e deslize-a lentamente (ou encontre uma maneira de deslizá-la lentamente e com segurança) enquanto obtém os dados de posição para garantir que não seja o sensor. Se o sensor estiver barulhento, melhore o desempenho adquirindo um novo sensor ou em paralelo ou filtrando a saída do sensor . Você pode precisar de um sensor com maior resolução.
Se o sensor não estiver barulhento, você precisará obter um loop de controle diferente. Os PIDs são sistemas de primeira ordem e não são realmente ótimos no controle de taxas.
fonte
Você está certo de que o problema é causado pelo atrito ou, possivelmente, uma combinação de atrito e folga. Seu gráfico de velocidade média versus ciclo de trabalho para várias larguras de pulso é característico de um sistema com atrito. Este documento explica o que você está vendo e possui um compêndio de soluções que são usadas desde sempre para lidar com os problemas. Você não os verá em seu currículo de engenharia porque é difícil de analisar; você basicamente precisa mexer com eles caso a caso para fazê-los funcionar.
Não sei o que os controladores comerciais fazem, apesar de suspeitar que haja uma variedade de soluções por aí. O que eu fiz no passado com coisas assim é quando o sinal de acionamento do motor fora do meu controlador PID cai abaixo de algum limite (provavelmente de 60 a 70 contagens no seu caso) eu começo a pulsar o acionamento do motor no limite, com uma obrigação ciclo que torna a unidade média igual à saída do PID. Eu geralmente uso um modulador sigma-delta-ish para isso, porque ele pode ser implementado em muito poucas linhas, mas você pode usar o que funcionar melhor para você.
fonte
Parece que a maior parte do ruído é proveniente do sinal da unidade PWM.
Você já tentou sincronizar a captura do ADC com o ciclo PWM? A maioria dos microcontroladores tem uma maneira de disparar a captura do ADC no timer, para que você possa sempre disparar no mesmo ponto do ciclo.
Para um ruído mais baixo, a posição ideal de amostragem seria correta antes de ligar a alimentação do motor, porque qualquer pico teve mais tempo para se estabilizar. Mas, independentemente da posição, a sincronização da captura reduzirá os picos porque a quantidade de deslocamento permanecerá aproximadamente a mesma no mesmo ponto do ciclo do PWM.
fonte
Você pode filtrar o ruído do sensor (ou qualquer outra medição / variável com ruído) no código com algo como isto (filtragem passa-baixo):
Onde0 < < ct ≤ 1 . Quanto mais próximo de 1, mais suave será a aparência, mas também adiciona mais atraso, comece com um valor de 0,9, por exemplo, e veja como ele se comporta.
fonte