مستشعرات الحركة

يوفر نظام Android الأساسي العديد من المستشعرات التي تتيح لك مراقبة حركة الجهاز.

تختلف الهياكل المحتملة لأجهزة الاستشعار حسب نوع أداة الاستشعار:

  • تعتمد كل من الجاذبية والتسارع الخطي ومتجه الدوران والحركة المهمة وعدّاد الخطوات وأدوات الاستشعار في رصد الخطوات على الأجهزة أو البرامج.
  • تعتمد أجهزة استشعار التسارع والجيروسكوب دائمًا على الأجهزة.

تحتوي معظم الأجهزة التي تعمل بنظام التشغيل Android على مقياس تسارع، ويشمل العديد منها الآن الجيروسكوب. يعتبر مدى توفر أدوات الاستشعار المستندة إلى البرامج أكثر متغيرًا لأنها غالبًا ما تعتمد على جهاز استشعار واحد أو أكثر من أجهزة الاستشعار لاستخلاص البيانات. اعتمادًا على الجهاز، يمكن لأدوات الاستشعار المستندة إلى البرامج هذه الحصول على بياناتها إما من مقياس التسارع ومقياس المغناطيسية أو من الجيروسكوب.

تعد مستشعرات الحركة مفيدة لمراقبة حركة الجهاز مثل الإمالة أو الاهتزاز أو الدوران أو التأرجح. وعادة ما تكون الحركة انعكاسًا لإدخال المستخدم المباشر (على سبيل المثال، يقود مستخدم سيارة في لعبة أو مستخدم يتحكّم في كرة في لعبة)، ولكنها يمكن أن تكون أيضًا انعكاسًا للبيئة المادية التي يجلس فيها الجهاز (على سبيل المثال، التحرّك معك أثناء قيادة سيارتك). في الحالة الأولى، أنت تراقب الحركة بالنسبة إلى الإطار المرجعي للجهاز أو الإطار المرجعي لتطبيقك وفي الحالة الثانية، يعني ذلك أنّك تراقب الحركة بالنسبة إلى الإطار المرجعي في العالم. ولا تُستخدَم أجهزة استشعار الحركة في حد ذاتها لرصد موضع الجهاز، لكن يمكن استخدامها مع أدوات استشعار أخرى، مثل مستشعر المجال المغناطيسي الجغرافي، لتحديد موضع الجهاز بالنسبة إلى الإطار المرجعي للعالم (راجِع أجهزة استشعار الموضع لمزيد من المعلومات).

تعرض جميع أجهزة استشعار الحركة صفائف متعددة الأبعاد لقيم أداة الاستشعار لكل SensorEvent. على سبيل المثال، خلال حدث مستشعر واحد، يعرض مقياس التسارع بيانات قوة التسارع لمحور الإحداثيات الثلاثة، ويعرض الجيروسكوب بيانات معدل الدوران لمحور الإحداثيات الثلاثة. يتم عرض قيم البيانات هذه في مصفوفة float (values) مع معلَمات SensorEvent أخرى. يلخص الجدول 1 أجهزة استشعار الحركة المتوفرة على نظام Android الأساسي.

الجدول 1. أجهزة استشعار الحركة المتوافقة مع نظام Android الأساسي.

أداة استشعار بيانات أحداث أدوات الاستشعار الوصف وحدات القياس
TYPE_ACCELEROMETER SensorEvent.values[0] قوة التسارع على طول المحور س (بما في ذلك الجاذبية). م/ث2
SensorEvent.values[1] قوة التسارع على طول المحور ص (بما في ذلك الجاذبية).
SensorEvent.values[2] قوة التسارع على طول المحور z (بما في ذلك الجاذبية).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] تم قياس التسارع على طول المحور "س" بدون أي تعويض عن التحيز. م/ث2
SensorEvent.values[1] تم قياس التسارع على طول المحور Y بدون أي تعويض للتحيز.
SensorEvent.values[2] تم قياس التسارع على طول المحور Z دون أي تعويض عن التحيز.
SensorEvent.values[3] تم قياس التسارع على طول المحور "س" مع تعويض التحيز التقديري.
SensorEvent.values[4] تم قياس التسارع على طول المحور Y مع تعويض التحيز التقديري.
SensorEvent.values[5] تم قياس التسارع على طول المحور Z مع تعويض التحيز التقديري.
TYPE_GRAVITY SensorEvent.values[0] قوة الجاذبية على طول المحور "س". م/ث2
SensorEvent.values[1] قوة الجاذبية على طول المحور ص.
SensorEvent.values[2] قوة الجاذبية على طول المحور z.
TYPE_GYROSCOPE SensorEvent.values[0] معدل الدوران حول المحور x. راد/ثانية
SensorEvent.values[1] معدل الدوران حول المحور ص.
SensorEvent.values[2] معدل الدوران حول المحور z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] معدّل الدوران (بدون تعويض الانجراف) حول المحور x. راد/ثانية
SensorEvent.values[1] معدل الدوران (بدون تعويض الانجراف) حول المحور ص.
SensorEvent.values[2] معدّل الدوران (بدون تعويض الانجراف) حول المحور z.
SensorEvent.values[3] الانحراف المقدر حول المحور س.
SensorEvent.values[4] الانحراف المقدر حول المحور ص.
SensorEvent.values[5] الانحراف المقدر حول المحور z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] قوة التسارع على طول المحور س (باستثناء الجاذبية). م/ث2
SensorEvent.values[1] قوة التسارع على طول المحور ص (باستثناء الجاذبية).
SensorEvent.values[2] قوة التسارع على طول المحور z (باستثناء الجاذبية).
TYPE_ROTATION_VECTOR SensorEvent.values[0] مكوّن متّجه التدوير على طول المحور x (x * sin(التحديد/2)) بلا وحدة
SensorEvent.values[1] مكوّن متجه التدوير على طول المحور y (y * sin(التحديد/2))
SensorEvent.values[2] مكوّن متجه التدوير على طول المحور z (z * sin(عقد/2))
SensorEvent.values[3] المكوّن التربيعي لمتّجه الدوران ((cos(عقد/2)).1
TYPE_SIGNIFICANT_MOTION لا ينطبق (لا ينطبق) لا ينطبق
TYPE_STEP_COUNTER SensorEvent.values[0] عدد الخطوات التي اتخذها المستخدم منذ آخر عملية إعادة تشغيل أثناء تفعيل جهاز الاستشعار. الخطوات
TYPE_STEP_DETECTOR لا ينطبق (لا ينطبق) لا ينطبق

1 المكوِّن العددي هو قيمة اختيارية.

يعد كل من مستشعر متجه الدوران ومستشعر الجاذبية هما أكثر أدوات الاستشعار شيوعًا في اكتشاف الحركة ومراقبتها. يعد مستشعر متجه الدوران متنوعًا بشكل خاص ويمكن استخدامه لمجموعة واسعة من المهام المتعلقة بالحركة، مثل اكتشاف الإيماءات ومراقبة التغير الزاوي ومراقبة تغييرات الاتجاه النسبي. على سبيل المثال، يُعدّ مستشعر المتّجهات الدورانية خيارًا مثاليًا عند تطوير لعبة أو تطبيق واقع معزّز أو تطبيق بوصلة ثنائية الأبعاد أو ثلاثية الأبعاد أو تطبيق لتثبيت الكاميرا. وفي معظم الحالات، يكون استخدام أدوات الاستشعار هذه خيارًا أفضل من استخدام مقياس التسارع ومستشعر المجال المغناطيسي أو مستشعر الاتجاه.

أدوات استشعار المشروع المفتوح المصدر لنظام Android

يوفِّر المشروع المفتوح المصدر لنظام التشغيل Android (AOSP) ثلاثة أدوات استشعار للحركة قائمة على البرامج: مستشعر الجاذبية، ومستشعر تسارع خطّي، ومستشعر متجه للدوران. تم تحديث أدوات الاستشعار هذه في الإصدار Android 4.0 وتستخدم الآن الجيروسكوب في الجهاز (بالإضافة إلى أدوات الاستشعار الأخرى) لتحسين الثبات والأداء. إذا أردت تجربة أدوات الاستشعار هذه، يمكنك التعرّف عليها باستخدام طريقة getVendor() وطريقة getVersion() (المورّد هو Google LLC، ورقم الإصدار هو 3). من الضروري تحديد أدوات الاستشعار هذه حسب المورد ورقم الإصدار لأن نظام Android يعتبر أدوات الاستشعار الثلاثة هذه أدوات استشعار ثانوية. على سبيل المثال، إذا قدمت الشركة المصنعة للجهاز أداة استشعار الجاذبية الخاصة بها، فإن جهاز استشعار الجاذبية AOSP سيظهر كجهاز استشعار ثانوي للجاذبية. تعتمد كل من أدوات الاستشعار الثلاثة هذه على الجيروسكوب: إذا لم يكن الجهاز يحتوي على جيروسكوب، لن تظهر هذه المستشعرات ولن تكون متاحة للاستخدام.

استخدام أداة استشعار الجاذبية

يوفر جهاز استشعار الجاذبية متجهًا ثلاثي الأبعاد يشير إلى اتجاه وحجم الجاذبية. عادةً ما يتم استخدام هذا المستشعر لتحديد الاتجاه النسبي للجهاز في الفراغ. توضح لك التعليمة البرمجية التالية كيفية الحصول على مثيل لجهاز استشعار الجاذبية الافتراضي:

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);

الوحدات هي نفسها تلك التي يستخدمها مستشعر التسارع (م/ث2)، ونظام الإحداثيات هو نفسه الذي يستخدمه مستشعر التسارع.

ملاحظة: عندما يكون هناك جهاز في وضع عدم النشاط، يجب أن يكون ناتج أداة استشعار الجاذبية متطابقًا مع ناتج مقياس التسارع.

استخدام مقياس التسارع الخطي

يوفر لك مستشعر التسارع الخطي متجهًا ثلاثي الأبعاد يمثل التسارع على طول كل محور في الجهاز، مع استبعاد الجاذبية. يمكنك استخدام هذه القيمة لرصد الإيماءات يمكن أن تكون القيمة أيضًا بمثابة مدخل لنظام التنقل الشامل، الذي يستخدم الحساب المفقود. يوضح الرمز التالي كيفية الحصول على مثيل لمستشعر التسارع الخطي الافتراضي:

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);

من الناحية النظرية، يزودك هذا المستشعر ببيانات التسارع وفقًا للعلاقة التالية:

linear acceleration = acceleration - acceleration due to gravity

وأنت تستخدم عادةً هذا المستشعر عندما تريد الحصول على بيانات التسارع بدون تأثير الجاذبية. على سبيل المثال، يمكنك استخدام أداة الاستشعار هذه لمعرفة مدى سرعة سير سيارتك. هناك دائمًا إزاحة لأداة استشعار التسارع الخطي، وعليك إزالتها. أبسط طريقة للقيام بذلك هي إنشاء خطوة للمعايرة في تطبيقك. أثناء المعايرة، يمكنك أن تطلب من المستخدم وضع الجهاز على طاولة، ثم قراءة الإزاحة لجميع المحاور الثلاثة. يمكنك بعد ذلك طرح تلك الإزاحة من القراءات المباشرة لمستشعر التسارع للحصول على التسارع الخطي الفعلي.

نظام إحداثيات أداة الاستشعار هو نفسه النظام الذي يستخدمه مستشعر التسارع، وكذلك وحدات القياس (م/ث2).

استخدام مستشعر الدوران المتجه

ويمثل متجه الدوران اتجاه الجهاز كمزيج من الزاوية والمحور، حيث استدار الجهاز من خلال زاوية ≤ حول أحد المحورين (س أو ص أو ع). يوضح لك الكود التالي كيفية الحصول على مثيل للمستشعر الافتراضي لمتجه الدوران:

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);

يتم التعبير عن العناصر الثلاثة لمتجه الدوران على النحو التالي:

x*sin(استكشاف/2), y*sin(عقد/2), z*sin(عقد/2)

عندما يكون حجم متجه الدوران يساوي sin(≤/2)، واتجاه متجه الدوران يساوي اتجاه محور الدوران.

الشكل 1. نظام الإحداثيات الذي يستخدمه مستشعر الدوران.

تساوي العناصر الثلاثة لمتجه الدوران المكونات الثلاثة الأخيرة من الوحدة الربعية (cos(عقد/2), x*sin(عقد/2), y*sin(أدخل/2), z*sin(عقد/2)). عناصر متجه الدوران غير موحدة. يتم تحديد المحاور x وy وz بنفس طريقة جهاز استشعار التسارع. يُعرَّف نظام إحداثيات المرجع بأنه أساس عادي مباشر (انظر الشكل 1). وتتميّز نظام الإحداثيات هذا بالخصائص التالية:

  • يتم تعريف س على أنه ناتج الضرب ص × ع. إنهاماسية للأرض في الموقع الحالي للجهاز وتشير إلى الشرق تقريبًا.
  • تمثّل حرف Y المماسية للأرض في الموقع الحالي للجهاز ويشير إلى القطب الشمالي المغناطيسي الجغرافي.
  • يشير حرف Z نحو السماء وعمودي بشكل عمودي على مستوى الأرض.

للحصول على نموذج تطبيق يوضّح كيفية استخدام مستشعر متجه الدوران، يمكنك الاطّلاع على RotationVectorDemo.java.

استخدام أداة استشعار الحركة المهمة

يعمل جهاز استشعار الحركة المهم على تشغيل حدث ما في كل مرة يتم فيها رصد حركة مهمة ثم يوقف الجهاز نفسه. الحركة المهمة هي حركة قد تؤدي إلى تغيير في الموقع الجغرافي للمستخدم، على سبيل المثال المشي أو ركوب الدرّاجة أو الجلوس في سيارة متحركة. يوضح لك الرمز البرمجي التالي كيفية الحصول على مثيل لأداة استشعار الحركة المهمة التلقائية وكيفية تسجيل مستمع للحدث:

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);

لمزيد من المعلومات، يُرجى الاطّلاع على "TriggerEventListener".

استخدام أداة استشعار عدّاد الخطوات

يوفر أداة استشعار عدّاد الخطوات عدد الخطوات التي اتخذها المستخدم منذ آخر عملية إعادة تشغيل أثناء تفعيل المستشعر. يتميّز عدّاد الخطوات بوقت استجابة أطول (يصل إلى 10 ثوانٍ) ولكنّه أكثر دقة من أداة استشعار أداة رصد الخطوات.

ملاحظة: يجب الإفصاح عن إذن ACTIVITY_RECOGNITION لكي يستخدم تطبيقك أداة الاستشعار هذه على الأجهزة التي تعمل بنظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.

توضح لك التعليمة البرمجية التالية كيفية الحصول على مثيل لأداة الاستشعار التلقائية لعداد الخطوات:

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);

للحفاظ على مستوى شحن البطارية في الأجهزة التي يعمل عليها تطبيقك، يجب استخدام الفئة JobScheduler لاسترداد القيمة الحالية من أداة استشعار عدّاد الخطوات على فترات زمنية محدّدة. على الرغم من أنّ الأنواع المختلفة من التطبيقات تتطلب فواصل زمنية مختلفة لقراءة أداة الاستشعار، عليك جعل هذه الفاصل الزمني أطول قدر ممكن ما لم يتطلّب تطبيقك بيانات في الوقت الفعلي من أداة الاستشعار.

استخدام أداة استشعار رصد الخطوات

تشغِّل أداة استشعار أداة رصد الخطوات حدثًا في كل مرة يتّخذ فيها المستخدم خطوة. من المتوقع أن يكون وقت الاستجابة أقل من ثانيتين.

ملاحظة: يجب الإفصاح عن إذن ACTIVITY_RECOGNITION لكي يستخدم تطبيقك أداة الاستشعار هذه على الأجهزة التي تعمل بنظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.

يوضح الرمز التالي كيفية الحصول على مثيل لأداة الاستشعار التلقائية لرصد الخطوات:

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);

استخدام البيانات الأولية

تزود أدوات الاستشعار التالية تطبيقك ببيانات أولية حول القوى الخطية والتدويرية التي يتم تطبيقها على الجهاز. من أجل استخدام القيم من هذه المستشعرات بشكل فعال، تحتاج إلى تصفية العوامل من البيئة، مثل الجاذبية. قد تحتاج أيضًا إلى تطبيق خوارزمية تجانس على اتجاه القيم لتقليل التشويش.

استخدام مقياس التسارع

يقيس جهاز استشعار التسارع التسارع المطبق على الجهاز، بما في ذلك قوة الجاذبية. يوضح لك الرمز التالي كيفية الحصول على مثيل لمستشعر التسارع التلقائي:

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);

ملاحظة: إذا كان تطبيقك يستهدف نظام Android 12 (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، تكون أداة الاستشعار هذه محدودة المعدّل.

من الناحية النظرية، يحدّد جهاز استشعار التسارع التسارع المطبّق على أحد الأجهزة (Ad) من خلال قياس القوى المطبّقة على أداة الاستشعار نفسها (Fs) باستخدام العلاقة التالية:

A_D=-(1/كتلة)∑F_S

ومع ذلك، تؤثر قوة الجاذبية دائمًا في التسارع الذي تم قياسه وفقًا للعلاقة التالية:

A_D=-g-(1/الكتلة)∑F_S

لهذا السبب، عندما يكون الجهاز موضوعًا على طاولة (وليس بشكل يتسارع)، يقرأ مقياس التسارع المقدار g = 9.81 م/ثانية2. وبالمثل، عندما يكون الجهاز في حالة سقوط حر، وبالتالي فإنّه يسرّع بسرعة نحو الأرض عند 9.81 متر/ثانية2، يقرأ مقياس التسارع المقدار g = 0 m/s2. ولذلك، لقياس التسارع الحقيقي للجهاز، يجب إزالة مساهمة قوة الجاذبية من بيانات مقياس التسارع. ويمكن تحقيق ذلك من خلال تطبيق فلتر عالي الجودة. وعلى العكس من ذلك، يمكن استخدام فلتر التمرير المنخفض لعزل قوة الجاذبية. يوضح المثال التالي كيف يمكنك القيام بذلك:

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];
}

ملاحظة: يمكنك استخدام العديد من الأساليب المختلفة لفلترة بيانات أداة الاستشعار. يستخدم نموذج التعليمة البرمجية أعلاه ثابت تصفية بسيطًا (ألفا) لإنشاء عامل تصفية تمرير منخفض. يُستمَد هذا الفلتر الثابت من ثابت زمني (t)، وهو تمثيل تقريبي لوقت الاستجابة الذي يضيفه الفلتر إلى أحداث المستشعر، ومعدّل تسليم الأحداث في أداة الاستشعار (dt). يستخدم نموذج التعليمات البرمجية قيمة ألفا 0.8 لأغراض العرض التوضيحي. إذا كنت تستخدم طريقة التصفية هذه، فقد تحتاج إلى اختيار قيمة ألفا مختلفة.

تستخدم مقاييس التسارع نظام الإحداثيات القياسي للمستشعر. عمليًا، يعني هذا أن الشروط التالية تنطبق عند وضع الجهاز بشكل مسطح على طاولة في اتجاهه الطبيعي:

  • إذا دفعت الجهاز على الجانب الأيسر (بحيث يتحرك إلى اليمين)، تكون قيمة التسارع x موجبة.
  • إذا دفعت الجهاز إلى الأسفل (بحيث يبتعد عنك)، تكون قيمة التسارُع ص موجبة.
  • إذا دفعت الجهاز نحو السماء بتسريع A م/ث2، فإن قيمة التسارع z تساوي A + 9.81، وهو ما يتوافق مع تسارع الجهاز (+ أم/ث2) مطروحًا منه قوة الجاذبية (-9.81 م/ث2).
  • ستكون قيمة التسارع في الجهاز الثابت +9.81، وهي ما تتوافق مع تسارع الجهاز (0 م/ث2 مطروحًا منه قوة الجاذبية، وهي -9.81 م/ث2).

بشكل عام، يعد مقياس التسارع أداة استشعار جيدة يمكن استخدامها إذا كنت مراقبتك لحركة الجهاز. يحتوي كل هاتف أو جهاز لوحي يعمل بنظام التشغيل Android تقريبًا على مقياس تسارع، ويستخدِم طاقة أقل بمقدار 10 مرات تقريبًا من أجهزة استشعار الحركة الأخرى. من عيوبك أنه قد تضطر إلى تنفيذ عوامل تصفية التمرير المنخفض والممر العالي للتخلص من قوى الجاذبية وتقليل الضوضاء.

استخدام الجيروسكوب

يقيس الجيروسكوب معدل الدوران بالرادار/ثانية حول المحور س وص وع، في الجهاز. يوضح لك الرمز التالي كيفية الحصول على مثيل للجيروسكوب التلقائي:

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);

ملاحظة: إذا كان تطبيقك يستهدف نظام Android 12 (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، تكون أداة الاستشعار هذه محدودة المعدّل.

نظام الإحداثيات لجهاز الاستشعار هو نفسه نظام استشعار التسارع. الدوران إيجابي في عكس اتجاه عقارب الساعة، أي أن المراقب الذي ينظر من موقع إيجابي على المحور س أو ص أو ع في جهاز موجود على المصدر سيبلغ عن الدوران الإيجابي إذا بدا أن الجهاز يدور عكس عقارب الساعة. هذا هو التعريف الرياضي القياسي للدوران الإيجابي وليس مطابقًا لتعريف اللفة الذي تستخدمه أداة استشعار الاتجاه.

عادةً ما يتمّ دمج ناتج الجيروسكوب بمرور الوقت لحساب دوران يصف التغيّر في الزوايا على مدار الوقت. مثلاً:

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;
}

توفر الجيروسكوب القياسي بيانات دورانية أولية بدون أي تصفية أو تصحيح للضوضاء والانحراف (التحيز). من الناحية العملية، سيؤدي ضوضاء الجيروسكوب والانحراف إلى حدوث أخطاء يجب تعويضها. عادة ما تحدد الانجراف (التحيز) والضوضاء من خلال مراقبة أدوات الاستشعار الأخرى، مثل أداة استشعار الجاذبية أو مقياس التسارع.

استخدام الجيروسكوب الذي لم تتم معايرته

ويكون الجيروسكوب الذي لم تتم معايرته مشابهًا للجيروسكوب، إلا أنه لا يتم تطبيق تعويض الانحراف عن دوران الجيروسكوب على معدل الدوران. معايرة المصنع وتعويض درجة الحرارة لا تزال تنطبق على معدل الدوران. ويكون الجيروسكوب الذي لم تتم معايرته مفيدًا لبيانات ما بعد المعالجة ودمج الاتجاه. وبشكل عام، سيكون gyroscope_event.values[0] قريبًا من uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]. أي

calibrated_x ~= uncalibrated_x - bias_estimate_x

ملاحظة: تقدّم أدوات الاستشعار التي لم تتم معايرتها نتائج أولية أكثر وقد تتضمّن بعض الانحياز، إلا أنّ قياساتها تتضمّن قفزات أقل بين التصحيحات التي تم تطبيقها من خلال المعايرة. قد تفضل بعض التطبيقات هذه النتائج التي لم تتم معايرتها باعتبارها أكثر سلاسة وموثوقية. على سبيل المثال، إذا كان أحد التطبيقات يحاول إجراء اندماج مستشعر خاص به، فإن تقديم عمليات معايرة يمكن أن تشوّه النتائج بالفعل.

بالإضافة إلى معدلات الدوران، يوفر الجيروسكوب الذي لم تتم معايرته أيضًا مقدار الانحراف المقدر حول كل محور. توضح لك التعليمة البرمجية التالية كيفية الحصول على مثيل للجيروسكوب الافتراضي الذي لم تتم معايرته:

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);

عيّنات تعليمات برمجية إضافية

يوضّح نموذج BatchStepSensor بشكل إضافي استخدام واجهات برمجة التطبيقات المشمولة في هذه الصفحة.

يجب عليك أيضًا قراءة