Projet Gamel Trophy: Robot Suiveur "La Gamelle"
Robot móvil autónomo de alta velocidad con 5 sensores IR, circuito impreso PCB en KiCad y control proporcional-derivativo (PD)
1. Présentation du Robot "La Gamelle"
Qu'est-ce que "La Gamelle" ?
"La Gamelle" est le surnom donné à l'IUT de Cachan au robot suiveur de ligne autonome conçu spécialement pour participer aux épreuves emblématiques du Gamel Trophy (2025/2026). Développé en binôme dans le cadre du BUT Génie Électrique et Informatique Industrielle (GEII) sous l'encadrement de M. Fabien Parrain et M. Jean Yves Le Chenadec, ce robot embarqué a pour objectif principal de parcourir un circuit complexe composé d'un tapis noir et d'une ligne blanche au sol, sans aucune aide extérieure.
Le robot intègre une structure matérielle complète comprenant un châssis mobile motorisé à courant continu, un écran LCD pour l'interface homme-machine, une carte capteurs à 5 canaux infrarouges, un bouton de fin de course (FDC), un connecteur jack de sécurité et une carte hacheur à MOSFETs IRL510. Lors de la phase de qualification, "La Gamelle" a validé son parcours d'homologation avec un temps remarquable d'environ 19 secondes.
2. Architecture Électronique & Schémas KiCad
Schéma Synoptique du Système
L'architecture globale relie une batterie 12V au plomb, alimentant directement la carte hacheur et abaissée à 5V via des régulateurs 7805 pour le microcontrôleur et les capteurs. Les 5 capteurs envoient des signaux analogiques (AN1-AN5) au microcontrôleur, qui génère ensuite deux signaux PWM (MLI) vers la carte hacheur pour piloter précisément la vitesse de chaque moteur.
Carte Capteur (KiCad)
Conception du schéma sur KiCad intégrant 5 capteurs infrarouges CNY70, des résistances de pull-up et un régulateur de tension 7805.
Carte Hacheur (KiCad)
Circuit de puissance basé sur des MOSFETs IRL510 permettant de contrôler la vitesse des moteurs 12V via les signaux PWM du microcontrôleur.
3. Spécifications Techniques & Code C Embarqué
Disposés sous le châssis à moins de 10 mm du sol. 3 capteurs centraux (espacés de 9.5 mm) pour le suivi de ligne continu et 2 capteurs extérieurs (à 40 mm) pour la détection des raccourcis à 90°.
Contrôle individuel des deux moteurs 12V à courant continu par modulation de largeur d'impulsion (PWM/MLI) générée par le compilateur XC8 sur MPLAB.
Calcul d'erreur, normalisation dynamique (0-100), filtrage numérique par variance et correction Proportionnelle-Dérivée :
Correction = C0 * erreur + Kd * (erreur - erreur_pre)
Détection sélective des raccourcis à gauche par le capteur LG avec temporisation de 0.25s anti-croisement et coupure du moteur intérieur pour virage à 90°.
Code Source C Officiel (MPLAB XC8)
#include <xc.h>
#include "iut_lcd.h"
#include "iut_adc.h"
#include "iut_pwm.h"
#include "iut_timers.h"
#define LG s[0] // Capteur extérieur gauche
#define LD s[4] // Capteur extérieur droit
#define CG s[1] // Capteur central gauche
#define CD s[3] // Capteur central droit
#define CC s[2] // Capteur central milieu
enum states { CALIB, C0_KD, VITESSE, RALENTISSEMENT, ALGO, RECHERCHE, RACCOURCI, JACK_IN };
int min[5] = {1023, 1023, 1023, 1023, 1023};
int max[5] = {0, 0, 0, 0, 0};
int s[5];
float ralentissement, vitesse, erreur, erreur_pre, C0, Kd;
enum states state = CALIB;
// Calibration continue des capteurs min/max
void calibration(void) {
for (int i = 1; i < 6; i++) {
int v = adc_read(i);
if (v < min[i - 1]) min[i - 1] = v;
if (v > max[i - 1]) max[i - 1] = v;
}
}
// Normalisation des valeurs des capteurs entre 0 et 100%
void normalisation(void) {
for (int i = 0; i < 5; i++) {
s[i] = ((long)(adc_read(i + 1) - min[i]) * 100) / ((long)(max[i] - min[i]));
}
}
// Algorithme de correction Proportionnelle-Dérivée (PD)
void algorithme(float vitesse) {
float static variance = 0;
float V_max_adapte, derivee, correction;
int V_droite, V_gauche;
if (erreur < 0 && somme < 80) erreur = -100;
else if (erreur > 0 && somme < 80) erreur = 100;
derivee = erreur - erreur_pre;
correction = C0 * erreur + Kd * derivee;
erreur_pre = erreur;
// Filtrage numérique avec la variance
variance = ((DEPTH_VAR - 1) * variance + fabs(derivee)) / DEPTH_VAR;
V_max_adapte = vitesse - ralentissement * variance;
V_droite = V_max_adapte + correction;
V_gauche = V_max_adapte - correction;
pwm_setdc1((int)(V_gauche));
pwm_setdc2((int)(V_droite));
}
// Machine d'état principale pour la prise de raccourci à 90°
void Raccourci() {
static int etat = 1;
switch (etat) {
case 1:
if (ReadTimer0() >= 5000 && LG < 10) etat = 2;
algorithme(200);
break;
case 2:
algorithme(200);
if (LG > 30 && CG > 30) etat = 3;
break;
case 3:
pwm_setdc1(0); // Arrêt moteur gauche pour virage serré 90°
pwm_setdc2(200);
if (CG < 20 && CC < 20 && CD < 20) etat = 4;
break;
}
}