Driver de Servos sur PRUs BBB

De Wiki LOGre
Aller à : navigation, rechercher
[Category:Software]]
Langue : Français  • English

Projet réalisé par fma38.

Abouti

Présentation

L'idée est d'implémenter la gestion de servos avec les PRUs de la BBB, comme le fait la carte Veyron Servo Driver de DFRobot, ou la SSC-32 de LynxMotion.

Cahier des charges

  • 32 servos
  • pulses :
    • plage d'utilisation : 5 à 5000µs
    • résolution : 1µs
  • variation de n servos (paramétrables) sur un temps donné (20ms à 20s)
  • communication avec hôte via mémoire partagée
  • gestion de fins de course : 8 entrées, chaque entrée stoppant un groupe de 4 servos

Gestion d'un servo

Un servo se pilote avec un simple pulse, allant habituellement de 500µs à 2500µs, mais les drivers ont habituellement une plage beaucoup plus large, genre 50-5000µs. Ce pulse correspond donc à une position absolue, position que le servo va se débrouiller pour atteindre et maintenir.

Ce pulse doit se répéter au minium toutes les 20ms (50Hz).

Implémentation

Ce qu'il faut, c'est pouvoir synchroniser les 32 servos (par groupes, librement configurables) pour qu'ils se déplacent en même temps. Pour ça, on donne leur position (largeur de pulse) finale, le temps pour s'y rendre, et ils partent et arrivent tous en même temps, quelle que soit leur position de départ.

Il y a donc 3 tâches :

  • gérer les pulses proprement dit (en soft, donc)
  • gérer la variation (vitesse) de ces pulses en fonction du temps, de manière synchrone
  • gérer les entrées, et stopper les servos correspondants

Un seul PRU est utilisé pour l'ensemble.

Le dernier point est la communication avec le CPU (cible = programme python tournant sous linux). Il est possible d'écrire des vrais drivers pour le noyau, qui vont pouvoir dialoguer avec les PRUs. Mais on peut aussi se contenter d'utiliser un mapping mémoire, directement depuis python, et faire une simple boîte aux lettres pour les échanges ; c'est cette dernière solution qui est retenue pour le driver de servos.

Premiers tests

Pru servos.png

Code

Cf framagit

Le PRU0 a 3 taches :

  • générer des largeurs de pulses fixes
  • changer la largeur des pulses de certains servos de manière synchrone, de façon à ce qu'ils démarrent et s'arrêtent en même temps
  • lire les entrées TOR, et stopper le groupe de servos correspondant lorsqu'elles sont activées

La communication avec l'hôte se fait par la mémoire partagée. Pour 32 servos :

  • [0x00000000:0x0000007f]: largeurs de pulses courantes
  • [0x00000080:0x000000ff]: incréments
  • [0x00000100:0x00000103]: nombre de pas
  • [0x00000104:0x00000123]: entrées TOR

Les valeurs sont stockées par mots (4 octets), en little endian.

Les largeurs de pulses doivent être décalées de 16 bits vers la gauche. Ceci car les calculs internes utilisent des valeurs de 32 bits pour une meilleure précision, mais uniquement les 16 bits de poids fort pour les résultats. Les incréments n'ont pas besoin d'être décalés.

Changer les valeurs courantes de largeurs de pulses modifie immédiatement la position des servos (pas de gestion de vitesse).

Utiliser une largeur de pulse de 0 pour désactiver le servo correspondant.

Pour bouger les servos avec gestion de vitesse, il faut calculer et positionner les valeurs d'incrément pour les servos qui doivent se déplacer de manière synchrone, puis donner le nombre de pas (cf ci-dessous pour le détail). Les servos commencent à se déplacer dès que le nombre de pas est non nul. Il est alors décrémenté par le PRU pendant le déplacement ; il suffit d'attendre qu'il revienne à 0 pour savoir quand le déplacement se termine. Une autre solution est d'attendre l'événement du PRU.

nbSteps = delay / 20
inc = (((targetPulse) << 16) - currentPulse) / nbSteps + 1

Attention à ne pas modifier les valeurs courantes des largeurs de pulses pendant un déplacement synchrone !

Les entrées TOR peuvent servir de fin de course pendant un déplacement (synchrone uniquement) ; chaque entrée correspondant à un groupe de 4 servos (0-3, 4-7, 8-11, 12-15, 16-19, 20-23, 24-27, 28-31), ceci afin de pouvoir gérer des pattes à 4 degré de libertés. Lorsqu'une entrée est activée, l'incrément du groupe de servos correspondant est mis à zéro.

Les valeurs en mémoire des entrées TOR peuvent être lues à n'importe quel moment, mais leur état n'est rafraîchi que pendant un déplacement synchrone.

Pour plus d'info, cf servosPRU.py.

Cape

Version 1.0

Cette nouvelle version apporte les corrections/modifications suivantes :

  • nouveau routage des GPIO pour ne pas utiliser celles de la séquence de boot en pullup
  • ajout de résistances en série avec le GPIO pour protection
  • ajout d'un régulateur de tension pour alimenter la carte depuis la batterie des servos
  • ajout d'un AO en suiveur pour booster la référence pour les ADC
  • routage de 8 entrées GPIO lisibles directement depuis les PRUS ; utilisées pour stopper les servos (détection du sol pour un robot, par exemple)
  • trous pour accéder aux vis de fixation de la BBB sans devoir retirer la cape

Servos 1.0.sch.png Servos 1.0.brd.png

Après les premiers tests, il s'avère que les résistances de protection des GPIO atténuent trop le signal : celui-ci n'étant que de 3,3V, il est tout juste suffisant pour les servos, qui attendent du 5V. Avec les résistances, cela ne fonctionne plus.

Version 0.9

Une cape (v0.9) a été réalisée via le service Fusion PCB de SeeedStudio. Il s'agit d'une simple breakout pour pouvoir connecter les servos, et accéder aux divers bus (I²C, série...).

Cette version a permis de mettre en avant quelques soucis (outre le mauvais routage !) : certains servos utilisent des GPIO qui sont aussi routées en interne pour configurer la séquence de boot, via des pullup et pulldown. Lorsqu'un servo est connecté, il fait office de pulldown, et trompe les GPIO qui devraient être lues à 1 ! Du coup, la carte ne boot pas :o(

Servos.sch.png Servos.brd.png

LogBook

  • juin 2016 : tests grandeur nature sur l'Hexapode v2
  • septembre 2015 : réalisation du PCB de la cape 1.0
  • juillet 2015 : réalisation du PCB de la cape v0.9 et premiers tests

Liens