Avtorica: Marjana Erdelji
E-pošta: marjana.erdelji@gmail.com
2017_255_29
Senzorji so vgrajeni v prenosnih telefonih od kar obstajajo (npr. mikrofon). Kaj je tisto kar je naredilo prenosne telefone pametne? Še več senzorjev (npr. ekran na dotik, senzor pospeška, žiroskop idr.). Danes smo lahko začudeni, zakaj nimamo na razpolago vseh možnih senzorjev v telefonu ali v kakšni drugi napravi. V praktični svet senzorjev v androidnih telefonih vas bomo popeljali skozi primer: Spraševali smo se, s katerimi senzorji in na kakšen način bi detektirali premik telefona v radiju 1m.
V prejšnjem članku na to temo smo si namestili in pogledali programsko okolje Android Studio, v katerem smo naredili svojo mobilno aplikacijo. Takrat smo vam obljubili, da vam ne bo treba vedeti kaj jeobjektno usmerjeno programiranje in da vam ne bo treba programirati. Sedaj ponavljamo obljube. Tudi tokrat si boste lahko kodo prenesli z dosegljivega linka.
Senzorji
Večina androidnih naprav ima vgrajene senzorje. Senzor je strojna oprema (fizična komponenta), lahko pa tudi programska (virtualna fizična komponenta), ki bere podatke iz zunanjega sveta. Z njimi beremo neobdelane podatke (ang. raw data) visoke ločljivosti in točnosti. Na primer, z gravitacijskim senzorjem razpoznavamo kompleksne geste uporabnika, kot so: nagib (ang. tilt), pretres (ang. shake), rotacija (ang. rotation), nihanje (ang. swing) in se uporablja za različne igrice. Vremenske aplikacije uporabljajo temperaturni senzor in senzor vlažnosti. Potovalne aplikacije uporabljajo GPS in senzor pospeška. Opravimo lahko tudi meritev srčnega utripa z zaznavanjem srčnega utripa žilice na prstu. To je le nekaj primerov rabe senzorjev. V grobem jih lahko uvrstimo v naslednje tri kategorije:
- Senzorji premika: Merijo pospešek in rotacijo v 3D koordinatnem sistemu. Sem spadajo senzor pospeška, žiroskop in vektorski rotacijski senzor.
- Okoljski senzorji: Merijo okoljske parametre – temperatura, pritisk, osvetljenost in vlaga. Sem spadajo barometer, kamera in termometer.
- Senzorji položaja: Merijo fizični položaj naprave. Sem spadata orientacijski senzor in magnetometer.
Vse naprave nimajo vgrajenih vseh senzorjev. Vse različice Androida nimajo podprtih vseh senzorjev. Dosegljivost programskih senzorjev je bolj spremenljiva od strojnih, ker so pogosto odvisni od enega ali več strojnih senzorjev za izpeljavo podatkov. Zato moramo to upoštevati pri razvoju androidne aplikacije. Brez skrbi, Android Studio vas bo na to opozoril. Z dobro voljo se moramo izogibati zastarelih (ang. deprecated) programskih senzorjev, saj to običajno pomeni, da je na voljo novejši in boljši senzor.
Spraševali smo se, s katerimi senzorji in na kakšen način bi brezplačno detektirali premik telefona v radiju 1m. Intuitivno je ta naloga povezana z zmožnostjo določanja trenutne lokacije in zaznave odmika od te lokacije. Pomislili smo na detekcijo lokacije z GPS-om, a je le-ta primeren za rabo na prostem. Androidov NLP (Network Location Provider) določa lokacijo naprave iz večkratnega vira: omrežja GSM/UMTS/LTE in omrežja WiFi, in je primeren za rabo tako zunaj kot znotraj, a si ne predstavljamo, da bi se omejili z dosegom lastnega WiFi omrežja, z drugimi pa ne želimo operirati. Možna alternativa je na primer detekcija s kombinacijo senzorja pospeška (za orientacijo) in žiroskopa (za rotacijo). Ker so senzorji vgrajeni v napravi, gredo povsod, kamor gre naprava. Delajo zunaj in znotraj. Na žalost žiroskopa na našem telefonu nimamo, in ni nujno, da ga imate tudi vi. Za nekaj časa smo se torej zataknili pri naslednjih pojmih:
- delovanje na lokaciji zunaj/znotraj,
- nizka poraba moči za učinkovito rabo baterije,
- točnost in odzivnost (hitrost pridobivanja podatkov) in
- podprtost potrebnih strojnih in programskih senzorjev.
Nizka poraba moči je pomemben omejevalni faktor. Na tem področju razvijajo znanost tisti, ki se ukvarjajo z napravami Android Wear (npr. ura). Kaj smo na YouTube-u izvedeli od uporabniške skupine Android Developers? Ura razpolaga z eno desetino kapacitete baterije telefona in mora trajati brez polnenja vsaj en dan. Priznajmo, to je velik razvojni izziv. Eden od kritičnih porabnikov razpoložljive energije je periodično pošiljanje podatkov preko komunikacijskega omrežja.
Glede točnosti lokacije lahko trdimo, da je GPS najbolj točen, a lokacije ne vrača tako hitro kot bi si uporabnik želel, torej ni odziven. Za določitev lokacije naprav bi sicer lahko uporabili GPS in NLP hkrati. Pridobivanje lokacije na tak način je komplicirano. Gre za uporabo podatkov iz večkratnega vira, periodično detektiranje premika naprave, preračunavanja lokacije uporabnika, natančnost se pri tem lahko spreminja in nova prebrana vrednost ima lahko slabšo kvaliteto od prejšnje.
Zato se raje držimo senzorjev. Seznam vseh tipov senzorjev (strojni ali programski) za Android, ki ga najdemo na spletni strani Android Developers, je: svetlobni senzor (ang. light/camera), senzor bližine (ang. proximity), temperaturni senzor (ang. temperature), senzor pritiska (ang. pressure), žiroskop (ang. gyroscope), senzor pospeška (ang. accelerometer), senzor magnetnega polja (ang. magnetic field), senzor orientacije (ang. orientation), od verzije Android 2.3 dalje pa tudi: gravitacijski senzor (ang. gravity), senzor linearnega pospeška (ang. linear accelerometer), senzor vektorske rotacije (ang. rotation vector) in senzor NFC (Near Field Communication).
Ker vse androidne naprave in vse verzije Androida nimajo podprtih vseh senzorjev, smo najprej z aplikacijo Sensor Box iz Trgovine Play (ang. Google Play) preverili, katere senzorje imamo na voljo v našem telefonu. Na Sliki 3 vidimo seznam teh senzorjev. Seznam, pridobljen z aplikacijo Senzor Box, ni popoln. Zato smo si prebrali minimalno potrebno teorijo, tudi vam dajemo to priložnost, odprli nov projekt v Android Studiu z imenom Senzorji in na zaslon izpisali seznam vseh podprtih senzorjev.
Do podatkov iz senzorjev pridemo z uporabo ogrodja (ang. framework) za senzorje. Ogrodje vsebuje razrede (ang. classes) in vmesnike (ang. interfaces) s katerimi lahko izvemo:
- kateri senzorji so podprti na napravi,
- kakšne so zmožnosti senzorja, njegov maksimalni doseg, kdo je proizvajalec, kakšna je poraba moči ter natančnost podatkov,
- definiramo lahko minimalne hitrosti pridobivanja podatkov ter beremo neobdelane podatke in
- registriramo ter odjavimo senzor z vmesnikom SensorEventListener, ki spremlja spremembe podatkov senzorja.
Ogrodje za androidne senzorje je del paketa android.hardware. Sestavljen je iz naslednjih razredov in vmesnikov:
- SensorManager, razred: Razred uporabimo, ko naredimo primerek servisa senzorja. Omogoča nam uporabo različnih metod za dostop do senzorja in branja podatkov ter registracijo in odjavo vmesnika SensorEventListener. Uporabimo ga lahko tudi za pridobivanje informacije o natančnosti, točnosti, in kalibraciji senzorja.
- Sensor, razred: Ta razred lahko uporabimo, da naredimo primerek izbranega senzorja. Omogoča različne metode za določanje zmogljivosti tega senzorja.
- SensorEvent, razred: S tem razredom ustvarimo objekt dogodka za senzor. Objekt sporoča informacijo o dogodkih; tip senzorja, ki je sprožil dogodek, trenutne vrednosti senzorja, točnost podatka in časovni žig dogodka.
- SensorEventListener, vmesnik: Vmesnik uporabimo za to, da ustvarimo dve metodi povratnih klicev (ang. callback), ki sprejemata obvestila o senzorjevih dogodkih, tj. ko se spremeni vrednost podatka senzorja ali ko se spremeni točnost podatka senzorja.
Izpis podprtih senzorjev
Da bi sami programsko preverili, katere senzorje imamo v napravi, lahko uporabimo neposredno in posredno metodo. Posredna metoda je tista, ki v manifestu aplikacije določa potrebne senzorje za namestitev aplikacije. Če tu navedenih senzorjev na ciljni napravi ni, se namestitev aplikacije prekine. Neposredna ali direktna metoda je programska, ki uporablja razred SenzorManager. Za to metodo moramo imeti aplikacijo nameščeno. Mi bomo tu direktni, glej program 1.
Kot vidite smo uvozili razreda Sensor in SensorManager, ki ju rabimo za naš primer detekcije premika telefona v radiju 1m. S klicem metode getSensorList(_) tipa senzorja TYPE_ALL, smo napolnili seznam mSensorList. V seznamu so shranjeni objekti tipa Senzor, glej program 2.
V zanki for se sprehodimo čez seznam podprtih senzorjev in izpišemo njegovo ime in tip. Ker klic metode getType() vrne celoštevilske vrednosti (npr. 1), pričakovali smo pa niz znakov (npr. “TYPE_ACCELEROMETER”), opravimo konvezijo podatkov, glej program 3.
V datoteki za design/layout aplikacije, v urejevalnem pogledu, smo dodali tekstovni element za izpis seznama. V našem primeru je to lblText2. Če vas zanima kako se nam izpiše seznam, potem poglejte Sliko 4.
Na podlagi izpisa smo izbrali dva senzorja, in ju uporabili za naš primer: iz izbora smo izločili žiroskop, ki ga (kot smo že napisali) na žalost nimamo na voljo, omogočil bi nam informacijo o orientaciji z večjo natančnostjo. Izločili smo tudi senzor bližine predmeta, ker mu ne bomo šli tako blizu. Senzor namreč uporablja snop infra-rdeče led svetlobe z detektorjem odboja od bližnjega objekta. Na telefonu ga najdemo tam, kjer običajno nastavimo uho med pogovorom. Zaradi tega senzorja se v fazi klica ekran ugasne. Spoznali smo ga kot neuporabnega za razdalje, daljše od 1cm. Svetlobni senzor nam ne bo dal koristnejše informacije od te, da je bil premik narejen v svetlem ali temnem. Senzor pritiska meri pritisk atmosfere, z njim določamo kako visoko smo nad nivojem morske gladine. V našem primeru je ta nivo le ena dimenzija v 3D koordinatnem sistemu in nam tudi ne nudi dovolj informacije. Okoljskih senzorjev ne potrebujemo, razen če bi nas zanimalo v kakšnih razmerah se je zgodil premik. Da bi izvedeli katera dva senzorja smo naposled izbrali, berite dalje.
Senzor | Tip | Opis | Pogosta raba |
---|---|---|---|
TYPE_ACCELEROMETER | Strojni | Meri silo pospeška v enoti m/s2, ki deluje na napravo v vseh treh oseh X-Y-Z, vključno s silo gravitacije. | Detekcija pospešenega premika (pretres, nagib ipd.). |
Senzor pospeška
Senzor pospeška (ang. accelerometer) je najbolj pogosto uporabljen senzor. Kot že samo ime pove, meri pospešek, ki ga čuti naprava relativno na prosti pad (gravitacija, g=9,8m/s2). Ko se naprava sunkovito premakne v katerikoli smeri koordinatnega sistema X-Y-Z, se podatki iz senzorja našpičijo, in spet uležejo, ko napravo umirimo. Isti senzor se uporablja za določanje orientacije naprave vzdolž osi X-Y-Z, torej ali je ekran telefona obrnjen v pokončni ali ležeči legi in ali je telefon položen na hrbtno ali čelno stran. Koordinatni sistem je prikazan na Sliki 5 – levo.
Uvozili smo razred SensorEvent in vmesnik SensorEventListener. Dodali smo senzor: Privatna spremenljivka mSensor določa senzor tipa TYPE_ACCELEROMETER. Za branje podatkov iz senzorja, moramo registrirati poslušalca in določiti pogostost branja. Ker ne razvijamo igrice, bo privzeta vrednost SENSOR_DELAY_NORMAL zadostovala, glej program 4.
S tem ko smo dodali vmesnik SensorEventListener, smo se zavezali, da bomo definirali njegove metode. Naš razred Senzorji smo najprej dopolnili z oznako implements SensorEventListener, kot je prikazano, glej program 5.
Vmesnik SensorEventListener vsebuje metodi onSensorChanged in onAccuracyChanged, ki ju moramo uporabiti. Definicij metod nam ni potrebno pisati. V Android Studiu uporabimo tipki Ctrl+O ali gremo preko menija Code->Override Methods in odpre se nam pojavno okno, kjer se na seznamu v skrčenem pogledu postavimo na android.hardware.SensorEventListener, tam pa označimo omenjeni metodi in ju s klikom na gumb OK prenesemo v kodo. Dodali smo še metodi onPause() in onResume(), ker moramo sami poskrbeti za to, da onemogočimo senzorje, ko jih ne potrebujemo (onPause()), saj ne želimo prehitro izprazniti baterije.
V datoteki za design/layout aplikacije v urejevalnem pogledu, smo dodali elemente tipa TextView in jih poimenovali txtX, txtY, txtZ in txtXYZ. V tekstovne elemente zapisujemo podatke s senzorja ob vsaki spremembi (event.values). Ob vsaki spremembi računamo tudi spremenljivko mAccelCurrent, ki ima vrednost matematičnega korena vsote kvadratov osi (evklidska razdalja). To razdaljo bomo kasneje uporabili za detekcijo premika.
Za merjenje dejanskega pospeška naprave, je potrebno izničiti vpliv sile gravitacije. To lahko naredimo z uporabo visokoprepustnega filtra. Nasprotno pa se za izolacijo gravitacijske sile lahko uporabi nizkoprepustni filter, glej program 6.
Aplikacijo smo prenesli na telefon in se z njim igrali v smislu spreminjanja orientacije in lokacije ter hkrati opazovali vrednosti spremenljivk x, y, z. Pomanjkljivost senzorja pospeška je nezmožnost detekcije nagiba, g-sil tu praktično ni, razen če se potrudimo na silo s silo. Potem je tu linearni premik (brez pospeška), ki ga ne moremo zaznati z merjenjem pospeška. Ker ne želimo tvegati, da bi izpustili kakšen premik, preizkusimo še kakšen senzor.
Primer aplikacije, ki uporablja senzor pospeška: Aplikacija Pocket Bubble Level (vodna tehtnica).
Senzor | Tip | Opis | Pogosta raba |
---|---|---|---|
TYPE_ORIENTATION | Programski | Meri stopnjo rotacije naprave okoli vseh treh fizičnih osi (X, Y, Z). Od nivoja API 3 lahko pridobimo matriko nagiba in rotacijsko matriko za napravo z uporabo gravitacijskega senzorja in senzorja magnetnega polja. | Detekcija pozicije naprave. |
Senzor orientacije
Senzor orientacije pridobi podatke z obdelavo podatkov iz senzorja pospeška in magnetnega senzorja. Zaradi intenzivnosti obdelave podatkov ima zmanjšano natančnost in točnost. Natančneje, ta senzor je zanesljiv le, če je kot nagiba 0 stopinj. Senzor orientacije je še dostopen, a ima od Androida verzije 2.2 (nivo API 8) status: zastarelo. Tudi tip senzorja orientacije TYPE_ORIENTATION ima od Androida verzije 4.4 (nivo API 20) status: zastarelo.
Priporočena zamenjava senzorja orientacije je uporaba metod getRotationMatrix() in getOrientation(). Slednja izračuna orientacijske kote z uporabo magnetnega senzorja v kombinaciji s senzorjem pospeška. Obstajajo trije orientacijski koti, ki so prikazani na Sliki 5 – desno:
Azimut (kot rotacije okoli osi -Z). Azimut je kot med smerjo kompasa naprave in magnetnim severom. Če je zgornji rob naprave obrnjen proti magnetnemu severu ima azimut vrednost 0 stopinj. Če je zgornji rob obrnjen proti magnetnemu jugu ima azimut vrednost 180 stopinj. Podobno, če je zgornji rob naprave obrnjen proti magnetnemu vzhodu je azimut 90 stopinj. Azimut ima vrednost 270 stopinj, ko je rob naprave obrnjen proti magnetnemu zahodu. Razpon vrednosti kota azimuta je od -180 stopinj do 180 stopinj.
Naklon (kot rotacije okoli osi X). Naklon je kot med ravnino, ki je vzporedna z zaslonom naprave in ravnino vzporedno z zemljo. Če držite napravo vzporedno s tlemi in je najbližji spodnji rob obrnjen proti vam, lahko nagnete zgornji rob naprave proti tlom in kot naklona se postavi v pozitivno vrednost, lahko pa zgornji rob naprave nagnete v nasprotno smer stran od tal in kot naklona se postavi v negativno vrednost. Razpon vrednosti kota naklona je od -180 stopinj do 180 stopinj.
Nagib (kot rotacije okoli osi Y). Nagib je kot med ravnino, pravokotno na zaslon naprave in ravnino, ki je pravokotna na tla. Če držite napravo vzporedno s tlemi in je najbližji spodnji rob obrnjen proti vam, lahko nagnete levi rob naprave proti tlom in kot nagiba se postavi v pozitivno vrednost, lahko pa desni rob naprave nagnete proti tlom in kot nagiba se postavi v negativno vrednost. Razpon vrednosti kota nagiba je od -90 stopinj do 90 stopinj.
static boolean | getRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)
Metoda izračuna naklonsko matriko I in rotacijsko matriko R. Rotacijska matrika pretvarja vektor iz koordinatnega sistema naprave v zunanji koordinatni sistem. |
---|---|
static float[] | getOrientation(float[] R, float[] values)
Metoda izračuna orientacijo naprave na podlagi rotacijske matrike. |
Omenjeni koti so postavljeni v drugačnem koordinatnem sistemu kot v letalstvu (yaw, pitch in roll). V letalskem sistemu je os X tista, ki poteka od repa do nosa. Lahko rečemo, da sta drugače poimenovani (zamenjani) osi X in Y.
Nismo posebej poudarili, da obstajata dva referenčna okvirja. Eden je tisti, ki deluje v sistemu naprave (ang. device’s frame of reference), drugi pa tisti, ki opisuje zunanji sistem (ang. world’s frame of reference). Z namenom preslikave med referenčnimi okvirji, imamo na voljo metodo remapCoordinateSystem().
Pri uporabi magnetnega senzorja moramo biti previdni. V kolikor imamo v bližini npr. magnetke za hladilnik ali tablo, lahko to vpliva na točnost meritve.
Kar je novega v naši kodi je nekaj novih spremenljivk in dodan senzor tipa TYPE_MAGNETIC_FIELD, ki ga registriramo podobno kot senzor pospeška. Pred uporabo podatka (event.values) preverimo s katerega senzorja je prišel. S klicem metod getRotationMatrix(_) in getOrientation(_) napolnimo rotacijsko matriko mRotationMatrix in izračunamo orientacijske kote. Kote dobimo v radianih, glej program 7.
Zaradi lažjega razumevanja kote v radianih pretvarjamo v stopinje. Zapisujemo jih v tekstovni element txtOrientation. Kot pri senzorju pospeška tudi tu računamo vrednost matematičnega korena vsote kvadratov kotov (evklidska razdalja). To razdaljo bomo uporabili za detekcijo premika. Naša aplikacija sedaj izgleda takole: glej Slika 7. Mimogrede, orientacijo boste morali testirati na napraviin ne na emulatorju.
Primer aplikacije, ki uporablja senzor orientacije: Aplikacija Compass 360 Pro (kompas).
Detekcija premika
Ali smo do sedaj razmišljali in delali v pravi smeri, se bo pokazalo čez določen čas testiranja in praktične rabe. Poglejmo si, kako smo izvedli detekcijo s senzorjem pospeška. Shranili smo si zadnjo merjeno vrednost in jo primerjali z novo. Razliko smo primerno utežili. Določili smo našo mejo, nad katero rečemo, da je prišlo do premika. Premik smo javili tako, da smo prikazali sliko. Ko premika ni več, slika izgine, glej program 8.
Poglejmo si, kako smo izvedli detekcijo s senzorjem pospeška in senzorjem magneta. Pravzaprav na podoben način. Rezultat detekcije na ta način je boljši, glej program 9.
Projekt si lahko prenesete z naslova: https://svet-el.si/za-download/programi/142-android-programi
Androidna aplikacija, ki smo jo izdelali tokrat, nam sama po sebi še ne nosi večje koristi. Zato jo bo treba izpiliti. Teoretično znanje smo za silo osvojili, v praktičnem smislu pa lahko trdimo, da smo si pripravili teren. Pripravite se, naslednjič bomo aplikacijo nadgradili do točke uporabnosti.
[?] Objektno usmerjeni programski koncepti
- Ogrodje – ang. framework: nabor osnovnih gradnikov, na primer programje, programske knjižnice, razredi, procesi, koncepti.
- Paket – ang. package: paket je sestavljen iz razredov in vmesnikov znotraj imenskega prostora, ki so organizirani na logičen način.
- Razred – ang. class: šablona za ustvarjanje primerkov objektov z enakim naborom spremenljivk, metod.
- Vmesnik – ang. interface: vmesnik je pogodba med razredom in zunanjim svetom. Ko razred izvede vmesnik, mora zagotoviti obnašanje, kot ga predvideva vmesnik.
- Objekt – ang. object: objekt je primerek razreda.
- Primerek – ang. instance: konkretna izvedba objekta v razredu.
- Metoda povratnih klicev – ang. callback method: del izvršljive programske kode, prenesen kot argument k drugi kodi, ki naj nazaj kliče (izvrši) argument v določenem času.
Program si lahko snamete tukaj!
Android Studio (1) – Programiranje
program 1 import android.hardware.SensorManager; import android.hardware.Sensor; @Override protected void onCreate(Bundle savedInstanceState) { // Get the SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); // List of Sensors Available List<Sensor> mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); }
program 2 StringBuilder sSensList = new StringBuilder(); sSensList.append("Seznam senzorjev na napravi:n"); for (Sensor s : msensorList){ sSensList.append("nIme: " + s.getName()); sSensList.append("nTip: " + getStringType1.get(s.getType()) + "nn"); } lblText2.setText(sSensList);
program 3 private HashMap<Integer, String> getStringType1 = new HashMap<Integer, String>(); // mapiramo par key – value, primer: getStringType1.put(Sensor.TYPE_ACCELEROMETER, "TYPE_ACCELEROMETER"); // … }
program 4 import android.hardware.SensorEvent; import android.hardware.SensorEventListener; private SensorManager mSensorManager; private Sensor mSensor; @Override protected void onCreate(Bundle savedInstanceState) { // … mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL); } program 5 public class Senzorji extends AppCompatActivity implements SensorEventListener { // }
program 6 protected void onPause() { // super.onPause(); mSensorManager.unregisterListener(this); } protected void onResume() { // super.onResume(); mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL); } public void onSensorChanged(SensorEvent event) { // final float alpha = 0.8f; Sensor mySensor = event.sensor; if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER){ mGravity = event.values.clone(); nGravity[0] = alpha * nGravity[0] + (1-alpha) * mGravity[0]; nGravity[1] = alpha * nGravity[1] + (1-alpha) * mGravity[1]; nGravity[2] = alpha * nGravity[2] + (1-alpha) * mGravity[2]; float x = mGravity[0] - nGravity[0]; float y = mGravity[1] - nGravity[1]; float z = mGravity[2] - nGravity[2]; mAccelCurrent = (float)Math.sqrt(x*x + y*y + z*z); txtX.setText("X: " + String.format("%.4f", x)); txtY.setText("Y: " + String.format("%.4f", y)); txtZ.setText("Z: " + String.format("%.4f", z)); txtXYZ.setText("XYZ: " + String.format("%.4f", mAccelCurrent)); } } public void onAccuracyChanged(Sensor sensor, int accuracy){ // metoda mora biti definirana }
program 7 private final float[] mAccelReading = new float[3]; private final float[] mMagnetReading = new float[3]; private final float[] mRotationMatrix = new float[9]; private final float[] mOrientationAngles = new float[3]; // vstavimo v onCreate(Bundle savedInstanceState) { nSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); // vstavimo v onResume() { mSensorManager.registerListener(this, nSensor, SensorManager.SENSOR_DELAY_NORMAL); public void onSensorChanged(SensorEvent event) { Sensor mySensor = event.sensor; if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER){ System.arraycopy(event.values, 0, mAccelReading, 0, mAccelReading.length); } if (mySensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){ System.arraycopy(event.values, 0, mMagnetReading, 0, mMagnetReading.length); } updateOrientationAngles(); } public void updateOrientationAngles(){ mSensorManager.getRotationMatrix(mRotationMatrix, null, mAccelReading, mMagnetReading); mSensorManager.getOrientation(mRotationMatrix, mOrientationAngles); }
program 8 public void onSensorChanged(SensorEvent event) { // if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER){ mAccelLast = mAccelCurrent; mAccelCurrent = (float)Math.sqrt(x*x + y*y + z*z); float delta = mAccelCurrent - mAccelLast; if (delta < 0) delta = delta * (-1f); mAccel = mAccel * 0.8f + delta; if (mAccel > 5) imgMoved.setVisibility(View.VISIBLE); else imgMoved.setVisibility(View.INVISIBLE); } }
program 9 public void updateOrientationAngles(){ // mOrientLast = mOrientCurrent; mOrientCurrent = (float)Math.sqrt(x*x + y*y + z*z); float delta = mOrientCurrent - mOrientLast; if (delta < 0 ) delta = delta * (-1f); mAccelMag = mAccelMag * 0.8f + delta; if (mAccelMag > 10) imgMoved.setVisibility(View.VISIBLE); else imgMoved.setVisibility(View.INVISIBLE); }