Club robotique de Sophia-Antipolis

Accueil > POBOTpedia > Programmation > Apprendre à coder > Les micro-contrôleurs > Les micro-contrôleurs sans ta mère > Bouge ton servo

Bouge ton servo

ou comment agir sur le monde

vendredi 2 décembre 2005, par Eric P.

Non, non, il n’y a aucune faute d’orthographe dans ce titre...

La manip d’aujourd’hui montre comment il est possible de piloter un ou plusieurs servo-moteurs depuis notre ATmega8, et ainsi être en mesure d’actionner des éléments méacaniques. Il s’agit d’un grand classique dans le monde de la robotique et des micro-contrôleurs.

Petit préliminaire

Pour ceux qui ignorent ce qu’est un servo-moteur (ou servo pour les intimes), tout d’abord je tiens à leur dire qu’il n’y a pas lieu d’en avoir honte. Ensuite, je vais aller assez vite, car beaucoup d’auteurs de par le vaste Web ont pris la peine d’écrire des pages très claires sur le sujet. Par exemple, nos amis de Fribotte.

Ce qu’il faut en retenir en deux mots :

  • un servo est un dispositif électro-mécanique dont on peut contrôler la position angulaire de manière (assez)précise (“assez” dépend du prix que vous mettez lors de l’achat de la chose)
  • ce contrôle se fait au moyen d’une impulsion pédiodique, dont la largeur, comprise entre 1ms et 2ms est proportionnelle à l’angle qu’on veut obtenir

Une petite précision qui aura son importance tout à l’heure : l’intervalle de temps entre les fronts montants de 2 impulsions consécutives ne doit pas dépasser 20ms en principe.

Et pour mettre un visage sur la chose, en voici un qu’on peut acheter pour un prix très modique :

Mon servo

(Il est ici relié mécaniquement à un antique rhéostat pour le contrôle de la vitesse d’un moteur électrique de bateau radio-commandé)

La sujet de la manip d’aujourd’hui

“Pouvoir contrôler jusqu’à 8 servos avec l’ATmega8, en envoyant à ce dernier les consignes de position respectives via HyperTerminal.”

Le schéma

Et bien non, pas de schéma. Pour la simple raison qu’on va tout simplement reprendre celui du chenillards à LEDs, en connectant nos servos en lieu et place des LEDs et de leur résistance. J’avoue avoir eu la flemme de refaire un nouveau schéma pour si peu, et puis vous pouvez bien bosser un peu de votre côté aussi 🙂

Connecter les servos... Et comment ? Ben avec leurs fils, banane !!!

Un peu de sérieux. Un servo se connecte au moyen de trois fils, rassemblés sur un connecteur femelle à 3 points. Ces 3 fils sont :

  • l’alimentation (entre 4,5V et 6V en général),
  • la masse,
  • le signal de commande (la fameuse impulsion de tout à l’heure).

Et c’est pareil quelle que soit la marque de l’engin. La seule chose qui change est la couleur du fil de commande, qui est tantôt blanc, tantôt jaune selon le fabriquant (non, non, cela n’a rien à voir avec le fait que le servo soit de marque allemande ou nipponne). Les deux autres seront toujours noir et rouge, selon la convention habituelle. Pas bien difficile de savoir qui est qui au bout du compte.

Le montage

Pour relier ce connecteur femelle à notre plaque d’expérimentation, il suffit de fabriquer un petit adaptateur comme celui-ci :

L’adaptateur de connexion

Le connecteur 3 broches mâles est tout simplement un morceau de barrette sécable. Les 3 pins à l’autre bout proviennent des mêmes types de barrettes (il suffit de tirer dessus avec une pince pour les sortir de l’isolant). Un peu de gaine thermo-rétractable autour du tout pour faire propre et éviter les court-circuits possibles. J’ai d’ailleurs équipé de cette manière tous les fils volants appelés à être connectés sur la plaquette d’expérimentation. Ainsi on a des broches bien rigides et donc faciles à enficher, et qui de plus offrent de très bons maintien et contact électrique avec les lyres de la plaquette.

On peut également voir ci-dessus le connecteur femelle monté sur le fil du servo, ici noir-rouge-blanc.

Remarque importante : vu qu’il n’y a aucune forme de détrompeur sur ce type de connecteurs, le repérage du sens de branchement se basera sur les couleurs de fils. Soyez donc attentif...

Un gros plan sur la connexion du servo au montage maintenant :

Connexion d’un servo au montage

Notez au passage que je n’ai même pas pris la peine d’enlever les LEDs. Ca m’a permis de vérifier qu’il y avait bien un signal sur les sorties, et ce sans brancher de servo. De plus, l’intensité d’allumage des LEDs est fonction de la largeur de l’impulsion, ce qui donne une vérification visuelle simple du fonctionnement.

Les résultats

Quelques images de l’oscillo pour illustrer les signaux obtenus, prélevés directement sur les sorties de l’ATmega :

On peut voir ici les signaux de 2 servos, réglés sur leur position mini. La base de temps ayant été calibrée de telle sorte qu’un carreau représente 1ms en abscisse, on peut constater que les impulsions durent exactement 1ms (au parallaxe près avec les graduations, car l’appareil photo n’était pas pile-poil dans l’axe).

Sur cette photo, le signal du bas correspond à la position maxi du servo, et l’impulsion y fait 2ms.

Quant à l’interface côté HyperTerminal, en voici une illustration :

Le numéro du servo concerné est donné par un chiffre entre 0 et 7. La position est donnée en 1/10e de débattement, la valeur étant saisie par un chiffre entre 0 et 9, et par la lettre A (pour obtenir les 11 positions correspondant aux 10 intervalles).

La programmation

Avant de recevoir 3 zillions de mails pour me dire, "ouais l’ôt bouffon, ta solution elle pue, moi j’fé kom sa" [1], je tiens à préciser qu’il n’y a pas qu’une seule solution bien entendu, et que celle-ci ne prétend être ni la meilleure, ni la plus belle, ni la plus [complétez par la caractéristique de votre choix]....

Elle a cependant les avantages suivants :

  • elle marche, ce qui n’est déjà pas si mal,
  • elle est simple à comprendre, ce qui pour un article à vocation pédagogique n’est pas une mauvaise chose
  • elle illustre l’utilisation des comparateurs, ce qui est nouveau par rapport aux articles précédents
  • et surtout, c’est la mienne (non mais)

Sur notre ATmega8, nous disposons de 3 compteurs/timers :

  • TMR0, sur 8 bits, et qui n’a plus de secret pour vous depuis que vous l’avez utilisé précédemment pour faire clignoter des LEDs
  • TMR2, sur 8 bits aussi, analogue à TMR0, et avec entre quelques autres possibilités (on verra cela un autre jour)
  • TMR1, sur 16 bits, et avec (entre autres aussi) deux comparateurs configurables

C’est ce dernier que nous allons regarder de plus près. La fonctionnalité qui nous intéresse ici est le fait qu’il dispose de deux comparateurs (A et B), capables de déclencher une interruption lorsque le compteur atteint la valeur à laquelle ils ont été configurés. De plus, avec la configuration appropriée du compteur, le comparateur A peut provoquer une remise à 0 automatique du comptage lorsque sa valeur est atteinte. Bien entendu une interruption peut également être déclenchée sur cet événement.

Comme toujours, RTFM. Traduisez par : “fortement, le datasheet à étudier vous êtes invités” (la version intégrale de 300 pages bien entendu, par le résumé de quelques feuilles. Soyons un peu sérieux).

Nous avons maintenant tout pour générer nos impulsions de commande. Le principe retenu est le suivant :

  • On va générer les impulsions des différents servos tour à tour (on va cheniller sur les servos en quelque sorte)
  • Chaque servo se verra assigner une fenêtre de 2ms, quelle que soit la durée de l’impulsion de commande. Ce n’est pas nécessaire à priori, car on aurait pu passer à l’impulsion du servo suivant dès que celle du précédent était terminée. Comme le disent nos amis de Fribotte : “Le retour à 0 de l’impulsion peut avoir n’importe quelle durée”. La conséquence est alors que la trame composée des 8 impulsions a une longueur variable, fonction de la durée individuelle de chacune des impulsions. La conséquence de cette conséquence est que la fréquence à laquelle chaque servo va recevoir ses impulsions est variable, et, au plus rapide, atteindre la valeur d’une impulsion toute les 10ms. Ca doit marcher aussi, et je laisse au lecteur le soin de programmer cette stratégie et de la tester.
  • On utilisera le comparateur A pour déterminer la durée (2ms) de la fenêtre, ramener le compteur à 0 et débuter l’impulsion
  • On utilisera le comparateur B pour déterminer la fin de l’impulsion en cours

Avant de faire tout cela, il faut également définir le prescale du compteur (comme pour les LEDs). Notre quartz étant à 8MHz, si on prescale l’horloge à 8, on va donc obtenir un pas de comptage toutes les micro-secondes, ce qui nous donne une résolution de 1/1000ème sur l’excursion de durée (rappel : entre 1ms et 2ms). Ce prescale est de plus éminemment pratique, puisqu’alors le réglage de nos comparateurs se fait en y chargeant les délais souhaités exprimés en micro-secondes (pas de division scabreuse pour traduire une durée en nombre de clocks).

Voilà, tout est dit. Il n’y a plus qu’à coder tout cela

Le code

Le source principal
La lib USART (source)
La lib USART (header)
Makefile

Comme pour les articles précédents, je ne vais pas faire de la redite ici, et je vous invite donc à lire le source et ses (abondants) commentaires. En cas de doute, n’hésitez pas à m’envoyer vos questions par mail (eric at pobot.org)

Ce que je trouve assez agréable dans l’utilisation qui est faite ici du compteur et de ses comparateurs est que tout tient dans les quelques lignes des deux interrupt handlers des comparateurs, et sans logique complexe. Le seul test qui y est fait est dû à la distribution des sorties sur deux ports, à cause de l’attribution des sorties PD0 et PD1 aux signaux Rx et Tx de l’USART. Si nous avions utilisé un autre moyen de communication comme l’I2C (pardon : le TWI), les 8 servos auraient pu rester groupés sur le seul port D.

Conclusion

Le timer/compteur 1 de l’ATmega offre également la possibilité de générer directement les impulsions sur les sorties associées aux deux comparateurs. Avec la configuration adéquate de son mode de fonctionnement, nous arions pu obtenir les impulsions directement sur ces sorties, sans en passer par les ports d’I/O. Mais dans ce cas, nous n’aurions pu contrôler que deux servos.

La solution proposée ici permet d’en piloter jusqu’à 10 en théorie. Dans la pratique, il vaut mieux se limiter à 9 pour être tranquille, car avec la durée cumulée de toutes les impulsions pour 10 servos, on serait trop à la limite des 20ms maximales entre deux impulsions d’un même servo.

A vous d’essayer maintenant d’autres approches, avec les autres timers/compteurs, etc, etc...

Ti bi di bi dip !!!

[1vous avez vu, moi aussi je sais causer d’jeuns

Vos commentaires

  • Le 8 avril 2009 à 21:08, par ? En réponse à : Bouge ton servo

    Bonjour,
    Pouvez vous me donner la prog en ASM ?
    Le C, ce n’est pas mon fort.
    Merci.

    • Le 8 avril 2009 à 22:16, par Julien H. En réponse à : Bouge ton servo

      Pour avoir l’équivalent en assembleur, il est possible de compiler le programme, puis d’ouvrir le fichier ".lst" qui va être créé (listing) : le code affiché est de l’ASM optimisé totalement équivalent au code C.

    • Le 8 avril 2009 à 23:17, par ? En réponse à : Bouge ton servo

      Tout juste.

      Et on a le choix entre le .lst et le .lss, ce dernier étant plus complet que le premier car il inclut les instructions C et permet donc de voir la correspondance C/ASM... ce qui peut réconcilier les partisans des deux mondes ;)

    • Le 9 avril 2009 à 17:21, par kapack En réponse à : Bouge ton servo

      Et pour bouger son servo branché directement sur le port // d’un pc standard en C++, est-ce que c’est possible en quelques lignes ?

    • Le 10 avril 2009 à 08:14, par Julien H. En réponse à : Bouge ton servo

      Je ne sais pas, il doit y avoir des sites spécialisés qui en parlent, mais ce n’est pas notre approche car ce n’est pas notre approche.

    Répondre à ce message

Un message, un commentaire ?

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.