Boucles de contrôle PID avec des anomalies importantes et imprévisibles

10

Question courte
Existe-t-il un moyen commun de traiter de très grandes anomalies (ordre de grandeur) dans une région de contrôle autrement uniforme?

Contexte
Je travaille sur un algorithme de contrôle qui entraîne un moteur dans une région de contrôle généralement uniforme. Sans charge / minimale, le contrôle PID fonctionne très bien (réponse rapide, peu ou pas de dépassement). Le problème que je rencontre est qu'il y aura généralement au moins un emplacement à charge élevée. La position est déterminée par l'utilisateur lors de l'installation, il n'y a donc aucun moyen raisonnable pour moi de savoir quand / où l'attendre.

Lorsque j'accorde le PID pour gérer l'emplacement de charge élevée, cela provoque de grandes prises de vue sur les zones non chargées (ce à quoi je m'attendais). Bien qu'il soit OK de dépasser la mi-course, il n'y a pas d'arrêts mécaniques durs sur le boîtier. L'absence d'arrêts durs signifie que tout dépassement important peut / entraîne la déconnexion du bras de commande du moteur (entraînant une unité morte).

Choses que je prototypage

  • PID imbriqués (très agressifs lorsqu'ils sont loin de la cible, conservateurs lorsqu'ils sont proches)
  • Gain fixe à distance, PID à proximité
  • PID conservateur (fonctionne sans charge) + un contrôle externe qui recherche le PID pour caler et appliquer de l'énergie supplémentaire jusqu'à ce que: l'objectif soit atteint ou un taux de changement rapide soit détecté (c'est-à-dire quitter la zone de charge élevée)

Limites

  • Voyage complet défini
  • Les arrêts fixes ne peuvent pas être ajoutés (à ce stade)
  • L'erreur ne sera probablement jamais remise à zéro
  • La charge élevée aurait pu être obtenue à partir d'une course inférieure à 10% (ce qui signifie pas de "démarrage en cours")
Adam Lewis
la source

Réponses:

2

Votre calcul d'erreur ne semble pas accumuler d'erreur lorsque vous travaillez avec le terme dérivé, et vous souhaiterez peut-être le modifier car seul le terme dérivé est capable de réagir aux changements rapides du processus.

Si j'ai bien compris ton code

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

calculera toujours le terme de contrôle en fonction de l'erreur actuelle, qui est la manière traditionnelle dont le PID a été implémenté. C'est très bien puisque le terme I est censé de toute façon s'occuper des erreurs accumulées.

Cependant, j'ai eu un client qui a eu l'idée suivante que vous voudrez peut-être essayer. Puisque vous avez une partie de la courbe de processus où des changements plus agressifs sont nécessaires, vous pouvez laisser même l'erreur de la partie D s'accumuler:

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)

Il y a deux choses intéressantes à noter ici:

  • La valeur TD n'est pas le gain dérivé (qui est KD) mais le temps dérivé, une constante utilisateur qui contrôle le temps pour que l'erreur s'accumule. S'il était réglé sur zéro, la partie D du PID est désactivée, sans tenir compte de la valeur de gain KD définie.

  • Notez comment l'erreur actuelle a été utilisée pour «facturer» la valeur Last_C avant de la transférer au calcul de la partie D. La variable Last_C agit comme un condensateur, elle s'accumulerait alors que l'erreur était importante, de sorte que votre partie dérivée agirait également sur la base d'un `` historique '' récent de l'erreur, et après cela (lorsque l'erreur était plus petite), cette `` histoire 'se déchargera comme un condensateur.

Bien sûr, vous devez limiter la sortie totale comme vous le faites probablement déjà (réinitialisation anti-liquidation, auto sans à-coups au transfert manuel et autres trucs habituels).

Je peux publier plus de détails sur les autres termes de mon algorithme PID si vous le trouvez utile, mais vous voudrez peut-être essayer cela et voir ce qui se passe. Cela a bien servi mon client pendant des années.

Drazen Cika
la source
Merci pour la contribution. Je vais devoir essayer. En un coup d'œil, cela semble logique.
Adam Lewis
Je vois, donc vous avez une contribution de terme D dans votre PID «principal» plus tout ce que la détection de décrochage apporte au calcul.
Drazen Cika
1
C'est correct. Le Dterm du PID est utilisé, mais pas très agressif, pendant le réglage. Ce qui rend ce problème encore plus difficile, c'est que la charge peut se libérer en très peu de temps. IE une liaison étant désengagée. Cette suppression brutale de la force provoque de grands dépassements lorsqu'il y a une fonction de lissage (sommation) appliquée aux forces de décrochage.
Adam Lewis
Problème épineux, il serait intéressant de savoir dans quelle mesure un algorithme de logique floue gérerait cela. Au moins, vous pourriez intégrer davantage votre expérience liée aux problèmes dans l'algorithme, au lieu de rester confiné dans les solutions standard. Quoi qu'il en soit, bonne chance avec cela :-)
Drazen Cika
1

Solution initiale

stalled_pwm_output = PWM / | ΔE |

PWM = valeur PWM max
ΔE = dernière_erreur - nouvelle_erreur

La relation initiale augmente avec succès la sortie PWM en raison de l' absence de changement dans le moteur. Voir le graphique ci-dessous pour l'exemple de sortie.

Cette approche fait depuis pour la situation où le PID non agressif a calé. Cependant, il a le problème malheureux (et évident) que lorsque le PID non agressif est capable d'atteindre le point de consigne et tente de ralentir, le stalled_pwm_output augmente. Cette montée en charge provoque un dépassement important lors du déplacement vers une position non chargée.

1 / ΔE vs ΔE

Solution actuelle

Théorie

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

kE = constante de mise à l'échelle
PID_PWM = demande PWM actuelle du PID non
agressif ΔE = last_error - new_error

Ma relation actuelle utilise toujours le concept 1 / ΔE, mais utilise la sortie PID PWM non agressive pour déterminer le stall_pwm_output. Cela permet au PID d'étouffer le stall_pwm_output lorsqu'il commence à se rapprocher du point de consigne cible, tout en autorisant une sortie PWM à 100% lorsqu'il est bloqué. La constante de mise à l'échelle kE est nécessaire pour garantir que le PWM pénètre dans le point de saturation (supérieur à 10 000 dans les graphiques ci-dessous).

Pseudo code

Notez que le résultat de cal_stall_pwm est ajouté à la sortie PID PWM dans ma logique de contrôle actuelle.

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;
}

Des données de sortie

Sortie PWM bloquée Sortie PWM bloquée

Notez que dans le graphique de sortie PWM au point mort, la chute soudaine de PWM à ~ 3400 est une fonction de sécurité intégrée activée parce que le moteur n'a pas pu atteindre la position dans un délai donné.

Sortie PWM non chargée Sortie PWM à vide

Adam Lewis
la source
1

Vous ne dites pas ce que vous contrôlez ... la vitesse du moteur? position? Quoi qu'il en soit, la première étape serait de définir ce qu'est une erreur acceptable. Par exemple, si le contrôle concerne la vitesse, une erreur maximale de moins de 1% de la cible peut être définie. Sans définir l'erreur acceptable, vous ne pouvez pas déterminer la résolution dont vous avez besoin pour les ADC ou le nombre de PWM. Sans cela, la compensation PID pourrait être parfaite, mais aurait toujours des oscillations de cycle limite.

Ensuite, vous devez connaître la dynamique du système en boucle ouverte. Sans cela, vous ne pouvez pas savoir quels gains sont nécessaires pour les parties proportionnelle (P), intégrale (I) et dérivée (D) de la boucle. Vous pouvez mesurer la dynamique avec un pas d'entrée (changement de pas du niveau d'entraînement ou PWM) ou des changements de pas de charge (cela semble pertinent pour vous).

L'utilisation de la modification d'erreur cycle à cycle, dans le dénominateur de votre algo de contrôle, pour modifier la valeur PWM garantit que la boucle ne s'établira jamais. Cela garantit une oscillation de cycle limite dans la commande. La plupart des clients ne l'accepteraient pas.

La partie P de la boucle s'occupe de l'erreur immédiate (répond rapidement à une erreur). Mais il aura un gain fini, il restera donc une erreur. La partie I de la boucle réagit lentement au fil du temps pour appliquer un gain infini (temps infini pour un gain infini) pour corriger cette erreur qui a été laissée par la partie P.

Étant donné que la partie I est lente, elle peut être déphasée avec la correction nécessaire pour la minimisation des erreurs, même si vous avez réglé le gain approprié. Ainsi, il s'enroule, ce qui prend beaucoup de temps pour récupérer. Ou, il est laissé en opposition à la partie P.

La meilleure façon de gérer la liquidation est de limiter la valeur maximale stockée dans l'intégrateur à un peu plus que ce qui est nécessaire pour corriger l'erreur proportionnelle au pire des cas. Si l'intégrateur est déphasé et opposé au P séparé, la meilleure chose à faire est de mettre la valeur de l'intégrateur à zéro. L'algo peut être conçu pour détecter cela et réinitialiser l'intégrateur si nécessaire.

gsills
la source