This shows you the differences between two versions of the page.
pm:prj2025:fstancu:veaceslav.safronii [2025/05/19 01:44] veaceslav.safronii [Hardware Design] |
pm:prj2025:fstancu:veaceslav.safronii [2025/05/30 00:05] (current) veaceslav.safronii [Rezultate Obţinute] |
||
---|---|---|---|
Line 22: | Line 22: | ||
===== Hardware Design ===== | ===== Hardware Design ===== | ||
- | {{:pm:prj2025:fstancu:sch_safronii_veaceslav.png?800|}} | + | {{:pm:prj2025:fstancu:sch1_safronii_veaceslav.png?700|}} |
+ | |||
+ | Sistemul este alimentat de un **acumulator Li-Po 103450** de 3.7V, care este conectat la un **modul de încărcare TP4056**, responsabil pentru încărcarea sigură a bateriei printr-un port USB-C. Ieșirea modulului TP4056 este conectată la un **ridicător de tensiune MT3608**, care converteste tensiunea de 3.7V la 5V, necesară pentru alimentarea **plăcii ESP32-WROOM-32** prin pinul VIN. | ||
+ | |||
+ | **Senzorul de mișcare MPU6050**, care integrează un accelerometru și un giroscop pe 3 axe, este conectat la ESP32 prin **interfața I²C** – folosind pinii SDA (GPIO 21) și SCL (GPIO 22). Acest senzor permite detectarea orientării și mișcării mâinii, informație esențială pentru aplicația glove-based. | ||
+ | |||
+ | Pentru interacțiunea utilizatorului, sistemul include două **butoane tactile**, conectate la **pinii GPIO** ai ESP32 (GPIO 34 și 35), folosind rezistențele de pull-up interne. | ||
**Piese:** | **Piese:** | ||
- | * ESP32-WROOM-32 | + | ^ Componentă ^ Descriere / Observație ^ |
- | * Sensor cu giroscop și accelerometru MPU6050 | + | | ESP32-WROOM-32 Devkit v1 | Placă de dezvoltare cu WiFi și Bluetooth | |
- | * Modul de încărcare TP4056 | + | | Sensor cu giroscop și accelerometru | MPU6050 – comunicare I²C | |
- | * Ridicător de tensiune MT3608 | + | | Modul de încărcare | TP4056 – pentru baterii Li-Ion/Li-Po | |
- | * Acumulator litiu-polimer 103450 | + | | Ridicător de tensiune | MT3608 – boost la 5V pentru ESP32 | |
- | * Butoane tactile | + | | Acumulator litiu-polimer | 103450 – 3.7V, 2000mAh | |
- | * Placa de prototipare cablaj | + | | Butoane tactile | Pentru input manual | |
+ | | Placa de prototipare cablaj | PCB | | ||
+ | |||
+ | |||
+ | |||
+ | {{:pm:prj2025:fstancu:proiect_poza_glove.jpg?400|}} | ||
===== Software Design ===== | ===== Software Design ===== | ||
- | <note tip> | ||
- | Descrierea codului aplicaţiei (firmware): | ||
- | * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) | ||
- | * librării şi surse 3rd-party (e.g. Procyon AVRlib) | ||
- | * algoritmi şi structuri pe care plănuiţi să le implementaţi | ||
- | * (etapa 3) surse şi funcţii implementate | ||
- | </note> | ||
- | ===== Rezultate Obţinute ===== | + | **Mediu de dezvoltare** |
- | <note tip> | + | - **PlatformIO** - Mediu integrat de dezvoltare (IDE) bazat pe Visual Studio Code, specializat pentru dezvoltarea sistemelor embedded |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | - **Framework-ul Arduino** pentru ESP32, care oferă un strat de abstractizare peste SDK-ul nativ ESP-IDF |
- | </note> | + | |
- | ===== Concluzii ===== | + | **Librării și surse third-party** |
- | ===== Download ===== | + | - **Biblioteca BLE Arduino** - Implementarea oficială a stivei Bluetooth Low Energy pentru ESP32 |
+ | - **Biblioteca MPU6050** - Adaptată și optimizată pentru comunicarea directă I2C cu senzorul de mișcare | ||
+ | - **Bleak** - Bibliotecă Python cross-platform pentru comunicarea Bluetooth Low Energy folosită în aplicația receptor | ||
- | <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**. | + | **Algoritmi și structuri implementate** |
- | </note> | + | |
- | ===== Jurnal ===== | + | **1. Structura modulară a firmware-ului** |
- | <note tip> | + | Codul firmware-ului a fost organizat în module funcționale pentru o mai bună întreținere și scalabilitate: |
- | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | |
- | </note> | + | * **__main.cpp__** - Punct de intrare, inițializare și bucla principală |
+ | * **__config.h__** - Constante, definiri și configurație globală | ||
+ | * **__ble_manager__** - Gestionarea comunicației Bluetooth Low Energy | ||
+ | * **__i2c_interface__** - Implementarea protocolului I2C pentru comunicare cu senzori | ||
+ | * **__mpu6050__** - Comunicare și procesare date de la senzorul inerțial MPU6050 | ||
+ | * **__controller__** - Logica de control și mapare a gesturilor la acțiuni | ||
+ | |||
+ | **Inițializarea și configurarea ESP32** | ||
+ | <code> | ||
+ | void setup() { | ||
+ | Serial.begin(SERIAL_BAUD_RATE); | ||
+ | Serial.println("Wireless Glove Controller initializing..."); | ||
+ | |||
+ | // Setup I2C pins | ||
+ | pinMode(SDA_PIN, INPUT_PULLUP); | ||
+ | pinMode(SCL_PIN, INPUT_PULLUP); | ||
+ | |||
+ | // Configure button with interrupt | ||
+ | pinMode(MODE_BUTTON_PIN, INPUT_PULLUP); | ||
+ | attachInterrupt(digitalPinToInterrupt(MODE_BUTTON_PIN), buttonISR, FALLING); | ||
+ | |||
+ | // Initialize systems | ||
+ | i2c_init(); | ||
+ | mpu6050_init(); | ||
+ | initBLE(); | ||
+ | calibrate_sensors(); | ||
+ | |||
+ | // Configure timer for sensor sampling | ||
+ | sampleTimer = timerBegin(0, 80, true); | ||
+ | timerAttachInterrupt(sampleTimer, &onSampleTimer, true); | ||
+ | timerAlarmWrite(sampleTimer, SAMPLE_RATE_MS * 1000, true); | ||
+ | timerAlarmEnable(sampleTimer); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Handler de întrerupere pentru eșantionare** | ||
+ | <code> | ||
+ | void IRAM_ATTR onSampleTimer() { | ||
+ | portENTER_CRITICAL_ISR(&timerMux); | ||
+ | readSensorFlag = true; | ||
+ | portEXIT_CRITICAL_ISR(&timerMux); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Bucla principală** | ||
+ | |||
+ | <code> | ||
+ | void loop() { | ||
+ | // Process sensor data when ready | ||
+ | if (readSensorFlag) { | ||
+ | readSensorFlag = false; | ||
+ | |||
+ | if (deviceConnected) { | ||
+ | process_motion_data(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Handle button press | ||
+ | if (buttonInterruptOccurred) { | ||
+ | buttonInterruptOccurred = false; | ||
+ | handle_button_interrupt(); | ||
+ | } | ||
+ | |||
+ | // Manage BLE reconnections | ||
+ | handleBLEEvents(); | ||
+ | |||
+ | delay(1); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Citirea datelor de la MPU6050** | ||
+ | <code> | ||
+ | void mpu6050_read_accel(int16_t *accelX, int16_t *accelY, int16_t *accelZ) { | ||
+ | uint8_t buffer[6]; | ||
+ | |||
+ | read_registers(MPU6050_ADDR, MPU6050_ACCEL_XOUT_H, buffer, 6); | ||
+ | |||
+ | *accelX = (int16_t)((buffer[0] << 8) | buffer[1]); | ||
+ | *accelY = (int16_t)((buffer[2] << 8) | buffer[3]); | ||
+ | *accelZ = (int16_t)((buffer[4] << 8) | buffer[5]); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Procesare mișcare mouse** | ||
+ | <code> | ||
+ | if (currentMode == MOUSE_MODE) { | ||
+ | // Apply dead zone filter | ||
+ | if (abs(deltaGyroX) < GYRO_DEADZONE) deltaGyroX = 0; | ||
+ | if (abs(deltaGyroY) < GYRO_DEADZONE) deltaGyroY = 0; | ||
+ | |||
+ | // Non-linear scaling for better precision | ||
+ | float scaledX = (float)deltaGyroY / GYRO_SCALE_MAX; | ||
+ | float scaledY = (float)deltaGyroX / GYRO_SCALE_MAX; | ||
+ | |||
+ | int16_t mouseX = -scaledX * mouseAcceleration * MOUSE_SPEED_MAX; | ||
+ | int16_t mouseY = scaledY * mouseAcceleration * MOUSE_SPEED_MAX; | ||
+ | |||
+ | send_mouse_command(mouseX, mouseY); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Trimitere comandă BLE** | ||
+ | <code> | ||
+ | void send_mouse_command(int16_t x, int16_t y) { | ||
+ | if (!deviceConnected) return; | ||
+ | |||
+ | // Limită pentru valorile ±127 | ||
+ | x = constrain(x, -127, 127); | ||
+ | y = constrain(y, -127, 127); | ||
+ | |||
+ | // Construcție pachet | ||
+ | uint8_t buffer[4]; | ||
+ | buffer[0] = MOUSE_MOVE; | ||
+ | buffer[1] = (uint8_t)(x & 0xFF); | ||
+ | buffer[2] = (uint8_t)(y & 0xFF); | ||
+ | buffer[3] = 0; // Scroll | ||
+ | |||
+ | // Transmisie BLE | ||
+ | pTxCharacteristic->setValue(buffer, 4); | ||
+ | pTxCharacteristic->notify(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | **Calibrare senzori** | ||
+ | <code> | ||
+ | const int numSamples = 50; | ||
+ | for (int i = 0; i < numSamples; i++) { | ||
+ | mpu6050_read_accel(&accelX, &accelY, &accelZ); | ||
+ | mpu6050_read_gyro(&gyroX, &gyroY, &gyroZ); | ||
+ | |||
+ | sumAccelX += accelX; | ||
+ | sumAccelY += accelY; | ||
+ | sumAccelZ += accelZ; | ||
+ | |||
+ | delay(10); | ||
+ | } | ||
+ | |||
+ | // Calculare valori de bază | ||
+ | baseAccelX = sumAccelX / numSamples; | ||
+ | baseAccelY = sumAccelY / numSamples; | ||
+ | baseAccelZ = sumAccelZ / numSamples; | ||
+ | </code> | ||
+ | |||
+ | **2. Aplicație Python (Receptor)** | ||
+ | |||
+ | - Comunicare Bluetooth: | ||
+ | * **__notification_handler()__** - Procesarea notificărilor BLE primite | ||
+ | * **___connect()__** - Stabilirea conexiunii cu dispozitivul controller | ||
+ | - Procesare comenzi: | ||
+ | * **__process_mouse_move()__** - Interpretarea și aplicarea mișcărilor mouse-ului | ||
+ | * **__process_key_press()__** / **__process_key_release()__** - Gestionarea apăsărilor de taste | ||
+ | - Interfață utilizator | ||
+ | * **__create_gui()__** - Construirea interfeței grafice | ||
+ | * **__log()__** - Sistemul de înregistrare a evenimentelor pentru debugging | ||
+ | |||
+ | Handler notificări BLE (Python) | ||
+ | <code> | ||
+ | def notification_handler(self, sender, data): | ||
+ | # Adaugă datele la buffer | ||
+ | self.receive_buffer.extend(data) | ||
+ | |||
+ | # Extrage comanda | ||
+ | cmd = self.receive_buffer[0] | ||
+ | |||
+ | if cmd == MOUSE_MOVE and len(self.receive_buffer) >= 4: | ||
+ | x = struct.unpack('b', bytes([self.receive_buffer[1]]))[0] | ||
+ | y = struct.unpack('b', bytes([self.receive_buffer[2]]))[0] | ||
+ | self.process_mouse_move(x, y) | ||
+ | self.receive_buffer = self.receive_buffer[4:] | ||
+ | </code> | ||
+ | ===== Rezultate Obţinute ===== | ||
+ | |||
+ | {{:pm:prj2025:fstancu:produs_final2_safronii_veaceslav.jpg?200|}} {{:pm:prj2025:fstancu:produs_final1_safronii_veaceslav.jpg?250|}} | ||
+ | |||
+ | |||
+ | **Demo:** | ||
+ | |||
+ | <html> | ||
+ | <iframe width="560" height="315" | ||
+ | src="https://www.youtube.com/embed/A-uMmCEJwlk" | ||
+ | title="YouTube video player" | ||
+ | frameborder="0" | ||
+ | allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" | ||
+ | allowfullscreen> | ||
+ | </iframe> | ||
+ | </html> | ||
+ | |||
+ | ===== Download ===== | ||
- | ===== Bibliografie/Resurse ===== | + | Codul sursa: |
+ | * src/ - Codul pentru ESP | ||
+ | * receptor/ - Programul in Python de receptie a comenzilor | ||
- | <note> | + | {{:pm:prj2025:fstancu:wirelesscontroller.zip|}} |
- | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | |
- | </note> | + | |
- | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | ||