J'essaie de contrôler un fader motorisé (potentiomètre à glissière linéaire) à l'aide d'un Arduino.
Le contrôle PID donne de bons résultats pour "sauter" à une position cible spécifique, mais le suivi des rampes est un problème, il n'est pas du tout lisse. Le mouvement est très saccadé, peu importe ce que j'essaie.
Voici un tracé de la position de référence, de la position mesurée et de la sortie du moteur lors du suivi d'une rampe:
Et voici une vidéo de ce même test.
Sur les systèmes commerciaux, cela semble beaucoup plus fluide, voyez ceci .
Détails :
Le fader du moteur est un Alps RSA0N11M9A0K . Pour le piloter, j'utilise un pont H ST L293D , alimenté par une alimentation régulée 10 V DC ( XL6009 ).
Sur l'Arduino UNO (ATmega328P), j'utilise les broches 9 et 10, avec une fréquence PWM de 31,372 kHz pour le rendre inaudible (Timer1 avec un pré-échelle de 1, TCCR1B = (TCCR1B & 0b11111000) | 0b001
).
Le potentiomètre est câblé entre la masse et 5V, avec l'essuie-glace allant à ADC0, comme d'habitude.
Le contrôleur :
J'utilise un simple contrôleur PID avec anti-windup, qui se met à jour à un rythme 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;
}
La sortie du contrôleur est une valeur comprise entre -127 et 127. La sortie PWM est générée comme suit:
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);
}
}
J'ai ajouté 48 au signal PWM 7 bits, car c'est là que le moteur commence à se déplacer à 31 kHz, puis je l'ai augmenté à un nombre 8 bits (car c'est ce que la analogWrite
fonction attend):
Ce que j'ai essayé :
j'ai essayé d'ajouter un filtre EMA à l'entrée, au signal de contrôle, à la composante dérivée du contrôleur PID, mais en vain. J'ai également essayé de réduire la résolution de l'entrée analogique, en utilisant l' hystérésis pour l'empêcher de basculer entre deux valeurs à l'arrêt. Cela ne semble rien affecter. Augmenter le pas de temps à 10 ms ne semble pas non plus aider.
J'ai également essayé de faire une identification du système dans MATLAB, et j'ai essayé de le régler dans Simulink (après cela série de vidéos ). J'ai eu un modèle avec un ajustement de 91%, mais je ne savais pas comment gérer les non-linéarités d'entrée et de sortie du modèle MATLAB, comment elles affectent le réglage PID et comment l'implémenter sur l'Arduino.
La dernière chose que j'ai essayée est de créer deux contrôleurs différents: un pour les grands sauts dans la position de référence et un pour les petites erreurs lors du suivi d'une rampe. Cela semble aider un peu, car alors je peux augmenter le coefficient intégral lors du suivi, sans augmenter le dépassement lors du saut.
Cependant, en augmentant le gain intégral (et proportionnel), le moteur fait maintenant toujours quelque chose, même lorsqu'il doit être stationnaire et que la référence ne change pas. (Il ne bouge pas vraiment, mais vous pouvez le sentir vibrer.)
Je n'ai pratiquement pas de gain dérivé, car l'augmentation plus élevée que 1e-4 semble le rendre encore plus saccadé, et je ne remarque pas vraiment de différence entre 0 et 1e-4.
Je suppose qu'il a besoin de plus de puissance pour surmonter le frottement statique, puis le frottement dynamique est moindre, donc il dépasse, donc il entraîne le moteur en arrière, le faisant s'arrêter à nouveau, puis il doit à nouveau surmonter le frottement statique, il tire à nouveau vers l'avant , etc.
Comment les contrôleurs commerciaux surmontent-ils ce problème?
Mes antécédents :
je suis en troisième année de bachelier en génie électrique, j'ai suivi des cours sur la théorie du contrôle, le traitement numérique du signal, le contrôle LQR, etc. J'ai donc des connaissances théoriques, mais j'ai du mal à appliquer toutes ces théories à ce système du monde réel.
Edit :
J'ai testé les mesures du capteur en boucle ouverte, comme recommandé par laptop2d, et je suis assez surpris des résultats: à des fréquences PWM élevées, il y a des pics désagréables dans les lectures. À 490 Hz, il n'y en a pas.
Et ceci est à un rapport cyclique constant, donc je ne peux pas imaginer quel genre de bruit je reçois lorsque le moteur inverse très rapidement la direction.
Je vais donc devoir trouver un moyen de filtrer ce bruit avant de recommencer à travailler sur le contrôleur.
Edit 2 : L'
utilisation d'un filtre exponentiel à moyenne mobile n'était pas suffisant pour filtrer le bruit.
J'ai essayé avec des poteaux en 0,25, 0,50 et 0,75. Les petits poteaux n'ont pas eu beaucoup d'effet, et les plus grands poteaux ont ajouté trop de latence, j'ai donc dû réduire les gains pour le maintenir stable, ce qui a entraîné une dégradation des performances globales.
J'ai ajouté un condensateur de 0,1 µF à travers le potentiomètre (entre l'essuie-glace et la masse), et cela semble le nettoyer.
Pour l'instant, cela fonctionne assez bien. En attendant, je lis le journal publié par Tim Wescott .
Merci à tous pour votre aide.
This device is suitable for use in switching applications at frequencies up to 5 kHz.
Mais les caractéristiques électriques à la page 3 suggèrent un maximum absolu de 690 kHz si vous additionnez tous les retards. (4 dernières lignes) Personnellement, j'irais beaucoup plus lentement que cela, mais je pense que 31 kHz devraient être adéquats ... sans la note de la page 1.