This shows you the differences between two versions of the page.
pm:prj2025:fstancu:dan.vrinceanu [2025/05/27 23:58] dan.vrinceanu [Software Design] |
pm:prj2025:fstancu:dan.vrinceanu [2025/05/28 09:28] (current) dan.vrinceanu [Main application flow] |
||
---|---|---|---|
Line 78: | Line 78: | ||
* LCD-ul afișează din nou: Mod: Manual | * LCD-ul afișează din nou: Mod: Manual | ||
- | ===== Main application flow===== | + | ==== Motivația Alegerii Bibliotecilor ==== |
+ | |||
+ | === Arduino Libraries === | ||
+ | |||
+ | ==== Motivația Alegerii Bibliotecilor ==== | ||
+ | |||
+ | === ESP32 Robotics Libraries === | ||
+ | |||
+ | #include <DabbleESP32.h> // Control Bluetooth cu aplicația mobilă Dabble (GamePad virtual) | ||
+ | #include <ESP32Servo.h> // Compatibilitate PWM pentru control precis al servomotoarelor pe ESP32 | ||
+ | #include <NewPing.h> // Măsurători rapide și stabile cu senzorul ultrasonic HC-SR04 | ||
+ | #include <Wire.h> // Comunicație I²C între ESP32 și periferice | ||
+ | #include <LiquidCrystal_I2C.h> // Afișare text pe LCD 16x2 cu interfață I²C | ||
+ | |||
+ | Justificare: | ||
+ | Am ales aceste biblioteci pentru a realiza un sistem robotic autonom cu control manual prin Bluetooth și feedback vizual. | ||
+ | |||
+ | - `DabbleESP32` permite interacțiunea prin aplicația mobilă fără componente fizice externe. | ||
+ | - `ESP32Servo` este necesară pentru compatibilitate cu PWM-ul specific ESP32, esențial în orientarea senzorului ultrasonic. | ||
+ | - `NewPing` asigură măsurători eficiente ale distanței fără blocaje, utile pentru evitarea obstacolelor. | ||
+ | - `Wire` este standard pentru comunicație I²C, permițând integrarea simplă a mai multor senzori sau afișaje. | ||
+ | - `LiquidCrystal_I2C` oferă un mod convenabil de a afișa mesaje de stare, diagnostic sau feedback pentru utilizator. | ||
+ | |||
+ | ==== Laboratoarele ==== | ||
+ | |||
+ | === Laboratorul 0: GPIO === | ||
+ | Folosit pentru controlul pinilor digitali – pornirea/opirea motoarelor, citirea stării senzorului IR. | ||
+ | |||
+ | === Laboratorul 1: UART === | ||
+ | Utilizat pentru comunicarea serială cu computerul prin Serial.begin() – afişează mesaje de stare și debug. | ||
+ | |||
+ | === Laboratorul 3: Timere. PWM === | ||
+ | PWM este folosit pentru a controla poziția servomotorului (ex: rotirea senzorului ultrasonic pentru detectarea obstacolelor). | ||
+ | |||
+ | === Laboratorul 6: I2C === | ||
+ | |||
+ | Folosit pentru comunicarea cu ecranul LCD 1602 prin interfața I2C – afişează mesaje despre obstacole, prăpastii sau conexiunea cu aplicația. | ||
+ | |||
+ | ==== Element de Noutate al Proiectului ==== | ||
+ | |||
+ | Integrarea controlului manual prin Bluetooth (Dabble) cu un sistem autonom de evitare a obstacolelor și prăpastiilor. | ||
+ | Robotul poate schimba direcția și viteza în timp real, oferind feedback pe LCD și folosind un servomotor pentru scanare laterală. | ||
+ | Această combinație de autonomie și interactivitate mobilă face proiectul versatil și inovator. | ||
+ | |||
+ | ==== Calibrarea senzorilor ==== | ||
+ | Senzor ultrasonic (HC-SR04) | ||
+ | Am setat o distanță maximă de detecție (200 cm) și un prag pentru obstacol (20 cm). | ||
+ | Am testat valorile în monitorul serial pentru a verifica funcționarea corectă. | ||
+ | Senzor IR | ||
+ | Am calibrat detectarea marginii ca semnal LOW. | ||
+ | Am verificat comportamentul apropiind senzorul de o margine (ex. masă). | ||
+ | Servomotor + senzor ultrasonic | ||
+ | Am setat unghiuri fixe (50° și 130°) pentru scanare laterală. | ||
+ | Am verificat că senzorul măsoară distanța corect în ambele direcții. | ||
+ | |||
+ | |||
+ | ===== Main application flow ===== | ||
**Setup** | **Setup** | ||
- | * Initializează comunicația serială la 115200 baud. | + | * Inițializează comunicația serială la 115200 baud. |
- | * Configurează pinii pentru motoare, senzor IR, ultrasunete și servomotor. | + | * Configurează pinurile pentru: |
- | * Atașează servomotorul și îl setează la poziția de mijloc (90°). | + | - Motoare (IN1, IN2, IN3, IN4) |
- | * Pornește conexiunea Bluetooth cu Dabble (`Dabble.begin`). | + | - Senzor IR (prăpastie) |
- | * Inițializează LCD-ul I2C (pe pini SDA = 25, SCL = 26). | + | - Ultrasunete (TRIG, ECHO) |
- | * Afișează mesaj de așteptare pe ecran. | + | - Servomotor (SERVO_PIN) |
+ | * Atașează servomotorul și îl poziționează inițial la 90°. | ||
+ | * Inițializează conexiunea Bluetooth cu aplicația Dabble. | ||
+ | * Configurează magistrala I2C (Wire.begin) pentru LCD. | ||
+ | * Inițializează LCD-ul (16x2) și aprinde lumina de fundal. | ||
+ | * Afișează mesaj pe ecran: "Conecteaza-te, sefule". | ||
<code cpp> | <code cpp> | ||
Line 106: | Line 167: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | --- | ||
**Main Loop** | **Main Loop** | ||
- | * Procesează comenzile din aplicația Dabble (Bluetooth). | + | * Procesează comenzile de la Dabble. |
* Dacă aplicația nu e conectată: | * Dacă aplicația nu e conectată: | ||
- | - Afișează mesaj de conectare și așteaptă. | + | - Afișează mesaj și iese temporar din buclă. |
* La prima conectare: | * La prima conectare: | ||
- | - Afișează pe LCD "Mod: Manual". | + | - Afișează "Mod: Manual" pe LCD. |
- | * Dacă se apasă butonul Triunghi (▲): | + | * Dacă se apasă Triunghi (▲): |
- | - Activează modul de evitare a obstacolelor și prăpastiei. | + | - Activează modul automat (evitarea obstacolelor + margini). |
- | * Dacă se apasă butonul X (✖): | + | * Dacă se apasă X (✖): |
- Dezactivează modul automat și revine la control manual. | - Dezactivează modul automat și revine la control manual. | ||
- | * În modul automat: | + | * Dacă modul automat este activ: |
- | - Apelează funcția `avoidObstacles()`: | + | - Apelează `avoidObstacles()` și iese din `loop`. |
- | - Verifică senzorul IR pentru margine. | + | * Altfel: |
- | - Măsoară distanța cu senzorul cu ultrasunete. | + | - Controlează robotul în mod **manual** cu D-pad: |
- | - Decide dacă merge înainte sau se întoarce. | + | - ▲ = înainte |
- | * În modul manual: | + | - ▼ = înapoi |
- | - Controlează mișcările cu D-pad-ul (↑ ↓ ← →). | + | - ◄ = stânga |
- | - În absența comenzilor, oprește motoarele. | + | - ► = dreapta |
+ | - Nimic = oprește | ||
<code cpp> | <code cpp> | ||
Line 150: | Line 214: | ||
} | } | ||
- | // Activare mod evitare obstacole și prăpastii | ||
if (GamePad.isTrianglePressed()) | if (GamePad.isTrianglePressed()) | ||
{ | { | ||
Line 163: | Line 226: | ||
} | } | ||
- | // Dezactivare mod automat | ||
if (GamePad.isCrossPressed()) | if (GamePad.isCrossPressed()) | ||
{ | { | ||
Line 181: | Line 243: | ||
} | } | ||
- | // Control manual | + | if (GamePad.isUpPressed()) moveForward(); |
- | if (GamePad.isUpPressed()) | + | else if (GamePad.isDownPressed()) moveBackward(); |
+ | else if (GamePad.isLeftPressed()) turnLeft(); | ||
+ | else if (GamePad.isRightPressed()) turnRight(); | ||
+ | else stopMotors(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | --- | ||
+ | |||
+ | **Auxiliary Functions** | ||
+ | |||
+ | <code cpp> | ||
+ | // Configurează toate pinurile relevante și inițializează servomotorul. | ||
+ | void setUpPinModes() | ||
+ | { | ||
+ | pinMode(IN1, OUTPUT); | ||
+ | pinMode(IN2, OUTPUT); | ||
+ | pinMode(IN3, OUTPUT); | ||
+ | pinMode(IN4, OUTPUT); | ||
+ | pinMode(IR_SENSOR_PIN, INPUT); | ||
+ | |||
+ | myServo.attach(SERVO_PIN); | ||
+ | myServo.write(90); | ||
+ | Serial.println("Servomotor inițiat la 90°"); | ||
+ | } | ||
+ | |||
+ | // Mișcări de bază pentru robot: | ||
+ | void moveForward() | ||
+ | { | ||
+ | GPIO.out_w1ts = (1 << IN1) | (1 << IN3); // Set IN1 și IN3 HIGH | ||
+ | GPIO.out_w1tc = (1 << IN2) | (1 << IN4); // Set IN2 și IN4 LOW | ||
+ | Serial.println("Înainte"); | ||
+ | } | ||
+ | |||
+ | void moveBackward() | ||
+ | { | ||
+ | GPIO.out_w1ts = (1 << IN2) | (1 << IN4); // Set IN2 și IN4 HIGH | ||
+ | GPIO.out_w1tc = (1 << IN1) | (1 << IN3); // Set IN1 și IN3 LOW | ||
+ | Serial.println("Înapoi"); | ||
+ | } | ||
+ | |||
+ | void turnLeft() | ||
+ | { | ||
+ | GPIO.out_w1ts = (1 << IN2) | (1 << IN3); // IN2 și IN3 HIGH | ||
+ | GPIO.out_w1tc = (1 << IN1) | (1 << IN4); // IN1 și IN4 LOW | ||
+ | Serial.println("Stânga"); | ||
+ | } | ||
+ | |||
+ | void turnRight() | ||
+ | { | ||
+ | GPIO.out_w1ts = (1 << IN1) | (1 << IN4); // IN1 și IN4 HIGH | ||
+ | GPIO.out_w1tc = (1 << IN2) | (1 << IN3); // IN2 și IN3 LOW | ||
+ | Serial.println("Dreapta"); | ||
+ | } | ||
+ | |||
+ | void stopMotors() | ||
+ | { | ||
+ | GPIO.out_w1tc = (1 << IN1) | (1 << IN2) | (1 << IN3) | (1 << IN4); // Toți LOW | ||
+ | Serial.println("Oprire"); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | --- | ||
+ | |||
+ | **Sensor and Navigation Functions** | ||
+ | |||
+ | <code cpp> | ||
+ | // Returnează distanța măsurată cu ultrasunete. | ||
+ | int readPing() | ||
+ | { | ||
+ | delay(70); | ||
+ | int cm = sonar.ping_cm(); | ||
+ | if (cm == 0) cm = MAX_DISTANCE; | ||
+ | |||
+ | Serial.print("Distanță: "); | ||
+ | Serial.print(cm); | ||
+ | Serial.println(" cm"); | ||
+ | return cm; | ||
+ | } | ||
+ | |||
+ | // Rotește servomotorul spre dreapta, măsoară, revine. | ||
+ | int lookRight() | ||
+ | { | ||
+ | myServo.write(50); | ||
+ | delay(500); | ||
+ | int distance = readPing(); | ||
+ | myServo.write(90); | ||
+ | return distance; | ||
+ | } | ||
+ | |||
+ | // Rotește servomotorul spre stânga, măsoară, revine. | ||
+ | int lookLeft() | ||
+ | { | ||
+ | myServo.write(130); | ||
+ | delay(500); | ||
+ | int distance = readPing(); | ||
+ | myServo.write(90); | ||
+ | return distance; | ||
+ | } | ||
+ | |||
+ | // Evită obstacole și margini. Apelată în mod automat. | ||
+ | void avoidObstacles() | ||
+ | { | ||
+ | int senzorIR = digitalRead(IR_SENSOR_PIN); // LOW = prăpastie | ||
+ | int distanceR = 0; | ||
+ | int distanceL = 0; | ||
+ | distance = readPing(); | ||
+ | |||
+ | if (senzorIR == LOW) | ||
{ | { | ||
- | moveForward(); | + | 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; | ||
} | } | ||
- | else if (GamePad.isDownPressed()) | + | |
+ | if (distance <= OBSTACLE_DISTANCE) | ||
{ | { | ||
+ | stopMotors(); | ||
+ | lcd.setCursor(0, 1); | ||
+ | lcd.print("Obstacol STOP "); | ||
+ | delay(100); | ||
moveBackward(); | moveBackward(); | ||
- | } | + | delay(300); |
- | else if (GamePad.isLeftPressed()) | + | stopMotors(); |
- | { | + | delay(200); |
- | turnLeft(); | + | |
- | } | + | distanceR = lookRight(); |
- | else if (GamePad.isRightPressed()) | + | delay(200); |
- | { | + | distanceL = lookLeft(); |
- | turnRight(); | + | delay(200); |
+ | |||
+ | if (distanceR >= distanceL) | ||
+ | { | ||
+ | turnRight(); | ||
+ | delay(500); | ||
+ | stopMotors(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | turnLeft(); | ||
+ | delay(500); | ||
+ | stopMotors(); | ||
+ | } | ||
} | } | ||
else | else | ||
{ | { | ||
- | stopMotors(); | + | moveForward(); |
+ | lcd.setCursor(0, 1); | ||
+ | lcd.print("Drum liber "); | ||
} | } | ||
} | } | ||
Line 209: | Line 413: | ||
{{:pm:prj2025:fstancu:img_2149.jpg?260|}} | {{:pm:prj2025:fstancu:img_2149.jpg?260|}} | ||
} | } | ||
+ | ===== VIDEO ===== | ||
+ | https://www.youtube.com/shorts/16-T-_LEwkY | ||
+ | |||
===== Rezultate Obţinute ===== | ===== Rezultate Obţinute ===== | ||
{{:pm:prj2025:fstancu:img_dan1.jpg?307|}} | {{:pm:prj2025:fstancu:img_dan1.jpg?307|}} | ||
Line 215: | Line 422: | ||
===== Concluzii ===== | ===== Concluzii ===== | ||
+ | Acest proiect este un robot autonom controlabil prin Bluetooth, capabil să evite obstacole și prăpastii cu ajutorul senzorilor, oferind în același timp control manual precis prin aplicația Dabble. Este o combinație reușită între inteligență integrată, interfață prietenoasă și control adaptiv al motoarelor. | ||
===== Download ===== | ===== Download ===== | ||
- | + | {{:pm:prj2025:fstancu:bluetoothcar_v1.1_vrinceanu.zip|}} | |
- | <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ă ;-). | + | |
- | + | ||
- | 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**. | + | |
- | </note> | + | |
- | + | ||
- | ===== Jurnal ===== | + | |
- | + | ||
- | <note tip> | + | |
- | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | |
- | </note> | + | |
===== Bibliografie/Resurse ===== | ===== Bibliografie/Resurse ===== | ||
- | <note> | + | LCD Help: |
- | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | https://www.youtube.com/watch?v=860eErq9c3E> |
- | </note> | + | |
- | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | + | Piese: |
+ | https://sigmanortec.ro | ||
+ | https://www.optimusdigital.ro/ro/ | ||