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

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

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

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

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

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

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

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

أداة استشعار بيانات أحداث أداة الاستشعار الوصف وحدات القياس
TYPE_ACCELEROMETER SensorEvent.values[0] قوة التسارع على طول المحور س (بما في ذلك الجاذبية). m/s2
SensorEvent.values[1] قوة التسارع على طول محور y (بما في ذلك الجاذبية)
SensorEvent.values[2] قوة التسارع على طول محور z (بما في ذلك الجاذبية)
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] التسارع المقاس على طول محور X بدون أي تعويض عن الانحياز m/s2
SensorEvent.values[1] التسارع المقاس على طول محور Y بدون أي تعويض عن الانحياز
SensorEvent.values[2] التسارع المقاس على طول محور Z بدون أي تعويض للانحياز
SensorEvent.values[3] قياس التسارع على طول المحور س مع تعويض التحيز المقدر.
SensorEvent.values[4] التسارع المقاس على طول محور Y مع التعويض المقدَّر عن الانحياز
SensorEvent.values[5] تم قياس التسارع على طول المحور Z مع تعويض التحيز المقدر.
TYPE_GRAVITY SensorEvent.values[0] قوة الجاذبية على طول محور x m/s2
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] الانحراف المُقدّر حول المحور x.
SensorEvent.values[4] الانحراف المُقدّر حول المحور ص.
SensorEvent.values[5] الانحراف المقدَّر حول محور z
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] قوة التسارع على طول المحور س (باستثناء الجاذبية). m/s2
SensorEvent.values[1] قوة التسارع على طول محور y (باستثناء الجاذبية)
SensorEvent.values[2] قوة التسارع على طول محور z (باستثناء الجاذبية)
TYPE_ROTATION_VECTOR SensorEvent.values[0] مكوّن متجه التدوير على طول المحور x (x * sin(الوارد/2)). بلا وحدة
SensorEvent.values[1] مكوّن متجه الدوران على طول المحور ص (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

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

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

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

يمثل متجه الدوران اتجاه الجهاز كمجموعة من الزاوية الذي يتم فيه تدوير الجهاز بزاوية LIVE حول محور (x أو y أو z). ما يلي: التعليمات البرمجية كيفية الحصول على مثيل لمستشعر متجه الدوران الافتراضي:

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(reset/2)

حيث يكون مقدار متجه الدوران يساوي sin(subtitle/2)، واتجاه خط متجه الدوران يساوي اتجاه محور الدوران.

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

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

  • يُعرّف س على أنه ناتج الخط المتجه ص × ع. العرض المماسي الأرض في الموقع الحالي للجهاز والنقاط الشرقية تقريبًا.
  • يُعدّ ص اتجاهًا للأرض في الموقع الجغرافي الحالي للجهاز ويشير إلى مغناطيسية أرضية القطب الشمالي.
  • يشير 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);

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

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

A_D=-(1/mass)∑F_S

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

A_D=-g-(1/mass)∑F_S

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

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، ما يتوافق مع تسارع الجهاز (+A م/ث2) مطروحًا منه قوة الجاذبية (-9.81 م/ث2).
  • سيكون للجهاز الثابت قيمة تسارع تبلغ 9.81، ما يتوافق مع تسارع الجهاز (0 م/ث2 مطروحًا منه قوة الجاذبية التي تبلغ -9.81 م/ث2).

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

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

يقيس الجيروسكوب معدّل الدوران بالراديان في الثانية حول محور x وy وz للجهاز. توضّح لك التعليمة البرمجية التالية كيفية الحصول على مثيل أداة الاستشعار الدوراني التلقائية:

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

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

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

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

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 بشكلٍ أكبر استخدام واجهات برمجة التطبيقات التي تتناولها هذه الصفحة.

ننصحك أيضًا بقراءة