RASPBERRY PICO W
Le capteur de couleur TCS34725 (Gravity)


À quoi ça sert sur notre robot ?
Le TCS34725 est un capteur de couleur.
Sur la compétition Rescue Line, il sert principalement à :
- suivre la ligne noire
- repérer les carrés verts pour savoir quand tourner à droite ou à gauche
Comment “voit” le capteur ?
Il éclaire le sol
Le capteur possède quatre petites LEDs blanches.
- Elle éclaire le sol juste en dessous du robot
- La lumière rebondit sur le sol et revient vers le capteur
- Un sol clair renvoie beaucoup de lumière
- Un sol foncé (ligne noire) renvoie peu de lumière
Il sépare la lumière en couleurs
À l’intérieur du capteur, il y a 4 détecteurs :
- 🔴 Rouge (R)
- 🟢 Vert (G)
- 🔵 Bleu (B)
- ⚪ Luminosité totale (Clear)
Pour chaque couleur, le capteur donne un nombre.
Ces nombres sont envoyés au microcontrôleur (ex : Raspberry Pico, mBot, etc.).
Le multiplexeur I2C

Pourquoi on en a besoin avec plusieurs capteurs de couleur ?
Rappel : c’est quoi le bus I2C ?
Le bus I2C, c’est comme une route avec quatres fils :
- SDA : pour envoyer et recevoir les données
- SCL : pour donner le rythme (l’horloge)
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.
Chaque capteur a une adresse
Sur cette route, chaque capteur a une adresse, comme un numéro de maison.
Exemple :
- Capteur température : adresse
0x48 - Capteur distance : adresse
0x29 - Capteur couleur TCS34725 : adresse
0x29
Quand le microcontrôleur veut parler à un capteur, il dit :
« Je parle au capteur numéro 0x29 »
Le problème avec plusieurs capteurs identiques
Dans notre robot, on utilise plusieurs capteurs de couleur identiques :
- gauche
- centre
- droite
Et ils ont tous la même adresse I2C
Résultat :
- Le microcontrôleur dit :
« Capteur 0x29, réponds ! » - Tous répondent en même temps
- Ça crée un conflit → le bus ne fonctionne plus
La solution : le multiplexeur I2C
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é.
Comment fonctionne le multiplexeur ?
Le multiplexeur est lui-même un appareil I2C
- Il a sa propre adresse
- Le microcontrôleur peut lui parler
Il possède plusieurs “canaux” de 1 à 8 canaux
Par exemple :
- canal 0
- canal 1
- canal 2
- …
- jusqu’à 8 canaux
Chaque canal peut avoir :
- un capteur
- ou même plusieurs capteurs (s’ils ont des adresses différentes)
On ouvre un canal à la fois
Le microcontrôleur dit au multiplexeur :
« Ouvre le canal 2 »
Résultat :
- Seul le capteur branché sur le canal 2 est visible
- Les autres sont déconnectés temporairement
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])

- 0x29 : capteur de couleur
- 0x72 : multiplexeur i2c
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é ! »)
RASPBERRY PICO W
- MICRO PYTHON RASPBERRYCARTE DE DEVELOPPEMENT RASPBERRY PICO W La carte dispose : La carte propose l’écosystème C/C++ mais également celui du Micropython. Pi Pico bénéficie des avantages de micro-python et on peut citer notamment : Sur une carte à microcontrôleur, on dispose : Le pico pi est vendu « vide », autrement dit, il ne dispose pas du Micropython… Lire la suite : MICRO PYTHON RASPBERRY
- L’écran OLED SSD1306CARTE DE DEVELOPPEMENT RASPBERRY PICO W C’est quoi un écran OLED SSD1306 ? 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. OLED, ça veut dire quoi ? Taille courante : Comment la Pico… Lire la suite : L’écran OLED SSD1306
- Entrées et sorties numériquesCARTE DE DEVELOPPEMENT RASPBERRY PICO W LED intégrée à la carte 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 : Comment la Pico contrôle la LED ? La Pico utilise une sortie numérique. C’est comme… Lire la suite : Entrées et sorties numériques
- CAPTEURS COULEURS TCS34725RASPBERRY PICO W Le capteur de couleur TCS34725 (Gravity) À quoi ça sert sur notre robot ? Le TCS34725 est un capteur de couleur.Sur la compétition Rescue Line, il sert principalement à : Comment “voit” le capteur ? Il éclaire le sol Le capteur possède quatre petites LEDs blanches. Il sépare la lumière en couleurs… Lire la suite : CAPTEURS COULEURS TCS34725
CARTE DE DEVELOPPEMENT RASPBERRY PICO W

LED intégrée à la carte
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 :
- à 1 (ON) → la LED s’allume
- à 0 (OFF) → la LED s’éteint

Comment la Pico contrôle la LED ?
La Pico utilise une sortie numérique.
C’est comme un interrupteur :
- ON = courant qui passe
- OFF = courant coupé
En MicroPython, on utilise la classe Pin.
Allumer la LED
from machine import Pin
led = Pin("LED",Pin.OUT) # LED sur la carte
led.on() # Allumer la LED
La LED s’allume
Eteindre la LED
led.off() # Éteindre la LED
La LED s’éteint
Faire clignoter la LED
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 :
- la LED s’allume 1 seconde
- puis s’éteint 1 seconde
- et recommence en boucle
Une autre façon
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 :
- tu règles l’heure
- et il sonne tout seul
- même si tu fais autre chose
Création du timer
Timer→ pour créer un minuteur automatique
timerLed = Timer()
On crée un minuteur qui appellera une fonction tout seul.
Démarrage du timer
timerLed.init(freq=5, callback=loopLed)
freq=5→ 5 fois par secondecallback=loopLed→ appelle la fonctionloopLed
La fonction appelée par le timer
def loopLed(timerLed):
led.toggle()
Cette fonction :
- est appelée automatiquement par le timer
- change l’état de la LED à chaque appel (allumée, éteinte)
Faire clignoter une LED sur le PIN GP2
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)
Faire clignoter une LED bleue avec un Timer
(sans boucle
while)
- La LED clignote toute seule,
- une fois par seconde,
- sans bloquer le programme.
C’est comme un réveil :
- tu règles le rythme
- et il déclenche la LED tout seul
- pendant que le programme fait autre chose
La LED
ledBlue = Pin(2, Pin.OUT)
La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)
Allumer / éteindre une LED avec un bouton poussoir (interruption)
Quand on appuie sur le bouton poussoir :
- la LED change d’état
- allumée → éteinte
- éteinte → allumée
Installe une LED de couleur bleue sur le port GP2 et un bouton poussoir sur GP3 :
Le code complet
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
)
Explication ligne par ligne
Importation
from machine import Pin, Timer
On utilise :
Pin→ pour la LED et le bouton
La LED bleue sur GP2
ledBlue = Pin(2, Pin.OUT)
La LED est branchée sur la broche 2
C’est une sortie (ON / OFF)
Le bouton poussoir sur GP3
button1 = Pin(3, Pin.IN, Pin.PULL_UP)
Le bouton est :
- sur la broche 3
- configuré en entrée
- avec une résistance pull-up interne
Pull-up, ça veut dire :
- sans appui → niveau 1
- bouton appuyé → niveau 0
Éteindre la LED au départ
ledBlue.off()
On commence avec la LED éteinte
État connu = pas de surprise
La partie la plus importante : l’interruption
button1.irq(
handler = lambda btn1: ledBlue.toggle(),
trigger = button1.IRQ_FALLING
)
C’est quoi une interruption ? :
- le programme fait autre chose
- Ding ! → bouton appuyé
- la Pico réagit tout de suite
IRQ_FALLING
L’interruption se déclenche :
- quand le signal passe de 1 à 0
- donc quand on appuie sur le bouton
(parce qu’il est en pull-up)
ledBlue.toggle()
toggle() le LED inverse son état :
- ON → OFF
- OFF → ON
Pourquoi lambda btn1: ?
C’est une petite fonction rapide :
lambda btn1: ledBlue.toggle()
- Elle est appelée automatiquement
btn1représente le bouton (obligatoire)- On n’en a pas besoin ici, mais MicroPython l’exige
Pourquoi utiliser une interruption ? (le gros avantage)
Sans interruption
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
Avec interruption
- Le bouton est détecté instantanément
- Le programme reste rapide
C’est quoi lambda en Python ?
lambda permet de créer une toute petite fonction,
- en une seule ligne,
- sans lui donner de nom.
Une fonction jetable, rapide à écrire.
Une fonction normale (classique)
def addition(a, b):
return a + b
Cette fonction :
- a un nom (
addition) - fait une action
- renvoie un résultat
La même chose avec lambda
addition = lambda a, b: a + b
C’est exactement pareil, mais :
- en une seule ligne
- plus court
- sans
def
Comment lire une lambda
lambda 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
L’écran OLED SSD1306
CARTE DE DEVELOPPEMENT RASPBERRY PICO W
C’est quoi un écran OLED SSD1306 ?
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.
OLED, ça veut dire quoi ?
- Chaque pixel s’allume tout seul
- Pas besoin de rétroéclairage
- Noir = pixel éteint → économie d’énergie
Taille courante :
- 128 × 64 pixels
- 128 × 32 pixels
Comment la Pico communique avec l’écran ?
La Pico communique avec l’écran grâce au bus I²C.
C’est comme une conversation :
- La Pico = celui qui parle
- L’écran = celui qui écoute
Les 2 fils importants du bus i2c
| 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.
À quoi sert la bibliothèque micropython-ssd1306 ?
La bibliothèque sert à :
- permettre d’écrire simplement :
- du texte
- des pixels
- des formes
https://github.com/stlehmann/micropython-ssd1306
Comment fonctionne l’affichage ? (idée clé)
L’écran ne s’actualise pas tout seul.
- La Pico dessine dans une image invisible (le buffer)
- Quand tout est prêt, on dit :
oled.show()
Et l’image apparaît à l’écran
Comme dessiner sur une feuille, puis l’afficher d’un coup
Exemple simple de programme
# 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()
Les commandes principales (les plus utiles)
Écrire du texte
oled.text("Texte", x, y)
x→ position horizontaley→ position verticale
🧹 Effacer l’écran
oled.fill(0)
Allumer tous les pixels
oled.fill(1)
Allumer un pixel
oled.pixel(x, y, 1)
Dessiner une ligne
oled.line(x1, y1, x2, y2, 1)
0 ou 1 pour éteindre ou allumer la ligne
Exemple amusant (point qui bouge)
for x in range(128):
oled.fill(0)
oled.pixel(x, 30, 1)
oled.show()
Le point se déplace à l’écran
ROBOCUP 2026 Maze
Stratégie de déplacement du robot dans le labyrinthe.
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 :
- devant lui
- à droite
- à gauche
Se déplacer dans un couloir en suivant une Ligne imaginaire
Quand le robot est dans un couloir, il ne colle pas au mur :
- il suit une ligne imaginaire parallèle au mur de droite
- cette ligne se situe au centre du couloir
Cela permet :
- d’éviter de toucher les murs
- d’avancer droit
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 :
- le robot s’arrête
- cela signifie qu’il est arrivé à la fin du couloir ou à une intersection

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 :

Suivi d’une ligne imaginaire au milieu du couloir
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.
- largeur du couloir = 30 cm
- écart de la ligne en prenant en compte la largeur du robot = 9 cm


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
Elimine les valeurs erronées :

Détail

Télécharge et teste
Essaye de suivre tout le labyrinthe, tourne en bout de couloir
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;
Problème 1 : le robot est trop proche des parois
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 :

Problème 2 : le robot reste collé à la paroi
Si le robot ne change pas de position pendant un certain temps, alors on essaye de le décoller de la paroi.


Problème 3 : le robot ne détecte pas toujours la bonne possibilité en fin de couloir
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 :

Problème 4 : Lorsque la paroi de droite est inexistante, le robot ne tourne pas suffisamment à droite ou tourne trop fort.
Modifie la valeur de kp :

ROBOCUP 2026 Rescue line
Configure MBLOCK pour le suivi de ligne
Utilise le bouton extension

Rajoute ces deux éléments :


Premier essai de fonctionnement du MBOT

Premier téléchargement


Teste ton programme
Teste une programmation des moteurs

Teste ton programme
Essayons de programmer par étape le suivi de ligne
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 :

- vitesse_droite : pour gérer la vitesse du moteur EM1
- vitesse_gauche : pour gérer la vitesse du moteur EM2
- vitesse_maxi : vitesse maximum du robot
- vitesse_mini : vitesse moyenne du robot
- position : poids de la position du robot par rapport à la ligne noire
- correction : correction à appliquer aux moteurs pour suivre la ligne noire
Gestion du bouton B pour lancer le suivi de ligne puis l’arrêter

Tester le bouton B , les leds s’allument en vert puis en rouge
Calcul pour lancer les moteurs en fonction de la position du robot par rapport à la ligne noire

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

Teste le robot pour qu’il tourne plus ou moins à gauche ou à droite
Une première version pour un Suivi de ligne
Utilise cette instruction pour la détection de la ligne noire :

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


Plus de détail :
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 :

Modifie le suivi de ligne avec le calcul du PID

- derivee : afin de suivre quand le robot passe de gauche à droite de la ligne noire
- Kp : pour accentuer ou diminuer pour prendre le angles droits,
- 1 ne fait rien
- < 1 diminue l’angle des virages
- > 1 augmente l’angle des virages
- Kd : pour empêcher le robot de faire des zigzags
- 0 ne fait rien
- 0 à 3 diminuer les zigzags en ligne droite


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 :

| 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 :
- le choix d’une traction avant ou arrière ;
- le positionnement des capteurs, afin d’éviter qu’ils ne s’éloignent du sol lors des montées de pente ;
- la maîtrise du robot lors des descentes.
Pour résoudre ces problèmes, nous devons revoir :
- l’adhérence du robot au sol, en choisissant des pneus en caoutchouc de meilleure qualité ;
- le choix d’un suivi de ligne basé sur un calcul PID, afin d’améliorer la stabilité et la précision du robot
Traction avant ou traction arrière : avantages et inconvénients
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 :
- le suivi de ligne
- la montée et la descente des pentes
- l’évitement et le franchissement des obstacles
Traction avant (moteurs à l’avant). les avantages
- Bon guidage de la trajectoire
- Les roues motrices tirent le robot
- Le robot suit plus facilement la direction des capteurs
- Intéressant pour le suivi de ligne précis
- Meilleur passage des petits obstacles
- Les roues motrices montent directement sur l’obstacle
- Moins de risque de rester bloqué
- Robot plus stable en descente
- Le poids vers l’avant aide à garder le contrôle
- Moins de risque de « glissade »
Traction avant (moteurs à l’avant). Inconvénients
- Moins d’adhérence en montée
- Le poids se déplace vers l’arrière
- Les roues avant peuvent patiner
- Problème d’adhérence sur des pentes fortes (25 %)
- Direction plus sensible
- Peut surcorriger dans les virages serrés
- Demande un réglage PID précis
Traction arrière (moteurs à l’arrière). Avantages
- Meilleure adhérence en montée
- Le poids du robot repose sur les roues motrices
- Très efficace sur les pentes raides (25%)
- Robot plus stable en ligne droite
- Le robot est “poussé” plutôt que tiré
- Moins de patinage
Traction arrière (moteurs à l’arrière). Inconvénients
- Suivi de ligne moins précis
- Les roues arrière poussent le robot
- Risque de dérapage de l’arrière
- Virages serrés plus difficiles
- Passage d’obstacles plus délicat
- Les roues avant ne sont pas motrices
- Elles peuvent buter sur l’obstacle
- Moins de contrôle en descente
- Le robot peut accélérer trop vite
- Risque de perte de contrôle, glissade surtout avec les roues bidirectionnelles
Choix d’un suivi de ligne basé sur un calcul PID
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.
Pourquoi utiliser un calcul PID pour suivre une 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 :
- dans les avions
- dans les voitures
- dans les robots
- dans les machines industrielles
Chaque fois qu’un système doit être stable et précis, on utilise un PID.
Pourquoi le PID est utile pour notre robot ?
Le PID aide le robot à :
- mieux prendre les virages
- éviter les balancements
- suivre la ligne de manière fluide
- mieux passer les lignes en pointillée
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.
Conclusion
Le calcul PID permet à notre robot de :
- mieux suivre la ligne
- être plus stable
- être plus performant en compétition
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 :

- Ligne au centre → erreur = 0
- Ligne à gauche → erreur négative
- Ligne à droite → erreur positive
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. »
- Si Kp est petit → le robot corrige doucement (il peut sortir de la ligne)
- Si Kp est grand → le robot corrige fort (il peut zigzaguer)
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. »
- Kd faible → le robot zigzague
- Kd plus grand → le robot devient plus stable
- Kd trop grand → le robot devient lent à réagir
- Ensemble : Kp + Kd
- Kp fait tourner le robot vers la ligne
- Kd empêche le robot de faire des zigzags
Ensemble, ils permettent au robot de :
- suivre la ligne correctement
- rester stable
- passer les virages serrés plus facilement
Comment les régler :
- Mettre Kd = 0 au départ
- Augmenter Kp jusqu’à ce que le robot suive la ligne
- Si le robot zigzague → augmenter Kd
Ajuster jusqu’à obtenir un mouvement fluide.
Configure MBLOCK pour le suivi de ligne
Utilise le bouton extension

Rajoute ces deux éléments :


Premier essai de fonctionnement du MBOT

Premier téléchargement


Teste ton programme
Teste une programmation des moteurs

Teste ton programme
Essayons de programmer par étape le suivi de ligne
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 :

- vitesse_droite : pour gérer la vitesse du moteur EM1
- vitesse_gauche : pour gérer la vitesse du moteur EM2
- vitesse_maxi : vitesse maximum du robot
- vitesse_mini : vitesse moyenne du robot
- position : poids de la position du robot par rapport à la ligne noire
- correction : correction à appliquer aux moteurs pour suivre la ligne noire
Gestion du bouton B pour lancer le suivi de ligne puis l’arrêter

Tester le bouton B , les leds s’allument en vert puis en rouge
Calcul pour lancer les moteurs en fonction de la position du robot par rapport à la ligne noire

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

Teste le robot pour qu’il tourne plus ou moins à gauche ou à droite
Une première version pour un Suivi de ligne

Plus de détail :
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 :

Modifie le suivi de ligne avec le calcul du PID

- derivee : afin de suivre quand le robot passe de gauche à droite de la ligne noire
- Kp : pour accentuer ou diminuer pour prendre le angles droits,
- 1 ne fait rien
- < 1 diminue l’angle des virages
- > 1 augmente l’angle des virages
- Kd : pour empêcher le robot de faire des zigzags
- 0 ne fait rien
- 0 à 3 diminuer les zigzags en ligne droite


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 :

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

Créer un Folder à votre nom pour mettre toutes vos créations :

Changer la couleur d’un part

local part = script.Parent
part.Touched:Connect(function(hit)
part.BrickColor = BrickColor.random()
part.Material = Enum.Material.Neon
end)
Un part mortel :

local HumanoidFinder = require(game.ReplicatedStorage.HumanoidFinder)
local part = script.Parent
part.Touched:Connect(function(hit)
-- On utilise la fonction du module pour tester
local humanoid, character = HumanoidFinder.Get(hit)
if humanoid then
humanoid:TakeDamage(10)
end
end)
Rendre tout petit le joueur :

local HumanoidFinder = require(game.ReplicatedStorage.HumanoidFinder)
local part = script.Parent
part.Touched:Connect(function(hit)
-- On utilise la fonction du module pour tester
local humanoid, character = HumanoidFinder.Get(hit)
if humanoid then
humanoid.BodyHeightScale.Value = 0.4
humanoid.BodyWidthScale.Value = 0.4
humanoid.BodyDepthScale.Value = 0.4
humanoid.HeadScale.Value = 0.4
end
end)
Faire glisser un part avec un clickDetector :

local part = script.Parent
local clickDetector = part.ClickDetector
clickDetector.MouseClick:Connect(function(player)
part.Anchored = false
part.AssemblyLinearVelocity = Vector3.new(0, 0, 50)
end)
Part pour voler avec un clickDetector :

local AntiGravity = require(game.ReplicatedStorage.AntiGravity)
local part = script.Parent
local clickDetector = part.ClickDetector
clickDetector.MouseClick:Connect(function(player)
part.Anchored = false
AntiGravity.Start(part)
part.AssemblyLinearVelocity = Vector3.new(0, 10, 10)
end)
Téléportation d’un point A à un point B :

local HumanoidFinder = require(game.ReplicatedStorage.HumanoidFinder)
-- Ressource sur le modèle de téléportation
local teleports = script.Parent
-- Récupération des objets sur les plateformes
local teleportA = teleports.TeleportA
local teleportB = teleports.TeleportB
-- Quand un joueur touche la première plateforme,
-- il est téléporté sur la seconde
-- on vérifie qu'il s'agit bien d'un personnage
teleportA.Touched:Connect(function(hit)
local humanoid, character = HumanoidFinder.Get(hit)
if humanoid then
character:PivotTo(CFrame.new(teleportB.Position))
end
end)
Grandir, Sauter, Courir plus vite :

local UserInputService = game:GetService("UserInputService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local runScalePlayer = replicatedStorage:WaitForChild("RunScalePlayer")
local HumanoidFinder = require(replicatedStorage.HumanoidFinder)
local humanoid, character = HumanoidFinder.GetLocal()
local function onKeyPress(input, gameProcessed)
if not humanoid then return end
if input.KeyCode == Enum.KeyCode.F and not gameProcessed then
humanoid.JumpHeight += 8
end
if input.KeyCode == Enum.KeyCode.G and not gameProcessed then
humanoid.JumpHeight -= 8
end
print(input.KeyCode)
if input.KeyCode == Enum.KeyCode.X and not gameProcessed then
humanoid.WalkSpeed += 10
end
if input.KeyCode == Enum.KeyCode.Z and not gameProcessed then
humanoid.WalkSpeed -= 10
end
if input.KeyCode == Enum.KeyCode.Q and not gameProcessed then
runScalePlayer:FireServer(0.5)
end
if input.KeyCode == Enum.KeyCode.E and not gameProcessed then
runScalePlayer:FireServer(-0.5)
end
end
-- Connecter la fonction à l'événement InputBegan
UserInputService.InputBegan:Connect(onKeyPress)
Touches du clavier :
- F sauter plus haut
- G sauter moins haut
- X courir plus vite
- W courir moins vite
- A grandir
- E plus petit
Menu disponible pour le joueur :


local screenGui = script.Parent
local open = screenGui.OpenButton
local screen = screenGui.Screen
local close = screen.CloseButton
local scaleUpPlayer = screen.ScaleUpPlayerButton
local scaleDownPlayer = screen.ScaleDownPlayerButton
local runSlowerPlayer = screen.RunSlowerPlayerButton
local runFasterPlayer = screen.RunFasterPlayerButton
local jumpUpPlayer = screen.JumpUpPlayerButton
local jumpDownPlayer = screen.JumpDownPlayerButton
local replicatedStorage = game:GetService("ReplicatedStorage")
local runScalePlayer = replicatedStorage:WaitForChild("RunScalePlayer")
local runScalePlayer = replicatedStorage:WaitForChild("RunScalePlayer")
local HumanoidFinder = require(replicatedStorage.HumanoidFinder)
local StarterPlayer = game:GetService("StarterPlayer")
local humanoid, character = HumanoidFinder.GetLocal()
screen.Visible = false
open.MouseButton1Click:Connect(function()
screen.Visible = not screen.Visible
open.Visible = not open.Visible
end)
close.MouseButton1Click:Connect(function()
screen.Visible = not screen.Visible
open.Visible = not open.Visible
end)
scaleUpPlayer.MouseButton1Click:Connect(function()
runScalePlayer:FireServer(0.5)
end)
scaleDownPlayer.MouseButton1Click:Connect(function()
runScalePlayer:FireServer(-0.5)
end)
runSlowerPlayer.MouseButton1Click:Connect(function()
humanoid.WalkSpeed -= 10
end)
runFasterPlayer.MouseButton1Click:Connect(function()
humanoid.WalkSpeed += 10
end)
jumpUpPlayer.MouseButton1Click:Connect(function()
humanoid.JumpHeight += 8
end)
jumpDownPlayer.MouseButton1Click:Connect(function()
humanoid.JumpHeight -= 8
end)
Créer une arme fatale :
Créer un objet Tool puis un part renommer Handle :

Pour réduire à l’impuissance vos adversaires :
local HumanoidFinder = require(game.ReplicatedStorage.HumanoidFinder)
local part = script.Parent
part.Touched:Connect(function(hit)
if not hit then return end
local humanoid, character = HumanoidFinder.Get(hit)
if humanoid then
humanoid:TakeDamage(10)
end
end)
