Pour les besoins d'un petit projet qui me trotte dans la tête depuis un moment, j'ai décidé de voir comment fonctionnent les servomoteurs avec Arduino. Je me suis donc procuré deux petits servomoteurs d'aéromodélisme afin de commencer à bricoler avec.
Un servomoteur :
Ces deux servomoteurs sont des SG90, nécessitant une tension d'alimentation de 5 V et un signal d'entrée PWM pour fonctionner. Trois broches y sont connectées : alimentation (fil orange), terre (fil marron), et signal (fil jaune). Ils peuvent faire pivoter leur axe de +/- 90° par rapport à leur position initiale.
Les positions du servomoteur :
De plus, je me suis également procuré un joystick analogique deux axes afin de pouvoir contrôler les servomoteurs.
Ce joystick fonctionne également avec une tension d'alimentation de 5 V, et transmet des valeurs analogiques variant entre 0 et 1 023 inclus. Il est également équipé d'un bouton-poussoir, actionné lorsque l'on appuie sur le stick. Cinq broches y sont connectées : alimentation, axe X, axe Y, bouton-poussoir, terre.
L'idée de ce petit montage est simple : bouger le joystick en axe X fait réagir le servomoteur 1, bouger le joystick en axe Y fait réagir le servomoteur 2, et ces deux actions sont bien sûr combinables.
Il ne reste plus qu'à s'occuper du plus intéressant : le code du programme ! Afin de me faciliter le travail et de ne pas réinventer la roue, j'ai utilisé la bibliothèque logicielle Servo.h, fournie par défaut avec l'environnement de développement Arduino, qui permet d'utiliser l'objet Servo, représentant un servomoteur. Une fois cet objet créé, deux méthodes seront utilisées : S.attach(P), qui permet d'utiliser le servomoteur S sur la broche P, et S.write(N), qui permet d'indiquer la valeur N de l'angle que doit prendre le servomoteur S.
Malheureusement, un problème s'est rapidement présenté : comment faire correspondre les valeurs analogiques reçues par le joystick en valeurs PWM utilisables par les servomoteurs ? Ou plus simplement : comment faire correspondre la plage de valeurs [0 ; 1 023] à la plage de valeurs [0 ; 180] ?
Il a donc fallu fixer quelques constantes : la position initiale d'un axe du joystick (environ 512) correspondra à la position initiale du servomoteur (90°) ; la position 0 d'un axe du joystick correspondra à un angle de 180° ; la position 1 023 d'un axe du joystick correspondra à un angle de 0°. Chaque valeur d'angle sera obtenue à partir d'une valeur du joystick grâce à une fonction affine de la forme y = a x + b ; on obtient alors le système d'équations suivant, à résoudre :
{ 180 = 0 x + b
{ 0 = 1 023 a + b
⇔
{ b = 180
{ 1 023 a + 180 = 0
⇔
{ b = 180
{ a = -180 / 1 023
⇔
{ a ≈ -0,175953
{ b = 180
On obtient alors la fonction à utiliser pour transformer les valeurs du joystick en valeurs pour les servomoteurs : f(x) = -0,175953 x + 180, ce qui permet de finaliser le code.
- Code Arduino :
#include <Servo.h> // Utilisation de la bibliothèque Servo.h.
#define pinJx A0 // Broche pour l'axe X du joystick.
#define pinJy A1 // Broche pour l'axe Y du joystick.
#define pinSx 9 // Broche pour le signal du servomoteur X.
#define pinSy 10 // Broche pour le signal du servomoteur Y.
unsigned short X, Y; // Variables pour les valeurs du joystick.
Servo Sx, Sy; // Déclaration de deux objets Servo.
void setup()
{
pinMode(pinSx, OUTPUT); // Broches fixées en sortie.
pinMode(pinSy, OUTPUT);
Sx.attach(pinSx); // Correspondance broche/servomoteur.
Sy.attach(pinSy);
Sx.write(90); // Mouvement du servomoteur en position initiale.
Sy.write(90);
}
void loop()
{
X = analogRead(pinJx); // Lecture des valeurs du joystick.
Y = analogRead(pinJy);
Sx.write(joyToServo(X)); // Envoi des signaux de rotation.
Sy.write(joyToServo(Y));
}
byte joyToServo(unsigned short n) // Fonction de correspondance.
{
return (byte)(-0.175953 * n + 180); // f(x) calculée précédemment.
}
Une fois encore, ce code ne contient aucune difficulté particulière. J'ai pris soin d'utiliser des types de variables correspondant le plus possible aux valeurs qu'elles sont supposées prendre : les valeurs du joystick variant entre 0 et 1 023 inclus, j'ai utilisé pour les stocker un unsigned short, dont les valeurs utilisables varient entre 0 et 65 535 (entre - 32 768 et 32 767 pour un short signé). Même chose pour les valeurs d'angle : celles-ci variant entre 0 et 180, j'ai utilisé un byte, dont les valeurs utilisables varient entre 0 et 255 (le byte est d'office non-signé).