Préambule
Les cartes arduino classiques (comme celle qui équipe les mini voitures qui seront utilisées) n'ont pas de chip wifi. Il faut donc leur adjoindre un "shield" (i.e. une carte additionnelle prévue pour se fixer sur les connecteurs de l'arduino) qui inclut ce chip. Il existe cependant d'autres micro-controleurs qui ont le wifi intégré, par exemple les esp32, ou leur "petit-frère" les esp8266.
Il existe plein de fabriquants de matériel électronique qui proposent de mini cartes basées sur ces deux micro-controleurs. Celle qui va être utilisée dans ce TP est de la firme TTGO, et s'appelle la T8. Ce fabriquant propose plusieurs types de cartes relativement bien pensées, et surtout très peu chères.
Grâce au kit de développement arduino pour ces cartes (fourni par le concepteur de l'esp32), il est extrêmement facile de créer des programmes plus ou moins complexes, utilisant des bibliothèques tierces afin de gérer des modules externes, tels que des capteurs (température, son, lumière, ...), des afficheurs, des moteurs, etc.
ATTENTION ! les composants de ces cartes sont fragiles donc des erreurs de manipulation peuvent facilement "cramer" la carte |
Préambule
Pour ce TP, la platine d'expérimentation ( = "planche à pain" = breadboard) est déjà complètement câblée. Si vous n'avez jamais utilisé de planche à pain, il faut savoir 2-3 choses à leur sujet :
- elles sont de différents formats mais elles contiennent toutes des rangées plus ou moins longues de trous,
- les trous permettent d'insérer des câbles qui vont connectés des composants,
- au sein d'une rangée, tous les trous sont connectés ensembles : il ne faut donc JAMAIS brancher les pins d'un composant sur une même rangée, sinon on provoque un court-circuit => on peut cramer le composant.
- sur les bords, il y a des rangées "spéciales" qui sont généralement dédiées pour distribuer l'alimentation (le +3.3V avec une esp32) et la masse (le 0V). Normalement, la rangée d'alimentation est signalée par un + et peinte en rouge, alors que la masse est signalée par un - et peinte en bleu (ou noir). Quand un composant nécessite d'être alimenté, il a une pin notée généralement VCC et une pin GND. La pin VCC doit être reliée sur la rangée +, et la pin GND sur la rangée -.
L'image ci-dessous correspond à un exemple de planche à pain, identique à celle utilisée dans les TPs, à part sa longueur :
- de part et d'autre de la rainure centrale, on retrouve des rangées verticales vertes de 5 trous connectés ensembles. Attention, pour une même colonne, la rangée de 5 du haut N'EST PAS connectée à celle du bas (ça serait même gênant)
- en haut et en bas de la platine, on retrouve les rangées de trous bleues et rouges horizontales, servant à distribuer l'alimentation et la masse. On remarque que les séries de 5 trous sont cette fois connectées ensemble, mais que bleus et rouges ne sont pas connectés (heureusement).
La planche à pain utilisée pour le TP comporte :
- un switch à 2 positions,
- une LED,
- un capteur de température, humidité, pression (type BME280)
- un capteur d'obstacle basé sur les ultrason (type HCSR04)
- un afficheur 4 digits (type TM1637)
Le câblage est le suivant (avec le µC placé à droite de la planche) :
- LED -> pin 5 du µC
- Switch
- pin gauche -> rangée - du haut de la planche
- pin central -> pin 27 du µC
- pin droite -> rangée + du bas de la planche
- TM1637 (du haut vers le bas, quand l'afficheur est à gauche de la planche) :
- pin CLK -> pin 32 du µC
- pin DIO -> pin 33 du µC
- pin VCC -> rangée + du bas de la planche
- pin GND -> rangée - du haut de la planche
- HCSR04 (de la gauche vers la droite, quand le capteur est en haut de la panche)
- pin GND -> rangée - du haut de la planche
- pin ECHO -> pin 19 du µC
- pin TRIGGER -> pin 22 du µC
- pin VCC -> rangée + du bas de la planche
- BME280 (de la gauche vers la droite, quand le capteur est en haut de la planche)
- pin VCC -> rangée + du bas de la planche
- pin GND -> rangée - du haut de la planche
- pin SCL -> pin 23 du µC
- pin SDA -> pin 18 du µC
- pin CSB -> rangée + du bas de la planche
- pin SDO -> rangée - du haut de la planche
NB : le BME280 n'est pas utilisé dans ce TP.
Exercice 1 : mise en place logicielle
1.1°/ Pour les machines du département
- Pour écrire des programmes pour l'esp32, il existe plusieurs solutions. Nous allons utiliser celle proposée par l'environnement de développement arduino, qui est basé sur un langage qui évoque le C++.
- Ce logiciel, ainsi que les kits de développement pour les micro-contrôleurs sont déjà installé sur les machines du département.
- Arduino se trouve dans /opt/arduino-1.8.19/arduino.
- Pour vous éviter de taper le chemin complet à chaque fois, ouvrez un terminal et tapez :
- cd ~
- gedit .bashrc
- Dans l'éditeur, allez à la fin du fichier et ajoutez les lignes suivantes :
- Sauvegardez le fichier.
- Ouvrez un nouveau terminal, dans lequel vous pouvez directement taper arduino pour lancer le logiciel.
- Lors du premier lancement, il configure automatiquement certains paramètres, tels que le répertoire où se trouvent vos projets (appelés croquis), à savoir ~/Arduino
- La première étape est d'installer arduino, en le téléchargeant depuis le site officiel : https://www.arduino.cc/en/software
- Compte tenu des améliorations non négligeables apportées par la v2 d'arduino, il est conseillé de télécharger cette version.
- Ensuite, il faut installer le kit de développement pour l'esp32 :
- Lancer arduino.
- Dans le menu "Fichier", choisissez "Préférences"
- Dans le champ "URL de gestionnaire de cartes ...", ajoutez https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json.
- Si vous avez déjà des URLs de définies, ajoutez une virgule à la fin puis copier celle ci-dessus juste après la virgule.
- Cliquez sur "Ok" pour enregistrer
- Dans le menu "Outils", allez sur l'item "Carte : ...", puis sélectionnez "Gestionnaire de carte"
- Dans le champ de saisie en haut à droite, tapez "ESP32" pour filtrer les résultats. S'il vous affiche plusieurs choix, prenez le "esp32 by Espressif Systems". La version actuelle est la 3.x.x
- Déplacez la souris sur le choix affiché et un bouton "Installer" devrait apparaître. Cliquez dessus pour lancer l'installation.
- Retournez dans "Outils" -> "Type de carte" et vérifiez que vous pouvez choisir "ESP32 Dev Module". Si c'est le cas, l'installation est réussie.
- Pour réellement tester votre configuration :
- brancher la carte de développement ttgo t8 à votre ordinateur via un câble USB,
- dans le menu Outils, le sous-menu Port permet de spécifier quel port doit être utilisé pour communiquer avec la carte. Si tout va bien, vous devriez voir /dev/ttyACM0 (sous linux), ou bien COM... (sous Windows)
- Attention, selon les cartes de dev., vous pouvez également avoir comme port /dev/ttyUSB0. De plus, si vous avez plusieurs cartes branchées, vous aurez 1, 2, ... à la place du 0.
- Ensuite, choisissez comme type de carte ESP32 Dev Module. C'est un type générique qui convient pour la ttgo T8 . Cependant, si vous utilisez un autre type de carte de dev, il est possible qu'elle soit directement listée. Par exemple, si vous utilisez une Lolin D32, vous pouvez sélectionner précisément cette carte.
- Si malgré cela, vous constatez qu'il n'est pas possible, soit d'avoir un port, soit d'uploader sur la carte, reportez-vous à l'article suivant pour tenter de régler le problème : Arduino : problèmes d'utilisation classiques & solutions
Exercice 2 : LED+switch
- Si on regarde la planche, on remarque que la LED n'est pas directement connectée à la pin 5. En effet, pour qu'il n'y ait pas trop de courant qui circule à travers celle-ci, on utilise un résistance de 300 Ohms entre la pin et la LED. Ainsi l'intensité du courant (en ampère) est limitée et ne risque pas de griller la LED.
- Le switch possède 3 pins (= broche en français). Le principe de fonctionnement est simple : si le switch est poussé vers la gauche, les broches 1 et 2 sont connectées et si le switch est poussé vers la droite les broches 2 et 3 sont connectées. Or, la broche 1 est connectée à la masse donc 0V et la broche 3 est connectée au +3.3V au travers d'une résistance (de 10KOhms). Si on lit l'état de la pin, on a donc soit l'état bas, soit l'état haut en fonction de la position du switch. Pour le switch, la résistance n'est pas spécialement nécessaire mais elle permet de limiter le courant entrant dans la pin 27 du µC. En effet, celui-ci n'a pas besoin d'un courant très important pour détecter l'état haut. Si l'µC était alimenté sur batterie, la résistance serait utile pour l'économiser.
- Lancez arduino et créez un nouveau sketch (menu "Fichier" -> "Nouveau") nommé par exemple esp32_ledswitch.
- Dans setup(), le sketch doit :
- initialiser la liaison série avec l'ordinateur, à 115200 bauds,
- initialiser la "direction" des pins du switch et de la LED,
- envoyer "OK" à l'ordinateur.
- Dans loop(), le sketch doit :
- récupérer l'état du switch,
- si l'état = 1, alors allumer la LED,
- si l'état = 0, alors éteindre la LED,
- attendre 500ms.
- Dans l'exercice 2, si on bouge 2 fois le switch pendant le temps d'attente de 500ms, on manque un changement d'état, ce qui peut être préjudiciable selon les applications.
- Pour éviter cela, on utilise les interruptions.
- Lancez arduino et créez un nouveau sketch (menu "Fichier" -> "Nouveau") nommé par exemple esp32_ledswitchint.
- Créer une fonction: void ICACHE_RAM_ATTR handleSwitch(), qui doit :
- lire l'état du switch,
- si l'état est haut : allumer la LED
- sinon éteindre la LED
- *Dans setup(), le sketch doit :
- initialiser la liaison série avec l'ordinateur, à 115200 bauds,
- initialiser la "direction" des pins du switch et de la LED,
- mettre en place la détection d'interruption sur la pin 27, dès que son état change. Dans ce cas, on appelle la fonction handleSwitch().
- envoyer "OK" à l'ordinateur.
- La fonction loop(), est laissée vide
Tester le sketch en changeant la position du switch : la LED doit s'allumer et s'éteindre en fonction de la position.
- Le principe du capteur ultrason est d'envoyer une onde sonore et de capter son retour. C'est pourquoi il y a une pin intitulée TRIGGER qui émet un ultrason, et la pin ECHO qui capte le retour.
- Le temps passé entre l'aller et le retour permet de mesurer la distance au plus proche obstacle.
- Ce n'est pas un capteur très précis et parfois les rebond sur les obstacles peuvent conduire le capteur à calculer une distance bien trop grande par rapport à la réalité.
- Lancez arduino et créez un nouveau sketch (menu Fichier -> Nouveau) nommé par exemple esp32_ultrasonic.
- Allez dans Fichier -> Préférences. Dans la fenêtre qui s'ouvre, notez le répertoire où sont placés par défaut vos sketch. Par exemple, sous linux, cela devrait être quelque chose du genre /home/login/sketchbook ou bien /home/login/Arduino.
- Allez dans ce répertoire. Vérifiez qu'il y a un sous-répertoire libraries. S'il n'existe pas, créez-le.
- Téléchargez la bibliothèque [ ultrasonic.tgz ] et décompactez-là dans libraries. Cela produit un sous-répertoire HCSR04Ultrasonic. avec les sources de la bibliothèques mais également un répertoire avec un exemple.
L'objectif de l'exercice est de s'inspirer de cet exemple pour créer un sketch qui va éteindre/allumer la LED en fonction du fait que l'on détecte un obstacle à 20cm du capteur, mais en tenant compte de l'état du switch.
- Dans setup(), le sketch doit :
- initialiser la liaison série avec l'ordinateur, à 115200 bauds,
- initialiser la "direction" des pins du switch et de la LED,
- envoyer "OK" à l'ordinateur.
- Dans loop(), le sketch doit :
- récupérer l'état du switch,
- récupérer la distance actuelle au premier obstacle rencontré,
- si l'état switch = 1 :
- si distance obstacle <=20cm alors allumer la LED,
- sinon éteindre la LED
- si l'état switch = 0 :
- si distance obstacle > 20cm, alors allumer la LED,
- sinon éteindre la LED
- attendre 500ms.
- L'esp32 n'a pas tout à fait la même façon d'initialiser le PWM que l'esp8266/arduino, car il y a un circuit interne qui permet de gérer 16 canaux, à savoir signaux PWM différents et donc de les attacher à 16 GPIO différentes. Pour utiliser PWM, il faut :
- initialiser les paramètres du PWM : ledcAttachChannel(num_pin, frequence, nb_bits, num_canal). num_canal va de 0 à 15. nb_bits va de 1 à 20 et permet de régler le nombre de pas possibles pour le duty-cycle, mais en précisant sur combien de bits et pas une valeur entière. Par exemple, on peut mettre 10 pour avoir 2^10 = 1024 pas.
- lancer le PWM : ledcWrite(num_pin, duty_cycle). duty_cycle va de 0 à la valeur max fixée par nb_bits. Par exemple, si nb_bits vaut 10, alors duty_cycle peut aller de 0 à 1023, sachant qu'avec 512, on obtient un duty cycle de 50%.
- Il existe d'autres fonctions, notamment pour changer les paramètres : se reporter à la documentation officielle de l'esp32 sur arduino : https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/ledc.html#
- Lancez arduino et créez un nouveau sketch (menu Fichier -> Nouveau) nommé par exemple esp32_ultrasonicpwm.
- Créer les variables globales :
- float dist;
- volatile byte stateSwitch;
- Créer une fonction : void ICACHE_RAM_ATTR handleSwitch() :
- lire l'état du switch et le mettre dans stateSwitch.
- Créer une fonction : void changeBlink() :
- si stateSwitch == 1 :
- si dist <= 10cm, régler la fréquence du PWM à 1Hz,
- si dist >=100cm, régler la fréquence du PWM à 50Hz,
- sinon régler la fréquence sur une valeur entre 1 et 50Hz, proportionnelle à la distance entre 10cm et 100cm.
- démarrer le PWM sur le canal choisi (cf.ci-dessous) un duty cycle de 50%
- sinon, éteindre la LED
- si stateSwitch == 1 :
- Dans setup(), le sketch doit :
- initialiser la liaison série avec l'ordinateur, à 115200 bauds,
- initialiser la "direction" des pins du switch et de la LED,
- initialiser le PWM sur la pin 5, avec 10 comme valeur de nb_bits (pas moins, sinon 1Hz ne sera pas possible).Vous pouvez choisir n'importe quel numéro de canal.
- mettre en place la détection d'interruption sur la pin 27, dès que son état change. Dans ce cas, on appelle la fonction handleSwitch().
- dist = 0
- récupérer l'état du switch et en fonction allumer ou éteindre la LED.
- envoyer "OK" à l'ordinateur.
- Dans loop(), le sketch doit :
- récupérer la distance actuelle au premier obstacle rencontré -> new_dist.
- si écart en new_dist et dist > 1cm :
- dist = new_dist
- appeler changeBlink().
- attendre 100ms.
- Dans arduino, allez dans Outils -> Gérer les bibliothèques. Dans la fenêtre qui s'ouvre, taper dans le champ de recherche : tm1637.
- Plusieurs choix sont possibles, offrant des fonctionnalités plus ou moins avancées. Pour le TP, choisissez Groove 4-digit display puis cliquez sur Installer.
Dans le répertoire d'installation de cette bibliothèque (NB : elle est aussi dans le répertoire libraries où vous avez installé celle de l'exercice 4), vous trouverez des exemples, notamment NumberFLow.ino qui peut vous servir d'inspiration pour cet exercice.
ATTENTION : dans cet exemple, les pins CLK et DIO utilisées sont 2 et 3. Il faut bien entendu changer ces valeurs pour utiliser les pins prévues sur la planche (cf. préambule)
- Créez un nouveau sketch (menu Fichier -> Nouveau) nommé par exemple esp32_tm1637.
- Copier/coller le code de l'exercice 5.
- Modifier le sketch pour qu'après l'appel à changeBlink(), la nouvelle distance en cm (tronquer les décimales) soit affichée sur les 3 premiers digits de l'afficheur si la distance est >= 100cm, et sur les digits 2 & 3 si la distance est <=99cm.
Exercice 7 : hacking de bibliothèque
La bibliothèque de l'afficheur est relativement simple à utiliser mais elle ne permet d'afficher que les chiffres de 0 à 9 et les lettres de A à F. En effet, si on regarde un peu dans le fichier TM1637.cpp, on voit au tout début un tableau nommé TubeTab contenant 16 valeurs et un commentaire indiquant quelle valeurs correspond à quel caractère. De plus, on voit que la fonction display() prend en paramètre un numéro de digit et de façon indirecte, un indice dans TubeTab du caractère à afficher. Par exemple, si on appelle display(4,15), un F apparaîtra sur le 4ème digit. Si on veut afficher d'autres caractères, il faudrait donc ajouter des valeurs à ce tableau TubeTab.
- Modifiez TubeTab pour ajouter les caractères + (NB : il manque forcément une des barres horizontale de la croix) et -
- Modifiez le sketch de l'exercice 6 pour que le 4ème digit de l'afficheur affiche un + si la distance a grandi depuis la dernière mise à jour de l'affichage, ou bien un - si elle a diminuée.
Indice : faîtes une recherche sur wikipedia de "afficheur 7 segments". En lisant jusqu'au bout, vous devriez trouver sans peine comment sont codés les caractères qui s'affichent.
Exercice 8 (bonus pour les rapides) : gérer des événements temporaires
L'objectif de cet exercice est de compléter l'exercice 7 pour que :
- l'afficheur puisse afficher les lettres H, L, un "crochet droit" formé par un L et le segment droite-bas allumé, ainsi que son symétrique par la verticale (c.a.d L inversé et segment gauche-bas allumé)
- si le switch change d'état, au lieu d'afficher la distance, on affiche pendant deux secondes l'état du switch. Après ces 2 secondes, on revient à l'affichage de la distance.
ATTENTION : pendant les 2 secondes, le script ne doit pas être bloqué et la mesure de la distance, le PWM doivent continuer à se faire.
Les caractères pour afficher l'état sont :
- haut => H, 1, 9, H
- bas => L, 0, crochet droit, crochet gauche (l'assemblage des 2 crochets forme une sorte de W)
Indice : cherchez du côté de la fonction millis() pour mesurer le temps qui passe.