Robot Autonome (Suiveur de Ligne)

Systèmes Embarqués C / C++ (Machine à états) KiCad (PCB) Bus I2C (Boussole/LiDAR)
Vue d'ensemble du Robot Suiveur de Ligne

Ce projet de SAÉ en équipe visait à concevoir un robot autonome capable de naviguer sur un parcours complexe. Mes contributions : J'étais en charge de la conception de la carte mère (Shield Arduino Nano) et surtout du développement de l'algorithme de suivi de cap via la boussole I2C (MPU-9250), permettant au robot de naviguer à l'aveugle. Pour tester et gérer mes modules de façon indépendante des autres membres du groupe, j'ai développé ma propre architecture logicielle basée sur une machine à états.

Carte Mère : Shield Arduino Nano (KiCad)

Routage & Adaptations de Niveaux

J'ai conçu sous KiCad le Shield central servant de "Hub" pour le robot. Le défi majeur était de faire communiquer le microcontrôleur fonctionnant en 5V avec des capteurs fonctionnant en 3.3V (Boussole MPU-9250, LiDARs).

Routage du Shield sous KiCad
  • Level Shifter (GT117) : Intégration d'un adaptateur de niveaux logiques bidirectionnel pour protéger le bus I2C (SDA/SCL) reliant l'Arduino (5V) aux capteurs LiDAR et MPU-9250 (3.3V).
  • Connectique Centralisée : Création de ports dédiés pour les capteurs CNY70, les moteurs (J13), la boussole (J12), et un module ESP8266 (J5) pour un futur débogage sans fil.
  • Intégration globale : Interconnexion de tous les sous-systèmes, incluant le circuit de mesure de la batterie dont le code a été réalisé par mon collègue.

Architecture Logicielle (C++)

Ma propre Machine à États

Pour faciliter les tests et l'intégration, chaque membre de l'équipe possédait sa propre machine à états (Automate Fini). De mon côté, j'ai architecturé mon programme autour d'un switch/case pour orchestrer mes modules et gérer la transition entre les différents modes de navigation.

etapeBatterie
Phase d'initialisation qui exploite le code de mesure de tension de mon collègue. En fonction de la valeur convertie par l'ADC, cette étape pilote un ruban LED (vert, orange ou rouge) pour indiquer visuellement le niveau de charge de la batterie LiPo au démarrage, et reste en attente de l'appui sur le bouton de départ.
etapeSuiviLigne
État nominal de navigation sur la piste guidée. Le robot utilise une configuration hybride de capteurs CNY70 : deux capteurs analogiques au centre pour évaluer l'écart exact avec la ligne noire, et deux capteurs numériques sur les côtés pour détecter les marques spécifiques du parcours (intersections, lignes d'arrêt). Il ajuste en temps réel la vitesse des moteurs pour rester centré.
etapeCap
État critique prenant le relais lors de la perte de la ligne au sol (navigation à l'aveugle). Le robot interroge le magnétomètre MPU-9250 via le bus I2C, compare son angle actuel avec sa consigne de cap initiale, et maintient une trajectoire parfaitement rectiligne jusqu'à retrouver un marqueur au sol.

Double Asservissement Proportionnel

Pour garantir un déplacement fluide et précis, j'ai développé des algorithmes de régulation basés sur des correcteurs proportionnels (P) appliqués à deux situations distinctes du parcours :

  • 1. Suivi de Ligne : Calcul de l'erreur spatiale à partir des valeurs des deux capteurs analogiques centraux. Cette erreur est multipliée par un gain (Kp) pour ajuster différentiellement la vitesse des roues et centrer le robot sur la piste, tandis que les capteurs numériques latéraux scrutent les événements du parcours.
  • 2. Suivi de Cap (MPU-9250) : Lors de la perte de ligne (navigation à l'aveugle), le magnétomètre I2C prend le relais. L'angle actuel est calculé par trigonométrie (atan2 sur les axes Y/Z). Un second correcteur proportionnel calcule l'écart avec la consigne de cap initiale et corrige les moteurs pour maintenir le robot parfaitement droit.
// Extrait : Suivi de cap avec régulation proportionnelle void suivi_cap() { float v = 260.0; // Vitesse de base float vr = 150.0; // Facteur de correction // Acquisition I2C du magnétomètre float hz = mpu.getMagZ(); float hy = mpu.getMagY(); // Calcul de l'angle actuel float angle = atan2(hz, hy) * (180.0 / M_PI); float erreur = abs(consigne_cap - angle); // Action proportionnelle à l'erreur angulaire vr = vr * (erreur / 180.0); // Ajustement différentiel des moteurs if (consigne_cap < angle) { moteurDroite(v + vr, true, false); moteurGauche(v - vr, true, false); } else { moteurDroite(v - vr, true, false); moteurGauche(v + vr, true, false); } }