This shows you the differences between two versions of the page.
|
pm:prj2026:florin.stancu:andrei.bleortu [2026/05/24 23:42] andrei.bleortu |
pm:prj2026:florin.stancu:andrei.bleortu [2026/05/25 14:04] (current) andrei.bleortu |
||
|---|---|---|---|
| Line 4: | Line 4: | ||
| Proiectul implementeaza un sistem de monitorizare si protectie pentru o linie de productie industriala simulata. In centrul sistemului se afla un motor stepper 28BYJ-48 care reprezinta echipamentul principal de productie - de exemplu o masa rotativa de asamblare sau un conveyor. In jurul lui sunt dispusi mai multi senzori care detecteaza situatiile periculoase: prezenta personalului in zona de operare, apropierea unor obiecte, infiltratii de apa, zgomote anormale si conditii de mediu nepotrivite. | Proiectul implementeaza un sistem de monitorizare si protectie pentru o linie de productie industriala simulata. In centrul sistemului se afla un motor stepper 28BYJ-48 care reprezinta echipamentul principal de productie - de exemplu o masa rotativa de asamblare sau un conveyor. In jurul lui sunt dispusi mai multi senzori care detecteaza situatiile periculoase: prezenta personalului in zona de operare, apropierea unor obiecte, infiltratii de apa, zgomote anormale si conditii de mediu nepotrivite. | ||
| - | Punctul de plecare a fost o intrebare destul de concreta: cum opresti in siguranta un echipament industrial cand apare o anomalie? In aplicatiile reale, timpul de raspuns trebuie sa fie de ordinul milisecundelor, iar sistemul trebuie sa functioneze fiabil chiar si atunci cand o parte din componente cedeaza. Aceste cerinte motiveaza arhitectura aleasa, cu doua microcontrollere avand roluri distincte. | + | Punctul de plecare a fost o intrebare concreta: cum se opreste in siguranta un echipament industrial cand apare o anomalie? In aplicatiile reale, timpul de raspuns trebuie sa fie de ordinul milisecundelor, iar sistemul trebuie sa functioneze fiabil chiar si atunci cand o parte din componente cedeaza. Aceste cerinte motiveaza arhitectura aleasa, cu doua microcontrollere avand roluri distincte. |
| - | Proiectul acopera bine conceptele de curs - senzori analogici si digitali, comunicatie seriala, WiFi, interfata cu utilizatorul - dar principalul motiv de interes este arhitectural: separarea hard real-time (siguranta, control motor) de procesare si conectivitate pe microcontrollere distincte e o abordare standard in sistemele industriale serioase. | + | Proiectul acopera conceptele de curs - senzori analogici si digitali, comunicatie seriala, WiFi, interfata cu utilizatorul - iar elementul principal de interes este arhitectural: separarea hard real-time (siguranta, control motor) de procesare si conectivitate pe microcontrollere distincte este o abordare standard in sistemele industriale. |
| ===== Descriere generala ===== | ===== Descriere generala ===== | ||
| - | Sistemul este construit pe doua microcontrollere cu roluri foarte diferite: | + | Sistemul este construit pe doua microcontrollere cu roluri distincte: |
| - | * **Arduino MEGA 2560** este "creierul" hard real-time. Citeste toti senzorii la fiecare 10 ms, ruleaza state machine-ul de siguranta, controleaza direct motorul si buzzer-ul si calculeaza scorul de sanatate. Bucla principala este complet non-blocking si bounded ca durata. | + | * **Arduino MEGA 2560** indeplineste functia de controler hard real-time. Citeste toti senzorii la fiecare 10 ms, ruleaza state machine-ul de siguranta, controleaza direct motorul si buzzer-ul si calculeaza scorul de sanatate. Bucla principala este non-blocking si bounded ca durata. |
| - | * **ESP32 WROOM-32D** functioneaza ca punte intre Arduino si restul lumii. Singura sa "intrare" este citirea senzorului DHT11 (conectat fizic la el), pe care o trimite Arduino-ului inapoi printr-un cadru UART de retur. In rest, primeste cadrele bogate de la Arduino, le afiseaza pe LCD si le retransmite catre server prin WebSocket. Nu calculeaza nimic local. | + | * **ESP32 WROOM-32D** functioneaza ca punte intre Arduino si infrastructura externa. Singura sa intrare proprie este citirea senzorului DHT11 (conectat fizic la el), retransmisa catre Arduino printr-un cadru UART de retur. In rest, primeste cadrele de la Arduino, le afiseaza pe LCD si le retransmite catre server prin WebSocket. Nu efectueaza procesare locala. |
| - | Arhitectura cu Arduino ca singura sursa de adevar aduce doua avantaje practice: redundanta (daca pica WiFi sau ESP32, Arduino continua sa opreasca motorul corect) si zero variabilitate de timing datorata retelei. Temperatura ambianta nu se schimba in milisecunde, deci e suficient ca ESP32 sa trimita valoarea DHT11 inapoi la Arduino o data la ~2 secunde. | + | Arhitectura cu Arduino ca unica sursa de adevar aduce doua avantaje: redundanta (la caderea WiFi sau ESP32, Arduino continua sa opreasca motorul corect) si eliminarea variabilitatii de timing introduse de retea. Temperatura ambianta nu se modifica in milisecunde, asadar este suficient ca ESP32 sa transmita valoarea DHT11 catre Arduino la interval de aproximativ 2 secunde. |
| {{:pm:prj2026:florin.stancu:safety_sensor_integration-2026-05-06-073804.png?800|}} | {{:pm:prj2026:florin.stancu:safety_sensor_integration-2026-05-06-073804.png?800|}} | ||
| Line 41: | Line 41: | ||
| </code> | </code> | ||
| - | Doar in NORMAL motorul se invarte. WARNING exista in enum (valoarea 1) dar nu este produsa de nicio conditie - orice anomalie declanseaza o stare de oprire, conform cerintei unui controler de siguranta industriala. | + | Motorul functioneaza exclusiv in starea NORMAL. WARNING exista in enum (valoarea 1) dar nu este produsa de nicio conditie - orice anomalie declanseaza o stare de oprire, conform cerintei unui controler de siguranta industriala. |
| ===== Hardware Design ===== | ===== Hardware Design ===== | ||
| Line 70: | Line 70: | ||
| ==== Organizarea fizica ==== | ==== Organizarea fizica ==== | ||
| - | Componentele sunt distribuite pe doua breadboard-uri pentru a separa logic responsabilitatile sistemului si pentru a facilita mentenanta. | + | Componentele sunt distribuite pe doua breadboard-uri pentru a separa responsabilitatile sistemului si pentru a facilita mentenanta. |
| **Breadboard principal (Arduino):** | **Breadboard principal (Arduino):** | ||
| Line 111: | Line 111: | ||
| ==== Compatibilitatea electrica ==== | ==== Compatibilitatea electrica ==== | ||
| - | Principalul aspect electric care trebuie luat in considerare este interfatarea intre Arduino (logica 5V) si ESP32 (logica 3.3V). Conform datasheet-ului, pinii GPIO ai ESP32 sunt 5V tolerant pe input, ceea ce permite conectarea directa a liniei TX a Arduino-ului la RX-ul ESP32-ului fara level shifter. Pentru directia inversa (ESP32 TX 3.3V -> Arduino RX 5V), tensiunea de 3.3V e interpretata ca HIGH, intrucat pragul de detectie al Arduino-ului este in jur de 3V. | + | Aspectul electric principal este interfatarea intre Arduino (logica 5V) si ESP32 (logica 3.3V). Conform datasheet-ului, pinii GPIO ai ESP32 sunt 5V tolerant pe input, ceea ce permite conectarea directa a liniei TX a Arduino-ului la RX-ul ESP32-ului fara level shifter. Pentru directia inversa (ESP32 TX 3.3V -> Arduino RX 5V), tensiunea de 3.3V este interpretata ca HIGH, intrucat pragul de detectie al Arduino-ului este in jur de 3V. |
| - | Divizorul 1k/2k pe linia Arduino TX -> ESP32 RX functioneaza fara probleme la 115200 baud. La 250 000 baud parser-ul ESP32 pierdea sincronizarea frecvent - probabil prea putin margin de integritate prin divizor si fire de breadboard. La 115200 link-ul e stabil si bandwidth-ul ramane mult peste necesar (cadrul de 27 bytes la 20 Hz ocupa sub 5% din capacitate). | + | Divizorul 1k/2k pe linia Arduino TX -> ESP32 RX functioneaza fara erori la 115200 baud. La 250 000 baud parser-ul ESP32 pierde sincronizarea frecvent - cauza probabila este marginea redusa de integritate a semnalului prin divizor si fire de breadboard. La 115200 link-ul este stabil iar bandwidth-ul ramane peste necesar (cadrul de 27 bytes la 20 Hz ocupa sub 5% din capacitate). |
| - | LCD-ul este alimentat la 5V dar accepta semnale de control de 3.3V, deoarece pragul sau de HIGH este in jurul valorii de 2.5V. | + | LCD-ul este alimentat la 5V dar accepta semnale de control de 3.3V, intrucat pragul sau de HIGH este in jurul valorii de 2.5V. |
| ==== Estimare consum energetic ==== | ==== Estimare consum energetic ==== | ||
| Line 133: | Line 133: | ||
| | Buzzer activ | 30 mA | 150 mW | | | Buzzer activ | 30 mA | 150 mW | | ||
| - | Consumul total maxim estimat este de aproximativ 840 mA (3.9 W), iar consumul tipic - cu stepper-ul in functiune intermitenta si buzzer-ul activat ocazional - ar trebui sa fie in jur de 550 mA (2.8 W). In practica ESP32-ul ruleaza cu ''WiFi.setSleep(false)'' (pentru latenta retelei), deci consuma constant ~240 mA si valoarea reala e mai aproape de plafon. | + | Consumul total maxim estimat este de aproximativ 840 mA (3.9 W), iar consumul tipic - cu stepper-ul in functiune intermitenta si buzzer-ul activat ocazional - se situeaza in jur de 550 mA (2.8 W). In practica ESP32-ul ruleaza cu ''WiFi.setSleep(false)'' (pentru latenta retelei), consuma constant ~240 mA, iar valoarea reala este apropiata de plafon. |
| - | Pentru o eventuala alimentare cu acumulatori NiMH de 1.2V / 2500 mAh, ar fi necesari 8 acumulatori in serie pentru a obtine 9.6V (compatibil cu intrarea Vin a Arduino-ului). Autonomia estimata ar fi de aproximativ 4 ore. | + | Pentru o eventuala alimentare cu acumulatori NiMH de 1.2V / 2500 mAh, sunt necesari 8 acumulatori in serie pentru a obtine 9.6V (compatibil cu intrarea Vin a Arduino-ului). Autonomia estimata este de aproximativ 4 ore. |
| ===== Software Design ===== | ===== Software Design ===== | ||
| Line 183: | Line 183: | ||
| </code> | </code> | ||
| - | La fiecare iteratie a buclei principale (la 10 ms), conditiile sunt evaluate de la prioritatea cea mai mare catre cea mai mica. Prima conditie indeplinita determina starea curenta. Motorul se invarte doar in NORMAL. | + | La fiecare iteratie a buclei principale (10 ms), conditiile sunt evaluate de la prioritatea cea mai mare catre cea mai mica. Prima conditie indeplinita determina starea curenta. Motorul functioneaza exclusiv in NORMAL. |
| - | Histerezele sunt importante pentru starile "live" (PROXIMITY, WATER_HIGH, TEMP_HIGH) - fara ele, sistemul ar oscila intre stop si start atunci cand un senzor se afla exact la prag. | + | Histerezele sunt necesare pentru starile "live" (PROXIMITY, WATER_HIGH, TEMP_HIGH); in absenta lor, sistemul ar oscila intre stop si start cand un senzor se afla in jurul pragului. |
| **E-stop cu latching si reset prin triple-press** | **E-stop cu latching si reset prin triple-press** | ||
| - | Prima apasare latcheaza EMERGENCY indefinit. Pentru a iesi, utilizatorul trebuie sa apese inca 3 ori in maxim 2 secunde - asta forteaza o actiune deliberata si previne resetari accidentale. Debouncing 50 ms in software. La reset se sterg si timerele PIR / sunet, deci linia reporneste imediat. | + | Prima apasare latcheaza EMERGENCY indefinit. Iesirea necesita inca 3 apasari in maxim 2 secunde - secventa impune o actiune deliberata si previne resetarile accidentale. Debouncing 50 ms in software. La reset se sterg si timerele PIR / sunet, asadar linia reporneste imediat. |
| **Driver stepper non-blocking cu rampa de acceleratie** | **Driver stepper non-blocking cu rampa de acceleratie** | ||
| - | 28BYJ-48 are frecventa maxima de pull-in in jur de 600 Hz - sub viteza dorita pentru demo (~20 RPM). Solutia: rampa liniara, pornire la 4000 µs/pas (~7 RPM, sub pull-in) si reducerea delay-ului cu 2 µs/pas pana la 1500 µs/pas (~20 RPM). Rampa se completeaza in ~1250 pasi (~3.4 secunde). E resetata la fiecare tranzitie OFF -> ON, deci motorul reporneste lin dupa fiecare iesire din MAINT / PROXIMITY (in loc sa incerce direct viteza de croaziera, ceea ce duce la vibratie fara rotatie). | + | 28BYJ-48 are frecventa maxima de pull-in in jur de 600 Hz - sub viteza tinta pentru demo (~20 RPM). Solutia adoptata este o rampa liniara: pornire la 4000 µs/pas (~7 RPM, sub pull-in) si reducerea delay-ului cu 2 µs/pas pana la 1500 µs/pas (~20 RPM). Rampa se completeaza in ~1250 pasi (~3.4 secunde). Este resetata la fiecare tranzitie OFF -> ON, astfel incat motorul reporneste lin dupa fiecare iesire din MAINT / PROXIMITY (incercarea de a porni direct la viteza de croaziera produce vibratie fara rotatie). |
| - | Secventa de comutare e full-step "two-phases-on". Pe placa fizica IN3 si IN4 sunt inversate fata de ordinea alfabetica - mapping-ul real este //A=IN1, B=IN2, C=IN4, D=IN3//, verificat cu un sketch de diagnostic care energizeaza fiecare coil pe rand. Secventa din software reflecta acest mapping; fara corectie, motorul vibreaza fara sa se invarta. | + | Secventa de comutare este full-step "two-phases-on". Pe placa fizica IN3 si IN4 sunt inversate fata de ordinea alfabetica - mapping-ul real este //A=IN1, B=IN2, C=IN4, D=IN3//, verificat cu un sketch de diagnostic care energizeaza fiecare coil pe rand. Secventa din software reflecta acest mapping; fara corectie, motorul vibreaza fara sa se roteasca. |
| **Senzor ultrasonic non-blocking** | **Senzor ultrasonic non-blocking** | ||
| - | ''pulseIn'' e blocking pana la ~25 ms - jitter inacceptabil pentru bucla. In loc, ecoul e masurat printr-o intrerupere pin-change pe D10 (PCINT4): ISR citeste micros() la fiecare tranzitie si calculeaza latimea pulsului. Bucla doar declanseaza trigger-ul la 60 ms si citeste rezultatul cand e gata. Jitter ~3-5 µs, sub precizia proprie a HC-SR04. | + | ''pulseIn'' este blocking pana la ~25 ms - jitter inacceptabil pentru bucla. In locul sau, ecoul este masurat printr-o intrerupere pin-change pe D10 (PCINT4): ISR citeste micros() la fiecare tranzitie si calculeaza latimea pulsului. Bucla declanseaza trigger-ul la 60 ms si citeste rezultatul cand este disponibil. Jitter rezultat ~3-5 µs, sub precizia proprie a HC-SR04. |
| **Protocolul UART** | **Protocolul UART** | ||
| Line 211: | Line 211: | ||
| </code> | </code> | ||
| - | Payload-ul forward contine starea, toti senzorii, uptime, temp/umiditate (echo-ate inapoi de la ESP32), scorul de sanatate, unghiul motorului si timpul ramas pana la repornire. Reverse contine doar temp_x10 si hum_x10 - DHT11 oricum nu se actualizeaza mai rapid de 1 Hz. Checksum-ul XOR prinde coruptiile cauzate de EMI-ul stepper-ului. NACK-urile sunt contorizate dar **nu** declanseaza retransmisie - asta ar introduce variabilitate de timing; urmatorul cadru vine in 50 ms oricum. | + | Payload-ul forward contine starea, toti senzorii, uptime, temp/umiditate (retransmise de la ESP32), scorul de sanatate, unghiul motorului si timpul ramas pana la repornire. Reverse contine temp_x10 si hum_x10 - DHT11 nu se actualizeaza mai rapid de 1 Hz. Checksum-ul XOR detecteaza coruptiile cauzate de EMI-ul stepper-ului. NACK-urile sunt contorizate dar **nu** declanseaza retransmisie - retransmisia ar introduce variabilitate de timing, iar urmatorul cadru ajunge in 50 ms. |
| **Detectia status-ului link-ului** | **Detectia status-ului link-ului** | ||
| - | Arduino monitorizeaza contorul ACK. Daca nu creste 1.5 s, declara link pierdut si afiseaza ''>>> LINK LOST/UP'' pe USB Serial la tranzitii. ESP32 face acelasi lucru in invers, cu timeout 3 s (mai indulgent fiindca propria bucla se poate bloca temporar in operatii WiFi/WS). | + | Arduino monitorizeaza contorul ACK. La absenta incrementarii timp de 1.5 s, declara link pierdut si afiseaza ''>>> LINK LOST/UP'' pe USB Serial la tranzitii. ESP32 aplica simetric aceeasi logica, cu timeout 3 s (mai permisiv intrucat propria bucla se poate bloca temporar in operatii WiFi/WS). |
| **Calculul scorului de sanatate (Arduino)** | **Calculul scorului de sanatate (Arduino)** | ||
| Line 236: | Line 236: | ||
| **Watchdog timer** | **Watchdog timer** | ||
| - | Pe Arduino am activat watchdog-ul cu timeout de 4 secunde. Daca bucla principala se blocheaza din orice motiv (deadlock, ciclu infinit), microcontroller-ul se reseteaza automat. Apelul ''wdt_reset()'' este facut la inceputul fiecarei iteratii a buclei. | + | Pe Arduino este activat watchdog-ul cu timeout de 4 secunde. La blocarea buclei principale din orice motiv (deadlock, ciclu infinit), microcontroller-ul se reseteaza automat. Apelul ''wdt_reset()'' este executat la inceputul fiecarei iteratii a buclei. |
| ==== Optimizari pentru determinism si latenta ==== | ==== Optimizari pentru determinism si latenta ==== | ||
| - | Decizii aplicate in fiecare strat pentru bucla Arduino predictibila si latenta end-to-end mica: | + | Decizii aplicate in fiecare strat pentru o bucla Arduino predictibila si latenta end-to-end redusa: |
| - | * **Arduino**: ultrasonic prin PCINT (fara ''pulseIn'' blocking), link UART open-loop fara retransmisii la NACK, port I/O direct (PORTx/PINx) pe pinii hot, prescaler ADC /32 (~27 µs/citire), watchdog 4 s. | + | * **Arduino**: ultrasonic prin PCINT (fara ''pulseIn'' blocking), link UART open-loop fara retransmisii la NACK, port I/O direct (PORTx/PINx) pe pinii frecvent accesati, prescaler ADC /32 (~27 µs/citire), watchdog 4 s. |
| - | * **ESP32**: ''WiFi.setSleep(false)'' pentru a evita ~100 ms latenta per pachet de la modem sleep, buffer UART RX 2048 bytes ca blocajele temporare ale buclei sa nu desincronizeze parser-ul, WebSocket persistent catre server cu push la fiecare cadru primit (20 Hz). | + | * **ESP32**: ''WiFi.setSleep(false)'' pentru a evita ~100 ms latenta per pachet introdusa de modem sleep, buffer UART RX 2048 bytes pentru ca blocajele temporare ale buclei sa nu desincronizeze parser-ul, WebSocket persistent catre server cu push la fiecare cadru primit (20 Hz). |
| - | * **Server**: SQLite WAL cu ''synchronous=NORMAL'' (commit-uri sub-ms in loc de ~10 ms cu fsync), broadcast WS thread-safe peste un set de clienti. | + | * **Server**: SQLite WAL cu ''synchronous=NORMAL'' (commit-uri sub-ms fata de ~10 ms cu fsync), broadcast WS thread-safe peste un set de clienti. |
| - | * **Frontend**: WebSocket pentru update-uri live, bootstrap istoric prin REST la incarcare apoi append incremental, Chart.js cu ''animation: false''. | + | * **Frontend**: WebSocket pentru update-uri live, bootstrap istoric prin REST la incarcare urmat de append incremental, Chart.js cu ''animation: false''. |
| ==== Functii principale ==== | ==== Functii principale ==== | ||
| Line 278: | Line 278: | ||
| ==== Interfata utilizator (dashboard) ==== | ==== Interfata utilizator (dashboard) ==== | ||
| - | Dashboard-ul are o ierarhie vizuala clara, de sus in jos: | + | Dashboard-ul are o ierarhie vizuala definita, de sus in jos: |
| - | - **Banner de stare** - cel mai mare element din pagina, cu numele starii mare, o descriere scurta si (cand e cazul) un countdown urias pentru timpul ramas pana la repornire. Culorile se schimba per stare, EMERGENCY pulseaza. | + | - **Banner de stare** - elementul cel mai proeminent al paginii, cu numele starii afisat mare, o descriere scurta si, cand este cazul, un countdown amplu pentru timpul ramas pana la repornire. Culorile se schimba per stare, iar EMERGENCY pulseaza. |
| - | - **Cardurile "feature"** - scorul de sanatate cu un gauge SVG si motorul cu un cadran care arata unghiul curent in timp real. | + | - **Cardurile "feature"** - scorul de sanatate cu un gauge SVG si motorul cu un cadran care indica unghiul curent in timp real. |
| - **Senzori grupati** in 3 sectiuni: //Ambient// (temp, umiditate), //Proximity & Personnel// (distanta, PIR, E-stop), //Anomaly detectors// (sunet, apa). PIR si E-stop devin rosii cand sunt active. | - **Senzori grupati** in 3 sectiuni: //Ambient// (temp, umiditate), //Proximity & Personnel// (distanta, PIR, E-stop), //Anomaly detectors// (sunet, apa). PIR si E-stop devin rosii cand sunt active. | ||
| - **Grafice istorice** Chart.js pentru temperatura/umiditate, distanta/apa, sunet si scor de sanatate. | - **Grafice istorice** Chart.js pentru temperatura/umiditate, distanta/apa, sunet si scor de sanatate. | ||
| - | Countdown-ul motorului foloseste un mic trick: la fiecare cadru primit, dashboard-ul retine ''hold_ms'' si timestamp-ul local, apoi decrementeaza local la 100 ms intre cadre. Fiecare cadru nou resincronizeaza valoarea, deci curge fluid in loc sa sara in trepte de 50 ms. | + | Countdown-ul motorului foloseste interpolare locala: la fiecare cadru primit, dashboard-ul retine ''hold_ms'' si timestamp-ul local, apoi decrementeaza local la 100 ms intre cadre. Fiecare cadru nou resincronizeaza valoarea, rezultand o afisare fluida in loc de salturi in trepte de 50 ms. |
| ===== Rezultate Obtinute ===== | ===== Rezultate Obtinute ===== | ||
| Line 291: | Line 291: | ||
| Sistemul functioneaza end-to-end conform specificatiilor. | Sistemul functioneaza end-to-end conform specificatiilor. | ||
| - | **Latenta end-to-end** (schimbare de senzor -> pixel pe dashboard): ~50-75 ms tipic, ~25 ms best-case. Componentele: | + | **Latenta end-to-end** (schimbare de senzor -> pixel pe dashboard): ~50-75 ms tipic, ~25 ms in cazul cel mai favorabil. Componentele: |
| ^ Etapa ^ Latenta ^ | ^ Etapa ^ Latenta ^ | ||
| Line 302: | Line 302: | ||
| | Randare browser | ~16 ms (un frame la 60 fps) | | | Randare browser | ~16 ms (un frame la 60 fps) | | ||
| - | **Motorul** se invarte stabil la ~20 RPM dupa rampa de acceleratie, fara vibratii. Pornirile dupa MAINT / PROXIMITY sunt line, opririle pentru siguranta instantanee. | + | **Motorul** functioneaza stabil la ~20 RPM dupa rampa de acceleratie, fara vibratii. Pornirile dupa MAINT / PROXIMITY sunt line, iar opririle pentru siguranta sunt instantanee. |
| - | **State machine-ul** raspunde corect la toate scenariile: trecere de mana = MAINT cu countdown, obiect sub 40 cm = PROXIMITY (live), bat din palme = SOUND_SHUTDOWN, apa peste prag = WATER_HIGH, buton = EMERGENCY latched, triple-press = reset. | + | **State machine-ul** raspunde corect la toate scenariile: trecere de mana = MAINT cu countdown, obiect sub 40 cm = PROXIMITY (live), bataie din palme = SOUND_SHUTDOWN, apa peste prag = WATER_HIGH, buton = EMERGENCY latched, triple-press = reset. |
| - | **Link-ul UART** e stabil la 115200 baud prin divizor - zero NACK-uri si zero "LINK LOST" in functionare normala. 250000 baud nu trece curat prin divizor + fire de breadboard. | + | **Link-ul UART** este stabil la 115200 baud prin divizor - zero NACK-uri si zero "LINK LOST" in functionare normala. 250000 baud nu se transmite corect prin divizor combinat cu fire de breadboard. |
| - | **Dashboard-ul** primeste 20 Hz fara lag - 4 grafice + KPI-uri + gauge sanatate + cadran motor redesenate la fiecare cadru. | + | **Dashboard-ul** primeste 20 Hz fara lag - 4 grafice, KPI-uri, gauge sanatate si cadran motor redesenate la fiecare cadru. |
| - | **Capcane intalnite**: | + | **Probleme intalnite**: |
| * **Coil mapping pe stepper**: pe placa fizica IN3 si IN4 sunt inversate fata de ordinea alfabetica. Verificat cu un sketch de diagnostic (''firmware/stepper_test'') care energizeaza fiecare coil pe rand; secventa din firmware reflecta mapping-ul real. | * **Coil mapping pe stepper**: pe placa fizica IN3 si IN4 sunt inversate fata de ordinea alfabetica. Verificat cu un sketch de diagnostic (''firmware/stepper_test'') care energizeaza fiecare coil pe rand; secventa din firmware reflecta mapping-ul real. | ||
| - | * **Frecventa de pull-in**: 28BYJ-48 nu poate porni direct la viteza de croaziera, rampa de acceleratie e mandatorie. | + | * **Frecventa de pull-in**: 28BYJ-48 nu poate porni direct la viteza de croaziera, rampa de acceleratie este obligatorie. |
| - | * **WiFi modem sleep**: pornit by default, costa ~100 ms per pachet. ''WiFi.setSleep(false)'' are impact mai mare decat te-ai astepta. | + | * **WiFi modem sleep**: activ implicit, introduce ~100 ms per pachet. ''WiFi.setSleep(false)'' produce o imbunatatire substantiala a latentei. |
| - | * **Buffer UART RX ESP32**: 256 bytes default sunt insuficient cand bucla se blocheaza ocazional (reconectare WS); buffer de 2048 lasa headroom de ~4 secunde la cadenta 20 Hz. | + | * **Buffer UART RX ESP32**: cei 256 bytes impliciti sunt insuficienti cand bucla se blocheaza ocazional (reconectare WS); un buffer de 2048 ofera headroom de ~4 secunde la cadenta de 20 Hz. |
| - | * **Heartbeat de debug**: zeci de ''Serial.print'' apeluri separate blocheaza bucla cu 19 ms (motorul desincronizeaza); un singur ''snprintf'' compact in TX-ul UART trece nedetectat. | + | * **Heartbeat de debug**: zeci de apeluri ''Serial.print'' separate blocheaza bucla timp de 19 ms (rezultand desincronizarea motorului); un singur ''snprintf'' compact in TX-ul UART are impact neglijabil. |
| ===== Concluzii ===== | ===== Concluzii ===== | ||
| - | Cateva decizii arhitecturale au avut impact mai mare decat restul: | + | Cateva decizii arhitecturale au avut impact disproportionat de mare: |
| - | **Logica de siguranta pe Arduino, nu pe ESP32.** Calculul scorului de sanatate si state machine-ul traiesc pe Arduino, cu ESP32 ca punte simpla. Avantajele: o singura sursa de adevar, zero variabilitate de timing de la retea, si rezistenta la caderea WiFi (Arduino continua sa opreasca motorul corect independent de conectivitate). Orice modul WiFi cu acelasi protocol UART de 27 bytes poate inlocui ESP32-ul. | + | **Logica de siguranta pe Arduino, nu pe ESP32.** Calculul scorului de sanatate si state machine-ul ruleaza pe Arduino, ESP32 functionand ca punte. Avantajele: o singura sursa de adevar, eliminarea variabilitatii de timing introduse de retea si rezistenta la caderea WiFi (Arduino opreste motorul corect independent de conectivitate). Orice modul WiFi care implementeaza protocolul UART de 27 bytes poate inlocui ESP32-ul. |
| - | **WebSocket cu push la 20 Hz.** Latenta end-to-end e in jur de 75 ms, iar dashboard-ul se simte live in loc de refreshat periodic. Push-ul declansat de fiecare cadru parsat scoate complet din ecuatie orice timer separat pentru transmisia catre server. | + | **WebSocket cu push la 20 Hz.** Latenta end-to-end este in jur de 75 ms, iar dashboard-ul are comportament live in loc de refresh periodic. Push-ul declansat de fiecare cadru parsat elimina necesitatea unui timer separat pentru transmisia catre server. |
| - | **Determinismul costa.** Cost-per-iteratie bounded cere multe alegeri individuale mici (PCINT, port I/O direct, fara retransmisii, ADC prescaler, heartbeat compact). Cumulate, dau o bucla cu cost predictibil in zona de microsecunde. | + | **Determinismul are cost.** Cost-per-iteratie bounded necesita numeroase alegeri individuale (PCINT, port I/O direct, absenta retransmisiilor, ADC prescaler, heartbeat compact). Cumulate, rezultatul este o bucla cu cost predictibil in zona de microsecunde. |
| - | **Histereza nu e optionala.** Toate starile "live" (PROXIMITY, WATER_HIGH, TEMP_HIGH) au nevoie de praguri separate enter / exit. Altfel, un senzor care variaza in jurul pragului face sistemul sa intre si sa iasa rapid - inutilizabil. | + | **Histereza este obligatorie.** Toate starile "live" (PROXIMITY, WATER_HIGH, TEMP_HIGH) necesita praguri separate enter / exit. In caz contrar, un senzor care variaza in jurul pragului determina sistemul sa intre si sa iasa rapid din stare - comportament inutilizabil. |
| - | **Triple-press pentru reset.** Forteaza o actiune deliberata si previne resetari accidentale ale E-stop-ului. Un singur buton face atat latch cat si reset - secventa de 3 apasari in 2 secunde e suficient de grea incat sa nu se intample din greseala. | + | **Triple-press pentru reset.** Impune o actiune deliberata si previne resetarile accidentale ale E-stop-ului. Un singur buton indeplineste atat functia de latch cat si pe cea de reset - secventa de 3 apasari in 2 secunde are probabilitate redusa de declansare accidentala. |
| - | **Imbunatatiri viitoare** neimplementate din lipsa de timp / piese: | + | **Imbunatatiri viitoare** neimplementate din lipsa de timp sau de componente: |
| * Senzor de vibratii (MPU6050) pentru detectia uzurii rulmentilor | * Senzor de vibratii (MPU6050) pentru detectia uzurii rulmentilor | ||
| - | * Profil de acceleratie S-curve pentru pornire si mai lina | + | * Profil de acceleratie S-curve pentru o pornire mai lina |
| * Tranzitii de stare salvate ca eveniment separat, nu doar metricile | * Tranzitii de stare salvate ca eveniment separat, nu doar metricile | ||
| - | * Autentificare pe dashboard + HTTPS/WSS pentru un deployment "serios" | + | * Autentificare pe dashboard si HTTPS/WSS pentru un deployment in productie |
| - | * Trecere la un motor mai puternic - 28BYJ-48 la 20 RPM e prea blajin pentru aplicatii reale | + | * Trecere la un motor mai puternic - 28BYJ-48 la 20 RPM are cuplu limitat pentru aplicatii reale |
| ===== Download ===== | ===== Download ===== | ||
| Line 346: | Line 346: | ||
| Etapele s-au aliniat pe milestone-urile cursului: | Etapele s-au aliniat pe milestone-urile cursului: | ||
| - | * **Saptamana 11 (4-8 Mai) - Milestone documentatie**: alegerea componentelor, motivarea arhitecturii dual-MCU, schema electrica in KiCad, calculul de consum si scrierea acestei pagini in forma initiala. | + | * **Saptamana 11 (4-8 Mai) - Milestone documentatie**: alegerea componentelor, motivarea arhitecturii dual-MCU, schema electrica in KiCad, calculul de consum si redactarea acestei pagini in forma initiala. |
| - | * **Saptamana 12 (11-15 Mai) - Milestone hardware**: montaj fizic pe cele doua breadboard-uri, cablare divizor 1k/2k pentru linia Arduino TX -> ESP32 RX, testare individuala a fiecarui senzor. Aici am descoperit prima capcana: motorul stepper vibra fara sa se invarta. Am scris un sketch dedicat (''firmware/stepper_test'') care energizeaza fiecare coil pe rand - s-a vazut ca pe placa concreta IN3 si IN4 sunt inversate fata de ordinea alfabetica. | + | * **Saptamana 12 (11-15 Mai) - Milestone hardware**: montaj fizic pe cele doua breadboard-uri, cablare divizor 1k/2k pentru linia Arduino TX -> ESP32 RX, testare individuala a fiecarui senzor. In aceasta etapa a fost identificata prima problema: motorul stepper vibra fara sa se roteasca. A fost dezvoltat un sketch dedicat (''firmware/stepper_test'') care energizeaza fiecare coil pe rand, iar testul a indicat ca pe placa concreta IN3 si IN4 sunt inversate fata de ordinea alfabetica. |
| - | * **Saptamana 13 (18-22 Mai) - Milestone software**: prima versiune end-to-end functionala (Arduino + ESP32 cu HTTP POST + Flask + dashboard cu polling), urmata in aceeasi saptamana de refactor-ul mare: inversarea arhitecturii (tot real-time pe Arduino, ESP32 doar punte), migrarea la WebSocket persistent in ambele directii, rampa de acceleratie pentru motor, starile noi (PROXIMITY, TEMP_HIGH, WATER_HIGH) cu histereza, E-stop cu latching si triple-press reset, optimizari pentru determinism (PCINT, port I/O direct, ADC prescaler, WiFi.setSleep(false), SQLite WAL). | + | * **Saptamana 13 (18-22 Mai) - Milestone software**: prima versiune end-to-end functionala (Arduino + ESP32 cu HTTP POST + Flask + dashboard cu polling), urmata in aceeasi saptamana de refactorul principal: inversarea arhitecturii (logica real-time pe Arduino, ESP32 doar ca punte), migrarea la WebSocket persistent in ambele directii, rampa de acceleratie pentru motor, starile noi (PROXIMITY, TEMP_HIGH, WATER_HIGH) cu histereza, E-stop cu latching si triple-press reset, optimizari pentru determinism (PCINT, port I/O direct, ADC prescaler, WiFi.setSleep(false), SQLite WAL). |
| * **Saptamana 14 (25-29 Mai) - PM Fair**: prezentarea proiectului. | * **Saptamana 14 (25-29 Mai) - PM Fair**: prezentarea proiectului. | ||