Sto cercando di controllare un fader motorizzato (potenziometro lineare a scorrimento) usando un Arduino.
Il controllo PID fornisce buoni risultati per "saltare" verso una posizione target specifica, ma il monitoraggio delle rampe è un problema, non è affatto regolare. Il movimento è molto a scatti, qualunque cosa io provi.
Ecco un grafico della posizione di riferimento, della posizione misurata e dell'uscita del motore quando si traccia una rampa:
Ed ecco un video di quello stesso test.
Sui sistemi commerciali, sembra molto più fluido, vedi questo .
Dettagli :
il fader del motore è un Alps RSA0N11M9A0K . Per guidarlo, sto usando un H-bridge ST L293D , alimentato da un alimentatore a 10 V CC regolato ( XL6009 ).
Su Arduino UNO (ATmega328P), sto usando i pin 9 e 10, con una frequenza PWM di 31.372 kHz per renderlo impercettibile (Timer1 con un prescaler di 1, TCCR1B = (TCCR1B & 0b11111000) | 0b001
).
Il potenziometro è cablato tra terra e 5 V, con il tergicristallo diretto su ADC0, come al solito.
Il controller :
sto usando un semplice controller PID con anti-windup, che si aggiorna ad una frequenza di 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;
}
L'uscita del controller ha un valore compreso tra -127 e 127. L'uscita PWM viene generata come segue:
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);
}
}
Ho aggiunto 48 al segnale PWM a 7 bit, perché è lì che il motore inizia a muoversi a 31 kHz, quindi lo ridimensiono fino a un numero di 8 bit (perché è quello che la analogWrite
funzione si aspetta):
Cosa ho provato :
ho provato ad aggiungere un filtro EMA all'ingresso, al segnale di controllo, al componente derivato del controller PID, ma senza risultati. Ho anche provato ad abbassare la risoluzione dell'ingresso analogico, usando l' isteresi per impedirgli di passare tra due valori quando è fermo. Questo non sembra influenzare nulla. Anche aumentare il tempo a 10 ms non sembra aiutare.
Ho anche provato a fare un'identificazione di sistema in MATLAB e ho provato a sintonizzarla in Simulink (seguendo questa serie di video ). Ho ottenuto un modello con un adattamento del 91%, ma non sapevo come gestire le non linearità di input e output del modello MATLAB, in che modo influiscono sulla regolazione PID e come implementarlo su Arduino.
L'ultima cosa che ho provato è realizzare due controller diversi: uno per i salti di grandi dimensioni nella posizione di riferimento e uno per i piccoli errori durante il tracciamento di una rampa. Questo sembra aiutare un po ', perché poi posso aumentare il coefficiente integrale durante il tracking, senza aumentare il superamento durante il salto.
Tuttavia, aumentando il guadagno integrale (e proporzionale), il motore ora fa sempre qualcosa, anche quando dovrebbe essere fermo e il riferimento non cambia. (Non si muove davvero, ma puoi sentirlo vibrare.)
Non ho praticamente alcun guadagno derivato, perché aumentarlo più in alto di 1e-4 sembra renderlo ancora più nervoso, e non noto davvero alcuna differenza tra 0 e 1e-4.
La mia ipotesi è che abbia bisogno di più potenza per superare l'attrito statico, quindi l'attrito dinamico è minore, quindi si supera, quindi spinge il motore all'indietro, facendolo arrestare di nuovo, quindi deve superare di nuovo l'attrito statico, spara di nuovo in avanti , eccetera.
In che modo i controller commerciali superano questo problema?
Il mio background :
Sono al mio terzo anno di laurea in ingegneria elettrica, ho seguito corsi di teoria del controllo, elaborazione del segnale digitale, controllo LQR ecc. Quindi ho un background teorico, ma ho problemi ad applicare tutte quelle teorie a questo sistema del mondo reale.
Modifica :
ho testato le misurazioni del sensore ad anello aperto, come raccomandato da laptop2d, e sono abbastanza sorpreso dai risultati: ad alte frequenze PWM, ci sono picchi cattivi nelle letture. A 490 Hz, non ce ne sono.
E questo è a un ciclo di lavoro costante, quindi non riesco a immaginare che tipo di rumore ricevo quando il motore inverte la direzione molto rapidamente.
Quindi dovrò trovare un modo per filtrare quel rumore prima di ricominciare a lavorare sul controller.
Modifica 2 : L'
uso di un filtro esponenziale a media mobile non era sufficiente per filtrare il rumore.
Ho provato con i poli in 0,25, 0,50 e 0,75. I poli piccoli non hanno avuto molto effetto e i poli più grandi hanno aggiunto troppa latenza, quindi ho dovuto ridurre i guadagni per mantenerlo stabile, con conseguente peggioramento delle prestazioni complessive.
Ho aggiunto un condensatore da 0,1 µF attraverso il potenziometro (tra tergicristallo e terra) e questo sembra pulirlo.
Per ora funziona abbastanza bene. Nel frattempo, sto leggendo l' articolo pubblicato da Tim Wescott .
Grazie a tutti per il vostro aiuto.
This device is suitable for use in switching applications at frequencies up to 5 kHz.
Ma le caratteristiche elettriche a pagina 3 suggeriscono un massimo assoluto di 690kHz se sommi tutti i ritardi. (righe 4 in basso) Personalmente, andrei molto più lentamente di così, ma penso che 31kHz dovrebbe essere adeguato ... se non fosse per la nota a pagina 1.