Implementarea unei aplicații pentru monitorizarea și gestionarea activității unui ciclist [309604]
UNIVERSITATEA “TITU MAIORESCU” DIN BUCUREȘTI FACULTATEA DE INFORMATICĂ
LUCRARE DE LICENȚĂ
COORDONATOR ȘTIINȚIFIC:
Conf.univ.dr. Ana Cristina DĂSCĂLESCU ABSOLVENT: [anonimizat]- Ionuț Handra
SESIUNEA IUNIE 2017
UNIVERSITATEA “TITU MAIORESCU” DIN BUCUREȘTI FACULTATEA DE INFORMATICĂ
LUCRARE DE LICENȚĂ
Implementarea unei aplicații pentru monitorizarea și gestionarea activității unui ciclist
COORDONATOR ȘTIINȚIFIC:
Conf.univ.dr. Ana Cristina DĂSCĂLESCU ABSOLVENT: [anonimizat]- Ionuț Handra
SESIUNEA IUNIE 2017
[anonimizat], a fost tot timpul nevoie de o monitorizare precisă a activității ciclistului. Pentru a atingerea acestui scop s-au creat mai multe dispoztitive care au că scop colectarea și procesarea datelor dintr-o [anonimizat], până la cele mai complexe și costisitoare aparate.
[anonimizat]. Produsul final dorind să demonstreză că platformele Android și Arduino sunt suficient de capabile pentru a [anonimizat], și totul la un preț mult mai redus.
Lucrarea este împărțită în patru capitole:
[anonimizat] o [anonimizat] o parte din cele mai importante calculatoare pentru ciclism implementate în android.
[anonimizat] o descriere a platformelor utilizare pentru implementare aplicației(Android și Arduino).
[anonimizat], și conține detalii despre ansamblarea și programarea părții hardware(Arduino), [anonimizat]: comunicaera cu platforma hardware(Arduino), [anonimizat].
[anonimizat], dar și detalii despre navigarea în aplicația Android.
I Calculatoare si senzori pentru ciclism
I.1 Tipuri de senzori folosiți în ciclism
Pentru ca un biciclist să își poată monitorizea activitea el are nevoie de anumiți senzori pentru a [anonimizat]. Cei mai folosiți senzori pentru ciclism ar fi:
Pentru măsurarea vitezei.
Este de regulă un senozor reed care se atașează de partea fixă a bicicletei, și împreună cu un magnet care se monteză pe roate bicicletei asigura ca în momentul în care magnetul trece prin dreptul senzorului să se genereaze un impuls. [anonimizat] a bicicletei crește.
Computer-ul simplu pentru bicicletă SVADING reprezintă poate cea mai ieftină modalitate de a monitoriza viteză. [anonimizat], legătură dintre aceștia poate fi ori una wireless(fără fir) sau cu fir. Funcțiile acestui computer ar fi: calcularea vitezei pentru diverse dimensiuni ale roți, salvarea distanței călătoriei împreună cu distanță totală, salvarea timului călătoriei, calcularea vitezei medii, salvarea vitezei maxime, iar pentru anumite versiuni chiar indicarea temperaturii.
Senzorul pentru viteză GARMIN este un sensor wireless care se conecteza de regulă la un smartphone prin Bluetooth. Astfel tot ce ține de procesarea datelor se va face pe o aplicație care ruleaza pe un smarthone sau alt dispozitiv care este compatibil cu tehnologia ANT+. Acest senzor se atașează de butucul roții, iar astfel poate determina când s-a efectuat o rotație completă a roții.
Pentru măsurarea cadenței
Acest tip de sensor se aseamănă foarte mult cu senzorul pentru determinarea vitezei, din acest motiv este de regulă vândut împreună cu senzorul pentru viteză. Singură diferența notabilă dintre acești doi senzori este că senzorul pentru cadența se monteză pe pedalierul bicicletei, iar calcularea cadenței se face în RPM(rotații pe minut). Un model cunoscut de sensor pentru cadența, este senzorul GARMIN, care este aproape identic cu senzorul pentru viteză produs de aceeași firma.
Pentru masurarea puterii
Acești senzori sunt destinați măsurării puterii pe care un bicilist o generează în timpul sesiunii. Senzorul este de regulă este încorporat în pedalierul bicicletei și măsoară forță pe care un ciclist o excertita. Din cauza tipurilor de senzori folosiți și constul mai ridicat de producție, acești senzori sunt de regulă foarte scumpti și sunt mai mult destinați sportivilor de performanță.
Powertap reprezintă un sistem care calculează puterea generată bazându-se pe cuplul care este generat de tensiunea în lanț, astfel când există tensiune în lanț această este detectată de către senzorii din butuc și cu ajutorul unor formule, cuplul este convertit în wați. Senzorul se conectează la smartphone prin bluetooth folosing protocolul ANT+. Prețul unui astfel de senzor nu este deloc neglijabil, el fiind de aproximativ 700 de dolari.
Pionner este tot un senzor pentru măsurarea puterii, dar mult mai performant și mai precis. El este încorporat în pedalier și măsoară puterea de 12 pentru o singură rotație. Din cauza volumului mai mare de date aceste senzor nu fololoseste tehnologia ANT+ direct, ci o versiunea bazata pe această, dar puteți oricând să schimbi pe ANT+ pentru a putea conecta senzorul la un smartphone. Prețul acestui senzor este de 1300 de dolari.
Pentru masurarea ritmului cardiac
Acest sensor este poate unul dintre cei mai important pentru cineva care dorește să își monitorizeze efortul depus în timpul unei sesiuni. Efortul pe care un ciclist în depune se împarte în 5-6 zone în funcție de intensitate, iar pentru a află în ce zone se află, ciclist are nevoie de acest senzor care se leagă de regulă în jurul toracelui și folosește tehnologia ANT+ pentru a comunica, asta pentru senzorii care folosesc impulsuri sonice. Mai există și senzori care se pot încorpora într-un ceas și se folosesc de un LED și un sensor pentru calcularea ritmul cardiac, dar de regulă acești senzori nu sunt foarte preciși.
I.2 Computere pentru ciclism implementate în android
Orice smartphone care are un senzor GPS poate cu ajutorul unei aplicații să fie transformat într-un computer pentru ciclism, însă folosind doar senzorul pentr GPS se poate determina doar distanță parcursă și viteză în timp real(care la viteze mici nu este foarte precisă). Pentru cine dorește să obține date mai multe și mai precise despre călătorie poate să folosească o aplicație care suportă conectarea senzorilor pentru fitness care utilizează tehnologia ANT+.
Există foarte multe aplicații destinate ciclismului, unele mai bune altele mai slabe, acum voi prezența trei aplicații pentru ciclism implementate pentru platforma android.
Strava
Strava(„The Social Network for Athletes”) reprezintă cea mai populară aplicație pentru fitness și este bazată pe tehnologia GPS. Strava funcționează asemea unei platforme sociale destinată persoanelor care practică diferite sporturi și vor să-și impartaseaca activitea dintr-o sesiune cu alte persoane care au aceeași pășine. Din păcate aplicația pentru smartphone Strava nu este compatibilă cu tehnologia ANT+, iar singurul mod prin care aceasta colectează date, este prin intermediul senzorului GPS, însă acest lucru nu este în totalitate rău, deoarce face că falsificarea datelor să fie mai dificilă. Deși aplicația poate gestiona activitățiile pentru mai multe sporturi, datele care se pot obține prin GPS nu sunt suficiente pentru a evalua corect o sesiune de ciclism. Strava este o aplicație free însă are și o versiune premium.
IpBike ANT+
IpBike ANT+™ este o aplicație mult mai complexă destinată cicliștilor, însă cu o interfață grafică nu foarte prietenoasă cu utilizatorul. Această aplicație se poate conecta cu aproape orice senzor pentru ciclism care suportă tehnologia ANT, și astfel poate să facă o analiză a datelor și să ofere foarte multe informații utile legate de sesiune de ciclism. IpBike ANT+ este o aplicație free însă are și versiuni premium.
Figura 1.9 Capturi IpBike
Bike Computer
Bike Computer este o aplicație destinată cicliștilor care oferă o interfață grafică foarte atractivă. Aplicația obține informațiile cu ajutorul senzorului GPS, și nu suportă tehnologia ANT+. Câteva din funcțiile importante ale aplicație ar fi: pornirea lanternei smartpohne-ului pe timpul nopți, posibilitatea de a distribui activitatea pe rețelele de socializare, afișarea traseului pe mapă etc.
Figura 1.11 Capturi BikeComputer
I.3 ANT+
ANT+ reprezintă o alianța dintre mai multe companii pentru a standartiza felul în care sunt transmise datele și astfel se asigura o compatibiliate între produse. ANT, ANT+ și ANT+ Alliance sunt toate gestionate de către compania numită ANT Wireless division of Dynastream Innovation, deținută de către Garmin din 2006. În 1998 compania introduce primul accelerometru bazat pe viteză și un monitor pentru distanță, destinat alergătorilor.
Tehnologia ANT este încorporată de regulă în senzori destinați activitatiilor sportive, dar poate fi folosit și în alte scopuri. Senzorul de emisie receptive este încorporate în echipamente cum ar fi monitoarele pentru determinarea pulsului, senzori pentru determinarea puterii generate, senzori distanță/viteză/cadența sau senzori pentru aplicații industriale.
Companiile care folosesc tehnologia ANT sunt:
Adidas
Fitbit
Garmin(compania parinte)
Nike
Suunto
Tacx
Limits
Senzorul ANT poate fi programat să petreacă perioade lungi de timp în modul pentru economisirea energiei. Tehnologia ANT este similară cu Bluetooth low energy, dar nu și compatibilă cu această.
II Tehnologii utilizate
II.1 Android
II.1.1.1 Platforma
Android este un sistem de operare care are la baza nucleul Linux și este dezvoltat de către Google. Sistemul de operare Android este un sistem mulți-utilizator în care fiecare aplicație reprezintă un utilizator. Fiecărei aplicații îi este atribuit un ID unic care este folosit doar de catre sistemul de operare și nu este cunoscut de către aplicație.
Figura 2.1 Principalele componentele ale platformei Android
Permisiunile pentru fișierele dintr-o aplicație sunt stabilite de către sistem, astfel încât să le poate accesa numai numele utilizatorului atribuit aplicației.
Fiecare aplicație rulează într-o instanța a mașinii virtuale, instanța este rulată în procesul propriu al aplicației.
Linux Kernel
Reprezintă baza platformai Android și este responsabil cu funcționalitățile de baza, cum ar fi: management-ul memoriei, controlul suportului hardware etc.
Hardware Abstraction Layer(HAL)
Hardware Abstraction Layer asigura o interfață care oferă acces la partea hardware pentru api-ul de nivel mai înalt(Java API framework). Atunci când API-ul Java face un apel către HAL pentru a accesa partea hardware, sistemul încarcă librăria pentru componentă hardware specificata.
Android Runtime(API 21+)
Înainte de versiunea 5.0(API level 21), Dalvik a reprezentat mașină virtuală în care erau rulate aplicațiile. Dacă o aplicație rulează în ART ar trebui să funcționeze și pe mașină Dalvik, însă nu și invers.
ART a fost conceput să ruleza mai multe mașini virtuale pe device-uri cu memorie limitată, executând fișiere DEX, un format bytecode conceput special pentru Android și optimizat pentru un consum de memorie cât mai mic.
Librariile C/C++
Multe din componentele de baza cum ar fi ART și HAL sunt alcătuite din librării scrise C/C++. Majoritatea functionalitatiile pot fi accesate folosind API-ul Java.
Se pot scrie și aplicații C/C++, dar este nevoie de Android NDK pentru a avea acces direct la librăriile native ale platformei.
Java API Framework
Toate funcționalitățile sistemul sunt disponibile prin API-uri scrise în limbajul Java. API-urile sunt concepute într-o manieră modulară pentru a mari reutilizabilitatea codului și a usora dezvoltatea unei aplicații.
Aceste API-uri s-ar grupa in cateva categorii:
View System, responsabile pentru construirea interfeței grafice.
Resouce Manager, pentru accesul la anumite resurse, cum ar fi: imagini, șiruri de caractere etc.
Notification Manager, responsabil pentru generarea notificărilor și înștiințarea utilizatorului.
Activity Manager, responsabil pentru gestionarea ciclului de viață al aplicațiilor.
Content Provider, responsabil pentru accesul la anumite date.
System Apps
Sunt funcționalități care sunt deja definite și nu trebuie implementate din nou.
II.1.1.2 Componentele aplicației
Componentele aplicației reprezintă blocurile de construcție ale unei aplicație. Principalele componente sunt:
Activities, realizează interacțiunea dintre utilizator și aplicație.
Services, sunt destinate procesării de date în background.
Broadcast receiver, realizează comunicarea dintre componentele aplicației
Content providers, se ocupă de gestionarea datelor.
Mai există componenete adiționale, cum ar fi:
Fragments, reprezintă un modul de interfață grafică dintr-o activitate.
Views, reprezintă elementele de UI.
Layouts, folosite pentru aranjarea elementelor vizuale.
Intents, sunt mesaje care asigura comunicarea dintre componente.
Resources, reprezintă resursele externe aplicației, cum ar fi poze, șiruri de caractere etc.
Manifest, reprezintă fișierul de configurare al aplicației.
Activities
Activitățile reprezintă componentă care asigura legătură dintre aplicație și utilizator. Activitățile sunt responsabile de afișarea componentelor vizuale și asigurarea unei legături intre aplicație și sistem.
Fiecare aplicație are cel puțin a activitate, dar o aplicație poate avea oricâte activități asta pentru a putea oferi o interacțiune cât mai plăcută pentru utilizator. Când o nouă activitate este pornită, vechea activitate este adăugată într-o stivă și va fi oprită până când nouă activitate va termină ce avea de făcut. De exemplu când se apasă butonul back, nouă activitate va fi distrusă, iar vechea activitate care se află în stivă îi va lua locul.
Crearea unei activități se face prin extinderea subclasei cu Activity.
Ciclul de viață al unei activității
Activitățile sunt gestionate de către stivă de activități. Când o nouă activitate este creată, ea este plasată în vârful stivei și astfel devine activitatea care rulează. Activitatea anterioară rămâne sunt activitatea curentă în sitva, și nu va fi apelată în foreground atâta timp cât există cea nouă.
O activitate are in principal patru stări:
Dacă activitatea este în foreground, atunci înseamnă că este activă.
Dacă o activitate nu mai este focusată, dar este încă vizibilă, atunci este în faza de pauză. Dacă o activitate este în pauză este încă „vie”(își menține toate stările și membrii,și va rămâne atașată de window manager), dar poate fi distrusă în situația în care sistemul are foarte puțină memorie.
Dacă o activitate este complet ascunsă de către altă activitate, atunci este oprită. Încă își păstrează toate stările și membrii, dar nu mai este vizibilă și poate să fie distrusă de către sistem dacă este nevoie de resurse suplimentare.
Dacă o activitate este în starea de pauză sau este oprită iar sistemul o distruge, când activitatea va fi chemată din nou, această va fi total recreată.
Definirea unei activitari împreună cu metodele pentru gestionarea ciclului de viață:
public class Activity extends ApplicationContext {
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
Figura 2.2 Reprezentarea grafică a ciclului de viață al unei activități
Descrierea metodelor:
onCreate() – este apelată atunci când activitatea este creată prima dată, aici se adaugă sau se crează view-urile, se atribuie valori aumitor variablile etc..
onRestart() – este apelată atunci când aplicație este oprită, înainte că metodă onStart() să fie apelată.
onStart() – este apelate atunci când activitatea devine vizibilă și este urmată de către metodă onResume() dacă activitatea vine din foreground, sau onStop() dacă activitatea va deveni ascunsă.
onResume() – este apelată atunci când activitatea va începe interacțiunea cu utilizatorul. În acest moment activitatea este în vârful stivei. Această metodă este mereu urmată de către onPause().
onPause() – este apelată în momentul în care sistemul se pregătește că reia o activitate anterioară. Este urmata de onRenume() dacă activitatea se întoarce înapoi în față sau onStop() dacă activitatea devine invizibilă pentru utilizator.
onStop() – este apelată când activitatea nu mai este vizibilă pentru utilizator deoarece a fost reluată o altă activitate. Este urmată de către metodă onRestart dacă activitatea revine în față, sau onDestroy() dacă activitatea va fi distrusă.
onDestroy() – Este apelată înainte că activitatea să fie distrusă.
Services
Un serviciu este o componentă destinată prelucrării datelor în background și nu oferă o interfață cu utilizatorul. Un serviciu poate fi pornit de către alte componente ale aplicației, cum ar fi activitățile, iar avantajul serviciilor ar fi că pot rula în background chiar dacă aplicația este schimbată. Compenetele se pot conecta cu serviciul și chiar să interacționeze cu acesta.
Crearea unui serviciu se face prin extinderea clasei Service sau IntentService. În implementarea serviciului, anumite metode callback trebuie extinse pentru a putea controla anumite aspecte ale ciclului de viață al serviciului și să ofere posibilitatea altor componente să se lege cu serviciul.
Service este clasa se baza pentru toate serviciile și este important că să creăm un nou thread unde va avea loc toată muncă. Acest serviciu folosește implicit thread-ul main al aplicației, și din acest motiv pot apărea probleme de performanță.
IntentService este o subclasa a clasei Service, și serviciul va fi pornit într-un worker thread. Această este cea mai bună opțiune dacă nu este nevoie că serviciul răspundă simultan la cereri multiple.
Cele mai comune metode care trebuie extinse sunt:
onStartCommands() – această metodă este apelată atunci când o altă componentă pornește serviciul apelând metodă startService(). După ce servicul este pornit el va rula independent în background, și se va opri când își va termină treaba, și va apela metodă stopSelf() sau stopService().
onBind() – această metodă este apelată atunci când o altă componeta dorește să se lege cu serviciul. În implementarea acestei metode trebuie să se furnizeze o interfață pe care clientul o va folosi pentru a comunica cu serviciul.
onCreate() – această metodă este apelată pentru a initializa serviciul și este apelată înaintea metodelor onStartCommand() sau onBind().
onDestroy() – acesta metodă este apelată când serviciul nu mai este folosit și urmează să fie distrus
Figura 2.3 Reprezentarea ciclul de viață al unui serviciu care este pornit folosind metodă onCommandStart() și un serviciu care este pornit folosind metodă onBind()
Toate serviciile trebuie declarate în fișierul manifest al aplicației astfel:
<manifest … >
…
<application … >
<service android:name=".ExampleService" />
…
</application>
</manifest>
Broadcast receivers
Un broadcast receiver(consumator de intenții) este o componentă care ascultă dupa evenimentele trimise de către metodă sendBroadcast(Intent). Broadcast reveiver-urile sunt folosite pentru a facilita comunicarea dintre componente, de exemplu comunicarea dintre două sau mai multe servicii, sau comunicarea dintre servicii și activități. Broadcast receiver-urile sunt foarte utile pentru aplicații care sunt asincrone, de exemplu așteptare după evenimentul generat de un serviciu, asta fără a bloca aplicația.
Un broadcast receiver este implementat că subclasa a BroadcastReceiver și fiecare broascast este livrat că un obiect de tip Intent.
Content Provider
Figura 2.4 Relația dintre furnizorul de conținut și alte componente
Furnizorul de conținut coordonează accesul către layer-ul de stocare a datelor dintr-o aplicație, asta pentru diferite API-uri și componente
Pentru a accesa datele dintr-un content provider, trebuie folosit obiectul ContentResolver în contextul aplicație, pentru comunicarea cu furnizorul că și client. Obiectul ContentResolver comunica cu obiectul furnizor, instanța a unei calse care implementeză ContentProvider. Obiectul furnizor obține dată cerută de către client, execută cererile și returnează rezultatul. Obiectul ContentResolver oferă câteva metode de baza pentru a lucra cu datele(create, retrieve, update and delete).
Un mod comun de a accesa un ContentProvider din UI este folosirea unui CursorLoader care execută o interogare asincorn în background fără a bloca interfață grafică, astfel utilizatorul poate încă naviga prin aplicație cât timp interogarea este executată.
Figura 2.5 Interacțiunea dintre un ContentProvider, alte clase și locul în care sunt stocate datele
Folosirea unui furnizor de conținut necesită anumite permisini care trebuie specificare în fișierul manifest al aplicației.
<uses-permission android:name="android.permission.READ_USER_DICTIONARY">
Fragments
Fragmentul este o secțiune modulară dintr-o activitate care are propriul ciclu de viață, primește evenimente și care poate fi adăugat și șters în timp ce activitatea funcționează. Se pot combină fragmente multiple într-o singură activitate pentru a crea o interfață mulți panou și pentru a putea reutiliză un fragment în mai multe activități.
Un fragment trebuie obligatoriu încorporat într-o activitate, iar ciclul de viață al unui fragment este direct afectat de către ciclul de viață al activității gazdă. Când un fragment devine activ, este adăugat într-o stivă care este gestionată de către activitate, astfel un fragment va fi scos când se apasă butonul back al dispozitivului.
Când un fragment este adăugat că parte din layout-ul activității, el rulează într-un ViewGroup din interiorul activității, iar fragmentul își definește propriul view layout. Un fragment poate fi folosit și că un worker invizibil pentru activitate .
Dacă alegeți să folosiți un fragment, atunci acestea va pot oferi:
Modularitate: împărțirea codului in fragmente pentru o mai bună organizare și întreținere.
Reutilizabilitate: înglobarea anumitor comonente vizuale că parte a unui fragment pentru a putea fi folosite și în alte activități.
Adaptabilitate: posibilitatea de a adaugă/scoate fragmente în funcție de poziția și dimensiunea ecranului
Figura 2.6 Ciclul de viață al unui fragmnet
Pentru a crea un fragment trebuie creată o subclasa a clasei Fragment. Fragmentul se aseamănă foarte mult cu o activitate, conține metode similare cu activitatea cum ar fi: onCreate(), onStart(), onPause() și onStop().
Cele mai importate metode care trebui implementate pentru un fragment sunt:
onCreate() – este apelat când fragmentul este creat și este folosită pentru initializare.
onCreateView() – această metodă este apelată când este timpul că fragmetul să afișeze conținut, și returnează un obiect de tip View. Dacă fragmenul nu generează conținut pentru UI, atunci se poate returna null.
onPause() – este apelată în momentul în care user-ul părăsește fragmentul, însă asta nu înseamnă neapărat că fragmentul va fi distrus.
AndroidManifest.xml
Fiecare aplicație trebuie să aibă fișierul AndroidManifest.xml, care oferă informații sistemului Android despre aplicație.
În fișierul manifest se definește nivelul minim de API care este necesar pentru rularea aplicației, permisiuni necesare, definirea componentelor aplicației(activități, servicii etc.), lista de librării necesare aplicației și multe altele.
Radacine fișierului manifest este marcate de către eticheta <manifest> .
Câteva din ethictele prezența în fișierul manifest ar fi:
<permision> -aici se declara permisiunile de securitate.
<application> – acest element conține subelemente în care se descriu componentele aplicației, acest element mai conține și atribute care pot afecta toate componentele.
<activity> – toate activitățile din aplicație trebuie declarate folosind această eticheta în fișierul manifest.
<services> – eticheta folosita pentru declararea servicilor .
<user-library> eticheta folosită pentru specificare librăriilor care vor fi utilizate de către aplicație.
<user-sdk> – aici se specifică compatibilitate aplicației cu alte versiuni de android
<user-permission> stabilește penrmisiunile care sunt necesare pentru că aplicația să funcționeze corect.
<intent-filter> – reprezintă tipurile de intenții la care activitatea, serviciul sau consumatorul de intenții poate să răspundă.
<action> – adaugă o acțiune unui filtru pentru intenții
Exemplu de fișier manifest:
II.2 Arduino
II.2.1 Introducere
Arduino reprezintă o platforma open-source atât din punct de vedere software cât și hardware, și este folosită pentru implementarea diferitor proiecte. Proiectul arduino a început în anul 2005 având Italia că țară de origine. Ideea care a stat la baza a fost construirea unei alternative mai ieftine a plăcii BASIC Stamp. Platforma de dezvoltarea Wiring creată de către Hernando Barragan stă la baza platformei Arduino.
În anul 2011 au fost produse peste 300.00 de plăci oficiale, iar în anul 2013 au fost produse 700.00 de plăci. Deoarece toate schemele sunt publice, orice poată să confecționeze plăci atâta timp cât respectă termenii licenței GNU.
II.2.2 Software
Pentru programarea unei plăci Arduino se pot folosi programe scrise în orice limbaj de programare atâta timp cât compilatorul este capabil să producă cod mașină binar. Arduino oferă un mediu de dezvoltare integrat care este o aplicație cross-platform scrisă în limbajul Java.
Dacă alegi să folosești mediul de dezovoltare ofert de Arduino, trebui să cunoști limbajele C sau C++ și să folosești librăriile puse la dispoziție pentru a efectua diferite operații.
Structura program:
II.2.3 Hardware
Placă de dezvoltare Arduino este alcătuită dintr-un microcontroller AVR(8, 16 sau 32 de biți). O placă arduino are conectori standard ceea face posibilă conectarea acesteai cu diferite module interschimbabile numite shield-uri.
Până în anul 2015 plăcile oficiale arduino foloseacu cipurile produse de către Atmel, și anume: megaAVR, în special ATmega8, ATmega168, ATmega328, ATmega1280 și ATmega2560. O placă arduino oferă mai mulți pini de intrare/ieșire care sunt controlați de către microcontroler.
Arduino Uno
„Uno” provine din italiană și înseamnă „unu”, numele a fost ales pentru a marca lansarea primei versiuni de arduino(Arduino 1.0).
Placă de dezovoltare Arduino Uno are la baza cipul Atmega328 și conține tot ce este nevoie pentru a suportă microcontroller-ul.
II.2.4 ISR(Interrupt Service Routines)
ISR(Întreruperea Rutinei Serviciului) reprezintă un semnal care întrerupe activitatea curentă și este foarte util pentru a ne asigura că nici un puls care este generat de un anumit senzor nu este pierdut. O funcție ISR foate fi declanșate de către un eveniment hardware sau de un eveniment sofware. Când funcția este apelată, codul care rula la mometul respectiv este oprint iar execuția acestuia va fi reluată după ce codul din interior funcție ISR este executat.
Deoarece cipurile arduino nu pot să ruleze secvențe de cod în paralel, singură modalitate de a optine o funcționalitate asemănătoare este prin folosirea funcțiilor ISR în mod asincron. Un al avantaj pe care Întreruperea Rutinei Serviciul o oferă, este măsurarea foarte precisă a timpului.
Tipuri de întreruperi:
Întreruperea de tip hardware, este declanșată de către un eveniment extern. De exemplu evenimentul generat de către un senzor care este conectat la unul din pinii plăcii.
Întreruperea de tip sofware, repezintă evenimente care sunt generate din cod, deorece procesoarele AVR pe 8 biți nu suportă întreruperile te tip software, acestea trebuie simulate prin schimbarea din cod a stării unui pin.
Un procesor AVR are definită o lista cu întreruperi care repezintă tipul de eveniment care poate declanșa întreruperea respectivă.
Întreruperile pot fi pornite sau oprite folosind funcțiile interrupts() sau noInterrupts(), iar pentru întreruperile pinilor externi se pot folosi functille attachInterrupt() și detachInterrupt().
II.2.5 Timer
Cronometrul unui microcontroller reprezintă un declanșator care va porni o alertă la un anumit timp în viitor. Alertă întrerupe microprocesorul, amintindu-i că trebuie să execute o anumită secvență de cod sau alte operații. Un timer la fel că și întreruperile externe funcționează independent de programul principal. În locul unei bucle infinite care apelează în mod repetat funcția millis() se poate seta un timer.
Cronometrul funcționează prin incrementarea unei variablile numită „counter register”, de obicei dimensiunea acesteia este de 8 sau 16 biți. Cronometrul incrementează această valoare până când atinge valoare maximă, valorea din registru este resetată. Pentru a ști când să se oprească cronometrul se setează un bit pentru semnalare. Acest bit poate fi verificat manual sau se poate seta un declanșator care să facă acest lucru automat.
Pentru a incrementă registrul de numărare, cronometrul trebuie să aibă un ceas care să furnizeze semnale la intervale regulate.
Tipuri de cronometre:
Timer0 este un cronometru pe 8 biți și este folosit de către funcțiile native ale arduino, cum ar fi delay() și millis().
Timer1 este un cronometru pe 16 biți și este folosit de către librăria arduino pentru controlarea motoarelor servo.
Timer2 este un cronometru pe 8 biți similar cu Timer1 și este folosit de către funcția tone()
Timer3, Timer4, Timer5 sunt tot niște cronometre pe 16 biți care sunt similare cu Timer1
III Proiectarea și implementarea aplicației
III.1 Obiective
Principalul obiectiv al acestei aplicații a fost să ofere o a două șansă dispozitivelor smartphone care au fost depășite de tehnologiile actuale, dar ar putea fi folosite că și computer pentru monitorizarea și gestionarea activitaii unui biciclist. De asemenea suportul hardware(Arduino) folosit pentru realizarea acestei aplicații ar putea fi folosit că o alternativă la senzori folosiți pentru monitorizarea vitezei și a cadenței care se găsesc deja în comerț, totul la un preț mult mai redus..
Pentru a facilita bună dezvoltate a aplicație și permiterea adăugări unor funcționalități noi cu mai mult ușurință, aplicația trebuie realizată într-un mod cât mai modular. De asemenea am considerat că monitorizarea vitezei și a cadenței reprezintă un minim necesar pentru un computer de bicicletă care dorește să ofere o analiză corecta pentru o sesiune de ciclism.
III.2 Partea hardware
III.2.1 Introducere
Pentru a putea determina viteză și cadența trebuie să știm intervalul de timp în care roată, respectiv pedalierul au efectuat o rotație completă. Pentru obținerea impulsurilor vom folosi senzori reed, care se declasează în momentul în care detectează un câmp magnetic.
Senzorii vor fi fixați pe cadrul bicicletei, un magnet va fi fixat pe una din spițele roții, iar celălalt magnet va fi fixat pe pedalier, trebuie să ne asigurăm că distanță dintre magneți și senzori este de aproximativ 3mm(magnetul nu trebuie să atingă senzorul, dar nici să fie foarte depărtat de acesta, deoarece la turații mai mari s-ar putea că senzorul să nu detecteze câmpul magnetic și astfel să se piardă date).
Când un impuls este detectat, se face o scădere dintre timpul curent al plăcii și timpul la care s-a detectat impulsul anterior. Pentru putea măsură timpul pentru mai mulți senzori simultan, va trebui să folosim două variabile care să rețină timpul la care s-a întregistrat ultimul impuls pentru senzorul respectiv. De asemenea pentru a mari precizia ceasului intern al plăcii vor trebui făcute niște setări din cod.
Deoarece dorim o fiabilitate cât mai bună a codului sursă și să nu fie nevoie să se facă update-uri constante, vom efectua toate calculele pe dispozitivul smartphone. Singură atribuție a părții hardware(arduino) este să trimită timpul dintre impulsuri pentru cadența și viteză prin bluetooth către smartphone.
III.2.2 Descrierea componentelor si modulelor hardware utilizate
Pentru realizarea părții hardware necesare acestui proiect am folosit:
placa de dezvoltare compatibila arduino(clona) .
Figura 3.1 Placa compatibila Arduino
doua module care au integrate cate un întrerupător reed
Figura 3.2 modul senzor reed
un modul bluetooh(HC-05) pentru comunicarea cu smartphone-ul
Figura 3.3 modulul bluetooth HC-05
mai mulți conectori pentru conectarea modulelor între ele.
baterie portabilă de 2000mAh, output: DC 5V/1A.
Placa are o memorie internă de 32KB dintre care 0.5KB sunt ocupați de către bootloader, microcontroler-ul este ATmega328 având o viteză de 16MHz, iar consumul este în jur de 30mA, dar acesta poate varia. Principala sarcina a plăcii în acest proiect este de a colecta datele de la cei doi senzori, să proceseze datele și apoi o să trimită informația procesată către modulul bluetooth care la rândul lui va trimite informația către smartphone.
Senzorul reed este un comutator care se închide atunci când este în prezența unui câmp magnetic. Senzorul se putea folosi și separat, dar era mai greu de integrat cu placă și nu ar fi oferit precizia și simplitatea pe care o oferă că și modul. Consumul modului este ~15mAh.
HC-05 este un modul Bluetooth SPP (Serial Port Protocol), care se ocupă de comunicarea fără fir de tip serial. Modulul poate fi folosit atât pentru transmiterea datelor cât și pentru receptarea acestora. Un avantaj al modului HC-05 este că poate să fie folosit atât că MASTER cât și că SLAVE, spre deosebire de modulul HC-06 care poate fi folosit doar că SLAVE.
III.2.4 Ansamblarea hardware-ului
Figura 3.4 Schemă pentru conectarea modulelor
Conectarea modului HC-05
Conectați pinul VCC al modulului la sursă plăcii(cea de 3.3V). În diagramă legătură este repezentata de către firul roșu.
Conectați pinul de împământare al modului la unul din pinii de împământare al palcii. În diagramă legătură este repezentata de către firul negru.
Conectați pinul de input al modului(RXD) la pînul de output pentru comunicarea serial al plăcii(TX). În diagramă legătură este repezentata de către firul galben.
Conectați pinul de output al modului(TXD) la pînul de input pentru comunicarea serial al plăcii(RX). În diagramă legătură este repezentata de către firul verde.
Conectarea senzorilor reed
Conectați pinii VCC ai senzorilor reed la sursă plăcii(cea de 3.3V). În diagramă legătură este repezentata de către firul roșu.
Conectați pinii de împământare ai senzorilor la unul din pinii de împământare al palcii. În diagramă legătură este repezentata de către firul negru.
Pentru senzorul reed care va înregistra viteză, conectați pinul de output al senzorului la pinul digital cu numărul 5 al plăcii. În diagramă legătură este repezentata de către firul mov.
Pentru senzorul reed care va înregistra cadența, conectați pinul de output al senzorului la pinul digital cu numărul 4 al plăcii. În diagramă legătură este repezentata de către firul maro.
Alimentarea placii
Pentru alimentare se poate folosi portul usb de tip B al plăcii conectat la o sursă de 5V, cum ar fi o baterie portabilă pentru încărcarea telefonului.
III.2.5 Codul sursa pentru arduino
Un program scris pentru arduino trebuie să conțină obligatoriu două metode, metoda setup() și metoda loop(). Metoda setup() este folosită pentru initializare, și este apelată o singură dată înaintea metodei loop().
Pentru acest proiect in metoda setup() vom initializa:
modul pinilor pe modul la care sunt conectati senzori pe modul INPUT
pinMode(speedReed, INPUT);// speedReed=5 pinul digital nr. 5 pentru senzorul de viteza
pinMode(cadenceReed, INPUT); //speedReed=4 pinul digital nr. 4 pentru senzorul de cadenta
setarea timer-ului(TIMER1) si setarea intreruperilor(interrupts)
cli(); //oprirea intreruperilor la nivel global
// initializare TIMER1
TCCR1A = 0; // setarea registrului TCCR1A cu 0
TCCR1B = 0; // setarea registrului TCCR1B cu 0
TCNT1 = 0; //setarea registrului TCNT1 (TimerCounter)
++
/*Configurand ultimi biti ai registrului TCCR1B, putem seta viteza timer-ului */
// setam numaratoarea timer-ului pentru 1khz de incrementari
OCR1A = 1999; // = (1/1000) / ((1/(16*10^6))*8) – 1
// pornim modul CTC(Clear Timer on Compare)
TCCR1B |= (1 << WGM12);
// setam bitul CS11 pentru TCCR1B
TCCR1B |= (1 << CS11);
// activarea intreruperii compararii timer-ului
TIMSK1 |= (1 << OCIE1A);
sei(); //permite intreruperi
setarea ratei de transmitere in serial la 9600 de biti pe secunda
Serial.begin(9600);
Codul pentru calcularea timpului dintre pulsuri va fi rulat in ISR (Interrupt Service Routine)
Calcularea intervalului dintre impulsurie pentru viteză și cadența sunt destul de asemănătoare că și cod, așa că voi descrie secvență de cod doar pentru unu dintre senzori.
Cod:
speedReedVal = digitalRead(speedReed); //citim valoarea pinului, poate fi LOW sau HIGH
// daca exista un impuls(valoarea variabilei speedReedVal este HIGH), atunci calculam intervalul dintre inpulsuri
if (!speedReedVal){
/*urmatorul if este un mecanism de siguranta in cazul in care semnaul este tot timpul HIGH si nu vrem sa se transmita valori false. Acest lucru se poate intampla in momentul in care magnetul se opreste chiar in dreptul senzorului*/
if ((prev_state_speed==true)){
prev_state_speed=false;
buff_1="";
buff_1=buff_1+"@"+speedTimer+"@";
Serial.print(buff_1); //trimitem timpul dintre impulsuri, pentru viteza formatul este @+interval+@
speedTimer = 0;//resetam timpul dintre impulsuri pentru viteza
moving_speed = true; //daca se inregistreaza un impuls pentru viteza inseamana ca bicicleta se afla in miscare, si marcam acest lucru.
}
}else{
prev_state_speed=true;
}
/*Daca au trecut mai mult de 2 secunde(2000 de incrementari) de la ultimul inpuls si bicicleta se afla in miscare, inseamna ca bicicleta sa oprit sau merge la o viteza foarte mica(~2-3km/h). Daca bicicleta s-a oprit trebuie sa comunicam acest lucru, trasmitand 0 ca interval dintre impulsuri, alfel incrementam intervalul curent*/
if ((speedTimer > 2000)&&(moving_speed==true)){
Serial.print("@0@");
// the bike is not moving
moving_speed = false;
}else{
speedTimer += 1; // incrementeaza interval;
}
*Deoarece tot codul necesar va fi rulart in ISR, metoda loop() nu va conține cod.
III.3 Aplicația android
III.3.1 Introducere
Aplicația android va fi responsabilă de procesarea datelor, salvarea datelor și comunicarea cu modulul bluetooh al plăci arduino care va trimite infromatii despre viteză și cadența. Aplicația oferă posibilitate de a fi folosită de mai mulți bicicliști împreună cu mai multe biciclete, asta fără că datele să fi amestecate.
Aplicația colectează datele chiar dacă ecranul smartphone-ului este închis sau utilizatorul folosește altă aplicație, acest lucru duce la o economisire a bateriei smartphone-ului.
III.3.2 Structura aplicației
III.3.2.1 Stocarea datelor
Pentru salvare datelor am creat o subclasa a clasei SQLiteOpenHelper. Pentru fiecare operație care implică salvarea, ștergerea, actualizarea sau obținerea de date trebuie instantiat un obiect al clasei DB_Management(subclasa a clasei SQLiteOpenHelper) și accesate metodele de care este nevoie.
Pentru a putea instantia un obiect de tip DB_Management, trebuie să specificăm contextul aplicației ca parametru pentru constructor.
Exemplu: DB_Management db_mgmt = new DB_Management(getApplicationContext());
Baza de date este alcatuita din patru tabele:
cyclists – în această tabela sunt salvate datele despre fiecare ciclist în parte, date cum ar fi: nume, greutate, înălțime, vârstă etc.
bicycles – în această tabela sunt salvate informațiile despre biciclete, date cum ar fi: tipul bicicletei, greutatea bicicletei, dimensiune roții etc.
trips – în această tabela sunt salvate datele despre toate călătoriile care au fost efectuate folosind aplicația, în această tabela trip_bicycle_id și trip_cyclist_id sunt chei străine pentru bicyle_id respectiv cyclist_id, acest lucru este necesar pentru a putea face posibilă utilizarea aplicației de către mai mulți utilizatori(aplicația fiind instalată doar pe un singur dispozitiv).
variables – în această tabela este folosită în principal pentru a salva anumite stări ale aplicației sau anumite preferințe ale utilizatorului. De exemplu în această tabela este salvat biciclistul și ciclistul curent, lucru foarte uptil pentru a ști ce călătorie trebuie returnată. De asemenea mai este salvată și dată la care a fost actualizată ultima dată valoarea.
Figura 3.5 Diagrama bazei de date
Pentru a putea întoarce toate datele pentru o singură înregistrare am definit o structura de dată pentru fiecare tabela.
Un exemplu este metoda get_data_about_current_cyclist() care intoarce informatiile despre ciclistul curent, metoda intoarce un obiect de tip Cyclist_record_struct.
public Cyclist_record_struct get_data_about_current_cyclist() {
Cyclist_record_struct record=new Cyclist_record_struct();
Cursor cursor=(db).rawQuery("SELECT "
+"cyclist_id"+","
+"cyclist_name"+","
+"cyclist_height"+","
+"cyclist_weight"+","
+"cyclist_birthday"
+" FROM "+TABLE_CYCLISTS_NAME+" WHERE cyclist_id=?",
new String[] {variables_struct.current_cyclist_id}
);
if (cursor != null && cursor.moveToFirst()) {
record.cyclist_id = cursor.getInt(cursor.getColumnIndex("cyclist_id"));
record.cyclist_name = cursor.getString(cursor.getColumnIndex("cyclist_name"));
record.cyclist_height = cursor.getInt(cursor.getColumnIndex("cyclist_height"));
record.cyclist_weight = cursor.getInt(cursor.getColumnIndex("cyclist_weight"));
record.cyclist_birthday = cursor.getInt(cursor.getColumnIndex("cyclist_birthday"));
}
cursor.close();
return record;
}
Metoda face o interogare in baza de date pentru a cere ciclistul al carui id coincide cu id-ul ciclistului curent. Ciclistul curent cât si bicicleta curenta pot fi setați doar in activitatea care se ocupa de initializarea si setarea datelor.
Alte metode implementate in clasa ar fi:
public void add_new_trip(Trip_record_struct record)- Adauga o cursa noua pentru utilizatorul current
public void update_current_trip(Trip_record_struct record) -Actualizeaza datele despre calatoriei curente
public Trip_record_struct get_data_about_current_trip() -Intoarce informatiile despre calatoria curenta
public ArrayList<Cyclist_record_struct> getAllCyclists() -Intoarce toti ciclisti din baza de date
public ArrayList<Bicycle_record_struct> getAllBicycles()- Intoarce toate bicicletele inregistrare in baza de bate
public String get_variable_value(String variable_name) – Intoarce valoarea stocata in tabela variables pentru o variabila, cautare se face dupa nume
public void update_variable_value(String variable_name, String variable_new_value)- Actualizeaza valoarea salvata pentru o variabila
Deoarece în structura bazei de date SQLite nu extista tipul de dată array, va trebui ca array-ul pe care trebuie să-l salvăm în baza de date să-l serializăm și să-l salvăm că tip de dată BLOB, iar atunci când dorim să obținem iar valorile salvate în BOLD, va trebuie să deserializam obiectul.
Metodele folosite pentru serializarea și deserializarea obiectelor sunt:
private static byte[] serialize(Object obj) throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();}
private static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
return is.readObject();
} catch(Exception e){
return null;}}
III.3.2.2 Definirea serviciilor
Procesarea datelor și comunicarea cu arduino se va face din interiorul serviciilor. Comunicarea dintre servicii și comunicarea dintre servicii și interfață grafică se fă realiza cu ajutorul evenimentelor de tip intent și a consumatoarelor de intent.
Pentru a transmite intenții și pentru a intregistra consumatori am ales să folosesc clasa LocalBroadcastManager deoarece este mai sigură, asta pentru că toate evenimentele generate folosind LocalBroadcastManager sunt locale aplicație adică nu pot fi recepționate de o altă aplicație, iar acest lucru face că aplicația să fie mai eficientă.
Aplicația are implementate trei servicii:
BluetoothGetDataService – extinde clasa IntentService și are ca scop preluarea datelor de la Arduino si transmiterea acestora mai departe sub forma de intent-uri.
BicycleComputerService – extinde clasa IntentService și are ca scop prelucarea datelor care sunt primate de la serviciul BluetoothGetDataService, salvarea datelor și crearea de evinimente care vor fi folosite pentru a actualize interfata grafica
PowerCalculatorService – și acest serviciu extinde clasa IntentService și are ca scop calcularea în timp real a energiei folosite de către ciclist.
Toate serviciile trebuie declarate in fișierul AndroidManifest.xml al aplicației
<manifest>
. . .
<application>
. . .
<service android:name=".services.BluetoothGetDataService" />
<service android:name=".services.BicycleComputerService" />
<service android:name=".services.PowerCalculatorService" />
</application>
</manifest>
De asemenea toate numele intent-urilor sunt salvate sub formă de resursă string într-un fișier xml numit LocalBroadcastManagerIntents.xml.
Serviciul BluetoothGetDataService
Acest serviciu crează o conexiune wireless între android și arduino folosit socket-uri, procesează datele și le trimite mai departe că și intenturi.
Pentru a ne putea conecta la arduino trebuie să avem permisiunea de a avea acces la bluetooh, acest lucru se face prin adăugarea permisiunii în fișierul AndroidManifest.xml al aplicației.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
După ce dispozitul arduino este cuplat cu smartphone-ul va trebuie să creăm o conexiune cu dispozitivul.
BluetoothSocket tmp = device.createRfcommSocketToServiceRecord(myUUID);
tmp.connect();
* Pentru a putea identifica dispozitivul trebuie să cunoaștem mac-ul acestuia(este trimis ca intent la pornirea serviciului).
După ce dispozitivul dispozitiul este conectat trebuie se initializam un obiect de tip InputStream pentru a putea colecta datele trimise de arduino.
mmInStream = tmp.getInputStream()
Așteptarea de date de la arduino se face într-un thread separat care o să fie distrus după ce serviciul este distrus. În momentul când sunt primite date, acestea sunt procesate iar în funcție de format se identifica dacă este vorba despre viteză sau cadența(dacă numărul de milisecunde este cuprins între caracterele „@” atunci este vorba de viteză bicicletei, iar dacă milisecundele sunt cuprinse între caracterele „#” atunci este vorba de cadența). După ce se identifica de la ce senzor sunt datele, se va trimite un intent în funcție de acest lucru.
Exemplu de intent pentru viteză:
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(speed_intent_sender.putExtra(getResources().getString(R.string.BluetoothGetDataService_intent_speed_ms_int), Integer.parseInt(str)));
Unde speed_indet_sender este un obiect de tip intent definit anterior.
speed_intent_sender = new Intent(getResources().getString(R.string.BluetoothGetDataService_intent_speed_ms_int);
Serviciul BicycleComputerService
Serviciul BicycleComputerService procesează toate datele primite de către serviciul BluetoothGetDataService și transmite mai departe viteză calculate în km/h, cadența calculate în rotații pe minut, detalii despre călătoria curentă(care sunt actualizate și trimise de către un thread odată pe secundă).
Pentru a primi evenimentele generate de către serviciul BluetoothGetDataService trebuie să înregistrăm un BroadcastReceiver care în momentul în care se trimite un intent care corespunde etichetei, va procesa datele.
Următoare secvență de cod reprezintă instantierea uni obiect de tip BroadcastReceiver și înregistrarea acestuia.
BroadcastReceiver Speed_ms_Receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
/*Procesarea datelor si trimiterea lor ca intenturi*/
}
}};
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(Speed_ms_Receiver, new IntentFilter(BluetoothGetDataService_speed_ms_int_TAG));
De asemenea cand serviciul va fi distrus trebui sa stergem si inregistrarile pentru BroadcastReceiver.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(Speed_ms_Receiver);
Când este primit un intent care reprezintă intervalul de timp în milisecunde în care roate bicicletei a efectuat o rotație completă atunci trebuie să se:
calculeze vitezei in km/h dupa urmatoare formula si trimiterea acesteia sub forma de intent.
pornirea cronometrului in caz ca viteza este mai mare de 0, sau oprirea acestuia in caz ca viteza este egala cu 0
actualizare distantei totala in caz ca viteza este mai mare de 0
calcularea vitezei medii care este raportul dintre distanta totala a calatoriei si timp total de deplasare al bicicletei
Procedeul pentru cadența este asemanatoar doar că există un intent separat, iar formulă de calcul a cadenței în RPM este:
În acest serviciu rulează două fire de execuție unul pentru actualizează în baza de date odată la cinci secunde a informațiilor despre călătoria curentă, iar alt fir de execuție pentru a actualiza odată la o secundă datele despre călătoria curentă pentru interfața grafică
Serviciul BicycleComputerService
Serviciul PowerCalculatorService este folosit pentru calcularea în timp real a energiei necesare pentru a pune bicicleta în mișcare.
Energia pe care o generează un biciclist pentru a pune în mișcare bicicleta este influențată de mai mulți factori cum ar fi: viteză vântului, înclinația drumului, greutatea bicicletei, greutatea biciclistului, tipul și mărimea cauciucurilor, rezistență mecanică etc.
Figura 3.6 Reprezentarea grafică a forțelor care acționează asupra ciclistului și a bicicletei
Puterea necesară(P), fără a pune la socoteală accelerarea și decelerarea este egală cu suma energiilor necesare pentru a compensa cele patru rezistențe: rezistență de rulare(Pr), rezistență aerului(Pa), rezistență la urcare(Pc) și rezistență mecanică(Pm).
Formule pentru calcularea puterii in W(watts) sunt:
Pentru rezistența la rulare:
Unde: reprezinta facorul de rezistenta, reprezinta masa totala(masa bicicletei plus masa biciclistului), reprezinsta atractia gravitationala(9.81m/s^2), iar reprezsinta viteza de deplasare.
Pentru rezistența aerului:
Unde: reprezinta densitatea aerului, repezinta coeficientul de rezistenta, reprezinta aria, reprezinta viteza de deplasare a bicicletei, iar reprezinta viteza vantului.
Pentru rezistența la urcare:
Unde: reprezinta inclinatia drumului in procente, reprezinta masa totala(masa bicicletei plus masa biciclistului), reprezinsta atractia gravitationala(9.81m/s^2), iar reprezsinta viteza de deplasare.
Pentru rezistența mecanica este necesare energia totala si eficienta bicicletei care este de regula 97.5%, iar formula este:
Unde reprezinta suma dintre ,si .
Acest servicu are inregistrat un BroadcastReceiver pentru primirea evenimentelor legate de viteza de la serviciul BicycleComputerService. Cand serviciul BicycleComputerService genereaza un eveniment legat de viteza, servicul PowerCalculatorService calculeaza puterea in functie de viteza, luand in considerare ca viteza vantului si inclinatia drumului sunt 0.
Pentru a masura cu exactitate energia generate trebuie sa stim inclinatia pantei, care s-ar putea obtine de la senzorul giroscopic al smarphone-ului(daca are), si de asemean trebuie sa stim si accelerarea si decelerarea, cea din urma ar putea fi folosita pentru a estima mai bine anumite forte, de exemplu daca bicicleta decelereaza mai rapid decat ar fi asteptat, inseama ca anumite forte sunt mai proeminente.
III.3.2.2 Interfața grafică
Interfață grafică este poate cel mai important aspect al unei aplicații, deoarce prin intermediul acestei se realizează toată interacțiune cu utilizatorul. În acest scop android ne pune la dispoziție o gama largă de componete și metode pentru a implementa o interfață grafică cât mai ușor.
Interfața grafică este alcătuită din trei activităi și mai multe fragmente care au ca scop să ofere o experiență cât mai plăcută și în același timp fiabilitatetea codudui să fie cât mai mare.
Cele trei activitati ale aplicatiei sunt:
FirstActivity
Aceasta activitate contine momentan doar un singur buton care duce catre alta activitate, dar in viitor aceasta activitate va avea ca scop informarea utilizatorului despre versiunea curenta si alte informatii care ar putea fi utile.
InitActivity
In aceasta aceasta clasa sunt initializate si introduse datele despre ciclist, bicicleta, si placa arduino. Meniul si toate elementele grafice sunt definite in interiorul fragmentului InitMenuFragment_v1 care este o sublasa a clasei fragment. In interiurul acesti activitati mai esti instantiat un obiect de tip DB_Management() pentru a seta si obtine date, acest este descris mai pe larg in subcapitolul III.3.2.1 Stocarea Datelor.
Fragmentul InitMenuFragment_v1 este incarcat intr-un FrameLayout care este generat dinamic.
Pentru a ne asigura ca senzorul bluetooth al telefonului este pornit trebuie sa instantiem un obiect al clasei BluetoothAdapter si sa verificam daca bluetooh-ul este pornit, daca nu este pornit trimitem utilizatorului o cerere prin care ii solicitam pornirea acestuia.
Dupa ce este incarcat, fargmentul InitMenuFragment_v1 foloseste un GridLayout pentru a imparti ecranul in 3 zone egale in care se vor incarca FrameLayout-uri care vor avea inaltimea si latimea calculate in functie de dimensiunea ecranului.
Fragmentele care vor fi incarcate in cele trei zone ale framentului InitMenuFragment_v1 sunt: Bicycle_Menu_Fragment, Cyclist_Menu_Fragment si Start_Button_Fragment
Bicycle_Menu_Fragment este folosit pentru adugarea si setarea bicicletei curente, si este incarcat in FrameLayout-ul din dreapta. Pentru a putea incarca bicicletele sub forma de lista am implementat un adaptor care extinde clasa ArrayAdapter.
Pentru a obtine o lista cu toate bicicletele se apeleaza o metoda pe care am implementat-o in activitate InitActivity, si care comunica cu baza de date.
Pentru a afisa continutul am folosit mai multe ferestre instantieri ale clasei PopupWindow in care incarc diverse componenete.
Figura 3.7 Capturi ale meniului pentru adaugarea/selectarea bicicletei
Cyclist_Menu_Fragment este un fragment similar cu Bicycle_Menu_Fragment, singura diferenta este la afisarea datelor si la salvarea acestora.
Figura 3.8 Capturi ale meniului pentru adaugarea/selectarea ciclistului
Start_Button_Fragment reprezinta fragmentul din mijloc si ofera doua butoane, unu care ne permite sa selectam placa arduino si un buton care va porni urmatoare activitate si anume ComputerActivity.
ComputerActivity
Este este ultima activitate, iar in aceasta sunt pornite si oprite serviciile si practic va reprezenta computer-ul in sine.
Cand activitatea este creata, aceasta va incarca ComputerDashboard_Fragment_v1 care este un fragment si va reprezenta interfata grafica, iar pe langa acesta va porni cele trei servicii pentru procesarea datelor si comunicarea cu placa arduino,
Pentru a preveni stingerea ecranului putem specifica acest lucru in fisierul manifest al aplicatiei sau putem scrie urmatoare linie de cod in interiorul activitatii:
Un lucru foarte important atunci cand activitatea este distrusa este sa nu uitam sa spunem sistemului sa distruga serviciile.
Fragmentele utilizate in aceasta activitate:
ComputerDashboard_Fragment_v1 este un fragment care va imparti ecranul in patru zone si in fiecare zona va introduce cate o componenta. Acest fragment are definite mai multe metode pentru a adauga cu usurinta fragmente, iar pentru componenta din mijloc mai are implementat in plus o metoda pentru a adauga un FragmentPageAdapter, care ne permite sa schimbam fragmentele doar prin glisarea view-ului din centru.
Acum voi descrie fragmentele care vor fi adaugate in cele 4 zone ale fragmentului ComputerDashboard_Fragment_v1.
Figura 3.9 Impartine pe zone facuta de fragmentul ComputerDashboard_Fragment_v1
In prima zona va fi introdus Fragmentul GaugeSpeedViewFragment care afiseaza viteza sub forma unui vitezometru de masina cu ac. Pentru a nu consuma CPU cand view-ul trebuie actualizat, am implemendat clasa vitezeometrului din mai multe view-uri suprapuse care se pot actualiza individual, acelasi lucru si pentru turometrul cadentei
In a doua zona este implementat un pageAdaper care contine doua fragmente care pot fi aduse in prin plan prin glisare. Un fragment arata datele despre calatoria curenta(BasicRideDataFragment), iar celalalt indica puterea consumata in timp real(SimplePowerViewFragment)
In a trei zona este un fragment pentru cadenta similar cu fragmentul pentru viteza din prima zona
In a patra zona este un fragment care va fi folosit pentru a implementa diferitelor actiuni, momentan singura actiune care este implementata este cea de resetare a calatorie curente.
Toate fragmentele comunica folosing Intent-uri, si se folosesc de LocalBroadcastManager pentru a inregistra broadcast receiver-uri si pentru a trimite intent-uri
Daca dorim sa tratam din cod evenimentul care este generat de rotirea ecranului pentru o activitate, putem sa specificam acest lucru in fisierul manifest al aplicatiei.
IV Ghid de utilizare
IV.1 Programarea plăcii și instalarea senzorilor
Pentru a putea instala propriile programe pe o placă arduino aveți nevoie de Arduino IDE ( https://www.arduino.cc/en/Main/Software ). Trebuie să descărcați cea mai recentă versiune în funcție de sistemul dumneavoastră de operare și să o instalați.
Pașii pentru a programa o placă arduino:
După ce instalați Arduino IDE puteți să alegeți un exemplu de cod din File->Examples, cel mai simplu exemplu pentru a verifică că placa funcționează cum trebuie, este Blink (File->Examples->01.Basics->Blink), care va face că led-ul aflat pe placă să „clipească”, asta în funcție de cât de mare este setat delay-ul.
Conectați placa la calculator.
Selectați modelul palacii din Tools->Board, in cazul nostru este „Arduino/Genuino Uno”
Selectați codul dorit, in acest caz vom folosi un exemple de cod care a venit cu software-ul (Blink)
Apasati butonul Verify, care o sa verifice daca sunt greseli de sintaxa in cod.
Selectați portul. Tools->Port
Apăsați butonul Upload.
Dacă ați ales programul Blink(fără să îl modificați) ar trebuie să observați că LED-ul care este încorporat pe placă(LED-ul notat L) „clipește” odată la o secundă.
După ce ați verificat că placa funcționează cum trebuie, încărcați codul computer-ului, și nu uitați că placă nu trebuie să aibă nici un senzor conectat când încercați să încărcați programul
* Dacă folosiți o placă compatibilă arduino va trebuie să descărcați și instalați driverul-ul pentru USB; http://www.wch.cn/download/CH341SER_EXE.html
După ce ați încărcat programul, legați senzori cum este descris în subcapitolul III.2.4 Ansamblarea Hardware-ului.
După ce placa este configurată corespunzător, începeți montarea senzorilor.
Senzorul de viteză se montează fie pe furcă din spate a bicicletei, fie pe cea din față, iar un magnet trebuie atașat de una dintre spițele roții și trebuie să va asigurați că distanță dintre magnet și senzor este de aproximativ 2-3mm.
Senzorul de cadența se poate atașa ori de furcă din spate ori de cadru, atâta timp cât este securizat,iar distanță dintre acesta și magnetul care va fi atașat de pedalier să fie de 2-3mm. De asemenea să aveți grijă la firele care leagă senzorii de placa arduino.
Pentru alimentarea plăcii se poate folosii o baterie portabilă.
Înainte de a folosi aplicația trebuie să ne „legăm” de modulul HC-05 folosind parolă 1234.
Figura 4.1 Crearea unei legaturi cu modulul HC-05
IV.2 Navigarea în aplicația android
Descriere interfață:
După ce setați toate datele puteți porni computer-ul.
Figura 4.2 Interfața grafică a computer-ului
În această captura este adus în prin plan fragmenul care afișează puterea, acest lucru se poate face prin glisarea view-ului din mijloc.
Figura 4.3 Evidențierea fragmentului pentru afișarea puterii
Dacă dorim să resetăm călătoria curentă trebuie să apăsăm butonul ACTIONS, după care va apărea un meniu care conține un buton care trebuie ținut apăsat până dispare.
Figura 4.4 Fereastra cu acțiuni
Concluzii
Dezvoltarea Aplicației pentru monitorizarea și gestionarea activități unui ciclist a necesitat utilizarea a două platforme diferite(Android și Arduino), dar și folosirea unor elemente practice pentru a reuși a duce la bun sfârșit aplicația. Implementarea aplicației nu a fost lipsită de incidente, dar rezolvarea problemele pe care le-am întâmpinat m-au făcut să înțeleg mai bine anumite noțiuni tehnice, dar și să-mi gestionez timpul cât mai bine pentru a reuși să termin tot ce mi-am propus.
Aplicația prezentată în această lucrare oferă o baza pentru crearea unui computer mult mai complex și capabil decât multe computere pentru ciclism, și acest lucru se datorează flexibilității platfomei android, dar și al capabilități platfomei arduino.
Pentru a îmbunătății această aplicație am să va prezint câteva din ideile care ar trebui implementate:
creare de programe pentru antrenament, bazate pe perfomatele obținute de către ciclist în sesiunile anterioare.
îmbunătățirea sistemului pentru calcularea puterii consumate, astfel încât să poată fi folosit că o alternativă pentru senzorul care calculează puterea.
implementarea unei API pentru a permite unui ciclist să urmărească datele despre un alt ciclist care are aceasta aplicație instalată.
suport pentru senzorii care folosesc tehnologia ANT+ și conectarea cu aceștia.
implementarea unui asistent care să ofere sfaturi în timpul sesiunii.
Bibliografie
[1] Documentație android:
https://developer.android.com/guide/platform/index.html#system-apps
[2]Pagina oficiala arduino:
https://www.arduino.cc/
[3] Componentele aplicației android:
https://www.tutorialspoint.com/android/android_application_components.htm
[4] Implementarea unui computer de bicicletă folosind arduino:
http://www.instructables.com/id/Arduino-Bike-Speedometer/
[5]Timer and interrupts:
[6]Tutorial interrupts:
http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/
[7]Rotirea acului vitezometrului:
http://development-in-android.blogspot.ro/2012/08/draw-and-move-watch-needle-on-android.html
https://stackoverflow.com/questions/35102161/edited-android-draw-needle-image-to-this-circle-similar-to-meter-guage
[8] The Secret of Cycling:
https://books.google.ro/books?id=iUdoDgAAQBAJ&printsec=frontcover&dq=cycling+power&hl=ro&sa=X&ved=0ahUKEwi9-bjAh-_TAhUCtxQKHYxYDZYQ6AEIPDAE#v=onepage&q=cycling%20power&f=false
[9]ANT +:
https://books.google.ro/books?id=oYmwCwAAQBAJ&pg=PA496&dq=ant%2B&hl=en&sa=X&redir_esc=y#v=onepage&q=ant%2B&f=false
https://www.thisisant.com/developer/ant-plus/ant-plus-basics
[10] Senzorii pentru măsurarea puterii:
http://www.bicycling.com/bikes-and-gear-features/guides/which-power-meter-should-i-buy/slide/7
[11]Strava:
https://play.google.com/store/apps/details?id=com.strava
[12]Bike computer:
https://play.google.com/store/apps/details?id=tinysoftwarefactory.bikecomputer
[13]Ip Bike:
https://play.google.com/store/apps/details?id=com.iforpowell.android.ipbike
[14] Descriere plăcii Arduino și istoria acesteia:
https://en.wikipedia.org/wiki/Arduino
http://digital.csic.es/bitstream/10261/127788/7/D-c-%20Arduino%20uno.pdf
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: Implementarea unei aplicații pentru monitorizarea și gestionarea activității unui ciclist [309604] (ID: 309604)
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.
