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/ | ||