This shows you the differences between two versions of the page.
pm:prj2025:fstancu:dan.vrinceanu [2025/05/27 23:51] dan.vrinceanu [Rezultate Obţinute] |
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 | ||
- | ===GitHub:=== | + | ==== Motivația Alegerii Bibliotecilor ==== |
- | https://github.com/ | + | |
+ | === 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** | ||
+ | * Inițializează comunicația serială la 115200 baud. | ||
+ | * Configurează pinurile pentru: | ||
+ | - Motoare (IN1, IN2, IN3, IN4) | ||
+ | - Senzor IR (prăpastie) | ||
+ | - Ultrasunete (TRIG, ECHO) | ||
+ | - 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> | ||
+ | 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..."); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | --- | ||
+ | |||
+ | **Main Loop** | ||
+ | * Procesează comenzile de la Dabble. | ||
+ | * Dacă aplicația nu e conectată: | ||
+ | - Afișează mesaj și iese temporar din buclă. | ||
+ | * La prima conectare: | ||
+ | - Afișează "Mod: Manual" pe LCD. | ||
+ | * Dacă se apasă Triunghi (▲): | ||
+ | - Activează modul automat (evitarea obstacolelor + margini). | ||
+ | * Dacă se apasă X (✖): | ||
+ | - Dezactivează modul automat și revine la control manual. | ||
+ | * Dacă modul automat este activ: | ||
+ | - Apelează `avoidObstacles()` și iese din `loop`. | ||
+ | * Altfel: | ||
+ | - Controlează robotul în mod **manual** cu D-pad: | ||
+ | - ▲ = înainte | ||
+ | - ▼ = înapoi | ||
+ | - ◄ = stânga | ||
+ | - ► = dreapta | ||
+ | - Nimic = oprește | ||
+ | |||
+ | <code cpp> | ||
+ | void loop() | ||
+ | { | ||
+ | Dabble.processInput(); | ||
+ | |||
+ | if (!Dabble.isAppConnected()) | ||
+ | { | ||
+ | lcd.setCursor(0, 0); | ||
+ | lcd.print("Conecteaza-te "); | ||
+ | lcd.setCursor(0, 1); | ||
+ | lcd.print("sefule "); | ||
+ | delay(1000); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | static bool wasConnected = false; | ||
+ | if (!wasConnected) | ||
+ | { | ||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0, 0); | ||
+ | lcd.print("Mod: Manual"); | ||
+ | wasConnected = true; | ||
+ | } | ||
+ | |||
+ | if (GamePad.isTrianglePressed()) | ||
+ | { | ||
+ | Serial.println("Mod obstacole+prapastie activat"); | ||
+ | obstacleAvoidanceMode = true; | ||
+ | |||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0, 0); | ||
+ | lcd.print("Mod: Obstacole+"); | ||
+ | lcd.setCursor(0, 1); | ||
+ | lcd.print("Prapastii "); | ||
+ | } | ||
+ | |||
+ | if (GamePad.isCrossPressed()) | ||
+ | { | ||
+ | Serial.println("Mod automat oprit, revenire la manual"); | ||
+ | obstacleAvoidanceMode = false; | ||
+ | stopMotors(); | ||
+ | |||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0, 0); | ||
+ | lcd.print("Mod: Manual"); | ||
+ | } | ||
+ | |||
+ | if (obstacleAvoidanceMode) | ||
+ | { | ||
+ | avoidObstacles(); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if (GamePad.isUpPressed()) moveForward(); | ||
+ | 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) | ||
+ | { | ||
+ | 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 "); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
{{:pm:prj2025:fstancu:img_2148.jpg?300|}} | {{:pm:prj2025:fstancu:img_2148.jpg?300|}} | ||
{{: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?305|}} | + | {{:pm:prj2025:fstancu:img_dan1.jpg?307|}} |
{{:pm:prj2025:fstancu:img_dan2.jpg?300|}} | {{:pm:prj2025:fstancu:img_dan2.jpg?300|}} | ||
===== 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/ | ||