Robot Mobil Line Follower cu Arhitectură Dual-MCU

1. Introducere și Obiectivele Proiectului

Acest proiect reprezintă implementarea practică a cunoștințelor acumulate la disciplina Proiectare cu Microprocesoare (PM). Scopul principal a fost dezvoltarea unui sistem embedded complex, mai exact un robot mobil autonom de tip Line Follower, echipat cu module periferice pentru detectarea obstacolelor și avertizare acustică, dar și cu un sistem independent de raportare a stării pe un ecran LCD.

Pentru a nu îngreuna bucla principală de control a robotului și pentru a evita latențele neplăcute induse de funcțiile de împrospătare a ecranului, am ales o abordare avansată: o arhitectură distribuită cu două microcontrollere independente (ATmega328P).

Prin acest montaj, am pus în practică direct tematicile studiate la laboratoarele de PM:

2. Arhitectura Hardware și Subsistemul de Alimentare

Gestiunea Energiei (Pachetul de Baterii AA)

Pentru a asigura portabilitatea completă a robotului pe traseu, am proiectat o sursă de alimentare dintr-un pachet agregat de 8 baterii alcaline tip AA (fiecare având o tensiune nominală de 1.5V). Din punct de vedere structural, am folosit două adaptoare de plastic de câte 4 baterii, pe care le-am conectat electric în serie.

Calculul tensiunii totale de linie introduse în sistem: $$V_{in} = 8 \times 1.5\text{V} = 12\text{V}$$

Această magistrală principală de 12V alimentează direct terminalele de putere ale driverului de motoare L298N pentru a pune în mișcare motoarele de curent continuu.

Totuși, circuitele logice de control (atât placa Arduino Uno, cât și placa Arduino Nano și senzorii) au nevoie de o tensiune stabilă de 5V. Pentru a obține acest prag, am folosit regulatorul liniar de tensiune integrat pe modulul L298N (78M05). Acesta coboară cei 12V din baterii la 5V curați, pe care i-am distribuit în paralel către pinii de `5V` ai ambelor plăci Arduino.

Masele electrice (GND) de la adaptoarele de baterii, de la driverul L298N, de la Arduino Uno și de la Arduino Nano au fost unite într-un nod central de masă pentru a asigura un potențial de referință unitar de 0V.

⚠️ Regulă de Aur la Laborator (Siguranță): Pentru a evita distrugerea componentelor, deconectăm întotdeauna pachetul de baterii AA de pe robot atunci când conectăm cablurile USB la calculator pentru a încărca codul. Conflictul direct dintre alimentarea din USB și tensiunea debitată de regulatorul L298N poate arde porturile USB ale PC-ului sau cipurile de comunicare serială de pe plăcuțe.

 Vedere de ansamblu hardware robot

Alocarea Resurselor I/O (Pin Mapping pe Module)

Deoarece am separat sarcinile pe două microcontrollere diferite, organizarea pinilor a devenit mult mai curată și am eliminat riscul de coliziune a semnalelor.

1. Placa Principală a Robotului (Arduino Uno)

Această placă se ocupă exclusiv de rularea algoritmului cinematic de urmărire a liniei, scanarea traseului prin ultrasunete și activarea alarmei în caz de urgență.

Componentă Periferică Pin Arduino Uno Direcție (I/O) Tip Semnal Rolul în cadrul Robotului
Driver Motoare (L298N - ENA) `D6` OUTPUT PWM Control viteză Motor Stânga
Driver Motoare (L298N - ENB) `D5` OUTPUT PWM Control viteză Motor Dreapta
Driver Motoare (L298N - IN1) `D7` OUTPUT Digital Direcție Motor Stânga (Sens A)
Driver Motoare (L298N - IN2) `D8` OUTPUT Digital Direcție Motor Stânga (Sens B)
Driver Motoare (L298N - IN3) `D9` OUTPUT Digital Direcție Motor Dreapta (Sens A)
Driver Motoare (L298N - IN4) `D10` OUTPUT Digital Direcție Motor Dreapta (Sens B)
Senzor Infraroșu (IR Stânga) `D12` INPUT Digital Citire stare linie (0 = alb, 1 = negru)
Senzor Infraroșu (IR Dreapta) `D11` INPUT Digital Citire stare linie (0 = alb, 1 = negru)
Senzor Sonar (HC-SR04 - Trig) `D3` OUTPUT Digital Declanșare impuls ultrasonic (10 µs)
Senzor Sonar (HC-SR04 - Echo) `D4` INPUT Digital Captare timp zbor undă reflectată
Avertizor Acustic (Buzzer) `D2` OUTPUT Digital Activare alarmă sonoră (sirenă sacadată)

 Vedere de ansamblu hardware robot

2. Placa Dedicată Afișajului (Arduino Nano)

Această placă secundară are un singur scop: preia textul și menține aprins ecranul LCD, rulând independent mașina de stări pentru mesaje fără a bloca resursele procesorului principal de pe Uno.

Componentă Periferică Pin Arduino Nano Direcție (I/O) Tip Semnal Rolul în cadrul Afișajului
Ecran LCD 1602 (Pin 4 - RS) `D12` OUTPUT Digital Selecție regiștri (Data/Command)
Ecran LCD 1602 (Pin 6 - E) `D11` OUTPUT Digital Linie de Enable (Validare date)
Ecran LCD 1602 (Pins D4-D7) `D5`, `D4`, `D3`, `D2` OUTPUT Digital Magistrală tranzitorie de date (Mod 4 biți)
Ecran LCD 1602 (Pin 15 - BLA) `D9` OUTPUT PWM Controlul hardware al luminii de fundal

3. Implementarea Software și Logica de Rulare

1. Firmware Subsistem Afișaj (Arduino Nano)

 Vedere de ansamblu hardware robot

Codul rulat pe placa Arduino Nano gestionează ecranul alfanumeric prin biblioteca `LiquidCrystal` în configurație de magistrală pe 4 biți (liniile de date inferioare D0-D3 ale ecranului rămân libere). Izolarea ecranului pe acest MCU ne permite să folosim instrucțiuni de tip `delay(2000)` pentru lizibilitatea textelor, lucru care pe o placă unică ar fi înghețat complet motoarele robotului pe pistă.

Pentru a asigura stabilitatea pixelilor și a elimina suprapunerile de caractere, am introdus o latență de 20 ms imediat după comanda `lcd.clear()`, oferind timp controllerului HD44780 să își reseteze regiștrii interni înainte de a primi un nou set de date.  Vedere de ansamblu hardware robot  Vedere de ansamblu hardware robot

lcd_subsystem.ino
#include <LiquidCrystal.h>
 
// Inițializăm pinii ecranului în ordinea: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int pinLumina = 9;
 
void setup() {
  pinMode(pinLumina, OUTPUT);
  // Aprindem lumina de fundal la maximum din semnalul PWM
  analogWrite(pinLumina, 255); 
 
  lcd.begin(16, 2);
  lcd.clear();
  delay(50);
}
 
void loop() {
  // Menținem intensitatea luminoasă activă
  analogWrite(pinLumina, 255);
 
  // --- Starea 1: Identificare Numar ---
  lcd.clear(); 
  delay(20);
  lcd.setCursor(0, 0); 
  lcd.print("BR 09 BIC BOSS");
  lcd.setCursor(0, 1); 
  lcd.print("BR 09 BIC BOSS");
  delay(2000);
 
  // --- Starea 2: Evaluare Proiect ---
  lcd.clear(); 
  delay(20);
  lcd.setCursor(0, 0); 
  lcd.print("NOTA 10");
  lcd.setCursor(0, 1); 
  lcd.print("NOTA 10");
  delay(2000);
 
  // --- Starea 3: Disciplina PM ---
  lcd.clear(); 
  delay(20);
  lcd.setCursor(0, 0); 
  lcd.print("    LINE FLW");
  lcd.setCursor(0, 1); 
  lcd.print(" PROIECT PM      ");
  delay(2000);
}

 Vedere de ansamblu hardware robot

2. Firmware Control Robot și Siguranță (Arduino Uno)

Placa Arduino Uno rulează algoritmul principal cu o frecvență ridicată de eșantionare. În cadrul buclei `loop()`, prioritatea absolută o are modulul de evitare a coliziunilor.

Funcția `citesteDistanta()` generează un trigger digital scurt de 10 microsecunde către senzorul HC-SR04, determinând emisia unui pachet de unde sonore la 40 kHz. Microcontrolerul contorizează durata pulsului întors pe pinul `Echo` cu ajutorul funcției `pulseIn()`. Distanța se calculează pe baza vitezei sunetului în aer ($\approx 0.0343\text{ cm/µs}$): $$distanta = \frac{durata \times 0.0343}{2}$$

Dacă distanța scade sub pragul critic de 20 cm, execuția codului de navigare este întreruptă forțat prin comanda `return;`. Robotul oprește punțile H și trece în starea de alertă, activând buzzerul într-o cadență de tip sirenă (100 ms pornit / 100 ms oprit). Când traseul este eliberat, robotul revine la citirea senzorilor infraroșu și corectează deplasarea pe linie folosind pinii de direcție ai driverului.

line_follower_core.ino
// Alocare pini driver motoare L298N
const int ENA = 6; const int IN1 = 7; const int IN2 = 8;
const int ENB = 5; const int IN3 = 9; const int IN4 = 10;
 
// Alocare pini senzori optici reflectivi
const int IRSensorLeft = 12; const int IRSensorRight = 11;
 
// Alocare pini senzor ultrasonic si alarma acustica
const int trigPin = 3; const int echoPin = 4;
const int buzzerPin = 2;
 
// Setare constante viteza prin factor de umplere PWM
#define s 80 
#define t 80 
 
void setup() {
  pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
  pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
 
  pinMode(IRSensorLeft, INPUT); pinMode(IRSensorRight, INPUT);
 
  pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
 
  Serial.begin(9600);
}
 
void loop() {
  // 1. Prioritate Siguranta: Verificare obstacole
  long distanta = citesteDistanta();
 
  if (distanta > 0 && distanta < 20) { 
    stopMotors();
    // Alarma sacadata de proximitate
    digitalWrite(buzzerPin, HIGH); delay(100);
    digitalWrite(buzzerPin, LOW);  delay(100);
    return; // Blocam restul executiei din loop
  } else {
    digitalWrite(buzzerPin, LOW);
  }
 
  // 2. Algoritm urmarire linie neagra
  bool leftSensor = digitalRead(IRSensorLeft);
  bool rightSensor = digitalRead(IRSensorRight);
 
  if (leftSensor == HIGH && rightSensor == HIGH)      { moveForward(); }
  else if (leftSensor == HIGH && rightSensor == LOW)  { turnRight(); }
  else if (leftSensor == LOW && rightSensor == HIGH) { turnLeft(); }
  else                                                { stopMotors(); }
 
  delay(50); 
}
 
long citesteDistanta() {
  digitalWrite(trigPin, LOW); delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long durata = pulseIn(echoPin, HIGH, 30000); // Timeout la 30ms
  return durata * 0.034 / 2;
}
 
void moveForward() {
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); analogWrite(ENA, s);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); analogWrite(ENB, s);
}
 
void turnRight() {
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); analogWrite(ENA, t);
  digitalWrite(IN3, LOW);  digitalWrite(IN4, LOW);  analogWrite(ENB, 0);
}
 
void turnLeft() {
  digitalWrite(IN1, LOW);  digitalWrite(IN2, LOW);  analogWrite(ENA, 0);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); analogWrite(ENB, t);
}
 
void stopMotors() {
  digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); analogWrite(ENA, 0);
  digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); analogWrite(ENB, 0);
}

4. Specificații și Calcule Electrice

Consumul de Curent al Etajului Logic

Pentru a asigura stabilitatea sistemului dual-MCU și a valida alegerea regulatorului hardware, am întocmit bilanțul energetic teoretic pe bara de alimentare de 5V în starea de sarcină maximă:

Calculul curentului cumulat pe magistrala de 5V: $$I_{total} = I_{uno} + I_{nano} + I_{logic\_lcd} + I_{backlight} + I_{sonar} + I_{ir} + I_{buzzer}$$ $$I_{total} = 45 + 30 + 1.1 + 100 + 15 + 20 + 15 = 226.1\text{ mA}$$

Calculul Disipării Termice pe Regulator

Regulatorul liniar intern (78M05) aflat pe driverul L298N reduce potențialul pachetului complet de baterii AA în serie ($12\text{V}$) la nivelul stabilizat de $5\text{V}$, preluând diferența de potențial și transformând-o în căldură. Puterea disipată ($P_d$) se determină cu formula studiată la curs:

$$P_d = (V_{in} - V_{out}) \times I_{total}$$

Înlocuind valorile parametrilor hardware folosiți în proiect: $$P_d = (12\text{V} - 5\text{V}) \times 0.2261\text{ A}$$ $$P_d = 7\text{V} \times 0.2261\text{ A} = 1.582\text{ W}$$

Valoarea de 1.582 W confirmă faptul că regulatorul în capsulă DPAK de pe placa driverului L298N lucrează în parametri siguri, fără risc de supraîncălzire critică sau intrare în protecție termică automată. Structurarea proiectului pe două microcontrollere oferă un avantaj major: izolarea completă a ecranului LCD garantează că zgomotul parazit inductiv generat de pornirea/oprirea motoarelor pe linia de alimentare nu va corupe datele trimise pe magistrala afișajului.