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.
- Pour Windows : télécharger et installer le logiciel depuis le site officiel.
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
- Télécharger l'archive pour Linux sur le site officiel.
- Extraire l'archive : clic droit - Ouvrir avec Gestionnaire d'Archives, ou en ligne de commande :
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).
- Exécuter le script d'installation install.sh : cliquer-déposer dans un terminal, ou clic droit - ouvrir dans un Terminal, ou en ligne de commande :
-E /opt/arduino-1.8.9/install.sh
- Ajouter l'utilisateur courant aux groupes dialout, tty, uucp et plugdev (nécessaire dans certains cas pour téléverser le code sur le microcontrôleur) :
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 :
- bit de start à 0 pour la synchronisation du récepteur;
- données : taille comprise entre 5 et 9 bits, envoyés du bit de poids faible (LSB) au bit de poids fort (MSB), soit l'inverse du sens de notation habituel;
- bit de parité (somme de contrôle pour vérifier l'intégrité du message);
- bit de stop au niveau 1.
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).
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.
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.
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(" %");
}