Minuteur de lavage des mains sans contact avec alertes musicales
Composants et fournitures
| Arduino UNO | ×1 |
| Boîtier ProtoStax pour Arduino | ×1 |
| Boîtier ProtoStax pour plaques d'essai/cartes personnalisées | ×1 |
| Kit d'empilement horizontal ProtoStax | ×1 |
| Capteur ultrasonique HC-SR04 (générique) | ×1 |
| Kit ProtoStax pour capteur ultrasonique HC-SR04 | ×1 |
| Adafruit afficheur 7 segments 4 digits 0,56" avec backpack I2C - Bleu | ×1 |
| Buzzer piézo Adafruit - PS1240 | ×1 |
| Plaque d'essai sans soudure (demi-taille) | ×1 |
Applications et services en ligne
- Arduino IDE
À propos du projet
Le lavage des mains a toujours été essentiel dans la prévention des maladies et la santé globale, mais il a pris une importance accrue comme mesure préventive contre la propagation de la pandémie de COVID-19.
Le CDC recommande de se frotter les mains pendant 20 secondes idéalement. Lien CDC
Info bonus : Voici la science derrière le lavage des mains si cela vous intéresse ! Lien CDC
Dans cette version revisitée, notre minuteur musical sans contact est activé en passant la main devant un capteur ultrasonique, et affiche le décompte sur un afficheur 7 segments. Pour le rendre plus ludique, il joue une sélection tournante de jingles de 20 secondes pré-programmés. Vous pouvez ajouter vos propres musiques facilement en transcrivant n'importe quelle partition !
Voici le Minuteur de lavage des mains musical sans contact en action, avec les 4 jingles programmés :
- Joyeux Anniversaire
- Do-Ré-Mi (La Mélodie du Bonheur)
- We Will Rock You (Queen)
- Thème de Jeopardy
Mes mains étaient super propres à la fin ! 😊
Info bonus : On sait que chanter « Joyeux Anniversaire » deux fois prend environ 20 secondes, devenu standard de facto pour le lavage des mains, même chanté par le Premier ministre canadien Justin Trudeau ! La Dre Theresa Tam, directrice de la santé publique du Canada, a ses favoris comme « We Will We Will Wash You » ! 😊 Regardez cette interview fascinante par Arjun Ram de CBC Kids News. Nos deux chansons sont incluses, plus deux autres ! 😊
Étape 1 - Schéma
Ce projet utilise un Arduino Uno, un backpack LED 7 segments (I2C), un capteur ultrasonique HC-SR04 et un buzzer piézo. Voir le schéma ci-dessous.

Étape 2 - Planification et mise en place
Au-delà du schéma et de la programmation, je voulais penser au « produit fini » et à son utilisation — donc le mettre dans un boîtier et planifier pour cela.
J'ai utilisé les boîtiers ProtoStax — empilables, avec support pour Arduino, Raspberry Pi et plaque d'essai. Comme j'utilisais un Arduino avec un circuit sur plaque d'essai, j'ai choisi le boîtier ProtoStax pour Arduino et celui pour plaque d'essai/cartes personnalisées. Je voulais aussi le capteur ultrasonique accessible de l'extérieur — j'ai utilisé le kit ProtoStax pour HC-SR04.
J'ai commencé par empiler horizontalement les plateformes de base Arduino et plaque d'essai avec les connecteurs d'empilement horizontal pour faciliter le prototypage :

Une fois la plateforme de prototypage prête, j'ai placé les composants selon le schéma. J'ai fixé le capteur HC-SR04 sur la paroi latérale du kit ProtoStax pour le rendre accessible une fois le boîtier assemblé. La paroi latérale avec le capteur s'insère dans l'emplacement de la plateforme de base :


Étape 3 - Programmation et tests
Avec une plateforme de prototypage fonctionnelle, j'ai développé le code. J'approfondirai la fonctionnalité et la structure du code dans une section séparée. Voici une vidéo des tests. C'est fou que l'iPhone 11 utilisé pour l'enregistrement ait capté le ping sonar distinct du capteur ultrasonique, audible très clairement dans la vidéo (bien que le pulsation ultrasonique soit à peine perceptible autrement, avec un petit clic-clic-clic inoffensif) ! 😊
Une fois tout confirmé fonctionnel, j'ai ajouté les parois latérales, connecteurs restants et couvercles pour finaliser le boîtier :

La vidéo en haut montre le « produit » final en utilisation ! 😊

Comprendre le code
Initialisation des composants
Nous utilisons la classe Adafruit_7segment de la bibliothèque LED Backpack pour initialiser et communiquer avec l'afficheur 7 segments.
Adafruit_7segment matrix = Adafruit_7segment();
Nous initialisons aussi les broches trig et echo du HC-SR04 en sortie et entrée respectivement :
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
matrix.begin(0x70);
Dans la boucle principale, voici ce qui se passe à haut niveau :
- Vérifier la lecture de distance du capteur ultrasonique pour voir si le minuteur est déclenché.
- Si oui, noter l'heure courante, initialiser le minuteur de décompte (20 pour 20 secondes), et choisir le prochain jingle musical. J'ai d'abord utilisé
random()pour choisir une mélodie aléatoire, mais je l'ai changé pour un mode « round-robin » sur le tableau des mélodies (retour à la première), et misstartMusicà 1 pour lancer le décompte et la musique.
if (distance < 10 && !startMusic) {
startMusic = 1;
countDown = 20;
currentTime = millis();
melodyNum = (melodyNum + 1) % NUM_MELODIES(melodies);
}
Regarde maman, pas de delay() !
Nous faisons deux choses simultanément : mettre à jour l'horloge de décompte périodiquement (secondes restantes) ET traiter le jingle pour le jouer correctement dans le temps.
Nous ne pouvons pas utiliser delay().
L'exemple typique de lecture musicale utilise tone() de la bibliothèque Tone, et attend le délai approprié avant de passer à la note suivante. Cela ne fonctionne pas car nous voulons toujours mettre à jour l'horloge de décompte !
tone() est un appel non-bloquant. Il utilise le Timer2 pour envoyer le signal pendant la durée spécifiée, ce qui signifie qu'entre-temps, nous sommes libres de faire d'autres traitements.
Nous utilisons millis() et des variables locales pour déterminer le temps écoulé, au lieu de delay(), et pouvons faire d'autres vérifications et opérations entre-temps.
Transcrire la musique facilement - Notes entières, quarts, etc.
Nous voulons jouer une mélodie donnée, et faciliter la transcription de nouvelles mélodies. Les exemples Arduino musicaux stockent habituellement deux tableaux distincts : un pour les notes, un pour les durées (en millisecondes).
Pour simplifier, j'ai créé une structure associant une note et sa durée. Et au lieu de durées absolues, j'utilise des durées relatives avec des #define :
typedef struct Note {
int frequency;
float duration;
} Note;
#define NOTE_WHOLE 1
#define NOTE_HALF 0.5f
#define NOTE_QUARTER 0.25f
#define NOTE_EIGHTH 0.125f
#define NOTE_SIXTEENTH 0.0625f
#define DOTTED(X) (X * 1.5f)
Prenons l'exemple de « Joyeux Anniversaire ».

Cela se transcrit ainsi, note pour note. Si vous ne lisez pas la musique, trouvez simplement les notes à utiliser. 🤓📚 Mais apprendre à lire la musique est une compétence utile, et vous n'avez pas besoin d'être expert — juste assez pour identifier les notes pour les transposer sur Arduino ! 🤓📚
// Joyeux Anniversaire
Note melody[] = {
{NOTE_G6, DOTTED(NOTE_EIGHTH)}, {NOTE_G6, NOTE_SIXTEENTH},
{NOTE_A6, NOTE_QUARTER}, {NOTE_G6, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER}, {NOTE_B6, NOTE_HALF},
{NOTE_G6, DOTTED(NOTE_EIGHTH)}, {NOTE_G6, NOTE_SIXTEENTH},
{NOTE_A6, NOTE_QUARTER}, {NOTE_G6, NOTE_QUARTER},
{NOTE_D7, NOTE_QUARTER}, {NOTE_C7, NOTE_HALF},
{NOTE_G6, DOTTED(NOTE_EIGHTH)}, {NOTE_G6, NOTE_SIXTEENTH},
{NOTE_E7, NOTE_QUARTER}, {NOTE_D7, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER}, {NOTE_B6, NOTE_QUARTER},
{NOTE_A6, NOTE_HALF}, {NOTE_F7, DOTTED(NOTE_EIGHTH)},
{NOTE_F7, NOTE_SIXTEENTH}, {NOTE_E7, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER}, {NOTE_D7, NOTE_QUARTER},
{NOTE_C7, NOTE_HALF}
};
Notez (jeu de mots !) que je n'ai utilisé aucune durée absolue, seulement des durées relatives : notes entières, quarts, huitièmes, seizièmes, etc. J'ai même une macro DOTTED() pour les notes pointées (1,5 × la durée de la note précédente).
Une mélodie comprend ce tableau, plus l'information sur la durée réelle d'une note entière :
typedef struct Melody {
Note *notes;
int numNotes;
int wholeNoteDurationMs;
} Melody;
Comme les tableaux C ne peuvent pas être dimensionnés via un pointeur, j'ajoute numNotes comme taille du tableau Note. Cela s'initialise facilement avec la macro MELODY_LENGTH — pas besoin de compter les notes pendant la transcription !
Je définis ensuite un tableau de telles Melody pour mon programme :
Melody melodies[] = {
{melody, MELODY_LENGTH(melody), 1250},
{melody3, MELODY_LENGTH(melody3), 1000},
{melody4, MELODY_LENGTH(melody4), 1000}
};
Dans la boucle, au démarrage du décompte et de la musique, j'utilise les infos des notes, durées relatives, et durée réelle de la note entière pour jouer la musique. Entre les notes, je vérifie et mets à jour le décompte et l'afficheur 7 segments.
Comme je suppose qu'on veut finir d'écouter le jingle entier, je continue de le jouer jusqu'à la fin, même si les 20 secondes sont écoulées (le décompte devient négatif jusqu'à la fin de la chanson). Une fois le jingle fini, il s'arrête jusqu'à un nouveau déclenchement par la main devant le capteur. Si le jingle est trop court, il rejoue en boucle jusqu'à ce que 20 secondes se soient écoulées ET que la musique soit finie ! Simple.
if (startMusic) {
Melody mel = melodies[melodyNum];
Note *m = mel.notes;
int mSize = mel.numNotes;
int speedUp = 1;
noTone(TONE_PIN);
for (int thisNote = 0; thisNote < mSize; thisNote++) {
int noteDuration = mel.wholeNoteDurationMs * m[thisNote].duration / speedUp;
unsigned long noteTime = millis();
tone(TONE_PIN, m[thisNote].frequency, noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
unsigned long nowTime = millis();
countDown = 20 - (int)((nowTime - currentTime) / 1000);
// Regarde maman, pas de delay() !
while (millis() - noteTime <= pauseBetweenNotes) {
countDown = 20 - (int)((millis() - currentTime) / 1000);
matrix.print(countDown);
matrix.writeDisplay();
delay(10);
}
noTone(TONE_PIN);
matrix.print(countDown);
matrix.writeDisplay();
}
}
Le code complet est sur GitHub (lien inclus). Je recommande de le récupérer là-bas plutôt que de copier-coller depuis ici.
Aller plus loin avec le projet
Une fois à l'aise avec l'exemple de code, voici quelques idées pour l'étendre :
1) Trouvez votre air préféré et transcrivez-le avec les macros NOTE et duration décrites. Pensez à commenter un ou plusieurs jingles existants pour économiser la mémoire (sauf si vous déplacez les tableaux Note et Melody en PROGMEM comme décrit ci-dessous ! 😊)
2) Les mélodies occupent de la SRAM et peuvent vite la saturer. Par exemple, 4 mélodies (Joyeux Anniversaire, Do-Ré-Mi, We Will Rock You, Jeopardy) poussaient l'utilisation SRAM à 96%, ne laissant pas assez pour la bibliothèque de l'afficheur 7 segments qui ne mettait plus à jour correctement ! J'ai dû exclure une mélodie du tableau pour que tout fonctionne.
L'Arduino Uno a 2 Ko de SRAM, mais 32 Ko de Flash (où réside le programme). Si vous déplacez certaines variables globales en Flash, vous libérez de la SRAM ET avez plus d'espace pour stocker plus de chansons ! Essayez de définir les tableaux Note et Melody en PROGMEM. Note : c'est une démarche avancée et non triviale. Vous reléguez le tableau de structures en PROGMEM et devez lire la PROGMEM pour accéder aux données.
Pour donner un ordre d'idée : ce programme (avec 3 mélodies) occupait 31% de l'espace programme et 76% de la mémoire dynamique sur un Uno. Avec les variables en PROGMEM : 32% d'espace programme (légère augmentation, plenty de Flash dispo) et seulement 22% de mémoire dynamique (contre 76%) ! Vous pouvez ajouter beaucoup de chansons à ce Minuteur Musical Sans Contact une fois en PROGMEM ! 😊
Pouvez-vous imaginer d'autres extensions ? Partagez-les ci-dessous ! 😊
Bon making ! 😊
Code
ProtoStax Touchless Musical Handwash Timer Demo
https://github.com/protostax/ProtoStax_Touchless_Musical_Handwash_Timer
Schémas
Schéma du circuit pour le minuteur de lavage des mains musical sans contact :

Processus de fabrication
- Construire un Spybot Arduino piloté par Bluetooth
- FlickMote : Télécommande IR à gestes pour maison connectée
- TV-B-Gone DIY Arduino : Télécommande universelle pour toutes les TV
- Comprendre le Watchdog Timer : Comment il empêche les blocages du microcontrôleur
- Construire une horloge maître LED personnalisée avec alarme – Visible à 12 mètres
- Find Me : Localisateur d'objets intelligent avec Arduino et Bluetooth
- Solutions d'alimentation optimisées pour projets Arduino
- Morpion sur matrice LED MAX7219 avec boîtier en carton
- Meilleures pratiques éprouvées pour l'inspection des stations de lavage des mains