Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2026:atoader:bianca.gorgovan [2026/05/16 22:26]
bianca.gorgovan [Hardware Design]
pm:prj2026:atoader:bianca.gorgovan [2026/05/22 00:16] (current)
bianca.gorgovan [Script demo video]
Line 8: Line 8:
  
   * detectează startul și sfârșitul unei lovituri din semnătura inerțială a swing-ului;   * detectează startul și sfârșitul unei lovituri din semnătura inerțială a swing-ului;
-  * estimează **tipul loviturii** — //​forehand//​ vs //​backhand//​ — pe baza sensului de rotație al brațului; 
   * estimează **intensitatea loviturii** — //slab// / //mediu// / //​puternic//​ — din vârful de accelerație;​   * estimează **intensitatea loviturii** — //slab// / //mediu// / //​puternic//​ — din vârful de accelerație;​
   * estimează **viteza unghiulară maximă** a swing-ului prin integrarea giroscopului;​   * estimează **viteza unghiulară maximă** a swing-ului prin integrarea giroscopului;​
Line 81: Line 80:
 Microcontrolerul ATmega328P are un număr limitat de pini cu funcții speciale (I2C, SPI, PWM, întreruperi). Alegerea fiecărui pin nu este arbitrară, ci impusă de funcția hardware de care avem nevoie. Microcontrolerul ATmega328P are un număr limitat de pini cu funcții speciale (I2C, SPI, PWM, întreruperi). Alegerea fiecărui pin nu este arbitrară, ci impusă de funcția hardware de care avem nevoie.
  
-^ Semnal ^ Pin AVR ^ Pin Arduino ​^ Componentă ^ Justificarea alegerii ^ +^ Semnal ^ Pin AVR ^ Componentă ^ Justificarea alegerii ^ 
-| SDA | PC4 | A4 | MPU6050 | Pin hardware TWI al ATmega328P — singura opțiune pentru I2C hardware. | +| SDA | PC4 | MPU6050 | Pin hardware TWI al ATmega328P — singura opțiune pentru I2C hardware. | 
-| SCL | PC5 | A5 | MPU6050 | Pin hardware TWI — pereche cu SDA. | +| SCL | PC5 | MPU6050 | Pin hardware TWI — pereche cu SDA. | 
-| SCK | PB5 | D13 | Display | Pin hardware SPI SCK. | +| SCK | PB5 | Display | Pin hardware SPI SCK. | 
-| MOSI (SDA) | PB3 | D11 | Display | Pin hardware SPI MOSI. | +| MOSI (SDA) | PB3 | Display | Pin hardware SPI MOSI. | 
-| CS | PB2 | D10 | Display | Pinul hardware SS; trebuie configurat ca ieșire, altfel modulul SPI cade în mod slave. | +| CS | PB2 | Display | Pinul hardware SS; trebuie configurat ca ieșire, altfel modulul SPI cade în mod slave. | 
-| DC | PB1 | D9 | Display | GPIO liber, adiacent fizic pinilor SPI — cablaj scurt. | +| DC | PB1 | Display | GPIO liber, adiacent fizic pinilor SPI — cablaj scurt. | 
-| RST | PB0 | D8 | Display | GPIO liber, adiacent pinului DC. | +| RST | PB0 | Display | GPIO liber, adiacent pinului DC. | 
-Roșu (R) | PD3 | D3 | LED RGB | Ieșire OC2B — PWM hardware generat de Timer 2. | +Rosu (R) | PD3 | LED RGB | Ieșire OC2B — PWM hardware generat de Timer 2. | 
-| Verde (G) | PD5 | D5 | LED RGB | Ieșire OC0B — PWM hardware generat de Timer 0. | +| Verde (G) | PD5 | LED RGB | Ieșire OC0B — PWM hardware generat de Timer 0. | 
-| Buton | PD2 | D2 | Buton | Pin INT0 — întrerupere externă dedicată, cu pull-up intern activat în software. |+| Buton | PD2 | Buton | Pin INT0 — întrerupere externă dedicată, cu pull-up intern activat în software. |
  
 **De ce I2C pe PC4/PC5:** magistrala I2C hardware (TWI) a ATmega328P este fixată pe acești doi pini. Nu există alternativă dacă vrem comunicare I2C hardware, fără emulare software. **De ce I2C pe PC4/PC5:** magistrala I2C hardware (TWI) a ATmega328P este fixată pe acești doi pini. Nu există alternativă dacă vrem comunicare I2C hardware, fără emulare software.
Line 104: Line 103:
  
 ==== 3. Schema electrică ==== ==== 3. Schema electrică ====
 +{{ :​pm:​prj2026:​atoader:​circuit_image.png?​400 |}}
  
  
Line 113: Line 112:
  
 Imaginea arată sistemul asamblat pe breadboard: placa ATmega328P Xplained Mini alimentată prin USB, senzorul MPU6050, display-ul ST7735, LED-ul RGB cu cei doi rezistori de limitare și butonul de reset. Alimentarea este distribuită prin șinele laterale ale breadboard-ului. Imaginea arată sistemul asamblat pe breadboard: placa ATmega328P Xplained Mini alimentată prin USB, senzorul MPU6050, display-ul ST7735, LED-ul RGB cu cei doi rezistori de limitare și butonul de reset. Alimentarea este distribuită prin șinele laterale ale breadboard-ului.
 +{{ :​pm:​prj2026:​atoader:​ecran.png?​300 |}}
  
  
Line 136: Line 135:
  
 ===== Software Design ===== ===== Software Design =====
 +==== Mediu de dezvoltare ====
 +Proiectul a fost dezvoltat folosind PlatformIO cu toolchain-ul avr-gcc, integrat în Visual Studio Code. Compilatorul țintă este ''​avr-gcc''​ cu flagul ''​-mmcu=atmega328p''​ și ''​-DF_CPU=16000000UL''​. Deoarece codul folosește ''​sqrt()''​ din ''<​math.h>'',​ au fost adăugate flagurile de linker pentru floating point:
 +<code ini>
 +build_flags = -Wl,​-u,​vfprintf -lprintf_flt -lm
 +</​code>​
 +Depanarea s-a realizat prin interfața UART la 9600 baud, cu mesaje trimise către un terminal serial (Serial Monitor din PlatformIO sau PuTTY).
 +==== Biblioteci și surse folosite ====
 +^ Modul ^ Fișier sursă ^ Origine ^ Rol ^
 +| Driver I2C/TWI | ''​twi.c''​ / ''​twi.h''​ | Preluat din Laboratorul 6, adaptat (F_CPU = 16 MHz, timeout adăugat) | Comunicare I²C cu MPU6050 |
 +| Driver SPI | ''​spi.c''​ / ''​spi.h''​ | Preluat din Laboratorul 5 | Comunicare SPI cu display-ul ST7735 |
 +| Driver TFT | ''​st7735.c''​ / ''​st7735.h''​ | Preluat din Laboratorul 5, adaptat pentru pinii ATmega328P Xplained Mini | Afișare text și grafice pe ecranul 1.8" |
 +| Loop principal + logică | ''​main.c''​ | Scris integral în cadrul proiectului | Inițializare,​ FSM detecție swing, clasificare,​ UART, LED RGB, buton |
 +| AVR LibC | ''<​avr/​io.h>'',​ ''<​avr/​interrupt.h>'',​ ''<​util/​delay.h>'',​ ''<​math.h>''​ | Standard AVR-LibC | Acces registre, întreruperi,​ delay, sqrt() |
 +Nu au fost folosite biblioteci externe de tip Arduino sau framework-uri de nivel înalt — întreaga stivă este bare-metal C pe AVR.
 +==== Algoritmi și structuri implementate ====
 +=== 1. Citirea senzorului MPU6050 prin I²C (burst read) ===
 +Funcția ''​mpu_read_gyro()''​ realizează o citire în rafală (burst read) a 6 octeți consecutivi începând de la registrul ''​0x43''​ (GYRO_XOUT_H). Secvența respectă protocolul I²C descris în Laboratorul 6:
 +<code c>
 +twi_start(SLA_W) → twi_write(REG_GYRO_X) →
 +twi_start(SLA_R) → twi_read(ACK) x5 → twi_read(NACK) → twi_stop()
 +</​code>​
 +Cei 6 octeți sunt recombinați în trei valori ''​int16_t''​ (gx, gy, gz) prin shift și OR pe biți:
 +<code c>
 +*gx = (int16_t)((b[0] << 8) | b[1]);
 +</​code>​
 +=== 2. Calculul magnitudinii vectorului giroscopic ===
 +Pentru a obține un scalar independent de orientarea rachetei, se calculează norma euclidiană a vectorului angular:
 +<​code>​
 +mag = sqrt(gx² + gy² + gz²)
 +</​code>​
 +Aceasta este implementată în ''​gyro_magnitude()''​ folosind ''​sqrt()''​ din ''<​math.h>''​ aplicat pe ''​double''​. Valorile intermediare sunt calculate pe ''​int32_t''​ pentru a evita overflow-ul pe 16 biți:
 +<code c>
 +int32_t sx = (int32_t)gx * gx;
 +</​code>​
 +Avantajul magnitudinii față de o singură axă este robustețea la montaj: indiferent cum este fixat senzorul pe rachetă, o mișcare rapidă va produce o valoare mare.
 +=== 3. Mașina de stări pentru detecția swing-ului (histerezis) ===
 +Detecția loviturii folosește un filtru cu histerezis pe două praguri, pentru a evita declanșările false datorită zgomotului sau vibrațiilor mici:
  
 +Starea IDLE: dacă ''​mag > GYRO_THR_START''​ (5000), se intră în starea ''​IN_HIT''​ și se înregistrează primul vârf.
 +Starea IN_HIT: se urmărește valoarea maximă (''​peak_gyro''​). Dacă ''​mag < GYRO_THR_END''​ (1500), lovitura s-a terminat → clasificare și reset.
 +Cooldown: după fiecare lovitură detectată, un contor de 1500 ms blochează detecțiile noi, pentru a lăsa timp rachetei să revină la poziția inițială fără a genera lovituri fantomă.
 +
 +Separarea pragului de intrare (5000) față de cel de ieșire (1500) formează un gap de histerezis de ~3500 unități, eliminând oscilațiile în jurul pragului.
 +=== 4. Clasificarea loviturii ===
 +La finalul unui swing, valoarea ''​peak_gyro''​ este comparată cu pragul ''​GYRO_GOOD_THR''​ (20000):
 +<code c>
 +if (peak_gyro >= GYRO_GOOD_THR) → BUNA (strong_hits++)
 +else                             → SLABA (weak_hits++)
 +</​code>​
 +=== 5. Feedback vizual prin LED RGB — degradeu roșu→verde ===
 +Funcția ''​led_from_peak()''​ mapează ''​peak_gyro''​ din intervalul [GYRO_MIN, GYRO_MAX] = [5000, 30000] pe un factor ''​f ∈ [0, 255]'':​
 +<code c>
 +f = (peak - GYRO_MIN) * 255 / (GYRO_MAX - GYRO_MIN)
 +green = f;   red = 255 - f;
 +</​code>​
 +Valorile sunt scalate la 80% din maxim (''​* 4 / 5''​) pentru a nu orbi utilizatorul. LED-ul are anod comun, deci duty cycle-ul este inversat: ''​OCRxB = 255 - valoare'',​ conform macrourilor ''​LED_SET_R()''​ și ''​LED_SET_G()''​. Semnalele PWM hardware sunt generate de Timer 0 (OC0B → verde, PD5) și Timer 2 (OC2B → roșu, PD3), fără intervenție software în buclă — exact modul Fast PWM studiat în Laboratorul 3.
 +=== 6. Debouncing software pentru buton (INT0) ===
 +Butonul pe PD2 este tratat în întreruperea externă ''​INT0_vect''​. Debouncing-ul se realizează prin compararea unui contor global de tick-uri (''​global_tick'',​ incrementat la fiecare 20 ms în bucla principală) cu momentul ultimei apăsări valide:
 +<code c>
 +if ((uint16_t)(global_tick - last_press_tick) > 3)  // > 3 × 20ms = 60ms
 +</​code>​
 +Această abordare non-blocantă este echivalentă cu fereastra de 30–50 ms recomandată în Laboratorul 2, fără a bloca execuția din ''​main''​.
 +=== 7. Afișare pe TFT ST7735 prin SPI ===
 +Driver-ul ''​st7735.c''​ folosește interfața SPI hardware (PB5=SCK, PB3=MOSI, PB2=CS) cu pini de control GPIO (PB0=DC, PB1=RST). Fontul 5×7 este stocat în memoria Flash (''​PROGMEM''​) și citit cu ''​pgm_read_byte()'',​ economisind RAM-ul limitat al ATmega328P. Actualizarea ecranului se face selectiv — doar zona numerelor (coordonate fixe) — pentru a minimiza traficul SPI și latența vizibilă.
  
 ===== Rezultate Obținute ===== ===== Rezultate Obținute =====
 +==== Stadiul actual al implementării software ====
 +Implementarea software este completă și funcțională. Toate modulele sunt integrate și validate pe hardware real:
 +
 + ​Inițializare și citire continuă MPU6050 prin I²C la 100 kHz
 + ​Detecție automată lovituri cu histerezis și cooldown
 +Clasificare binară slab/bun bazată pe peak-ul giroscopului
 +Afișare live pe TFT ST7735 (total, slabe, bune)
 +Feedback LED RGB cu degradeu roșu→verde proporțional cu intensitatea
 +Reset prin buton fizic cu debouncing software
 +Logging serial UART la 9600 baud pentru depanare și calibrare
 +
 +==== Motivația alegerii bibliotecilor ====
 +S-a optat deliberat pentru o arhitectură bare-metal, fără Arduino sau alte framework-uri de nivel înalt, din următoarele motive:
 +
 +Control precis al resurselor hardware: ATmega328P are 2 KB RAM și 32 KB Flash. Un framework de tip Arduino adaugă sute de octeți overhead pentru funcționalități nefolosite.
 +Familiaritate cu laboratoarele cursului: driver-ele ''​twi.c'',​ ''​spi.c''​ și ''​st7735.c''​ sunt extensii directe ale scheletelor din Laboratoarele 5 și 6, asigurând o înțelegere profundă a protocolelor.
 +Latență determinabilă:​ în sisteme de detecție în timp real, buclele de polling cu ''​_delay_ms()''​ și întreruperile hardware oferă timinguri predictibile,​ spre deosebire de un RTOS sau scheduler complex.
 +
 +Singura funcție din bibliotecă externă (AVR-LibC) cu potențial overhead este ''​sqrt()''​ pe ''​double''​ — acceptabil deoarece este apelată o singură dată per eșantion (la 20 ms), deci ~50 apeluri/​secundă,​ neglijabil față de ciclurile CPU disponibile la 16 MHz.
 +==== Elementul de noutate ====
 +Față de implementările academice tipice care testează un singur senzor izolat, acest proiect integrează simultan patru periferice hardware diferite pe același microcontroller (I²C + SPI + PWM × 2 + UART + GPIO interrupt), cu o logică de procesare a semnalului în timp real care produce output multimodal (vizual + serial) în același ciclu de 20 ms. Degradeul de culoare continuu al LED-ului (nu simplu roșu/verde binar) și algoritmul de histerezis cu cooldown adaptiv sunt elemente care aduc valoare practică față de o implementare banală cu prag simplu.
 +==== Justificarea utilizării funcționalităților din laborator ====
 +^ Funcționalitate ^ Laborator sursă ^ Utilizare în proiect ^
 +| UART / printf redirecționat | Laboratorul 1 | Logging serial: magnitudine giroscop, tip lovitură, contor — esențial pentru calibrarea pragurilor |
 +| Întrerupere externă INT0 + debouncing | Laboratorul 2 | Reset contor prin buton fizic, non-blocant |
 +| PWM hardware Fast PWM, Timer 0 + Timer 2 | Laboratorul 3 | Control intensitate LED RGB cu anod comun pe două canale independente |
 +| SPI hardware + driver ST7735 | Laboratorul 5 | Afișare statistici live pe TFT 1.8" color |
 +| I²C / TWI + citire registre senzor | Laboratorul 6 | Citire burst gyroscop MPU6050, același pattern ca MPL3115A2 din laborator |
 +==== Scheletul proiectului și interacțiunea dintre funcționalități ====
 +Bucla principală din ''​main()''​ rulează la o perioadă fixă de SAMPLE_MS = 20 ms și urmează un pipeline liniar:
 +<​code>​
 +[Buton ISR] ─────────────────────────────────► reset_flag
 +                                                    │
 +main loop (20ms tick): ​                             ▼
 +  1. Verifică reset_flag → resetează contoare și ecran
 +  2. mpu_read_gyro() ──I²C──► MPU6050 ──► gx, gy, gz
 +  3. gyro_magnitude() ──────────────────► mag (int32_t)
 +  4. FSM histerezis:
 +       IDLE ──mag > 5000──► IN_HIT (track peak)
 +       ​IN_HIT ──mag < 1500──► clasificare + LED + ecran update
 +  5. led_from_peak() ──PWM──► Timer0/​Timer2 ──► LED RGB
 +  6. screen_update_counts() ──SPI──► ST7735
 +  7. Debug UART la fiecare 25 iterații (~500 ms)
 +  8. _delay_ms(20) + global_tick++
 +</​code>​
 +Validarea funcționării s-a realizat în două etape:
 +
 +Validare prin UART: cu senzorul în repaus, mesajele ''​gyro_mag=XXX''​ confirmau valori < 500. Scuturând senzorul brusc, valorile depășeau 10000–30000,​ confirmând că pragurile GYRO_THR_START = 5000 separă corect zgomotul de fundal de un swing real.
 +Validare vizuală: LED-ul schimba culoarea consistent cu intensitatea mișcării (roșu pentru mișcări ușoare, verde/​galben pentru swing-uri puternice), iar ecranul TFT incrementa contorul corect la fiecare lovitură detectată.
 +
 +==== Calibrarea senzorului ====
 +MPU6050 a fost folosit în configurația implicită (fără calibrare offset a giroscopului),​ deoarece:
 +
 +Detecția se bazează pe magnitudini relative (este swing vs. nu este swing), nu pe valori absolute. Driftul de offset al giroscopului (tipic 1–3 LSB/°C) este neglijabil față de valorile de 5000–30000 atinse în swing.
 +Pragurile au fost determinate empiric prin UART logging: sistemul a fost conectat la un terminal serial și senzorul a fost mișcat cu intensități variate. S-au observat valorile tipice:
 +
 +Repaus / vibrații mici: mag ≈ 100–400
 +Mișcare lentă a mâinii: mag ≈ 800–2000
 +Swing moderat: mag ≈ 5000–12000
 +Swing puternic: mag ≈ 15000–28000
 +
 +
 +
 +Pe baza acestor observații s-au stabilit: GYRO_THR_START = 5000, GYRO_THR_END = 1500, GYRO_GOOD_THR = 20000.
 +==== Optimizări realizate ====
 +^ Optimizare ^ Unde ^ Motivație ^
 +| Font stocat în Flash (''​PROGMEM''​) | ''​st7735.c''​ | Fontul 5×7 ASCII ocupă 475 octeți; dacă ar fi în RAM, ar consuma ~23% din cei 2KB disponibili |
 +| Actualizare selectivă a ecranului | ''​screen_update_counts()''​ | Se rescrie doar zona cu numere (3 stringuri de 5 caractere), nu întregul ecran; reduce traficul SPI cu ~95% față de ''​st7735_fill()''​ complet |
 +| Padding cu spații în ''​sprintf''​ | ''​main.c''​ | ''​sprintf(buf,​ "​%-5u",​ val)''​ suprascrie cifrele vechi fără a șterge și redesena fundalul — evită flickering |
 +| Histerezis cu cooldown | ''​main.c''​ | Fără cooldown, un singur swing ar genera 5–10 detecții false; cooldown-ul de 1500 ms garantează maximum 1 lovitură per swing |
 +| Calcul magnitudine pe ''​int32_t''​ | ''​gyro_magnitude()''​ | Produsele ''​gx*gx''​ pe ''​int16_t''​ ar produce overflow (max 32767² = 1.07×10⁹ > 32767); cast la ''​int32_t''​ înainte de înmulțire previne silently wrong results |
 +| Debouncing non-blocant | ''​ISR(INT0_vect)''​ | Compararea tick-urilor nu blochează ISR-ul și nici bucla principală,​ față de un ''​_delay_ms()''​ în ISR care ar dezactiva alte întreruperi |
 +==== Script demo video ====
 +{{:​pm:​prj2026:​atoader:​demo_racheta.mp4.zip|}}
 +
  
  
Line 146: Line 283:
  
 ===== Download ===== ===== Download =====
 +{{:​pm:​prj2026:​atoader:​smart_tennis_racket.zip|}}
  
  
Line 171: Line 309:
  
   * jrowberg / i2cdevlib — bibliotecă C++ MPU6050 (referință pentru registre): [[https://​github.com/​jrowberg/​i2cdevlib/​tree/​master/​Arduino/​MPU6050]]   * jrowberg / i2cdevlib — bibliotecă C++ MPU6050 (referință pentru registre): [[https://​github.com/​jrowberg/​i2cdevlib/​tree/​master/​Arduino/​MPU6050]]
-  * "​Tennis Stroke Recognition Using Inertial Data" — articole academice pe IEEE Xplore ​(de citat ulterior, în etapa de etapa 3 documentație).+  * "​Tennis Stroke Recognition Using Inertial Data" — articole academice pe IEEE Xplore.
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
  
pm/prj2026/atoader/bianca.gorgovan.1778959611.txt.gz · Last modified: 2026/05/16 22:26 by bianca.gorgovan
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0