Construire un robot suiveur de ligne à contrôle PID avec intégration Android
Composants et fournitures
| Composant | Quantité |
|---|---|
| Arduino Nano R3 | 1 |
| Capteur suiveur de ligne SparkFun RedBot (ou module TCRT5000 4 canaux) | 1 |
| Module capteur IR TCRT5000 4 canaux (supplémentaire) | 1 |
| Module Bluetooth HC-06 | 1 |
| Appareil Android | 1 |
| Support 4 piles AA | 2 |
| Servomoteurs rotation continue (SM-S4303R) | 2 |
Applications et services en ligne
- Arduino IDE
- MIT App Inventor 2 (création application Android)
À propos du projet
Ce projet vise à construire un robot suiveur de ligne avec contrôle PID. Une application Android permet de régler facilement les paramètres PID pour un ajustement rapide. C'est la première partie d'un projet en deux étapes ; la seconde sera un robot résolveur de labyrinthe avec IA simple.

Étape 1 : Liste du matériel (BOM)
Coût total ~75 $ :
- Châssis : 2 carrés bois 80×80 mm, 3 pinces binder, 2 roues bois Ø50 mm, 1 roulette à bille, 9 élastiques, bande 3M Command, fixations plastiques capteurs.
- Électronique : breadboard, câblage, 2 packs 4×NiMH (5 V chacun), 2 servos rotation continue, Arduino Nano, HC-06, 5 capteurs ligne (module 4 canaux + 1 individuel), 1 LED, 1 bouton.
Étape 2 : Configuration des moteurs
Deux servos rotation continue (SM-S4303R) collés ensemble (bande 3M). Alimentation externe 5-6 V. Signaux Arduino : Pin 5 (gauche), Pin 3 (droite).
Largeur d'impulsion : 1,0 ms = vitesse max sens 1 ; 1,5 ms = arrêt ; 2,0 ms = vitesse max sens inverse. Comme les servos sont montés en opposition :
- Droit : 1500 µs (arrêt) → 2000 µs (avant max)
- Gauche : 1500 µs (arrêt) → 1000 µs (avant max)
Test d'arrêt : envoyer 1500 µs et ajuster la vis de réglage (ou modifier la valeur 1500 dans le code).
#include <Servo.h>
Servo leftServo, rightServo;
void setup() {
leftServo.attach(5);
rightServo.attach(3);
leftServo.writeMicroseconds(1500);
rightServo.writeMicroseconds(1500);
}
void loop() {}
Étape 3 : Assemblage châssis et test mouvement

Fixez servos sur le premier carré bois (bande 3M). Second carré au-dessus (pinces binder). Roulette sur pince. Batterie moteurs entre breadboard et châssis. Câblage : GND commun, signaux servos sur pins 5 et 3, LED pin 13, bouton pin 9.
Code de test mouvement (avance, recule, arrêt, virages) : voir fichier FDDQRQOIN4TTVY0.ino.
Étape 4 : Module Bluetooth HC-06 (optionnel)

Connexions : HC-06 Tx → Arduino Pin 10 (Rx), Rx → Pin 11 (Tx), VCC/GND → 5V/GND. Bibliothèque SoftwareSerial. Le robot fonctionne avec ou sans Bluetooth (paramètres par défaut dans le code). L'app Android sert au réglage PID et contrôle manuel.
Étape 5 : Capteurs de ligne

5 capteurs sur une barre plastique (espacement pour couvrir la largeur de la ligne). Broches Arduino :
- Capteur 0 (gauche) → Pin 12
- Capteur 1 → Pin 18 (A4)
- Capteur 2 (centre) → Pin 17 (A3)
- Capteur 3 → Pin 16 (A2)
- Capteur 4 (droit) → Pin 19 (A5)
Deuxième pack batteries → Vin Arduino. Câbles sous le châssis (élastiques).
Étape 6 : Logique des capteurs IR
Chaque capteur : LED IR + photodiode. Sortie numérique : HIGH = surface sombre (ligne), LOW = claire. Potentiomètre sur module règle le seuil.
Avec 5 capteurs, les combinaisons typiques sur une ligne donnent un tableau de 5 bits. On en déduit une variable erreur :
| Tableau capteurs | Erreur |
|---|---|
| 0 0 1 0 0 | 0 (centré) |
| 0 0 0 0 1 | 4 |
| 0 0 0 1 1 | 3 |
| 0 0 0 1 0 | 2 |
| 0 0 1 1 0 | 1 |
| 0 1 1 0 0 | -1 |
| 0 1 0 0 0 | -2 |
| 1 1 0 0 0 | -3 |
| 1 0 0 0 0 | -4 |
Implémentation Arduino :
const int lineFollowSensor0 = 12;
const int lineFollowSensor1 = 18;
const int lineFollowSensor2 = 17;
const int lineFollowSensor3 = 16;
const int lineFollowSensor4 = 19;
int LFSensor[5] = {0,0,0,0,0};
void readLFSsensors() {
LFSensor[0] = digitalRead(lineFollowSensor0);
LFSensor[1] = digitalRead(lineFollowSensor1);
LFSensor[2] = digitalRead(lineFollowSensor2);
LFSensor[3] = digitalRead(lineFollowSensor3);
LFSensor[4] = digitalRead(lineFollowSensor4);
if((LFSensor[0]==0)&&(LFSensor[1]==0)&&(LFSensor[2]==0)&&(LFSensor[3]==0)&&(LFSensor[4]==1)) error = 4;
else if((LFSensor[0]==0)&&(LFSensor[1]==0)&&(LFSensor[2]==0)&&(LFSensor[3]==1)&&(LFSensor[4]==1)) error = 3;
else if((LFSensor[0]==0)&&(LFSensor[1]==0)&&(LFSensor[2]==0)&&(LFSensor[3]==1)&&(LFSensor[4]==0)) error = 2;
else if((LFSensor[0]==0)&&(LFSensor[1]==0)&&(LFSensor[2]==1)&&(LFSensor[3]==1)&&(LFSensor[4]==0)) error = 1;
else if((LFSensor[0]==0)&&(LFSensor[1]==0)&&(LFSensor[2]==1)&&(LFSensor[3]==0)&&(LFSensor[4]==0)) error = 0;
else if((LFSensor[0]==0)&&(LFSensor[1]==1)&&(LFSensor[2]==1)&&(LFSensor[3]==0)&&(LFSensor[4]==0)) error = -1;
else if((LFSensor[0]==0)&&(LFSensor[1]==1)&&(LFSensor[2]==0)&&(LFSensor[3]==0)&&(LFSensor[4]==0)) error = -2;
else if((LFSensor[0]==1)&&(LFSensor[1]==1)&&(LFSensor[2]==0)&&(LFSensor[3]==0)&&(LFSensor[4]==0)) error = -3;
else if((LFSensor[0]==1)&&(LFSensor[1]==0)&&(LFSensor[2]==0)&&(LFSensor[3]==0)&&(LFSensor[4]==0)) error = -4;
}
Étape 7 : Contrôle proportionnel (P)

Vitesse de base iniMotorPower = 250 (demi-vitesse). Correction proportionnelle :
int Kp = 50;
rightServo.writeMicroseconds(1500 + iniMotorPower - Kp*error);
leftServo.writeMicroseconds(1500 - iniMotorPower - Kp*error);
Erreur positive (robot dérive à gauche) → ralentit droit, accélère gauche → revient au centre.
Étape 8 : Contrôle PID complet (optionnel)

PID = Proportionnel + Intégral + Dérivé.
- P = error (magnitude correction)
- I = I + error (somme erreurs passées, élimine erreur statique)
- D = error - previousError (variation, réduit dépassement)
PIDvalue = (Kp*P) + (Ki*I) + (Kd*D)
Réglage manuel (méthode essai-erreur) :
- Kd=Ki=0. Régler Kp seul (départ 25-50).
- Puis Kp=Kd=Kp/2. Augmenter Kd pour réduire dépassement, diminuer si instable.
- Ajuster le taux d'échantillonnage (délai dans la boucle).
void calculatePID() {
P = error;
I = I + error;
D = error - previousError;
PIDvalue = (Kp*P) + (Ki*I) + (Kd*D);
previousError = error;
}
void motorPIDcontrol() {
int leftMotorSpeed = 1500 - iniMotorPower - PIDvalue;
int rightMotorSpeed = 1500 + iniMotorPower - PIDvalue;
leftServo.writeMicroseconds(leftMotorSpeed);
rightServo.writeMicroseconds(rightMotorSpeed);
}
Étape 9 : Code final

Boucle principale avec machine d'états :
#define STOPPED 0
#define FOLLOWING_LINE 1
#define NO_LINE 2
void loop() {
readLFSsensors();
// Détection conditions spéciales
if (all sensors HIGH) mode = STOPPED; // ligne large = arrêt
else if (all sensors LOW) mode = NO_LINE; // perte ligne
else mode = FOLLOWING_LINE;
switch (mode) {
case STOPPED: motorStop(); break;
case NO_LINE: motorStop(); motorTurn(LEFT, 180); break; // demi-tour
case FOLLOWING_LINE: calculatePID(); motorPIDcontrol(); break;
}
}
Code complet modulaire (fichiers .ino et .h) disponible sur GitHub.
Étape 10 : Réglage PID via application Android

Application créée avec MIT App Inventor 2. Commandes manuelles : 'f' (avant), 'b' (arrière), 'l' (gauche), 'r' (droite), 's' (stop), 'g' (go = suivre ligne). Curseurs pour Kp, Ki, Kd : envoient 'p/XXX', 'i/XXX', 'd/XXX' (0-100). Bouton 'Start' = bouton physique pin 9.
Fichiers : .aia (source App Inventor) et .apk (installable).
Étape 11 : Modification code pour réglage PID à distance
Dans setup(), boucle d'attente du bouton Start (ou commande 'g' via BT) :
while (digitalRead(buttonPin) && !mode) {
checkBTcmd(); // lit commande Bluetooth
manualCmd(); // exécute commande manuelle ou change Kp/Ki/Kd
command = "";
}
checkPIDvalues();
mode = STOPPED;
void manualCmd() {
switch (command[0]) {
case 'g': mode = FOLLOWING_LINE; break;
case 's': motorStop(); break;
case 'f': motorForward(); break;
case 'r': motorTurn(RIGHT,30); motorStop(); break;
case 'l': motorTurn(LEFT,30); motorStop(); break;
case 'b': motorBackward(); break;
case 'p': Kp = command.substring(2).toFloat(); break;
case 'i': Ki = command.substring(2).toFloat(); break;
case 'd': Kd = command.substring(2).toFloat(); break;
}
}
Étape 12 : Conclusion

Première partie d'un projet plus large (robot résolveur de labyrinthe à suivre). Fichiers mis à jour sur GitHub. Plus de tutoriels sur MJRoBot.org.
Code source
Dépôt GitHub : https://github.com/Mjrovai/MJRoBot-Line-Follower
Schémas
Fichier Fritzing : oIDhLcHQ30lDgVBXZvb8.fzz
Processus de fabrication
- Robotique au 21e siècle : systèmes distribués, téléprésence et exploration spatiale
- Capteur de suivi de ligne KY‑033 avec Raspberry Pi : Détecteur de porte/lignes simple
- Maîtriser le contrôle des capteurs et actionneurs sur Raspberry Pi : Accéléromètre, Servo et Streaming de données
- Construire un robot piloté Wi‑Fi avec Raspberry Pi & Smartphone Android
- Wittmann Battenfeld lance la gamme WX153 : robots avancés pour l'automatisation de l'injection à haute force de fermeture
- FANUC élargit sa gamme de robots SCARA : six modèles, charges 3–20 kg, portées 400–1100 mm
- Construire une télécommande Android universelle avec Arduino, 1Sheeld et contrôle IR
- Maîtriser le contrôle PID pour une pince robot 3D dans MATLAB/Simulink
- Optimisez l'assurance qualité de l'emballage avec des systèmes de contrôle automatisés avancés