Controlarea Unor Jaluzele Verticale Si a Unei Usi Glisante Prin Leap Motiondocx

=== Controlarea unor jaluzele verticale si a unei usi glisante prin Leap Motion ===

Facultatea de Automatică și Calculatoare

Programul de Licență: Informatică

Controlarea Unor Jaluzele Verticale și a Unei Uși Glisante prin Leap Motion

Lucrare de licență

Maher AL ABBASI

Conducător științific:

Prof. dr. ing. Lăcrămioara STOICU-TIVADAR

Timișoara,

2015

Introducere

„Calculatoarele sunt incredibil de rapide, precise și proaste. Ființele umane sunt incredibil de lente, inexacte și geniale. Împreună, puterea lor depășește orice imaginabilă limită.” (Albert Einstein).

Prefață

Privind în urmă, pe vremea când un calculator necesita ocuparea spațiului unei întregi încăperi, până în zilele noastre, unde depozitarea acestora nu mai constituie o problema, având în vedere faptul că majoritatea dintre noi deținem un astfel de dispozitiv chiar și în buzunarele noastre, putem observa cu ușurință evoluția continuă a acestora, atât din punct de vedere al dimensiunii, dar și mai importat, al vitezei.

Trăim într-o perioadă în care viteza de transmitere a informației reprezintă un aspect foarte important al vieții cotidiene, iar întrebuințările unui calculator în diferite domenii nu mai par să ne uimească.

În foarte multe domenii, nu mai este suficientă doar utilizarea unui sistem de calcul independent. Noile tehnologii oferă oportunități de dezvoltare, iar acest aspect necesită capacitatea unui calculator de a se interconecta și comunica cu alte componente precum cele mecanice, electronice etc.

Astfel de exemple ni le pot oferi companiile din industria automotive, prin dorința de realiza autovehicule care oferă posibilitatea de activare a unui pilot automat inteligent, sau diferite firme care produc aparate medicale de îngrijire a pacienților fără a necesită utilizarea acestora de către un cadru medical specializat, și de ce nu, roboți inteligenți care oferă o modalitate rapidă de aspirare a unei încăperi, prin intermediul unei aplicații mobile

Așadar, putem observa cum utilitatea acestora începe să se ramifice treptat, iar rezultatul dezvoltării diferitelor tehnologii, poate oferi un viitor promițător pentru a ne oferi un stil de viață cât mai sigur și ușor.

Pornind de la această premisă a luat naștere un concept care probabil că, va duce în timp la schimbarea modului de a privi activitățile ce țin de mentenanța și confortul propriului cămin mai exact, conceptul de casă inteligentă.

Conceptul de casă inteligentă reprezintă o serie de soluții pentru automatizarea totală sau parțială a activităților unui cămin cu scopul de a ridica nivelul confortului, securității și eficienței.[WIK15]

Primele concepte de automatizare al caselor, au apărut odată cu nașterea literaturii științifico-fantastice, în special în momentul adaptării acesteia pe marile ecrane. Până în anul 1966, dezvoltarea unui sistem funcțional reprezenta doar o idee greu de atins.

Între anii 1966-1967 i-au naștere proiectele „ECHO IV and the Kitchen Computer”. Cu toate că nu s-a ajuns la comercializarea sa, „ECHO IV” a fost primul dispozitiv inteligent din acest domeniu, care avea ca scop alcătuirea unei liste de cumpărături, capacitatea de a porni și opri alte aparate electrocasnice, cât și controlul temperaturii. Cel de-al doilea proiect, oferea utilizatorului posibilitatea de a stoca rețete culinare în memoria dispozitivului.[IOT15]

Până în anii 2000, soluțiile oferite necesitau costuri ridicate, aspect care a împiedicat implementarea pe scară largă a acestora. Odată cu apariția dispozitivelor și al microcontrolerelor la un preț accesibil, a avut loc o ascensiune rapidă a dezvoltării de noi funcționalități în ceea ce privește automatizarea anumitor sarcini de rutină.

Figura 1 – Model casă inteligentă

În prezent se pune foarte mult accent pe soluționarea problemelor legate de securitatea caselor inteligente cât și de consumul de energie. Un astfel de sistem ar nu trebui să necesite costuri suplimentare față de un cămin obișnuit, sau cel puțin să evite consumul inutil de energie.

Noile tendințe din acest domeniu, sunt reprezentate de utilizarea dispozitivelor mobile pentru diferite acțiuni de la distanță, astfel existând un nivel de control mai ridicat asupra propriei case.

sisteme automate de iluminare

ajustarea automată a termostatului

notificări prin intermediul mesajelor text și email

supraveghere video de la distanță

programarea unor acțiuni asupra dispozitivelor electrice și electronice

În viitor ideea de casă inteligentă probabil că va introduce noi concepte care vor revoluționa acest domeniu precum controlul dispozitivelor prin intermediul undelor cerebrale, sau al unor gesturi ale mâinii, holograme 3D, etc.

Un alt pas important în evoluția acestui concept este reprezentat de încercarea de a asigura soluții pentru crearea de legături sociale. Există posibilitatea ca în viitorul apropiat astfel de concepte să fie implementate treptat de către marile companii din domeniul automatizărilor cât și cel al telecomunicațiilor.[GSM11]

Domeniul temei

Lucrarea de față își propune să abordeze o tematică mai puțin cunoscută de către publicul larg, având ca scop utilizarea de noi tehnologii privind automatizarea anumitor obiecte uzuale aflate în orice casă.

Procesul de automatizare constă în tehnica prin care un dispozitiv, proces sau un sistem poate opera în mod automat. Un astfel de proces se poate realiza utilizând sisteme embedded.

Un sistem embedded reprezintă un computer care este construit pentru a rezolva probleme specifice. Asemenea unui sistem de calcul, sistemele embedded au un procesor, memorie și porturi de intrare / ieșire.

De asemenea o mare parte a sistemelor integrate se prezintă cu un sistem de operare cu scopul de a rula diferite servicii specializate. Astfel de servicii au ca scop asigurarea funcționării întregului sistem. Spre exemplu, în cazul în care o anumită funcționalitate își schimbă comportamentul, provocând erori, se poate executa un serviciu (daemon) prin care sistemul va încerca o revenire din eroare.[WIK15]

În cadrul acestor tipuri de sisteme, o interfață grafică nu este obligatorie, însă unele sisteme pot prezenta interfețe complexe. În general este suficientă utilizarea câtorva butoane și led-uri.

De obicei pentru rezolvarea unei probleme specifice, este necesară construcția unui astfel de sistem, însă există și soluții ce oferă un „kit” general prin care se pot realiza aplicații în diferite domenii.

Sistemele embedded sunt tot mai des întâlnite datorită practicității pe care o oferă prin caracteristicile lor:

Eficiență – optimizate pentru un consum redus de energie, timp de execuție, greutate, dimensiune și cost

Acțiune în timp real – un aspect important de menționat este faptul că se pot crea sisteme în timp real, ce pot fi controlate prin transmiterea anumitor semnale și stări.

Interacțiune – sistemele embedded deseori pot interacționa cu mediul înconjurător prin senzori, propulsori, etc. Astfel se pot dezvolta sisteme reactive care execută un anumit eveniment în funcție de mediul în care acesta se află.

Tema proiectului

Tema proiectului presupune automatizarea modului de închidere / deschidere al unei uși glisante cât și al unor jaluzele verticale. În cadrul jaluzelelor verticale se va automatiza și rotirea acestora. Controlul acestora se va realiza prin utilizarea controlerului „Leap Motion”, iar automatizarea se realizează prin intermediul unei plăcuțe „Arduino Uno”.

În momentul interacțiunii cu dispozitivul, acesta recunoaște anumite gesturi implementate în prealabil, moment în care se preia informația, după care se transmite plăcuței „Arduino”.

Odată ce informația este transmisă plăcuței, aceasta va fi interpretată și în funcție de tipul gestului utilizat, se va efectua o acțiune specifică gestului.

Comanda obiectelor automatizate se va realiza atât în mod manual cât și în mod automat. În modul manual i se permite utilizatorului controlul continuu asupra funcționalității alese în timp real, iar modul automat se realizează printr-o singură comandă dată controlerului „Leap Motion”. În acest moment oprirea se va efectua în mod automat la efectuarea unui ciclu întreg de cursă, cu condiția ca utilizatorul să nu interacționeze cu dispozitivul. Utilizatorul are control permanent asupra modului de comanda, având posibilitatea de a trece dintr-un mod în altul după bunul plac.

Figura 2 – Arhitectura generală și principalele entități

Partea de noutate a aplicație constă în controlul obiectelor prin gesturi ale mâinii, cu ajutorul controlerului „Leap Motion”. Acest tip de control nu mai permite controlul fizic cu acestea. Astfel se reduce numărul de componente necesare controlului manual.

Descrierea temei

Tema de licență în sine presupune o aplicație realizată în limbajul Java utilizând metodele oferite de către interfața dispozitivului „Leap Motion”.

Aplicația presupune implementarea unor gesturi ce vor fi interpretate de către dispozitivul „Leap Motion”. Fiecare gest interpretat va fi procesat de către codul realizat, și va trimite o valoare specifică, către modulul Bluetooth al plăcuței Arduino.

Studiu Bibliografic

Pentru documentarea temei am studiat diferite proiecte care utilizează tehnologiile prezentate în cadrul acestui proiect, precum și diverse cărți de specialitate și pagini de internet.

În următoarele subcapitole vor fi prezentate proiectele pe care le-am studiat.

Leap Lamp

Acest proiect își propune controlul unei lămpi de birou prin utilizarea gesturilor mâinii, mai exact controlul direcției și a înălțimii acesteia.

Pe partea de configurare a conexiunii între „Leap Motion” și „Arduino UNO” este realizată prin intermediul unei websocket pre configurat de către aplicația software a controlerului prezentat mai sus. În momentul activării, aplicația software transmite date prin intermediul adresei serverului de websocket (ws://127.0.0.1:6437).

Pentru a putea fi posibilă conexiunea între aplicație și server se folosește biblioteca Node.js. Această bibliotecă analizează datele primite și le trimite mai departe plăcuței „Arduino”, iar prin intermediul bibliotecii „jhonny-five” se interpretează datele primite.[VIM15]

Figura 3 – Leap Lamp

Arduino controlled automated blinds with Web UI

Proiectul prezentat în acest subcapitol își propune controlul unor jaluzele orizontale prin intermediul plăcuței „Arduino UNO”.

Funcționalitățile oferite utilizatorului sunt controlul deschiderii și închiderii programate a jaluzelelor, pe baza temperaturii camerei și luminozității externe.

Parametrii de intrare pot fi setați prin intermediul unei aplicații web, care îi va permite utilizatorului atât controlul manual al jaluzelelor, cât și programarea automata a acestora.

Conexiunea dintre cele doua aplicații oferite se realizează prin intermediul unui shield ethernet, iar controlul jaluzelelor se realizează cu ajutorul unui motor pas cu pas. Acționarea jaluzelelor în funcție de temperatura camerei sau luminii exterioare se realizează printr-un senzor de temperatură, respectiv print-o fotocelulă.[INS15]

Figura 4 – Jaluzele orizontale automate

Controlling Arduino car via Leap Motion

Următorul proiect prezintă o modalitate de a controla o machetă a unei mașini cu ajutorul plăcuței „Arduino” și al controlerului „Leap Motion”, cu o conexiune realizată prin intermediul unui Web Socket. Pentru funcționarea conexiunii dintre cele două elemente se folosește biblioteca „Node.js”.

Precizia machetei se bazează pe distanța dintre controler și poziția mâinii. Din motive de siguranță, „mașinuța” este programată să se oprească în momentul în care dispozitivul „Leap Motion” nu găsește nici o mână sau atunci când primește o dată eronată.[INS15]

Direcția în care se va deplasa macheta este determinată de poziționarea mâinii, prin sistemul de coordonate 3D oferit de către controler.

Dacă valoarea axei X este mai mică decât 10 cm, iar valoarea axei Z este mai mică decât 5 cm, „mașinuța” se va opri.

Se impune o verificare pe cele două axe pentru a se determina valoarea cea mai mare obținută pe acestea. Aceasta va determina direcția în care se va deplasa macheta.

Dacă pe axa Z se află o valoare negativă, atunci „mașinuța” se va deplasa înapoi, iar în caz contrar aceasta se va deplasa înainte.

Pentru valorile pozitive sau negative ale axei X, macheta va efectua o rotație la stânga, respectiv la dreapta.

Valoarea axei Y determină puterea motorului. Cu cât valoarea este mai mare, cu atât motorul se va roti mai repede.

Figura 5 – Mașină Arduino controlată prin Leap Motion

Robotic Hand with Arduino and Leap Motion

Acest proiect își propune controlul unei mâini robotice folosind o placă „Arduino” și un controler „Leap Motion”. Mișcarea este realizată cu ajutorul unor servo-motoare, iar conexiunea este realizată tot prin intermediul unui Web socket cu ajutorul bibliotecii „Node.js” și al bibliotecii „Johnny Five”.

Prototipul permite controlul de la distanță, permițând recunoașterea separată a fiecărui deget cu precizie și sensibilitate foarte bună.

Pentru permiterea controlului mâinii robotice, a fost necesară legarea servo-motoarelor cu fire de nailon, pentru simularea ligamentelor.

Aplicația software funcționează în felul următor: se preiau informații de la controlerul „Leap Motion”. Dacă se detectează o singură mână de către controler, atunci se preiau și interpretează informații legate de numărul de degete „active”. În funcție de unghiul și poziția acestora pe sistemul de coordonate, se transmit informațiile obținute către plăcuța „Arduino”, care în funcție de id-ul obținut de la controler va acționa unul dintre servo-motoarele atașate pe brațul robotic.[INS15]

Figura 6 – Robotic Hand with Arduino and Leap Motion

Automated blinds via „Arduino”

Proiectul prezentat în acest subcapitol își propune rotirea unor jaluzele verticale prin intermediul plăcuței „Arduino UNO”.

Proiectul este realizat în modul următor: se utilizează un motor de curent continuu la care se atașează un scripete proiectat astfel încât permită acționarea sforii pentru rotirea jaluzelelor.

Prin utilizarea unei punți H, permite mișcarea bidirecțională a motorului, astfel încât sa se poată efectua atât deschiderea cât și închiderea acestora.

Proiectul conține o fotodiodă care preia date despre lumina din încăperea în care se află și trimite aceste date plăcuței „Arduino”, pentru a putea permite acționarea jaluzelelor.[INS15]

Figura 7 – Automated Blinds via Arduino

Concluzii

În urma studierii proiectelor prezentate anterior, am observat diversitatea aplicabilității a unei plăcuțe „Arduino” a unui controller „Leap Motion” și a utilizării acestora împreună.

Aceste tehnologii, pot duce la dezvoltarea unor proiecte complexe, atât pentru a ușura stilul de viață al utilizatorului (sisteme automate), cât și pentru efectuarea unor acțiuni ce necesită controlul de la distanță, sau de divertisment (jocuri video, „jucării”).

În continuare voi prezenta un tabel în care voi compara principalele caracteristici ale fiecărui proiect studiat.

Din tabelul de mai sus, am dorit să aduc la cunoștință faptul că toate proiectele prezentate în acest capitol, au la bază „Arduino” și / sau „Leap Motion”, iar cele care le folosesc pe amândouă, realizează o conexiune printr-un WebSocket.

Proiectul nostru diferă de cele prezentate prin faptul că folosește o conexiune prin Bluetooth și prin faptul că este realizată și deplasarea jaluzelelor cât și controlul acestora prin gesturi.

Fundamentare teoretică

Pentru a realiza acest proiect am făcut următoarele cercetări de fundamentare teoretică.

Leap Motion

Controlerul Leap Motion se prezintă ca fiind un mic dispozitiv periferic conectat prin USB cu un design adaptat astfel încât să poată fi plasat în fața unui calculator. Parametrii de intrare preluați de către controller, se realizează prin partea superioară a acesteia. În funcție de modul în care se dorește a fi utilizat dispozitivul, acest produs se poate achiziționa fie separat, astfel încât acesta sa poată fi folosit de către utilizator după bunul plac, fie ca o parte a unui ansamblu mai complex (industria auto sau medicală, modelare 3d).

Hardware

În compoziție dispozitivul utilizează două camere IR monocromatice și trei LED-uri infraroșii. Dispozitivul acționează pe o rază emisferică, până la o distanță de aproximativ un metru.

Cele două camere generează pană la 300 de cadre pe secundă, cu informații ce mai apoi se transmit prin cablul USB către calculator, unde datele obținute sunt analizate de către partea software a controlerului folosind metode de calcul avansate, astfel încât să se poată „sintetiza” o copie tridimensională cu privire la poziția și unghiul în care se află mâna, comparând cadrele obținute de la cele două camere 2D.[SPA15]

Arhitectura Software

Partea software necesară utilizării controlerului rulează ca un serviciu (Windows) sau daemon (Mac și Linux). Toate aplicațiile realizate pe baza controlerului „Leap Motion” necesită accesul la acest serviciu pentru a putea prelua informațiile necesare cu privire la poziționarea mâinii.

Kitul de dezvoltare software oferă două modalități de a prelua informațiile necesare pentru aplicațiile create de către dezvoltatori: o interfață nativă și o interfață de tip WebSocket.

Cele două modalități permit realizarea de aplicații în diferite limbaje de programare, oferind chiar și posibilitatea de a realiza aplicații de tip Web.

Interfața nativă este oferită prin intermediul unei biblioteci dll.

Aceasta se conectează la serviciul „Leap Motion” și oferă informațiile necesare aplicației dezvoltate. Aceste biblioteci sunt oferite în cazul limbajelor C++, C#, Objective C, Java și Python.

Figura 8 – Interfața nativă

Procesul se desfășoară în felul următor:

Serviciul „Leap Motion” interceptează datele oferite de către controler prin cablul USB. Procesează informația și o trimite aplicațiilor realizate. În final serviciul trimite doar informații legate de coordonatele mâinii.

Aplicațiile realizate cu ajutorul dispozitivului „Leap Motion” rulează separat de serviciu și permit utilizatorului să configureze dispozitivul în momentul instalării. Aplicația „Leap Motion” oferă un panou de control pentru astfel de setări.

Aplicațiile lansate în rulare primesc informații legate de mișcare de la serviciu. O aplicație ce permite utilizarea dispozitivului se poate conecta la serviciul „Leap Motion” utilizând biblioteca nativa a acestuia. Aplicațiile pot face o legătură fie în mod direct (C++ și Objective-C) sau printr-o bibliotecă de tip wrapper (Java, C# și Python).

Când o aplicație pierde legătura sau este deconectat, serviciul va înceta să mai trimită date. Aplicațiile care rulează pe fundal pot cere permisiunea de a primi date chiar dacă nu sunt direct în contact cu utilizatorul. Când acestea rulează pe fundal, setările de configurare sunt stabilite de către aplicația în rulare.

Interfața de tip WebSocket

În acest caz serviciul „Leap Motion” rulează un server WebSocket pe domeniul localhost la portul 6437. Interfața oferă informațiile „capturate” sub formă de mesaje de tip JSON. O bibliotecă client realizată în JavaScript este pregătită să „consume” mesajele JSON și transformă informațiile interceptate sub forma unor obiecte de tip JavaScript.

Figura 9 – Interfața WebSocket

Serviciul „Leap Motion” oferă un server de tip WebSocket care așteaptă mesaje la adresa http://127.0.0.1:6437.

Panoul de control oferit de către aplicația dispozitivului permite activarea sau dezactivarea serverului.

Serverul trimite date sub formă de mesaje JSON. O aplicație poate trimite mesaje de configurare înapoi către server.

Clientul oferit („leap.js”) trebuie folosit pentru toate aplicațiile web. Biblioteca stabilește o conexiune cu serverul și consumă mesajele de tip JSON. API-ul oferit de către bibliotecă este asemenea celui prezentat anterior din punct de vedere al structurii și al modului de funcționare.

Interfața prezentată este concepută în principal pentru aplicațiile de tip web, însă orice aplicație care poate stabili o conexiune de tip WebSocket poate accesa această interfață. Serverul se conformă protocolului RFC6455 (protocolul pentru WebSocket).[LEA15]

Introducere în modul de urmărire a modelului scheletic al mâinii

Versiunea actuală de API al dispozitivului „Leap Motion” (versiunea 2.0) introduce noi tehnici de urmărire a mâinii, tehnică prin care se pot obține noi informații despre mână cât și degete, încercând să ofere o acuratețe în privința datelor transmise.

Prin încercarea modelării unei mâini, aplicația software a dispozitivului, poate prezice poziția degetelor și a mâinii chiar și în cazul în care acestea nu sunt în poziția ideală de prelucrare a datelor, cu condiția ca mâna să se afle în raza de detectare a dispozitivului. Gesturile subtile sau complexe pot duce uneori la erori de interpretare datorită faptului că anumite suprapuneri ale degetelor nu pot fi preluate corespunzător în cazul în care acestea nu sunt extinse.

Această versiune oferă o fereastră de vizualizarea a mâinii pentru a oferi dezvoltatorului o viziune cât mai clară a gesturilor preluate de către dispozitiv.

Figura 10 – Aplicația Vizualizer

Printre funcționalitățile oferite de această tehnică de interpretare a datelor se prezintă:

Raportarea nivelului de încredere al mâinii bazat pe corelația dintre modelul intern și datelor prelucrate de către aplicație

Identificarea tipului mâinii (stânga sau dreapta)

Raportarea poziției cât și a orientării fiecărui os al degetelor

Raportarea puterii de strângere bazată pe o comparație a gesturilor implementate de tip strângere sau prindere

Raportarea celor cinci degete pentru fiecare mână

Raportarea existenței unui deget

Limbajul de programare Java

Java este un limbaj de programare orientat pe obiecte (POO), realizat în așa fel încât să aibă cât mai puține dependințe posibile din punct de vedere al implementării. Acest limbaj a fost realizat cu scopul de a îi permite programatorului să își scrie codul sursă o singură dată („Write once, run anywhere”) pentru toate platformele care suportă acest limbaj fără a fi necesară recompilarea codului sursă. Java este un limbaj robust și de nivel înalt.

Fiecare mediu hardware și software în care un program rulează, este cunoscut ca o platformă. Având în vedere faptul că Java are propriul mediu în care rulează „Java Runtime Environment ” (JRE) și propria interfață programabilă (API), Java este și o platforma.

Conform companiei „Sun”, 3 miliarde de dispozitive utilizează limbajul Java. În momentul de față există un număr ridicat de dispozitive care suportă acest limbaj.

Aplicații desktop

Aplicații web

Aplicații destinate sistemelor bancare

Dispozitive mobile

Sisteme incorporate

Carduri inteligente

Robotică

Jocuri etc.

Scurt istoric

Acest proiect a fost inițiat în anul 1991 de către James Gosling, Mike Sheridan și Patrick Naughton. Inițial limbajul a fost realizat cu scopul utilizării acestuia pentru a crea o interactivitate în televiziune, însă în acel moment era mult prea avansat pentru această industrie. Limbajul Java preia o mare parte a sintaxei limbajelor C și C++ cu scopul de a le oferi programatorilor care au cunoștințe în acestea o ușurință în a înțelege acest limbaj.

În anul 1995 Sun Microsystems a lansat prima implementare a limbajului (versiunea 1.0). Ideea cu care au început a fost cea de a scrie cod o singură data și de a oferi posibilitatea de a fi rulat de pe majoritatea platformelor cunoscute, fără a implica nici un fel de costuri. Fiind suficient de securizat și oferind modalități de configurare a securității, a permis utilizarea acestuia în cadrul navigatoarelor de internet prin intermediul rulării unor applet-uri.

În anul 1997, deținătorii limbajului au abordat mai multe standarde pentru a formaliza limbajul, însă aceste standarde nu au intrat în practică. Astfel limbajul Java ajunge să fie standardizat prin acceptarea unor standarde decise de către comunitatea acestuia.

În 2006, Sun Microsystems a oferit majoritatea limbajului publicului larg, sub termenii li condițiile licenței GNU (General Public License).[JAV15]

Principiile limbajului

În timpul creări acestui limbaj s-au respectat cinci principii:

Trebuie să fie simplu, orientat pe obiecte și familiar

Trebuie să fie robust și sigur

Trebuie să fie independent de arhitectură și portabil

Trebuie să fie executat astfel încât să ofere o performanță înaltă

Trebuie să fie interpretabil, dinamic și concurent

Simplitatea programului se prezintă prin faptul că față de limbajul C++, s-au înlăturat un număr mare de funcționalități care au fost considerate nesigure, sau care produceau confuzie în utilizare (pointeri expliciți, supraîncărcarea operatorilor, etc). O astfel de simplitate prin modul de implementare, este reprezentat de capacitatea limbajului de a înlătura obiectele utilizate în mod automat (Garbage Collector). Față de alte limbaje de programare, acest limbaj este pur orientat pe obiecte, încercând să ușureze modul de dezvoltare al aplicațiilor software.

Prin cel de-al doilea principiu se impune ca limbajul să fie puternic. Java folosește tehnici complexe de administrare a memoriei, iar prin lipsa pointerilor se evită probleme de securitate. Alte funcționalități care transformă limbajul întru unul puternic, sunt tratarea excepțiilor și mecanismul de verificare a tipurilor. Toate acestea fac limbajul să fie robust.

Prin independența față de o anumită arhitectură se respectă cel de-al treilea principiu. Acest lucru este posibil prin implementarea unor funcționalități independente. Un astfel de exemplu sunt tipurile de date primitive.

Al patrulea principiu se realizează prin viteza de interpretare a codului bit, fiind pe cât posibil similar codului mașină, însă nu la fel de rapid precum cel al limbajelor compilate (C++). Cu toate acestea diferența este aproape insesizabilă.

Un alt aspect important oferit de către cel de-al cincilea principiu este prezentat de capacitatea limbajului de a permite programarea concurenta. Astfel se pot crea programe ce pot rezolva mai multe probleme la un moment dat, utilizând mai multe fire de execuție. Cel mai important avantaj al firelor de execuție, este faptul că împart aceeași memorie. Firele de execuție sunt utile în cazul aplicațiilor web, multimedia, etc.

Introducere în programare Java

Pentru realizarea celui mai simplu program în acest limbaj, este necesară instalarea unui „kit„ de dezvoltare (Java Development Kit), cât și un mediu de dezvoltare, spre exemplu Eclipse.

Următorul program va afișa un mesaj cu textul „Hello World”:

class Simple

{

public static void main(String args[])

{

System.out.println("Hello Java");

}

}

Pentru o bună înțelegere a modului în care limbajul oferă posibilitatea de a programa, este necesară înțelegerea elementelor de bază. Pentru acest aspect voi prezenta pe scurt elementele utilizate în programul anterior.

class – este cuvântul cheie utilizat în a declara o clasa în limbajul java

public – reprezintă un modificator de acces utilizat pentru a reprezenta vizibilitatea, mai exact vizibil pentru toată lumea

void – este tipul pe care îl returnează metoda în cauză, ceea ce înseamnă ca nu va returna nimic

main – reprezintă începutul programului realizat

String[]args – este utilizat pentru a oferi argumente din linia de comandă.

System.out.println() – utilizat pentru a afișa un mesaj.

Pentru a se afișa mesajul „Hello World”, este necesară compilarea codului sursă. În momentul compilării, fișierele de tip java sunt preluate independent de sistemul de operare de către compilatorul Java, ca mai apoi să fie transformate în bytecode.

Figura 11 – Proces de compilare

Variabile și tipuri de date în limbajul Java

O variabilă reprezintă un nume pentru un spațiu rezervat de memorie unde se pot stoca date în momentul creării acesteia. În acest limbaj, există trei tipuri de variabile: locale, statice și instanțe ale variabilelor. Sunt două tipuri de tipuri de date în java, primitive și non-primitive.

Spre exemplu: int data = 10; // data este o variabiă

O variabilă declarată în interiorul unei metode, se numește variabilă locală. O variabilă declarată în interiorul unei clase, dar în afara unei metode, este o variabilă instanță, dacă nu este declarată ca fiind statică. O variabilă statică este declarată utilizând cuvântul cheie static. Aceasta nu poate fi locală.

Exemplu:

class A

{

int data = 50; // variabilă instanță

static int m = 1; // variabilă statică

void method()

{

int n = 24; // variabilă locală

}}

Tipul de dată reprezintă o clasificare prin care se identifică unul sau mai multe tipuri de date, care determină posibile valori pentru acel tip, operații ce se pot realiza asupra acestora, ce înseamnă tipul respectiv și modurile în care se pot stoca date în cadrul acestora.

Majoritatea limbajelor de programare oferă în mod explicit noțiunea de tip de dată și un set general de tipuri de date cel mai des întâlnite. Cu excepția acestora se mai permit și definirea altor tipuri de date, acest aspect fiind în general acoperit de către programator.

În limbajul java, există doua tipuri de date predefinite: primitive și non-primitive.

Tipuri de date primitive:

Tipurile de date non-primitive sunt: Șiruri de caractere (String), Tablouri (Array), Liste (List), Coada (Queue), Stive (Stack), etc.

Operatori în limbajul Java

Operatorii sunt simboluri speciale care realizează operații specifice pe unul, doi, sau trei operanzi, după care returnează un rezultat. Fiecare dintre acești operatori au o anumită precedență unul față de celălalt în funcție de ordinea precedenței. Operatorii cu o precedență mai ridicată, sunt evaluați înaintea operatorilor cu o precedență relativ mai scăzută. Operatori care au aceeași nivel de precedență se evaluează după anumite reguli. Toți operatorii binari, cu excepția operatorilor de atribuire sunt evaluați de la stânga la dreapta; iar operatorii de atribuire sunt evaluați de la dreapta la stânga.[ORA15]

Tipuri de operatori

Expresii, Declarații și blocuri

Expresii

O expresie reprezintă o construcție realizată din variabile, operatori și invocarea anumitor metode, care se construiesc cu ajutorul sintaxei limbajului utilizat și se evaluează la o singură valoare. Valoarea tipului de dată returnat de către o expresie depinde de elementele utilizate în acea expresie. Spre exemplu expresia de atribuire „a = 0” va returna un întreg datorită faptului ca operator de atribuire returnează o valoare de același tip de dată precum partea stângă a operandului; în acest caz, variabila menționată mai sus, este de tip întreg. Astfel că tipul de dată va guverna valoarea ce poate fi returnată de variabila declarată de către programator.

Limbajul java permite construirea unor expresii mai complexe, prin expresii mai simple, cu condiția ca tipul de dată necesar de către o parte a expresiei, să fie compatibil cu tipul de dată al celeilalte părți. Un astfel de exemplu poate fi o simplă înmulțire a trei operanzi (1 * 2 * 3). În acest caz particular, ordinea în care expresiile sun evaluate nu reprezintă o importanță, deoarece rezultatul înmulțirii este independent de ordinea operanzilor, rezultatul fiind tot timpul același, indiferent de ordinea în care se aplică multiplicarea. Spre exemplu operația de mai jos, oferă rezultate diferite în funcție de modul în care se execută adunarea și împărțirea:

X + Y / 100 – va reprezenta o evaluare ambiguă.

Dacă se dorește, există posibilitatea evaluării într-o ordine aleasă de către programator, utilizând paranteze rotunde.

(X + Y) / 100 – nu reprezintă o evaluare ambiguă

Dacă nu se specifică ordinea în care se vor evalua operațiile dintre operanzi, aceasta va fi determinată de către precedența operatoriilor.

Declarații

Declarațiile sunt echivalente propozițiilor reprezentate într-o anumită limbă. O declarație formează o unitate completă de execuție. În cadrul limbajului Java, o declarație se finalizează în momentul în care se întâlnește semnul de punctuație „;”. În momentul utilizării unor operații de post fixare, atribuire, invocare a unor metode sau al creării unor expresii, declarațiile se numesc declarații de expresii. Exemplu:

dec = 8933.234; // declarație de atribuire

dec++; // declarație de post fixare

System.out.println("Hello World!"); // invocare a unei metode

Blocuri

Un bloc reprezintă un grup de zero sau mai multe declarații între acolade și pot fi utilizate oriunde o declarație este permisă. Exemplul „Hello World” a demonstrat acest aspect.

Declarații de control

Declarațiile din interiorul unui fișier sursă sunt în general executate de sus în jos, în funcție de ordinea în care acestea apar. Acest tip de declarații pot opri execuția unei bucăți de cod datorită unor condiții oferite în cadrul acestora. Astfel de tipuri sunt declarațiile decizionale (if, if-then, if-then-else, switch), declarații de tip buclă (for, while, do-while) și cele de ramificare (break, continue, return).[CSH07]

Declarația decizională if-then

Acest tip de declarație poate fi considerat ca fiind cea mai de bază declarație dintre toate cele existente în acest limbaj de programare. Prin această declarație i se spune programului să execute o secțiune de cod doar dacă o anumită condiție se evaluează ca fiind adevărată. Spre exemplu:

int varsta = 18;

if(varsta == 18) { System.out.println("Acest mesaj va fi afisat!"); }

În cazul de față, dacă variabila vârstă va fi egală cu 18, se va afișa mesajul din cadrul secțiunii condiției if. În cazul în care condiția se va evalua ca fiind falsă (varsta este mai mică decât 18), se va încerca evaluarea celorlalte ramuri.

Declarația if-then-else

Acest tip de declarație oferă o cale secundară a execuției în cazul în care clauza if va fi evaluată ca fiind falsă. Acestea tipuri de declarații se pot rezuma fie doar la două ramuri, sau la un număr nelimitat de ramuri, în funcție de necesitatea utilizării. Spre exemplu:

Declarația switch

Spre deosebire de tipul anterior, acest tip de declarație poate avea un număr de căi de execuții posibile. Un switch poate avea ca și valoare de evaluat un tip de dată primit precum byte, short, char și int. Poate utiliza ca si valoare tipuri de enumerații, șiruri de caractere sau alte obiecte.

Corpul unei declarații switch este cunoscut ca și bloc. O declarație în cadrul unui switch poate fi etichetat cu unul sau mai multe etichete implicite. Acesta își va evalua expresia inițială iar mai apoi va executa fiecare declarație din interiorul etichetelor de tip case.

Exemplu:

int luna = 3;

String strLuna;

switch(luna) {

case 1: strLuna = "Ianuarie";

break;

case 2: strLuna = "Februarie";

break;

case 3: strLuna = "Martie";

break;

default: strLuna = "A trecut iarna.";

}

Declarația while și do-while

Declarația while execută în mod continuu o secțiune de cod atât timp cât o condiție particulară este evaluată ca fiind adevărată. Sintaxa acesteia arată astfel:

while (condiție) {

declarație(i)

}

Declarația while evaluează expresia, care necesită returnarea unei valori booleene. Dacă expresia se evaluează ca fiind adevărată, această declarație va executa secvența de cod din interiorul său. Această condiție se va evalua până în momentul în care expresia va ajunge să fie evaluată ca fiind falsă. Astfel în cazul în care condiția va fi evaluată tot timpul cu o valoare de adevăr, se poate crea o buclă infinită.

Limbajul de programare oferă și o declarație de tip do-while, care are forma următoare:

do {

declarație(i)

} while(expresie);

Diferența dintre cele două este că în cazul declarației do-while se va evalua expresia condițională la sfârșitul buclei, ci nu la început. Astfel secvența de cod din cadrul unui bloc do, se va executa cel puțin o singură dată.

Declarația for

Acest tip de declarație oferă o metodă compactă de a itera peste un interval de valori. Forma generală a unei bucle de tip for poate fi scrisă astfel:

for(inițializare ; finalizare ; incrementare) {

declarație(i)

}

În momentul utilizării unei astfel de declarații este foarte important să se țină cont de:

Inițializarea expresiei va inițializa bucla; este executată o singură dată, la începutul buclei

În momentul în care expresia de finalizare se evaluează ca fiind falsă, iterarea buclei se va opri

Expresia de incrementare utilizată după fiecare iterare a buclei. Este perfect acceptabil ca această expresie să se incrementeze sau decrementeze o valoare

Cele trei expresii din cadrul buclei for sunt opționale, astfel că dacă se dorește se poate crea o buclă infinită în felul următor:

for( ; ; 😉 {

secvența de cod

}

Bucla for mai are încă o formă de utilizare, realizată în mod special pentru iterarea colecțiilor sau a tablourilor. Această formă se mai numește și „forma îmbunătățită a buclei for” și poate fi utilizată pentru a realiza bucle mai compacte și mult mai ușor de citit. Pentru o demonstrație se consideră următorul tablou cu numere întregi de la 1 la 10.

int[] tablou = {1,2,3,4,5,6,7,8,9,10};

for(int număr : tablou) {

System.out.println("Număr: " + număr);

}

În acest exemplu variabila număr reține valoarea curentă a numărului din tablou. Cea de a doua variantă prezentată se recomandă a fi utilizată cât mai des în practică.

Concepte ale Programării Orientate pe Obiecte

Programarea orientată pe obiecte reprezintă o paradigmă prin care fiecare program prelucrează date care descriu entități (obiecte și evenimente) similare celor din viața reală. Astfel prin obiecte se pot descrie caracteristici și comportamente ale unor entități similare. Scopul principal al programării orientate pe obiecte îl reprezintă modalitatea rapidă de a dezvolta și a menține codul sursă realizat pe parcursul dezvoltării unui proiect. Un alt aspect important este legat de faptul că generalizarea unor anumite părți din cod pot oferi o modalitate de reutilizare, aplicând principiile potrivite.[CMV02]

Principiile fundamentale ale unui limbaj de programare sunt, încapsularea, moștenirea, abstractizarea și polimorfismul.

Clase și Obiecte

Declararea claselor

În acest limbaj clasele se pot declara în felul următor:

class Clasa {

// câmpuri, constructor și declararea metodelor

}

Corpul clasei (zona dintre acolade) va conține tot codul necesar unui ciclu de viață al unui obiect instanțiat printr-o clasă: constructori pentru inițializarea de noi obiecte, declarații pentru câmpuri care oferă stările clasei și ale obiectelor și metode necesare pentru a implementa comportamentul clasei și al obiectelor sale.

Exemplu oferit anterior pentru definirea unei clase, oferă o variantă minimală, însă se pot oferi mai multe informații în privința clasei precum numele superclasei sale, existența unei interfețe sau clase abstracte. Toate acestea se pot declara la începutul zonei de definire al claselor. Spre exemplu,

class ClasaMea extends SuperClasa implements OInterfata {

// câmpuri, constructor și declararea metodelor

}

explicitează faptul că clasa „ClasaMea” este o sub-clasă a „SuperClasa” și implementează interfața „OInterfata”.

Se pot adăuga și modificatori de acces precum public sau privat la începutul clasei.

Modificatori de acces

Modificatorii de acces permit controlul asupra elementelor din interiorul unei clase.

modificatorul public – câmpurile ce vor utiliza acest modificator sunt accesibile de către orice altă clasă

modificatorul privat – câmpurile ce vor utiliza acest modificator vor fi accesibile doar din interiorul clase

Pentru a se respecta principiul incapsulării, se obișnuiește declararea câmpurilor ca fiind private, iar utilizarea variabilelor se va efectua strict prin metode ce vor oferi modalități de scriere și citire al variabilelor.

public int getValue() { return value; }

public void setValue(int v) { value = value; }

Definirea metodelor

Forma unei metode se prezintă astfel:

(modificator de acces) (tip) numeFuncție (parametrii) {

// secvență de cod

}

Singurele elemente necesare declarării unei metode sunt tipul pe care îl vor returna, o pereche de paranteze (), și corpul funcției dintre acolade {}.

În general, o declarație a unei metode, are șase componente:

Modificator – precum public, privat, etc.

Tip – tipul de dată al valorii ce va fi returnată de către metodă, sau void în cazul în care nu se va returna nici o valoare.

Numele metodei

O listă de parametrii – în cazul în care există mai mul de un parametru, aceștia vor fi delimitați prin virgulă (”,”). Aceștia vor fi precedați de către tipul lor de dată. Chiar dacă nici un parametru nu va fi utilizat, prezența parantezelor este necesară.

Corpul metodei – toată secvența de cod necesară metodei, se va insera între cele două acolade.

Limbajul java permite supraîncărcarea metodelor, iar Java poate face distincția dintre metode cu diferite semnături. Acest aspect oferă posibilitatea ca mai multe metode din cadrul unei clase, să aibă același nume chiar dacă acestea au o listă diferită de parametri.

Diferențierea metodelor supraîncărcate se va efectua prin tipul și numărul de argumente oferite în momentul apelului metodei. Cu toate acestea nu există posibilitatea declarării a două metode absolut identice. În acest caz compilatorul va semnala o eroare.

Constructori

O clasă conține constructori care sunt apelați în momentul creări unui obiect pe baza clasei. Declarația unui constructor nu diferă cu foarte mult față de declarația unei metode cu excepția faptului că un constructor utilizează numele clasei și nu returnează o valoare. Spre exemplu:

clasa ClasaMea {

ClasaMea() {}

}

În cadrul unei clase pot fi definiți zero sau mai mulți constructori, în funcție de necesități. Unui constructor îi pot lipsi parametrii, caz în care se recomandă utilizarea constructorului implicit, adică nu este necesară declararea acestuia. Un alt aspect important este faptul că nu pot exista doi constructori cu același număr de parametri și același tip.

În cazul în care există o superclasă a clasei, al cărei constructor are cel puțin un parametru, este necesară utilizarea a cel puțin unui constructor bazat pe clasa moștenită.

Obiecte

Un program tipic limbajului java, creează în general un număr destul de mare de obiecte, pentru a se putea interacționa cu acestea și metodele oferite de fiecare obiect în parte. Fiecare declarație a unui obiect, va crea obiectul în sine și îl va atribui unei variabile:

Complex variabila = new Complex(2, 3);

Complex dreptunghi = new Dreptunghi();

Instanțierea unei clase

Această operație se realizează cu ajutorul operatorului new. Operatorul new necesită un singur argument de tip post fix și anume apelul constructorului. Numele constructorului trebuie să fie identic cu cel al clasei instanță. Operatorul returnează o referință la obiectul creat. Această referință este de obicei atribuită unei variabile al acelui obiect precum:

Punct origine = new Punct(0, 30);

Aspectul menționat nu este o necesitate, astfel încât poate fi utilizat direct într-o expresie fără nici o atribuire, astfel:

int înălțime = new Rectangle().height;

Apelul metodelor unui obiect

De cele mai multe ori, în cazul instanțierii unei clase, este necesar apelul metodei obiectului creat. Pentru apelul unei astfel de metode, este necesară scrierea obiectului urmat de operatorul punct (.), după care urmează numele metodei și un set de paranteze pentru lista de parametri, dacă este cazul.

Garbage-Collector

Unele limbaje de programare necesită urmărirea continuă a numărului de obiecte create, pentru a le dealoca în momentul în care acestea nu mai necesită o utilizare, cu scopul de a elibera memoria ocupată de către acestea. Această metodă poate duce la erori în codul scris de către programator. Așadar, limbajul Java permite crearea unui număr limitat de obiecte fără a fi necesară distrugerea lor. Mediul de dezvoltare Java se va ocupa de acest aspect în momentul în care decide că obiectele create nu mai sunt utilizate în codul scris. Acest concept se numește garbage-collector.

Această decizie ține de faptul că nu mai există referințe la un anumit obiect păstrat până în acel moment în memorie.

Cuvântul cheie this

În cadrul unei instanțe al unei metode sau constructor, cuvântul cheie this face o referire la obiectul curent, și anume la obiectul al cărei metode este apelată. Se poate face referire la orice număr de obiecte din cadrul unei instanțe al unei metode sau al unui constructor utilizând cuvântul this.

public class Point {

public int x = 0;

public int y = 0;

//constructor

public Point(int a, int b) {

x = a;

y = b;

}

}

Liste

Listele reprezintă un subtip al colecției Java.Utils. Listele reprezintă o listă ordonată de obiecte, ceea ce înseamnă ca se pot accesa elementele unei liste într-o ordine specifică, cu ajutorul unui index.

Inițializarea unei liste se realizează astfel:

List lista = new ArrayList();

Operațiile ce se pot efectua în cadrul unei liste sunt:

Adăugare

Ștergere

Adăugarea elementelor într-o listă se efectuează ordonat, ceea ce înseamnă ca ultimul element adăugat în cadrul unei liste va fi primul element din coada acesteia.

Listele pot fi parcurse doar în ordinea acestora, și nu pot fi accesate fără parcurgerea în întregime a listei.

Ștergerea unui element din listă presupune pasul de eliminare din listă al unui element, după care se efectuează îmbinarea celor două părți ale listei rămase pentru a recrea lista fără elementul șters.

List listA = new ArrayList();

listA.add("element 0");

listA.add("element 1");

// Iterare a unei liste.

for(Object object : listA) {

String element = (String) object;

}

Specificațiile aplicației

Schema bloc a sistemului. Scurtă descriere

Figura 12 – Schema bloc a sistemului

Aplicația va fi un sistem automat, prin care utilizatorul va putea acționa jaluzele verticale și o ușă glisantă, prin intermediul dispozitivului „Leap Motion”. Utilizatorul interacționează cu „Leap Motion” prin intermediul gesturilor implementate. Odată ce un anumit gest este recunoscut de către dispozitiv, acesta va trimite date sistemului de operare care mai apoi le interpretează cu ajutorul aplicației java. Noile date sunt trimise plăcuței Arduino prin Bluetooth, care pune în acțiune unul dintre cele trei motoare, în funcție de gestul ales. Astfel se va deschide sau închide ușa glisantă, se vor deschide sau închide jaluzelele, se va realiza rotirea acestora, sau se poate opri orice acțiune aflată în desfășurare.

Utilizatorul va putea realiza acțiunile menționate mai sus atât manual cât și în mod automat, în funcție de durata gestului. Oprirea automată se realizează la nivel fizic, cu ajutorul unor butoane.

Funcțiile sistemului

În cadrul aplicației am realizat următoarele funcții:

Gestul cu două degete

Gestul mână

Gestul prin rotație al mâinii

Comunicare prin Bluetooth

Gestul cu două degete realizează operația de deschidere și închidere al uși glisante cât și cea de oprire al acesteia. Controlul se poate realiza atât în mod manual și automat.

Gestul mână efectuează controlul jaluzelelor verticale pentru închiderea și deschiderea lor, cât și oprirea jaluzelelor. Similar gestului anterior, operația se poate realiza în mod manual și automat.

Gestul prin rotație a mâinii oferă posibilitatea de rotație al jaluzelelor verticale în ambele sensuri.

Gestul pumn oferă posibilitatea utilizatorului de a opri orice comanda aflată în acțiune, indiferent de modul de desfășurare (manual sau automat).

Comunicarea prin Bluetooth realizează un set de instrucțiuni necesare pentru inițializarea conexiunii dintre calculator și „Arduino UNO”, ca mai apoi să permită transmiterea mesajelor între cele două. În momentul finalizării schimbului de date, se oferă și posibilitatea de închidere a conexiunii stabilite.

Proiectarea aplicației

Arhitectura sistemului

Modulul dezvoltat pentru controlarea sistemului, este realizat în mediul de dezvoltare Eclipse.

Funcțiile dezvoltate până în momentul de față sunt: gestul cu două degete, gestul mână, gestul prin rotație al mâinii, gestul pumn și comunicarea prin Bluetooth.

Figura 13 – Funcțiile sistemului

Sistemul permite utilizatorului efectuarea unui gest care mai apoi interpretat de dispozitivul „Leap Motion” va transmite un anumit mesaj prin Bluetooth plăcuței „Arduino UNO” unde datele vor fi prelucrate pentru acționarea fizică a componentelor.

Figura 14 – Arhitectura Sistemului

Descrierea componentelor

Funcțiile folosite în cadrul acestei aplicații sunt următoarele:

Gestul cu două degete

Înaintea acționării acestui gest, se verifică dacă există în componența informațiilor primite la intrare, două degete extinse. În momentul acționării gestului se verifică prima poziție primită de către dispozitivul „Leap Motion”. Această valoare va fi comparată cu următoarele valori primite la intrare. În cazul în care valoarea este aproximativ egală cu valoarea primei poziții, se va realiza oprirea. Dacă valoarea va fi mai mică sau mai mare, se va acționa direcția de deplasare a unei componente în partea stângă, respectiv dreaptă.

public class TwoFingersGesture extends CalmaGesture

{

private float motionSpeed;

private Hand hand;

public TwoFingersGesture(Hand hand)

{

super(hand);

motionSpeed = DEFAULT_MOTION_SPEED;

this.hand = hand;

}

public TIP type()

{

TIP value = CalmaGestureList.TIP.NONE;

if(countFingers() == 2 && isFingerType(Finger.Type.TYPE_INDEX)

&& isFingerType(Finger.Type.TYPE_MIDDLE))

{

value = CalmaGestureList.TIP.TWO_FINGERS;

}

return value;

}

public float getMotionSpeed()

{

return motionSpeed;

}

public void setMotionSpeed(float value)

{

motionSpeed = value;

}

public int start(int value)

{

int option = 0;

Vector vector = hand.direction();

double previousHandPosition = 0;

if(FrameListener.isHand) {

previousHandPosition = vector.getX();

FrameListener.isHand = false;

}

if(vector.getX() > previousHandPosition + motionSpeed) {

option = 4;

if(option != value)

System.out.println("Door on forward.");

}

else if(vector.getX() < previousHandPosition – motionSpeed) {

option = 6;

if(option != value)

System.out.println("Door on reverse.");

}

else {

option = 5;

if(option != value)

System.out.println("Door idle.");

}

return option;

}

}

Gestul mână

Acest gest este destinat controlului închiderii și deschiderii jaluzelelor verticale. Pentru a putea fi valid, gestul necesită interpretarea celor cinci degete ca fiind extinse. Odată ce acest gest este recunoscut de către aplicație, se va păstra prima valoare a poziției mâinii într-o variabilă cu scopul comparării acesteia față de viitoarele poziții. Dacă poziția următoare va fi mai mică decât prima valoare obținută, se va efectua deplasarea la stânga a jaluzelelor, iar în cazul în care poziția curentă va fi mai mare decât prima valoare, se va realiza deplasarea jaluzelelor la dreapta. În cazul în care cele două valori sunt similare, se va realiza oprirea.

public class HandGesture extends CalmaGesture

{

private float motionSpeed;

Hand hand;

public HandGesture(Hand hand)

{

super(hand);

this.hand = hand;

motionSpeed = DEFAULT_MOTION_SPEED;

}

public TIP type()

{

TIP value = CalmaGestureList.TIP.NONE;

if(countFingers() == 5) {

value = CalmaGestureList.TIP.HAND;

}

return value;

}

public float getMotionSpeed()

{

return motionSpeed;

}

public void setMotionSpeed(float value)

{

motionSpeed = value;

}

public int start(int value)

{

int option = 0;

Vector vector = hand.direction();

double previousHandPosition = 0;

if(FrameListener.isHand) {

previousHandPosition = vector.getX();

FrameListener.isHand = false;

}

if(vector.getX() > previousHandPosition + motionSpeed) {

option = 1;

if(option != value)

System.out.println("Blinds on forward.");

}

else if(vector.getX() < previousHandPosition – motionSpeed) {

option = 3;

if(option != value)

System.out.println("Blinds on reverse.");

}

else {

option = 2;

if(option != value)

System.out.println("Blinds idle.");

}

return option;

}

}

Gestul prin rotație al mâinii

Gestul prin rotație al mâinii diferă puțin față de gesturile anterioare, prin faptul că nu permite oprirea automată a componentelor acționate. Pentru inițializarea acestui gest, este necesară verificarea celor cinci degete ca fiind extinse, cât și faptul că mâna utilizatorului este rotată la 90 de grade. Odată acționat acest gest, se va păstra prima poziție într-o variabilă pentru a putea fi comparată cu pozițiile viitoare. În funcție de valoarea poziției curente, mai mare, respectiv mai mică, se va efectua rotirea jaluzelelor la stânga, respectiv la dreapta a acestora.

public class RotatedHandGesture extends CalmaGesture

{

private float motionSpeed;

Hand hand;

public RotatedHandGesture(Hand hand)

{

super(hand);

this.hand = hand;

motionSpeed = DEFAULT_MOTION_SPEED;

}

public TIP type()

{

TIP value = CalmaGestureList.TIP.NONE;

if(countFingers() == 5) {

value = CalmaGestureList.TIP.HAND;

}

return value;

}

public float getMotionSpeed()

{

return motionSpeed;

}

public void setMotionSpeed(float value)

{

motionSpeed = value;

}

public int start(int value)

{

int option = 0;

Vector vector = hand.direction();

double previousHandPosition = 0;

if(FrameListener.isHand) {

previousHandPosition = vector.getX();

FrameListener.isHand = false;

}

if(vector.getX() > previousHandPosition + motionSpeed) {

option = 7;

if(option != value)

System.out.println("Rotating blinds on forward.");

}

else if(vector.getX() < previousHandPosition – motionSpeed) {

option = 9;

if(option != value)

System.out.println("Rotating blinds on reverse.");

}

else {

option = 8;

if(option != value)

System.out.println("Rotating blinds idle.");

}

return option;

}

}

Gestul pumn

Acest gest se acționează în momentul în care datele preluate de către dispozitivul „Leap Motion” detectează flexia, mâinii utilizatorului. În momentul acționării acestui gest, se va efectua oprirea ușii cât și a jaluzelelor, indiferent de modul de acționare (manual sau automat). Acest gest a fost realizat cu scop de oprire prioritară.

public class FistGesture extends CalmaGesture {

public FistGesture(Hand hand) {

super(hand);

}

public TIP type()

{

TIP value = CalmaGestureList.TIP.NONE;

if(countFingers() == 0) {

value = CalmaGestureList.TIP.FIST;

}

return value;

}

public int start(int value)

{

int option = 0;

if(option != value) {

System.out.println("Stop!");

}

return option;

}

}

Toate cele patru gesturi realizate, moștenesc o clasă de bază numită CalmaGesture, cu scopul de a utiliza unul dintre facilitățile limbajelor orientate pe obiecte, și anume polimorfismul. Astfel se explică similaritatea metodelor realizate în cadrul aplicației.

Toate cele trei gesturi permit controlul manual și automat prin cadrul unui timer realizat cu scopul de a verifica perioada de timp al acționării unui gest. În cazul în care perioada de timp depășește o secundă, se consideră controlul jaluzelelor în mod manual, altfel prin testări multiple s-a observat că, acționarea unei comenzi automate necesită o perioadă de timp mai mică de o secundă (0,50).

Comunicarea prin Bluetooth

În cadrul comunicării prin Bluetooth se efectuează stabilirea conexiunii dintre sistemul de operare și „Arduino UNO”, cât și al inițializării, dacă conexiunea a fost realizată cu succes. În cazul în care nu se poate efectua o conexiune între cele două dispozitive, nu va avea loc inițializarea aplicației.

După acest pas se poate accesa cu ușurință funcționalitatea de transmitere a datelor către modulul Bluetooth al plăcuței „Arduino”, iar în cazul în care se va semnala o eroare în modul de transmitere al datelor, aceasta va fi „prinsă” cu ajutorul blocurilor try și catch.

Deoarece este necesară oprirea conexiuni în momentul finalizării transmiterii datelor, o funcționalitate a acestui modul, va fi posibilitatea de a închide conexiunea dintre cele două dispozitive. Acest lucru va permite o nouă conexiune între cele două, eliberând portul utilizat anterior.

public class Bluetooth implements SerialPortEventListener {

SerialPort serialPort = null;

private static final String PORT_NAMES[] = {"COM6"};

private String appName;

private BufferedReader input;

private OutputStream output;

private static final int TIME_OUT = 1000; // Port open timeout

private static final int DATA_RATE = 115200; // Arduino serial port

public boolean initialize() {

try {

CommPortIdentifier portId = null;

Enumeration<?> portEnum = CommPortIdentifier.getPortIdentifiers();

System.out.println( "Trying:");

while (portId == null && portEnum.hasMoreElements()) {

CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();

System.out.println( " port" + currPortId.getName() );

for (String portName : PORT_NAMES) {

if ( currPortId.getName().equals(portName)

|| currPortId.getName().startsWith(portName)) {

serialPort = (SerialPort)currPortId.open(appName, TIME_OUT);

portId = currPortId;

System.out.println( "Connected on port" + currPortId.getName() );

break;

}

}

}

if (portId == null || serialPort == null) {

System.out.println("Oops… Could not connect to Arduino");

return false;

}

serialPort.setSerialPortParams(DATA_RATE,

SerialPort.DATABITS_8,

SerialPort.STOPBITS_1,

SerialPort.PARITY_NONE);

serialPort.addEventListener(this);

serialPort.notifyOnDataAvailable(true);

try { Thread.sleep(2000); } catch (InterruptedException ie) {}

return true;

}

catch ( Exception e ) {

e.printStackTrace();

}

return false;

}

public void sendData(String data) {

try {

System.out.println("Sending data: '" + data +"'");

output = serialPort.getOutputStream();

output.write( data.getBytes() );

}

catch (Exception e) {

System.err.println(e.toString());

System.exit(0);

}

}

public synchronized void close() {

if ( serialPort != null ) {

serialPort.removeEventListener();

serialPort.close();

}

}

FrameListener

În cadrul acestei clase se vor efectua schimbările între gesturi, inițializarea, verificarea și acționarea lor.

Această clasă este necesară pentru a permite dispozitivului „Leap Motion” interpretarea datelor la fiecare frame obținut în cadrul unei secunde.

Fiecare dintre gesturile utilizate sunt acționate în cadrul unui bloc de tip switch pentru a se putea verifica tipul gestului primit la intrare. Verificarea se realizează prin comparația fiecărui gest cu o listă de gesturi. Dacă gesturile coincid, atunci acest gest va returna ca fiind existent.

Tot în cadrul acestei clase, se oprește transmiterea datelor în cazul în care acestea sunt identice cu cele anterioare, pentru a realiza o sincronizare cu portul de citire al modului „Arduino”, astfel încât să nu existe probleme de supraîncărcare al acestui modul.

public void onFrame(Controller controller)

{

Frame frame = controller.frame();

HandList hands = frame.hands();

Hand hand = null;

if(hands.count() == oneHand) {

hand = hands.get(currentHand);

CalmaGestureList gesturesList = new CalmaGestureList(hand);

for(int i = 0; i < gesturesList.count(); i++) {

CalmaGesture gesture = gesturesList.get(i);

float f = hand.palmNormal().roll();

if(Math.toDegrees(f) >= 30 || Math.toDegrees(f) <= -30)

isRotated = true;

else

isRotated = false;

switch(gesture.type()) {

case HAND:

if(isRotated) {

RotatedHandGesture rotatedHand = new RotatedHandGesture(hand);

rotatedHand.setMotionSpeed(0.30F);

option = rotatedHand.start(previousOption);

}

else {

new CalmaTimer(1);

counter++;

HandGesture handGesture = new HandGesture(hand);

option = handGesture.start(previousOption);

}

break;

case ROTATED_HAND:

break;

case TWO_FINGERS:

new CalmaTimer(1);

counter++;

TwoFingersGesture twoFingersGesture = new TwoFingersGesture(hand);

option = twoFingersGesture.start(previousOption);

break;

case FIST:

FistGesture fistGesture = new FistGesture(hand);

option = fistGesture.start(previousOption);

break;

case NONE:

break;

}

}

}

else {

isHand = true;

if(change == 1 ) {

option = 0;

change = 0;

}

}

if(option != previousOption) {

bluetooth.sendData("" + option);

previousOption = option;

System.out.println("Option: " + option);

try { Thread.sleep(30); }

catch (InterruptedException e) { e.printStackTrace(); }

}

}

Probleme rezolvate

În cadrul acestui subcapitol voi prezenta problemele întâmpinate în timpul elaborării proiectului, și modul de soluționare al acestora.

Transmiterea de date prin Bluetooth

Datorită faptului că modul de preluare a datelor de către dispozitivul „Leap Motion” presupune citirea fiecărui cadru, mai exact 365 cadre pe secundă, datele transmise către modulul Bluetooth atașat plăcuței Arduino, primea uneori valori eronate, concatenând mai multe șiruri de caractere, fapt ce ducea la acționarea unei comenzi greșite.

Pentru soluționarea acestei probleme a fost necesară parcurgerea a doi pași, și anume:

transmiterea datelor o singură dată către modulul Bluetooth

schimbarea vitezei de transmitere a datelor

Cele două probleme ce duceau la transmiterea valorilor eronate necesită o abordare concomitentă deoarece sunt strâns legate una de cealaltă. Pentru a explica acest aspect se consideră următorul scenariu:

viteza de transfer a datelor este egală cu 9600;

utilizatorul efectuează un gest pentru deschiderea jaluzelelor verticale;

după interpretarea gestului specific deschiderii, valoarea transmiterii modulului Bluetooth va fi 1;

valoarea transmisă se preia de Arduino pentru acționarea fizică a jaluzelelor.

utilizatorul efectuează imediat gestul de oprire al jaluzelelor cât și cel de deschidere al ușii glisante;

În acest moment gesturile interpretate vor trimite valorile 2, respectiv 5;

Deoarece se trimite un șir de caractere, valoarea preluată de către Bluetooth va fi 12;

În cadrul programului rulat de către Arduino, nu există nici un motor ce poate fi acționat prin această valoare, așadar motorul se va opri, însă nu va efectua acțiunea necesară deschiderii ușii glisante.

Prima etapă de soluționare a constat în verificarea valorii trimise anterior, astfel încât dacă un gest a fost executat într-un cadru, valoarea acestuia va fi comparată cu valorile celorlalte cadre și nu se va schimba cât timp valorile sunt egale. Astfel ne putem asigura că nu există posibilitatea de a trimite în mod continuu aceeași valoare de mai multe ori.

Pentru cea de-a doua etapă, prin schimbarea vitezei de transfer la o valoare de 115200, se elimină posibilitatea transmiterea a două valori simultan, în cazul în care acestea se trimit într-un timp foarte scurt.

Probleme dependente de dispozitiv

Având în vedere faptul că dispozitivul „Leap Motion” se prezintă ca fiind o tehnologie relativ nouă, există anumite probleme legate de modul de interpretare al gesturilor. Cele două probleme întâmpinate în cadrul acestui proiect au fost reprezentate de către distanța dintre degete și numărul acestora.

În cazul unui degetului arătător, datele nu sunt tot timpul preluate corespunzător și există riscul ca acesta să fie interpretat ca fiind deget mijlociu. Deoarece nu există o soluție pentru această problemă, aceasta fiind dependentă de algoritmul din cadrul serviciului oferit de către dispozitiv, se recomandă evitarea utilizării degetului arătător, în afara unei combinații cu alte degete.

Dacă un utilizator dorește realizarea unui gest, fără a exista o distanță între degetele sale, deseori dispozitivul interpretează gestul greșit, considerând că mâna are un singur deget extins. Această problemă se datorează unor calcule eronate ale algoritmului său similar exemplului anterior. Problema se poate rezolva prin păstrarea unei distanțe între degete. Nu se cere o distanță anume între degete atât timp cât se acestea pot fi evidențiate între ele.

Utilizarea sistemului

Pentru a folosi aplicația este necesară realizarea împerecherii modulului Bluetooth al sistemului de operare și cu modulul Bluetooth Hc-05 montat pe plăcuța „Arduino”. Ulterior conexiunea este realizată automat de către program. În cazul în care conexiunea a fost realizată cu succes, se va afișa un mesaj de confirmare.

În acest moment, utilizatorul poate interacționa cu dispozitivul „Leap Motion” pentru a accesa funcționalitățile sistemului. Gesturile implementate sunt următoarele:

Două degete (arătător și mijlociu);

Mână

Mână rotită

Pumn

Gestul două degete, va închide și deschide ușa glisantă. Poziția inițială a gestului va determina originea acestuia. Deschiderea ușii glisante se va realiza prin deplasarea gestului la stânga față de punctul de origine, iar închiderea se va realiza la dreapta față de acesta. Oprirea ușii se poate realiza prin revenirea la poziția inițială, prin retragerea mâinii în afara razei de acțiune a dispozitivului „Leap Motion” sau automat, când ușa ajunge la capătul cursei.

Pentru a acționa deschiderea și închiderea automată, durata deplasării față de punctul de origine, trebuie să fie mai scurtă de o secundă.

Figura 15 – Gestul „Două degete”

Gestul mână, va închide și deschide ușa jaluzelele verticale. Similar gestului anterior, poziția inițială a gestului va determina originea acestuia. Deschiderea jaluzelelor se va realiza prin deplasarea gestului la stânga față de punctul de origine, iar închiderea se va realiza la dreapta față de aceasta. Oprirea jaluzelelor se poate realiza prin revenirea la poziția inițială, prin retragerea mâinii în afara razei de acțiune a dispozitivului sau automat, când jaluzelele ajung la capătul cursei.

Pentru a acționa deschiderea și închiderea automată, durata deplasării față de punctul de origine, trebuie să fie mai scurtă de o secundă.

Figura 16 – Gestul „Mână”

Gestul mână rotită, va efectua rotirea jaluzelelor verticale în ambele direcții. Poziția inițială a gestului va determina originea acestuia. Rotirea la stânga în sensul acelor de ceasornic se va realiza prin deplasarea gestului la stânga față de punctul de origine, iar rotirea în sens opus acelor de ceasornic se va realiza la dreapta față de aceasta. Oprirea rotirii jaluzelelor se poate realiza prin revenirea la poziția inițială sau prin retragerea mâinii în afara razei de acțiune a dispozitivului.

Figura 17 – Gestul „mână rotită”

Gestul Pumn oprește orice acțiune aflată în desfășurare, fie manuală sau automată. În cazul acestui gest nu mai există deplasare, și implicit nici punct de origine. Astfel acțiunea acestui gest se va efectua imediat ce este detectat de către dispozitivul „Leap Motion”.

Concluzii

Ce s-a realizat

Am realizat un sistem informatic de control al automatizării, cu scopul de acționare al unor jaluzele verticale și al unei uși glisante cu ajutorul dispozitivului „Leap Motion”, fapt care presupune controlul de la distanță asupra componentelor menționate.

Pentru realizarea aplicației, s-a utilizat limbajul de programare Java și mediul de dezvoltare Eclipse, cu scopul de a oferi un nivel de portabilitate mai ridicat față de alte limbaje de programare ce impun anumite restricții.

Cu ajutorul aplicației, se vor prelua anumite gesturi de către dispozitivul „Leap Motion”, care vor fi interpretate de către aplicația realizată, și mai apoi trimise prin Bluetooth sub formă de șiruri de caractere, plăcuței „Arduino”.

În funcție de gestul utilizat se va putea efectua deschiderea și închiderea unor jaluzele verticale și a unei uși glisante. Pe lângă acestea se mai poate realiza rotirea jaluzelelor într-o anumită direcție.

Bazat pe un interval de timp de acțiune, aplicația oferă posibilitatea controlului manual cât și automat al componentelor menționate anterior. Pentru oprirea spontană a oricărei acțiuni, s-a implementat un gest specific.

Comparația cu alte realizări similare

Sistemele prezentate în partea de Studiu bibliografic, sunt dezvoltate folosind unul sau ambele dispozitive menționate, iar în cazul celor care folosesc „Leap Motion”, realizează conexiunea cu aceasta prin intermediul unui WebSocket. Scopul acestei conexiuni este pentru a permite controlul plăcuței Arduino prin intermediul dispozitivului „Leap Motion”.

Direcții de dezvoltare

Sistemul poate fi dezvoltat în orice moment prin schimbarea jaluzelelor verticale și a uși glisante cu alte obiecte ce se doresc automatizate dar și prin adăugarea de noi facilități cu scopul de a îmbunătăți modul de funcționare. Spre exemplu se poate adăuga o funcționalitate de control multiplu al jaluzelelor verticale și ușilor glisante pentru diferite încăperi simultan. O altă funcționalitate ce ar putea îmbunătăți modul de vizualizare al situației unei încăperi ar fi realizarea unei interfețe grafice. În momentul de față conexiunea dintre cele două dispozitive, permite doar transferul de informații către plăcuța Arduino cu scop de control al direcției, însă există și posibilitatea de setării vitezei de deplasare al jaluzelelor verticale și uși glisante, fapt care ar duce la un control mai ridicat direct din aplicația oferită utilizatorului.

Index Figuri

Figura 1 – Model casă inteligentă 5

Figura 2 – Arhitectura generală și principalele entități 8

Figura 3 – Leap Lamp 10

Figura 4 – Jaluzele orizontale automate 11

Figura 5 – Mașină Arduino controlată prin Leap Motion 12

Figura 6 – Robotic Hand with Arduino and Leap Motion 13

Figura 7 – Automated Blinds via Arduino 14

Figura 8 – Interfața nativă 18

Figura 9 – Interfața WebSocket 19

Figura 10 – Aplicația Vizualizer 20

Figura 11 – Proces de compilare 24

Figura 12 – Schema bloc a sistemului 36

Figura 13 – Funcțiile sistemului 38

Figura 14 – Arhitectura Sistemului 39

Figura 15 – Gestul „Două degete” 48

Figura 16 – Gestul „Mână” 49

Figura 17 – Gestul „mână rotită” 49

Similar Posts