This shows you the differences between two versions of the page.
pm:prj2025:fstancu:alexandra.dinca2908 [2025/05/27 23:22] dan.vrinceanu [Software Design] |
pm:prj2025:fstancu:alexandra.dinca2908 [2025/05/28 01:49] (current) alexandra.dinca2908 |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Software Design ===== | + | ====== Mașină cu senzor de parcare și parcare automată - Dincă Alexandra-Cristina ====== |
- | ===Mediu de dezvoltare: Arduino IDE=== | + | Dincă Alexandra-Cristina, 334CD |
- | ===Descrierea flow-ului software:=== | + | ===== Introducere ===== |
- | Mașina funcționează în două moduri distincte, controlate din aplicația de pe smartphone (Dabble): | + | * Proiectul constă într-o mașină care, la comandă, începe să caute un loc de parcare. În funcție de spațiul găsit, decide dacă va realiza parcare paralelă sau cu spatele și, pe baza sistemului de parcare, va realiza manevrele fără coliziuni. Sistemul dispune de avertizări auditive pentru a informa //șoferul// asupra obstacolelor de la fiecare pas. În plus, mașina este dotată cu un LCD care afișează distanța până la coliziune în timpul parcării și temperatura când mașina este idle. |
- | Modul Manual (default la conectare) | + | * Scopul proiectului este de a simula un sistem de parcare autonomă al unei mașini. |
- | Modul Automat: Evitare obstacole + prăpastii | + | |
- | Starea 0 → Așteptare conectare Bluetooth (Idle): | + | * Ideea de la care am pornit a fost senzorul de parcare, după care am decis să dezvolt proiectul astfel încât mașina să se folosească de informațiile primite pentru a realiza și parcarea propriu-zisă. |
- | * La pornirea microcontrollerului, mașina așteaptă conectarea prin Bluetooth. | + | |
- | * Pe LCD se afișează mesajul: Conecteaza-te sefule | + | |
- | * Nicio mișcare nu este permisă până la stabilirea conexiunii. | + | |
- | Starea 1 → Mod Manual (Bluetooth GamePad activ): | + | |
- | * După conectare, mașina intră în Mod Manual, unde poate fi controlată de utilizator folosind aplicația Dabble. | + | |
- | * Se afișează pe LCD: Mod: Manual | + | |
- | * Direcțiile disponibile: | + | |
- | * ↑ - Mers înainte | + | |
- | * ↓ - Mers înapoi | + | |
- | * ← - Viraj la stânga | + | |
- | * → - Viraj la dreapta | + | |
- | * În lipsa unei comenzi, motoarele sunt oprite automat. | + | |
- | Starea 2 → Mod Automat (Evitare obstacole și prăpastii): | + | |
- | * Activat prin apăsarea butonului Triangle din aplicație. | + | |
- | * Comportament: | + | * Proiectul este util deoarece are aplicabilitate și în viața reală, ușurând procesul de parcare pentru șoferi. |
- | * Se afișează pe LCD: Mod: Obstacole+, Prapastii | + | ===== Descriere generală ===== |
- | * Se utilizează senzorul ultrasonic pentru detecția obstacolelor și senzorul IR pentru prăpastii. | + | |
- | * Dacă se detectează o prăpastie (senzor IR = LOW): | + | |
- | * Mașina oprește, dă înapoi și virează automat pentru a evita zona periculoasă. | + | |
- | * Mesaj pe LCD: Prapastie STOP | + | |
- | * Dacă se detectează un obstacol în față: | + | |
- | * Se măsoară distanțele din stânga și dreapta prin rotirea servomotorului. | + | |
- | * Se alege direcția cea mai liberă și se virează în acea parte. | + | |
- | * Mesaj pe LCD: Obstacol STOP | + | |
- | * Dacă drumul e liber: mașina merge înainte. | + | |
- | * Mesaj pe LCD: Drum liber | + | |
- | Starea 3 → Revenire la Manual: | + | |
- | * Apăsarea butonului Cross din aplicație dezactivează modul automat. | + | |
- | * Mașina oprește orice mișcare și revine în modul manual. | + | |
- | * LCD-ul afișează din nou: Mod: Manual | + | |
- | ===COD:=== | + | {{ :pm:prj2025:fstancu:schema_bloc_dinca_alexandra.png?300 |}} |
- | #define CUSTOM_SETTINGS | + | |
- | #define INCLUDE_GAMEPAD_MODULE | + | |
- | #include <DabbleESP32.h> | + | |
- | #include <ESP32Servo.h> | + | |
- | #include <NewPing.h> | + | |
- | #include <Wire.h> | + | |
- | #include <LiquidCrystal_I2C.h> | + | |
- | // LCD setup (SDA=25, SCL=26) | + | Alimentarea tuturor componentelor se face dintr-un stabilizator de 5V al unui driver. Cele 2 drivere sunt alimentate din sursă cu 7.5V. |
- | LiquidCrystal_I2C lcd(0x27, 16, 2); | + | |
- | // Motoare | + | Cele 4 motoare sunt controlate de câte 2 drivere (punte H dublă). Acestea împart pini de input și enable (In1, In2 cu In3, In4 si EnA cu EnB pe fiecare driver) pentru a economisi pini de pe Arduino si pentru că fiecare laterală a masinii primeste exact aceleași semnale. |
- | #define IN1 18 | + | |
- | #define IN2 19 | + | |
- | #define IN3 21 | + | |
- | #define IN4 22 | + | |
- | // Ultrasunete | + | Restul componentelor se conectează direct la plăcuță. |
- | #define TRIG_PIN 14 | + | * 2 senzori ultrasunete se conectează la pini digitali, iar al 3-lea la pini analogi (inițial voiam să îi conectez pe toți 3 la pini analogi, dar A4 și A5 interferează cu I2C, iar A1 este necesar senzorului de temperatură) |
- | #define ECHO_PIN 27 | + | * LCD I2C se conectează la SDA și SCL |
- | #define MAX_DISTANCE 200 | + | * butonul se conectează la un pin digital |
+ | * senzorul de temperatură se conectează la pin analog (A1) | ||
- | // Servomotor | + | ===== Hardware Design ===== |
- | #define SERVO_PIN 32 | + | |
- | // Senzor IR pentru margine/prăpastie | + | **Lista de piese:** |
- | #define IR_SENSOR_PIN 34 | + | |
- | // Configurări | + | ^ Componentă ^ Cantitate ^ Link ^ |
- | #define MAX_MOTOR_SPEED 255 | + | | Placă de plastic | 4 | https://www.optimusdigital.ro/ro/mecanica-accesorii-de-prindere/450-placa-din-plastic-cu-gaurigalbena.html?search_query=placa+de+plastic&results=39| |
- | #define TURN_SPEED 150 | + | | Motor cu reductor si roată | 4 | https://www.optimusdigital.ro/ro/motoare-altele/139-motor-cu-reductor-si-roata.html?search_query=wheel&results=33| |
- | #define OBSTACLE_DISTANCE 20 | + | | Punte H dublă L298N | 2 | https://www.optimusdigital.ro/ro/drivere-de-motoare-cu-perii/145-driver-de-motoare-dual-l298n.html?search_query=driver+modul+&results=151| |
+ | | Senzor ultrasunete HC SR-04P | 3 | https://sigmanortec.ro/Senzor-Ultrasunete-HC-SR-04P-3-5-5V-p148477760| | ||
+ | | Breadboard 400 puncte | 2 | https://sigmanortec.ro/Breadboard-400-puncte-p129872825| | ||
+ | | Placă de Dezvoltare Compatibilă cu Arduino UNO R3 (ATmega328p + ATmega16u2) | 1 | https://www.optimusdigital.ro/ro/placi-avr/4561-placa-de-dezvoltare-compatibila-cu-arduino-uno-r3-atmega328p-atmega16u2-cablu-50-cm.html?search_query=arduino+uno+r3&results=129| | ||
+ | | LCD 1602 cu interfață I2C | 1 | https://www.optimusdigital.ro/ro/optoelectronice-lcd-uri/2894-lcd-cu-interfata-i2c-si-backlight-albastru.html?search_query=lcd+i2c&results=17| | ||
+ | | Senzor de temperatură LM35D | 1 | https://www.optimusdigital.ro/ro/senzori/1469-senzor-de-temperatura-analogic-lm35d-to-92.html?search_query=lm35&results=2| | ||
+ | | Buzzer | 1 | https://sigmanortec.ro/Buzzer-activ-5v-p126421597| | ||
+ | | Butoane | 2 | https://sigmanortec.ro/buton-mini-6x6x5-4-pini| | ||
+ | | Suport de 6 baterii AA | 1 | https://www.optimusdigital.ro/ro/suporturi-de-baterii/941-suport-de-baterii-2-x-18650.html?search_query=suport&results=600| | ||
- | Servo myServo; | + | **Scheme electrice:** |
- | NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); | + | |
- | boolean goesForward = false; | + | Schemă circuit: |
- | boolean obstacleAvoidanceMode = false; | + | {{ :pm:prj2025:fstancu:schema_circuit_pm_dinca_alexandra.png?300 |}} |
- | int distance = 100; | + | |
- | int speedSet = 0; | + | |
- | void setUpPinModes() | + | Schema conține driver-ul L293D, dar proiectul folosește punte dublă H L298N. Am adaptat (dpdv schematic) L293D la L298N astfel încât să simuleze alimentarea plăcuței prin stablizator. Pinii sunt similari (4 in, 4 out, 2 enable), dar diferențele de conectare se pot observa în schemele următoare: |
- | { | + | |
- | pinMode(IN1, OUTPUT); | + | |
- | pinMode(IN2, OUTPUT); | + | |
- | pinMode(IN3, OUTPUT); | + | |
- | pinMode(IN4, OUTPUT); | + | |
- | pinMode(IR_SENSOR_PIN, INPUT); | + | |
- | myServo.attach(SERVO_PIN); | + | * Alimentarea Arduino se face direct din L298N, folosindu-se de stabilizatorul de 5V: |
- | myServo.write(90); | + | |
- | Serial.println("Servomotor inițiat la 90°"); | + | |
- | } | + | |
- | void moveForward() | + | {{ :pm:prj2025:fstancu:l298n_power_dinca_alexandra.png?300 |}} |
- | { | + | |
- | digitalWrite(IN1, HIGH); | + | |
- | digitalWrite(IN2, LOW); | + | |
- | digitalWrite(IN3, HIGH); | + | |
- | digitalWrite(IN4, LOW); | + | |
- | Serial.println("Înainte"); | + | |
- | } | + | |
- | void moveBackward() | + | * Conectarea pinilor (in + out + enables): |
- | { | + | |
- | digitalWrite(IN1, LOW); | + | |
- | digitalWrite(IN2, HIGH); | + | |
- | digitalWrite(IN3, LOW); | + | |
- | digitalWrite(IN4, HIGH); | + | |
- | Serial.println("Înapoi"); | + | |
- | } | + | |
- | void turnLeft() | + | {{ :pm:prj2025:fstancu:l298n_enables_dinca_alexandra.png?300 |}} |
- | { | + | |
- | digitalWrite(IN1, LOW); | + | |
- | digitalWrite(IN2, HIGH); | + | |
- | digitalWrite(IN3, HIGH); | + | |
- | digitalWrite(IN4, LOW); | + | |
- | Serial.println("Stânga"); | + | |
- | } | + | |
- | void turnRight() | ||
- | { | ||
- | digitalWrite(IN1, HIGH); | ||
- | digitalWrite(IN2, LOW); | ||
- | digitalWrite(IN3, LOW); | ||
- | digitalWrite(IN4, HIGH); | ||
- | Serial.println("Dreapta"); | ||
- | } | ||
- | void stopMotors() | + | **Asamblare hardware:** |
- | { | + | * Testare senzori ultrasunete, LCD, buzzer: https://youtu.be/x5yYTv9ybwY?si=-RUvqDohS8IVTNfX |
- | digitalWrite(IN1, LOW); | + | * Testare drivere L298N și motoare: https://youtube.com/shorts/KdDjAjdK4gs?si=r4qqvSIynApig93P |
- | digitalWrite(IN2, LOW); | + | ===== Software Design ===== |
- | digitalWrite(IN3, LOW); | + | |
- | digitalWrite(IN4, LOW); | + | |
- | Serial.println("Oprire"); | + | |
- | } | + | |
- | int readPing() | + | ===Mediu de dezvoltare: Arduino IDE=== |
- | { | + | |
- | delay(70); | + | |
- | int cm = sonar.ping_cm(); | + | |
- | if (cm == 0) | + | |
- | { | + | |
- | cm = MAX_DISTANCE; | + | |
- | } | + | |
- | Serial.print("Distanță: "); | + | |
- | Serial.print(cm); | + | |
- | Serial.println(" cm"); | + | |
- | return cm; | + | |
- | } | + | |
- | int lookRight() | + | ===Descrierea flow-ului software:=== |
- | { | + | |
- | myServo.write(50); | + | |
- | delay(500); | + | |
- | int distance = readPing(); | + | |
- | myServo.write(90); | + | |
- | return distance; | + | |
- | } | + | |
- | + | ||
- | int lookLeft() | + | |
- | { | + | |
- | myServo.write(130); | + | |
- | delay(500); | + | |
- | int distance = readPing(); | + | |
- | myServo.write(90); | + | |
- | return distance; | + | |
- | } | + | |
- | + | ||
- | void avoidObstacles() | + | |
- | { | + | |
- | int senzorIR = digitalRead(IR_SENSOR_PIN); // LOW = prăpastie | + | |
- | int distanceR = 0; | + | |
- | int distanceL = 0; | + | |
- | distance = readPing(); | + | |
- | + | ||
- | if (senzorIR == LOW) | + | |
- | { | + | |
- | stopMotors(); | + | |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("Prapastie STOP "); | + | |
- | delay(200); | + | |
- | + | ||
- | moveBackward(); | + | |
- | delay(400); | + | |
- | stopMotors(); | + | |
- | delay(200); | + | |
- | + | ||
- | turnLeft(); // Întoarcere completă | + | |
- | delay(700); | + | |
- | stopMotors(); | + | |
- | delay(200); | + | |
- | return; | + | |
- | } | + | |
- | + | ||
- | if (distance <= OBSTACLE_DISTANCE) | + | |
- | { | + | |
- | stopMotors(); | + | |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("Obstacol STOP "); | + | |
- | delay(100); | + | |
- | moveBackward(); | + | |
- | delay(300); | + | |
- | stopMotors(); | + | |
- | delay(200); | + | |
- | + | ||
- | distanceR = lookRight(); | + | |
- | delay(200); | + | |
- | distanceL = lookLeft(); | + | |
- | delay(200); | + | |
- | + | ||
- | if (distanceR >= distanceL) | + | |
- | { | + | |
- | turnRight(); | + | |
- | delay(500); | + | |
- | stopMotors(); | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | turnLeft(); | + | |
- | delay(500); | + | |
- | stopMotors(); | + | |
- | } | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | moveForward(); | + | |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("Drum liber "); | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | void setup() | + | |
- | { | + | |
- | Serial.begin(115200); | + | |
- | setUpPinModes(); | + | |
- | Dabble.begin("MyBluetoothCar"); | + | |
- | + | ||
- | Wire.begin(25, 26); // SDA, SCL | + | |
- | lcd.init(); | + | |
- | lcd.backlight(); | + | |
- | lcd.setCursor(0, 0); | + | |
- | lcd.print("Conecteaza-te"); | + | |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("sefule "); | + | |
- | + | ||
- | Serial.println("Dabble și LCD inițiate, aștept conectarea..."); | + | |
- | } | + | |
- | void loop() | + | Mașina stă default în modul idle, până la apasărea pe buton, moment în care se generează o întrerupere și se începe rutina de căutare a locului de parcare. |
- | { | + | |
- | Dabble.processInput(); | + | |
- | if (!Dabble.isAppConnected()) | + | * Starea 0 -> Idle: la pornirea μC-ului sau la revenirea în starea 0, se măsoară temperatura o dată și se afișează pe LCD |
- | { | + | * Starea 1 -> Căutare loc de parcare: mașina se mișcă în față și se folosește de senzorul lateral pentru a găsi locul și a determina ce tip de loc e. Când acesta detectează o adâncime de peste 20 de cm, începe să măsoare locul. După ce adâncimea laterală se micșorează, algoritmul aproximează lungimea locului de parcare pe baza timpului petrecut scanând. În funcție de lungime, determină dacă parcarea se va realiza lateral sau cu spatele. Senzorul din față are scopul de a opri mașina în cazul în care nu există loc și urmează să se producă o coliziune. |
- | lcd.setCursor(0, 0); | + | * Starea 2 -> Realizare parcare laterală: mașina face o rotație de 45 de grade, dă cu spatele până senzorul din spate detectează impact, și apoi se rotește -45 grade |
- | lcd.print("Conecteaza-te "); | + | * Starea 3 -> Realizare parcare cu spatele: mașina se poziționează corect (dând cu spatele puțin), se rotește 90 de grade, iar apoi dă cu spatele până când senzorul din spate detectează impact |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("sefule "); | + | |
- | delay(1000); | + | |
- | return; | + | |
- | } | + | |
- | static bool wasConnected = false; | + | ===GitHub:=== |
- | if (!wasConnected) | + | https://github.com/alexandradinca2908/Self-parking-car/ |
- | { | + | ===== Rezultate Obţinute ===== |
- | lcd.clear(); | + | |
- | lcd.setCursor(0, 0); | + | |
- | lcd.print("Mod: Manual"); | + | |
- | wasConnected = true; | + | |
- | } | + | |
- | // Activare mod evitare obstacole (include și prăpastie) | + | Parcare laterala: https://youtube.com/shorts/XJ7GHUrpqy0?si=_H5usa8ieqtIjbZN |
- | if (GamePad.isTrianglePressed()) | + | |
- | { | + | |
- | Serial.println("Mod obstacole+prapastie activat"); | + | |
- | obstacleAvoidanceMode = true; | + | |
- | lcd.clear(); | + | Parcare cu spatele: https://youtube.com/shorts/Ijl0gOAfbaM?si=Wpsz6emT9Ds-nGsz |
- | lcd.setCursor(0, 0); | + | |
- | lcd.print("Mod: Obstacole+"); | + | |
- | lcd.setCursor(0, 1); | + | |
- | lcd.print("Prapastii "); | + | |
- | } | + | |
- | // Dezactivare | + | ===== Concluzii ===== |
- | if (GamePad.isCrossPressed()) | + | |
- | { | + | |
- | Serial.println("Mod automat oprit, revenire la manual"); | + | |
- | obstacleAvoidanceMode = false; | + | |
- | stopMotors(); | + | |
- | lcd.clear(); | + | ===== Download ===== |
- | lcd.setCursor(0, 0); | + | |
- | lcd.print("Mod: Manual"); | + | |
- | } | + | |
- | if (obstacleAvoidanceMode) | + | <note warning> |
- | { | + | O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). |
- | avoidObstacles(); | + | |
- | return; | + | |
- | } | + | |
- | // Control manual | + | Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:prj20??:c?:nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin, 331CC -> **:pm:prj2009:cc:dumitru_alin**. |
- | if (GamePad.isUpPressed()) | + | </note> |
- | { | + | |
- | moveForward(); | + | |
- | } | + | |
- | else if (GamePad.isDownPressed()) | + | |
- | { | + | |
- | moveBackward(); | + | |
- | } | + | |
- | else if (GamePad.isLeftPressed()) | + | |
- | { | + | |
- | turnLeft(); | + | |
- | } | + | |
- | else if (GamePad.isRightPressed()) | + | |
- | { | + | |
- | turnRight(); | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | stopMotors(); | + | |
- | } | + | |
- | } | + | |