FİZYOPHONE

Telefonun ivme sensörleri kullanılarak fizik tedavi uygulaması yapılması amaçlanmıştır.

kol hareketleri sırasında verileler websiteye gönderilecek şeklilde android uygulama geliştirilmiştir.

websitesinde hareketlerin doğruluğunu kontrol edecek yazılım geliştirildi.

bu araştırma projesi Prof.Drt Serdar Arıtan ile birlikte yapıldı.

Bu proje, 3 aşamadan oluşmaktadır:

Projenin birinci aşamasında android uygulamasıyla sabit hızda hareket ettirilen telefonun açı hesaplanması ve açı verisinin kaydedilmesi sağlandı. Kaydedilen veriler incelenmesi için web uygulama geliştirildi.

Projenin ikinci aşamasında android uygulamasına yeni eklemeler yapılarak telefonun hareketi sırasındaki hızı da kaydedildi ve kaydedilen verilerin incelenmesi için web uygulama geliştirildi.

Projenin üçüncü aşamasında telefonun hareketinin derece, hız gibi özellikleri kaydedildi. Kayıt sırasında telefon hareketinin 3 boyutlu animasyonu yapıldı. Kaydedilen verilerle saniyede bir veri okunarak telefonun veri kaydedilirken konumunun animasyonu yapıldı.

Anahtar Kelimeler: fizik tedavi, android algılayıcılar, animasyon, derece hesaplama, hız hesaplama, açısal hız hesaplama, android animasyon

1.1 Fizik Tedavide Kullanılan Teknolojiler

Fizik tedavi, vücuda dışarıdan uygulanan sıcak, soğuk uygulamalar, elektrik akımları, masaj ve egzersiz ile ağrıyı kesmeye yönelik uygulamaları içeren ve kas iskelet sistemi hastalıklarında ya da yararlanmalarında uygulanan ilaç dışı bir tedavi şeklidir.

Fizik tedavi uygulamalarında birçok teknolojik yöntem kullanılmaktadır. İnsanları sıkıcı fizik tedavi hareketlerini zevkli hale getiren oyunlar ilk görünendir. Bu oyunlar sanal gerçeklik teknolojisiyle daha da zevkli hale getirilmektedir.

Gelişen teknolojiyle birlikte şehir hayatı giderek insanları ev, iş, okul döngüsüne sokmaktadır. Özellikle çocuklar olmak üzere, parkların yetersiz ve ulaşılabilirliğinin az olması, güvenlik vb. sorunlar, bilgisayar oyunlarına ve iletişim araçlarına bağımlılıklarının artması nedeniyle fiziksel aktivitelerinde azalma ile karşı karşıya kalmaktadır. Bu durum başta obezite olmak üzere, birçok sağlık sorununu beraberinde getirmektedir.

Günümüzde nörolojik, ortopedik, romatizmal vb. hastalıklara sahip, kas-iskelet sistemi ve sinir sistemine ait sorunları olan hastalar ve sağlıklı bireyler fizik tedavi uygulamalarından fayda görmektedir. Fizik tedavi başta egzersiz olmak üzere, ısı, elektrik akımları, el ile yapılan teknikler, kinezyolojik bantlama gibi birçok uygulamayı içermektedir. Gelişen teknoloji ile birlikte teknolojik ürünler, birçok alanda olduğu gibi fizik tedavi uygulamalarının içinde de yer almaya başladı.

Robotik sistemler, hareket destekleyici teknolojiler, web tabanlı uygulamalar ve video temmelli oyunlar en popüler teknoloji temelli iyileştirme uygulamalarıdır. Kişinin hareketlerini veya aktivitelerini bilgisayarla etkileşim içinde yapabilme imkânı sunan video temelli oyunlar ise günümüzde diğer teknolojik uygulamalardan daha fazla ilgi görerek, bir adım öne geçti.

Nintendo Wii oyun konsolu tenis, golf, boks, bowling ve beyzbol gibi spor aktivitelerini içeren oyunlarının yanı sıra kayak, ip üzerinde yürüme, denge tahtasında tilt ve kaleci olma gibi oyunları sayesinde özellikle bacak, ayak ve kalça problemi nedeniyle denge problemi olan hastalarda etkin sonuçlar sağlamaktadır. Nintendo Wii ile tüm egzersizler Wii Denge Tahtası üzerinde yapılmaktadır.

Kinect teknolojisi ise çocuklara sevdikleri bilgisayar oyunlarına sunarken, oyunlar sırasında kol, bacak, gövde hareketleri ile fiziksel aktivitenin artmasını sağlıyor. Sadece çocuklar için değil, erişkinler için de spor, dans, fitness seçenekleri olan kinect uyumlu oyunlar, hem ailenin birlikte zaman geçirip, hem eğleneceği hem de fiziksel aktivite yapabileceği üstün yanları ile beğeni toplamaktadır.

1.2 Projenin Geliştirilme Sebebi

Bazı uygulamalar da hareketin doğru yapılıp yapılmadığını kontrol etmek için geliştirilmiştir. Bunlar özel olarak tasarlanan cihazlardır. Pahalı olması ulaşılabilirliği büyük ölçüde etkilemektedir.

Günümüzde herkesin elinde telefonlar bulunmaktadır. Bu telefonların içinde belli ölçümleri yapan algılayıcılar bulunmaktadır. Örneğin; nem ölçümü, sıcaklık ölçümü, hız ölçümü, ivme ölçümü, manyetik alan ölçümü vb.

Bu telefon algılayıcıları kullanarak doğru veri alabilirse ve uygun yazılım ile donanım için herhangi bir ücret ödemeden insanların sağlığı için kullanılabilecek cihazlara dönüştürülebilir.

2. ANDROID ALGILAYICILAR

Google, Android telefonlarda geliştiricilerin algılayıcıları kolay bir şekilde uygulamalarında kullanabilmesi için Uygulama Programı Arabirimi (UPA / API) desteği sağlamıştır.

 Bu algılayıcıların bazıları şunlardır;

 

2.1 İvme Ölçer (İVMEÖLÇER)

Donanım tabanlıdır. Yerçekimi kuvveti de dâhil olmak üzere üç fiziksel eksende (x, y ve z) bir cihaza uygulanan m/ s^2   'deki ivme kuvvetini ölçer. Yani ölçümleri saniyenin karesindeki metre değişimi olarak verir. a = F/m formülüyle bulunur.

Telefonda bulunan tüm kuvvetlerin vektörel değişimleri toplanıp kütlesine bölünerek sonuç bulunur. Tabi ölçümler ağırlık merkezinden etkilenmektedir. Duran bir telefon yerçekimi etkisinde 9.81 m/s^2 görünebilirken hareket halindeki de 0 m/s^2 görünebilir. Bu etkiyi kaldırmak için high-pass türü filtre uygulanarak aşılabilir:

 public void onSensorChanged(SensorEvent event)

     {

          // alpha is calculated as t / (t + dT)

          // with t, the low-pass filter's time-constant

          // and dT, the event delivery rate



          final float alpha = 0.8;



          gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];

          gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];

          gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];



          linear_acceleration[0] = event.values[0] - gravity[0];

          linear_acceleration[1] = event.values[1] - gravity[1];

          linear_acceleration[2] = event.values[2] - gravity[2];

     }

Şekil 2.1: high-pass filtre kodu

 

2.2 Manyetik Alan Ölçer (TYPE_MAGNETIC_FIELD)

Donanım tabanlı olarak ölçüm yapar. micro-Tesla (uT) türünden ortam manyetik alanını ölçer. Genelde maddeleri ayrıştırmak için kullanılan bu algılayıcı burada telefon tarafından açı hesaplanması için bir giriş verisi olarak kullanılacaktır.

2.3 Açısal Hız Ölçer (TYPE_GYROSCOPE)

Donanım tabanlı olarak açısal hızı ölçer. Bir aygıtın, üç fiziksel eksenin (x, y ve z) her biri etrafında rad/s hızını ölçer. Örneğin: bisiklet hızlı giderken gyroscope özelliğinden dolayı dengeyi daha iyi sağlarız. Buradan alınan sonuçlarda sabit hızda veriler gelmesi beklenmektedir.

3. ANDOID ALGILAYICILAR İLE HESAPLAMA YAPMAK

Google tarafından sağlanan Uygulama Programı Arabirimi fiziksel algılayıcılardan direk veri almasını sağladığı gibi bunları kullanarak başka verilerin elde edilmesi için kullanılmaktadır.

3.1 Telefonun Rotasyon Matrisini Hesaplama (getRotationMatrix)

Ortam manyetiği(geomagnetic) ve telefonun ivmesini(gravity) giriş alarak rotasyon matrisini(R) ve eğim matrisini(I) çıktı olarak verir.

 

Şekil 3.1: Telefonun Dünya Koordinat Sistemi

<>•X, vektör ürün Y.Z olarak tanımlanır (cihazın bulunduğu yerde zeminle tanjanttır ve kabaca Doğu'yu işaret eder).
/  M[ 0]    M[ 1]    M[ 2]    M[ 3]  \

   |  M[ 4]    M[ 5]    M[ 6]    M[ 7]  |

   |  M[ 8]    M[ 9]    M[10]   M[11]  |

   \  M[12]   M[13]   M[14]   M[15]  /

Şekil 3.2: getRotationMatrix tarafından döndürülen matris

/  M[ 0]   M[ 1]   M[ 2]    0  \

   |  M[ 4]   M[ 5]   M[ 6]    0  |

   |  M[ 8]   M[ 9]   M[10]   0  |

   \     0        0          0       1  /

Şekil 3.3: getRotationMatrix tarafından döndürülen matris.

/  M[ 0]   M[ 1]   M[ 2]  \

   |  M[ 3]   M[ 4]   M[ 5]  |

   \  M[ 6]   M[ 7]   M[ 8]  /

Şekil 3.4: getRotationMatrix tarafından döndürülen matris.

Her bir matrisin tersi, kendi trans pozisyonunu alarak kolayca hesaplanabilir.

Bu fonksiyon tarafından döndürülen matrisler, cihaz serbestçe düşme yapmadığında ve manyetik kuzeye yakın olmadığında anlamlıdır.

Cihaz hızlanıyorsa veya güçlü bir manyetik alana yerleştirilirse, döndürülen matrisler hatalı olabilir.

 

 

 

 

 

Parameters

R

float: 9 büyüklüğünde matris olarak döndürülür. R null olarak girdi gönderilebilir.

I

float: 9 büyüklüğünde matris olarak döndürülür. R null olarak girdi gönderilebilir.

gravity

float TYPE_ACCELEROMETER kullanılarak alınan 3 boyutlu x,y,z matrisidir.

geomagnetic

float: TYPE_MAGNETIC_FIELD kullanılarak alınan 3 boyutlu x, y, z matrisidir.

R

Başarılı ise true, başarısız ise false  değerini döndürür.
Cihaz serbest düşme gibi durumlarda false döndürür.
Serbest düşme, yerçekiminin büyüklüğü nominal değerin 1 / 10'undan az olduğunda koşul olarak tanımlanır. Arıza durumunda çıkış matrisleri değiştirilmez.

 

Şekil 3.5: getRotationMatrix parametre ve döndürülen değer

3.2 Oryantasyon Matrisi (getOrientation)

float[] getOrientation (float[] R, float[] values)

Dönüş matrislerini temel alarak cihazın yönünü hesaplar yani dünya koordinatına göre radyan türünden yapılan açıyı hesaplar.

Şekil 3.6 Oryantasyon matrisinin dünya koordinatı ile yaptığı açı

Dünya koordinat sistemi 3 değer döndürür:

 

Returns

float[]

Sırasıyla Azimuth, Pitch, Roll 3 boyutlu matris olarak radyan cinsinden sonuç verir.

R

float: rotasyon matrisi girdi olarak alır.

 

Şekil 3.7 getOrientation parametre ve döndürülen

3.3 Telefon Koordinat Sistemi (remapCoordinateSystem)

boolean remapCoordinateSystem (float[] inR, int X, Y, float[] outR)

Elde edilen döndürme matrisini farklı koordinat sistemlerine çevirmek için kullanılır.
Bu genellikle farklı koordinat sistemlerinde açıları hesaplamak için kullanılır.

Örnekler:

remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);

Döndürüldüğünde cihazı Surface.ROTATION_90 olarak mekanik bir pusula olarak kullanma:

remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);

Elde edilen koordinat sistemi birbirine bağımlı olduğu için yalnızca iki eksen belirtilmelidir.

Parameters

inR

float:  rotasyon matrisi (R)

X

int: x ekseni yerine gelecek eksen belirtilir.

Y

int: y ekseni yerine gelecek eksen belirtilir.

outR

float: yeni eksene göre rotasyon matrisi

R

true düzgün çalışırsa. false Eğer giriş parametreleri yanlışsa,
örneğin X ve Y aynı ekseni tanımlarlarsa.

Veya inR ve outR'nin uzunluğu aynı değilse.

 

 

Şekil 3.8 remapCoordinateSystem parametre ve döndürülen

3.4 Telefon Dünya Koordinatıyla Yaptığı Açı Hesaplaması

android uygulamasına ait getRotationMatrix fonksiyonuna o anki ivme değeri ve manyetik değerlerin girdisini alarak bir rotasyon matrisi döndürmektedir. Bu rotasyon matrisini kullanarak getOrientation fonksiyonundan radyan türünden açı değeri elde edilmektedir. Bu açı değerleri de matematiğin radyandan dereceye çevirme fonksiyonu kullanıldı. Derece türünden x, y ve z koordinatlarına olan açı değerleri elde edildi.

mSensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerometerReading, mMagnetometerReading);


mSensorManager.getOrientation(mRotationMatrix, mOrientationAngles);


mOrientationAnglesDegree[0] = (float)Math.toDegrees(mOrientationAngles[0]);
mOrientationAnglesDegree[1] = (float)Math.toDegrees(mOrientationAngles[1]);
mOrientationAnglesDegree[2] = (float)Math.toDegrees(mOrientationAngles[2]);

Şekil 3.9 Telefon derece hesaplaması kodu

4. ÇALIŞMALAR

Android uygulama geliştirilmesi için bununla ilgili kodlama nasıl yapılabilir diye ön çalışma yapıldı. Bu ön çalışmanın sonucunda android uygulama geliştirilmesi ait bilgiler elde edildi. Bu bilgiler ışığında 3 çalışma yapıldı.

4.1. Birinci Çalışma

Birinci çalışma, açı bilgisi ve telefon zaman etiketi kaydedilecek android uygulama geliştirildi. Sabit hızda hareket edilen cihaza telefon bağlanarak hareketler yapıldı. Hareketlerin verileri kaydedildi. Bu bilgiler ile web uygulama geliştirilerek grafiksel analizleri yapıldı.

Telefon konumu düz, sola dönük, sağa dönük ve yatay konumdayken saniyede 60, 120, 240 derece yapacak şekilde 5 defa tekrarlı bir şekilde hızı sabit olacak bir cihaza telefon bağlandı.

Alınan veriler:

  1. Doğruluk Bilgisi: alınan algılayıcı verisinin doğruluk bilgisi telefondan alındı.
  2. Timestamp: cihazın zaman etiketi alındı. Bunu sonradan zamana çevirme gibi bir düşünce vardı ama bu her cihaza özel olarak alındığından anlık olarak çevrilmesi gerektiği anlaşıldı.
    Bu veri kullanılarak iki ölçüm arasındaki zaman bulundu. Çok az verilerde bu zaman aralığı sıfırdan küçük çıkmıştır.
  3. Açı Bilgisi: telefondan derece hesaplanarak radyan ve derece türünden x, y ve z eksenine yapılan açı değerleri alındı.
    Bazı durumlarda getRotationMatrix yanlış hesaplamaları sonucunda yanlış açı değerleri ortaya çıkmış olabilir. Bununla ilgili veri toplanmadı ve kontrol yapılmadı.
  4. Ölçüm Sayısı: ölçüm başlangıcından bitene kadar algılayıcıdan alınan her bir kayıtın numara bilgisi alındı. Bu şekilde hangi kayıt ne için alındı onun ayırımı yapılmaktadır.
  5. Lokal Ölçüm Sayısı: her bir ölçümün başlangıcından bitimine kadar algılayıcılardan alınan veri için bir kayıt numarası alınmaktadır. Bundan her bir ölçüm sırasında kaç veri alındığı bilgisi alınmaktadır. 1 ile başlar.

Açı verilerindeki ani yükselişleri yumuşatmak için kayan ortalama filtresi kullanıldı.

Şekil 4.1: Kayan ortalama denklemi

Şekil 4.2: Cihaza telefonun bağlanma şekli ve yapılan tekrarlar

Şekil 4.3: Çalışma sonucu alınan açı verisi (radyan)

Şekil 4.4: kayan ortalama filtresi uygulanan açı verisi (radyan)

Şekil 4.5: algılayıcı doğruluk oranı 2 veya 3 olduğundaki açı verisi (radyan)

Şekil 4.6 algılayıcı doğruluk oranı 2 veya 3 olduğundaki filtre uygulandıktan sonraki açı verisi (radyan)

Şekil 4.7: Cihaza telefonun bağlanma şekli ve yapılan tekrarlar

 

Şekil 4.8: Çalışma sonucu alınan açı verisi (radyan)

Şekil 4.9: kayan ortalama filtresi uygulanan açı verisi(radyan)

Şekil 4.10: algılayıcı doğruluk oranı 2 veya 3 olduğundaki açı verisi (radyan)

Şekil 4.11: algılayıcı doğruluk oranı 2 veya 3 olduğundaki filtre uygulandıktan sonraki açı verisi (radyan)

 

 

Şekil 4.12: Cihaza telefonun bağlanma şekli ve yapılan tekrarlar

 

Şekil 4.13: Çalışma sonucu alınan açı verisi (radyan)

Şekil 4.14: kayan ortalama filtresi uygulanan açı verisi (radyan)

Şekil 4.15: algılayıcı doğruluk oranı 2 veya 3 olduğundaki açı verisi (radyan)

Şekil 4.16: algılayıcı doğruluk oranı 2 veya 3 olduğundaki filtre uygulandıktan sonraki açı verisi (radyan)

 

 

Şekil 4.17: Cihaza telefonun bağlanma şekli ve yapılan tekrarlar

 

 

Şekil 4.18: Çalışma sonucu alınan açı verisi (radyan)

Şekil 4.19: kayan ortalama filtresi uygulanan açı verisi (radyan)

Şekil 4.20: algılayıcı doğruluk oranı 2 veya 3 olduğundaki açı verisi (radyan)

Şekil 4.21: algılayıcı doğruluk oranı 2 veya 3 olduğundaki filtre uygulandıktan sonraki açı verisi (radyan)

 

Şekil 4.22: Çalışma sonucu alınan açı verisinin tümü (radyan)

Şekil 4.23: kayan ortalama filtresi uygulanan açı verisinin tümü (radyan)

Şekil 4.24: algılayıcı doğruluk oranı 2 veya 3 olduğundaki tüm açı verisi (radyan)

Şekil 4.25: algılayıcı doğruluk oranı 2 veya 3 olduğundaki filtre uygulandıktan sonraki tüm açı verisi (radyan)

 

Şekil 4.26: Açı verisi (radyan)

 

Şekil 4.27: Açı verisi (radyan) ve kayan ortalama uygulandığında açı değişimi (radyan)

Şekil 4.28: Kayan ortalama uygulandığında açı değişimi (radyan)

Bunun sonuçları ve yeniden kayan ortalama hesaplamak için http://fizyophone.com/graph adresindeki web uygulaması kullanılabilmektedir.

4.2. İkinci Çalışma

Telefon konumu düz konumdayken saniyede 30, 60, 120 derece yapacak şekilde 3 defa tekrarlı bir şekilde hızı sabit olacak bir cihaza telefon bağlandı. Ani hareketler sonucunda telefonun sabitlendiği demir çok az da olsa sabit hıza uymayacak şekilde değişim olabildiği gözlemlendi. Bir önceki çalışmaya oranla telefondan daha çok veri çeşidi alındı.

Alınan veriler:

  1. Doğruluk Bilgisi: alınan algılayıcı verisinin doğruluk bilgisi telefondan alındı.
  2. Timestamp: cihazın zaman etiketi alındı. Bunu sonradan zamana çevirme gibi bir düşünce vardı ama bu her cihaza özel olarak alındığından anlık olarak çevrilmesi gerektiği anlaşıldı.
    Bu veri kullanılarak iki ölçüm arasındaki zaman bulundu. Çok az verilerde bu zaman aralığı sıfırdan küçük çıkmıştır.
  3. Açı Bilgisi: telefondan derece hesaplanarak radyan ve derece türünden x, y ve z eksenine yapılan açı değerleri alındı.
    Bazı durumlarda getRotationMatrix yanlış hesaplamaları sonucunda yanlış açı değerleri ortaya çıkmış olabilir. Bununla ilgili veri toplanmadı ve kontrol yapılmadı.
  4. Ölçüm Sayısı: ölçüm başlangıcından bitene kadar algılayıcıdan alınan her bir kayıtın numara bilgisi alındı. Bu şekilde hangi kayıt ne için alındı onun ayırımı yapılmaktadır.
  5. Lokal Ölçüm Sayısı: her bir ölçümün başlangıcından bitimine kadar algılayıcılardan alınan veri için bir kayıt numarası alınmaktadır. Bundan her bir ölçüm sırasında kaç veri alındığı bilgisi alınmaktadır. 1 ile başlar.
  6. Lokal Açı Bilgisi: ilk açı değeri temel alınarak diğer açıları ona göre dünya koordinat sisteminden bağımsız olarak oluşan açı değişimi alındı.
  7. Açısal Hız Bilgisi: her bir ölçüm sırasındaki telefonun açısal hız bilgisi alındı.
  8. İvme Bilgisi: her bir ölçüm sırasında telefonun ivme bilgisi alındı.
  9. Zaman Farkı Bilgisi: her iki ölçüm arasında geçen zaman farkı bilgisi alındı.

Şekil 4.29: Açı verisi (radyan)

Şekil 4.30: kayan ortalama uygulandığında açı değişimi (radyan)

Şekil 4.31: açısal hız değişimi tüm veri (radyan/saniye)

Şekil 4.32: kayan ortalama uygulandığında açısal hız değişimi tüm veri (radyan/saniye)

Şekil 4.33: açısal hız değişimi algılayıcı doğruluğu 3 olan veri (radyan/saniye)

Şekil 4.34: kayan ortalama uygulandığında açısal hız değişimi algılayıcı doğruluğu 3 olan veri  (radyan/saniye)

4.3. Üçüncü Çalışma

Telefon algılayıcıları kullanılarak kaydetme sırasında ve sonrasında telefonun hareketinin animasyonu yapıldı. Saniyede her bir kayıt sırasında telefonun konumunun dünyada nasıl göründüğü gösterildi.

Alınan veriler:

  1. Doğruluk Bilgisi: alınan algılayıcı verisinin doğruluk bilgisi telefondan alındı.
  2. Timestamp: cihazın zaman etiketi alındı. Bunu sonradan zamana çevirme gibi bir düşünce vardı ama bu her cihaza özel olarak alındığından anlık olarak çevrilmesi gerektiği anlaşıldı.
    Bu veri kullanılarak iki ölçüm arasındaki zaman bulundu. Çok az verilerde bu zaman aralığı sıfırdan küçük çıkmıştır.
  3. Açı Bilgisi: telefondan derece hesaplanarak radyan ve derece türünden x, y ve z eksenine yapılan açı değerleri alındı.
    Bazı durumlarda getRotationMatrix yanlış hesaplamaları sonucunda yanlış açı değerleri ortaya çıkmış olabilir. Bununla ilgili veri toplanmadı ve kontrol yapılmadı.
  4. Ölçüm Sayısı: ölçüm başlangıcından bitene kadar algılayıcıdan alınan her bir kayıtın numara bilgisi alındı. Bu şekilde hangi kayıt ne için alındı onun ayırımı yapılmaktadır.
  5. Lokal Ölçüm Sayısı: her bir ölçümün başlangıcından bitimine kadar algılayıcılardan alınan veri için bir kayıt numarası alınmaktadır. Bundan her bir ölçüm sırasında kaç veri alındığı bilgisi alınmaktadır. 1 ile başlar.
  6. Lokal Açı Bilgisi: ilk açı değeri temel alınarak diğer açıları ona göre dünya koordinat sisteminden bağımsız olarak oluşan açı değişimi alındı.
  7. Açısal Hız Bilgisi: her bir ölçüm sırasındaki telefonun açısal hız bilgisi alındı.
  8. İvme Bilgisi: her bir ölçüm sırasında telefonun ivme bilgisi alındı.
  9. Zaman Farkı Bilgisi: her iki ölçüm arasında geçen zaman farkı bilgisi alındı.
  10. Rotasyon Matrisi: telefonun dünya koordinatına göre değişimleri kaydedilmektedir. Bunu kullanarak telefonun animasyonu yapıldı.

5. ANDROID UYGULAMA KODLARI

Telefondan algılayıcı verileri alabilmek için android uygulaması geliştirildi.

5.1 AndroidManifest Kodu

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.fizyophone.fizyophoneproject1">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ShowActivity"></activity>
        <activity android:name=".LoadAndShowActivity"></activity>
    </application>

</manifest>

Şekil 4.38: Android Manifest Kodu

 

5.2 DBHelper Kodu

package com.fizyophone.fizyophoneproject1;

/**
 * Created by murat on 25.03.2017.
 */


import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static android.R.attr.id;

public class DBHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "FizyophoneDB.db";
    public static final String TABLE_NAME = "egzercisedata";

    public static final String COLUMN_ID = "id";
    public static final String COLUMN_SENSOR_TYPE = "sensor_type";
    public static final String COLUMN_ACCURACY = "sensor_accuracy";
    public static final String COLUMN_TIMESTAMP = "sensor_timestamp";
    public static final String COLUMN_DIFFTIME = "sensor_difftime";
    public static final String COLUMN_COUNT = "sensor_count";

    public static final String COLUMN_RADIANX = "sensor_radianx";
    public static final String COLUMN_RADIANY = "sensor_radiany";
    public static final String COLUMN_RADIANZ = "sensor_radianz";

    public static final String COLUMN_DEGREEX = "sensor_degreex";
    public static final String COLUMN_DEGREEY = "sensor_degreey";
    public static final String COLUMN_DEGREEZ = "sensor_degreez";

    public static final String COLUMN_LOCAL_DEGREEX = "sensor_local_degreex";
    public static final String COLUMN_LOCAL_DEGREEY = "sensor_local_degreey";
    public static final String COLUMN_LOCAL_DEGREEZ = "sensor_local_degreez";

    public static final String COLUMN_ACCELEROMETERX = "sensor_accelerometerx";
    public static final String COLUMN_ACCELEROMETERY = "sensor_accelerometery";
    public static final String COLUMN_ACCELEROMETERZ = "sensor_accelerometerz";

    public static final String COLUMN_GYROSCOPEX = "sensor_gyroscopex";
    public static final String COLUMN_GYROSCOPEY = "sensor_gyroscopey";
    public static final String COLUMN_GYROSCOPEZ = "sensor_gyroscopez";

    public static final String COLUMN_ROTATIONMATRIX1 = "sensor_rotation_matrix1";
    public static final String COLUMN_ROTATIONMATRIX2 = "sensor_rotation_matrix2";
    public static final String COLUMN_ROTATIONMATRIX3 = "sensor_rotation_matrix3";
    public static final String COLUMN_ROTATIONMATRIX4 = "sensor_rotation_matrix4";
    public static final String COLUMN_ROTATIONMATRIX5 = "sensor_rotation_matrix5";
    public static final String COLUMN_ROTATIONMATRIX6 = "sensor_rotation_matrix6";
    public static final String COLUMN_ROTATIONMATRIX7 = "sensor_rotation_matrix7";
    public static final String COLUMN_ROTATIONMATRIX8 = "sensor_rotation_matrix8";
    public static final String COLUMN_ROTATIONMATRIX9 = "sensor_rotation_matrix9";

    private String PackageName;
    private StringRequest sq;
    private static final String SenderUrl = "http://www.fizyophone.com/send_data/index.php";

    private static String DB_PATH = "";

    private final Context mContext;
    private Cursor res;

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, 1);
        if (android.os.Build.VERSION.SDK_INT >= 17) {
            DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
        } else {
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        }
        this.mContext = context;
        PackageName = context.getPackageName();
//        context.deleteDatabase(DATABASE_NAME);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
       
db.execSQL("create table " + TABLE_NAME + " ( " + COLUMN_ID + " integer primary key,"
                + COLUMN_SENSOR_TYPE + " integer , "
                + COLUMN_ACCURACY + " integer , "
                + COLUMN_TIMESTAMP + " integer , "
                + COLUMN_DIFFTIME + " integer , "
                + COLUMN_COUNT + " integer , "
                + COLUMN_RADIANX + " real , "
                + COLUMN_RADIANY + " real , "
                + COLUMN_RADIANZ + " real , "
                + COLUMN_DEGREEX + " real , "
                + COLUMN_DEGREEY + " real , "
                + COLUMN_DEGREEZ + " real , "
                + COLUMN_LOCAL_DEGREEX + " real , "
                + COLUMN_LOCAL_DEGREEY + " real , "
                + COLUMN_LOCAL_DEGREEZ + " real , "
                + COLUMN_ACCELEROMETERX + " real , "
                + COLUMN_ACCELEROMETERY + " real , "
                + COLUMN_ACCELEROMETERZ + " real , "
                + COLUMN_GYROSCOPEX + " real , "
                + COLUMN_GYROSCOPEY + " real , "
                + COLUMN_GYROSCOPEZ + " real , "
                + COLUMN_ROTATIONMATRIX1 + " real , "
                + COLUMN_ROTATIONMATRIX2 + " real , "
                + COLUMN_ROTATIONMATRIX3 + " real , "
                + COLUMN_ROTATIONMATRIX4 + " real , "
                + COLUMN_ROTATIONMATRIX5 + " real , "
                + COLUMN_ROTATIONMATRIX6 + " real , "
                + COLUMN_ROTATIONMATRIX7 + " real , "
                + COLUMN_ROTATIONMATRIX8 + " real , "
                + COLUMN_ROTATIONMATRIX9 + " real "
                + " ) "
        );
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub
//        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    public boolean insertEgzerciseData(int type, int accuracy, Long timestamp, Long difftime, int data_count, double radian_x, double radian_y, double radian_z, double degree_x, double degree_y, double degree_z, double local_degree_x, double local_degree_y, double local_degree_z, double accelerometer_x, double accelerometer_y, double accelerometer_z, double gyroscope_x, double gyroscope_y, double gyroscope_z, double rotation_matrix1, double rotation_matrix2, double rotation_matrix3, double rotation_matrix4, double rotation_matrix5, double rotation_matrix6, double rotation_matrix7, double rotation_matrix8, double rotation_matrix9) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();

        contentValues.put(COLUMN_SENSOR_TYPE, type);
        contentValues.put(COLUMN_ACCURACY, accuracy);
        contentValues.put(COLUMN_TIMESTAMP, timestamp);
        contentValues.put(COLUMN_DIFFTIME, difftime);
        contentValues.put(COLUMN_COUNT, data_count);
        contentValues.put(COLUMN_DEGREEX, degree_x);
        contentValues.put(COLUMN_DEGREEY, degree_y);
        contentValues.put(COLUMN_DEGREEZ, degree_z);
        contentValues.put(COLUMN_RADIANX, radian_x);
        contentValues.put(COLUMN_RADIANY, radian_y);
        contentValues.put(COLUMN_RADIANZ, radian_z);
        contentValues.put(COLUMN_LOCAL_DEGREEX, local_degree_x);
        contentValues.put(COLUMN_LOCAL_DEGREEY, local_degree_y);
        contentValues.put(COLUMN_LOCAL_DEGREEZ, local_degree_z);
        contentValues.put(COLUMN_ACCELEROMETERX, accelerometer_x);
        contentValues.put(COLUMN_ACCELEROMETERY, accelerometer_y);
        contentValues.put(COLUMN_ACCELEROMETERZ, accelerometer_z);
        contentValues.put(COLUMN_GYROSCOPEX, gyroscope_x);
        contentValues.put(COLUMN_GYROSCOPEY, gyroscope_y);
        contentValues.put(COLUMN_GYROSCOPEZ, gyroscope_z);
        contentValues.put(COLUMN_ROTATIONMATRIX1, rotation_matrix1);
        contentValues.put(COLUMN_ROTATIONMATRIX2, rotation_matrix2);
        contentValues.put(COLUMN_ROTATIONMATRIX3, rotation_matrix3);
        contentValues.put(COLUMN_ROTATIONMATRIX4, rotation_matrix4);
        contentValues.put(COLUMN_ROTATIONMATRIX5, rotation_matrix5);
        contentValues.put(COLUMN_ROTATIONMATRIX6, rotation_matrix6);
        contentValues.put(COLUMN_ROTATIONMATRIX7, rotation_matrix7);
        contentValues.put(COLUMN_ROTATIONMATRIX8, rotation_matrix8);
        contentValues.put(COLUMN_ROTATIONMATRIX9, rotation_matrix9);
        db.insert(TABLE_NAME, null, contentValues);
        return true;
    }

    public Cursor getData(int id) {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME + " where id=" + id + "", null);
        return res;
    }

    public int numberOfRows() {
        SQLiteDatabase db = this.getReadableDatabase();
        int numRows = (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME);
        return numRows;
    }

    public boolean updateEgzerciseData(int type, int accuracy, Long timestamp, Long difftime, int data_count, double radian_x, double radian_y, double radian_z, double degree_x, double degree_y, double degree_z, double local_degree_x, double local_degree_y, double local_degree_z, double accelerometer_x, double accelerometer_y, double accelerometer_z, double gyroscope_x, double gyroscope_y, double gyroscope_z) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();

        contentValues.put(COLUMN_SENSOR_TYPE, type);
        contentValues.put(COLUMN_ACCURACY, accuracy);
        contentValues.put(COLUMN_TIMESTAMP, timestamp);
        contentValues.put(COLUMN_DIFFTIME, difftime);
        contentValues.put(COLUMN_COUNT, data_count);
        contentValues.put(COLUMN_DEGREEX, degree_x);
        contentValues.put(COLUMN_DEGREEY, degree_y);
        contentValues.put(COLUMN_DEGREEZ, degree_z);
        contentValues.put(COLUMN_RADIANX, radian_x);
        contentValues.put(COLUMN_RADIANY, radian_y);
        contentValues.put(COLUMN_RADIANZ, radian_z);
        contentValues.put(COLUMN_LOCAL_DEGREEX, local_degree_x);
        contentValues.put(COLUMN_LOCAL_DEGREEY, local_degree_y);
        contentValues.put(COLUMN_LOCAL_DEGREEZ, local_degree_z);
        contentValues.put(COLUMN_ACCELEROMETERX, accelerometer_x);
        contentValues.put(COLUMN_ACCELEROMETERY, accelerometer_y);
        contentValues.put(COLUMN_ACCELEROMETERZ, accelerometer_z);
        contentValues.put(COLUMN_GYROSCOPEX, gyroscope_x);
        contentValues.put(COLUMN_GYROSCOPEY, gyroscope_y);
        contentValues.put(COLUMN_GYROSCOPEZ, gyroscope_z);
        db.update(TABLE_NAME, contentValues, "id = ? ", new String[]{Integer.toString(id)});
        return true;
    }

    public Integer deleteEgzerciseData(Integer id) {
        SQLiteDatabase db = this.getWritableDatabase();
        return db.delete(TABLE_NAME,
                "id = ? ",
                new String[]{Integer.toString(id)});
    }

    public ArrayList<String> getAllEgzercises() {
        ArrayList<String> array_list = new ArrayList<String>();

        //hp = new HashMap();
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME, null);
        res.moveToFirst();

        while (res.isAfterLast() == false) {
            array_list.add(res.getString(res.getColumnIndex(COLUMN_COUNT)));
            res.moveToNext();
        }
        return array_list;
    }

    public String importDB() {
        String return_str = DATABASE_NAME;
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();
        FileChannel source = null;
        FileChannel destination = null;
        String currentDBPath = "/data/" + PackageName + "/databases/" + DATABASE_NAME;
        String backupDBPath = DATABASE_NAME;
        File backupDB = new File(data, currentDBPath);
        File currentDB = new File(sd, backupDBPath);
        try {
            source = new FileInputStream(currentDB).getChannel();
            destination = new FileOutputStream(backupDB).getChannel();
            destination.transferFrom(source, 0, source.size());
            source.close();
            destination.close();
        } catch (IOException e) {
            return_str = "Error: " + e.getMessage();
            e.printStackTrace();
        }
        return return_str;
    }

    public String exportDB() {
        String return_str = DATABASE_NAME;
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();
        FileChannel source = null;
        FileChannel destination = null;
        String currentDBPath = "/data/" + PackageName + "/databases/" + DATABASE_NAME;
        String backupDBPath = DATABASE_NAME;
        File currentDB = new File(data, currentDBPath);
        File backupDB = new File(sd, backupDBPath);
        try {
            source = new FileInputStream(currentDB).getChannel();
            destination = new FileOutputStream(backupDB).getChannel();
            destination.transferFrom(source, 0, source.size());
            source.close();
            destination.close();
        } catch (IOException e) {
            return_str = "Error: " + e.getMessage();
            e.printStackTrace();
        }
        return return_str;
    }

    private boolean exportDBServerForRow() {
        sq = new StringRequest(Request.Method.POST, SenderUrl, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        }) {
            protected Map<String, String> getParams() {
                Map<String, String> parr = new HashMap<String, String>();
                parr.put("key", "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgF");
                parr.put("id", res.getString(res.getColumnIndex(COLUMN_ID)));
                parr.put("sensor_type", res.getString(res.getColumnIndex(COLUMN_SENSOR_TYPE)));
                parr.put("accuracy", res.getString(res.getColumnIndex(COLUMN_ACCURACY)));
                parr.put("timestamp", res.getString(res.getColumnIndex(COLUMN_TIMESTAMP)));
                parr.put("difftime", res.getString(res.getColumnIndex(COLUMN_DIFFTIME)));
                parr.put("count", res.getString(res.getColumnIndex(COLUMN_COUNT)));
                parr.put("degreex", res.getString(res.getColumnIndex(COLUMN_DEGREEX)));
                parr.put("degreey", res.getString(res.getColumnIndex(COLUMN_DEGREEY)));
                parr.put("degreez", res.getString(res.getColumnIndex(COLUMN_DEGREEZ)));
                parr.put("radianx", res.getString(res.getColumnIndex(COLUMN_RADIANX)));
                parr.put("radiany", res.getString(res.getColumnIndex(COLUMN_RADIANY)));
                parr.put("radianz", res.getString(res.getColumnIndex(COLUMN_RADIANZ)));
                parr.put("degreelocalx", res.getString(res.getColumnIndex(COLUMN_LOCAL_DEGREEX)));
                parr.put("degreelocaly", res.getString(res.getColumnIndex(COLUMN_LOCAL_DEGREEY)));
                parr.put("degreelocalz", res.getString(res.getColumnIndex(COLUMN_LOCAL_DEGREEZ)));
                parr.put("accelerometerx", res.getString(res.getColumnIndex(COLUMN_ACCELEROMETERX)));
                parr.put("accelerometery", res.getString(res.getColumnIndex(COLUMN_ACCELEROMETERY)));
                parr.put("accelerometerz", res.getString(res.getColumnIndex(COLUMN_ACCELEROMETERZ)));
                parr.put("gyroscopex", res.getString(res.getColumnIndex(COLUMN_GYROSCOPEX)));
                parr.put("gyroscopey", res.getString(res.getColumnIndex(COLUMN_GYROSCOPEY)));
                parr.put("gyroscopez", res.getString(res.getColumnIndex(COLUMN_GYROSCOPEZ)));
                return parr;
            }
        };
        AppController.getInstance().addToRequestQueue(sq);
        return true;
    }

    public boolean exportDBServer() {
        SQLiteDatabase db = this.getReadableDatabase();
        res = db.rawQuery("select * from " + TABLE_NAME, null);
        res.moveToFirst();
        while (res.isAfterLast() == false) {
            exportDBServerForRow();
            res.moveToNext();
        }

        return true;
    }
}

Şekil 4.39: Android Veritabanına Kaydetme Kodu

5.3 AppController Kodu

package com.fizyophone.fizyophoneproject1;



import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;


public class AppController extends Application {

    public static final String TAG = AppController.class.getSimpleName();

    private RequestQueue mRequestQueue;

    private static AppController mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

Şekil 4.40: Android AppController Kodu

5.4 MainActivity Kodu

package com.fizyophone.fizyophoneproject1;

import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

public class MainActivity extends AppCompatActivity implements SensorEventListener {
    DBHelper FizyophoneLocalDb;
    private SensorManager mSensorManager;
    private Sensor AccelerometerSensor;
    private Sensor MagneticfieldSensor;
    private Sensor GyroscopeSensor;
    private long SensorTimestamp;
    private int SensorAccuracy;
    private int SensorType;
    private int SensorCount;
    private long SensorTimeOld;
    private boolean IsSave;
    private boolean IsNew;
    private boolean IsSaveOpened;
    private final float[] mAccelerometerReading = new float[3];
    private final float[] mMagnetometerReading = new float[3];
    private final float[] mAccelerometer = new float[3];
    private final float[] mGyroscope = new float[3];

    private final float[] mRotationMatrix = new float[9];
    private final float[] mOrientationAngles = new float[3];
    private final float[] mOrientationLocalAnglesDegree = new float[3];
    private final float[] mOrientationAnglesDegree = new float[3];
    private final float[] mOrientationAnglesDegreeFirst = new float[3];
    public static int StartId = 0;
    public static int FinishId = 200;

    /**
     * Called when the user taps the Send button
     */
   
public void showPhone(View view) {
        if (IsSaveOpened) {
            Intent intent = new Intent(this, ShowActivity.class);
            startActivity(intent);
        }else{
//            EditText editText = (EditText) findViewById(R.id.editTextFirst);
//            StartId = Integer.parseInt(editText.getText().toString());
//            editText = (EditText) findViewById(R.id.editTextLast);
//            FinishId = Integer.parseInt(editText.getText().toString());
            Intent intent = new Intent(this, LoadAndShowActivity.class);
            startActivity(intent);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
            AccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            mSensorManager.registerListener(this, AccelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
            MagneticfieldSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
            mSensorManager.registerListener(this, MagneticfieldSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null) {
            GyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
            mSensorManager.registerListener(this, GyroscopeSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        SensorTimestamp = System.currentTimeMillis();
        IsSave = false;
        IsNew = true;
        IsSaveOpened = false;
        FizyophoneLocalDb = new DBHelper(this);
    }

    public void saveChangeClick(View v) {
        IsSave = ((ToggleButton) v).isChecked();
        IsSaveOpened = IsSave;
        if (IsSave) {
            SensorCount = 0;
        } else {
            Toast.makeText(getApplicationContext(), FizyophoneLocalDb.exportDB(), Toast.LENGTH_SHORT).show();
        }
    }

//    public void sendDataServer(View v) {
//        FizyophoneLocalDb.exportDBServer();
//    }

    @Override
    protected void onResume() {//Devam edildiğinde çalışır
        super.onResume();
    }

    @Override
    protected void onPause() {//ekran kapatıldığında durması için.
        super.onPause();
//        mSensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        SensorAccuracy = event.accuracy;
        SensorTimestamp = event.timestamp;
        SensorType = event.sensor.getType();
        switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER://Active
                System.arraycopy(event.values, 0, mAccelerometerReading, 0, mAccelerometerReading.length);
                System.arraycopy(event.values, 0, mAccelerometer, 0, mAccelerometer.length);
                updateOrientationAngles();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD://Active
                System.arraycopy(event.values, 0, mMagnetometerReading, 0, mMagnetometerReading.length);
                updateOrientationAngles();
                break;
            case Sensor.TYPE_GYROSCOPE://Active
                System.arraycopy(event.values, 0, mGyroscope, 0, mGyroscope.length);
                break;
        }
    }

    public void updateOrientationAngles() {
//        if (mAccelerometerReading != null && mMagnetometerReading != null) {
        long curTime = System.currentTimeMillis();
        long diffTime = curTime - SensorTimeOld;
        SensorTimeOld = curTime;
        // Update rotation matrix, which is needed to update orientation angles.
        mSensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerometerReading, mMagnetometerReading);
        mSensorManager.getOrientation(mRotationMatrix, mOrientationAngles);
        mOrientationAnglesDegree[0] = (float) Math.toDegrees(mOrientationAngles[0]);
        mOrientationAnglesDegree[1] = (float) Math.toDegrees(mOrientationAngles[1]);
        mOrientationAnglesDegree[2] = (float) Math.toDegrees(mOrientationAngles[2]);

        if (IsNew) {
            mOrientationAnglesDegreeFirst[0] = mOrientationAnglesDegree[0];
            mOrientationAnglesDegreeFirst[1] = mOrientationAnglesDegree[1];
            mOrientationAnglesDegreeFirst[2] = mOrientationAnglesDegree[2];
        } else {
            mOrientationLocalAnglesDegree[0] -= mOrientationAnglesDegreeFirst[0];
            mOrientationLocalAnglesDegree[1] -= mOrientationAnglesDegreeFirst[1];
            mOrientationLocalAnglesDegree[2] -= mOrientationAnglesDegreeFirst[2];
            if (mOrientationLocalAnglesDegree[0] < -180) {
                mOrientationLocalAnglesDegree[0] += 360;
            } else if (mOrientationLocalAnglesDegree[0] > 180) {
                mOrientationLocalAnglesDegree[0] -= 360;
            }
            if (mOrientationLocalAnglesDegree[1] < -180) {
                mOrientationLocalAnglesDegree[1] += 360;
            } else if (mOrientationLocalAnglesDegree[1] > 180) {
                mOrientationLocalAnglesDegree[1] -= 360;
            }
            if (mOrientationLocalAnglesDegree[2] < -180) {
                mOrientationLocalAnglesDegree[2] += 360;
            } else if (mOrientationLocalAnglesDegree[2] > 180) {
                mOrientationLocalAnglesDegree[2] -= 360;
            }
        }
        if (IsSave) {//Telefona Kaydetme İşlemi Gerçekleştirilir.
            IsNew = false;
            SensorCount++;
            FizyophoneLocalDb.insertEgzerciseData(SensorType, SensorAccuracy, SensorTimestamp, diffTime, SensorCount, mOrientationAngles[1], mOrientationAngles[2], mOrientationAngles[0], mOrientationAnglesDegree[1], mOrientationAnglesDegree[2], mOrientationAnglesDegree[0], mOrientationLocalAnglesDegree[1], mOrientationLocalAnglesDegree[2], mOrientationLocalAnglesDegree[0], mAccelerometer[0], mAccelerometer[1], mAccelerometer[2], mGyroscope[0], mGyroscope[1], mGyroscope[2], mRotationMatrix[0], mRotationMatrix[1], mRotationMatrix[2], mRotationMatrix[3], mRotationMatrix[4], mRotationMatrix[5], mRotationMatrix[6], mRotationMatrix[7], mRotationMatrix[8]);
        }

        // "mRotationMatrix" now has up-to-date information.
//        values[0]: Azimuth, angle of rotation about the -z axis. This value represents the angle between the device's y axis and the magnetic north pole. When facing north, this angle is 0, when facing south, this angle is π. Likewise, when facing east, this angle is π/2, and when facing west, this angle is -π/2. The range of values is -π to π.
//        values[1]: Pitch, angle of rotation about the x axis. This value represents the angle between a plane parallel to the device's screen and a plane parallel to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the top edge of the device toward the ground creates a positive pitch angle. The range of values is -π to π.
//        values[2]: Roll, angle of rotation about the y axis. This value represents the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the left edge of the device toward the ground creates a positive roll angle. The range of values is -π/2 to π/2.
        TextView text_degree_x = (TextView) findViewById(R.id.textView_degree_x);
        TextView text_degree_y = (TextView) findViewById(R.id.textView_degree_y);
        TextView text_degree_z = (TextView) findViewById(R.id.textView_degree_z);
        TextView text_x = (TextView) findViewById(R.id.textViewx);
        TextView text_y = (TextView) findViewById(R.id.textViewy);
        TextView text_z = (TextView) findViewById(R.id.textViewz);
        TextView text_accuracy = (TextView) findViewById(R.id.textView_accuracy);

        text_degree_x.setText("X: " + mOrientationAnglesDegree[1]);
        text_degree_y.setText("Y: " + mOrientationAnglesDegree[2]);
        text_degree_z.setText("Z: " + mOrientationAnglesDegree[0]);

        text_x.setText("X: " + mOrientationAngles[1]);
        text_y.setText("Y: " + mOrientationAngles[2]);
        text_z.setText("Z: " + mOrientationAngles[0]);

        text_accuracy.setText("Type: " + SensorType + " A: " + SensorAccuracy + " t: " + diffTime + " > " + FizyophoneLocalDb.numberOfRows() + " ");

//        }
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

}

Şekil 4.41: Android MainActivity Kodu

 

5.5 activity_main Kodu

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_sensor"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true"
    tools:context="com.fizyophone.fizyophoneproject1.MainActivity">

    <ToggleButton
        android:id="@+id/toggleButton"
        android:layout_width="368dp"
        android:layout_height="75dp"
        android:onClick="saveChangeClick"
        android:text="Start Stop"
        tools:layout_editor_absoluteX="8dp"
        tools:layout_editor_absoluteY="-3dp" />

    <TextView
        android:id="@+id/textView_degree_x"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="X"
        android:textColor="@android:color/holo_green_dark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.138" />

    <TextView
        android:id="@+id/textView_degree_y"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Y"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.23000002" />

    <TextView
        android:id="@+id/textView_degree_z"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Z"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.32" />

    <TextView
        android:id="@+id/textViewx"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="X"
        android:textColor="@android:color/holo_green_dark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.43" />

    <TextView
        android:id="@+id/textViewy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Y"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.52" />

    <TextView
        android:id="@+id/textViewz"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Z"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.61" />

    <TextView
        android:id="@+id/textView_accuracy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0 : 0"
        android:textColor="@android:color/black"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.71000004" />

    <Button
        android:id="@+id/button_show"
        android:layout_width="368dp"
        android:layout_height="48dp"
        android:onClick="showPhone"
        android:text="Show Phone"
        tools:layout_editor_absoluteX="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_accuracy"
        app:layout_constraintVertical_bias="0.584"/>

</android.support.constraint.ConstraintLayout>

Şekil 4.42: Android activity_main Kodu

5.6 ShowActivity Kodu

package com.fizyophone.fizyophoneproject1;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * Wrapper activity demonstrating the use of the new
 * {@link SensorEvent#values rotation vector sensor}
 * ({@link Sensor#TYPE_ROTATION_VECTOR TYPE_ROTATION_VECTOR}).
 *
 * @see Sensor
 * @see SensorEvent
 * @see SensorManager
 */

public class ShowActivity extends AppCompatActivity  implements SensorEventListener{
    private GLSurfaceView mGLSurfaceView;
    private SensorManager mSensorManager;
    private Sensor AccelerometerSensor;
    private Sensor MagneticfieldSensor;
    private final float[] mAccelerometerReading = new float[3];
    private final float[] mMagnetometerReading = new float[3];
    private MyRenderer mRenderer;
    private boolean IsNew;
    private final float[] mRotationMatrix = new float[16];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IsNew = true;
        // Get an instance of the SensorManager
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
            AccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            mSensorManager.registerListener(this, AccelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
            MagneticfieldSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
            mSensorManager.registerListener(this, MagneticfieldSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        // Create our Preview view and set it as the content of our
        // Activity
        mRenderer = new MyRenderer();
        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setRenderer(mRenderer);
        setContentView(mGLSurfaceView);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER://Active
                System.arraycopy(event.values, 0, mAccelerometerReading, 0, mAccelerometerReading.length);
                mSensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerometerReading, mMagnetometerReading);
                break;
            case Sensor.TYPE_MAGNETIC_FIELD://Active
                System.arraycopy(event.values, 0, mMagnetometerReading, 0, mMagnetometerReading.length);
                mSensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerometerReading, mMagnetometerReading);
                break;
        }

//            mRotationMatrix[0] = 1.0f;
//            mRotationMatrix[1] = 0.0f;
//            mRotationMatrix[2] = 0.0f;
        mRotationMatrix[3] = 0.0f;// Sabit

//            mRotationMatrix[4] = 1.0f;
//            mRotationMatrix[5] = 0.0f;
//            mRotationMatrix[6] = 0.0f;
        mRotationMatrix[7] = 0.0f;// Sabit

//            mRotationMatrix[8] = 1.0f;
//            mRotationMatrix[9] = 0.0f;
//            mRotationMatrix[10] = 0.0f;
        mRotationMatrix[11] = 0.0f;// Sabit

        mRotationMatrix[12] = 0.0f;// Sabit
        mRotationMatrix[13] = 0.0f;// Sabit
        mRotationMatrix[14] = 0.0f;// Sabit
        mRotationMatrix[15] = 1.0f;// Sabit
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    protected void onResume() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
        IsNew = true;
        mRenderer.start();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
        mRenderer.stop();
        mGLSurfaceView.onPause();
    }

    class MyRenderer implements GLSurfaceView.Renderer {
        private Cube mCube;

        public MyRenderer() {
            mCube = new Cube();
            // initialize the rotation matrix to identity

//İLK BAŞLANGIÇ DEĞERLERİ

//            mRotationMatrix[0] = 1.0f;
//            mRotationMatrix[1] = 0.0f;
//            mRotationMatrix[2] = 0.0f;
//            mRotationMatrix[3] = 0.0f;// Sabit
//
//            mRotationMatrix[4] = 1.0f;
//            mRotationMatrix[5] = 0.0f;
//            mRotationMatrix[6] = 0.0f;
//            mRotationMatrix[7] = 0.0f;// Sabit
//
//            mRotationMatrix[8] = 1.0f;
//            mRotationMatrix[9] = 0.0f;
//            mRotationMatrix[10] = 0.0f;
//            mRotationMatrix[11] = 0.0f;// Sabit
//
//            mRotationMatrix[12] = 0.0f;// Sabit
//            mRotationMatrix[13] = 0.0f;// Sabit
//            mRotationMatrix[14] = 0.0f;// Sabit
//            mRotationMatrix[15] = 1.0f;// Sabit

        }

        public void start() {
            // enable our sensor when the activity is resumed, ask for
            // 10 ms updates.
        }

        public void stop() {
            // make sure to turn our sensor off when the activity is paused
        }

        public void onDrawFrame(GL10 gl) {
            // clear screen
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
            // set-up modelview matrix
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glTranslatef(0, 0, -3.0f);
            gl.glMultMatrixf(mRotationMatrix, 0);
            // draw our object
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
            mCube.draw(gl);
        }

        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // set view-port
            gl.glViewport(0, 0, width, height);
            // set projection matrix
            float ratio = (float) width / height;
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // dither is enabled by default, we don't need it
            gl.glDisable(GL10.GL_DITHER);
            // clear screen in white
            gl.glClearColor(1, 1, 1, 1);
        }

        class Cube {
            // initialize our cube
            private FloatBuffer mVertexBuffer;
            private FloatBuffer mColorBuffer;
            private ByteBuffer mIndexBuffer;

            public Cube() {
                final float vertices[] = {//Küp oluşturma köşe koordinatları (x,y, z)
                        -1.5f, -0.7f, -0.1f, 1.5f, -0.7f, -0.1f,
                        1.5f, 0.7f, -0.1f, -1.5f, 0.7f, -0.1f,
                        -1.5f, -0.7f, 0.1f, 1.5f, -0.7f, 0.1f,
                        1.5f, 0.7f, 0.1f, -1.5f, 0.7f, 0.1f,
                };
                final float colors[] = {
                        0, 0, 0, 1, 0, 0, 0, 1,//her bir köşenin rengi
                        0, 0, 0, 1, 0, 0, 0, 1,
                        0, 1, 1, 1, 0, 1, 0, 0,
                        0, 1, 0, 0, 0, 1, 1, 1,
                };
                final byte indices[] = {//Köşelerin bağlanması
                        0, 4, 5, 0, 5, 1,
                        1, 5, 6, 1, 6, 2,
                        2, 6, 7, 2, 7, 3,
                        3, 7, 4, 3, 4, 0,
                        4, 7, 6, 4, 6, 5,
                        3, 0, 1, 3, 1, 2
                };
                ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
                vbb.order(ByteOrder.nativeOrder());
                mVertexBuffer = vbb.asFloatBuffer();
                mVertexBuffer.put(vertices);
                mVertexBuffer.position(0);
                ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
                cbb.order(ByteOrder.nativeOrder());
                mColorBuffer = cbb.asFloatBuffer();
                mColorBuffer.put(colors);
                mColorBuffer.position(0);
                mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
                mIndexBuffer.put(indices);
                mIndexBuffer.position(0);
            }

            public void draw(GL10 gl) {
                gl.glEnable(GL10.GL_CULL_FACE);
                gl.glFrontFace(GL10.GL_CW);
                gl.glShadeModel(GL10.GL_SMOOTH);
                gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
                gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
                gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
            }
        }
    }
}

Şekil 4.43: Android ShowActivity Kodu

 

5.7 activity_show Kodu

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.fizyophone.fizyophoneproject1.ShowActivity">

</android.support.constraint.ConstraintLayout>

Şekil 4.44: Android activity_show Kodu

 

5.8 LoadAndShowAcitivity Kodu

package com.fizyophone.fizyophoneproject1;

import android.database.Cursor;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static java.lang.Float.parseFloat;

public class LoadAndShowActivity extends AppCompatActivity {

    DBHelper FizyophoneLocalDb;
    private GLSurfaceView mGLSurfaceView;
    private MyRenderer mRenderer;
    private final float[] mRotationMatrix = new float[16];
    private int startId = 0;
    private int finishId = 0;
    private int CountId=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FizyophoneLocalDb = new DBHelper(this);
        CountId = FizyophoneLocalDb.numberOfRows();

        startId = MainActivity.StartId;
        finishId = MainActivity.FinishId;
        if(finishId > CountId){
            finishId = CountId;
        }
        mRenderer = new MyRenderer();
        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setRenderer(mRenderer);
        setContentView(mGLSurfaceView);
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                Cursor selected_data = FizyophoneLocalDb.getData(startId);
                if (selected_data.moveToFirst()) {
                    mRotationMatrix[0] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX1)));
                    mRotationMatrix[1] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX2)));
                    mRotationMatrix[2] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX3)));

                    mRotationMatrix[4] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX4)));
                    mRotationMatrix[5] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX5)));
                    mRotationMatrix[6] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX6)));

                    mRotationMatrix[8] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX7)));
                    mRotationMatrix[9] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX8)));
                    mRotationMatrix[10] = parseFloat(selected_data.getString(selected_data.getColumnIndex(FizyophoneLocalDb.COLUMN_ROTATIONMATRIX9)));
                }

                if (startId < finishId) {
                    startId++;
                }
            }
        }, 0, 100);//put here time 1000 milliseconds=1 second
    }

    @Override
    protected void onResume() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
        mRenderer.start();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
        mRenderer.stop();
        mGLSurfaceView.onPause();
    }

    class MyRenderer implements GLSurfaceView.Renderer {
        private Cube mCube;

        public MyRenderer() {
            mCube = new Cube();
            // initialize the rotation matrix to identity

//İLK BAŞLANGIÇ DEĞERLERİ

            mRotationMatrix[0] = 1.0f;
            mRotationMatrix[1] = 0.0f;
            mRotationMatrix[2] = 0.0f;
            mRotationMatrix[3] = 0.0f;// Sabit

            mRotationMatrix[4] = 1.0f;
            mRotationMatrix[5] = 0.0f;
            mRotationMatrix[6] = 0.0f;
            mRotationMatrix[7] = 0.0f;// Sabit

            mRotationMatrix[8] = 1.0f;
            mRotationMatrix[9] = 0.0f;
            mRotationMatrix[10] = 0.0f;
            mRotationMatrix[11] = 0.0f;// Sabit

            mRotationMatrix[12] = 0.0f;// Sabit
            mRotationMatrix[13] = 0.0f;// Sabit
            mRotationMatrix[14] = 0.0f;// Sabit
            mRotationMatrix[15] = 1.0f;// Sabit

        }

        public void start() {
            // enable our sensor when the activity is resumed, ask for
            // 10 ms updates.

        }

        public void stop() {
            // make sure to turn our sensor off when the activity is paused
        }

        public void onDrawFrame(GL10 gl) {
            // clear screen
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
            // set-up modelview matrix
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glTranslatef(0, 0, -3.0f);
            gl.glMultMatrixf(mRotationMatrix, 0);
            // draw our object
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
            mCube.draw(gl);
        }

        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // set view-port
            gl.glViewport(0, 0, width, height);
            // set projection matrix
            float ratio = (float) width / height;
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // dither is enabled by default, we don't need it
            gl.glDisable(GL10.GL_DITHER);
            // clear screen in white
            gl.glClearColor(1, 1, 1, 1);
        }

        class Cube {
            // initialize our cube
            private FloatBuffer mVertexBuffer;
            private FloatBuffer mColorBuffer;
            private ByteBuffer mIndexBuffer;

            public Cube() {
                final float vertices[] = {//Küp oluşturma köşe koordinatları (x,y, z)
                        -1.5f, -0.7f, -0.1f, 1.5f, -0.7f, -0.1f,
                        1.5f, 0.7f, -0.1f, -1.5f, 0.7f, -0.1f,
                        -1.5f, -0.7f, 0.1f, 1.5f, -0.7f, 0.1f,
                        1.5f, 0.7f, 0.1f, -1.5f, 0.7f, 0.1f,
                };
                final float colors[] = {
                        0, 0, 0, 1, 0, 0, 0, 1,//her bir köşenin rengi
                        0, 0, 0, 1, 0, 0, 0, 1,
                        0, 1, 1, 1, 0, 1, 0, 0,
                        0, 1, 0, 0, 0, 1, 1, 1,
                };
                final byte indices[] = {//Köşelerin bağlanması
                        0, 4, 5, 0, 5, 1,
                        1, 5, 6, 1, 6, 2,
                        2, 6, 7, 2, 7, 3,
                        3, 7, 4, 3, 4, 0,
                        4, 7, 6, 4, 6, 5,
                        3, 0, 1, 3, 1, 2
                };
                ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
                vbb.order(ByteOrder.nativeOrder());
                mVertexBuffer = vbb.asFloatBuffer();
                mVertexBuffer.put(vertices);
                mVertexBuffer.position(0);
                ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
                cbb.order(ByteOrder.nativeOrder());
                mColorBuffer = cbb.asFloatBuffer();
                mColorBuffer.put(colors);
                mColorBuffer.position(0);
                mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
                mIndexBuffer.put(indices);
                mIndexBuffer.position(0);
            }

            public void draw(GL10 gl) {
                gl.glEnable(GL10.GL_CULL_FACE);
                gl.glFrontFace(GL10.GL_CW);
                gl.glShadeModel(GL10.GL_SMOOTH);
                gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
                gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
                gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
            }
        }
    }
}

Şekil 4.45: Android ShowAndLoadActivity Kodu

 

5.9 activity_load_and_show Kodu

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.fizyophone.fizyophoneproject1.LoadAndShowActivity">

</android.support.constraint.ConstraintLayout>

Şekil 4.46: Android activity_load_and_show Kodu

6. UYGULAMA

Herhangi bir hastanın koluna telefon takıldı. Kol hareketi kontrollü bir şekilde yapıldı. Yapılan egzersiz hareketlerinin verileri telefon algılayıcılarıyla kaydedildi.

 

Şekil 5.1: android telefon kola serbest hareket etmeyecek şekilde bağlandı.

 

 

Şekil 5.2: android uygulama çalıştırıldı.

 

Şekil 5.3: kol egzersizleri yapılırken uygulama telefon algılayıcıları kaydetmektedir.

Şekil 5.4: kol egzersizleri yapılırken uygulama telefon algılayıcıları kaydetmektedir.

 

 

 

Şekil 5.5: android uygulama ilk çalıştırma görüntüsü

 

Şekil 5.6: android uygulama algılayıcı verileri kaydedilirken görüntüsü

Şekil 5.7: android algılayıcı kaydettiği telefon hareketlerinden bir görüntü

7. SONUÇLAR

Android uygulama geliştirme becerisi elde edilmiştir. Herhangi bir uygulama geliştirebilmek için deneyim kazanılmıştır.

Telefonların fizik tedavi için kullanılması elde edilen sonuçlar doğrultusunda kolay bir iş olmadığını ve bunun için daha büyük çaba harcanması gerektiği anlaşılmıştır.

Telefondan algılayıcı verileri alındığında kullanılan sistemde ani hareketler ani çıkış veya inişler olarak grafiklere yansımıştır. Bu ani çıkış ve inişleri ortadan kaldırmak için filtre kullanılmıştır. Sonuç verisi olarak daha iyi açı verisi elde edilmiştir.

İkinci çalışmada kullanılan sistemin sabit hızlı hareket etmesinden dolayı telefon algılayıcıların da sabit bir hız vermesi beklenmiştir ama bunun karşılanmadığı grafiklerden de anlaşılmıştır. Bazı yerlerde sıfırdan farklı sonuçlar çıkmıştır.

Alınan veriler üzerinden titizlikle incelemeler yapılıp sonuçların neden kaynaklığı ve daha iyi çözüm bulabilmek için neler yapılabileceği üzerine çalışmalar yapılmıştır. Bu konu çok basit görünse de bir proje dönemine sığmayacak kadar zor olduğu anlaşılmış ve bu çalışmalar bir temel olarak ele alınmıştır.

 

Android Kodlarını İndirmek İçin Tıklayınız.

barcode
Destek İçin Buradaki Reklamları Tıklayabilirsiniz.
Destek İçin Buradaki Reklamları Tıklayabilirsiniz.

Ses Kontrolleri

Tam Ekran Yap