Le jour de Saint-Valentin, nous offrons souvent des fleurs, des cartes ou des bonbons. Les petites attentions sont toujours, d'une manière ou d'une autre, bien accueillies. Cette année, nous avons mis au point un petit projet pour lequel nous utilisons à nouveau l'affichage matriciel 8x32 points. Si vous souhaitez recréer la petite copine de AZ pour le jour de la Saint-Valentin, n'hésitez pas à jeter un autre coup d'œil sur le blogpost de l'année dernière.
Comme la Saint-Valentin a une plus grande importance pour de nombreux amoureux et que l'amour est également lié à la proximité, nous utilisons cette année un capteur de proximité. Vous savez probablement ceci : une personne qui compte beaucoup pour vous se rapproche de vous, puis votre rythme cardiaque s'accélère et vous pouvez vous sentir très chaud. C'est ce que nous voulons simuler avec le projet de cette année. Nous présentons deux animations sur l'écran. Elles changent à mesure que l'on se rapproche du capteur. L'impulsion s'accélère et la lumière rouge des LEDs représente la chaleur croissante. Nous y voilà.
Ce dont nous avons besoin
Numéro | Composante |
---|---|
1 | MAX7219 8x32 4 in 1 Dot Matrix LED Modul |
1 | Nano V3.0 100% Arduino compatible avec Nano V3 ou |
1 | ESP8266 D1 Mini ou |
1 | ESP32 Devkit C V4 |
1 | VL53L0X ToF Abstandssensor |
Jumper Kabel | |
Breadboard | |
PC mit Arduino IDE und Internetverbindung |
Note : L'affichage matriciel doit être fourni avec 5V. Certaines ESP32 ne fournissent pas de sortie à cette tension. Vous avez alors besoin soit d'une source de tension externe, ou un autre microcontrôleur.
Schéma des circuits
Microcontrôleur Nano ou UNO :
ESP8266 (ici D1 Mini) :
ESP32 (ici Devkit C V4):
Le capteur ToF est connecté comme suit :
VL53L0X |
Nano / UNO |
VIN |
5V ou 3,3V |
GND |
GND |
SCL |
SCL (A5) |
SDA |
SDA (A4) |
GPIO1 |
- |
XSHUT |
- |
VL53L0X |
ESP8266 D1 Mini |
VIN |
5V ou 3,3V |
GND |
GND |
SCL |
SCL (D1 / GPIO5) |
SDA |
SDA (D2 / GPIO4) |
GPIO1 |
- |
XSHUT |
- |
VL53L0X |
ESP32 |
VIN |
5V ou 3,3V |
GND |
GND |
SCL |
SCL (GPIO 22) |
SDA |
SDA (GPIO 21) |
GPIO1 |
- |
XSHUT |
- |
L'affichage matriciel est connecté comme suit, la broche CS étant librement sélectionnable. Cependant, la broche SS ou MISO ne doit pas être utilisée pour cela (info du code source de la bibliothèque LEDMatrixDriver).
MAX7219 Matrix Display |
Nano / UNO |
VCC |
5V |
GND |
GND |
VACARME |
MOSI (D11) |
CS |
D9 |
CLK |
SCK (D13) |
MAX7219 Matrix Display |
ESP8266 D1 Mini |
VCC |
5V |
GND |
GND |
VACARME |
MOSI (D7, GPIO 13) |
CS |
D3 (GPIO 0) |
CLK |
SCK (D5, GPIO 14) |
MAX7219 Matrix Display |
ESP32 |
VCC |
5V |
GND |
GND |
VACARME |
MOSI (GPIO 23) |
CS |
GPIO 32 |
CLK |
SCK (GPIO 18) |
Bibliothèques
La manière d'utiliser le capteur ToF VL53L0X a déjà été décrite dans la série de blogs correspondante. Comme bibliothèque, j'utilise ici le VL53L0X.h de Pololu :
Pour contrôler l'affichage matriciel, vous pouvez utiliser différentes bibliothèques. Dans le blog Afficher les caractères individuels sur l'écran matriciel Albert Vu vous montre comment utiliser la bibliothèque MD_Parola (ou MD_MAX72xx). Cela permet de disposer d'un arsenal très étendu d'exemples de codes sources. Sur Arduino Playground la bibliothèque LEDControl est décrite. J'ai décidé d'utiliser la bibliothèque LEDMatrixDriver et j'ai utilisé le code d'exemple du site DrawSprites.ino comme base :
Une autre bibliothèque est nécessaire, car les valeurs du capteur doivent être mises dans un rapport de valeurs différent pour la luminosité des LED, ainsi que la vitesse de l'animation. Normalement, vous pouvez utiliser la fonction map() incluse pour cela. Malheureusement, l'exécution de cette fonction est très lente. La bibliothèque FastMap fournit un certain nombre d'aides :
Fonction du programme
Nous utilisons un affichage matriciel composé de quatre segments de 8x8 LED (points) chacun. Le premier segment devrait montrer un cœur qui bat. Les trois autres segments montrent un pic ECG animé. Selon la distance qui le sépare du capteur, le cœur devrait pulser plus ou moins vite, les LED devraient briller plus ou moins fort et le pic ECG devrait s'accélérer ou ralentir.
Code source
J'ai utilisé l'exemple simple de la bibliothèque ToF-Sensor, l'exemple de code DrawSprites.ino de la bibliothèque LEDMatrixDriver et le code de démonstration FastMap pour créer une base permettant de mettre en œuvre un programme adapté à notre projet.
Tout d'abord, il faut des cartes binaires pour le cœur qui bat. En outre, une image pour le pic de l'ECG. Bien entendu, en raison de la faible résolution des images (8x8 pixels), l'affichage des images est de qualité limitée. Mais on reconnaîtra ce dont il s'agit.
Sur l'Article de blog par Albert Vu vous trouverez un modèle pour créer des tableaux bitmap. J'ai utilisé le générateur en ligne sur ce site. Alternativement, vous pouvez également utiliser ce site, vous pouvez y créer plusieurs bitmaps et les générer sous forme de tableau. Vous cliquez sur vos images ensemble, puis vous ne copiez que le code source.
Vous pouvez télécharger l'esquisse terminée pour l'IDE Arduino ici : téléchargement direct
Description détaillée du programme
J'aimerais maintenant entrer dans les détails du code source. Après l'inclusion des bibliothèques, il faut définir le réglage du capteur ToF. Comme nous dépendons des vitesses élevées dans ce projet, j'ai utilisé le mode HIGH_SPEED. La plage de mesure maximale est alors limitée à environ 60 cm. Toutefois, cela peut être toléré. L'étape suivante consiste à vérifier si le microcontrôleur sélectionné (via le menu Outils -> Carte) est un AVR (UNO, Nano), ESP8266 ou ESP32. J'ai ajouté les broches de l'interface SPI (pour l'affichage matriciel) en commentaire. Ici aussi, la broche CS est définie dans chaque cas, qui est librement sélectionnable.
Ensuite, nous déterminons la taille de l'affichage. Nous utilisons quatre segments de 8 pixels chacun en largeur (et en hauteur). Ces valeurs sont ensuite utilisées pour l'instance LEDMatrixDriver.
Ensuite, suivez les déclarations et les définitions des bitmaps. Pour une meilleure visibilité, je les ai créés sous forme binaire. Le pic de l'ECG est un tableau d'un seul octet. Le cœur qui palpite est un réseau d'octets en deux dimensions. Il est ainsi plus facile de le parcourir en boucle. C'est ainsi que nous créons l'animation du cœur qui palpite.
Plus bas, les différentes variables suivent. intens_min et intens_max sont définies par la bibliothèque LEDMatrixDriver. La luminosité des LED peut donc être réglée en 10 étapes. 0 ne signifie pas qu'une LED est éteinte, cependant. Il ne représente que la valeur de luminosité la plus faible possible.
heartBeatDelayDefault définit la vitesse à laquelle l'animation doit tourner au ralenti lorsqu'aucun objet n'est à sa proximité. heartBeatDelayMin est la vitesse la plus rapide. Avec HEART_ANIM_DELAY, vous pouvez régler la vitesse du cœur qui bat.
Les deux instances objet FastMap mapper_heartBeat et FastMap mapper_intensity convertissent les valeurs des capteurs qui arrivent en vitesse de l'animation ECG ou en luminosité des LEDs pour notre usage.
J'ai pris la fonction drawSprite() du code source de l'échantillon. Il affiche le bitmap à l'écran.
Dans setup(), l'interface I²C, le capteur ToF et le fastMapper sont initialisés. En outre, le mode du capteur ToF est défini et la plage de valeurs maximales est définie comme une variable sur cette base. Ensuite, l'affichage est activé.
Dans la fonction loop(), il est vérifié si un capteur ToF est connecté. Sinon, la vitesse et la luminosité de l'animation sont passées en revue avec les valeurs par défaut. Il serait donc possible de tester le programme sans capteur. Si vous souhaitez connecter un capteur d'un autre type, vous devez modifier ou supprimer la commande à ce stade. Si un capteur est présent (isToFpresent), il sera lu. La valeur de la distance retournée est ensuite utilisée pour décider s'il faut revenir à la vitesse par défaut ou définir une nouvelle vitesse d'animation. Il en va de même pour la luminosité des LED. L'animation du pic de l'ECG suit ensuite. Elle est programmée sans interruption (fonction without delay()). Pour le principe, je recommande l'exemple du projet BlinkWithoutDelay. La boucle principale est parcourue sans fin à la vitesse la plus rapide possible. Le temps est alors arrêté et comparé à celui que nous avons fixé auparavant. Une fois ce point atteint, la partie du programme dans la demande "si" est exécutée. Ici, le pic ECG est affiché sur l'écran. Pour que nous puissions voir le mouvement, la valeur X est incrémentée, c'est-à-dire qu'elle est comptée. Notre symbole est donc déplacé d'un pixel vers la droite à chaque passage. Lorsque la largeur maximale de l'affichage est dépassée, la position X est réinitialisée à la valeur de départ. J'ai également ajouté à ce stade un interrupteur qui contrôle l'animation des battements de cœur. De plus, cela ne devrait être fait qu'une seule fois. Il est ensuite verrouillé et ne se libère que lorsque le pic est passé. Alors tout commence par le début.
L'animation du cœur qui palpite fonctionne de la même manière. Ici, le temps entre chaque bitmap (le cœur apparaît, devient plus grand, puis plus petit à nouveau et disparaît) est constant. Pour que le cœur semble battre plus vite (au même rythme que le pic ECG), cette animation ne commence que lorsque le pic ECG commence également. D'où le changement dans la requête précédente. Sans cette mise en œuvre, le cœur ne ferait que battre constamment. De cette façon, nous obtenons une animation fluide et le cœur peut battre à des rythmes différents selon la distance au capteur.
La lecture du capteur et de toutes les autres commandes nécessite du temps. Comme l'animation à l'écran en dépend, le temps ne doit pas devenir trop long. C'est pourquoi j'ai essayé d'optimiser le programme en termes de temps. La première chose que j'ai faite a été d'interdire la fonction delay() dans les exemples. Sinon, le capteur ne serait lu que lorsque le temps est écoulé. J'ai utilisé principalement des variables int au lieu de variables long car le processeur peut les traiter plus rapidement. C'est en fait un peu compliqué, parce que la fonction millis() renvoie en fait un long non signé. J'ai réglé le capteur ToF sur HIGH_SPEED, même si cela réduit la plage de mesure. De plus, pour mettre à l'échelle les valeurs du capteur en fonction de la vitesse et de la luminosité, j'ai utilisé la fonction fastMap() au lieu de la fonction map(). En conséquence, une animation tout à fait utilisable apparaît sur l'écran. Si l'on considère qu'un seul processeur fait tout, c'est plutôt bien. Bien sûr, cela dépend aussi du microcontrôleur utilisé.
Regardez comment le projet Valentine assemblé se présente à la fin dans cette courte vidéo :
Extensions possibles
Il est également possible d'utiliser d'autres capteurs de distance tels que le Capteur à ultrasons HC-SR04 ou pour utiliser un capteur de distance infrarouge. Vous donnez les valeurs mesurées au fastMap ()-Fonction. Vous devrez peut-être régler les plages de mesure (minRange et maxRange) ajuster.
Les valeurs du capteur mises à l'échelle peuvent également être inversées, de sorte que la vitesse devient plus lente à une petite distance, ou plus rapide à une distance plus grande. Pour cela, vous pouvez brancher un interrupteur sur l'une des broches numériques, par exemple pour basculer entre les deux modes "nouvellement amoureux" et "marié depuis 40 ans". Sans interrupteur, il suffit de modifier ces deux lignes pour que les variables cibles soient permutées :
précédemment :
mapper_heartBeat.init (minRange, maxRange, heartBeatDelayMin, heartBeatDelayDefault);
mapper_intensity.init (minRange, maxRange, intens_max, intens_min);
après :
mapper_heartBeat.init (minRange, maxRange, heartBeatDelayDefault, heartBeatDelayMin);
mapper_intensity.init (minRange, maxRange, intens_min, intens_max);
Passez un excellent jour de Saint-Valentin.
Andreas Wolter
pour AZ-Delivery Blog
4 commentaires
Andreas Wolter
@Andy
@Florian
Thank you for your advice / Danke für Euren Hinweis.
(english below)
Für eine flüssigere Animation hatte ich die Variablen als “int” deklariert. Das ist etwas unsauber, denn millis() gibt unsigned long zurück. Wie Andy schon bemerkt hat, ist der Wertebereich wesentlich kleiner und somit kann die Zeit nicht mehr verglichen werden. Ich habe nun die Deklaration folgendermaßen geändert:
// millis for nonblocking Animation
unsigned long animZeit = 0;
unsigned long heartAnimZeit = 0;
Alle anderen Variablen bleiben int. Das ist immer noch unsauber, da kein ordentlicher Typecast durchgeführt wird. Das nehme ich in Kauf, damit die Animation flüssig bleibt. Die Arduino IDE hilft da ein wenig nach.
Es sollte nun funktionieren.
Ich wünsche einen schönen Valentinstag.
English:
For a smoother animation, I had declared the variables as “int”. This is a bit messy, because millis() returns unsigned long. As Andy has already noticed, the value range is much smaller and thus the time can no longer be compared. I have now changed the declaration as follows:
// millis for nonblocking animation
unsigned long animTime = 0;
unsigned long heartAnimTime = 0;
All other variables remain int. This is still messy, as no proper typecast is performed. I put up with this to keep the animation smoothly. The Arduino IDE helps a little.
It should work now. Have a nice Valentine’s Day.
Andreas
Florian
Hallo,
das gleiche Problem wie Andy schrieb habe ich auch: nach etwa 1 Minute läuft die Animation auf voller Geschwindigkeit. Die Helligkeit funktioniert wie vorher unverändert. Gibt es dafür eine Lösung?
Gruß
Florian
Andy
I love this and have made it for my wife on Valentines day, but it seems that after a minute of so the heartbeat animation always runs at full speed, this seems to correspond with the variables heartAnimZeit and animZeit exceeding 65535 and resetting to zero I have this happen after a longer period my making them unsigned long but I’d be grateful to see if it is possible to correct this somehow?
Angelo De Lucia
Molto bello il progetto, spiegato molto bene.
Complimenti , grande lavoro , grandissimi.