Circuiti di controllo PID con anomalie grandi e imprevedibili


10

Breve domanda
Esiste un modo comune per gestire anomalie molto grandi (ordine di grandezza) all'interno di una regione di controllo altrimenti uniforme?

Sfondo
Sto lavorando ad un algoritmo di controllo che guida un motore attraverso una regione di controllo generalmente uniforme. Con il carico minimo / minimo il controllo PID funziona alla grande (risposta rapida, superamento minimo o nullo). Il problema in cui mi imbatto è che di solito ci sarà almeno una posizione di carico elevato. La posizione viene determinata dall'utente durante l'installazione, quindi non ho modo ragionevole di sapere quando / dove aspettarmi.

Quando eseguo l'ottimizzazione del PID per gestire la posizione di carico elevato, si verificano grandi tiri eccessivi sulle aree non caricate (cosa che mi aspettavo completamente). Mentre è OK per viaggiare overshoot metà, non ci sono fermi meccanici duri sulla custodia. La mancanza di hardstop significa che qualsiasi significativo superamento può / fa causare la disconnessione del braccio di controllo dal motore (dando luogo a un'unità morta).

Cose che sto prototipando

  • PID nidificati (molto aggressivi quando lontani dal bersaglio, conservativi quando vicini)
  • Guadagno fisso quando lontano, PID quando vicino
  • PID conservativo (funziona senza carico) + un controllo esterno che cerca il PID per arrestarsi e applicare energia aggiuntiva fino a quando: l'obiettivo viene raggiunto o viene rilevato un rapido tasso di cambiamento (ovvero lasciando l'area di carico elevato)

limitazioni

  • Viaggio completo definito
  • Gli hard disk non possono essere aggiunti (in questo momento)
  • L'errore probabilmente non azzererà mai
  • Il carico elevato avrebbe potuto essere ottenuto da una corsa inferiore al 10% (il che significa che nessun "avvio in marcia")

Risposte:


2

Il calcolo dell'errore non sembra accumulare errori quando si lavora con il termine derivato e potrebbe essere necessario modificarlo poiché solo il termine derivato è in grado di reagire ai rapidi cambiamenti nel processo.

Se ho capito bene il tuo codice

// Determine the error delta
dE = abs(last_error - new_error);
last_error = new_error;

calcolerà sempre il termine di controllo in base all'errore corrente, che è il modo tradizionale in cui è stato implementato il PID. Va bene dal momento che il termine I dovrebbe occuparsi comunque dell'errore accumulato.

Tuttavia, ho avuto un cliente che ha avuto la seguente idea che potresti voler provare. Poiché hai una parte della curva del processo in cui sono necessari cambiamenti più aggressivi, puoi lasciare accumulare anche l'errore della parte D:

if(TD)                                                 // Calculate D term
{  
   Last_C += (Error - Last_C) / TD;                    // D term simulates
   Dterm = (Error - Last_C) * KD;                      // capacitor discharging
}
else    
   Dterm = 0;                                          // D term is OFF (TD is 0)

Ci sono due cose interessanti da notare qui:

  • Il valore TD non è il guadagno derivativo (che è KD) ma il tempo derivativo, una costante utente che controlla il tempo di accumulo dell'errore. Se era impostato su zero, la parte D del PID è disabilitata ignorando il valore di guadagno KD impostato.

  • Nota come è stato utilizzato l'errore corrente per "caricare" il valore Last_C prima di trasferirlo nel calcolo della parte D. La variabile Last_C si comporta come un condensatore, si accumulerebbe mentre l'errore era grande, in modo che la parte derivata agisse anche in base a una "cronologia" recente dell'errore, e successivamente (quando l'errore era minore) questa "cronologia 'si scaricherà come un condensatore.

Ovviamente, dovresti limitare l'output totale nel modo in cui probabilmente già lo fai (ripristino anti-windup, auto bumpless al trasferimento manuale e altre cose normali).

Posso pubblicare ulteriori dettagli su altri termini del mio algoritmo PID se lo trovi utile, ma potresti voler provare questo e vedere cosa succede. Ha servito bene il mio cliente per anni.


Grazie per l'input. Dovrò provarlo. A prima vista sembra avere senso.
Adam Lewis,

Vedo, quindi hai un contributo a termine D all'interno del tuo PID "principale" più qualunque rilevamento di stallo porti al calcolo.
Drazen Cika,

1
È corretto. Dterm del PID viene utilizzato, anche se non molto aggressivo, durante la messa a punto. Ciò che rende questo problema ancora più difficile è che il carico può liberarsi in un arco di tempo molto breve. Vale a dire un collegamento che viene disattivato. Questa brusca rimozione della forza provoca grandi superamenti quando c'è una funzione di livellamento (somma) applicata alle forze di stallo.
Adam Lewis,

Problema malvagio, sarebbe interessante sapere quanto bene sarebbe gestito da un algoritmo di logica fuzzy. Almeno potresti integrare la maggior parte della tua esperienza relativa ai problemi nell'algoritmo, invece di rimanere confinato nelle soluzioni standard. Ad ogni modo, buona fortuna con questo :-)
Drazen Cika,

1

Soluzione iniziale

stalled_pwm_output = PWM / | ΔE |

PWM = Valore PWM massimo
ΔE = last_error - new_error

La relazione iniziale aumenta correttamente l'uscita PWM in base alla mancanza di modifiche nel motore. Vedere il grafico seguente per l'output di esempio.

Questo approccio rende la situazione in cui il PID non aggressivo si è bloccato. Tuttavia, ha lo sfortunato (e ovvio) problema che quando il PID non aggressivo è in grado di raggiungere il setpoint e tenta di rallentare, stalled_pwm_output aumenta. Questa salita provoca un grande superamento quando si viaggia in una posizione non caricata.

1 / ΔE vs ΔE

Soluzione attuale

Teoria

stalled_pwm_output = (kE * PID_PWM) / | ΔE |

kE = Costante di scala
PID_PWM = Richiesta PWM corrente dal PID non aggressivo
ΔE = last_error - new_error

La mia relazione attuale utilizza ancora il concetto 1 / ΔE, ma utilizza l'output PWM PID non aggressivo per determinare lo stallo_pwm_output. Ciò consente al PID di rallentare il valore stall_pwm_output quando inizia ad avvicinarsi al setpoint di destinazione, ma consente al 100% di uscita PWM in caso di stallo. La costante di ridimensionamento kE è necessaria per garantire che il PWM raggiunga il punto di saturazione (sopra 10.000 nei grafici sotto).

Codice pseudo

Si noti che il risultato di cal_stall_pwm viene aggiunto all'uscita PWM PID nella mia logica di controllo corrente.

int calc_stall_pwm(int pid_pwm, int new_error)
{
    int ret = 0;
    int dE = 0;
    static int last_error = 0;
    const int kE = 1;

    // Allow the stall_control until the setpoint is achived
    if( FALSE == motor_has_reached_target())
    {
        // Determine the error delta
        dE = abs(last_error - new_error);
        last_error = new_error;

        // Protect from divide by zeros
        dE = (dE == 0) ? 1 : dE;

        // Determine the stall_pwm_output
        ret = (kE * pid_pwm) / dE;
    }

    return ret;
}

Dati di output

Uscita PWM bloccata Uscita PWM bloccata

Si noti che nel grafico di uscita PWM in stallo la caduta improvvisa di PWM a ~ 3400 è una funzione di sicurezza integrata attivata perché il motore non è stato in grado di raggiungere la posizione entro un determinato tempo.

Uscita PWM non caricata Uscita PWM a vuoto


1

Non dici che cosa stai controllando ... velocità del motore? posizione? Bene, qualunque cosa sia, il primo passo sarebbe definire quale sarebbe un errore accettabile. Ad esempio, se il controllo è per la velocità, è possibile impostare un errore massimo entro l'1% del target. Senza definire l'errore accettabile non è possibile determinare la risoluzione necessaria per gli ADC o il conteggio PWM. Senza questo, la compensazione PID potrebbe essere perfetta, ma avrebbe comunque oscillazioni del ciclo limite.

Quindi è necessario conoscere la dinamica del sistema ad anello aperto. Senza questo non puoi sapere quali guadagni sono necessari per le parti proporzionale (P), integrale (I) e derivata (D) del loop. È possibile misurare la dinamica con il passo di input (cambio di passo nel livello di azionamento o PWM), o cambi di passo nel carico (sembra che questo sia rilevante per te).

L'uso della modifica dell'errore ciclo-ciclo, nel denominatore dell'algoritmo di controllo, per modificare il valore PWM assicura che il loop non si stabilizzerà mai. Ciò garantisce un'oscillazione del ciclo limite nel controllo. La maggior parte dei clienti non ce la farebbe.

La parte P del ciclo si occupa dell'errore immediato (risponde prontamente a un errore). Ma avrà un guadagno finito, quindi rimarrà qualche errore. La parte I del ciclo reagisce lentamente nel tempo per applicare un guadagno infinito (tempo infinito per guadagno infinito) per correggere quell'errore lasciato dalla parte P.

Poiché la parte I è lenta, può sfasarsi con la correzione necessaria per minimizzare gli errori, anche se hai impostato il guadagno giusto. Quindi, si finisce, impiegando molto tempo per riprendersi. Oppure, viene lasciato in opposizione alla parte P.

Il modo migliore per gestire la liquidazione è limitare il valore massimo memorizzato nell'integratore a un po 'più di quanto è necessario per correggere l'errore proporzionale nel caso peggiore. Se l'integratore esce di fase e in opposizione alla P a parte, la cosa migliore da fare è impostare il valore dell'integratore su zero. L'algo può essere progettato per rilevare ciò e ripristinare l'integratore quando necessario.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.