L’Arduino c’est à la fois une carte équipée d’un microcontrôleur et un environnement logiciel qui fournit à l’utilisateur des fonctions pour manipuler le matériel de manière plus simple que s’il devait mettre en œuvre le micro-contrôleur à partir de rien.
L’Arduino se programme en langage C et quelques fois en C++. Le C est un langage de programmation très populaire, notamment sur les systèmes embarqués, c’est à dire les systèmes informatiques intégrés dans un procédé dans le but de le piloter.
Un programme minimum pour Arduino
Le programme minimum pour l’Arduino est constitué de deux fonctions. Une fonction regroupe une série d’instructions et remplit un rôle. Voici ces deux fonctions, setup()
et loop()
. La fonction setup()
est exécutée 1 seule fois au début de programme. La fonction loop()
est exécutée répétitivement.
- /*
- * La fonction setup() est exécutée 1 fois
- * au démarrage du programme
- */
- void setup()
- {
- }
- /*
- * La fonction loop() est exécutée
- * répétitivement
- */
- void loop()
- {
- }
en langage C, une fonction retourne une valeur dont le type est indiqué juste à gauche du nom de la fonction. Il existe plusieurs types de données en C, les nombres entiers positifs et négatif (int
), ceux qui sont seulement positif (unsigned int
) etc. Nous verrons les types au fur et à mesure des besoins. Ici le type est void
, il s’agit d’un type spécial qui signifie « rien » ou « vide » et qui indique que les fonctions setup()
et loop()
ne retournent aucune valeur.
Une fonction peut prendre des arguments. Les arguments sont donnés entre les parenthèses juste après le nom de la fonction. Ici les deux fonctions n’ont aucun argument.
Les instructions qui constituent la fonction sont données entre les accolades. Ici les deux fonctions sont vides et par conséquent elle ne font strictement rien.
Au dessus des fonctions il y a du texte. Il s’agit de commentaires. Un commentaire commence par /*
et termine par */
. C’est une bonne habitude de commenter abondamment ses programmes. En effet, quelques semaines plus tard, il est difficile de se rappeler de ce que l’on a voulu faire dans un programme et les commentaires explicatifs sont bienvenus.
Mise en œuvre d’un servo-moteur
La mise en œuvre d’un servo-moteur avec l’Arduino est aisée. Il y a une bibliothèque pour ça !
Une bibliothèque est un jeu de fonctions optionnelles que l’on peut ou non employer dans le programme. Pour utiliser la bibliothèque permettant de piloter des servo-moteurs, il suffit d’inclure, au début du programme la directive suivante
- #include <Servo.h>
Il faut ensuite pouvoir manipuler le servo-moteur. Il faut pour cela créer une variable de type Servo
. On dit aussi instancier une variable. Le type Servo
est un peu spécial, on entre là sur le terrain du C++. Servo
est une classe et créer une variable de ce type donne un objet. En plus de contenir une valeur comme une variable de type nombre entier, un objet possède des fonctions qui agissent sur lui. Dans le monde de l’objet on appelle communément ces fonctions des méthodes. Nous n’avons pas besoin d’en connaître plus pour utiliser un objet de type Servo
. Voici comment on crée une variable, que nous appelons monServo
de type Servo
.
- Servo monServo;
Notez le « ; » qui termine la ligne, il est nécessaire et termine la directive. Notez aussi que le respect des majuscules et des minuscules est important car le langage C fait la différence entre s
et S
par exemple. Par conséquent appeler la variable monServo
n’est pas la même chose que de l’appeler monservo
.
La variable monServo
est instanciée, il faut maintenant l’accrocher à une des sorties numériques de l’Arduino. Nous allons choisir la sortie 2 car les sorties 0 et 1 ont un rôle particulier : elles permettent d’envoyer des messages qui seront affichés sur votre ordinateur hôte. Il s’agit d’une aide irremplaçable qui se révèle nécessaire pour comprendre ce qui se passe quand le programme ne fait pas ce que l’on attend.
Accrocher la variable à une sortie se fait avec la méthode attach
et, évidemment, dans la fonction setup()
car il est inutile de le faire plus d’une fois.
- void setup()
- {
- monServo.attach(2); /* accroche monServo à la pin 2 de l'Arduino */
- }
Aller-retours
La première application est très simple, il s’agit de faire faire au servo des aller-retours de part et d’autre de la position médiane. La méthode write(...)
permet de donner l’angle auquel le servo doit se positionner. L’argument est une valeur comprise entre 0 et 180°. L’angle minimum choisi est donc de 70° et l’angle maximum de 110°. On fixe la pause entre 2 changements de position à 1s. La fonction loop()
est donc la suivante.
- void loop()
- {
- /* positionne le servo à 70° */
- monServo.write(70);
- /* attend 1000 ms */
- delay(1000);
- /* positionne le servo à 110° */
- monServo.write(110);
- /* attend 1000 ms */
- delay(1000);
- }
Cette première application ne remplit pas le cahier des charges. À savoir un mouvement lent. Le mouvement a bien lieu toutes les secondes mais il est très rapide, quasi instantané.
Aller-retours lents
Pour obtenir un mouvement lent, il faut faire varier l’angle du servo progressivement. Pour cela, il faut changer l’angle très très peu et le faire plus souvent. Fixons par exemple un changement d’angle de 1°. Si l’on veut que le mouvement, passer de 70° à 110° soit accompli en 1s, il faut augmenter l’angle de 1° toutes les 1000ms / (110 - 70). soit une pause de 25ms. Quand l’angle atteint 110°, il faut inverser le mouvement. Quand l’angle atteint 70°, il faut de nouveau inverser le mouvement. Nous avons donc besoin de deux variables, angle
qui contient l’angle courant du servo et vitesse
qui contient 1 si on augmente l’angle et -1 si on le diminue. Pour faciliter la programmation, on va placer 70 et 110 dans deux constantes. Le programme est le suivant.
Programme 2
- #include <Servo.h>
- Servo monServo;
- int vitesse;
- int angle;
- const int angleMin = 70;
- const int angleMax = 110;
- /*
- * La fonction setup() est exécutée 1 fois
- * au démarrage du programme
- */
- void setup()
- {
- monServo.attach(2);
- angle = angleMin;
- vitesse = 1;
- }
- /*
- * La fonction loop() est exécutée
- * répétitivement
- */
- void loop()
- {
- monServo.write(angle);
- /* calcule le nouvel angle */
- angle = angle + vitesse;
- if (angle > angleMax) {
- /*
- * le nouvel angle dépasse le maximum
- * on le recale au maximum et on inverse la vitesse
- */
- angle = angleMax;
- vitesse = -1;
- }
- else if (angle < angleMin) {
- /*
- * le nouvel angle dépasse le minimum
- * on le recale au minimum et on inverse la vitesse
- */
- angle = angleMin;
- vitesse = 1;
- }
- delay(25);
- }
Le mouvement est bien lent comme on le désire mais avec une variation de l’angle par degré, le mouvement est un peu saccadé. Une autre méthode permet un positionnement plus précis. Il s’agit de la méthode writeMicroseconds(...)
. L’argument de cette méthode n’est plus un angle mais la durée de l’impulsion de commande du servo-moteur en micro-secondes. En effet, le signal de commande du servo-moteur est une impulsion dont la largeur détermine la position du servo (plus d’informations sont données dans l’article « La carte de commande 6 servo-moteurs, le matériel », une autre mise en œuvre utilisant une conception matérielle personnelle). Cette impulsion a donc la forme suivante.
- La PWM de commande d’un servo
- Seuls les durées extrêmes de l’impulsion et la durée médiane sont montrées mais toutes les valeurs entre 0,5 ms et 2,5 ms sont possibles.
La valeur médiane est donc de 1500µs et les valeurs minimum et maximum pour les angles que nous avions fixés deviennent respectivement et approximativement 1250 et 1750. On va conserver une vitesse de 1 ou -1 et pour avoir un mouvement d’1s alors que l’on franchi 500 pas d’angle on va désormais faire une pause de 2ms. Le programme est donc le suivant.
Programme 3
- #include <Servo.h>
- Servo monServo;
- int vitesse;
- int angle;
- const int angleMin = 1250;
- const int angleMax = 1750;
- /*
- * La fonction setup() est exécutée 1 fois
- * au démarrage du programme
- */
- void setup()
- {
- monServo.attach(2);
- angle = angleMin;
- vitesse = 1;
- }
- /*
- * La fonction loop() est exécutée
- * répétitivement
- */
- void loop()
- {
- monServo.writeMicroseconds(angle);
- /* calcule le nouvel angle */
- angle = angle + vitesse;
- if (angle > angleMax) {
- /*
- * le nouvel angle dépasse le maximum
- * on le recale au maximum et on inverse la vitesse
- */
- angle = angleMax;
- vitesse = -1;
- }
- else if (angle < angleMin) {
- /*
- * le nouvel angle dépasse le minimum
- * on le recale au minimum et on inverse la vitesse
- */
- angle = angleMin;
- vitesse = 1;
- }
- delay(2);
- }
Le résultat est meilleur avec un mouvement plus fluide.
Voici qui conclut cette prise en main des servo-moteurs. Le prochain article portera sur l’ajout d’un bouton permettant de commander le mouvement du servo-moteur.