Sistem de monitorizare a activității cardiace a șoferilor utilizând electrozi capacitivi [305788]
[anonimizat] a activității cardiace a șoferilor utilizând electrozi capacitivi
Proiect de diplomă
Prezentat ca cerință parțială pentru obținerea titlului de Inginer
în domeniul Electronică și Telecomunicații
programul de studii de licență Electronică Aplicată
Conducători științifici Absolvent: [anonimizat]. Sever PAȘCA Loredana Alexandra Luiza GHEORGHE
Ing. Lucian GRUIA
Anul 2016
Anexa 6
Copyright © 2016, Loredana Alexandra Luiza GHEORGHE
Toate drepturile rezervate
Autorul acordă UPB dreptul de a reproduce și de a [anonimizat].
LISTA FIGURILOR
LISTA TABELELOR
LISTA ACRONIMELOR
A
API – Application Programming Interface
C
CD – [anonimizat] – [anonimizat] – Raport de Rejecție de Mod Comun
E
ECG/EKG – [anonimizat]
G
GPS – [anonimizat]
L
LAP – Least Address Part
M
MAC – Media Access Control
N
NAP – Non-[anonimizat] – Nodul Sinoatrial
P
PC – [anonimizat] – Produs Intern Brut
R
RFCOMM – Radio Frequency Communication
S
SMD – Surface Mount Device
U
UAP – [anonimizat] / [anonimizat] – Magistrală universală serială
W
WHO – World Health Organisation
Introducere
Conform WHO (World Health Organisation), afecțiunile cardiovasculare reprezintă prima cauză a deceselor la nivel global. [anonimizat]. [anonimizat] a persoanelor suferinde de boli de inimă. [anonimizat]. [anonimizat], [anonimizat] a celorlalți participanți la trafic. [anonimizat] a șoferilor se poate anticipa și preveni adormitul la volan.
[anonimizat] o soluție de monitorizare cardiacă a conducătorilor de autovehicule prin realizarea unei electrocardiograme (ECG) [anonimizat]. Înregistrarea activității electrice a cordului, electrocardiograma, permite obținerea rapidă de informații legate de starea inimii. [anonimizat], biopotențialele provenite de la inimă sunt captate cu ajutorul electrozilor. În contextul monitorizării cardiace a șoferilor, [anonimizat], nu reprezintă o [anonimizat] o perioadă îndelungată poate duce la iritații ale pielii. Pentru a [anonimizat], [anonimizat], nefiind necesar contactul direct cu pielea. Semnalele culese de aceștia sunt amplificate și trimise la microcontroler de unde, prin intermediul modulului Bluetooth al acestuia, ajung la terminalul mobil unde poate fi vizualizată electrocardiograma.
Lucrarea este structurată astfel încât primul capitol să prezinte importanța soluției propuse, noțiunile necesare în vederea înțelegerii fiziologiei inimii, modul de realizare a electrocardiogramei precum și o introducere în electrocardiografia capacitivă împreună cu un experiment realizat în cadrul Universității RWTH Aachen (Rheinisch-Westfälische Technische Hochschule Aachen). Al doilea capitol descrie soluția propusă, următoarele două capitole înfățișând realizarea părții hardware respectiv a celei software însoțită de rezultatele experimentale aferente.
În urma cercetării realizate, se poate concluziona că este posibilă monitorizarea cardiacă a șoferilor de autovehicul prin intermediul electrozilor capacitivi ce permit culegerea semnalelor de la inimă prin haine. Rezultatele practice demonstrează că electrocardiograma obținută poate oferi informațiile necesare în vederea detectării unor afecțiuni cardiace precum aritmiile și a prevenirii adormitului la volan.
Capitolul 1 – Introducere teoretică
Cauzele producerii accidentelor rutiere
Conform unui raport despre siguranța în trafic realizat de WHO (World Health Organisation), [1], mai mult de 1.2 milioane de oameni își pierd anual viața în accidentele rutiere. Acest aspect nu reprezintă numai o problemă de sănătate publică, ci și o problemă de dezvoltare: țările cu venit mic si mediu înregistrează pierderi de aproximativ 3% din PIB.
În prezent, se estimează că accidentele rutiere ocupă locul 9 în topul cauzelor de deces, la nivelul tuturor grupelor de vârstă. Se preconizează ca până în anul 2030, să ocupe locul 7 în același top.
De asemenea, accidentele rutiere reprezintă cea mai semnificativă cauză a deceselor înregistrate în rândul persoanelor de 15-29 ani. Celelalte cauze sunt prezentate în Figura 1.1.
Figura 1.1. Principalele cauze ale decesului persoanelor cu vârste cuprinse între 15 și 29 ani, Sursa [1]
Riscul de a fi victima unui accident rutier variază semnificativ în funcție de regiune. După cum se poate observa în Figura 1.2, cea mai mare rată este în regiunea africană, pe când cea mai mică se găsește în regiunea europeană:
Figura 1.2. Rata mortalității cauzate de accidente rutiere, pe o populație de 100.000, raportată pe regiuni WHO, Sursa [1]
Cauzele accidentelor rutiere sunt variate. Conform [1], printre cele mai des întâlnite se numără neatenția la volan (vorbitul la telefon fără accesorii de tipul handsfree, mâncatul la volan), condusul cu viteză ce depășește limita legală, consumul de alcool sau substanțe halucinogene, neadaptarea la condițiile meteo, nerespectarea semnelor de circulație, neasigurarea la efectuarea manevrelor de depășire, infrastructura defectuoasă a drumurilor, adormitul la volan și incapacitatea șoferului de a conduce cauzată de afecțiuni ale sănătății.
Lucrarea de față are în vedere reducerea numărului de accidente rutiere prin anticiparea ultimelor două cauze menționate în paragraful anterior. Prin monitorizarea activității cardiace a șoferilor se dorește evitarea adormitului la volan precum și preîntâmpinarea unor evenimente cardiace astfel încât șoferul să poată opri în condiții de siguranță, asigurându-se atât sănătatea sa, cât și a celorlalți participanți la trafic.
1.2. Prezentare generală a inimii
Lucrarea de față va trata ca prim aspect inima și fiziologia sa, în vederea înțelegerii modalității de funcționare a acesteia. Pentru a realiza acest capitol, am sintetizat informație provenită din mai multe surse: [3], [4], [5], [6], [7], [8].
Inima, denumită și cord, este un organ muscular al cărui rol este de a pompa sânge în vasele sistemului circulator. Sângele si constituenții săi servesc drept vehicul pentru oxigen și nutrienții necesari bunei funcționări a organismului, contribuind totodată și la eliminarea deșeurilor metabolice.
Din punct de vedere al localizării și al aspectului, inima se situează în cutia toracică, în spatele sternului, între plămâni și deasupra diafragmei (Figura 1.3.). Dimensiunea ei este apropiată de cea a pumnului individului, având o masă în jur de 250 – 300g și forma unei piramide triunghiulare al cărei vârf este orientat în jos, spre înainte și la stânga. Este învelită de un sac protector denumit pericard, iar peretele ei are trei straturi: epicard, miocard și endocard.
Figura 1.3. Localizarea inimii, Sursa [3]
La oameni, precum și la alte mamifere sau păsări, inima este împărțită în patru camere: două atrii și două ventricule. De obicei, atriul și ventriculul drept sunt denumite „inima dreaptă”, iar atriul și ventriculul stâng „inima stângă”.
Circulația sângelui prin corp este esențială pentru a avea o activitate celulară optimă. Ea este generată de inimă prin pomparea sângelui într-un circuit închis de vase sangvine. Din punct de vedere anatomo-funcțional, există două teritorii vasculare cu roluri diferite: circulația pulmonară, ce asigură efectuarea schimburilor de gaze (oxigen și dioxid de carbon) între sânge și plămâni și circulația sistemică, ce deservește restul organelor și țesuturilor (Figura 1.4.).
Circulația mare constă în transportul sângelui oxigenat de la ventriculul stâng prin intermediul arterei aorte și a ramurilor sale prin corp și revenirea prin vene a sângelui cu dioxid de carbon și deșeuri metabolice în atriul drept. Atriile se contractă, iar sângele este împins în ventricule, unde va avea loc următorul tip de circulație ce va fi descris în cele ce urmează.
Circulația mică, cunoscută și ca circulație pulmonară, începe de la nivelul ventriculului drept și transportă la plămâni prin artera pulmonară sângele cu dioxid de carbon provenit din corp. La nivelul plămânilor, sângele este oxigenat, urmând să ajungă prin venele pulmonare în atriul stâng.
Figura 1.4. Circulația mare și circulația mică, Sursa [7]
Circulația sângelui prin vasele sangvine este permisă într-o singură direcție (și anume: de la vene la atrii și apoi la ventricule și în cele din urmă la artere), valvele din structura internă a inimii împiedicând curgerea în sens contrar. În interiorul inimii avem patru valve cu următoarele roluri: cele două valve atrioventriculare (dreaptă – valva tricuspidă și stângă – bicuspidă sau mitrală) asigură circulația sângelui numai din atrii în ventricule (nu și invers), iar cele două valve semilunare (pulmonară și aortică) previn circulația sângelui din artere în ventricule, Figura 1.5.
Un ciclu cardiac reprezintă durata dintre două bătăi ale inimii, cuprinzând două perioade numite sistolă și diastolă. Sistola reprezintă perioada de contracție a inimii, timp în care inima expulzează sânge. Diastola reprezintă perioada de relaxare a inimii, fiind acea perioadă în care inima se umple cu sânge.
Figura 1.5. Structura inimii umane și circulația sângelui prin camerele ei, Sursa [3]
Din punct de vedere histologic, inima este compusă majoritar din celule musculare numite miocite, ele fiind cele care, în urma stimulării electrice, realizează contracția mecanica. Cel de-al doilea tip de celule poartă numele de „celule pacemaker”, fiind responsabile de generarea impulsului electric ce se va propaga către restul cordului, declanșând procesele fizico-chimice ce duc la contracția miocardului. Remarcabil la aceste celule este faptul că ele funcționează independent de sistemul nervos, proprietate ce poartă numele de automatism.
Celulele pacemaker sunt grupate în noduli, căi internodale si fascicule. Fiecărui nodul îi corespunde un ritm propriu de generare a impulsurilor, contracțiile fiind imprimate de cel cu frecvența cea mai mare. În mod normal, controlul bătăilor inimii îi revine nodulului sino-atrial (NSA), cu o rată de aproximativ 80 de depolarizări pe minut. Mai există nodulul atrio-ventricular (NAV), la nivelul căruia se produc circa 40 de depolarizări pe minut, precum și fasciculul Hiss si fibrele Purkinje cu o rată de 20 de depolarizări pe minut. În condițiile în care nodulul sino-atrial nu își mai poate îndeplini funcția, controlul bătăilor cordului va fi preluat de celelalte structuri.
În condiții normale, impulsul electric va fi generat în nodulul sino-atrial, apoi se va propaga din aproape în aproape prin miocitele atriale, dar și prin fasciculele internodale, către nodulul atrio-ventricular. De remarcat faptul că există o barieră electrică între atrii și ventricule, ea putând fi traversată doar prin intermediul nodulului atrio-ventricular. Acest lucru se reflectă în latența de 0,1 secunde dintre contracția atriilor si cea a ventriculelor. După ce traversează nodulul atrio-ventricular, impulsul se transmite către ventricule.
.
Figura 1.6. Secțiune prin inimă, Sursa [8]
Potențialul electric este generat de mișcarea ionilor între fețele internă si externă a membranei celulare. Diferența dintre potențialul electric de pe cele două fețe poartă numele de potențial de membrană. În repaus, acesta are o valoare de aproximativ -80mV pentru celulele cardiace. În momentul în care pe membrană este aplicat un stimul, se deschid o serie de canale ionice. În prima fază, ionii de sodiu trec din mediul extracelular in celulă, astfel încât potențialul membranar urcă rapid până la +30mV, proces numit depolarizare. În urma acestei modificări de potențial, canalele pentru sodiu se închid, urmând o fază de platou dată de efluxul de ioni de potasiu concomitent unui influx de ioni de calciu. În ultima fază are loc repolarizarea, prin continuarea efluxului de ioni de potasiu si încetarea influxului de calciu.
Figura 1.7. Fiziologia electrică a celulei musculare cardiac, Sursa [4]
În Figura 1.7. se poate observa mecanismul de depolarizare a celulei musculare. În primă fază, membrana celulară este polarizată negativ: avem ioni de sodiu în exteriorul membranei și ioni de potasiu în interiorul ei (membrana este polarizată pozitiv la exterior și negativ la interior). Tensiunea de repaus are o valoare în jur de -70mV. La venirea stimulului electric, se deschid canalele active de sodiu, permițând intrarea sodiului și, prin urmare, creșterea potențialului. Astfel are loc depolarizarea membranei celulare (membrana devine polarizată negativ în exterior și pozitiv în interior). Urmează o fază de platou în care canalele de sodiu încep să se închidă concomitent cu deschiderea celor de potasiu. Repolarizarea celulei are loc cu ajutorul pompelor active care au nevoie de energie pentru a expulza sodiul în exterior.
1.3. Electrocardiograma (ECG/EKG)
Pentru a realiza acest subcapitol, am folosit sursele [4], [5], [6], [9].
După cum am prezentat anterior, proprietatea care diferențiază cordul de restul organelor din punct de vedere funcțional este automatismul – abilitatea anumitor celule cardiace de a genera spontan potențiale electrice ce se propagă de-a lungul celulelor musculare, traducându-se astfel printr-o contracție mecanică. Aceste potențiale electrice pot fi înregistrate cu ajutorul unor electrozi, obținându-se astfel electrocardiograma. Propagarea potențialului electric se face radiar, din aproape în aproape, respectând bariera electrică dintre atrii și ventricule.
Plasarea electrozilor conectați la amplificatoare pe corp permite detectarea curentului electric asociat fiecărui ciclu cardiac. Electrozii pot fi așezați în moduri diferite pe corp, fiecare aranjare particulară numindu-se derivație. În Figura 1.8. sunt prezentați electrozi cu Ag/AgCl care se plasează direct pe pielea pacientului într-o anumită derivație. Derivațiile vor fi prezentate ulterior.
Figura 1.8. Electrozi de suprafață cu Ag/AgCl, Sursa [9]
Sunt folosite 12 derivații ce vor fi prezentate în cele ce urmează:
Trei derivații standard bipolare la nivelul membrelor (I, II, III)
Trei derivații unipolare la nivelul toracelui (CR, CL, CF)
Trei derivații amplificate unipolare la nivelul membrelor (aVL, aVF, aVR)
Șase derivații precordiale la nivelul toracelui (V1-V6)
Derivația I reprezintă măsurarea și redarea grafică a diferențelor de potențial generate de activitatea electrică cardiacă între electrozii de suprafață plasați pe mâna dreaptă respectiv mâna stângă. Electrodul de referință este pe piciorul drept. Acest electrod de referință (masa) va rămâne la fel și în celelalte două derivații.
Derivația II are electrozii de suprafață plasați pe mâna dreaptă respectiv piciorul stâng.
Derivația III are electrozii de suprafață plasați pe mâna stângă respectiv piciorul stâng.
Tensiunile care apar pe fiecare derivație în parte sunt definite mai jos:
D1, D2, D3 reprezintă tensiunea derivației I, II respectiv III.
𝛷𝐿, 𝛷𝑅, 𝛷𝐹 reprezintă potențialul electric al mâinii stângi, potențialul electric al mâinii drepte respectiv potențialul electric al piciorului stâng.
Conform legii lui Kirchhoff există următoarea relație între tensiunile celor trei derivații, care ne arată că numai două din cele trei derivații sunt independente:
Vectorii derivațiilor asociați cu sistemul de derivații al lui Einthoven se găsesc bazându-ne pe presupunerea că inima este localizată într-un volum conductor infinit si omogen (sau în centrul unei sfere omogene – a toracelui). Considerând că poziția mâinii drepte, a mâinii stângi și a piciorului stâng sunt vârfurile unui triunghi echilateral în al cărui centru se află inima, atunci vectorii derivațiilor formează de asemenea un triunghi echilateral. Triunghiul lui Einthoven este reprezentat în Figura 1.9:
Figura 1.9. Triunghiul lui Einthoven, Sursa [8]
Frank Norman Wilson (1890-1952) a studiat modul în care potențialele unipolare pot fi definite. El a propus ca referință “terminalul central” (CT). Referința mai este numită și potențialul la infinit, care într-un mediu infinit ar trebui să aibă valoarea zero. Pentru corpul uman nu este foarte ușor de aproximat potențialul la infinit din cauza configurației complicate a corpului și a numărului finit de electrozi. Aproximația introdusă de Wilson este că potențialul la infinit reprezintă media potențialelor celor două mâini și a piciorului stâng. Astfel, prin conectarea unei rezistențe de 5kΩ (Figura 1.10.) pe fiecare terminal de la cele trei membre, care ulterior sunt conectate într-un punct comun, se obține terminalul central (CT).
Demonstrația se realizează cu ajutorul primei teoreme a lui Kirchhoff:
Figura 1.10. Terminalul central – CT, Sursa [5]
Astfel, potențialul unipolar măsurat la nivelul piciorului drept este:
Modificând terminalul central Wilson (𝛷TCWm) se pot obține potențiale unipolare cu o amplitudine dublă, rezultând astfel derivațiile augmentate. Acest lucru se realizează eliminând rezistența conectată la electrodul care măsoară. În acest caz, potențialele unipolare sunt:
O altă metodă de înregistrare a electrocardiogramei este cea a derivațiilor amplificate (aVL, aVF, aVR) unipolare. Ea derivă din cele trei derivații standard bipolare. E. Goldberger introduce aceasta metodă în 1942. El a observat că poate amplifica potențialele obținute cu metoda lui Wilson dacă elimină rezistența conectată la electrodul care măsoară (electrodul pozitiv). În acest caz, electrodul negativ este o modificare a terminalului central descris de Wilson. Acesta se formează prin conectarea împreună a celor trei derivații standard (I, II, III) la borna negativă a electrocardiografului, după cum se poate vedea și în Figura 1.11.
aVL – electrodul pozitiv pe mâna stângă. Electrodul negativ este o combinație între electrodul plasat pe mâna dreaptă și cel de pe piciorul stâng, ce amplifică puterea semnalului din electrodul pozitiv de pe mâna stângă
aVR – electrodul pozitiv pe mâna dreaptă. Electrodul negativ este o combinație între electrodul plasat pe mâna stângă și cel de pe piciorul stâng, ce amplifică puterea semnalului din electrodul pozitiv de pe mâna dreaptă
aVF – electrodul pozitiv pe piciorul stâng. Electrodul negativ este o combinație între electrodul plasat pe mâna stângă și cel de pe mâna dreaptă, ce amplifică puterea semnalului din electrodul pozitiv de pe piciorul stâng
Figura 1.11. Sistemul de înregistrare ECG folosind derivațiile amplificate, Sursa [5]
În vederea obținerii unei informații mai bogate despre activitatea electrică a inimii se folosesc mai multe derivații. Astfel, se pot stabili diagnostice mai precise.
În Figura 1.12. este prezentată înregistrarea electrocardiogramei prin 6 derivații. Astfel, se plasează șase electrozi, V1-V6, pe suprafața pieptului acoperind diferite regiuni ale inimii. Ne dorim să înregistrăm activitatea electrică în plan perpendicular pe planul frontal.
Figura 1.12. Plasarea electrozilor pentru cazul înregistrării unipolare cu șase electrozi, Sursa [8]
În Figura 1.13. putem observa cum fiecare electrod din cei șase înregistrează o activitate electrică diferită a inimii. Din acest motiv, forma undei diferă de cea înregistrată bipolar cu trei electrozi:
Figura 1.13. Morfologia ECG măsurată de fiecare din cei șase electrozi, Sursa [8]
Cel mai folosit sistem pentru înregistrarea ECG este cel cu 12 derivații: I, II, III, aVL, aVF, aVR și V1-V6. Din cele 12 derivații, primele șase sunt măsurate în aceleași trei puncte. De aceea oricare două din cele șase derivații conțin exact aceeași informație ca restul de patru.
1.4. Caracteristicile electrocardiogramei
După cum se poate observa în Figura 1.14, obținerea undelor caracteristice electrocardiogramei reprezintă o consecință a depolarizării și a repolarizării atriilor respectiv a ventriculelor. Într-o primă fază, nodul sinoatrial determină depolarizarea atrială căreia îi corespunde pe electrocardiograma unda P. Datorită barierei electrice dintre atrii și ventricule, există o întârziere a impulsului între cele două etaje, tradusă prin intervalul dintre unda P si complexul QRS. A treia fază este constituită de depolarizarea ventriculară având drept consecință apariția complexului QRS. Unda T corespunde procesului de repolarizare ventriculară.
Figura 1.14. Obținerea electrocardiogramei, Sursa [10]
În funcție de succesiunea și frecvența de apariție a complexelor QRS, se pot determina anumite evenimente cardiace. În contextul acestui sistem destinat creșterii gradului de siguranță în trafic, determinarea complexelor QRS și a relației dintre complexele QRS vecine ne pot oferi informații importante cu privire la apariția unor eventuale aritmii (complexele vor apărea ca fiind mai apropiate față de activitatea cardiacă normală) sau a instalării somnului la volan (complexele vor apărea ca fiind mai depărtate decât în mod normal).
1.5. Electrocardiograma capacitivă
Electrocardiograma capacitivă (cECG) permite monitorizarea cardiacă a șoferilor fără a necesita contact direct cu pielea acestora. Ea propune amplasarea senzorilor capacitivi (electrozilor capacitivi) pe scaunul șoferului, făcând posibilă captarea semnalelor provenite de la inimă prin haine.
Pe când electrozii cu Ag/AgCl au un comportament preponderent rezistiv, cei utilizați pentru cECG formează o interfață capacitivă cu corpul uman. În [11] se precizează că în cazul electrocardiogramei prin electrozi capacitivi se obține o impedanță de cuplaj ridicată. Pentru a o compensa, este necesară amplificare direct lângă suprafața de cuplaj. De asemenea, electrozii capacitivi necesită ecranare deoarece sunt sensibili la zgomot (acesta poate proveni de la mișcările făcute de șofer în timpul condusului, de la încărcările electrostatice, etc).
Articolul din sursa [12] descrie un sistem de monitorizare cardiacă folosind electrozi capacitivi ce nu impun un contact direct cu pielea, denumit „The Aachen SmartChair”. Acesta poate fi integrat într-un automobil pentru a permite realizarea electrocardiogramei șoferilor în timp ce aceștia conduc. Datele obținute se transmit printr-o comunicație wireless către PC. Pentru a demonstra conceptul, sistemul a fost integrat într-un scaun de birou.
În cele ce urmează, voi prezenta principiile pe care a fost bazat acest experiment, precum și rezultatele obținute, fără a detalia însă realizarea comunicației wireless, deoarece lucrarea de față propune o modalitate de realizare a comunicației diferită.
Schema bloc a sistemului dezvoltat se poate vedea în Figura 1.15:
Figura 1.15. Schema bloc a sistemului Aachen SmartChair, Sursa [12]
Sistemul este format din doi electrozi activi și unul de comandă a piciorului drept, de referință. Semnalul care provine de la inimă este preluat prin haine de către cei doi electrozi capacitivi activi. Fiecare senzor activ amplifică semnalul preluat; cele două semnale sunt ulterior însumate, iar electrodul de referință ajută la rejecția de mod comun. Semnalul rezultat este amplificat prin intermediul amplificatorului operațional. După filtrări și ulterioare amplificări, semnalul este convertit din analog în digital și transmis către PC prin interfață serială sau printr-un convertor digital-analog către un monitor.
În contextul electrocardiogramei capacitive, suprafața electrozilor (realizați din metal conductor) este luată în considerare pentru a putea calcula capacitatea de cuplaj ce apare între corpul subiectului și intrarea în amplificatoarele A1 respectiv A2. În acest experiment, cei doi electrozi activi au avut fiecare suprafața A=4×8=32cm2. Capacitatea de cuplaj mai depinde de grosimea d a electrozilor, precum și de constanta dielectrică εr a materialului din care este realizată haina șoferului. Valorile din experiment sunt d=0.3mm și εr=1. Așadar, capacitatea rezultantă este:
Mediul înconjurător poate influența aceste măsurători. De aceea, electrozii trebuie sa fie ecranați. Pentru a evita influența energiei statice, este folosită rezistorul RBIAS de valoare foarte mare, de valoarea 100GΩ în această aplicație (energia statică se va descărca prin el). După cum se poate observa în Figura 1.16 ,RBIAS și cele două capacități C1 și C2 formează un filtru trece sus cu frecvența de tăiere:
Figura 1.16. Schema “circuitului de comandă a piciorului drept”, Sursa [12]
În practică, tensiunile de 50Hz de la sursa de alimentare care sunt conectate capacitiv la corpul pacientului pot duce la apariția unei tensiuni de mod comun, VCM, între corpul individului și circuitul izolat de aproximativ 1V. În Figura 1.15. , Cs reprezintă capacitatea de izolație între masa comună a circuitului și împământare. CP reprezintă cuplajul cu sursa de alimentară de 220V, iar CB cuplajul între circuit și împământare. Rejecția de mod comun (CMRR) a amplificatorului instrumental este finită, de aceea tensiunile de mod comun pot influența semnalul de ieșire VOUT și trebuie suprimate. Pentru eliminarea tensiunilor de mod comun se folosește “circuitul de comandă a piciorului drept” care conține electrodul de referință. Se poate observa atât în 1.15. cât și în 1.16. că suma celor două semnale culese de cei doi electrozi activi este influențată de amplificatorul invertor A3 spre planul conductiv C3. Rezistoarele RA și RF permit reglarea amplificării lui A3:
Pe lângă faptul că amplificatorul instrumental are un CMRR redus, un alt motiv pentru care suntem nevoiți să reducem tensiunea de mod comun este posibila transformare a semnalului diferențial la intrarea în amplificatorul diferențial, VD, după cum se poate vedea și în Figura 1.17:
Figura 1.17. Circuit echivalent pentru tensiunea de mod comun la intrarea în sistemul de măsurare, Sursa [12]
Această transformare a semnalului diferențial VD poate avea loc în contextul electrocardiogramei capacitive dacă capacitățile de cuplaj au valori diferite din cauza neomogenității hainelor.
Amplificatoarele A1 și A2 sunt de tipul OPA124.
Relația dintre VD și VCM este:
Cu
,
Pentru a minimiza interferențele de la intrarea în amplificatorul operațional avem două variante: ori ne asigurăm că cele două capacități, C1 și C2, sunt identice ori că VCM are o valoare cât mai mică posibil. Prin realizarea “circuitului de comandă a piciorului drept” am optat pentru a doua variantă, cea a unei valori cât mai mici pentru tensiunea de mod comun, VCM.
Cu amplificarea
Mai departe, pentru amplificarea semnalului la nivelul amplificatorului de intrumentație și pentru filtrarea sa, s-au utilizat:
Un amplificator de instrumentație, INA114 de la Texas Instruments
Un filtru Butterworth trece-sus de ordinul 4 cu frecvența de tăiere de 0,5Hz
Un amplificator tampon
Un filtru Butterworth trece-jos de ordinul 6 cu frecvența de tăiere de 200Hz
Un filtru Notch pentru eliminarea zgomotului de rețea cu frecvențele de tăiere 40Hz și 60Hz
Sistemul de măsurare a fost integrat într-un scaun de birou (Figura 1.18):
Figura 1.18. Integrarea sistemului într-un scaun de birou, Sursa [12]
Semnalul este apoi transmis wireless, iar electrocardiograma rezultată este vizualizată prin intermediul programului Labview.
Mai jos, în Figura 1.19, sunt reprezentate rezultatele obținute pe un subiect sănătos, în vârstă de 26 de ani, în timpul unei respirații normale, fără a impune alte mișcări subiectului:
Figura 1.19. Rezultate obținute prin haine de bumbac de diverse grosimi, Sursa [12]
Concluzia experimentului a fost că este posibilă monitorizarea cardiacă și fără contact cu pielea subiectului. Complexul QRS și unda T, relevante pentru anticiparea și prevenirea anumitor evenimente cardiace sau a ațipitului la volan, pot fi identificate clar.
Deoarece electrozii nu sunt fixați pe corp, mișcările pot duce la artefacte ale ECG-ului.
Capitolul 2 – Descrierea soluției propuse
După cum am precizat anterior, WHO (World Health Organisation) plasează afecțiunile cardiovasculare ca primă cauză a deceselor la nivelul mapamondului. De asemenea, s-a discutat și despre cauzele producerii accidentelor rutiere. Astfel, ne propunem să creștem siguranța tuturor participanților la trafic prin monitorizarea activității cardiace a șoferilor în timp ce aceștia conduc.
În subcapitolele anterioare, a fost prezentată fiziologia inimii și înregistrarea activității electrice a acesteia prin intermediul electrocardiogramei. Printr-o astfel de monitorizare se pot preveni atât evenimente cardiace cât și adormitul la volan. Astfel, se poate crește gradul de siguranță a șoferilor, pasagerilor și pietonilor.
Monitorizarea cardiacă a șoferilor nu se poate realiza însă prin intermediul electrocardiografiei clasice care presupune plasarea electrozilor direct pe pielea acestuia. Printre argumentele care susțin această afirmație se numără faptul că șoferii nu pot conduce comod având electrozi aplicați pe piele și fire care pot nu numai incomoda, cât pune în pericol siguranța acestora. Mai mult, aplicarea îndelungată a electrozilor pe piele pot duce la iritații ale acesteia.
Soluția propusă în lucrarea de față este un sistem de monitorizare a activității cardiace a șoferilor utilizând electrozi capacitivi amplasați pe scaun care să nu îl incomodeze pe acesta la condus. Bazându-mă pe cercetarea [12], am construit un sistem de realizare a electrocardiogramei fără contact și transmiterea acesteia prin intermediul modulului Bluetooth al unui microcontroler către un terminal mobil, unde aceasta va fi afișată.
Figura 2.1. Structura proiectului
Capitolul 3 – Componenta hardware
3.1. Principiul de funcționare
În Figura 3.1. este prezentată schema de principiu a proiectului. Electrozii sunt amplasați pe husa scaunului șoferului astfel: cei doi electrozi activi în partea superioară a husei, pe spătar, iar cel de referință (al cărui rol este de a rejecta modul comun) pe partea inferioară.
Semnalul preluat de către fiecare din cei doi electrozi activi este amplificat iar în vederea rejecției modului comun se folosește electrodul de referință. Pentru a evita pe cât posibil influența mediului înconjurător asupra calității semnalului, cele două amplificatoare al căror rol este de a amplifica semnalul preluat de către electrozii activi vor fi ecranate (introduse în cutii de cupru).
Semnalul amplificat, cele două semnale de alimentare precum și ground-ul sunt transmise mai departe cu ajutorul unui fir ecranat. Cele trei semnale, două de la electrozii activi și unul de la electrodul de referință sunt legate la un jack audio stereo. Prin intermediul jack-ului, semnalul diferențial intră în shield-ul EKG-EMG de la firma Olimex care este conectat la placa de dezvoltare Arduino Uno. La nivelul acesteia este convertit semnalul în digital.
Modulul Bluetooth HC-05 este conectat la placa de dezvoltare și transmite semnalul digital către terminalul mobil. Prin intermediul aplicației dezvoltate, datele sunt preluate și pe baza lor se realizează un grafic care reprezintă electrocardiograma utilizatorului.
Figura 3.1. Schema de principiu a proiectului
3.2. Componentele utilizate
Pentru a realiza partea hardware a proiectului am folosit următoarele componente:
2 rezistoare cu valoarea de 50GΩ de tip SMD
2 rezistoare cu valoarea de 5GΩ de tip SMD
2 rezistoare cu valoarea de 10MΩ
2 rezistoare cu valoarea de 100kΩ
2 potențiometre de 10kΩ
4 condensatoare cu valoarea de 47µF
3 condensatoare cu valoarea de 22nF
3 amplificatoare operaționale LM301A de la firma National Semiconductor
2 baterii de 9V fiecare
Cablu ecranat
1 jack audio stereo
2 plăci de sticlotextolit de dimensiune 11x11cm
1 placă de sticlotextolit de dimensiune 22x11cm
1 PCB de test pe care am împărțit-o în trei
O placă de dezvoltare Arduino Uno
Un shield EKG-EMG compatibil cu placa de dezvoltare Arduino Uno de la firma Olimex
Electrozi de contact compatibili pentru shield-ul ECG/EMG pentru rezultate comparative
Un modul Bluetooth HC-05
O husă de scaun de automobil
În următoarele subcapitole vor fi prezentate caracteristicile următoarelor componente: amplificatorul LM301A, placa de dezvoltare Arduino Uno, shield-ul EKG-EMG de la firma Olimex care este compatibil cu placa de dezvoltare Arduino Uno și modulul Bluetooth HC-05.
3.2.1. Amplificatorul LM301A
Amplificatorul LM301A face parte din seria amplificatoarelor operaționale de uz general LM101A, după cum este prezentat în datasheet, [13]. Pe baza aceluiași datasheet sunt prezentate toate informațiile din acest subcapitol.
Aceste amplificatoare sunt foarte eficiente oferind facilități precum protecția la suprasarcină atât la intrare cât și la ieșire, eliminarea oscilațiilor și compensarea prin intermediul unui condensator de 30pF. De asemenea, oferă acuratețe ridicată și zgomot scăzut în circuitele cu impedanță înaltă. Amplificatoarele LM101A funcționează în parametrii normali în intervalul de temperatură 55°C -125°C, LM201A în intervalul 25°C – 85°C iar LM301A în intervalul 0°C – 70°C. Tensiunea de alimentare este de 18V, iar tensiunea de la intrarea sa este de ordinul mV.
În Figura 3.2. este prezentată diagrama de conectare a amplificatorului LM301A:
Figura 3.2. Diagrama de conectare a amplificatorului LM301A, Sursa [13]
3.2.2. Placa de dezvoltare Arduino Uno
Pentru a realiza acest subcapitol, am folosit informațiile tehnice oferite pe website-ul oficial Arduino, [14], precum și cele disponibile pe website-ul magazinului Robofun, [15].
După cum este descris în [15], Arduino Uno este o „platformă de procesare open-source, bazată pe software și hardware flexibil și simplu de folosit”. Această platformă conține un procesor de semnal care poate rula codul scris într-un limbaj de programare foarte asemănător C++. Arduino Uno poate prelua prin intermediul a diverși senzori informații din mediul exterior. De asemenea, poate acționa în mediu prin intermediul unor dispozitive mecanice, cum ar fi motoarele și servomotoarele. Placa de dezvoltare Arduino Uno se poate conecta la calculatorul personal prin intermediul portului USB al calculatorului.
Arduino Uno este o platformă de dezvoltare bazată pe microcontrolerul ATmega328P. Are 14 pini de intrare/ieșire digitale, 6 intrări analogice, cristal de cuarț cu frecvența de 16MHz, un buton de Reset, o conexiune USB și alimentare.
Tabel 3.1. Placa de dezvoltare Arduino Uno – specificații tehnice, Sursa [15]
În Figura 3.3. este prezentată platforma de dezvoltare Arduino Uno împreună cu o prezentare succintă a pinilor.
Figura 3.3. Placa de dezvoltare Arduino Uno, Sursa [16]
3.2.3. Shield-ul EKG-EMG
După cum este prezentat și în manualul de utilizare [17], shield-ul EKG-EMG este un modul compatibil cu plăcile de dezvoltare Arduino. El poate fi întrebuințat în cadrul mai multor aplicații, în special pentru realizarea electrocardiogramelor (ECG/EKG) și a electromiogramelor (EMG). El este reprezentat în Figura 3.4:
Figura 3.4. Shield-ul EKG-EMG privit de sus, Sursa [17]
În cadrul proiectului realizat, acest shield este folosit pentru a face legătura cu placa de dezvoltare Arduino Uno. De asemenea, semnalul este amplificat (întâi prin intermediul unui amplificator de instrumentație, INA321EA, apoi prin intermediul amplificatoarelor operaționale MCP607) și filtrat cu ajutorul a mai multor blocuri de filtrare.
După cum se poate observa în schema electrică a shield-ului EKG-EMG, disponibilă în Anexa 1 (Sursa [17], pagina 18), semnalele provenite de la electrozii compatibili cu shield-ul EKG-EMG achiziționați din comerț (Figura 3.6.) intră în amplificator prin intermediul unui jack audio stereo, ca în figura Figura 3.5:
Figura 3.5. Intrarea în shield-ul EKG-EMG a semnalului provenit de la electrozi, Sursa [17]
Figura 3.6. Electrozi de contact compatibili cu shield-ul EKG-EMG achiziționați din comerț, Sursa [18]
Codul scris pentru afișarea electrocardiogramei în Serial Plotter, în mediul de dezvoltare Arduino, prin intermediul shield-ului EKG-EMG, precum și pentru transmiterea datelor prin Bluetooth către terminalul mobil, este disponibil în Anexa 2.
3.2.4. Modulul Bluetooth HC-05
În vederea descrierii pe scurt a standardului de comunicație Bluetooth, am sintetizat informație prezentată în sursa [19].
Bluetooth este un standard de comunicație de voce și date wireless, pe distanțe scurte, bazată pe tehnologia radio. Are consum de putere mic, preț scăzut, este securizat și are o rază de acțiune redusă. Scopul acestui standard este de a permite realizarea unei rețele personale (PAN – Personal Area Network) care să permită conexiunea lipsită de cabluri între diverse dispozitive electronice: telefoane mobile, tablete, calculatoare personale etc. De asemenea, poate fi folosit ca punct de acces WLAN.
Pentru a folosi tehnologia Bluetooth, se utilizează spectrul de bandă de 2.4 GHz, care nu necesită licență.
În funcție de clasa din care face parte, raza de acțiune poate varia.
Fiecare dispozitiv Bluetooth are o adresă numită Bluetooth Device Address (BD_ADDR). Aceasta are o lungime de 48 biți și este împărțită în trei secțiuni, după cum se poate vedea și în Figura 3.7. Cu o lungime de 24 biți, avem Least Address Part (LAP), cu 8 biți Upper Address Part (UAP) și cu 16 biți avem Non-significant Address Part (NAP).
Figura 3.7. Bluetooth Device Address (BD_ADDR), Sursa [19]
În continuare, sunt prezentate caracteristicile tehnice ale modulului Bluetooth HC-05, așa cum sunt ele prezentate în sursa [20]:
Tensiune de alimentare: 3.6 – 6V
Curent consumat: maxim 30mA
Pinii de I/O sunt compatibili pentru 3.3V
Comunică pe serială UART
Baudrate: 9600 – 460800 bps
Distanță de transmisie: <10m
Putere de transmisie: +4dBm
Senzitivitate recepție: -80dBm
Dimensiuni: 35.7 x 15.2 mm
Figura 3.8. Vedere din față a modulului Bluetooth HC-05, Sursa [20]
Figura 3.9. Vedere din spate a modulului Bluetooth HC-05, Sursa [20]
3.3. Realizarea practică a husei pentru scaun
Pentru a realiza practic husa pentru scaunul șoferului, am urmat o serie de etape pe care le voi descrie în cele ce urmează. Componentele folosite sunt cele prezentate la Capitolul 3.2.
Schema electrică folosită pentru implementare este cea din Figura 3.10:
Figura 3.10. Schema electrică a circuitului
Permitivitatea electrică a vidului este ε0=8.85×1012, constanta dielectrică a aerului εr=1, aria unui electrod activ (a plăcuței de sticlotextolit) este A=10×10=100cm2, iar grosimea sa este d=0.5mm. Astfel, putem calcula capacitatea de cuplaj între corpul șoferului și intrarea în amplificatoarele LM301A pe baza formulei:
Deci valoarea capacităților de cuplaj este C =177pF (după cum se poate observa și pe schemă).
Capacitatea de cuplaj (177pF) împreună cu rezistența de intrare (50GΩ) formează un filtru trece sus cu frecvența de tăiere calculată pe baza formulei:
Astfel, frecvența de tăiere are valoarea de 0.18Hz. Pentru a obține electrocardiograma, este necesar ca frecvența de tăiere să fie de cel mult 0.5Hz, așa că frecvența de tăiere calculată se încadrează.
După cum se poate observa în Figura 3.10, fiecare din cei doi electrozi activi sunt urmați de amplificatoare cu impedanța de intrare foarte mare, de ordinul GΩ. Impedanța de valoare mare la intrarea în amplificatorul operațional are rolul de a nu diviza semnalul util între impedanța electrodului capacitiv și impedanța de intrare în amplificatorul operațional. Utilizarea acestor rezistoare de valori atât de mari se mai justifică și astfel: ele asigură curentul de polarizare pentru intrarea în amplificatorul operațional și, cum electrocardiograma este realizată prin haine și este foarte probabil ca energia electrostatică acumulată prin mișcarea subiectului să afecteze într-un mod negativ analiza, ele ajută la descărcarea energiei electrostatice prin ele.
Amplificatoarele folosite sunt LM301A realizate de compania National Semiconductor. Amplificatoarele sunt dispuse în configurație neinversoare, oferind o amplificare cuprinsă între 11 si 101 (variabilitatea amplificării este posibilă prin utilizarea potențiometrelor de 10kΩ și a rezistoarelor de 100kΩ). După cum am prezentat în subcapitolul 3.2.1., pentru o compensare mai bună a amplificatoarelor LM301A se utilizează condensatoare de aproximativ 30pF dispuse între pinii de compensare ai amplificatorului. În cazul aplicației curente, s-au utilizat amplificatoare de 22pF. Condensatoarele de 47pF conectate la bornele de alimentare ale amplificatoarelor sunt condensatoare de decuplare a alimentării al căror rol este de a menține tensiunea de la borne constantă în cazul circuitelor alimentate în curent continuu. În cazul acestui proiect, alimentarea este reprezentată de două baterii de 9V înseriate (deci 18V). Este important ca ambele baterii să aibă valori egale.
Cele două rezistoare de 10MΩ împreună cu amplificatorul de la electrodul de referință au rolul de a rejecta modul comun. Așa cum s-a prezentat și în subcapitolul 1.5, modelul „The Aachen SmartChair”, tensiunea de mod comun, de valori de aproximativ 1V (valori extrem de mari deoarece semnalul util este de ordinul µV sau maxim mV), poate apărea din cauza tensiunii de 50Hz de la sursa de alimentare. Rejecția modului comun este importantă deoarece rejecția amplificatorului este finită așadar utilizăm “circuitul de comandă a piciorului drept” care conține electrodul de referință. Astfel, amplificatorul de la electrodul de referință are o amplificare de:
A3===500
Valoarea de 2.5GΩ s-a obținut punând în paralel două rezistoare cu valoarea de 5GΩ.
Circuitul prezintă două tipuri de masă: masa de semnal și masa funcțională. Masa funcțională este legată la ground-ul shield-ului EKG-EMG de la Olimex (la V_Ref din schema shield-ului, disponibilă în Anexa 1) .
Cele două semnale provenite de la electrozii activi împreună cu cel de la electrodul de referință, după rejecția modului comun, sunt introduse prin intermediul unui jack stereo în shield-ul EKG-EMG care are rol de amplificator instrumental și oferă mai multe blocuri de filtrare.
Pentru a reduce pe cât posibil influența mediului exterior, cele două amplificatoare ale electrozilor activi sunt ecranate (introduse în cutii de Cupru).
Figura 3.11. Montajul realizat: cele trei plăci de sticlotextolit, amplificatoarele electrozilor activi și cel al electrodului de referință
Figura 3.12. Montajul realizat: cele trei plăci de sticlotextolit, amplificatoarele electrozilor activi și cel al electrodului de referință, bateriile de 9V înseriate, shield-ul EKG-EMG dispus deasupra plăcii de dezvoltare Arduino Uno
Figura 3.13. Montajul realizat: amplificatorul aferent electrodului activ
Figura 3.14. Montajul realizat: amplificatorul aferent electrodului de referință
Figura 3.15. Montajul realizat: amplificatorul aferent electrodului de referință, vedere din față
Figura 3.16. Montajul realizat: amplificatorul aferent electrodului de referință și bateriile înseriate
Figura 3.17. Montajul realizat: confecționarea cutiilor de cupru pentru ecranare, etape de realizare
Figura 3.18. Montajul realizat: montaj complet, înainte de amplasarea lui pe scaunul șoferului
Figura 3.19. Amplasarea electrozilor pe scaunul șoferului
3.4. Rezultate experimentale
În continuare, vor fi prezentate rezultatele obținute cu sistemul realizat. Electrocardiograma a fost obținută în Serial Plotter-ul din mediul de dezvoltare Arduino. Se vor prezenta trei cazuri:
electrocardiograma realizată prin amplasarea electrozilor din comerț direct pe piele
electrocardiograma realizată prin amplasarea electrozilor realizați pe husa scaunului șoferului și prin contact direct cu pielea acestuia
electrocardiograma realizată prin amplasarea electrozilor realizați pe husa scaunului șoferului și prin hainele acestuia
De asemenea, înregistrările se vor efectua în două situații:
atunci când placa de dezvoltare Arduino Uno este alimentată de la un laptop conectat la rețea (alimentat la priză)
atunci placa de dezvoltare Arduino Uno este alimentată de la un laptop care nu este alimentat de la rețea (alimentat de către acumulator).
Figura 3.20. ECG cu electrozii din comerț, plasați pe piele, cu placa de dezvoltare Arduino Uno alimentată de un laptop conectat la rețea
Figura 3.21. ECG cu electrozii din comerț, plasați pe piele, cu placa de dezvoltare Arduino Uno alimentată de un laptop care nu este conectat la rețea
Figura 3.22. ECG cu electrozii realizați amplasați pe husa scaunului șoferului și prin contact direct cu pielea acestuia, cu placa de dezvoltare Arduino Uno alimentată de un laptop conectat la rețea
Figura 3.23. ECG cu electrozii realizați amplasați pe husa scaunului șoferului și prin contact direct cu pielea acestuia, cu placa de dezvoltare Arduino Uno alimentată de un laptop care nu este conectat la rețea
Figura 3.24. ECG cu electrozii realizați amplasați pe husa scaunului șoferului și înregistrarea făcută prin haine, cu placa de dezvoltare Arduino Uno alimentată de un laptop conectat la rețea
Figura 3.25. ECG cu electrozii realizați amplasați pe husa scaunului șoferului și înregistrarea făcută prin haine, cu placa de dezvoltare Arduino Uno alimentată de un laptop care nu este conectat la rețea
După cum se poate observa în rezultatele experimentale, calitatea ECG-ului obținut prin haine, cu ajutorul electrozilor capacitivi, este comparabilă cu cea obținută prin intermediul electrozilor compatibili cu shield-ul EKG-EMG din comerț. Complexul QRS se distinge clar în ambele situații.
De asemenea, se poate constata că alimentarea plăcii de dezvoltarea Arduino Uno prin intermediul unui laptop conectat la rețea nu este indicată deoarece introduce zgomot.
Capitolul 4 – Componenta software
4.1. Schema logică a aplicației
Figura 4.1. Schema logică a aplicației Android “ECG”
4.2. Descrierea aplicației Android
Aplicația “ECG” este o aplicație Android care permite afișarea electrocardiogramei șoferului. Ea se conectează la modulul Bluetooth HC-05 care primește datele preluate de către electrozi prin intermediul plăcii de dezvoltare Android Uno și a shield-ului EKG-EMG de la Olimex.
Dezvoltarea aplicației a fost realizată în Android Studio, mediul integrat de dezvoltare oficial al platformei Android [21]. Android Studio oferă o varietate de instrumente utile pentru dezvoltare aplicațiilor destinate sistemului de operare Android.
Figura 4.2. Logo-ul mediul integrat de dezvoltare Android Studio, Sursa [22]
După cum se poate observa și în Figura 4.1, unde este prezentată schema logică a aplicației, la inițializare se verifică dacă se poate utiliza serviciul Bluetooth al terminalului mobil. În cazul în care acest serviciu nu este activat, aplicația nu poate funcționa. De aceea, se cere permisiunea de a activa acest serviciu (Figura 4.3.). În cazul în care aplicația este utilizată pentru prima oară, se va cere permisiunea de a folosi serviciul de localizare al terminalului (Location – Figura 4.4.), cerință impusă de versiunea 6 a sistemului de operare Android. Aplicația oferă apoi lista dispozitivelor care au fost deja partajate (pair-uite) cu terminalul mobil; dacă modulul HC-05 a fost deja partajat, el va apărea în această listă din care îl putem selecta. În caz contrar, (Figura 4.5.) putem scana în raza de acțiune a terminalului mobil pentru a găsi dispozitive Bluetooth disponibile cu care aplicația se poate conecta (Figura 4.6.). După realizarea conexiunii, noul dispozitiv Bluetooth va apărea în lista de dispozitive partajate (precum în Figura 4.7.). Odată conectat prin intermediul aplicației “ECG” la dispozitivul Bluetooth corespunzător (în cazul proiectului de față, modulul Bluetooth HC-05), terminalul mobil va primi datele provenite de la electrozi prin intermediul plăcii de dezvoltare Arduino Uno și a shield-ului EKG-EMG și dacă acestea sunt valide va putea afișa graficul corespunzător electrocardiogramei șoferului (Figura 4.8.).
Figura 4.3. Aplicația cere permisiunea de a porni serviciul Bluetooth al terminalului mobil
Figura 4.4. Aplicația cere permisiunea de a porni serviciul de localizare (Location) al terminalului mobil
Figura 4.5. Lista dispozitivelor Bluetooth deja partajate cu terminalul mobil
Figura 4.6. Lista dispozitivelor Bluetooth disponibile în raza terminalului mobil
Figura 4.7. Lista dispozitivelor Bluetooth deja partajate cu terminalul mobil în cazul în care modulul HC-05 este partajat (paired)
Figura 4.8. Electrocardiograma văzută în cadrul aplicației Android de pe terminalul mobil
Aplicația “ECG” conține cinci clase (dintre care trei sunt activități) ce vor fi descrise în subcapitolele ce urmează:
BluetoothService
Constants
DeviceListActivity
MainActivity
MeasureActivity
4.3. Bluetooth în Android
Acest subcapitol a fost realizat pe baza informației disponibile pe website-ul oficial Android, din cadrul secțiunii dedicate special celor ce doresc să dezvolte aplicații destinate acestui sistem de operare, [23].
Platforma Android oferă API-ul necesar dezvoltării de aplicații ce utilizează Bluetooth, permițând schimbul de date între dispozitivul mobil și hardware.
Proiectul de față este realizat folosind modulul Bluetooth HC-05 care presupune realizarea unei conexiuni Bluetooth standard. Totodată există și suportul necesar dezvoltării de proiecte ce necesită un consum redus de energie, caz în care este necesară folosirea de module Bluetooth cu consum de energie redus (Bluetooth Low Energy).
După cum am menționat în paragraful anterior, pentru proiectul de față se realizează o conexiune Bluetooth standard. Pentru a comunica prin Bluetooth, se realizează următoarele acțiuni:
Se setează Bluetooth-ul
Se găsesc dispozitivele Bluetooth care sunt partajate (pair-uite) sau cele care sunt disponibile în apropiere
Se conectează dispozitivele
Se transmit date între dispozitivul mobil și modulul Bluetooth utilizat (HC-05)
Pentru a putea utiliza Bluetooth în aplicație, este necesară declararea permisiunii BLUETOOTH. Aceasta permite realizarea comunicației Bluetooth (solicitarea unei conexiuni, acceptarea unei conexiuni și transferul de date).
Permisiunea BLUETOOTH_ADMIN este necesară pentru a inițializa descoperirea de dispozitive și pentru a manipula setările Bluetooth.
Cele două permisiuni au fost declarate în fișierul Manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Tot aici, este declarată și permisiunea de a utiliza localizarea terminalului mobil (necesară pentru sistemul de operare Android versiunea 6):
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Pentru configurarea Bluetooth trebuie să se verifice dacă terminalul mobil poate oferi acest serviciu și, în caz afirmativ, să se probeze dacă serviciul Bluetooth este disponibil. Pentru a realiza acest lucru, avem nevoie de BluetoothAdapter. Acesta reprezintă adaptorul Bluetooth local, fiind elementul cheie pentru toată interacțiunea Bluetooth. Cu ajutorul lui, se pot descoperi alte dispozitive Bluetooth, se pot interoga o listă de dispozitive deja partajate (pair-uite), se pot instanția dispozitive Bluetooth folosind o adresă MAC cunoscută și se poate crea un BluetoothServerSocket, folosit pentru a primi comunicația venită de la alte dispozitive.
Obținerea BluetoothAdapter-ului se face prin apelarea metodei statice getDefaultAdapter() care returnează adaptorul Bluetooth al dispozitivului, BluetoothAdapter. Metoda ajută și la verificarea existenței serviciului Bluetooth pe terminal: dacă metoda returnează valoarea null ni se indică faptul că dispozitivul nu oferă serviciul Bluetooth.
În clasa BluetoothService, se obține adaptorul Bluetooth al terminalului mobil:
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Activarea serviciul Bluetooth, în cazul în care acesta este inactiv, se face în activitatea DeviceListActivity:
if(!MainActivity.sBluetoothAdapter.isEnabled()){
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, Constants.REQUEST_ENABLE_BT);
}
Aplicația va cere permisiunea de a activa Bluetooth, după cum se poate vedea în Figura 4.3.
Cu ajutorul adaptorului BluetoothAdapter se pot găsi dispozitive Bluetooth: se pot descoperi/scana dispozitive noi sau se pot interoga cele din lista de dispozitive partajate. Descoperirea dispozitivelor este o procedură de scanare care caută în aria de acoperire a dispozitivului Bluetooth alte dispozitive cărora le solicită anumite informații. Pentru a putea descoperi un dispozitiv trebuie ca acesta să fie poată fi găsit, să fie descoperibil. În aceste condiții, el va răspunde cu anumite informații precum: numele său, clasa și adresa MAC. Pe baza acestor informații dispozitivul care face descoperirea poate iniția o conexiune cu dispozitivul descoperit. Atunci când se realizează o conexiune cu un dispozitiv pentru prima oară, se inițiază automat o cerere de partajare (pairing). Atunci când un dispozitiv este partajat, se salvează informații de bază despre el, precum: numele, clasa și adresa MAC, care pot fi citite cu ajutorul API-ului de Bluetooth. Atunci când se cunoaște adresa MAC a unui dispozitiv și acesta se află în aria de acoperire, se poate iniția o conexiune în orice moment fără a mai fi necesar procesul de descoperire.
Un dispozitiv partajat este un dispozitiv a cărui existență este cunoscută de către dispozitivul care dorește să se conecteze, are o cheie de legătură care poate fi utilizată pentru autentificare și este capabil să realizeze o conexiune criptată cu dispozitivul care dorește să se conecteze. A fi conectat înseamnă însă că cele două dispozitive împart deja un canal RFCOMM și sunt capabile să transmită date între ele. API-ul Bluetooth existent în Android impune ca cele două dispozitive să fie deja partajate înainte de realizarea conexiunii RFCOMM.
Pentru a obține lista dispozitivelor partajate (paired), am folosit metoda getBondedDevices() în cadrul activității DeviceListActivity:
Set<BluetoothDevice> pairedDevices=MainActivity.sBluetoothAdapter.getBondedDevices();
if(pairedDevices.size()>0){
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for(BluetoothDevice device : pairedDevices){
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}else{
String noDevices = "No Paired devices found";
mPairedDevicesArrayAdapter.add(noDevices);
}
Dacă există deja dispozitive partajate, ele sunt adăugate în lista ce conține dispozitivele partajate. În caz contrar, se afișează că nu s-au descoperit dispozitive partajate.
Atunci când se descoperă dispozitive noi, cele la care să ne conectăm vor fi partajate și adăugate în lista destinată lor. Pentru a sesiza fiecare modificare ce intervine în listele destinate afișării de dispozitive disponibile se utilizează un ArrayAdapter<String>.
BroadcastReceiver ascultă dispozitivele descoperite și se schimbă atunci când descoperirea se încheie.
private BroadcastReceiver mNewDiscoverReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch(action){
case BluetoothDevice.ACTION_FOUND:
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getBondState() != BluetoothDevice.BOND_BONDED){
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
setProgressBarIndeterminateVisibility(false);
setTitle("Select a device to connect");
mNewDevicesListView.setClickable(true);
if(mNewDevicesArrayAdapter.getCount() == 0){
String noDevices = "No New devices found.";
mNewDevicesArrayAdapter.add(noDevices);
mNewDevicesListView.setClickable(false);
}
break;
}
}
Conexiunea prin Bluetooth între două dispozitive se realizează astfel: unul dintre cele două va avea rolul de server și va avea BluetoothServerSocket deschis, va aștepta cererile de conexiune. Atunci când se va realiza conexiunea, prin intermediul interfeței BluetoothSocket se vor putea schimba date între cele două dispozitive prin InputStream și OutputStream. În cazul proiectului de față, serverul este reprezentat de modulul Bluetooth atașat plăcii de dezvoltare Arduino Uno, iar clientul este terminalul mobil. Pentru gestionarea datelor transmise între cele două dispozitive conectate, am folosit un thread ConnectedThread. În cadrul unei bucle infinite se citesc datele provenite de la server (de la modulul de Bluetooth HC-05). Acestea se rețin în cadrul unui String (readed). În cazul în care există date citite, acestea sunt transmise către activitatea MeasureActivity unde vor fi prelucrate și, în cele din urmă, afișate sub forma unui grafic care, în cazul proiectului de față, va reprezenta electrocardiograma șoferului.
4.4. Trasarea graficului corespunzător electrocardiogramei în aplicație
MeasureActivity este activitatea în cadrul căreia se prelucrează datele primite prin Bluetooth în scopul obținerii unui grafic care reprezintă electrocardiograma șoferului. Constantele utilizate pentru realizarea graficului au fost definite în clasa Constants. Starea conexiunii Bluetooth (conectat, în curs de conectare sau neconectat) se poate verifica prin intermediul obiectului de tip BluetoothService. Tot prin intermediul unor mesaje se obține și numele dispozitivului cu care s-a creat conexiunea, precum și recepția datelor. Aceste mesaje devin vizibile cu ajutorul unui obiect de tip Handler care ajută la trimiterea și procesarea mesajelor și a obiectelor asociate cu un thread. Fiecare instanță a unui Handler este asociată cu un singur thread și cu coada de mesaje a acestuia. Atunci când se creează un Handler, el este legat cu thread-ul/coada de mesaje a thread-ului care îl creează. Din acel punct, el va livra mesaje și executabile acelei cozi de mesaje și le va executa cum ies din coada de mesaje. Handler-urile sunt utilizate pentru a programa executarea mesajelor și a executabilelor la același moment din viitor, dar și pentru a pune în coadă o acțiune pentru a fi realizată pe un thread diferit.
private final Handler mHandlerMess = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case Constants.MESSAGE_STATE_CHANGE:
switch(msg.arg1){
case Constants.STATE_CONNECTED:
mTxtStatus.setTextColor(Color.argb(0xff, 0x4C, 0xAF, 0x50));
mTxtStatus.setText("Connected to " + mConnectedDeviceName);
mConnectionState = true;
invalidateOptionsMenu();
break;
case Constants.STATE_CONNECTING:
mTxtStatus.setTextColor(Color.BLACK);
mTxtStatus.setText("Connecting…");
break;
case Constants.STATE_LISTEN:
break;
case Constants.STATE_NONE:
mTxtStatus.setText("Not connected");
mTxtStatus.setTextColor(Color.RED);
mConnectionState = false;
invalidateOptionsMenu();
break;
}
break;
case Constants.MESSAGE_DATA_WRITE:
break;
case Constants.MESSAGE_DATA_READ:
counter = 0;
final String readMessage = (String)msg.obj;
int[] readBuffer = parseMessage(readMessage);
plotData(readBuffer);
break;
case Constants.MESSAGE_DEVICE_NAME:
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
Toast.makeText(MeasureActivity.this, "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case Constants.MESSAGE_TOAST:
Toast.makeText(MeasureActivity.this, msg.getData().getString(Constants.TOAST),Toast.LENGTH_SHORT).show();
break;
}
}
};
În MeasureActivity, datele recepționate prin Bluetooth sub forma unui String sunt convertite în numere întregi și adăugate într-un vector ce va fi folosit mai departe în trasarea graficului. Tot aici, prin intermediul Handler-ului mHandlerMess care are rolul de a obține informația de la serviciul Bluetooth, se stabilește comportamentul pentru stările: conectat, în curs de conectare, neconectat, dar și pentru mesajele de tip schimbare a stării, citire a datelor, scriere a datelor (nu este cazul pentru aplicația de față), nume al dispozitivului. Graficul este realizat cu ajutorul metodei plotData.
Codul aferent celor cinci clase principale se poate găsi în Anexa 3. Proiectul în totalitate este disponibil pe CD.
4.5. Rezultate experimentale
În continuare sunt prezentate electrocardiogramele obținute în aplicația dezvoltată pentru sistemul de operare Android. Acestea au fost realizate în trei moduri:
prin intermediul electrozilor compatibili cu shield-ul EKG-EMG de la firma Olimex cumpărați din comerț și aplicați pe piele
prin intermediul electrozilor realizați aplicați direct pe pielea șoferului
prin intermediul electrozilor realizați dispuși pe husa scaunului șoferului ce achiziționează biopotențialele prin haine de bumbac
Figura 4.9. Electrocardiograma obținută în aplicația Android folosind electrozii din comerț
Figura 4.10. Electrocardiograma obținută în aplicația Android folosind electrozii realizați aplicați direct pe piele
Figura 4.11. Electrocardiograma obținută în aplicația Android folosind electrozii realizați aplicați pe husa scaunului șoferului
Concluziile proiectului
În această lucrare am prezentat un sistem destinat monitorizării activității cardiace a șoferilor folosind electrozi ce nu necesită contactul direct cu pielea șoferului.
După cum se poate observa în rezultatele experimentale prezentate anterior (în subcapitolele 3.4. și 4.5.), calitatea electrocardiogramei obținute prin haine prin intermediul electrozilor capacitivi este comparabilă cu cea obținută prin utilizarea electrozilor ce necesită contactul direct cu pielea șoferului (electrozii compatibili cu shield-ul EKG-EMG achiziționați din comerț sau electrozii capacitivi dispuși direct pe pielea șoferului). Complexul QRS se distinge clar în toate situațiile, ceea ce poate permite calcularea frecvenței cardiace, determinarea unor afecțiuni cardiace precum aritmiile sau detectarea instalării somnului.
După cum am observat în rezultatele experimentale din subcapitolul 3.4., pentru îmbunătățirea calității semnalului preluat se recomandă ca placa de dezvoltare Arduino Uno împreună cu shield-ul EKG-EMG să fie alimentate prin intermediul unei baterii. Astfel, se poate reduce zgomotul de rețea care influențează semnalul achiziționat.
O limitare a soluției propuse pentru monitorizarea cardiacă a șoferilor o constituie faptul că aceasta poate fi puternic influențată de mișcarea șoferului precum și de îmbrăcămintea acestuia (materialul din care aceasta este confecționată, dar și grosimea acestuia).
Din punct de vedere al direcțiilor de dezvoltare viitoare, acestea pot fi atât pe plan hardware cât și pe plan software.
În plan hardware, se poate înlocui shield-ul EKG-EMG de la firma Olimex, destinat electrocardiogramelor prin contact, cu un ansamblu format dintr-un amplificator de instrumentație și mai multe blocuri de filtrare. Această abordare ar oferi un grad de adaptabilitate mai crescut pentru realizarea unui sistem de monitorizare cardiacă fără contact.
În plan software, se pot aduce o varietate de îmbunătățiri aplicației Android menite să crească și mai mult gradul de siguranță al participanților la trafic. O primă idee este transmiterea coordonatelor GPS ale șoferului către un dispecerat în cazul în care aplicația detectează o activitate cardiacă anormală sau chiar în cazul producerii unui accident. O a doua direcție de îmbunătățire software este oferirea posibilității de înregistrare a electrocardiogramelor în scopul realizării unui istoric al șoferului. O altă idee este oferirea posibilității de a crea în cadrul aplicației profiluri noi pentru cazul în care telefonul este partajat între mai mulți membri ai familiei. În cele din urmă, se poate implementa o rețea neurală nesupervizată care să poată detecta abateri de la activitatea cardiacă considerată normală și să îl poată atenționa pe șofer de necesitatea de a programa pentru un consult medical specializat.
Bibliografie
[1] Global Status Report on Road Safety, WHO (World Health Organisation), 2015, http://www.who.int/violence_injury_prevention/road_safety_status/2015/en/, accesat la data 10 martie 2016
[2] Website-ul Serious Accidents, https://seriousaccidents.com/legal-advice/top-causes-of-car-accidents/, accesat la data de 15 martie 2016
[3] Malmuvio Jaakko, Plonsey Robert, Bioelectromagnetism, Capitolul 6, disponibil online http://www.bem.fi/book/, accesat la data de 15 martie 2016
[4] Malmuvio Jaakko, Plonsey Robert, Bioelectromagnetism, Capitolul 6.2., disponibil online http://www.bem.fi/book/, accesat la data de 15 martie 2016
[5] Malmuvio Jaakko, Plonsey Robert, Bioelectromagnetism, Capitolul 15, disponibil online http://www.bem.fi/book/, accesat la data de 15 martie 2016
[6] Robin R. Preston, Thad E. Wilson, Physiology, Editura Lippincott’s Illustrated Reviews, 2013
[7] Website-ul disciplinei Electronică și Informatică Medicală din cadrul Departamentului de Electronică Aplicată a Facultății de Electronică, Telecomunicații și Tehnologia Informației, www.elmed.pub.ro, accesat la data de 28 martie 2016, platforma de laborator „Măsurarea presiunii sângelui”
[8] Website-ul disciplinei Electronică și Informatică Medicală din cadrul Departamentului de Electronică Aplicată a Facultății de Electronică, Telecomunicații și Tehnologia Informației, www.elmed.pub.ro, accesat la data de 28 martie 2016, platforma de laborator „Principiile electrocardiografiei”
[9] Website-ul Cephalon, http://shop.cephalon.eu/Pre-gelled-Disposable-Surface-Electrode,-50-cm-Lea/ItemDetails.aspx?9=GB&5=9013L0453&11=1959, accesat la data de 28 martie 2016
[10] Curs despre anatomia inimii, Pearson Education, http://www.slideshare.net/kmilaniBCC/heart-2-online, accesat la data de 28 martie 2016
[11] Marian Walter, Benjamin Eilebrecht, Tobias Wartzek, Steffen Leonhardt, „The smart car seat: personalized monitoring of vital signs in automotive applications”, publicat online la data de 7 ianuarie 2011, https://www.academia.edu/17848549/The_smart_car_seat_personalized_monitoring_of_vital_signs_in_automotive_applications, accesat la data de 5 mai 2016
[12] A. Aleksandrowicz, S. Leonhardt, „Wireless and Non-Contact ECG Measurement System, „The Aachen SmartChair”, publicat în Acta Polytechnica, Vol. 47, No. 4-5, anul 2007
[13] Data Sheet-ul amplificatorului operațional LM301, http://www.utm.edu/staff/leeb/LM301.pdf, accesat la data de 6 mai 2016
[14] Website-ul oficial al producătorului platformei de dezvoltare Arduino, https://www.arduino.cc/en/Main/ArduinoBoardUno, accesat la data de 6 mai 2016
[15] Website-ul oficial al magazinului de componente electronice Robofun, https://www.robofun.ro/arduino_uno_v3, accesat la data de 6 mai 2016
[16] Forumul website-ului oficial al producătorului platformei de dezvoltare Arduino, https://forum.arduino.cc/index.php?topic=363467.0, accesat la data de 6 mai 2016
[17] Manualul de utilizare a shield-ului EKG-EMG disponibil pe pagina producătorului Olimex, https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/resources/SHIELD-EKG-EMG.pdf, accesat la data de 6 mai 2016
[18] Website-ul magazinului online RapidOnline, http://www.rapidonline.com/olimex-shield-ekg-emg-pa-passive-electrodes-for-arduino-style-ekg-emg-shield-73-0275, accesat la data de 21 mai 2016
[19] Website-ul https://www.academia.edu/1349600/Bluetooth_Protocol_Tutorial_and_Simulation, accesat la data de 5 iunie 2016
[20] Website-ul oficial al magazinului de componente OptimusDigital, https://www.optimusdigital.ro/wireless-bluetooth/153-modul-bluetooth-master-slave-hc-05-cu-adaptor.html?search_query=bluetooth&results=29, accesat la data de 5 iunie 2016
[21] Website-ul Android, https://developer.android.com/studio/index.html, accesat la data de 10 iunie 2016
[22] Blogul dedicat dezvoltatorilor de aplicații Android, http://android-developers.blogspot.ro/2014/12/android-studio-10.html, accesat la data de 10 iunie 2016
[23] Website-ul Android, https://developer.android.com/guide/topics/connectivity/bluetooth.html, accesat la data de 10 iunie 2016
Anexe
Anexa 1 – Schema electrică a shield-ului EKG-EMG, Sursa [17]
Anexa 2 – Afișarea ECG în Serial Plotter și transmiterea datelor prin Bluetooth către terminalul mobil
#include "SoftwareSerial.h"
int bluetoothTx=2;
int bluetoothRx=3;
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
void setup() {
bluetooth.begin(9600);
Serial.begin(9600);
}
void loop() {
bluetooth.println(analogRead(0));
Serial.println(analogRead(0));
delay(10);
}
Anexa 3 – Codul folosit pentru realizarea aplicației Android
Clasa BluetoothService
package com.android.ekg_app;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class BluetoothService {
private static final String TAG = "BluetoothService";
private final BluetoothAdapter mBluetoothAdapter;
private final Handler mHandler;
private AcceptThread mSecureAcceptThread;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
public static boolean sConnectionState = false;
public BluetoothService(Context context, Handler handler) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mState = Constants.STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
Log.d(TAG, "start");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(Constants.STATE_LISTEN);
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
mSecureAcceptThread.start();
}
if (mInsecureAcceptThread == null) {
mInsecureAcceptThread = new AcceptThread(false);
mInsecureAcceptThread.start();
}
}
public synchronized void connect(BluetoothDevice device, boolean secure) {
Log.d(TAG, "connect to: " + device);
if (mState == Constants.STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device, secure);
mConnectThread.start();
setState(Constants.STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device, final String socketType) {
Log.d(TAG, "connected, Socket Type:" + socketType);
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(Constants.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(Constants.STATE_CONNECTED);
sConnectionState = true;
}
public synchronized void stop() {
Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
setState(Constants.STATE_NONE);
sConnectionState = false;
}
public void write(byte[] out) {
ConnectedThread r;
synchronized (this) {
if (mState != Constants.STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(out);
}
private void connectionFailed() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(Constants.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
BluetoothService.this.start();
sConnectionState = false;
}
private void connectionLost() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(Constants.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
BluetoothService.this.start();
sConnectionState = false;
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
try {
if (secure) {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(Constants.NAME_SECURE,
Constants.MY_UUID_SECURE);
} else {
tmp = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(
Constants.NAME_INSECURE, Constants.MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
Log.d(TAG, "Socket Type: " + mSocketType +
"BEGIN mAcceptThread" + this);
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
while (mState != Constants.STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
break;
}
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case Constants.STATE_LISTEN:
case Constants.STATE_CONNECTING:
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case Constants.STATE_NONE:
case Constants.STATE_CONNECTED:
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
}
public void cancel() {
Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
Constants.MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
Constants.MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThread" + mSocketType);
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType +
" socket during connection failure", e2);
}
connectionFailed();
return;
}
synchronized (BluetoothService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
public int bytes;
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[Constants.DATA_LENGTH];
StringBuilder readMessage = new StringBuilder();
while (true) {
try {
bytes = mmInStream.read(buffer);
String readed = new String(buffer, 0, bytes);
readMessage.append(readed);
if(readed.contains("\n")){
mHandler.obtainMessage(Constants.MESSAGE_DATA_READ, bytes, -1, readMessage.toString()).sendToTarget();
readMessage.setLength(0);
}
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
BluetoothService.this.start();
break;
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mHandler.obtainMessage(Constants.MESSAGE_DATA_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
Clasa Constants
package com.android.ekg_app;
import java.util.UUID;
public class Constants {
public static final String EXTRA_DEVICE_ADDRESS = "device_address";
public static final String EXTRA_DEVICE_NAME = "device_name";
public static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
public static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
public static final int REQUEST_ENABLE_BT = 3;
public static final int MY_PERMISSIONS_REQUEST_COARSE_LOCATION = 1;
public static final String NAME_SECURE = "HC-05";
public static final String NAME_INSECURE = "HC-05";
public static final UUID MY_UUID_SECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public static final UUID MY_UUID_INSECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_DATA_READ = 2;
public static final int MESSAGE_DATA_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
public static final int DATA_LENGTH = 65535;
public static final int POINTS_TO_SHOW = 400;
}
Clasa DeviceListActivity
package com.android.ekg_app;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Set;
public class DeviceListActivity extends AppCompatActivity {
private ArrayAdapter<String> mNewDevicesArrayAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ListView mPairedListView;
private ListView mNewDevicesListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_list);
setResult(Activity.RESULT_CANCELED);
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mPairedListView = (ListView)findViewById(R.id.paired_devices);
mPairedListView.setAdapter(mPairedDevicesArrayAdapter);
mPairedListView.setOnItemClickListener(mDeviceClickListener);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mNewDevicesListView = (ListView)findViewById(R.id.new_devices);
mNewDevicesListView.setAdapter(mNewDevicesArrayAdapter);
mNewDevicesListView.setOnItemClickListener(mDeviceClickListener);
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mNewDiscoverReceiver, filter);
Set<BluetoothDevice> pairedDevices = MainActivity.sBluetoothAdapter.getBondedDevices();
if(pairedDevices.size() > 0){
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for(BluetoothDevice device : pairedDevices){
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}else{
String noDevices = "No Paired devices found";
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onResume() {
super.onResume();
if(!MainActivity.sBluetoothAdapter.isEnabled()){
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, Constants.REQUEST_ENABLE_BT);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(MainActivity.sBluetoothAdapter != null){
MainActivity.sBluetoothAdapter.cancelDiscovery();
}
unregisterReceiver(mNewDiscoverReceiver);
}
public void onClickScan(View view){
doDiscovery();
view.setVisibility(View.GONE);
}
private void doDiscovery(){
setProgressBarIndeterminateVisibility(true);
setTitle("Scanning for devices…");
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
if(MainActivity.sBluetoothAdapter.isDiscovering()){
MainActivity.sBluetoothAdapter.cancelDiscovery();
}
MainActivity.sBluetoothAdapter.startDiscovery();
}
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MainActivity.sBluetoothAdapter.cancelDiscovery();
String info = ((TextView) view).getText().toString();
String address = info.substring(info.length() – 17);
Intent intent = new Intent(DeviceListActivity.this, MeasureActivity.class);
intent.putExtra(Constants.EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
startActivity(intent);
}
};
private BroadcastReceiver mNewDiscoverReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch(action){
case BluetoothDevice.ACTION_FOUND:
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getBondState() != BluetoothDevice.BOND_BONDED){
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
setProgressBarIndeterminateVisibility(false);
setTitle("Select a device to connect");
mNewDevicesListView.setClickable(true);
if(mNewDevicesArrayAdapter.getCount() == 0){
String noDevices = "No New devices found.";
mNewDevicesArrayAdapter.add(noDevices);
mNewDevicesListView.setClickable(false);
}
break;
}
}
};
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
boolean doubleBackToExitPressedOnce = false;
public static int backPressCount = 0;
@Override
public void onBackPressed() {
if (backPressCount == 0){
Toast.makeText(this, "Please click BACK again to exit.", Toast.LENGTH_SHORT).show();
backPressCount++;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
backPressCount = 0 ; }
}, 1000);
} else {
super.onBackPressed();
setResult(Activity.RESULT_CANCELED);
finishAffinity();
System.exit(0);
return;
}
}
}
Clasa MainActivity
package com.android.ekg_app;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
public static Intent sDeviceListIntent;
public static BluetoothAdapter sBluetoothAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
sBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
sDeviceListIntent = new Intent(this, DeviceListActivity.class);
}
@Override
protected void onResume() {
super.onResume();
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, Constants.MY_PERMISSIONS_REQUEST_COARSE_LOCATION);
}
if(!sBluetoothAdapter.isEnabled()){
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, Constants.REQUEST_ENABLE_BT);
}else{
startActivity(sDeviceListIntent);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode){
case Constants.MY_PERMISSIONS_REQUEST_COARSE_LOCATION:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}else{
Toast.makeText(this, "The app needs 'Location Permission'", Toast.LENGTH_SHORT).show();
finishAffinity();
System.exit(0);
return;
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == Constants.REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finishAffinity();
System.exit(0);
return;
}else if(requestCode == Constants.REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK){
startActivity(sDeviceListIntent);
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
Clasa MeasureActivity
package com.android.ekg_app;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
public class MeasureActivity extends AppCompatActivity {
private String mConnectedDeviceName = null;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothService mBluetoothService;
private TextView mTxtStatus;
private GraphView mGraph;
private LineGraphSeries<DataPoint> mSeries;
private double graphLastXValue = 5d;
private int counter;
private boolean mConnectionState = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_measure);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mTxtStatus = (TextView)findViewById(R.id.txtStatus);
mGraph = (GraphView)findViewById(R.id.graph);
mSeries = new LineGraphSeries<DataPoint>();
mGraph.addSeries(mSeries);
mGraph.getViewport().setXAxisBoundsManual(true);
mGraph.getViewport().setMinX(0);
mGraph.getViewport().setMaxX(Constants.POINTS_TO_SHOW);
}
@Override
protected void onStart() {
super.onStart();
if(mBluetoothService == null){
mBluetoothService = new BluetoothService(MeasureActivity.this, mHandlerMess);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mBluetoothService != null){
mBluetoothService.stop();
}
}
@Override
protected void onResume() {
super.onResume();
if(mBluetoothService != null){
if(mBluetoothService.getState() == Constants.STATE_NONE){
mBluetoothService.start();
}
Intent serverIntentInsecure = getIntent();
connectDevice(serverIntentInsecure, false);
}
}
private final Handler mHandlerMess = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case Constants.MESSAGE_STATE_CHANGE:
switch(msg.arg1){
case Constants.STATE_CONNECTED:
mTxtStatus.setTextColor(Color.argb(0xff, 0x4C, 0xAF, 0x50));
mTxtStatus.setText("Connected to " + mConnectedDeviceName);
mConnectionState = true;
invalidateOptionsMenu();
break;
case Constants.STATE_CONNECTING:
mTxtStatus.setTextColor(Color.BLACK);
mTxtStatus.setText("Connecting…");
break;
case Constants.STATE_LISTEN:
break;
case Constants.STATE_NONE: mTxtStatus.setText("Not connected");
mTxtStatus.setTextColor(Color.RED);
mConnectionState = false;
invalidateOptionsMenu();
break;
}
break;
case Constants.MESSAGE_DATA_WRITE:
break;
case Constants.MESSAGE_DATA_READ:
counter = 0;
final String readMessage = (String)msg.obj;
int[] readBuffer = parseMessage(readMessage);
plotData(readBuffer);
break;
case Constants.MESSAGE_DEVICE_NAME:
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
Toast.makeText(MeasureActivity.this, "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case Constants.MESSAGE_TOAST:
Toast.makeText(MeasureActivity.this, msg.getData().getString(Constants.TOAST),Toast.LENGTH_SHORT).show();
break;
}
}
};
private int[] parseMessage(String message){
int[] readBuffer;
String[] separatedValues = message.split("\r\n");
if(separatedValues.length > 0){
readBuffer = new int[separatedValues.length];
for(int i =0 ; i<separatedValues.length; i++){
try{
int currentValue = Integer.parseInt(separatedValues[i]);
readBuffer[i] = currentValue;
}catch(Exception ex){
ex.printStackTrace();
}
}
}else{
readBuffer = new int[1];
readBuffer[0] = 0;
}
return readBuffer;
}
private void plotData(int[] data){
if(counter < Constants.DATA_LENGTH){
graphLastXValue += 1d;
mSeries.appendData(new DataPoint(graphLastXValue, data[counter]), true, Constants.POINTS_TO_SHOW);
counter++;
}
}
private void connectDevice(Intent connectionIntent, boolean secure){
String address = connectionIntent.getExtras().getString(Constants.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if(mBluetoothService != null){
mBluetoothService.connect(device, secure);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_measure, menu);
if(mConnectionState){
menu.findItem(R.id.menu_disconnect).setVisible(true);
menu.findItem(R.id.menu_insecure_connect).setVisible(false);
menu.findItem(R.id.menu_secure_connect).setVisible(false);
}else{
menu.findItem(R.id.menu_disconnect).setVisible(false); menu.findItem(R.id.menu_insecure_connect).setVisible(true);
menu.findItem(R.id.menu_secure_connect).setVisible(true);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.menu_secure_connect:
Intent serverIntentSecure = getIntent();
connectDevice(serverIntentSecure, true);
return true;
case R.id.menu_insecure_connect:
Intent serverIntentInsecure = getIntent();
connectDevice(serverIntentInsecure, false);
return true;
case R.id.menu_disconnect:
if(mBluetoothService != null){
mBluetoothService.stop();
}
}
return false;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
}
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Sistem de monitorizare a activității cardiace a șoferilor utilizând electrozi capacitivi [305788] (ID: 305788)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
