Go Down

Topic: Décodeurs quadratiques pour 4 moteurs sur un UNO ? (Read 213 times) previous topic - next topic

demokrato

  Bonjour à tous,

J'ai tenté l'année passée de gérer un asservissement vitesse sur quatre moteurs à la fois en récupérant les infos des compteurs quadratiques de 4 moteurs différents sur une Arduino méga.
Avec mes gros souliers, j'ai créer 4 "attach interrupt" (oui pour bien il en aurait fallu 8) pour un résultat absolument mauvais. Avec un moteur, les interruptions fonctionnaient bien et je lisais une vitesse cohérente.
A 4 moteurs c'était une catastrophe et toute les interruptions n'étaient pas comptées.

Aujourd'hui je découvre la lib Encoder.h qui semble me dire que je peux, et d'un autre coté, un roboticien rencontré cet été me dit que je dois séparé physiquement les calculs de robot et le contrôle de vitesse de mes moteurs.
 Avez vous des retour d'experience par rapport à cela ?

Merci :)

Jambe

Bonjour,

Un extrait d'un exemple de la lib:
Quote
// Change these pin numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
Pour 4 encodeurs et "good performance", il te faut a minima 4 interruptions, donc une méga (qui en a 6), la uno en gère "matériellement" que 2.

Avec une UNO, tu passe en Low performance. Pour des moteurs, selon la vitesse de rotation et le nombre de "pulse" par tour, ça me parait compromis


ard_newbie


Pour gérer des encodeurs quadratiques, il est fortement recommandé d'utiliser des timers en mode input-capture avec 2 entrées, une pour la phase A et l'autre pour la phase B. La fréquence des timers doit être suffisamment élevée pour pouvoir mesurer la durée entre 2 évènements, c.a.d. les fronts des signaux envoyés par l'encodeur. Le uc doit aussi être capable d'effectuer des calculs sur les données des timers.

A ma connaissance, l'Arduino DUE est pourvu de (2) décodeurs quadratiques intégrés et d'une palanquée de timers dont 5 d'entre eux ont les entrées citées plus haut (soit 10 pins) nécessaires aux phases A/phases B.

3Sigma

Bonjour,

Je fais de l'asservissement de vitesse des 4 moteurs de l'un des mes robots avec une Mega. Si tu n'y arrives pas, c'est sans doute qu'il y a des problèmes dans ton code.

Schématiquement, ça se passe comme ça:
  • j'ai un timer qui exécute la tâche principale à 10 ms (avec la librairie flexitimer2)
  • en parallèle, les entrées codeurs sont branchées sur 4 interruptions
  • toutes les 10 ms, je compte le nombre d'interruptions sur chaque codeur, ce qui permet de récupérer la vitesse


Pour gérer des encodeurs quadratiques, il est fortement recommandé d'utiliser des timers en mode input-capture avec 2 entrées, une pour la phase A et l'autre pour la phase B. La fréquence des timers doit être suffisamment élevée pour pouvoir mesurer la durée entre 2 évènements, c.a.d. les fronts des signaux envoyés par l'encodeur. Le uc doit aussi être capable d'effectuer des calculs sur les données des timers.
En théorie ça devrait pouvoir se passer comme ça, mais tout dépend des encodeurs que tu utilises: si c'est du "pas cher" (genre codeur magnétique avec entre 3 et 16 aimants), tu n'es pas sûr d'avoir un écart angulaire constant entre les aimants. Et dans ce cas, tu as une mesure de vitesse pourrie car même avec une vitesse super-constante, tu as un écart temporel entre deux fronts qui n'est pas constant, car l'écart angulaire entre deux aimants ne l'est pas.

ard_newbie


Je pense plutôt à ce type d'encodeur quadratique 600 p/r:


68tjs

la uno en gère "matériellement" que 2.
Un peu rapide comme affirmation :smiley-mr-green:
La UNO gère "directement" deux pins et TOUTES les autres de manière un peu moins directe mais tout à fait matériellement.

Il existe les interruptions PCINTxx qui sont des interruptions sur les PORTS, toutes les I/O sont concernées y compris les pins int0 et int1 qui peuvent donc être gérées de deux façons différentes !
Elles ne gèrent les interruptions que sur les niveaux , pas sur les fronts.
Dernier point c'est au programmeur de tester quel pin du port à changé d'état.

PCINT est un peu plus long à traiter qu'INT mais pour un organe lent comme un moteur ce n'est pas bloquant.

Je ne connais que la programmation des PCINT en jouant avec les registres du micro mais il paraît qu'il existe une bibliothèque toute faite.
Ce n'est pas dit qu'elle sera plus rapide, je dirais même que si elle veut gérer tous les cas possibles la bibliothèque sera plus lente que l'action directe sur les registres.

Cela vaux ce que ça vaux, j'ai mis mes notes au propre ici : https://forum.arduino.cc/index.php?topic=100906.0

3Sigma

... il paraît qu'il existe une bibliothèque toute faite.
Ce n'est pas dit qu'elle sera plus rapide, je dirais même que si elle veut gérer tous les cas possibles la bibliothèque sera plus lente que l'action directe sur les registres.
Tu penses sans doute à EnableInterrupt (https://github.com/GreyGnome/EnableInterrupt).

Elle est probablement plus lente que de le faire à la mano. Comme toujours, il faut choisir entre le confort et les performances...

Jambe

Un peu rapide comme affirmation :smiley-mr-green:

Oui, j'ai répondu rapidement, j'aurai du être plus précis.

Disons que je parlais des interruptions qui nécessite pas de traitement(détection de la broche parmi le port et son état) par l'utilisateur, hormis attachInterrup();

demokrato

Bonjour,

Je fais de l'asservissement de vitesse des 4 moteurs de l'un des mes robots avec une Mega. Si tu n'y arrives pas, c'est sans doute qu'il y a des problèmes dans ton code.

Schématiquement, ça se passe comme ça:
  • j'ai un timer qui exécute la tâche principale à 10 ms (avec la librairie flexitimer2)
  • en parallèle, les entrées codeurs sont branchées sur 4 interruptions
  • toutes les 10 ms, je compte le nombre d'interruptions sur chaque codeur, ce qui permet de récupérer la vitesse


D'accord, et du coup en utilisant la lib Encodeur.h ou avec de simples interruptions ?

Je devrais avoir près de 2000 interruption par encodeur et par seconde.
Il n'y a pas de risque de chevauchement de mes interruptions qui me ferait louper mon comptage ? (si je code correctement :) )

3Sigma

D'accord, et du coup en utilisant la lib Encodeur.h ou avec de simples interruptions ?
Avec de simples interruptions.

Je devrais avoir près de 2000 interruption par encodeur et par seconde.
Il n'y a pas de risque de chevauchement de mes interruptions qui me ferait louper mon comptage ? (si je code correctement :) )
Non, mais tu dois mettre dans tes fonctions sur interruptions l'ultra-minimum, à savoir l'incrémentation (ou la décrémentation) du compteur et le test qui va avec. Je te recommande de ne pas utiliser la fonction standard digitalRead, mais plutôt digitalReadFast2 (de la librairie digitalWriteFast). Peut-être que la lib Encoder.h le fait déjà, je ne sais pas (et pas le temps de regarder).

demokrato

Non, mais tu dois mettre dans tes fonctions sur interruptions l'ultra-minimum, à savoir l'incrémentation (ou la décrémentation) du compteur et le test qui va avec. Je te recommande de ne pas utiliser la fonction standard digitalRead, mais plutôt digitalReadFast2 (de la librairie digitalWriteFast).
D'acc d'acc, de toutes façons je ne pensais n'utiliser que le canal A car dans la phase durant laquelle j'ai besoin d'une précision de mesure, les moteurs seront obligatoirement dans un sens donné ça m'enlevera le "test" dans l'interuption.

Pour la lib, j'y regarderai.
 Merci !!

J'essaye de tenir ça à jour en fonction de mon succès.

Go Up