Mașina așteaptă comenzi prin Bluetooth de pe smartphone. Odată primită o comandă, aceasta ajunge prin HC-05 la microcontroller, care o traduce în semnale către driver-ul L298N (PWM pentru viteză și GPIO pentru direcție), punând cele 4 motoare în mișcare. Pentru viraj, motoarele de pe o parte se rotesc mai repede decât cele de pe cealaltă.
Senzorul ultrasonic rulează în permanență în fundal. Dacă detectează un obstacol prea aproape în față, microcontrollerul ignoră automat orice comandă de mers înainte, obligând utilizatorul să schimbe direcția. Când drumul e liber, mașina răspunde din nou normal la toate comenzile.
| Periferic Conectat | Pin ATmega328P | Pin Periferic | Direcție Semnal |
|---|---|---|---|
| Modul Bluetooth HC-05 | PD0 (RX) | TXD | Intrare |
| PD1 (TX) | RXD | Ieșire | |
| Senzor HC-SR04 | PD2 | Trig | Ieșire |
| PD3 | Echo | Intrare | |
| Driver L298N | PD5 | IN1 | Ieșire |
| PD6 | IN2 | Ieșire | |
| PB1 | IN3 | Ieșire | |
| PB2 | IN4 | Ieșire |
Schema electrică arată cum sunt legate toate componentele în jurul microcontrollerului ATmega328P.
Pentru alimentare, am folosit 4 baterii AA (6V) conectate direct la pinul de 12V al driverului L298N, de unde își iau curent motoarele. Regulatorul intern de pe driver reduce această tensiune la 5V pentru a alimenta microcontrollerul, modulul Bluetooth și senzorul ultrasonic. Toate componentele din circuit împart aceeași masă comună (GND).
Pe partea de date, legăturile respectă exact tabelul de pinout. Modulul Bluetooth comunică serial prin pinii PD0 și PD1 (conectați la TXD/RXD). Senzorul de distanță folosește pinii PD2 (Trig) și PD3 (Echo) pentru a trimite și primi semnalele folosite la evitarea obstacolelor. Driverul L298N primește comenzile de direcție prin pinii IN1-IN4 (legați la pini de pe plăcuță ce permit folosirea PWM, pentru a controla manual viteza), iar ieșirile lui (OUT1-OUT4) controlează cele 4 motoare ale șasiului, fiind legate în paralel câte două pentru fiecare lateral al mașinii.
Mașina asamblată arată ca în imaginile de mai jos. Un demo în care se poate observa că funcționează toate componentele se poate găsi aici.
Codul a fost scris în C++ folosind extensia PlatformIO din Visual Studio Code. Singura bibliotecă third-party folosită este Arduino.h, care oferă funcțiile de bază pentru interacțiunea cu pinii microcontrollerului (digitalWrite, analogWrite, pinMode, millis etc.), cât și pentru comunicarea cu modulul HC-05 prin portul UART hardware al ATmega328P.
Codul este organizat în jurul unui automat de stări simplu, bazat pe variabila currentCommand, care reține ultima comandă validă primită prin Bluetooth. În fiecare iterație a loop(), microcontrollerul procesează orice comandă nouă sosită, citește distanța față de obstacole și execută acțiunea corespunzătoare sau declanșează evitarea autonomă dacă e cazul.
Funcțiile principale sunt:
setForwardSpeed(), setBackwardSpeed(), turnLeft(), turnRight(), stopCar() — controlează direcția și viteza motoarelor prin semnale PWM și GPIO către driverul L298NreadDistance() — trimite un puls pe TRIG și măsoară durata echo-ului pe ECHO_PIN folosind pulseIn(), convertind rezultatul în centimetrireadDistanceStable() — apelează readDistance() de 3 ori și returnează media citirilor valide, ignorând citirile eronatehandleAcceleration() — incrementează currentSpeed progresiv la fiecare iterație folosind millis(), fără a bloca execuția cu delay()autonomousEvasion() — oprește mașina, merge înapoi până când distanța față de obstacol depășește SAFE_DISTANCE sau se atinge un timeout de siguranță, după care apelează scanAndAlign()scanAndAlign() — rotește mașina spre stânga, măsoară distanța, apoi spre dreapta, măsoară din nou, și se orientează spre direcția cu mai mult spațiu disponibilserialEvent() — funcție apelată automat de framework după fiecare iterație a loop() când au sosit date pe UART, validează comanda primită și o pune într-un buffer volatil Elementul care diferențiază acest proiect de o mașină RC simplă este mecanismul de evitare autonomă a obstacolelor. Când mașina detectează un obstacol la mai puțin de 15cm în față în timp ce primește comanda de mers înainte, preia controlul autonom: se oprește, merge înapoi până ajunge la o distanță sigură, scanează stânga și dreapta și se orientează spre direcția cu mai mult spațiu. După finalizarea manevrei, returnează controlul utilizatorului. Un alt element notabil este accelerarea progresivă la pornire, care simulează comportamentul unei mașini reale.
serialEvent(), care este apelată automat de framework pe baza întreruperii hardware USART_RX, imediat după fiecare iterație a loop(); comenzile sunt validate și puse într-un buffer volatil, decuplând recepția de execuția propriu-zisăanalogWrite() este folosit pe pinii PD5, PD6, PB1, PB2 pentru a controla viteza motoarelor; millis() este folosit în handleAcceleration() pentru a incrementa viteza non-blocantPragurile de distanță au fost determinate experimental. Threshold-ul de oprire a fost setat la 15cm — suficient de aproape ca mașina să nu se oprească prea devreme, dar suficient de departe ca motoarele să aibă timp să se oprească înainte de impact. Distanța de siguranță pentru terminarea manevrei de evitare a fost setată la 30cm, oferind suficient spațiu după ce mașina a ieșit din zona de pericol. Citirea distanței se face ca medie a 3 măsurători consecutive pentru a elimina ecourile false ale senzorului HC-SR04.
loop(), astfel încât comenzile să fie preluate imediat, fără să aștepte finalizarea celor 3 citiri ale senzorului.millis() în loc de delay(), astfel încât senzorul și UART-ul să fie în continuare procesate în timp ce viteza crește.serialEvent() înainte de a fi acceptate — doar caracterele din setul FBLRS sunt procesate, ignorând zgomotul de pe linie.Un demo video al proiectului poate fi găsit aici.
Pentru testare, codul proiectului poate fi gasit în acest repo.