Hareket sensörleri

Android platformunda bir cihazın hareketini izlemenize olanak tanıyan çeşitli sensörler bulunur.

Sensörlerin olası mimarileri sensör türüne göre değişiklik gösterir:

  • Yer çekimi, doğrusal ivme, dönme vektörü, anlamlı hareket, adım sayacı ve adım algılayıcı sensörleri donanım tabanlı veya yazılım tabanlıdır.
  • İvme ölçer ve jiroskop sensörleri her zaman donanım tabanlıdır.

Android destekli cihazların çoğunda ivme ölçer ve artık birçoğunda jiroskop da bulunur. Yazılım tabanlı sensörlerin kullanılabilirliği daha değişkendir çünkü bu sensörler, verilerini elde etmek için genellikle bir veya daha fazla donanım sensörüne ihtiyaç duyar. Bu yazılım tabanlı sensörler, cihaza bağlı olarak ivme ölçer ve manyetometre ya da jiroskoptan veri alabilir.

Hareket sensörleri; yatırma, sallama, döndürme veya sallanma gibi cihaz hareketlerini izlemek için faydalıdır. Hareket genellikle doğrudan kullanıcı girdilerinin bir yansımasıdır (örneğin, oyunda arabayı yönlendiren bir kullanıcı veya oyundaki bir topu kontrol eden bir kullanıcı) ancak cihazın durduğu fiziksel ortamın da bir yansıması olabilir (örneğin, arabanızı sürerken sizinle birlikte hareket etme). İlk örnekte, cihazın referans çerçevesine veya uygulamanızın referans çerçevesine göre hareketi izlersiniz; ikinci durumda ise dünyanın referans çerçevesine göre hareketi izlersiniz. Hareket sensörleri genellikle cihaz konumunu izlemek için kullanılmaz, ancak bir cihazın dünyanın referans çerçevesine göre konumunu belirlemek için jeomanyetik alan sensörü gibi başka sensörlerle birlikte kullanılabilir (daha fazla bilgi için Konum Sensörleri bölümüne bakın).

Tüm hareket sensörleri, her bir SensorEvent için çok boyutlu sensör değeri dizileri döndürür. Örneğin, tek bir sensör etkinliği sırasında ivme ölçer üç koordinat ekseni için ivme kuvveti verilerini, jiroskop da üç koordinat ekseni için dönüş hızı verilerini döndürür. Bu veri değerleri, diğer SensorEvent parametreleriyle birlikte bir float dizisinde (values) döndürülür. Tablo 1'de, Android platformunda kullanılabilen hareket sensörleri özetlenmiştir.

Tablo 1. Android platformunda desteklenen hareket sensörleri.

Sensör Sensör etkinlik verileri Açıklama Ölçü birimleri
TYPE_ACCELEROMETER SensorEvent.values[0] X ekseni boyunca ivme kuvveti (yer çekimi dahil). m/sn.2
SensorEvent.values[1] Y ekseni boyunca ivme kuvveti (yer çekimi dahil).
SensorEvent.values[2] Z ekseni boyunca ivme kuvveti (yer çekimi dahil).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] Herhangi bir sapma telafisi olmadan X ekseni boyunca ölçülen ivme. m/sn.2
SensorEvent.values[1] Herhangi bir sapma telafisi olmadan Y ekseni boyunca ölçülen ivme.
SensorEvent.values[2] Herhangi bir sapma dengelemesi olmadan Z ekseni boyunca ölçülen ivme.
SensorEvent.values[3] Tahmini sapma telafisiyle birlikte X ekseni boyunca ölçülen ivme.
SensorEvent.values[4] Tahmini sapma telafisiyle birlikte Y ekseni boyunca ölçülen ivme.
SensorEvent.values[5] Tahmini sapma telafisiyle birlikte Z ekseni boyunca ölçülen ivme.
TYPE_GRAVITY SensorEvent.values[0] x ekseni boyunca yer çekimi kuvveti. m/sn.2
SensorEvent.values[1] Y eksenindeki yer çekimi kuvveti.
SensorEvent.values[2] Z ekseni boyunca yer çekimi kuvveti.
TYPE_GYROSCOPE SensorEvent.values[0] x ekseni etrafındaki dönüş hızı. rad/sn
SensorEvent.values[1] Y ekseni etrafındaki dönüş hızı.
SensorEvent.values[2] Z ekseni etrafındaki dönüş hızı.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] x ekseni etrafındaki dönüş hızı (kayma dengelemesi olmadan). rad/sn
SensorEvent.values[1] Y ekseni etrafındaki dönüş hızı (kayma dengelemesi olmadan).
SensorEvent.values[2] Z ekseni etrafındaki dönüş hızı (kayma dengelemesi olmadan).
SensorEvent.values[3] x ekseni çevresindeki tahmini kayma.
SensorEvent.values[4] Y ekseni etrafındaki tahmini kayma.
SensorEvent.values[5] Z ekseni etrafındaki tahmini kayma.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] X ekseni boyunca ivme kuvveti (yer çekimi hariç). m/sn.2
SensorEvent.values[1] Y ekseni boyunca ivme kuvveti (yer çekimi hariç).
SensorEvent.values[2] Z ekseni boyunca ivme kuvveti (yer çekimi hariç).
TYPE_ROTATION_VECTOR SensorEvent.values[0] x ekseni boyunca döndürme vektör bileşeni (x * sin(θ/2)). Birimsiz
SensorEvent.values[1] Y ekseni boyunca rotasyon vektör bileşeni (y * sin(θ/2)).
SensorEvent.values[2] Z ekseni boyunca rotasyon vektör bileşeni (z * sin(θ/2)).
SensorEvent.values[3] Rotasyon vektörünün skaler bileşeni ((cos(θ/2)).1
TYPE_SIGNIFICANT_MOTION Yok Yok Yok
TYPE_STEP_COUNTER SensorEvent.values[0] Sensör etkinken son yeniden başlatmadan sonra kullanıcının gerçekleştirdiği adım sayısı. Adımlar
TYPE_STEP_DETECTOR Yok Yok Yok

1 Skaler bileşen isteğe bağlı bir değerdir.

Döndürme vektör sensörü ve yer çekimi sensörü, hareket algılama ve izleme için en sık kullanılan sensörlerdir. Dönme vektör sensörü özellikle çok yönlüdür ve hareketleri algılama, açısal değişimi izleme ve göreli yön değişikliklerini izleme gibi hareketle ilgili çeşitli görevlerde kullanılabilir. Örneğin, bir oyun, artırılmış gerçeklik uygulaması, 2 boyutlu veya 3 boyutlu bir pusula ya da kamera sabitleme uygulaması geliştiriyorsanız dönme vektör sensörü idealdir. Çoğu durumda, bu sensörleri kullanmak, ivme ölçer ve jeomanyetik alan sensörü veya yön sensörü kullanmaktan daha iyi bir seçimdir.

Android Açık Kaynak Projesi sensörleri

Android Açık Kaynak Projesi (AOSP), yazılım tabanlı üç hareket sensörü sağlar: Yerçekimi sensörü, doğrusal ivme sensörü ve bir dönüş vektör sensörü. Android 4.0'da güncellenen bu sensörler artık kararlılık ve performansı artırmak için diğer sensörlerin yanı sıra cihazın jiroskopunu kullanıyor. Bu sensörleri denemek isterseniz getVendor() ve getVersion() yöntemini kullanarak bunları tanımlayabilirsiniz (tedarikçi firma Google LLC'dir; sürüm numarası 3'tür). Bu sensörlerin tedarikçi ve sürüm numarasına göre tanımlanması gerekir çünkü Android sistemi bu üç sensörü ikincil sensörler olarak kabul eder. Örneğin, bir cihaz üreticisi kendi yer çekimi sensörünü sağlarsa AOSP yer çekimi sensörü ikincil bir yer çekimi sensörü olarak görünür. Bu sensörlerin üçü de jiroskopa dayanır: Bir cihazda jiroskop yoksa bu sensörler görünmez ve kullanılamaz.

Yer çekimi sensörünü kullanma

Yer çekimi sensörü, yer çekiminin yönünü ve büyüklüğünü gösteren üç boyutlu bir vektör sağlar. Tipik olarak bu sensör, cihazın uzaydaki göreceli yönünü belirlemek için kullanılır. Aşağıdaki kod, varsayılan yerçekimi sensörünün bir örneğini nasıl alacağınızı göstermektedir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);

Birimler ivme sensörü tarafından kullanılanlarla aynıdır (m/sn2) ve koordinat sistemi, ivme sensörü tarafından kullanılan koordinat sistemiyle aynıdır.

Not: Cihaz aktif değilken yerçekimi sensörünün çıkışı ivme ölçerin çıkışıyla aynı olmalıdır.

Doğrusal ivme ölçeri kullanma

Doğrusal ivme sensörü, yer çekimini hariç tutarak her bir cihaz eksenindeki ivmeyi temsil eden üç boyutlu bir vektör sağlar. Bu değeri hareket algılamak için kullanabilirsiniz. Bu değer, ölü hesaplama kullanan bir eylemsiz gezinme sistemine de girdi olarak kullanılabilir. Aşağıdaki kod, varsayılan doğrusal ivme sensörünün bir örneğini nasıl alacağınızı göstermektedir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);

Kavramsal olarak bu sensör, aşağıdaki ilişkiye göre ivme verilerini sağlar:

linear acceleration = acceleration - acceleration due to gravity

Bu sensörü genellikle yer çekiminden etkilenmeden ivme verileri elde etmek istediğinizde kullanırsınız. Örneğin, arabanızın ne kadar hızlı gittiğini görmek için bu sensörü kullanabilirsiniz. Doğrusal ivme sensörünün her zaman bir ofseti vardır ve bunu kaldırmanız gerekir. Bunu yapmanın en basit yolu, uygulamanızda bir kalibrasyon adımı oluşturmaktır. Kalibrasyon sırasında kullanıcıdan cihazı bir masaya ayarlamasını isteyebilirsiniz ve ardından üç eksen için ofsetleri de okuyabilirsiniz. Daha sonra, gerçek doğrusal ivmeyi elde etmek için bu ofseti ivme sensörünün doğrudan okumalarından çıkarabilirsiniz.

Sensör koordinat sistemi ve ölçü birimleri (m/sn2) ivme sensörü tarafından kullanılan sistemle aynıdır.

Dönüş vektör sensörünü kullanma

Döndürme vektörü, cihazın yönünü bir açı ve eksenin kombinasyonu olarak temsil eder. Cihazda, cihaz bir eksen (x, y veya z) çevresindeki açı ile döndürülmüştür. Aşağıdaki kod, varsayılan döndürme vektör sensörünün bir örneğini nasıl alacağınızı gösterir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

Dönme vektörünün üç elemanı aşağıdaki gibi ifade edilir:

x*sin(strict/2), y*sin(θ/2), z*sin(θ/2)

Döndürme vektörünün büyüklüğünün sin(θ/2) olduğu ve döndürme vektörünün yönü, dönme ekseninin yönüne eşit olduğunda.

Şekil 1. Dönüş vektör sensörü tarafından kullanılan koordinat sistemi.

Rotasyon vektörünün üç öğesi, bir birimin son üç bileşenine eşittir (cos(IMA)/2), x*sin(θ/2), y*sin(yayını/2), z*sin(θ/2)). Döndürme vektörünün öğeleri birimsizdir. x, y ve z eksenleri, ivme sensörüyle aynı şekilde tanımlanır. Referans koordinat sistemi, doğrudan ortonormal temel olarak tanımlanır (şekil 1'e bakın). Bu koordinat sisteminin özellikleri şöyle:

  • X, Y x Z vektör çarpımı olarak tanımlanır. Cihazın mevcut konumunda zemine teğettir ve yaklaşık olarak Doğu'yu işaret eder.
  • Y, cihazın mevcut konumundaki zemine teğettir ve jeomanyetik Kuzey Kutbu'nu işaret eder.
  • Z, gökyüzünü işaret eder ve yer düzlemine diktir.

Döndürme vektör sensörünün nasıl kullanılacağını gösteren örnek bir uygulama için RotationVectorDemo.java sayfasına bakın.

Önemli hareket sensörünü kullanma

Önemli hareket sensörü, her ciddi hareket algılandığında bir etkinliği tetikler ve ardından kendini devre dışı bırakır. Önemli bir hareket, kullanıcının konumunda değişikliğe yol açabilecek bir harekettir (ör. yürümek, bisiklete binmek veya hareket eden bir arabada oturmak). Aşağıdaki kod, varsayılan anlamlı hareket sensörünün bir örneğini nasıl alacağınızı ve bir etkinlik işleyicinin nasıl kaydedileceğini gösterir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
val triggerEventListener = object : TriggerEventListener() {
    override fun onTrigger(event: TriggerEvent?) {
        // Do work
    }
}
mSensor?.also { sensor ->
    sensorManager.requestTriggerSensor(triggerEventListener, sensor)
}

Java

private SensorManager sensorManager;
private Sensor sensor;
private TriggerEventListener triggerEventListener;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

triggerEventListener = new TriggerEventListener() {
    @Override
    public void onTrigger(TriggerEvent event) {
        // Do work
    }
};

sensorManager.requestTriggerSensor(triggerEventListener, mSensor);

Daha fazla bilgi için TriggerEventListener başlıklı makaleyi inceleyin.

Adım sayacı sensörünü kullanma

Adım sayacı sensörü, sensör etkinleştirildiği sırada son yeniden başlatmadan bu yana kullanıcının attığı adım sayısını belirtir. Adım sayacında daha fazla gecikme vardır (10 saniyeye kadar) ancak adım algılayıcı sensöründen daha doğrudur.

Not: Uygulamanızın bu sensörü Android 10 (API düzeyi 29) veya sonraki sürümleri çalıştıran cihazlarda kullanabilmesi için ACTIVITY_RECOGNITION iznini beyan etmeniz gerekir.

Aşağıdaki kod, varsayılan adım sayacı sensörünün bir örneğini nasıl alacağınızı gösterir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

Uygulamanızı çalıştıran cihazlarda pil kullanımını korumak için belirli bir aralıkta adım sayacı sensöründen geçerli değeri almak üzere JobScheduler sınıfını kullanmanız gerekir. Farklı uygulama türleri farklı sensör okuma aralıkları gerektirse de uygulamanız sensörden gerçek zamanlı veriler gerektirmediği sürece bu aralığı mümkün olduğunca uzun tutmalısınız.

Adım dedektörü sensörünü kullanma

Adım dedektörü sensörü, kullanıcı her adım attığında bir etkinlik tetikler. Gecikmenin 2 saniyenin altında olması beklenmektedir.

Not: Uygulamanızın bu sensörü Android 10 (API düzeyi 29) veya sonraki sürümleri çalıştıran cihazlarda kullanabilmesi için ACTIVITY_RECOGNITION iznini beyan etmeniz gerekir.

Aşağıdaki kod, varsayılan adım algılayıcı sensörünün bir örneğini nasıl alacağınızı göstermektedir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);

Ham verilerle çalışın

Aşağıdaki sensörler, uygulamanıza cihaza uygulanan doğrusal ve dönen kuvvetler hakkında ham veriler sağlar. Bu sensörlerden gelen değerleri etkili bir şekilde kullanmak için yer çekimi gibi etkenleri çevreden filtrelemeniz gerekir. Ayrıca gürültüyü azaltmak için değer eğilimine bir yumuşatma algoritması uygulamanız gerekebilir.

İvme ölçeri kullanma

İvme sensörü, cihaza uygulanan ivmeyi (yer çekimi kuvveti dahil) ölçer. Aşağıdaki kod, varsayılan ivme sensörünün bir örneğini nasıl alacağınızı göstermektedir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

Java

private SensorManager sensorManager;
private Sensor sensor;
  ...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

Not: Uygulamanız Android 12 (API düzeyi 31) veya daha üst sürümleri hedefliyorsa bu sensör hız sınırlandırılır.

Kavramsal olarak, bir ivme sensörü, bir cihaza uygulanan ivmeyi (Ad) aşağıdaki ilişkiden kullanıp sensörün kendisine uygulanan kuvvetleri (Fs) ölçerek belirler:

A_D=-(1/kütle)∑F_S

Bununla birlikte, yer çekimi kuvveti, ölçülen ivmeyi her zaman aşağıdaki ilişkiye göre etkiler:

A_D=-g-(1/kütle)∑F_S

Bu nedenle, cihaz masada otururken (hızlanmadığında) ivme ölçer, g = 9,81 m/sn2 büyüklüğünü okur. Benzer şekilde, cihaz serbest düşüş modundaysa ve bu nedenle yere doğru 9, 81 m/sn2 hızında hızlı bir şekilde hızlanıyorsa cihazın ivme ölçeri g = 0 m/sn2 büyüklüğünü okur. Bu nedenle, cihazın gerçek ivmesini ölçmek için yer çekimi kuvvetinin katkısı ivme ölçer verilerinden kaldırılmalıdır. Bunu, yüksek geçişli filtre uygulayarak yapabilirsiniz. Öte yandan, yer çekimi kuvvetini izole etmek için düşük geçişli bir filtre kullanılabilir. Aşağıdaki örnekte bunu nasıl yapabileceğiniz gösterilmektedir:

Kotlin

override fun onSensorChanged(event: SensorEvent) {
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    val alpha: Float = 0.8f

    // Isolate the force of gravity with the low-pass filter.
    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]

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0]
    linear_acceleration[1] = event.values[1] - gravity[1]
    linear_acceleration[2] = event.values[2] - gravity[2]
}

Java

public void onSensorChanged(SensorEvent event){
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    final float alpha = 0.8;

    // Isolate the force of gravity with the low-pass filter.
    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];

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0];
    linear_acceleration[1] = event.values[1] - gravity[1];
    linear_acceleration[2] = event.values[2] - gravity[2];
}

Not: Sensör verilerini filtrelemek için birçok farklı teknik kullanabilirsiniz. Yukarıdaki kod örneğinde, düşük geçiş filtresi oluşturmak için basit bir filtre sabiti (alfa) kullanılır. Bu filtre sabiti, filtrenin sensör olaylarına eklediği gecikmenin ve sensörün etkinlik iletim hızının (dt) kabaca gösterimi olan zaman sabitinden (t) türetilir. Kod örneğinde, gösterim amacıyla 0,8 alfa değeri kullanılmaktadır. Bu filtreleme yöntemini kullanırsanız farklı bir alfa değeri seçmeniz gerekebilir.

İvme ölçerler standart sensör koordinat sistemini kullanır. Pratikte bu, cihaz doğal yönünde bir masa üzerinde düz bir şekilde dururken aşağıdaki koşulların geçerli olduğu anlamına gelir:

  • Cihazı sol tarafa iterseniz (böylece sağa doğru) x hızlanma değeri pozitif olur.
  • Cihazı en alta iterseniz (yani sizden uzaklaşırsa) y hızlanma değeri pozitif olur.
  • Cihazı A m/s2 ivmesiyle gökyüzüne doğru iterseniz z ivme değeri A + 9,81'e eşit olur. Bu değer, cihazın ivmesinden (+A m/sn2) yer çekimi kuvvetinden (-9,81 m/sn2) elde edilen değere eşittir.
  • Sabit cihazın +9,81 ivme değeri olur. Bu değer, cihazın ivmesine karşılık gelir (0 m/sn2 eksi yer çekimi kuvveti, yani -9,81 m/sn2).

Genel olarak, cihaz hareketini izliyorsanız ivme ölçer, kullanmak için iyi bir sensördür. Android destekli hemen hemen her telefonun ve tabletin ivme ölçeri vardır ve diğer hareket sensörlerinden yaklaşık 10 kat daha az güç tüketir. Dezavantajlarından biri, yerçekimi kuvvetlerini ortadan kaldırmak ve gürültüyü azaltmak için alçak ve yüksek geçişli filtreler uygulamak zorunda kalabilmenizdir.

Jiroskopu kullanın

Jiroskop, cihazın x, y ve z ekseni etrafında rad/sn cinsinden dönüş hızını ölçer. Aşağıdaki kod, varsayılan jiroskop örneğinin nasıl alınacağını gösterir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

Not: Uygulamanız Android 12 (API düzeyi 31) veya daha üst sürümleri hedefliyorsa bu sensör hız sınırlandırılır.

Sensörün koordinat sistemi, ivme sensörü için kullanılan sistemle aynıdır. Döndürme, saat yönünün tersine doğru pozitiftir. Yani, kaynak üzerinde konumlandırılmış bir cihazın x, y veya z eksenindeki pozitif bir konumdan bakan bir gözlemci, cihaz saat yönünün tersine dönüyormuş gibi görünürse pozitif bir dönüş rapor eder. Bu, pozitif dönüşün standart matematiksel tanımıdır ve yön sensörü tarafından kullanılan videonun tanımıyla aynı değildir.

Genellikle, zaman adımında açılardaki değişimi açıklayan bir dönüşü hesaplamak için, jiroskopun çıktısı zaman içinde entegre edilir. Örneğin:

Kotlin

// Create a constant to convert nanoseconds to seconds.
private val NS2S = 1.0f / 1000000000.0f
private val deltaRotationVector = FloatArray(4) { 0f }
private var timestamp: Float = 0f

override fun onSensorChanged(event: SensorEvent?) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0f && event != null) {
        val dT = (event.timestamp - timestamp) * NS2S
        // Axis of the rotation sample, not normalized yet.
        var axisX: Float = event.values[0]
        var axisY: Float = event.values[1]
        var axisZ: Float = event.values[2]

        // Calculate the angular speed of the sample
        val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)

        // Normalize the rotation vector if it's big enough to get the axis
        // (that is, EPSILON should represent your maximum allowable margin of error)
        if (omegaMagnitude > EPSILON) {
            axisX /= omegaMagnitude
            axisY /= omegaMagnitude
            axisZ /= omegaMagnitude
        }

        // Integrate around this axis with the angular speed by the timestep
        // in order to get a delta rotation from this sample over the timestep
        // We will convert this axis-angle representation of the delta rotation
        // into a quaternion before turning it into the rotation matrix.
        val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
        val sinThetaOverTwo: Float = sin(thetaOverTwo)
        val cosThetaOverTwo: Float = cos(thetaOverTwo)
        deltaRotationVector[0] = sinThetaOverTwo * axisX
        deltaRotationVector[1] = sinThetaOverTwo * axisY
        deltaRotationVector[2] = sinThetaOverTwo * axisZ
        deltaRotationVector[3] = cosThetaOverTwo
    }
    timestamp = event?.timestamp?.toFloat() ?: 0f
    val deltaRotationMatrix = FloatArray(9) { 0f }
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

Java

// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;

public void onSensorChanged(SensorEvent event) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0) {
      final float dT = (event.timestamp - timestamp) * NS2S;
      // Axis of the rotation sample, not normalized yet.
      float axisX = event.values[0];
      float axisY = event.values[1];
      float axisZ = event.values[2];

      // Calculate the angular speed of the sample
      float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

      // Normalize the rotation vector if it's big enough to get the axis
      // (that is, EPSILON should represent your maximum allowable margin of error)
      if (omegaMagnitude > EPSILON) {
        axisX /= omegaMagnitude;
        axisY /= omegaMagnitude;
        axisZ /= omegaMagnitude;
      }

      // Integrate around this axis with the angular speed by the timestep
      // in order to get a delta rotation from this sample over the timestep
      // We will convert this axis-angle representation of the delta rotation
      // into a quaternion before turning it into the rotation matrix.
      float thetaOverTwo = omegaMagnitude * dT / 2.0f;
      float sinThetaOverTwo = sin(thetaOverTwo);
      float cosThetaOverTwo = cos(thetaOverTwo);
      deltaRotationVector[0] = sinThetaOverTwo * axisX;
      deltaRotationVector[1] = sinThetaOverTwo * axisY;
      deltaRotationVector[2] = sinThetaOverTwo * axisZ;
      deltaRotationVector[3] = cosThetaOverTwo;
    }
    timestamp = event.timestamp;
    float[] deltaRotationMatrix = new float[9];
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

Standart jiroskoplar, gürültü ve kayma (önyargı) için herhangi bir filtreleme veya düzeltme olmadan ham dönme verileri sağlar. Pratikte, jiroskop gürültüsü ve kaymaları telafi edilmesi gereken hatalara neden olur. Kaymayı (yanlama) ve gürültüyü genellikle yer çekimi sensörü veya ivme ölçer gibi diğer sensörleri izleyerek belirlersiniz.

Kalibre edilmemiş jiroskopu kullanın

Kalibre edilmemiş jiroskop, dönüş hızına herhangi bir jiroskop telafisi uygulanmaması haricinde, jiroskop'a benzer. Fabrika kalibrasyonu ve sıcaklık dengelemesi, dönüş hızına yine de uygulanır. Kalibre edilmemiş jiroskop, yön verilerinin işlenmesi ve erime sonrası verileri için kullanışlıdır. Genel olarak gyroscope_event.values[0], uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3] değerine yakındır. Yani,

calibrated_x ~= uncalibrated_x - bias_estimate_x

Not: Kalibre edilmemiş sensörler daha ham sonuçlar sağlar ve bazı sapmalar içerebilir ancak bu sensörlerin ölçümleri kalibrasyon yoluyla uygulanan düzeltmelerden daha az atlama içerir. Bazı uygulamalar bu kalibre edilmemiş sonuçların daha düzgün ve güvenilir olmasını tercih edebilir. Örneğin, bir uygulama kendi sensör füzyonunu yürütmeye çalışıyorsa kalibrasyon eklemek aslında sonuçları bozabilir.

Kalibre edilmemiş jiroskop, dönüş hızlarına ek olarak her eksen etrafında tahmini kaymayı da gösterir. Aşağıdaki kod, varsayılan kalibre edilmemiş jiroskopun bir örneğini nasıl alacağınızı göstermektedir:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);

Ek kod örnekleri

BatchStepSensor örneği, bu sayfadaki API'lerin kullanımını daha ayrıntılı bir şekilde göstermektedir.

Ayrıca şunu da okumalısınız: