Table des matières
Fonctionnement des servomoteurs AX-12
Quand on réalise un projet avec des moteurs, on souhaite contrôler leur position ou leur vitesse (par exemple pour fixer la vitesse de rotation d'une roue). Cela peut être fait en asservissant un moteur quelconque, mais la structure finale peut être assez lourde, surtout pour les débutants (avec les connexions pour le micro-contrôleur, la nécessité de laisser de l'espace pour la codeuse, …). Une méthode alternative consiste à prendre un pack “tout-en-un”, où tout cela est déjà intégré au moteur, qui devient un servo-moteur. On peut alors communiquer avec lui (via un micro-contrôleur) pour qu'il suive les commandes reçues. Les AX-12 sont un modèle de servo-moteurs qu'on utilise beaucoup dans les robots de la Coupe de France et dont on va expliquer le fonctionnement dans cet article en étudiant notamment sa datasheet, disponible ici.
Panoramique
Les AX-12A sont un modèle de servo-moteur chez Dynamixel d'entrée de gamme malgré leur prix d'environ 45€, à première vue élevé (en comparaison, certains modèles de la gamme MX et RX peuvent atteindre les 500€). Ils ont été conçus pour des mécanismes à basse vitesse et bas couple.
Grandeur | Valeurs |
---|---|
Tension (V) | entre 7 et 10 |
Courant (A) | max. 0,9 |
Couple (Nm) | max. 1,62 |
Vitesse (tours min-1) | max. 59 |
Amplitude angulaire (°) | entre 0 et 300 |
Résolution angulaire (°) | 0,35 |
Communication | UART 8-bits 1-stop sans parité |
Inputs | Angle, vitesse angulaire, couple |
Outputs | Angle, vitesse angulaire, couple, température, … |
Même si on peut fixer un angle de consigne seulement entre 0 et 300°, le moteur peut tourner à 360° si configuré en “Wheel Mode”. Cela verra défini dans une section ultérieure.
Communication
Les AX-12 communiquent par UART (Universal Asynchronous Receiver Transmitter) avec des données de 8 bits, 1 bit de STOP et sans parité à travers des ports à 3 pins. La vitesse de communication doit être comprise entre 7 343 bps (bits par seconde) et 1 Mbps (1 Mb par seconde).
Même s'il y en a deux, un seul est suffisant pour communiquer avec l'AX-12, ce qui permet d'utiliser l'autre port pour le connecter à un autre AX-12. On pourra commander le servomoteur qui nous intéresse en spécifiant l'ID du moteur (compris entre 0 et 253, 254 indiquant un message pour tous les servomoteurs). Si deux AX-12 ont le même ID, on ne pourra pas distinguer lequel est à la source de l'information, ni lequel il faut commander.
Le contrôleur à gauche de ce dessin peut être n'importe quel circuit qui peut communiquer en UART half duplex avec des niveaux de tension TTL, notamment la “Control Box” CM-5, à la base des robots d'entraînement Bioloid.
Le paquet à envoyer a la structure suivante:
0xFF 0xFF ID LENGTH INSTRUCTION PARAMETRES CHECKSUM
- ID est l'identifiant du servomoteur, de 0 à 253 (si vous devez vous adresser à plusieurs servomoteurs, il faut utiliser l'ID 254, et il n'y aura pas de STATUS renvoyés)
- LENGTH est la longueur du message. On peut la calculer ainsi: LENGTH = nombre paramètres + 2
- INSTRUCTION est l'instruction à effectuer (voir la section dédiée)
- PARAMETRES est l'ensemble des paramètres à passer à l'instruction (un octet par paramètre)
- CHECKSUM est un octet utilisé pour vérifier l'intégrité du message (pas d'erreurs pendant l'envoi, par exemple), calculé selon la formule suivante: CHECKSUM = NOT(ID + LENGTH + INSTRUCTION + Σ PARAMETRES) & 0x00FF
Le paquet envoyé par le servomoteur en réponse a la structure suivante:
0xFF 0xFF ID LENGTH ERROR PARAMETRES CHECKSUM
Elle est égale au paquet envoyé, sauf pour ERROR, un octet dont les bits montrent quelles erreurs ont eu lieu (l'une n'excluant pas les autres).
Instructions
Les instructions disponibles soselon le tableau suivant:
Octet | Instruction | Explication | Nombre de paramètres |
---|---|---|---|
0x01 | PING | Le moteur appelé va répondre par un paquet Status | 0 |
0x02 | READ_DATA | Le moteur appelé renvoie la valeur demandée | 2 |
0x03 | WRITE_DATA | Le moteur appelé écrit les valeurs envoyées dans les cases mémoires spécifiées | au moins 2 |
0x04 | REG_WRITE | Comme WRITE_DATA, mais les modifications auront lieu quand l'instruction ACTION sera envoyée | au moins 2 |
0x05 | ACTION | Applique les instructions stockées avec REG_WRITE | 0 |
0x06 | RESET | Le moteur appelé va être réinitialisé à ses valeurs de sortie d'usine (les valeurs par défaut) | 0 |
0x83 | SYNC_WRITE | La mémoire aux mêmes adresses des moteurs appelés va être modifiée en même temps | au moins 4 |
Structure des paquets envoyés pour chaque instruction:
- PING: 0xFF 0xFF ID 0x02 0x01 CHECKSUM
- READ_DATA: 0xFF 0xFF ID 0x04 0x02 Adresse de la case mémoire de départ Nombre de cases à lire CHECKSUM
- WRITE_DATA: 0xFF 0xFF ID N+3 0x03 Adresse de la case mémoire de départ Valeur à écrire 1 (à la case de départ) Valeur à écrire 2 (à la case suivante) … Valeur à écrire N (à la case N-1 après celle de départ) CHECKSUM
- REG_WRITE: 0xFF 0xFF ID N+3 0x04 Adresse de la case mémoire de départ Valeur à écrire 1 (à la case de départ) Valeur à écrire 2 (à la case suivante) … Valeur à écrire N (à la case N-1 après celle de départ) CHECKSUM
- ACTION: 0xFF 0xFF ID 0x02 0x05 CHECKSUM
- SYNC_WRITE: 0xFF 0xFF 0xFE (L+1)*N+4 0x83 Adresse de la case mémoire de départ Nombre de données à écrire (L) ID du 1er servomoteur Valeur à écrire 1 (à la case de départ) Valeur à écrire 2 (à la case suivante) … Valeur à écrire L (à la case L-1 après celle de départ) ID du 2ième servomoteur Valeur à écrire 1 (à la case de départ) Valeur à écrire 2 (à la case suivante) … Valeur à écrire L (à la case L-1 après celle de départ) … ID du dernier servomoteur (le N-ième) Valeur à écrire 1 (à la case de départ) Valeur à écrire 2 (à la case suivante) … Valeur à écrire L (à la case L-1 après celle de départ) CHECKSUM
Réponses aux paquets précédents:
- PING: 0xFF 0xFF ID 0x02 ERROR CHECKSUM
- READ_DATA: 0xFF 0xFF ID Nombre de cases à lire (N) + 2 ERROR Valeur de la case 1 Valeur de la case 2 … Valeur de la case N CHECKSUM
- WRITE_DATA: 0xFF 0xFF ID 0x02 ERROR CHECKSUM
- REG_WRITE: 0xFF 0xFF ID 0x02 ERROR CHECKSUM
- ACTION: 0xFF 0xFF ID 0x02 ERROR CHECKSUM
- RESET: 0xFF 0xFF ID avant le RESET 0x02 ERROR CHECKSUM
- SYNC_WRITE: pas de message renvoyé
Mémoire
La mémoire du servomoteur est structurée ainsi:
Instruction | Accessible en … | Octet | Valeur par défaut | Valeur minimale | Valeur maximale | |
---|---|---|---|---|---|---|
Lecture | Ecriture | |||||
Area EEPROM | ||||||
Nombre de modèle (octet “bas”) | X | 0x00 | 12 | - | - | |
Nombre de modèle (octet “haut”) | X | 0x01 | 0 | - | - | |
Version du firmware | X | 0x02 | variable | - | - | |
ID | X | X | 0x03 | 1 | 0 | 253 |
Baud Rate | X | X | 0x04 | 1 | 0 | 254 |
Temps de retour | X | X | 0x05 | 250 | 0 | 254 |
Angle limite (octet “bas”) (sens horaire) | X | X | 0x06 | 0 | 255 | |
Angle limite (octet “haut”) (sens horaire) | X | X | 0x07 | 0 | 0 | 3 |
Angle limite (octet “bas”) (sens antihoraire) | X | X | 0x08 | 255 | 0 | 255 |
Angle limite (octet “haut”) (sens antihoraire) | X | X | 0x09 | 3 | 0 | 3 |
[espace réservé] | 0x0A | 0 | - | - | ||
Température maximale | X | X | 0x0B | 85 | 0 | 190 |
Tension minimale | X | X | 0x0C | 60 | 50 | 250 |
Tension maximale | X | X | 0x0D | 190 | 50 | 250 |
Couple maximal (octet “bas”) | X | X | 0x0E | 255 | 0 | 255 |
Couple maximal (octet “haut”) | X | X | 0x0F | 3 | 0 | 3 |
Niveau de retour des status | X | X | 0x10 | 2 | 0 | 2 |
LED d'alarme | X | X | 0x11 | 4 | 0 | 127 |
Extinction de l'alarme | X | X | 0x12 | 4 | 0 | 127 |
[espace réservé] | X | X | 0x13 | 0 | 0 | 1 |
Calibration basse (octet “bas”) | X | 0x14 | variable | - | - | |
Calibration basse (octet “haut”) | X | 0x15 | variable | - | - | |
Calibration haute (octet “bas”) | X | 0x16 | variable | - | - | |
Calibration haute (octet “haut”) | X | 0x17 | variable | - | - | |
Activation du couple | X | X | 0x18 | 0 | 0 | 1 |
LED | X | X | 0x19 | 0 | 0 | 1 |
Marge d'erreur pour rotation horaire | X | X | 0x1A | 0 | 0 | 254 |
Marge d'erreur pour rotation antihoraire | X | X | 0x1B | 0 | 0 | 254 |
Marge de pente pour rotation horaire | X | X | 0x1C | 32 | 1 | 254 |
Marge de pente pour rotation antihoraire | X | X | 0x1D | 32 | 1 | 254 |
Position objectif (octet “bas”) | X | X | 0x1E | valeur à l'adresse 0x24 [position actuelle (octet “bas”)] | 0 | 255 |
Position objectif (octet “haut”) | X | X | 0x1F | valeur à l'adresse 0x25 [position actuelle (octet “haut”)] | 0 | 3 |
Vitesse objectif (octet “bas”) | X | X | 0x20 | 0 | 0 | 255 |
Vitesse objectif (octet “haut”) | X | X | 0x21 | 0 | 0 | 3 |
Couple limite (octet “bas”) | X | X | 0x22 | valeur à l'adresse 0x0E [ Couple maximal (octet “bas”)] | 0 | 255 |
Couple limite (octet “haut”) | X | X | 0x23 | valeur à l'adresse 0x0F [ Couple maximal (octet “haut”)] | 0 | 3 |
Area RAM | ||||||
Position actuelle (octet “bas”) | X | 0x24 | variable | - | - | |
Position actuelle (octet “haut”) | X | 0x25 | variable | - | - | |
Vitesse actuelle (octet “bas”) | X | 0x26 | variable | - | - | |
Vitesse actuelle (octet “haut”) | X | 0x27 | variable | - | - | |
Couple actuel (octet “bas”) | X | 0x28 | variable | - | - | |
Couple actuel (octet “haut”) | X | 0x29 | variable | - | - | |
Tension actuelle | X | 0x2A | variable | - | - | |
Température actuelle | X | 0x2B | variable | - | - | |
Instruction enregistrée | X | X | 0x2C | 0 | 0 | 1 |
[espace réservé] | 0x2D | 0 | - | - | ||
Mouvement | X | 0x2E | 0 | 0 | 1 | |
Verrouillage | X | X | 0x2F | 0 | 1 | 1 |
Courant minimal (octet “bas”) | X | X | 0x30 | 32 | 0 | 255 |
Courant minimal (octet “haut”) | X | X | 0x31 | 0 | 0 | 3 |
Les données dans la partie EEPROM (mémoire non-volatile) ne seront pas réinitialisées quand le moteur est allumé, contrairement à la RAM (mémoire volatile). Par exemple, si l'ID est 25 et la vitesse objectif est de 150, une fois le moteur éteint et rallumé l'ID vaudra toujours 25, mais la vitesse objectif vaudra 0.
Bit | Nom erreur | Explication |
---|---|---|
1xxx_xxxx | [non utilisé?] | - |
x1xx_xxxx | Erreur de l'instruction | Instruction non définie ou instruction d'action envoyée sans l'instruction Reg_Write (voir plus loin) |
xx1x_xxxx | Erreur de charge excessive | Le moteur ne peut pas bouger la charge en appliquant le couple maximal autorisé |
xxx1_xxxx | Erreur de checksum | Le checksum est incorrect |
xxxx_1xxx | Erreur d'intervalle | Les paramètres de l'instruction ne sont pas dans l'intervalle autorisé (par exemple quand on veut fixer un couple trop élevé) |
xxxx_x1xx | Erreur de surchauffe | La température du servomoteur est supérieure à la limite autorisée |
xxxx_xx1x | Erreur d'angle limite | L'angle objectif n'est pas dans l'intervalle fixé par les angles limites pour les sens horaire et antihoraire |
xxxx_xxx1 | Erreur de tension | La tension d'entrée n'est pas dans l'intervalle autorisé |
Cases mémoire
Voici l'explication détaillée des cases mémoire du AX-12 (pour plus de détails, voir la datasheet).
0x00 et 0x01: numéro du modèle du servomoteur (0x000C ou 12 pour l'AX-12)
0x02: version du firmware (lecture seule)
0x03: ID du servomoteur. Il doit être différent pour chaque servomoteur dans le même réseau.
0x04: coefficient pour déterminer le Baud Rate: Baud Rate = 2 000 000 / (1 + valeur de la case). La tolérance du UART (et donc l'erreur maximale tolérée) est d'environ 3%.
0x05: coefficient pour déterminer le délai entre le paquet d'instruction et celui de status selon la formule: t = (2 * valeur de la case ) µs
0x06 à 0x09: limites angulaires. Il faut: angle limite horaire ≤ angle objectif ≤ angle limite antihoraire, sinon l'erreur d'angle limite sera déclenchée.
0x0B: température maximale autorisée (en °C). La dépasser déclenchera l'erreur de surchauffe.
0x0C et 0x0D: limites de tension autorisées, avec tension minimale ≤ tension actuelle ≤ tension maximale, sinon l'erreur de tension sera déclenchée. La valeur de ces cases est la tension souhaitée multipliée par 10 (la tension minimale par défaut est donc 8,0 V).
0x0E et 0x0F: couple maximal autorisé (copié au démarrage du moteur dans les cases 0x22 et 0x23). Si leur valeur est 0, le servomoteur passe en mode “rotation infinie” (Endless Turn), et donc on peut faire un asservissement en vitesse. La vitesse objectif est alors définie par les cases 0x1E et 0x1F (0000 0xpp pppp pppp, avec p la vitesse en valeur absolue et x le sens de rotation, 0 en sens antihoraire et 1 en sens horaire)
0x10: niveau de retour STATUS. Il peut prendre ces valeurs:
- 0: le servomoteur ne renvoie pas de STATUS
- 1: le servomoteur renvoie un STATUS seulement pour une instruction READ_DATA
- 2: le servomoteur renvoie toujours un STATUS
Si le message est envoyé à tous les servomoteurs (ID 254) il n'y aura pas de STATUS
0x11: cet octet indique quand la LED clignote suite à une erreur. Si le bit de l'erreur est à 1, la LED clignote si cette erreur survient, et elle s'arrête deux secondes après que l'erreur a été résolue.
0x12: cet octet se comporte comme le précédent, mais le moteur est désactivé (couple ramené à 0) si l'erreur survient. Pour redémarrer le servomoteur, il faut écrire 1 à l'adresse 0x18.
0x14 à 0x17: constantes de calibration pour le servomoteur (lecture seule)
0x18: si cette case est à 0, le moteur est en mode roue libre (couple nul), si à 1 il peut appliquer un couple à la charge.
0x19: la LED est allumée si cette case est à 1 et éteinte si elle est à 0.
0x1A à 0x1D: variables pour déterminer le comportement du moteur pour atteindre la position objectif: 0x1A et 0x1B indiquent l'intervalle dans lequel doit être la position pour être considérée égale à l'objectif, 0x1C et 0x1D indiquent l'intervalle dans lequel la vitesse de rotation diminue quand la position se rapproche de l'objectif.
0x1E et 0x1F: position objectif, dans le sens antihoraire et à moitie à la verticale (0x0000: 5h, 0x01ff: 12h, 0x03ff: 7h).
0x20 et 0x21: vitesse maximale pour atteindre la position objectif (s'il y a assez de puissance en entrée). 0x03ff correspond à 114 tours par minute, et 0x0001 est la vitesse minimale. 0x0000 désactive le contrôle de vitesse, qui sera la maximale pour la tension en entrée donnée.
0x22 et 0x23: couple maximal. Cette valeur fixe la limite actuelle, alors que les cases 0x0E et 0x0F servent à initialiser cette valeur au démarrage du moteur.
0x24 et 0x25: position actuelle du moteur. La même convention que pour la position objectif s'applique.
0x26 et 0x27: vitesse actuelle du servomoteur.
0x28 et 0x29: charge appliquée au servomoteur: 0000 0xpp pppp pppp avec p la charge en valeur absolue et x le sens de la charge (0: antihoraire, 1: horaire).
0x2A: tension appliquée au moteur (V+ = valeur de la case * 0.1)
0x2B: température du servomoteur (en °C)
0x2C: cette case passe à 1 si une instruction REG_WRITE a été exécutée et elle passe à 0 quand ACTION a été exécutée
0x2E: cette case passe à 1 si le servomoteur est en train de tourner (et pas de se faire tourner) et à 0 sinon.
0x2F: si cette case passe à 1, les seules cases pouvant être modifiées sont celles allant de 0x18 à 0x23 (mode de rotation, LED, marges, position objectif, vitesse maximale et couple maximal), la lecture restant autorisée. Une fois bloqué, le servomoteur ne peut être débloqué qu'en le débranchant et en le rebranchant.
0x30 et 0x31: valeur de courant minimal quand le moteur tourne.
Nouveau article écrit par FAGAN Patrick
Article originel écrit par BERNARDI GRA Thibaut
9 février 2010