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
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.
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.
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;
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
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.
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.
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.
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 |
Başarılı ise true, başarısız ise false değerini döndürür. |
Şekil 3.5: getRotationMatrix parametre ve döndürülen değer
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 |
|
|
Sırasıyla Azimuth, Pitch, Roll 3 boyutlu matris olarak radyan cinsinden sonuç verir. |
|
|
Şekil 3.7 getOrientation parametre ve döndürülen
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 |
|
|
|
|
|
|
|
|
|
|
Veya inR ve outR'nin uzunluğu aynı değilse. |
Şekil 3.8 remapCoordinateSystem parametre ve döndürülen
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
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ı.
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:
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.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.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.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.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.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.
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:
Ş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)
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:
Telefondan algılayıcı verileri alabilmek için android uygulaması geliştirildi.
<?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
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
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
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
<?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
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
<?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
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
<?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
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ü
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.