Atelier informatique  

Atelier

Arduino

Découvrez la programmation physique avec des capteurs, LEDs et afficheurs LCD. Du code C++ au monde réel.

Pour les ateliers qui vous seront proposés ci-dessous, vous allez avoir besoin de l’interface Arduino (Arduino IDE), interface qui permet de coder et de communiquer avec le matériel. Pour télécharger cette interface, allez sur ce site, cliquez sur « Download » et suivez les instructions d’installation qui vous sont données.

 

				
					#include <Wire.h>
#include "rgb_lcd.h"
 
// Connecter détecteur sur A0, LED sur D8
#define SOUND_PIN A0
#define LED_PIN 8
 
const int noiseFloor = 50;
const int maxSignal = 600;
 
void loop() {
 float dB = map(soundValue,
 noiseFloor, maxSignal, 0, 100);
 if (dB > 50) {
    digitalWrite(LED_PIN, HIGH);
    lcd.setRGB(255, 0, 0); // rouge
 }
 delay(100);
}
				
			
  // 01 - Concepts clés   

LES BASES DU CODE

01

LES BOUCLES

Les boucles permettent de répéter une action indéfiniment ou un certain nombre de fois. Dans Arduino, la fonction void loop() est une boucle infinie qui s’exécute tant que la carte est alimentée. La boucle for est utilisée pour exécuter un bloc de code un nombre défini de fois avec un compteur.

02

LES FONCTIONS

Une fonction est comme une mini-recette de cuisine au sein de notre grand programme. Elle regroupe plusieurs instructions sous un seul nom. Arduino impose au moins void setup() (qui s’exécute une seule fois au démarrage) et void loop(). Vous pouvez créer vos propres fonctions pour clarifier le code.

03

Les Évènements

Contrairement à Scratch, Arduino ne réagit pas nativement à « quand on clique ». On doit vérifier en permanence l’état des capteurs dans le loop en utilisant des conditions if ou else.Ce principe s’appelle du polling.

04

digitalWrite

digitalWrite(PIN, ETAT) est la commande de base pour contrôler les composants externes. PIN est le numéro du port, et ETAT peut être HIGH (allumé, 5 Volts envoyés) ou LOW (éteint, 0 Volt).

05

analogRead

analogRead(PIN) sert à lire une intensité variable (lumière, température…), contrairement au numérique qui n’est que ON/OFF. Il renvoie un chiffre de 0 à 1023 proportionnel à la tension reçue sur la broche analogique. On l’utilise souvent avec la fonction map().

06

Bibliothèques

Les bibliothèques contiennent du code préécrit par la communauté. Au lieu d’écrire 500 lignes pour communiquer avec un capteur complexe (comme un écran LCD), vous l’incluez avec  #include, ce qui vous donne accès à des fonctions simples comme lcd.print().

NoteLa bibliothèque HUSKYLENSArduino ne peut pas être trouvée ou téléchargée directement depuis le gestionnaire de bibliothèques de l’IDE Arduino. Vous pouvez la télécharger depuis la page GitHub officielle.

Tutoriel YouTube : How to Add Library in Arduino IDE

  // 02 - Matériel  

CONTENU DU KIT

x1

ARDUINO

Microcontrôleur programmable qui lit les entrées (capteurs) et contrôle les sorties (LEDs, écrans). C’est le cerveau de notre project.

x2

Afficheur LCD 12C

Écran à cristaux liquides pour afficher du texte et des données en temps réel. I2C signifie qu’il n’utilise que 4 fils pour communiquer.

x4

LED

Composant qui émet de la lumière quand du courant le traverse. Attention à la polarité (la patte longue sur le +).

x1

Télémètre Ultrasons

Capteur qui émet un ultrason et écoute son écho pour calculer la distance d’un objet en fonction du temps mis par le son pour revenir.

x1

Détecteur de Bruit

Capteur analogique qui convertit le volume sonore de la pièce en un signal électrique mesurable par l’Arduino.

x3

Bloc d’alimentation

Permet d’alimenter la carte Arduino directement sur une prise secteur sans avoir besoin de la brancher au PC.

x3

Câble imprimante

Câble USB utilisé pour téléverser notre code depuis le logiciel vers la carte Arduino.

x8

Fils de branchement

Câbles (Dupont) essentiels pour relier tous les composants à la carte Arduino sans soudure.

x2

Caméra IA HuskyLens

Une caméra dotée d’intelligence artificielle capable de reconnaître les objets et les gestes, ce qui la rend idéale pour les projects interactifs et l’automatisation.

x1

Capteur d’humidité

Capteur conçu pour mesurer le taux d’humidité des sols et des surfaces solides, idéal pour les projects horticoles, la surveillance environnementale ou pour des applications créatives dans divers secteurs.

  // 03 - Niveaux de difficulté  

PROGRESSEZ À VOTRE RYTHME

Le code est correct mais incomplet. Vous devez le compléter en suivant les instructions pour obtenir le comportement attendu.


 1  Comprendre la structure générale du code fourni

 2  Remplir les parties manquantes avec la bonne logique

 3  Vérifier (✓) puis téléverser (→) dans l’IDE Arduino

 4  Tester et ajuster les paramètres si besoin
Le code fourni contient des erreurs intentionnelles. À vous de les repérer et les corriger pour que le programme fonctionne.

 1  Lire le code fourni avec les commentaires étape par étape

 2  Identifier les erreurs de syntaxe ou de logique

 3  Corriger et téléverser vers l’Arduino

 4  Observer le résultat physique sur le montage
Veuillez analyser les commentaires TODO dans la structure de code fournie pour comprendre les exigences attendues, puis complétez l’implémentation en conséquence.

 1  Comprendre la structure globale du code fourni

 2  Lire les commentaires TODO et écrire la logique du code pour implémenter le comportement attendu

 3  Appliquer des améliorations et téléverser sur Arduino

 4  Tester et ajuster les paramètres si nécessaire
  // 04 - Mise en pratique  

ATELIERS GUIDÉS

1 heure – Comprendre les bases du code avec les boucles. Faire clignoter deux LED en alternance avec un délai précis.
 #Sortie-LED   #GPIO-Numérique   #Délai-Temporisation 
Matériel
  • Arduino x1
  • LED x2
  • Jumper Wires x2
  • Câble imprimante x1
Settings
  • LED 1 (Red): (+) -> Pin D8
  • LED 2 (Green): (+) -> Pin D7
  • GND (Ground): Tous -> GND Pin

Le code ci-dessous contient des erreurs intentionnelles. Lis chaque étape, corrige les erreurs et téléverse le programme dans l’IDE Arduino.

  • 1En vous basant sur le câblage effectué lors de la préparation, corrigez les erreurs dans le code ci-dessous.
  • 2Vérifiez (✓) et téléversez (→) le code dans l’IDE Arduino.
  • 3Test : les deux LED doivent clignoter alternativement toutes les 0,2 seconde.
				
					//Etape 1 : Sortir le Matos

//Etape 2 : Nous allons donner l'information que led1
//est branché sur D8 et que led2 est branché sur D7

8 led1 = int;          // ← à replacer dans l'ordre
led2 int = 7;          // ← à replacer dans l'ordre

//Etape 3 : Nous allons écrire dans void setup dire
//que led 1 et 2 soit en fonction
void setup() {
  // On branche LED 1 et 2 sur D8, D7
  OUTPUT (led1, pinMode);     // ← inverser les arguments
  led2 (pinMode, OUTPUT);     // ← corriger la syntaxe
}

//Etape 4 : Dans un premier temps dans void loop nous
//allons dire que la led1 s'allume mais pas la led2
//pendant un délai de 0.2 seconde
void loop() {
  // LED 1 allumée, LED 2 éteinte
  digitalWrite(led1, HIGH);
  digitalWrite(LOW, led2);    // ← inverser les arguments
  200(delay);              // ← corriger la syntaxe

//Etape 5 : Maintenant nous allons allumer led2 et éteindre led1
  // LED 1 éteinte, LED 2 allumée
  LOW(led1, digitalWrite);   // ← corriger la syntaxe
  led2(digitalWrite, HIGH); // ← corriger la syntaxe
  (delay)200;              // ← corriger la syntaxe
}

//Etape 6 : Si tout a été bien placé il n'y aura pas d'erreur
//et vous aurez le bon résultat
				
			
Solution
				
					//Etape 1 : Sortir le Matos

//Etape 2 : Nous allons donner l'information que led1
//est branché sur D8 et que led2 est branché sur D7

int led1 = 8;
int led2 = 7;

//Etape 3 : Nous allons écrire dans void setup dire
//que led 1 et 2 soit en fonction
void setup() {
  // On branche LED 1 et 2 sur D8, D7
   pinMode(led1, OUTPUT);    
   pinMode(led2, OUTPUT);
}

//Etape 4 : Dans un premier temps dans void loop nous
//allons dire que la led1 s'allume mais pas la led2
//pendant un délai de 0.2 seconde
void loop() {
  // LED 1 allumée, LED 2 éteinte
  digitalWrite(led1, HIGH);
  digitalWrite(led2, LOW);
  delay(200);  

//Etape 5 : Maintenant nous allons allumer led2 et éteindre led1
  // LED 1 éteinte, LED 2 allumée
  digitalWrite(led1, LOW);   
  digitalWrite(led2, HIGH); 
  delay(200);   
}

//Etape 6 : Si tout a été bien placé il n'y aura pas d'erreur
//et vous aurez le bon résultat
				
			
Concept

Au lieu d’utiliser directement des numéros bruts (comme la broche 7 ou 8) dans le code, nous attribuons des noms explicites à l’aide de variables. Cela rend le code organisé et facile à modifier.

Les microcontrôleurs pilotent le matériel à l’aide de signaux numériques. L’état HIGH envoie du courant pour allumer un composant, tandis que l’état LOW coupe le courant pour l’éteindre.

L’Arduino exécute le code ligne par ligne, de manière séquentielle. La fonction delay(1000) met le processeur en pause ; le microcontrôleur est donc « figé « pendant ce laps de temps.

Aperçu rapide

What will happen when »delay(1000) » are removed? 
The delay(1000) function is used to pause the execution of the program for 1000 milliseconds (1 second).

How to modify the code to make it a traffic light?
You can use multiple LEDs and modify the timing of the delay function to simulate traffic light behavior.

3 heures – Mesurer le niveau d’effort physique via la sudation. Si la valeur dépasse 60%, la zone dorée est atteinte, et si elle dépasse 75%, une LED rouge s’allume en avertissement.
 #Capteur   #MappageDonnées   #SeuilAlerte 
 

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Capteur d’humidité x1
  • LED x2
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • VCC (+): Tous -> VCC Pin
  • GND (-): Tous -> GND Pin
  • Capteur d’humidité: SIG to Pin A0
  • Afficheur LCD 12C: SDA -> SDA; SCL to SCL

Le code est presque correct, mais incomplet et désordonné. Remettez les éléments dans le bon ordre et complétez les parties manquantes pour afficher la vitesse sur l’écran LCD.

  • 1En vous basant sur le câblage effectué lors de la préparation, corrigez les erreurs (4 erreurs) dans le code ci-dessous.
  • 2Vérifiez (✓) et téléversez (→) le code dans l’IDE Arduino.
  • 3Tester : faire du bruit — la LED et l’écran doivent passer au rouge.
				
					
#include "rgb_lcd.h"

rgb_lcd lcd;
const int SENSOR_PIN = "A0";  // ←'const int' ne peut pas se voir attribuer une valeur de chaîne ( "A0" → A0 )

void setup() {
    lcd.begin(); // ← paramètre manquant ( → "begin(16, 2)")
    lcd.setRGB(100, 100, 100); 
}

void loop() {
    int raw_val = analogRead(SENSOR_PIN);
    int percent = map(raw_val, 0, 1023, 0, 100);
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Entraînement : "); lcd.print(percent); lcd.print("%");
    lcd.setCursor(0, 1);

    else if (percent < 25) {  // ← instruction de condition incorrecte ('else if' → 'if')
      lcd.setRGB(100, 100, 100); 
      lcd.print("[ Continuez à bouger ! ]"); 
    } else if (percent < 55){
      lcd.setRGB(255, 150, 0);   
      lcd.print("[ Échauffement... ]"); 
    } else if (percent < 75){
      lcd.setRGB(0, 255, 0);     
      lcd.print("[ ZONE D'OR ! ]"); 
    } else{
      lcd.setRGB(255, 0, 0);     
      lcd.print("[ SUR-EXERCICE ! ]"); 
    }
    delay(400)  // ← point-virgule manquant (→ ;)
}
 
				
			
Solution
				
					
#include "rgb_lcd.h"

rgb_lcd lcd;
const int SENSOR_PIN = A0;

void setup() {
    lcd.begin(16, 2);
    lcd.setRGB(100, 100, 100); 
}

void loop() {
    int raw_val = analogRead(SENSOR_PIN);
    int percent = map(raw_val, 0, 1023, 0, 100);
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Entraînement : "); lcd.print(percent); lcd.print("%");
    lcd.setCursor(0, 1);

    if (percent < 25) {
      lcd.setRGB(100, 100, 100); 
      lcd.print("[ Continuez à bouger ! ]"); 
    } else if (percent < 55){
      lcd.setRGB(255, 150, 0);   
      lcd.print("[ Échauffement... ]"); 
    } else if (percent < 75){
      lcd.setRGB(0, 255, 0);     
      lcd.print("[ ZONE D'OR ! ]"); 
    } else{
      lcd.setRGB(255, 0, 0);     
      lcd.print("[ SUR-EXERCICE ! ]"); 
    }
    delay(400); 
}
 
				
			
Concept

Contrairement aux broches numériques (0 ou 1), analogRead() capte des tensions continues issues du monde physique et les convertit en une valeur numérique allant de 0 à 1023.

La fonction map() permet de convertir une valeur d’une plage à une autre. Ici, elle transforme mathématiquement les données brutes du capteur (0-1023) en un pourcentage plus lisible (0-100 %).

Le code agit comme un moteur de décision. En divisant les pourcentages en différents seuils à l’aide de la structure if-else, le système modifie dynamiquement le texte de l’écran LCD ainsi que la couleur de son rétroéclairage pour fournir un retour visuel immédiat.

Aperçu rapide

Quel type de capteur physique peut-on connecter à la broche A0 pour faire fonctionner ce « moniteur d’entraînement « en conditions réelles ?
Réfléchissez aux données corporelles ou environnementales qui varient lorsque nous faisons de l’exercice.


Si la valeur lue par le capteur oscille légèrement au niveau du seuil, le rétroéclairage et le texte de l’écran LCD risquent de clignoter rapidement. Comment peut-on éviter ce phénomène ?
Envisagez les méthodes permettant de stabiliser l’affichage lorsque les valeurs se situent à la limite entre deux seuils.

1 heure – Utiliser un télémètre à ultrasons pour mesurer la distance et afficher le résultat sur l’écran LCD en cm.

 #Capteur   #Télémètre   #Ultrasons 
 

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Télémètre Ultrasons x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Télémètre Ultrasons: SIG -> Pin D8
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Le code est presque correct mais incomplet et désordonné. Remets les éléments dans le bon ordre et complète les parties manquantes pour afficher la distance sur l’écran LCD.

  • 1
    Sortir le matériel : Arduino, télémètre ultrasons, écran LCD, fils.
  • 2Brancher le télémètre sur D7 et l’écran LCD sur I2C.
  • 3Corriger les erreurs dans le code (7 erreurs), vérifier (✓) et téléverser (→).
				
					
// Etape 1 : Sortir le Matos

// Etape 2 : Mettre les bibliothèques du télémètre
// ultrasons ainsi que l'afficheur lcd
"Ultrasonic.h" #include        // ← remettre dans l'ordre
#include "rgb_lcd.h"

rgb_lcd lcd;

// Etape 3 : Broche du capteur ultrasons D7
const int ultrasonicPin = 7;

long duration;
int distance;

// Etape 4 : Dans le void setup mettre en route l'écran
// puis initialiser le télémètre
void setup() {
  lcd.begin(16, 2);

  //Couleur rétroéclairage (R, G, B)
  lcd.setRGB(0, 34000, 0);         // ← valeur invalide (→ 255)

  lcd.setCursor(0, 1);
  lcd.print("Distance:");

  // Etape 5 : Initialiser le télémètre
  UltrasonicPin, (pinMode);      // ← corriger la syntaxe
}

void loop() {
  // Envoi impulsion ultrason
  pinMode(ultrasonicPin, OUTPUT);
  digitalWrite(ultrasonicPin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultrasonicPin, HIGH);
  delayMicroseconds(10); digitalWrite(ultrasonicPin, LOW); //  ← ',' → ';'

  // Lecture echo
  pinMode(INPUT, ultrasonicPin);  // ← inverser les arguments
  duration = pulseIn(ultrasonicPin, HIGH); // ← corriger la syntaxe

  // Calcul distance en cm
  distance = duration / 2 / 29;

  // Affichage LCD
  lcd.setCursor(1, 0);             // ← inverser les arguments
  print.lcd("        ");           // ← corriger la syntaxe
  lcd.setCursor(0, 1);
  lcd.print(distance); 
  lcd.print(" cm");

  delay().500;                    // ← corriger la syntaxe
}
				
			
Solution
				
					#include "Ultrasonic.h"
#include "rgb_lcd.h"
rgb_lcd lcd;

// Broche du capteur ultrasons D7
const int ultrasonicPin = 7;
long duration;
int distance;

void setup() {
  lcd.begin(16, 2);
  // Couleur (R, G, B)
  lcd.setRGB(0, 255, 0); // vert
  lcd.setCursor(0, 0);
  lcd.print("Distance:");
  pinMode(ultrasonicPin, OUTPUT);
}

void loop() {
  // Envoi impulsion ultrason
  pinMode(ultrasonicPin, OUTPUT);
  digitalWrite(ultrasonicPin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultrasonicPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(ultrasonicPin, LOW);

  // Lecture echo
  pinMode(ultrasonicPin, INPUT);
  duration = pulseIn(ultrasonicPin, HIGH);

  // Calcul distance en cm
  distance = duration / 29 / 2;

  // Affichage LCD
  lcd.setCursor(0, 1);
  lcd.print("        "); // efface ligne
  lcd.setCursor(0, 1);
  lcd.print(distance);
  lcd.print(" cm");

  delay(500);
}
				
			
Concept

Le capteur ne possède pas de notion intrinsèque de distance. Il se contente d’enregistrer le temps d’aller-retour en microsecondes (durée). La formule / 29 / 2 utilise la vitesse du son et divise le résultat par 2 pour convertir cette durée brute en une distance physique.

Ce projet repose sur une astuce matérielle utilisant une seule broche. Il modifie dynamiquement le rôle de la broche `ultrasonicPin` : elle est configurée en sortie (OUTPUT) pour émettre l’impulsion, puis basculée quelques instants plus tard en entrée (INPUT) pour capter l’écho, illustrant ainsi une communication semi-duplex.

Aperçu rapide

Ce capteur est très précis face à des murs en béton. Toutefois, s’il est dirigé vers une personne portant un pull en laine épais et duveteux, la distance calculée restera-t-elle fiable ? Pourquoi ?
Les studios d’enregistrement utilisent généralement de la mousse poreuse ou des éponges comme matériaux d’isolation acoustique.


Comment modifier le code pour afficher la distance en pouces au lieu de centimètres ?
Les centimètres et les pouces sont des unités de distance interchangeables (1 pouce = 2,54 cm).

3 heures – Mesurer le niveau sonore de la pièce. Si le son dépasse 50 dB, la LED rouge s’allume et l’écran vire au rouge

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Détecteur de Bruit x1
  • LED x1
  • Jumper Wires x3
  • Câble imprimante x1

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Détecteur de Bruit : SIG -> A0;
  • LED : (+) -> D3;
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Le code contient des erreurs intentionnelles. Trouve-les, corrige-les et téléverse — la LED et l’écran doivent réagir au bruit en temps réel.

  • 1Lis le code ligne par ligne avec les commentaires.
  • 2Identifie les erreurs de syntaxe et de logique (4 erreurs à trouver).
  • 3Corrige et téléverse vers l’Arduino.
  • 4Observe : faire du bruit → LED rouge + écran rouge ; silence → LED éteinte + écran vert.
				
					
#include <Wire.h>
#include "rgb_lcd.h"

#define SOUND_PIN A0
#define LED_PIN 9    

rgb_lcd lcd;

const int noiseFloor = 50;
const int maxSignal = 600;

void setup() {
  lcd.begin(16,2);
  pinMode(LED_PIN, INPUT);
  lcd.setRGB(0, 255, 0);
  lcd.setCursor(0, 0);
  lcd.print("Detecteur bruit");
}

void loop() {
  int soundValue = analogRead(SOUND_PIN);

  float dB = map(soundValue, noiseFloor,
                  maxSignal, 100, 0);
  // Affichage temps réel
  lcd.setCursor(0, 1);
  lcd.print("Niveau: ");
  lcd.print(dB, 1);
  lcd.print(" dB ");
  // LED si > 50 dB
  if (dB > 50) {
    digitalWrite(LED_PIN, HIGH);
    lcd.setRGB(255, 0, 0);
  } else {
    digitalWrite(LED_PIN, LOW);
    lcd.setRGB(0, 255, 0);
  }

  delay(100); 
}
				
			

Veuillez vérifier si les broches sont correctement attribuées ou non.

 

Même avec la bonne broche, la LED est très faible car son mode est incorrect. Changez-le en mode « output » dans setup().

Le système fonctionne à l’envers : plus la pièce est silencieuse, plus les valeurs de dB augmentent. Vérifiez l’ordre des sorties dans la fonction map().

 

Quand la pièce est parfaitement calme, l’écran affiche des dB négatifs impossibles. Utilisez une fonction pour limiter les valeurs entre 0 et 100.

 

Solution
				
					#include <Wire.h>
#include "rgb_lcd.h"

// Connecter l'afficheur au I2C, le Détecteur
// sur A0, et la LED sur D8
#define SOUND_PIN A0
#define LED_PIN 3

rgb_lcd lcd;

const int noiseFloor = 50; // bruit ambiant
const int maxSignal = 600;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  lcd.begin(16, 2);
  // rétroéclairage vert
  lcd.setRGB(0, 255, 0);
  lcd.setCursor(0, 0);
  lcd.print("Detecteur bruit");
}

void loop() {
  int soundValue = analogRead(SOUND_PIN);

  // Conversion approximative en dB
  float dB = map(soundValue, noiseFloor,
                  maxSignal, 0, 100);
  dB = constrain(dB, 0, 100);

  // Affichage temps réel
  lcd.setCursor(0, 1);
  lcd.print("Niveau: ");
  lcd.print(dB, 1);
  lcd.print(" dB ");

  // LED si > 50 dB
  if (dB > 50) {
    digitalWrite(LED_PIN, HIGH);
    lcd.setRGB(255, 0, 0); // rouge si bruit
  } else {
    digitalWrite(LED_PIN, LOW);
    lcd.setRGB(0, 255, 0); // vert sinon
  }

  delay(100);
}
				
			
Concept

#define et const permettent tous deux de stocker des données immuables. #define est une macro de remplacement de texte du préprocesseur qui économise de la mémoire, tandis que const int est une variable en lecture seule, typée de manière sûre et allouée dans un emplacement mémoire spécifique.

constrain(val, min, max) est une mesure de sécurité pour les données. Elle force toute valeur d’entrée à rester strictement dans les limites inférieure et supérieure définies, en écrêtant tout pic dépassant ces bornes.

Serial.print(val, format) contrôle la précision d’affichage des nombres à virgule flottante (float). Elle remplace l’affichage par défaut à deux décimales en forçant le compilateur à afficher exactement N décimales (par ex. (dB, 1)).

Aperçu rapide

Si nous déployons ce système dans une bibliothèque calme plutôt que dans une usine bruyante, quelles lignes de code doivent être modifiées et comment ?
The background noise level (noiseFloor) and the maximum signal level of a library is different than that of a factory.

Un claquement sec fait clignoter la LED pendant une fraction de seconde seulement. Comment modifier notre code pour conserver et afficher cette valeur plus longtemps ?
Consider the way(s) we can track and hold a peak value over time, and what are their differences?

3 heures – Mesurez la vitesse d’un objet en approche. L’écran LCD devient rouge et affiche sa vitesse.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Télémètre Ultrasons x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Détecteur de Bruit : SIG -> A0;
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Le code ci-dessous contient des erreurs intentionnelles. Repérez-les toutes, corrigez-les, puis téléchargez le code : la vitesse devrait s’afficher en m/s sur l’écran LCD.

  • 1Lis le code ligne par ligne avec les commentaires.
  • 2Identifier les erreurs de syntaxe et de logique (5 erreurs à trouver).
  • 3Corriger et téléverser vers l’Arduino.
  • 4Observer la vitesse affichée sur l’écran LCD.
				
					
#include "Ultrasonic.h"
#include "rgb_lcd.h"

const unsigned long scanInterval = 40; // Définir le temps d'échantillonnage (40 ms)
const int ultrasonicPin = 9;

unsigned long lastScanTime = 0;
long d1 = 0;
long d2 = 0; 

rgb_lcd lcd;
Ultrasonic ultrasonic(ultrasonicPin);

void setup() {
  lcd.begin(2, 16);       
  lcd.setRGB(0, 255, 0);    //color(R,G,B)
  lcd.print("PRÊT POUR LE RADAR");
}

void loop() {
  unsigned long currentTime = millis();

  if (currentTime - lastScanTime >= scanInterval) {
    // Décaler la période et effacer les registres
    d1 = d2;           
    d2 = 0;
    
    long rawDistance = ultrasonic.MeasureInCentimeters(); // Envoyer une impulsion ultrasonique et lire l'écho
    if (rawDistance > 0 && rawDistance < 150) rawDistance = d2;

    lastScanTime = currentTime;

    if (d1 > 0 && d2 > 0) {
      long del_d = d1 - d2;

      if ( del_d < 0 && d1 <= 80) { 
        float speed_m_s = del_d * 4.0;  // Calculer la distance en cm
        // Affichage LCD
        if (speed_m_s > 0.10) {
          lcd.clear();
          lcd.setRGB(255, 0, 0);
          lcd.setCursor(0, 0);  lcd.print("VITESSE DÉTECTÉE !");
          lcd.setCursor(0, 1);  lcd.print("v = " + String(speed_m_s, 2) + " m/s");

          delay(3000);
          // Réinitialiser l'affichage LCD
          lcd.clear();
          lcd.setRGB(0, 255, 0);
          lcd.print("PRÊT POUR LE RADAR");
          d1 = 0;
          d2 = 0;
          lastScanTime = millis();
        }
      }
    }
  }
}
				
			

Verify your physical wiring on the shield. Is the sensor truly connected to the pin specified at the very top of the code?

 

Review the parameters passed into lcd.begin(). Are columns and rows placed in the correct order for a standard 16×2 character display?

Examine the statement inside the distance validation block. Remember the behavior of the = operator in C++: is the freshly measured sensor data actually being saved into your tracking variable, or is it being overwritten?

When an object approaches the radar, the distance gets shorter d_1 > d_2. Check if the inequality sign for del_d correctly filters this specific movement direction.

 

Review the arithmetic operator used to calculate speed_m_s. Based on the relationship between distance change del_d and the 40ms time window, should the delta value be multiplied or divided to get the correct speed in m/s?

Solution
				
					
#include "Ultrasonic.h"
#include "rgb_lcd.h"

const unsigned long scanInterval = 40; // Définir la durée d'échantillonnage (40 ms) 
const int ultrasonicPin = 7;           // Configurez la broche 7 pour le capteur à ultrasons

unsigned long lastScanTime = 0;
long d1 = 0;
long d2 = 0;

rgb_lcd lcd;
Ultrasonic ultrasonic(ultrasonicPin);

void setup() {
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0);   // couleur(R,G,B)
  lcd.print("PRÊT POUR LE RADAR");
}

void loop() {
  unsigned long currentTime = millis();

  if (currentTime - lastScanTime >= scanInterval) {
    // Décalage de la fenêtre temporelle et effacement des registres
    d1 = d2;
    d2 = 0;
    
    long rawDistance = ultrasonic.MeasureInCentimeters();  // Lecture de l'écho
    if (rawDistance > 0 && rawDistance < 150) d2 = rawDistance;

    lastScanTime = currentTime;

    if (d1 > 0 && d2 > 0) {
      long del_d = d1 - d2;            // Distance parcourue dans la fenêtre de 40 ms

      if (del_d > 0 && d1 <= 80) {
        float speed_m_s = del_d / 4.0;  // Calculer la distance en cm
        // Affichage LCD
        if (speed_m_s > 0.10) {
          lcd.clear();
          lcd.setRGB(255, 0, 0);
          lcd.setCursor(0, 0);  lcd.print("VITESSE DÉTECTÉE !");
          lcd.setCursor(0, 1);  lcd.print("v = " + String(speed_m_s, 2) + " m/s");

          delay(3000);         
          // Réinitialiser l'affichage LCD
          lcd.clear();
          lcd.setRGB(0, 255, 0);
          lcd.print("PRÊT POUR LE RADAR");
          d1 = 0;
          d2 = 0;
          lastScanTime = millis();
        }
      }
    }
  }
}
				
			
Concept

Au lieu d’utiliser delay(), qui fige le microcontrôleur, on peut utiliser millis() qui s’appuie sur l’horloge interne du microcontrôleur ; cela permet à la puce de rester active et d’exécuter d’autres tâches de manière fluide.

Cela crée un registre à décalage temporel via l’instruction d1 = d2; pour suivre les positions passée et actuelle. Dans une fenêtre de 40 ms, le programme applique un calcul cinématique via le raccourci del_d / 4.0 pour déduire instantanément la vitesse dynamique.

Aperçu rapide

Pourquoi l’intervalle d’échantillonnage du radar est-il fixé précisément à 40 ms plutôt qu’à une autre valeur (comme une valeur extrême de 1 ms ou une valeur très lente de 5000 ms) ?
L’impulsion acoustique nécessite un temps de trajet physique d’environ 9 ms pour effectuer l’aller-retour ; qu’en est-il du déplacement et du temps de réaction d’une voiture en mouvement ou d’un piéton ?

En réalité, un compteur de vitesse plus précis utilise deux capteurs. Comment les disposeriez-vous dans l’espace et en quoi le code différerait-il de celui que nous utilisons actuellement ?
Ces deux capteurs doivent-ils vraiment être placés juste à côté l’un de l’autre, ou peut-on les espacer davantage ?

3 heures – Décodez le nombre de visages en temps réel à l’aide d’un capteur de vision IA. L’écran LCD s’allumera en vert et changera de couleur selon le nombre de personnes détectées, tout en affichant les résultats du comptage.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Caméra IA HuskyLens x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • VCC (+) : -> VCC Pin
  • GND (-) : -> GND Pin
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL
  • Caméra IA HuskyLens :
    • Connexion série : TX -> D2; RX -> D3 (Baud: 9600)
    • Mode : Reconnaissance faciale

Le code ci-dessous contient des erreurs intentionnelles. Repérez-les toutes, corrigez-les, puis téléchargez le code : la vitesse devrait s’afficher en m/s sur l’écran LCD.

  • 1Lis le code ligne par ligne avec les commentaires.
  • 2Identifier les erreurs de syntaxe et de logique (5 erreurs à trouver).
  • 3Corriger et téléverser vers l’Arduino.
  • 4Observer le nombre de visages détectés affiché sur l’écran LCD.
				
					
#include <SoftwareSerial.h>
#include <Wire.h>
#include "HUSKYLENS.h"
#include "rgb_lcd.h"

SoftwareSerial mySerial(3, 2); 
HUSKYLENS huskylens;
rgb_lcd lcd;
int last_faces = 0;

void setup() {
    mySerial.begin(9600);   
    // Wire.begin();
    lcd.begin(16, 2);
    lcd.setRGB(0, 100, 200); 
    lcd.print("AI Face Counter"); 
    
    while (!huskylens.begin(mySerial)) {
      delay(500);  // Wait for HuskyLens to initialize
    }
}

void loop() {
    if (!huskylens.request()) return;  // Request the latest recognition data frame from HuskyLens
    int current_faces = huskylens.countBlocks();   // Get the number of detected face blocks

    if (current_faces == last_faces) { 
        if (current_faces == 0) lcd.setRGB(0, 50, 100);
        else lcd.setRGB(0, 255, 0);
        
        lcd.setCursor(0, 1);
        lcd.print("                ");
        lcd.setCursor(0, 1);
        lcd.print("Faces: " + String(current_faces) + " P"); 
        current_faces = last_faces; 
    }
    delay(50); 
}
 
				
			

Le format du constructeur est SoftwareSerial(RX, TX). Vérifiez si cela correspond aux connexions physiques sur votre platine d’essai.

Réfléchissez à ce qui se passe si aucune personne n’est détectée juste au démarrage. L’écran se mettra-t-il à jour ?

 

Vérifiez bien l’opérateur de comparaison dans l’instruction if clé. Cherche-t-on un changement ou une stabilité ?

N’oubliez pas que l’opérateur = en C++ affecte la valeur située à droite à l’opérande de gauche.

Voyez ce qui arrive à l’écran LCD si le câble de la caméra est soudainement débranché pendant le fonctionnement.

Solution
				
					
#include <SoftwareSerial.h>
#include <Wire.h>
#include "HUSKYLENS.h"
#include "rgb_lcd.h"

SoftwareSerial mySerial(2, 3); 
HUSKYLENS huskylens;
rgb_lcd lcd;
int last_faces = -1; 

void setup() {
    mySerial.begin(9600);   
    Wire.begin();
    lcd.begin(16, 2);
    lcd.setRGB(0, 100, 200); 
    lcd.print("AI Face Counter"); 
    while (!huskylens.begin(mySerial)) {
      delay(500);  // Wait for HuskyLens to initialize
    }
}

void loop() {
    if (!huskylens.request()) return;  // Request the latest recognition data frame from HuskyLens
    int current_faces = huskylens.countBlocks();   // Get the number of detected face blocks

    if (current_faces != last_faces) {
        if (current_faces == 0) lcd.setRGB(0, 50, 100);
        else lcd.setRGB(0, 255, 0);
        
        lcd.setCursor(0, 1);
        lcd.print("                ");
        lcd.setCursor(0, 1);
        lcd.print("Faces: " + String(current_faces) + " P"); 
        last_faces = current_faces; 
    }
    delay(50); 
}
 
				
			
Concept

SoftwareSerial() permet aux broches numériques standard d’imiter les ports série matériels dédiés TX/RX. Cela permet au microcontrôleur d’établir une ligne de données indépendante avec la caméra IA sans bloquer le port de programmation USB principal.

huskylens.request() agit comme un filtre pour le flux de données. L’utilisation d’un return immédiat en cas d’échec de la communication interrompt la boucle prématurément, évitant ainsi au processeur de gaspiller des cycles ou de planter face à un flux de données vide.

HuskyLens envoie des résumés numériques entièrement traités. L’Arduino n’effectue aucun traitement de vision par ordinateur ; il se contente de lire les résultats finaux calculés.

Aperçu rapide

Si HuskyLens confond des motifs (comme un visage imprimé sur un t-shirt) avec un véritable visage, quel paramètre du menu matériel de la caméra permet de corriger cela ?
Existe-t-il un réglage permettant de garantir que le ou les résultats finaux se situent dans une plage donnée ou dépassent une valeur attendue ?

Si le compteur fonctionne parfaitement sous un éclairage intense mais échoue dans des couloirs sombres ou en contre-jour, quel facteur réel perturbe le modèle d’IA et comment y remédier ?
Réfléchissez à la manière dont le capteur de la caméra gère la lumière ambiante et aux différences qui en découlent.

3 heures – Utilisez un Arduino et le moniteur série pour enregistrer et étiqueter les ID de la caméra IA HuskyLens. De nouveaux noms de tags apparaîtront alors en temps réel sur les blocs de l’écran de la caméra.

Matériel

  • Arduino x1
  • Caméra IA HuskyLens x1
  • Afficheur LCD 12C x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

Le code contient des erreurs intentionnelles. Trouvez-les, corrigez-les et téléversez — l’Arduino doit étiqueter les ID via le moniteur série et de nouveaux noms de tags doivent apparaître sur l’écran de la caméra en temps réel.

  • 1Lire le code ligne par ligne avec les commentaires.
  • 2Identifier les erreurs de syntaxe et de logique (5 erreurs à trouver).
  • 3Corriger et téléverser vers l’Arduino.
  • 4Observer le nom de la couleur détectée affiché sur l’écran LCD.
				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"

SoftwareSerial mySerial(2, 3); // RX = 2, TX = 3 (Connected to HuskyLens)
HUSKYLENS huskylens;

int currentID = 1; 
int TOTAL_IDS = 5; 

void printIDPrompt() {
    int currentID = 3;
    Serial.print("ID: " + String(currentID) + "/" + String(TOTAL_IDS));
    Serial.println(" -> Please enter name for ID " + String(currentID) + ": ");
    Serial.println("-----------------------------------------");
}

void setup() {
    Serial.begin(115200); // Channel A: PC to Arduino
    mySerial.begin(115200);
    
    while (!huskylens.begin(mySerial)) {
        delay(500); 
    }
    
    printIDPrompt(); 
}

void loop() {
    if (currentID != TOTAL_IDS) {
        if (Serial.available() > 0) {
            String newName = Serial.readStringUntil('\n');
            newName.trim();

            if (newName.length() > 0) {
                if (huskylens.setCustomName(newName, currentID)) {
                    Serial.println(">> Target saved: ID " + currentID + " is now [" + newName + "]");
                    currentID--; 
                } else Serial.println(">> ERROR: Failed to write to HuskyLens. Retrying...");
                
                if (currentID <= TOTAL_IDS) printIDPrompt(); 
                else Serial.println("SUCCESS: All IDs Labeled! System Fully Armed.");
            }
        }
    } else {
        if (!huskylens.request()) return;
        delay(50); 
    }
}
 
				
			

Vérifiez mySerial.begin(…) dans setup(). Cette vitesse correspond-elle à celle du menu matériel de la HuskyLens ?

Comparez avec la variable globale située en haut. Y a-t-il une variable locale qui masque la variable globale à l’intérieur de printIDPrompt() ?

Vérifiez if (currentID != TOTAL_IDS) dans loop(). Que se passe-t-il exactement au moment où la valeur atteint 5 ?

Observez currentID– après l’enregistrement. La caméra peut-elle accepter des nombres négatifs comme identifiants d’humain ?

En C++, « String » + currentID provoque un décalage de pointeur. Comment corriger cela en utilisant String() ?

Solution
				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"

SoftwareSerial mySerial(2, 3); // RX = 2, TX = 3 (Connected to HuskyLens)
HUSKYLENS huskylens;

int currentID = 1; 
int TOTAL_IDS = 5; 

void printIDPrompt() {
    Serial.print("ID: " + String(currentID) + "/" + String(TOTAL_IDS));
    Serial.println(" -> Please enter name for ID " + String(currentID) + ": ");
    Serial.println("-----------------------------------------");
}

void setup() {
    Serial.begin(115200); // Channel A: PC to Arduino
    mySerial.begin(9600);
    
    while (!huskylens.begin(mySerial)) {
        delay(500); 
    }
    
    printIDPrompt(); 
}

void loop() {
    if (currentID <= TOTAL_IDS) {
        if (Serial.available() > 0) {
            String newName = Serial.readStringUntil('\n');
            newName.trim();

            if (newName.length() > 0) {
                if (huskylens.setCustomName(newName, currentID)) {
                    Serial.println(">> Target saved: ID " + String(currentID) + " is now [" + newName + "]");
                    currentID++; 
                } else Serial.println(">> ERROR: Failed to write to HuskyLens. Retrying...");
                
                if (currentID <= TOTAL_IDS) printIDPrompt(); 
                else Serial.println("SUCCESS: All IDs Labeled! System Fully Armed.");
            }
        }
    } else {
        if (!huskylens.request()) return;
        delay(50); 
    }
}
 
				
			
Concept

Le Moniteur série sert de passerelle homme-machine. Il permet à la puce d’afficher des diagnostics en temps réel et de détecter les frappes au clavier, transformant ainsi un microcontrôleur « aveugle « en une console interactive.

La fonction setCustomName() représente l’étape clé de l’IA : l’étiquetage des données. Elle associe des caractéristiques physiques brutes (comme « Face ID 1 ») à un nom compréhensible par l’humain, permettant au système de fournir des données de suivi explicites.

La fonction trim() nettoie les données brutes saisies par l’utilisateur avant de les transmettre au système. En supprimant les caractères de contrôle non imprimables et les espaces accidentels, elle garantit que la puce d’IA ne stocke que des chaînes de texte valides et propres.

Aperçu rapide

Lorsque vous étiquetez un visage avec succès à l’aide de ce poste, où le nom personnalisé est-il réellement stocké de manière permanente : dans la mémoire de l’Arduino ou dans le matériel de la caméra IA ?
Si l’on éteint complètement le matériel HuskyLens puis qu’on le redémarre, les étiquettes et les noms mémorisés précédemment sont-ils conservés ou disparaissent-ils ?

Que se passera-t-il si vous alimentez ce système à l’aide d’une batterie externe sans le connecter à un ordinateur ?
Observez attentivement l’instruction if(Serial.available() > 0). Si aucun ordinateur n’est connecté pour envoyer des caractères, cette condition sera-t-elle jamais remplie ?

3 heures – Décodez les codes Morse internationaux en lettres et chiffres à l’aide d’un capteur de sons. L’écran LCD s’allumera en vert et affichera en temps réel votre vitesse de frappe ainsi que les résultats du décodage.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Détecteur de Bruit x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Détecteur de Bruit : SIG -> A0;
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Lisez les commentaires TODO, analysez le comportement attendu et implémentez le code pour vous assurer que l’écran LCD et le capteur de niveau sonore fonctionnent comme prévu.

				
					
#include <Wire.h>
#include "rgb_lcd.h"

#define SOUND_PIN A0

rgb_lcd lcd;

int WPM = 16;        
int soundlevel = 450; 
int dotTime = 1200 / WPM;         
int letterTimeout = dotTime * 5;  

String code = ""; 
unsigned long startTime = 0;
unsigned long pushTime = 0;
unsigned long lastTapTime = 0;
unsigned long lastSoundTime = 0; 
bool isPressing = false;

String morseTable[] = {
  ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---",   // A - J
  "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-",     // K - T  
  "..-", "...-", ".--", "-..-", "-.--", "--..",                            // U - Z  
  "-----", ".----", "..---", "...--", ".....", "-....", "--...", "---..", "----."  // 0 - 9  
};
char charTable[] = {
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
  'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};

int totalElements = 36;

void setup() {
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0); //vert
  lcd.clear();
}

void loop() {
  int sound = analogRead(SOUND_PIN);
  unsigned long now = millis();

  if (sound > soundlevel) {
    lastSoundTime = now; 
    if (!isPressing) {
      startTime = now;   
      isPressing = true;
    }
  }
  // Compensation temporelle pour la détection des soudures
  if (sound < soundlevel && isPressing) {
    if (now - lastSoundTime > (dotTime / 2)) {
      pushTime = lastSoundTime - startTime; 
      isPressing = false;
      lastTapTime = now;
      // TODO 1 : Utilisez "pushTime "et "dotTime "pour déterminer s'il s'agit d'un point (.) ou d'un trait (-). 
      // - Seuil du trait (-) : pushTime >= dotTime * 2 
      // - Seuil pour le point (.) : pushTime > 15 ms (pour filtrer le bruit)
      // - Ajouter les résultats à 'code' à l'aide de '+=' (par exemple, code += '-'';)
      
       /* ----- - ENTREZ VOTRE CODE ICI ------ */ 

      lcd.setCursor(0, 0);
      lcd.print(String(WPM) + "WPM      " + code + "     "); 
    }
  }
  // Vérification du délai d'attente des lettres
  if (code.length() > 0 && (now - lastTapTime > letterTimeout) && !isPressing) { 
    lcd.setCursor(0, 1);
    lcd.print("DÉCODAGE: "); 
    // À FAIRE 2 : Écrire une boucle "for "pour décoder "code "via "morseTable ».
    // - Boucle jusqu'à 'totalElements
    // - Si correspondance, affiche à partir de “charTable” à l'aide de lcd.print().
    // - Si non trouvé, affiche un espace vide " " pour effacer l'ancien caractère.
    
    /* ------ ENTREZ VOTRE CODE ICI ------ */
    
    code = ""; 
    lcd.setCursor(0, 0);
    lcd.print(String(WPM) + "WPM                "); // efface l'affichage du code
  }
}
 

				
			
Solution
				
					
#include <Wire.h>
#include "rgb_lcd.h"

#define SOUND_PIN A0

rgb_lcd lcd;

int WPM = 16;        
int soundlevel = 450; 
int dotTime = 1200 / WPM;         
int letterTimeout = dotTime * 5;  

String code = ""; 
unsigned long startTime = 0;
unsigned long pushTime = 0;
unsigned long lastTapTime = 0;
unsigned long lastSoundTime = 0; 
bool isPressing = false;

String morseTable[] = {
  ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---",   // A - J
  "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-",     // K - T  
  "..-", "...-", ".--", "-..-", "-.--", "--..",                            // U - Z  
  "-----", ".----", "..---", "...--", ".....", "-....", "--...", "---..", "----."  // 0 - 9  
};
char charTable[] = {
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
  'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};

int totalElements = 36;

void setup() {
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0); // vert 
  lcd.clear();
}

void loop() {
  int sound = analogRead(SOUND_PIN);
  unsigned long now = millis();

  if (sound > soundlevel) {
    lastSoundTime = now; 
    if (!isPressing) {
      startTime = now;   
      isPressing = true;
    }
  }
  // Jugement de soudure avec compensation de temporisation
  if (sound < soundlevel && isPressing) {
    if (now - lastSoundTime > (dotTime / 2)) {
      pushTime = lastSoundTime - startTime; 
      isPressing = false;
      lastTapTime = now;
      // Examen des notes longues et courtes
      if (pushTime >= (dotTime * 2)) {
        code += "-"; 
      } else if (pushTime > 15) { 
        code += "."; 
      }

      lcd.setCursor(0, 0);
      lcd.print(String(WPM) + "WPM      " + code + "     "); 
    }
  }
  // Vérification du délai d'expiration des lettres
  if (code.length() > 0 && (now - lastTapTime > letterTimeout) && !isPressing) { 
    lcd.setCursor(0, 1);
    lcd.print("DÉCODAGE: "); 
    // Recherche du caractère correspondant dans la table Morse
    bool found = false;
    for (int i = 0; i < totalElements; i++) {
      if (code == morseTable[i]) {
        lcd.print(charTable[i]); // Affichage du caractère décodé
        found = true;
        break; 
      }
    }
    // Effacement de la deuxième ligne si aucune correspondance n'est trouvée
    if (!found) {
      lcd.print(" ");
    }    
    lcd.print("      "); 
    
    code = ""; 
    lcd.setCursor(0, 0);
    lcd.print(String(WPM) + "WPM                "); // Effacement de l'affichage du code
  }
}
 
				
			
Concept

Transforme les ondes sonores analogiques irrégulières en bits nets (0 ou 1). En ignorant les fluctuations de tension inférieures au seuil sonore, le système élimine le bruit ambiant pour établir une base de référence fiable et insensible au bruit, idéale pour l’analyse temporelle.

Le code Morse impose des rapports temporels stricts (1:3), mais le matériel est sujet à la gigue (jitter). Le code utilise des marges de tolérance (comme dotTime / 2) pour combler les interruptions du signal et compenser les erreurs d’exécution physique.

Il remplace les branchements conditionnels complexes par des matrices alignées (morseTable[] et charTable[]). Cela permet à une boucle unique de faire correspondre instantanément clés et valeurs, réduisant ainsi la complexité algorithmique à l’exécution.

char[] alloue un bloc mémoire fixe et prévisible dès la compilation. À l’inverse, String manipule dynamiquement le tas (heap) à l’exécution, ce qui provoque facilement une fragmentation de la mémoire et des plantages système sur les microcontrôleurs.

Aperçu rapide

Si le bruit de fond de la pièce dépasse la valeur de votre filtre actuel (450), comment le programme réagira-t-il ?
Si le bruit de fond ne descend jamais en dessous de 450, l’ordinateur croira qu’une personne émet un sifflement continu.

Lorsqu’une personne tape beaucoup plus vite que la normale (par ex. 32 mots/minute), ses traits longs deviennent très courts.Quel sera le programme décodé ?
Lorsqu’on tape très vite, un trait long devient aussi court qu’un point normal.

Si vous émettez un sifflement très, très long pendant 10 secondes sans vous arrêter, le programme se fige-t-il en attendant que vous ayez fini, ou effectue-t-il discrètement d’autres tâches pendant que vous sifflez ?
La fonction millis() fonctionne comme un chronomètre en arrière-plan, tandis que delay() bloque la puce.

3 heures – Concevoir une horloge numérique sans dérive à l’aide de la fonction millis(). Implémenter une logique algorithmique pour gérer dynamiquement les contraintes liées aux mois non uniformes et aux années bissextiles sur l’écran LCD.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Jumper Wires x2

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Lire les commentaires TODO, analyser le comportement attendu et implémenter le code pour garantir le bon fonctionnement de l’écran LCD et de la logique du calendrier.

				
					
#include "rgb_lcd.h"

rgb_lcd lcd;

int date[3] = {2000, 2, 28}; // jour : aa,mm,jj
int time[3] = {23, 59, 50}; // heure : hh,mm,ss

unsigned long previousMillis = 0; 

int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

void printTwoDigits(int number) {
  if (number < 10) lcd.print("0");
  lcd.print(number);
}

void setup() {
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0); // rétroéclairage vert
}

void loop() {
  unsigned long currentMillis = millis();
  // utilisation de millis() pour la synchronisation
  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    // Mise à jour de la date et de l'heure
    time[2]++;
    if (time[2] == 60) {
      time[2] = 0;
      time[1]++;
      if (time[1] == 60) {
        time[1] = 0;
        time[0]++;
        if (time[0] == 24) {
          date[2]++;
          time[0] = time[1] = time[2] = 0;
        }
      }
    }
    // TODO1 : Validation de la date (gestion de la durée des mois, des années bissextiles, etc.)
    // - Lorsque l'heure atteint 23:59:59 et que le jour se répète, remettre l'heure à 0 et incrémenter le jour de 1.
    // - Règle des années bissextiles : une année est bissextile tous les 4 ans, sauf tous les 100 ans, mais une année est bissextile tous les 400 ans.
    // - Mettre à jour février à 29 jours s'il s'agit d'une année bissextile (sinon 28), puis gérer les incréments de mois et d'année en cas de dépassement du nombre de jours.

    /* ------ ENTREZ VOTRE CODE ICI ------ */

    // TODO2: Affichage LCD
    // - Utilisez 'lcd.setCursor()'' et insérez des espaces vides ' ' pour écraser et effacer sélectivement les anciens chiffres.
    // - Modifiez la mise en page de l'affichage de la date en remplaçant le tiret "-" par une barre oblique "/".
    // - Alignez et centrez le texte (date sur la ligne 0, heure sur la ligne 1) pour une interface utilisateur claire.

    /* ------ ENTREZ VOTRE CODE ICI ------ */
  }
}
 
				
			
Solution
				
					
#include "rgb_lcd.h"

rgb_lcd lcd;

int date[3] = {2000, 2, 28}; // jour : aa,mm,jj
int time[3] = {23, 59, 50}; // heure : hh,mm,ss

unsigned long previousMillis = 0; 

int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

void printTwoDigits(int number) {
  if (number < 10) lcd.print("0");
  lcd.print(number);
}

void setup() {
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0); // rétroéclairage vert
}

void loop() {
  unsigned long currentMillis = millis();
  // utilisation de millis() pour la synchronisation
  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    // Mise à jour de la date et de l'heure
    time[2]++;
    if (time[2] == 60) {
      time[2] = 0;
      time[1]++;
      if (time[1] == 60) {
        time[1] = 0;
        time[0]++;
        if (time[0] == 24) {
          date[2]++;
          time[0] = time[1] = time[2] = 0;
        }
      }
    }
    // Validation de la date (gestion des durées de mois, des années bissextiles, etc.)
    int year = date[0];
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
      daysInMonth[2] = 29;
    } else {
      daysInMonth[2] = 28; 
    }
    int currentMaxDays = daysInMonth[date[1]]; 
    if (date[2] > currentMaxDays) { date[1]++; date[2] = 1;}
    if (date[1] == 13) { date[0]++; date[1] = 1;}
    // Affichage LCD
    lcd.setCursor(3, 0);
    lcd.print(date[0]); lcd.print("/");
    printTwoDigits(date[1]); lcd.print("/");
    printTwoDigits(date[2]);

    lcd.setCursor(4, 1);
    printTwoDigits(time[0]); lcd.print(":");
    printTwoDigits(time[1]); lcd.print(":");
    printTwoDigits(time[2]);
  }
}
 
				
			
Concept

The program executes a modulo check year % 4 == 0 every second to actively re-write the value inside the daysInMonth[2] memory array, expanding or shrinking February’s deadline before the day overflow occurs.

When a smaller time unit hits its ceiling (60 -> 60 -> 24), the code forces it back to $0$ and triggers a ++ increment on the next larger unit, creating an upward-rippling chain reaction.

The code directly uses the numeric month variable date[1] as a hardware memory pointer to extract the maximum days from the daysInMonth[] array, replacing complex conditional branches with a direct lookup.

Aperçu rapide

What will happen if the program uses delay(1000) inside the loop instead of checking millis()?
When delay(1000) is running, the microcontroller completely « sleeps » for 1 second.

How does the code handle leap years in terms of February’s day count?
The code checks if the year is divisible by 4 to determine if it’s a leap year, adjusting February’s day count accordingly.

3 heures – Recréez le jeu Flappy Bird sur l’écran LCD. Le joueur contrôle un oiseau qui doit éviter des obstacles en appuyant sur un bouton. L’écran LCD affichera le score en temps réel et la LED s’allumera en rouge lorsque le joueur perd.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Jumper Wires x2
  • Câble imprimante x1
  • Capteur Ultrasonic x1

Settings

  • VCC (+) : Tous -> VCC Pin
  • GND (-) : Tous -> GND Pin
  • Télémètre Ultrasons: SIG -> Pin D8
  • Afficheur LCD 12C : SDA -> SDA; SCL -> SCL

Lire les commentaires TODO

				
					
#include "rgb_lcd.h"
#include "Ultrasonic.h"

rgb_lcd lcd;
Ultrasonic ultrasonic(8);

byte birdChar[8] = { B00100, B01110, B11111, B10101, B11111, B11111, B01010, B00000 };
byte pipeChar[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };
int pipeCol[2] = {15, 10};
int pipeRow[2] = {0, 1};

int birdRow = 0;
int score = 0;
bool gameOver = false;

void setup() {
  randomSeed(analogRead(A0));
  lcd.begin(16, 2);      
  lcd.setRGB(0, 255, 0);
  lcd.createChar(0, birdChar);
  lcd.createChar(1, pipeChar);
  
  pipeRow[0] = random(0, 2);
  pipeRow[1] = random(0, 2);
}

void loop() {
  if (gameOver) {
    handleGameOver();
    return;
  }

  long distance = ultrasonic.MeasureInCentimeters(); 
  // TODO1 : Contrôle de la position de l'oiseau et rafraîchissement de l'écran
  // - Contrôlez la position de l'oiseau en fonction de la distance mesurée par le capteur (1-15 cm : ligne du bas ; sinon : ligne du haut).
  // - Mettez à jour la position d'affichage de l'oiseau sur l'écran LCD à la colonne 2.
  // [Indice] : Vous pouvez utiliser la fonction lcd.write(0) pour afficher des icônes personnalisées sur l'écran LCD.

  /* WRITE YOUR CODE HERE */

  for (int i = 0; i < 2; i++) {
    // TODO2 : Déplacement de l'obstacle et détection de collision
    // - Déplacez l'obstacle vers la gauche. S'il sort de l'écran, replacez-le à droite, choisissez une ligne aléatoire et ajoutez 1 au score.
    // - Déclenchez la fin de partie (Game Over) si l'obstacle entre en collision avec l'oiseau à la colonne 2.
    // [Indice] : Une collision se produit lorsque l'oiseau et l'obstacle occupent exactement la même position au même moment (même colonne ET même ligne).

    /* WRITE YOUR CODE HERE */

    lcd.setCursor(pipeCol[i], pipeRow[i]);
    lcd.write((uint8_t) 1);
  }

  lcd.setCursor(14, 0); lcd.print(score);
  delay(220); 
}

void handleGameOver() {
  lcd.setRGB(255, 0, 0);
  lcd.clear();
  lcd.setCursor(3, 0);  lcd.print("Game Over!");
  lcd.setCursor(4, 1);  lcd.print("Score: "); 
  lcd.print(score);
  delay(3000);
  
  lcd.setRGB(0, 255, 0); 
  score = 0;
  pipeCol[0] = 15;
  pipeCol[1] = 10;
  birdRow = 0;
  gameOver = false;
}
				
			
Solution
				
					#include "rgb_lcd.h"
#include "Ultrasonic.h"

rgb_lcd lcd;
Ultrasonic ultrasonic(8);

byte birdChar[8] = { B00100, B01110, B11111, B10101, B11111, B11111, B01010, B00000 };
byte pipeChar[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };
int pipeCol[2] = {15, 10};
int pipeRow[2] = {0, 1};

int birdRow = 0;
int score = 0;
bool gameOver = false;

void setup() {
  randomSeed(analogRead(A0));
  lcd.begin(16, 2);      
  lcd.setRGB(0, 255, 0);
  lcd.createChar(0, birdChar);
  lcd.createChar(1, pipeChar);
  
  pipeRow[0] = random(0, 2);
  pipeRow[1] = random(0, 2);
}

void loop() {
  if (gameOver) {
    handleGameOver();
    return;
  }

  long distance = ultrasonic.MeasureInCentimeters(); 
  // Contrôle de la position de l'oiseau et rafraîchissement de l'écran
  birdRow = 0;
  if (distance > 0 && distance < 15) birdRow = 1;

  lcd.clear();
  lcd.setCursor(2, birdRow); lcd.write((uint8_t) 0);

  for (int i = 0; i < 2; i++) {
    // Déplacement de l'obstacle et détection de collision
    pipeCol[i]--;

    if (pipeCol[i] < 0) {
      pipeCol[i] = 15;
      pipeRow[i] = random(0, 2);
      score++;
    }

    if (pipeCol[i] == 2 && birdRow == pipeRow[i]) gameOver = true;

    lcd.setCursor(pipeCol[i], pipeRow[i]);
    lcd.write((uint8_t) 1);
  }

  lcd.setCursor(14, 0); lcd.print(score);
  delay(220); 
}

void handleGameOver() {
  lcd.setRGB(255, 0, 0);
  lcd.clear();
  lcd.setCursor(3, 0);  lcd.print("Jeu terminé!");
  lcd.setCursor(4, 1);  lcd.print("Score: "); 
  lcd.print(score);
  delay(3000);
  
  lcd.setRGB(0, 255, 0); 
  score = 0;
  pipeCol[0] = 15;
  pipeCol[1] = 10;
  birdRow = 0;
  gameOver = false;
} 
				
			
Concept

La détection de collision consiste essentiellement à vérifier une exclusivité spatiale. Ce code simplifie l’opération en une correspondance exacte des coordonnées : une collision se déclenche dès que l’oiseau et l’obstacle occupent la même position discrète (X, Y).

L’utilisation de if(gameOver)-return; au début permet d’intercepter rapidement les états anormaux. Ce modèle évite les blocs if-else profondément imbriqués, préservant ainsi la lisibilité et la linéarité du flux d’exécution.

L’illusion du vol est entièrement créée en déplaçant les obstacles de l’arrière-plan vers l’arrière (pipeCol[i]–), tandis que le joueur reste immobile. Ce « mouvement relatif « simule une carte infinie avec une empreinte mémoire minimale.

Tous les affichages numériques génèrent des visuels grâce à une combinaison de micropixels. En chargeant un masque binaire (1 pour activé, 0 pour désactivé) dans le registre, le code illustre le rendu graphique matériel de bas niveau.

Aperçu rapide

Outre le capteur à ultrasons actuellement utilisé, quel autre matériel pourrait permettre d’obtenir des effets de contrôle de mouvement similaires, voire plus précis et stables ?
Envisagez deux pistes : changer la technologie de détection ou modifier entièrement la dimension suivie.

Ce code utilise une clause de garde de type « if-return » pour intercepter les états, maintenant ainsi la logique de jeu linéaire et simple. Toutefois, la clause de garde est-elle toujours la solution optimale ?
Si vous avez plusieurs conditions mutuellement exclusives mais que vous enchaînez des instructions « if-return » consécutives, à quoi ressemble le code ?

Le code utilise actuellement une valeur fixe de -1 pour déplacer les obstacles vers l’arrière. Si vous vouliez simuler une physique dynamique telle que l’accélération, l’inertie ou la traînée, comment cette décrémentation des coordonnées devrait-elle être modifiée sur le plan mathématique ?
Pour intégrer ces effets physiques, est-il vraiment nécessaire d’accumuler davantage d’instructions conditionnelles (if-else) ou de rédiger un bloc logique entièrement distinct ?

3 heures – Utilisez une carte Arduino et la caméra IA HuskyLens pour suivre un objet en temps réel. La caméra reconnaîtra l’objet et affichera sa position sur l’écran LCD. Le servomoteur se déplacera également pour suivre la position de l’objet.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Caméra IA HuskyLens x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

  • LED 1 (Red): Long leg (+) to Pin D8
  • Afficheur LCD 12C: SDA -> SDA; SCL to SCL
  • GND (Ground): Both short legs (-) to GND Pin

Lisez les commentaires TODO, analysez le comportement attendu et implémentez le code pour vous assurer que l’écran LCD et le capteur de niveau sonore fonctionnent comme prévu.

				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"
#include <Wire.h>
#include "rgb_lcd.h"

SoftwareSerial mySerial(2, 3);
HUSKYLENS husky;
rgb_lcd lcd;

const char* MOTION_TEXT[5] = {
  "Analyse du visage...",
  "Vers la gauche <-- ",
  "--> Vers la droite",
  "Approche ! [PROCHE]", 
  "Éloignement... [LOIN]"  
};

const int TRACK_THRESHOLD = 8;
int motionIdx = 0;             
unsigned long stateHoldTimer = 0; 
const int HOLD_DURATION = 500;

int lastX = 160;
int lastW = 40;

void setup() {
  Wire.begin();
  lcd.begin(16, 2);
  mySerial.begin(9600); 

  while (!husky.begin(mySerial)) {
    delay(1000);
  }
  
  husky.writeAlgorithm(ALGORITHM_FACE_RECOGNITION); 
  lcd.setRGB(50, 50, 50);
  lcd.print("HUD facial prêt");
  delay(1000);
}

void loop() {
  if (!husky.request()) return;

  bool isLocked = (millis() - stateHoldTimer < HOLD_DURATION);

  if (husky.available()) {
    HUSKYLENSResult result = husky.read();
    int currentX = result.xCenter;
    int currentW = result.width;

    // TODO : Décodage du mouvement IA et mise à jour de l'état.
    // - Calculer les écarts (deltaX, deltaW) en comparant les données actuelles avec celles de l'image précédente.
    // - Si le suivi n'est PAS verrouillé, mettre à jour 'motionIdx' (1~4) en fonction de TRACK_THRESHOLD.
    // - Mettre à jour 'stateHoldTimer' avec millis() à chaque fois qu'un nouveau mouvement est détecté.
    // - Enregistrer la position actuelle dans les registres historiques (lastX, lastW) pour la prochaine boucle.
    
    /* -------- ÉCRIVEZ VOTRE CODE ICI -------- */

  } else {
    if (!isLocked) motionIdx = 0;
  }
  // Affichage LCD
  lcd.setCursor(0, 0); lcd.print("Suivi du visage   ");
  lcd.setCursor(0, 1); lcd.print(MOTION_TEXT[motionIdx]); 

  switch (motionIdx) {
    case 1:  lcd.setRGB(255, 120, 0);  break; // Gauche
    case 2:  lcd.setRGB(0, 120, 255);  break; // Droite
    case 3:  lcd.setRGB(255, 0, 0);    break; // Arrivée
    case 4:  lcd.setRGB(0, 255, 100);  break; // Départ
    default: lcd.setRGB(30, 30, 30);   break;
  }

  delay(30); 
}
 
				
			
Solution
				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"
#include <Wire.h>
#include "rgb_lcd.h"

SoftwareSerial mySerial(2, 3);
HUSKYLENS husky;
rgb_lcd lcd;

const char* MOTION_TEXT[5] = {
  "Analyse du visage...",
  "Vers la gauche <-- ",
  "--> Vers la droite",
  "Approche ! [PROCHE]", 
  "Éloignement... [LOIN]"  
};

const int TRACK_THRESHOLD = 8;
int motionIdx = 0;             
unsigned long stateHoldTimer = 0; 
const int HOLD_DURATION = 500;

int lastX = 160;
int lastW = 40;

void setup() {
  Wire.begin();
  lcd.begin(16, 2);
  mySerial.begin(9600); 

  while (!husky.begin(mySerial)) {
    delay(1000);
  }
  
  husky.writeAlgorithm(ALGORITHM_FACE_RECOGNITION); 
  lcd.setRGB(50, 50, 50);
  lcd.print("HUD facial prêt");
  delay(1000);
}

void loop() {
  if (!husky.request()) return;

  bool isLocked = (millis() - stateHoldTimer < HOLD_DURATION);

  if (husky.available()) {
    HUSKYLENSResult result = husky.read();
    int currentX = result.xCenter;
    int currentW = result.width;
    // Décodage du mouvement IA et mise à jour de l'état
    int deltaX = currentX - lastX;
    int deltaW = currentW - lastW;
    
    if (!isLocked) {
      int newMotion = 0; 

      if (deltaW > TRACK_THRESHOLD) newMotion = 3; // Arrivée
      else if (deltaW < -TRACK_THRESHOLD) newMotion = 4; // Départ
      else if (deltaX > TRACK_THRESHOLD)  newMotion = 2; // Droite
      else if (deltaX < -TRACK_THRESHOLD) newMotion = 1; // Gauche

      if (newMotion != 0) {
        motionIdx = newMotion;
        stateHoldTimer = millis(); 
      } else {
        motionIdx = 0; 
      }
    }

    lastX = currentX;
    lastW = currentW;
  } else {
    if (!isLocked) motionIdx = 0;
  }
  // Écran LCD
  lcd.setCursor(0, 0); lcd.print("Suivi du visage   ");
  lcd.setCursor(0, 1); lcd.print(MOTION_TEXT[motionIdx]); 

  switch (motionIdx) {
    case 1:  lcd.setRGB(255, 120, 0);  break; // Gauche
    case 2:  lcd.setRGB(0, 120, 255);  break; // Droite
    case 3:  lcd.setRGB(255, 0, 0);    break; // Arrivée
    case 4:  lcd.setRGB(0, 255, 100);  break; // Départ
    default: lcd.setRGB(30, 30, 30);   break;
  }

  delay(30); 
}
 
				
			
Concept

Le système suit le mouvement à l’aide d’une soustraction simple. En soustrayant votre position précédente de votre position actuelle (Delta_X & Delta_W), le système détecte immédiatement si vous vous déplacez vers la gauche ou la droite, ou si vous vous rapprochez.

La caméra dotée d’IA utilise une technique appelée « reconnaissance faciale » pour identifier les individus. Elle compare les traits du visage qu’elle perçoit avec une base de données de visages connus.

En raison de contraintes énergétiques, les puces d’IA en périphérie (Edge AI) aplatissent le monde en 3D pour le ramener à un plan en 2D. Cette réduction de dimensionnalité rend un visage réel en 3D et une photo en 2D indiscernables pour l’algorithme, créant ainsi une faille de sécurité critique.

Aperçu rapide

Lors de la mémorisation d’un utilisateur, pourquoi la caméra IA enregistre-t-elle uniquement les « écarts par rapport au visage moyen « au lieu d’une photo couleur standard ?
Si une seule photo couleur occupe des centaines de kilo-octets, quel espace nécessiteraient des dizaines de photos ? De plus, que se passerait-il si la carte SD était volée ?

En examinant le code de près, on constate que nous calculons deltaX (gauche/droite) et deltaW (proche/loin), mais que nous ignorons totalement les changements le long de l’axe Y (haut/bas). Dans quel type d’application réelle ou de scénario de jeu devrions-nous suivre les mouvements sur l’axe Y ?
Notre projet actuel vise uniquement à détecter les mouvements latéraux de base et la proximité ; l’axe Y revêt-il une quelconque signification physique pratique ?

Sans passer à une caméra 3D coûteuse, quelle astuce logicielle ou règle interactive pourriez-vous ajouter pour obliger la cible à « prouver « qu’il s’agit d’un être humain bien vivant en 3D, et non d’une photo plate ?
Au-delà de la différence spatiale entre 3D et 2D, quelles autres caractéristiques biologiques ou physiques possède un être humain vivant qu’une photo imprimée ne pourra jamais reproduire ?

3 heures – Utilisez un Arduino et la caméra IA HuskyLens pour créer un système de caisse. La caméra reconnaîtra les articles et affichera leurs noms et prix sur l’écran LCD. Le prix total sera calculé et affiché en temps réel.

Matériel

  • Arduino x1
  • Afficheur LCD 12C x1
  • Caméra IA HuskyLens x1
  • Jumper Wires x2
  • Câble imprimante x1

Settings

Le code contient quelques erreurs. Trouvez-les, corrigez-les et téléversez le code : l’Arduino pourra ainsi reconnaître les articles via la caméra et afficher leurs noms et prix sur l’écran LCD.

				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"
#include <Wire.h>
#include "rgb_lcd.h"

SoftwareSerial mySerial(2,3);
HUSKYLENS huskylens;
rgb_lcd lcd;

const int RGB_BLUE[3]  = {0, 0, 255};   
const int RGB_GREEN[3] = {0, 255, 0};     

const int PROD_COUNT = 2;                             
const int PRODUCT_IDS[PROD_COUNT]   = {1, 2};
const String PRODUCT_NAMES[PROD_COUNT] = {"Cola", "Chips"};
const float PRODUCT_PRICES[PROD_COUNT] = {1.50, 3.00};

int cartQtyMatrix[PROD_COUNT] = {0, 0}; 

void updateDisplay(const int rgb[3], const String line1, const String line2) {
  lcd.setRGB(rgb[0], rgb[1], rgb[2]);
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print(line1);
  lcd.setCursor(0, 1); lcd.print(line2);
}

void setup() {
  Wire.begin();
  mySerial.begin(9600);
  huskylens.begin(mySerial);
  lcd.begin(16, 2);
  updateDisplay(RGB_BLUE, "Self-Checkout ON!", "Ready to Scan...");
}

void loop() {
  if (!huskylens.request()) return;
  
  if (huskylens.available()) {
    HUSKYLENSResult result = huskylens.read();
    int scannedID = result.ID;               

    if (scannedID == 3) {
      // TODO 1 : Logique de caisse [Priorité : Promo A -> Promo B] 
      // - Récupérer les quantités actuelles depuis 'cartQtyMatrix'. Vérification de panier vide : si total <= 0, quitter.
      // - Appliquer la Promo A [3 achetés, 1 offert] et la Promo B [1 € de réduction par tranche de 10 €]
      // - Affichage : Afficher le total via String(totalAmount, 2). Réinitialiser la matrice à 0.

      /* -------- ÉCRIVEZ VOTRE CODE ICI -------- */
    }
    // TODO 2 : Boucle de correspondance et scan de l'inventaire.
    // - Écrire une boucle 'for' pour parcourir tous les produits (de 0 à PROD_COUNT - 1).
    // - En cas de correspondance : incrémenter cartQtyMatrix[i], afficher le statut et attendre 1500 ms.
    // - Utiliser 'return;' pour quitter immédiatement.
    
    /* -------- ÉCRIVEZ VOTRE CODE ICI -------- */
  }
}
 
				
			
Solution
				
					
#include <SoftwareSerial.h>
#include "HUSKYLENS.h"
#include <Wire.h>
#include "rgb_lcd.h"

SoftwareSerial mySerial(2,3);
HUSKYLENS huskylens;
rgb_lcd lcd;

const int RGB_BLUE[3]  = {0, 0, 255};   
const int RGB_GREEN[3] = {0, 255, 0};     

const int PROD_COUNT = 2;                             
const int PRODUCT_IDS[PROD_COUNT]   = {1, 2};
const String PRODUCT_NAMES[PROD_COUNT] = {"Cola", "Chips"};
const float PRODUCT_PRICES[PROD_COUNT] = {1.50, 3.00};

int cartQtyMatrix[PROD_COUNT] = {0, 0}; 

void updateDisplay(const int rgb[3], const String line1, const String line2) {
  lcd.setRGB(rgb[0], rgb[1], rgb[2]);
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print(line1);
  lcd.setCursor(0, 1); lcd.print(line2);
}

void setup() {
  Wire.begin();
  mySerial.begin(9600);
  huskylens.begin(mySerial);
  lcd.begin(16, 2);
  updateDisplay(RGB_BLUE, "Caisse libre-service activée !", "Prêt à scanner...");
}

void loop() {
  if (!huskylens.request()) return;
  
  if (huskylens.available()) {
    HUSKYLENSResult result = huskylens.read();
    int scannedID = result.ID;               

    if (scannedID == 3) {
      // Logique de passage en caisse [Priorité : Promo A -> Promo B]
      int colaCount = cartQtyMatrix[0];
      int chipsCount = cartQtyMatrix[1];
      // Promo A : 3 achetés, 1 offert sur le cola
      int freeCola = colaCount / 3; 
      float totalAmount = ((colaCount - freeCola) * PRODUCT_PRICES[0]) + (chipsCount * PRODUCT_PRICES[1]);

      if (totalAmount <= 0.0) {
        updateDisplay(RGB_BLUE, "Panier vide !", "Scannez d'abord un article");
        delay(1500);
        return;
      }
      // Promo B : remise en EUR par tranche de 10 EUR
      if (totalAmount >= 10.0) {
        int discount = (int)(totalAmount / 10.0); 
        totalAmount -= discount;                  
      }

      updateDisplay(RGB_GREEN, "Opération réussie !", "Total : " + String(totalAmount, 2) + " EUR");
      
      for (int i = 0; i < PROD_COUNT; i++)  cartQtyMatrix[i] = 0;
      
      delay(4000); 
      updateDisplay(RGB_BLUE, "Caisse libre-service activée !", "Prêt à scanner...");
      return;
    }
    // Boucle de correspondance et analyse de l'inventaire
    for (int i = 0; i < PROD_COUNT; i++) {
      if (scannedID == PRODUCT_IDS[i]) {
        cartQtyMatrix[i]++;
        updateDisplay(RGB_BLUE, "Article : " + PRODUCT_NAMES[i], "Qté :  " + String(cartQtyMatrix[i]));
        delay(1500); 
        return;
      }
    }
  }
}
 
				
			
Concept

Les variables primitives vous obligent à écrire name1, name2…, ce qui alourdit le code à mesure que le projet grandit. Un tableau alloue un bloc de mémoire unique, indexé et continu. Cela permet à une seule boucle « for « utilisant l’indice i de traiter 2 ou 100 éléments simultanément.

L’IA n’a aucune compréhension conceptuelle d’une canette de soda. Elle traduit les pixels en vecteurs mathématiques pour générer un tableau de probabilités (par ex. 85 % de soda, 10 % de chips) et renvoie aveuglément l’étiquette présentant la probabilité statistique la plus élevée.

Forcer une IA à faible puissance à traiter des contours géométriques provoque une dérive des caractéristiques lorsque les ombres déforment les lignes, ce qui fait chuter la précision. Les ingénieurs contournent ce problème en isolant uniquement les « caractéristiques principales « les plus robustes (comme les blocs de couleur de l’emballage) qui ne sont pas affectées par le bruit extérieur.

Aperçu rapide

Si un client scanne plusieurs articles rapidement à la suite, comment le système garantit-il la mise à jour des bonnes quantités sans en oublier aucun ?
Le système applique un délai de 1500 ms après chaque scan pour permettre à l’Arduino de traiter l’entrée et de mettre à jour l’affichage. Cela garantit que chaque scan est correctement enregistré avant de passer à l’article suivant.

Comment modifieriez-vous le code pour gérer le cas où un client souhaite retirer un article de son panier après l’avoir scanné ?
Vous pourriez implémenter une fonction distincte pour décrémenter la quantité dans la matrice cartQtyMatrix lorsqu’un article spécifique est retiré. Cette fonction

Si la caméra IA identifie mal un article (par ex. en confondant un paquet de chips avec une canette de soda), comment améliorer le système pour réduire ces erreurs ?
Pour réduire les erreurs d’identification, vous pourriez mettre en place une étape de confirmation où l’utilisateur valide l’article avant qu’il ne soit ajouté au panier. Par ailleurs, l’amélioration du modèle d’IA grâce à davantage de données d’entraînement et l’utilisation de multiples caractéristiques (telles que la forme, la couleur et la texture) pour l’identification peuvent accroître la précision.

Réalisé par

  • Clément Herguezabal
  • Yakun Chen