Réalisation d’un jeu 2D pour comprendre le fonctionnement de Construct 3
Partie 01 mise en place des éléments graphiques
Partie 02 Animer les éléments graphiques
Réalisation d’un jeu 2D pour comprendre le fonctionnement de Construct 3
Partie 01 mise en place des éléments graphiques
Partie 02 Animer les éléments graphiques
RASPBERRY PICO W


Le TCS34725 est un capteur de couleur.
Sur la compétition Rescue Line, il sert principalement à :
Le capteur possède quatre petites LEDs blanches.
À l’intérieur du capteur, il y a 4 détecteurs :
Pour chaque couleur, le capteur donne un nombre.
Ces nombres sont envoyés au microcontrôleur (ex : Raspberry Pico, mBot, etc.).

Le bus I2C, c’est comme une route avec quatres fils :
Tous les capteurs sont branchés sur la même route et parlent avec le microcontrôleur.
Avec un bus I2C ont peut dialoguer avec plusieurs dispositifs sur le même bus.
Sur cette route, chaque capteur a une adresse, comme un numéro de maison.
Exemple :
0x480x290x29Quand le microcontrôleur veut parler à un capteur, il dit :
« Je parle au capteur numéro 0x29 »
Dans notre robot, on utilise plusieurs capteurs de couleur identiques :
Et ils ont tous la même adresse I2C
Résultat :
Un multiplexeur I2C (ex : TCA9548A) est comme :
un aiguillage ou un feu de circulation pour le bus I2C
Il permet de choisir quel capteur est connecté au bus à un instant donné.
Par exemple :
Chaque canal peut avoir :
Le microcontrôleur dit au multiplexeur :
« Ouvre le canal 2 »
Résultat :
Pour programmer, le capteur TCS34725 utilise la librairie class tcs34725.py à télécharger sur le microcontroleur :

Dans ton programme importe ces bibliothèques :
from machine import I2C
import time
from tcs34725 import TCS34725
Recherche les adresses sur le bus i2c :
from machine import I2C
import time
from tcs34725 import TCS34725
print("Initialisation I2C...")
i2c = I2C(0)
print("Scan I2C en cours...")
devices = i2c.scan()
print("Adresses trouvées:", [hex(d) for d in devices])

Exemple d’un programme de test pour lire les valeurs de deux capteurs sur les port 0 et 1 :
from machine import I2C
import time
from tcs34725 import TCS34725
print("Initialisation I2C...")
i2c = I2C(0)
print("Scan I2C en cours...")
devices = i2c.scan()
print("Adresses trouvées:", [hex(d) for d in devices])
# Initialisation du capteur
# Si vous n'utilisez PAS de multiplexeur, laissez multiplexer_addr=None
# Si vous en utilisez un, changez multiplexer_addr=0x70 (ou autre) et le port=0-7
ADDRESS_MULTIPLEXER = const(0x72)
try:
print("Initialisation TCS34725...")
#sensor = TCS34725(i2c)
# Pour un multiplexeur:
sensor01 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 0)
sensor02 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 1)
print("Capteur trouvé !")
# Configuration optionnelle
sensor01.integration_time(50) # 50ms (plus rapide mais moins précis que 2.4ms * n)
sensor01.gain(4) # Gain 4x (1, 4, 16, 60)
sensor02.integration_time(50)
sensor02.gain(4)
while True:
# Lecture brute
r, g, b, c = sensor01.read(raw=True)
# Lecture interprétée
temp, lux = sensor01.read(raw=False) # Note: refait une lecture
print(f"R:{r} G:{g} B:{b} C:{c} | Temp:{temp}K Lux:{lux}")
gray01 = sensor01.read_grayscale()
gray02 = sensor02.read_grayscale()
print("Read Gray : ", gray01)
# Détection simple couleur
if sensor01.is_red():
print(" >> ROUGE détecté !")
elif sensor01.is_green():
print(" >> VERT détecté !")
elif sensor01.is_blue():
print(" >> BLEU détecté !")
time.sleep(1)
except RuntimeError as e:
print("ERREUR FATALE:", e)
except Exception as e:
print("Erreur inattendue:", e)
Exemple initialisation capteur de couleur en direct sans le multiplexeur :
sensor = TCS34725(i2c)
Exemple initialisation capteurs couleur via le multiplexeur :
sensor01 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 0)
sensor02 = TCS34725(i2c, ADDRESS_MULTIPLEXER, 1)
Lecture de la nuance de gris :
gray01 = sensor01.read_grayscale()
print("Read Gray : ", gray01)
Détection d’une couleur :
if sensor01.is_red():
print( » >> ROUGE détecté ! »)
elif sensor01.is_green():
print( » >> VERT détecté ! »)
elif sensor01.is_blue():
print( » >> BLEU détecté ! »)
CARTE DE DEVELOPPEMENT RASPBERRY PICO W

Sur la Raspberry Pi Pico, il y a une petite LED intégrée à la carte.
Cette LED est reliée à une broche spéciale.
Quand on met cette broche :

La Pico utilise une sortie numérique.
C’est comme un interrupteur :
En MicroPython, on utilise la classe Pin.
from machine import Pin
led = Pin("LED",Pin.OUT) # LED sur la carte
led.on() # Allumer la LED
La LED s’allume
led.off() # Éteindre la LED
La LED s’éteint
from machine import Pin
from time import sleep
led = Pin("LED", Pin.OUT)
while True:
led.on() # LED allumée
sleep(1) # attendre 1 seconde
led.off() # LED éteinte
sleep(1) # attendre 1 seconde
Résultat :
from machine import Pin, Timer
# led de la carte
led=Pin("LED",Pin.OUT)
timerLed=Timer() # déclare un objet timer
def loopLed(timerLed):
led.toggle()
timerLed.init(freq=5, callback=loopLed)
La LED clignote toute seule, sans bloquer le programme.
C’est comme une alarme tous les x secondes :
Timer → pour créer un minuteur automatiquetimerLed = Timer()
On crée un minuteur qui appellera une fonction tout seul.
timerLed.init(freq=5, callback=loopLed)
freq=5 → 5 fois par secondecallback=loopLed → appelle la fonction loopLeddef loopLed(timerLed):
led.toggle()
Cette fonction :
Installe une LED de couleur bleue sur le port GP2 :

from machine import Pin, Timer
# led de la carte
ledBlue=Pin(2,Pin.OUT)
timerLedBlue=Timer() # déclare un objet timer
def loopLedBlue(timerLedBlue):
ledBlue.toggle()
timerLedBlue.init(freq=1, callback=loopLedBlue)
(sans boucle
while)
C’est comme un réveil :
ledBlue = Pin(2, Pin.OUT)
La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)
Installe une LED de couleur bleue sur le port GP2 et un bouton poussoir sur GP3 :
from machine import Pin, Timer
# led de la carte
ledBlue = Pin(2, Pin.OUT)
button1 = Pin(3, Pin.IN, Pin.PULL_UP)
ledBlue.off()
button1.irq(
#définition de l'interruption sur la broche
handler = lambda btn1: ledBlue.toggle(),
# mode de déclenchement IRQ_RISING IRQ_FALLING
trigger = button1.IRQ_FALLING
)
from machine import Pin, Timer
On utilise :
Pin → pour la LED et le boutonledBlue = Pin(2, Pin.OUT)
La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)
button1 = Pin(3, Pin.IN, Pin.PULL_UP)
Le bouton est :
Pull-up, ça veut dire :
ledBlue.off()
On commence avec la LED éteinte
État connu = pas de surprise
button1.irq(
handler = lambda btn1: ledBlue.toggle(),
trigger = button1.IRQ_FALLING
)
IRQ_FALLINGL’interruption se déclenche :
(parce qu’il est en pull-up)
ledBlue.toggle()toggle() le LED inverse son état :
lambda btn1: ?C’est une petite fonction rapide :
lambda btn1: ledBlue.toggle()
btn1 représente le bouton (obligatoire)while True:
if button1.value() == 0:
ledBlue.toggle()
sleep(0.3)
Le programme regarde le bouton tout le temps
Risque de rater un appui
Le robot est ralenti
lambda en Python ?lambda permet de créer une toute petite fonction,
Une fonction jetable, rapide à écrire.
def addition(a, b):
return a + b
Cette fonction :
addition)lambdaaddition = lambda a, b: a + b
C’est exactement pareil, mais :
deflambda a, b: a + b
Ça se lit comme :
« Une fonction qui prend
aetbet qui retournea + b»
Tout ce qui est après : est le résultat
CARTE DE DEVELOPPEMENT RASPBERRY PICO W
Un écran OLED SSD1306 est un petit écran que l’on branche à un microcontrôleur (comme une Raspberry Pi Pico) pour afficher du texte ou des dessins sur un port I2C.
Taille courante :
La Pico communique avec l’écran grâce au bus I²C.
C’est comme une conversation :
| Fil | Rôle |
|---|---|
| SDA | Données envoyées à l’écran |
| SCL | Cadence (rythme de communication) |
L’écran a une adresse (souvent 0x3C) pour qu’on sache à qui on parle.
micropython-ssd1306 ?La bibliothèque sert à :
https://github.com/stlehmann/micropython-ssd1306
oled.show()
Et l’image apparaît à l’écran
Comme dessiner sur une feuille, puis l’afficher d’un coup
# Création du bus I2C
i2c = I2C(0)
# Création de l'écran
oled = SSD1306_I2C(128, 64, i2c)
# Effacer l'écran
oled.fill(0)
# Écrire du texte
oled.text("Bonjour !", 0, 0)
oled.text("Initialisation", 0, 10)
# Afficher à l'écran
oled.show()
oled.text("Texte", x, y)
x → position horizontaley → position verticaleoled.fill(0)
oled.fill(1)
oled.pixel(x, y, 1)
oled.line(x1, y1, x2, y2, 1)
0 ou 1 pour éteindre ou allumer la ligne
for x in range(128):
oled.fill(0)
oled.pixel(x, 30, 1)
oled.show()
Le point se déplace à l’écran
L’objectif est de permettre au robot de se déplacer tout seul dans un labyrinthe, sans se perdre, en utilisant une stratégie simple :
suivre le mur de droite et prendre en priorité les ouvertures à droite.
Principe général : suivre le mur de droite ou de gauche
Le robot imagine qu’il garde toujours sa main droite posée sur un mur.
S’il continue ainsi, il pourra explorer tout le labyrinthe sans rester bloqué.
Pour cela, le robot utilise des capteurs de distance pour savoir s’il y a un mur :
Quand le robot est dans un couloir, il ne colle pas au mur :
Cela permet :
Le robot ajuste légèrement sa direction pour rester à la même distance du mur de droite et avance jusqu’à la fin du couloir
Dès que le capteur détecte un mur devant :

Teste et affiche sur l’écran le niveau de batterie :

Si le niveau de batterie est trop faible le comportement du robot devient incohérent.

Quand le capteur ultrasonique n’arrive plus à mesurer, par exemple trop proche d’un mur, la valeur retournée est 300.


Télécharge et teste le robot dans le labyrinthe dans un couloir
Utilise le calcul de trajectoire PID du suivi de ligne :

Indique kp = 1 et kd = 0 pour l’instant

Télécharge et teste : Le robot va tout droit

Télécharge et teste : Le robot va à droite

Télécharge et teste : Le robot va à gauche
Modifie la valeur de kp entre 1.5 et 0.5, tu constateras que ton robot tourne plus ou moins fortement :

On imagine une ligne noire posée au milieu du couloir parallèle au mur droit du couloir. Le robot suit cette ligne en allant de droite à gauche comme pour le suivi d’une ligne noire.


Détail du suivi de ligne avec le capteur ultrasonique 2 sur le mur droit :

On image une ligne à 9cm (ecart_ligne) de la paroi de droite et d’une largeur de 3 cm. A droite de la ligne le robot tourne à gauche (position = -0.5à, sur la ligne il va tout droit (position = 0), à gauche de la ligne il tourne vers la droite (position = 0.5).
Télécharge et teste un couloir avec un mur à droite tout le long

Détail

Télécharge et teste
En fonction des possibilités tourne à 90° en bout de couloir soit à droite, soit à gauche ou fait un demi-tour à 180°


Télécharge et teste
Le robot commence à suivre le labyrinthe avec quelques imperfection à corriger;
Si le capteur ultrasonique de droite ou de gauche détecte une distance trop proche de la paroi, alors le robot recule en changeant de sens de direction pour essayer de se recentrer au milieu du couloir.

Détail pour détecter un rapprochement avec les parois de droite et de gauche :

Si le robot ne change pas de position pendant un certain temps, alors on essaye de le décoller de la paroi.


Parfois la mesure par le capteur ultrasonique est erronée. Pour éviter une erreur de direction suit à une mesure, la solution est de prendre plusieurs mesures afin valider la bonne direction à prendre :
Le robot est trop proche de la paroi en fin de couloir, on tente de reculer le robot :

On cumule les mesures pendant 3 secondes toute les 0.5 secondes

Après que le robot a effectué son quart de tour à gauche ou à droite, on vérifie de nouveau si une paroi est présente devant le robot :

Le code complet :

Modifie la valeur de kp :

Utilise le bouton extension

Rajoute ces deux éléments :





Teste ton programme

Teste ton programme
Affichons le niveau de batterie car si celle-ci est inférieure à un certain niveau, le comportement du robot devient incohérent :

Sous le lancement du MBOT CyberPi crée les variables suivantes :


Tester le bouton B , les leds s’allument en vert puis en rouge

Si le robot est à gauche de la ligne noire, il tourne à droite pour se recentrer sur la ligne :

Si le robot est à droite de la ligne noire, il tourne à gauche pour se recentrer sur la ligne :

Si le robot est centrer sur la ligne noire, il va tout droit :

Détail du calcul :




Ne pas oublier que les moteurs du MBOT sont inversés :

Teste pour vérifier que ton calcul est correct avec position = 0 pour aller tout droit :

Teste, le robot roule tout droit
Teste des valeurs de position de -2 à 2 :

Teste le robot pour qu’il tourne plus ou moins à gauche ou à droite avec des valeurs dans position entre -2 et 2
Utilise cette instruction pour la détection de la ligne noire :

Elle permet une détection par capteur L2, L1, R1, R2 :



Détection d’un virage par les capteurs extrêmes L2, D2 du Quad RGB du MBOT :


Capteur central ou L1 et R1 sur la ligne pour aller tout droit :

Détail du si :

Et les 2 capteurs L1 et R1 du Quad RGB du MBOT :

Teste le suivi de ligne
Tu peux rajouter plus de précision :

Plus de détail sur le rajout :




Tu peux jouer sur ces deux valeurs pour ajuster ton suivi de ligne :

à

puis teste :

à


Si le capteur au central détecte une ligne noire en même temps que les capteurs L2 et R2, on peut déduire que le robot est sur un croisement. Le robot doit aller tout droit.




Si le robot détecte un obstacle avec un dispositif placé à l’avant du robot, une stratégie de forçage est déclenchée : le robot effectue une accélération franche vers l’avant afin de franchir l’obstacle.

Puis rajouter l’appel de la fonction dans le code :




| Finale régionale | 14 mars 2026 | INP |
| Finale nationale | 30 et 31 mai 2026 | Bordeaux (France) |
| Finale européenne | du 1er au 5 juin 2026 | Vienne (Autriche) |
Lors de nos participations à la RoboCup Junior, nous avons constaté que notre robot rencontrait des difficultés dans les virages très serrés.
Il avait tendance à zigzaguer, à se balancer de gauche à droite et parfois à perdre la ligne, en particulier lorsque celle-ci est en pointillée.
L’année dernière, sur nos mBot 2, nous avons ajouté un capteur central, ce qui a permis d’améliorer le suivi de ligne.
Afin de progresser cette année, nous devons nous reposer plusieurs questions, notamment :
Pour résoudre ces problèmes, nous devons revoir :
Le choix entre une traction avant (roues motrices à l’avant) et une traction arrière (roues motrices à l’arrière) a un impact important sur :
Traction avant (moteurs à l’avant). les avantages
Traction avant (moteurs à l’avant). Inconvénients
Traction arrière (moteurs à l’arrière). Avantages
Traction arrière (moteurs à l’arrière). Inconvénients
Le suivi de ligne simple, qui consiste à tourner à gauche ou à droite selon les capteurs, n’est pas suffisant. Il est nécessaire d’utiliser un système plus précis pour permettre au robot de rester bien centré sur la ligne.
Le PID est une méthode de calcul utilisée pour corriger automatiquement un mouvement. Le PID (Proportionnel – Intégral – Dérivé) est un algorithme de régulation inventé au début du XXᵉ siècle, notamment grâce aux travaux de Nicolas Minorsky en 1922, lors de l’étude du pilotage automatique des navires, pour aider à guider des bateaux sans les faire osciller.
Aujourd’hui, le PID est utilisé partout :
Chaque fois qu’un système doit être stable et précis, on utilise un PID.
Le PID aide le robot à :
Grâce aux moteurs avec encodeurs, notre robot avance droit.
Nous utilisons donc seulement une partie du PID (P et D), ce qui est suffisant et plus simple.
Le calcul PID permet à notre robot de :
C’est pour cela que nous devons expérimenter ce calcul pour améliorer notre robot en RoboCup Junior.
Quelque indications pour le mettre en œuvre avec le MBOT 2.
Les capteurs disent au robot où est la ligne :

Utilise une variable « position » pour affecter un poids d’erreur en fonction des capteurs, voir cet exemple :
la formule du PID est la suivante :
correction = (Kp × erreur) + (Kd × variation de l’erreur)
vitesse_gauche = vitesse_mini + (correction * vitesse_mini)
vitesse_droit = vitesse_mini – (correction * vitesse_mini)
Kp accentue proportionnellement l’erreur de positionnement par rapport à la ligne noire, Kp veut dire coefficient proportionnel.
Il sert à dire au robot :
« Plus je suis loin de la ligne, plus je corrige fort. »
Kd – Calmer le robot, Kd veut dire coefficient dérivé. Il va permettre de se remettre bien droit sur la ligne droite suite à des virages, notamment pour que le robot se positionne pour suivre une ligne en pointillée.
Il sert à dire au robot :
« Attention, tu corriges trop vite, ralentis un peu. »
Ensemble, ils permettent au robot de :
Comment les régler :
Ajuster jusqu’à obtenir un mouvement fluide.
Utilise le bouton extension

Rajoute ces deux éléments :





Teste ton programme

Teste ton programme
Affichons le niveau de batterie car si celle-ci est inférieure à un certain niveau, le comportement du robot devient incohérent :

Sous le lancement du MBOT CyberPi crée les variables suivantes :


Tester le bouton B , les leds s’allument en vert puis en rouge

Teste, le robot roule tout droit
Teste des valeurs de position de -2 à 2 :

Teste le robot pour qu’il tourne plus ou moins à gauche ou à droite

Capteur central pour aller tout droit :

Détail du si :

Et les 4 capteurs du Quad RGB du MBOT :

Teste le suivi de ligne
Tu peux rajouter plus de précision :

Plus de détail sur le rajout :




Tu peux jouer sur ces deux valeurs pour ajuster ton suivi de ligne surtout pour le passage de la ligne en pointillé :

Passage d’un obstacle
Si le robot reste bloqué devant un obstacle, l’objectif est de détecter qu’il est à l’arrêt, et qu’il tente de franchir l’obstacle sans y parvenir.
Ce blocage peut être identifié par un état de secousses répétées pendant une certaine durée.
Lorsque le robot est reconnu dans cet état, une stratégie de forçage est déclenchée : le robot recule légèrement, puis effectue une accélération franche vers l’avant afin de franchir l’obstacle.

Puis rajouter l’appel de la fonction dans le code :

Visualisation de la vidéo pour la construction d’une roue en 3D :
