Arduino : une plateforme de prototypage à base de microcontrôleur

Toutes les commandes doivent être exécutées en tant que superutilisateur. Le code indiqué entre chevrons < > est à remplacer par la valeur correspondante. Le code suivant une double barre oblique / / est un commentaire.

« Arduino est la marque d'une plateforme de prototypage open-source qui permet aux utilisateurs de créer des objets électroniques interactifs à partir de cartes électroniques matériellement libres sur lesquelles se trouve un microcontrôleur (…). Le microcontrôleur peut être programmé pour analyser et produire des signaux électriques, de manière à effectuer des tâches très diverses comme la domotique (…), le pilotage d'un robot, de l'informatique embarquée, etc. » (Wikipédia)

Caractéristiques

Arduino Uno R3 Arduino Nano
Microcontrôleur ATmega328P ATmega328
Tension de fonctionnement 5V 5V
Tension d'entrée (recommandée) 7-12V 7-12V
Tension d'entrée (min/max) 6-20V 6-20V
Consommation électrique ~30mAh ~19mAh
Entrées/Sorties numériques (I/O) 14 14
Dont alimentée (PWM out) 6 6
Intensité par entrée/sortie 20mA 40mA
Intensité de la sortie 3.3V 50mA 50mA
Entrées analogiques (10 bits) 6* 8
Mémoire morte EEEPROM 1KB 1KB
Mémoire vive SRAM 2KB 2KB
Mémoire flash (bootloader) 32KB (0.5KB) 32KB (2KB)
Vitesse d'horloge 16Mhz 16Mhz
Dimensions 68.6x53.4mm 18x45mm
Connecteur USB USB-B µUSB

*Les entrées analogiques peuvent être utilisées comme entrées numériques à condition d'être déclarées comme telles, par exemple :

pinMode(A0,INPUT);

Installation de l'environnement de programmation Arduino IDE

« Le logiciel de programmation des modules Arduino, dont l'interface, appelée Arduino IDE, est une application Java, [est] libre et multi-plateforme (…). Il est également possible de se passer de l'interface Arduino, et de compiler et téléverser les programmes via l'interface en ligne de commande. Le langage de programmation utilisé est le C++, (…) lié à la bibliothèque de développement Arduino, permettant d'utiliser la carte et ses entrées/sorties. » (Wikipedia)

Sources : site officiel, linuxhint.com, ubuntu-fr.org.

Méthode 1 : depuis les dépôts

apt update
apt install arduino

N.B. : la version disponible dans les dépôts est parfois ancienne, la méthode ci-dessous permet d'obtenir la dernière version du logiciel.

Méthode 2 : depuis le site officiel

tar -xvJf <archive.tar.xz> -C <repertoire>

N.B. : Arduino IDE sera désarchivé dans repertoire, qui peut par exemple être /opt (répertoire d'installation dédié aux logiciels hors dépôts installés manuellement).

-E /opt/arduino-1.8.9/install.sh
usermod -aG dialout <user> // <user> peut être remplacé par $(whoami) pour ajouter l'utilisateur courant
usermod -aG tty <user>
usermod -aG uucp <user>
usermod -aG plugdev <user>

Se déconnecter et se reconnecter pour appliquer les changements. Arduino IDE peut être lancé depuis le menu ou via l'icône sur le bureau. Consulter les instructions et conseils spécifiques pour les différentes cartes disponibles sur le site officiel si nécessaire.

Programmation

Adressage mémoire

L'adresse mémoire désigne une zone de la mémoire de travail (variables…) ou de stockage (programme). Le byte est la plus petite unité logique adressable ; il mesure généralement 8 bits (un octet).

Communication série

La communication série est une « modalité de transmission de données dans laquelle les éléments d'information se succèdent, les uns après les autres, sur une seule voie entre deux points » (Wikipédia). La transmission s'effectue généralement par trames qui contiennent des données liées au protocole en plus du message lui-même. Une communication série permet d'échanger une suite de signaux binaires, comme des niveaux électriques haut et bas. En fonction de la mémoire disponible, il est possible de transmettre de nombreux types de données, comme une suite de caractères codés en ASCII par exemple.

Arduino peut communiquer en série avec un ordinateur ou un périphérique série grâce à un émetteur-récepteur asynchrone universel (UART) intégré utilisant des niveaux logiques de type Transistor Transistor-Logic (TTL). Le niveau du signal est considéré comme bas entre 0 et 1,4V, haut entre 2,4 et 5V. Une trame UART est constitué de la façon suivante :

La liaison série utilise soit le port USB (convertisseur intégré), soit les ports 0 (RX, réception) et 1 (TX, transmission) de l'Arduino. La bibliothèque Serial contient les fonctions nécessaires.

La vitesse de communication série se mesure en bauds. Le baud est l'unité de rapidité de modulation d'un signal. En communication série, un baud vaut un byte par seconde. Arduino peut communiquer avec les baud rate suivants : 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, ou 115200.

Exemple de mise en oeuvre d'une communication série avec Arduino :

void setup() {
  Serial.begin(9600); // Initialisation de la communication série
}

void loop() {
  int memoire;
  // Stockage de la mémoire disponible (en byte) dans la variable memoire
  memoire = Serial.availableForWrite();
  // affichage de la mémoire disponible (en byte) dans la console série
  Serial.println(memoire);
  delay(1000);
}

Typage

Le type des constantes et des variables doit être obligatoirement précisé au moment de leur déclaration. Le type définit l'adresse mémoire (taille et position) de la constante ou variable. Les principaux types pouvant être déclarés sont les suivants :

type taille (byte) valeur
boolean 1 true ou false
char 1 caractère ou entier entre -128 et 127
unsigned char 1 entier entre 0 et 255
byte 1 entier entre 0 et 255
int 2 entier entre -32768 et 32767
unsigned int 2 entier entre 0 et 65535
float 4 décimal (précision : 7 chiffres après la virgule)

Portée

Une variable peut être appelée et modifiée dans l'espace de la fonction où elle est déclarée (setup(), loop()…). Une variable déclarée en dehors d'une fonction est dite globale et peut être appelée de n'importe quel endroit du programme. Contrairement aux variables locales, une variable globale ne libère jamais sa place occupée en mémoire.

Tableaux

Un tableau permet de stocker plusieurs variables identifiées par leur position, voire des sous-tableaux contenant exclusivement des variables du même type (tableaux croisés). La première variable d'un tableau est à la position [0]. Exemple de déclaration de tableau et appel d'une variable stockée :

// modèle : type nomTableau[nombre_variables] = {variable 1, variable x};
boolean tab[2] = {1,0}; // forme 1

boolean tab[2]; // forme 2
tab[0] = 1;
tab[1] = 0;
Serial.println(tab[0]); // affiche 1

boolean tab[2][2] = {0,1,  // tableau avec sous-tableau affiché
                     1,0}; // sur 2 lignes pour faciliter la lecture

Serial.println(tab[0][1]); // affiche la variable 1 du sous-tableau 2,
                           // soit la première variable de la deuxième ligne,
                           // soit la troisième variable, soit 1

Fonctions

Une fonction est une portion de code qui peut être appelée de multiples fois dans le programme. Exemple de déclaration et d'appel d'une fonction de type void (sans valeur de sortie) :

// Modèle : type nomFonction(type param1,type param2) {code à exécuter;}
void setup() {
  Serial.begin(9600);
  tableMulti(9,13); // Affiche la table de 9 jusqu'à 9x13
}

void loop() {
}

void tableMulti(int base,int maximum) { // Fonction d'affichage de la table de multiplication de base jusqu'à maximum
  int result;
  for(int i=0;i<=maximum;i++) {
    Serial.println(result=base*i);
  }
}

Une fonction peut renvoyer une valeur du type défini en sortie :

int nomFonction(type param1, type param2) {
  return; // La fonction retournera une valeur du type int;
}

Aléatoire

La fonction randomSeed(analogRead(0)), avec en paramètre une entrée analogique libre (ici la A0), fournit un échantillon du bruit (de la tension) mesurée sur cette broche. Celle-ci est (réellement) aléatoire et peut servir de « réservoir » de valeurs pour la fonction random(), qui génère une suite de valeurs pseudo-aléatoires. Exemple :

void setup {
  randomSeed(analogRead(0)); // échantillon du bruit sur la broche A0;
  Serial.begin(9600);
}
void loop {
  int resultat = random(0,100); // modèle : random(min, max) avec min inclus et max exclus
  Serial.println(resultat);
  delay(1000); // Affiche une valeur aléatoire entre 0 et 99 toutes les secondes
}

Étalonnage

La fonction map() permet d'étalonner (convertir) une valeur d'un intervalle donné en valeur d'un intervalle différent. Exemple de déclaration :

// Modèle : int map(valeur,minOrigine,maxOrigine,minDest,maxDest);
int val10Bits = 659;
val8Bits = map(val10Bits,0,1023,0,255); // Convertit une valeur 10 bits
                                        // comprise entre 0-1023 en valeur 8 bits
                                        // comprise entre 0-255, ici 659 en 164

La fonction map() ne renvoie que des valeurs de type int, mais accepte un paramètre min>max, ce qui permet d'inverser simplement une valeur :

int nb1 = 1;
nb2 = map(nb1,0,30,30,0); // nb2 vaut l'inverse de nb1 dans l'intervalle 0-30, soit 29

Modulation de largeur d'impulsions (PWM)

Le microcontrôleur de l'Arduino est capable d'utiliser la modulation de largeur d'impulsions (MLI, ou Pulse width modulation, PWM) pour générer un signal pseudo-analogique. La PWM consiste à générer un train d'impulsions 5V de période fixe (2ms entre deux impulsions) mais de durée variable (entre 0-2ms). Le rapport de la durée d'une impulsion sur la période est appelé rapport cyclique. La valeur du signal pseudo-analogique généré équivaut à la moyenne du rapport cyclique, soit le produit du rapport cyclique par l'amplitude maximale du signal. Par exemple, un signal de rapport cyclique 0,5 (impulsion de 5V pendant 1ms, soit la moitié de la période) aura une valeur de 2,5V.

La PWM est utilisée pour la conversion analogique-numérique, les alimentations à découpage (conversion CC-CC…), les amplificateurs de classe D, les variateurs de vitesse. Il peut également permettre de transmettre des données.

Le rapport cyclique du signal est généré numériquement sur 8 bits par l'Arduino, il peut donc prendre une valeur entre 0 et 255. On obtient un signal analogique en sortie. Les sorties PWM sont indiquées sur le PCB par le symbole ~ . Exemple d'utilisation de la PWM pour générer un signal analogique sur le connecteur 9 :

// modèle : analogWrite(connecteur, valeur);
int connecteur = 9;
pinMode(connecteur, OUTPUT);
int pourCent = 70; // on veut un signal en sortie équivalent à 70% de sa hauteur maximale,
                   // soit un rapport cyclique de 0,7
int cycle8bits = map(pourCent,0,100,0,255); // conversion du pourcentage en rapport cyclique sur 8 bits
analogWrite(connecteur, cycle8bits); // on envoie un signal PWM de rapport cyclique 0,7

Électronique

Propriétés électriques

Les propriétés suivantes s'appliquent en circuit fermé alimenté en courant continu. Rappel : tension (V), intensité (A), résistance (Ω), puissance (W), capacité (F).

Propriétés électriques en courant continu

Loi d'Ohm : avec R la résistance en Ohms d'un dipôle, U la différence de potentiel (ou tension) en Volts à ses bornes et I l'intensité du courant en Ampères qui le traverse, on a : U = R x I, ou encore R = U/I.

Puissance : la puissance électrique en Watts désigne la quantité d'énergie par unité de temps fournie par un générateur ou utilisée/dissipée par un composant. Un watt équivaut à une joule par seconde. La puissance électrique traversant un dipôle est le produit de la tension U à ses bornes par l'intensité I du courant le traversant, soit : P = U x I, ou encore P = R x I².

Loi des mailles : « Dans une maille quelconque d'un réseau [un circuit fermé], (…) la somme algébrique des différences de potentiel le long de la maille est constamment nulle ». (wikipedia.org).

Loi des nœuds : « La somme des intensités des courants qui entrent par un nœud est égale à la somme des intensités des courants qui sortent du même nœud ». (wikipedia.org).

Circuits de commande et de puissance

Le circuit de commande désigne la partie d'un circuit qui contient les commandes manuelles (bouton-poussoir, potentiomètre) et électroniques (microcontrôleur, capteurs). Elle est sensible aux parasites et fonctionne sous très basse tension (ici, entre 3,3-12V). Le circuit de puissance désigne la partie d'un circuit qui contient des dispositifs récepteurs de puissance (tension et intensité plus élevées), tels que des moteurs.

Il convient de les isoler l'un de l'autre et de protéger le circuit de commande (ainsi que son opérateur) quand c'est possible.On utilise souvent un relai électromécanique, piloté par le circuit de commande, pour commander l'alimentation électrique du circuit de puissance. Quand c'est possible, l'alimentation et la masse de chaque partie du circuit peuvent être distinctes.

Séparation des circuits - résistance de tirage

Résistances de rappel et de tirage

Une résistance reliée à la masse et placée entre une source d'alimentation et l'entrée d'un circuit (ou ligne) permet d'amener celle-ci au niveau bas électrique (ou 0 logique). Elle est appelée résistance de rappel (pull-down). Elle permet d'établir un niveau bas par défaut pour une ligne qu'on ne veut pas laisser "flottante" (non alimentée), ce qui peut provoquer un fonctionnement erratique du circuit. On utilise dans ce cas une valeur élevée de résistance (ex : 10KΩ).

Une résistance reliée à l'alimentation et placée entre la masse et l'entrée d'un circuit (ou ligne) permet d'amener celle-ci au niveau haut électrique (ou 1 logique). Elle est appelée résistance de tirage (pull-up). Elle permet d'établir un niveau haut par défaut pour une ligne qu'on ne veut pas laisser "flottante" (non reliée à l'alimentation).

L'Arduino dispose d'une résistance interne de 20KΩ qu'il est possible d'utiliser comme résistance de tirage sur une ligne (connecteur) grâce au mode INPUT_PULLUP. Exemple de déclaration :

int pinNum = 7;
pinMode(pinNum, INPUT_PULLUP);

N.B : le connecteur n°13 ne fournira que du 1.7V s'il est utilisé avec la résistance de tirage interne (chute de tension liée à la présence d'une LED + résistance en série sur cette ligne).

Pont en H

« Le pont en H est une structure électronique servant à contrôler la polarité aux bornes d'un dipôle. Il est composé de quatre éléments de commutation (…). Les commutateurs peuvent être des relais, des transistors, ou autres éléments de commutation (…). On utilise le pont en activant les commutateurs de différentes combinaisons pour obtenir le branchement voulu. ». (Wikipédia.org)

Sur le schéma ci-contre, les combinaisons de fermetures d'interrupteurs sont possibles : A1+B2, A2+B1 (inversion de la polarité aux bornes du moteur), A1+B1, A2+B2 (freinage magnétique : court-circuit aux bornes du moteur).

Le circuit intégré L293D repose sur quatre demi-ponts en H et permet de contrôler jusqu'à deux moteurs dans les deux sens, ou quatre dans un seul sens.

Pont en H - diode de roue libre

Diode de roue libre

Un courant électrique parcourant un conducteur produit un champ magnétique. De même, un courant électrique apparaît dans un conducteur qui est soumis à un champ magnétique. Cette propriété appelée induction électromagnétique est utilisée dans des composants comme les relais, moteurs et convertisseurs CC-CC qui intègrent une bobine à cet effet. Quand un tel composant cesse d'être alimenté, la tension aux bornes de la bobine s'inverse. Le dispositif qui le pilote (microcontrôleur, transistor) risque dans ce cas de subir une surtension par retour de courant "parasite". Dans le cas du transistor, la tension entre son collecteur et son émetteur est alors égale à la somme de la tension d'alimentation et de la tension aux bornes de la bobine.

La solution consiste à le protéger grâce à une diode dite de roue libre polarisée en inverse et placée en parallèle de la bobine, à l'entrée du collecteur, de sorte à bloquer la tension inverse. Le courant qui continue à circuler dans la bobine se décharge dans la diode.

Mécanique

Engrenage

Un engrenage est composé d'un pignon (roue possédant le moins de dents) et d'une seconde roue dentée, d'une crémaillère ou d'une vis, qui se transmettent un mouvement. Le sens de rotation s'inverse d'une roue à l'autre. La transmission du mouvement gagne en puissance (couple) du pignon vers la roue dentée, et en vitesse de la roue dentée au pignon.

Le couple représente la puissance de transmission d'un axe. Il se mesure en kg.cm. Un moteur de couple 1kg.cm est capable d'entraîner une masse d'un kilogramme situé à l'extrémité d'un axe d'un centimètre.

Scripts

Étalonnage d'une photorésistance

Source : OpenClassrooms

int pinPR=A0; //pin de connexion pour la photorésistance
int valMin=1024; // on initialise la valeur minimale au plus haut
int valMax=0; // et la valeur maximale au plus bas
void setup() {
  Serial.begin(9600);
}

void loop() {
  int valeur=analogRead(pinPR); // on lit la valeur transmise par la photorésistance
  if (valeur>valMax) //on compare avec valMax
    valMax=valeur;  // on modifie valMax
  if (valeur<valMin) // on compare avec valMin
    valMin=valeur;  // on modifie valMin
  int pourcentage=map(valeur,valMin,valMax,0,100); //pourcentage entre les bornes
  //Séquence d'affichage
  Serial.print("Valeur : ");
  Serial.print(valMin);
  Serial.print(" < ");
  Serial.print(valeur);
  Serial.print(" < ");
  Serial.print(valMax);
  Serial.print("  soit : ");
  Serial.print(pourcentage);
  Serial.println(" %");
}