حسگرهای حرکتی

پلاتفرم Android چندین حسگر ارائه می‌دهد که به شما امکان می‌دهد حرکت دستگاه را پایش کنید.

معماری‌های احتمالی حسگرها بسته به نوع حسگر متفاوت است:

  • حسگرهای جاذبه، شتاب خطی، بردار چرخش، حرکت قابل‌توجه، گام‌شمار، و تشخیص گام یا سخت‌افزارپایه هستند یا نرم‌افزارپایه.
  • حسگرهای شتاب‌سنج و ژیروسکوپ همیشه سخت‌افزارپایه هستند.

اکثر دستگاه‌های مجهز به Android شتاب‌سنج دارند و بسیاری از آن‌ها اکنون ژیروسکوپ هم دارند. دردسترس بودن حسگرهای نرم‌افزاری متغیرتر است زیرا آن‌ها اغلب برای به‌دست آوردن داده‌هایشان به یک یا چند حسگر سخت‌افزاری متکی هستند. بسته به دستگاه، این حسگرهای مبتنی بر نرم‌افزار می‌توانند داده‌هایشان را از شتاب‌سنج و مغناطیس‌سنج یا از ژیروسکوپ دریافت کنند.

حسگرهای حرکتی برای پایش حرکت دستگاه، مانند کج شدن، لرزش، چرخش، یا تاب خوردن مفید هستند. این حرکت معمولاً بازتابی از ورودی مستقیم کاربر است (برای مثال، کاربری که در بازی خودرویی را هدایت می‌کند یا کاربری که در بازی توپی را کنترل می‌کند)، اما می‌تواند بازتابی از محیط فیزیکی‌ای باشد که دستگاه در آن قرار دارد (برای مثال، حرکت کردن با شما درحین رانندگی). در حالت اول، حرکت را نسبت به چارچوب مرجع دستگاه یا چارچوب مرجع برنامه‌تان پایش می‌کنید؛ در حالت دوم، حرکت را نسبت به چارچوب مرجع جهان پایش می‌کنید. حسگرهای حرکتی معمولاً به‌تنهایی برای نظارت بر موقعیت دستگاه استفاده نمی‌شوند، اما می‌توان از آن‌ها همراه با حسگرهای دیگر، مانند حسگر میدان ژئومغناطیسی، برای تعیین موقعیت دستگاه نسبت به چارچوب مرجع جهان استفاده کرد (برای اطلاعات بیشتر، به حسگرهای موقعیت مراجعه کنید).

همه حسگرهای حرکت آرایه‌های چندبعدی از مقادیر حسگر را برای هر SensorEvent برمی‌گردانند. برای مثال، درطول یک رویداد حسگر، شتاب‌سنج داده‌های نیروی شتاب را برای سه محور مختصات برمی‌گرداند و ژیروسکوپ داده‌های نرخ چرخش را برای سه محور مختصات برمی‌گرداند. این مقادیر داده در آرایه float (values) به‌همراه سایر پارامترهای SensorEvent برگردانده می‌شود. جدول ۱ حسگرهای حرکتی را که در پلاتفرم Android دردسترس هستند خلاصه می‌کند.

جدول ۱. حسگرهای حرکتی که در پلاتفرم Android پشتیبانی می‌شوند.

حسگر داده‌های رویداد حسگر شرح واحدهای اندازه‌گیری
TYPE_ACCELEROMETER SensorEvent.values[0] نیروی شتاب در امتداد محور x (شامل گرانش). متر بر مجذور ثانیه2
SensorEvent.values[1] نیروی شتاب در امتداد محور y (شامل گرانش).
SensorEvent.values[2] نیروی شتاب در امتداد محور z (شامل گرانش).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] شتاب اندازه‌گیری‌شده در امتداد محور X بدون هیچ‌گونه جبران سوگیری. متر بر مجذور ثانیه2
SensorEvent.values[1] شتاب اندازه‌گیری‌شده در امتداد محور Y بدون هیچ‌گونه جبران سوگیری.
SensorEvent.values[2] شتاب اندازه‌گیری‌شده در امتداد محور Z بدون هیچ‌گونه جبران سوگیری.
SensorEvent.values[3] سوگیری تخمینی در امتداد محور X.
SensorEvent.values[4] سوگیری تخمینی در امتداد محور Y.
SensorEvent.values[5] انحراف تخمینی در امتداد محور Z.
TYPE_GRAVITY SensorEvent.values[0] نیروی جاذبه در امتداد محور x. متر بر مجذور ثانیه2
SensorEvent.values[1] نیروی جاذبه در امتداد محور y.
SensorEvent.values[2] نیروی جاذبه در امتداد محور z.
TYPE_GYROSCOPE SensorEvent.values[0] نرخ چرخش حول محور x. rad/s
SensorEvent.values[1] نرخ چرخش حول محور y.
SensorEvent.values[2] نرخ چرخش حول محور z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] نرخ چرخش (بدون جبران رانش) حول محور x. rad/s
SensorEvent.values[1] نرخ چرخش (بدون جبران رانش) حول محور y.
SensorEvent.values[2] نرخ چرخش (بدون جبران رانش) حول محور z.
SensorEvent.values[3] انحراف تخمینی حول محور x.
SensorEvent.values[4] انحراف تخمینی حول محور y.
SensorEvent.values[5] انحراف تخمینی حول محور z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] نیروی شتاب در امتداد محور x (به‌استثنای جاذبه). متر بر مجذور ثانیه2
SensorEvent.values[1] نیروی شتاب در امتداد محور y (به‌استثنای جاذبه).
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)).۱
TYPE_SIGNIFICANT_MOTION موجود نیست موجود نیست موجود نیست
TYPE_STEP_COUNTER SensorEvent.values[0] تعداد قدم‌هایی که کاربر از آخرین راه‌اندازی مجدد برداشته است، درحالی‌که حسگر فعال بوده است. قدم‌ها
TYPE_STEP_DETECTOR موجود نیست موجود نیست موجود نیست

۱ مؤلفه اسکالر مقداری اختیاری است.

حسگر بردار چرخش و حسگر گرانش پرکاربردترین حسگرها برای تشخیص و پایش حرکت هستند. حسگر بردار چرخشی به‌ویژه همه‌کاره است و می‌تواند برای طیف گسترده‌ای از کارهای مرتبط با حرکت، مانند تشخیص اشاره‌ها، نظارت بر تغییر زاویه، و نظارت بر تغییرات جهت نسبی استفاده شود. برای مثال، اگر درحال توسعه بازی، برنامه واقعیت افزوده، قطب‌نمای ۲بعدی یا ۳بعدی، یا برنامه تثبیت دوربین هستید، حسگر بردار چرخشی ایده‌آل است. در بیشتر موارد، استفاده از این حسگرها انتخاب بهتری نسبت‌به استفاده از شتاب‌سنج و حسگر میدان ژئومغناطیسی یا حسگر جهت‌یابی است.

حسگرهای پروژه منبع باز Android

«پروژه منبع باز Android»‏ (AOSP) سه حسگر حرکتی نرم‌افزارمحور ارائه می‌دهد: حسگر گرانش، حسگر شتاب خطی، و حسگر بردار چرخش. این حسگرها در Android 4.0 به‌روزرسانی شدند و اکنون از ژیروسکوپ دستگاه (علاوه‌بر حسگرهای دیگر) برای بهبود پایداری و عملکرد استفاده می‌کنند. اگر می‌خواهید این حسگرها را امتحان کنید، می‌توانید آن‌ها را بااستفاده از روش getVendor() و روش getVersion() شناسایی کنید (فروشنده Google LLC است؛ شماره نسخه ۳ است). شناسایی این حسگرها براساس فروشنده و شماره نسخه ضروری است زیرا سیستم Android این سه حسگر را حسگرهای ثانویه درنظر می‌گیرد. برای مثال، اگر سازنده دستگاه حسگر گرانش خودش را ارائه دهد، حسگر گرانش AOSP به‌عنوان حسگر گرانش ثانویه نشان داده می‌شود. هر سه این حسگرها به ژیروسکوپ متکی هستند: اگر دستگاهی ژیروسکوپ نداشته باشد، این حسگرها نشان داده نمی‌شوند و برای استفاده دردسترس نیستند.

استفاده از حسگر گرانش

حسگر گرانش یک بردار سه‌بعدی ارائه می‌دهد که جهت و مقدار گرانش را نشان می‌دهد. معمولاً از این حسگر برای تعیین جهت نسبی دستگاه در فضا استفاده می‌شود. کد زیر نحوه دریافت نمونه‌ای از حسگر گرانش پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

واحدها همان واحدهایی هستند که حسگر شتاب استفاده می‌کند (m/s2)، و سیستم مختصات همان سیستمی است که حسگر شتاب استفاده می‌کند.

توجه: وقتی دستگاه در حالت استراحت است، خروجی حسگر گرانش باید با خروجی شتاب‌سنج یکسان باشد.

استفاده از شتاب‌سنج خطی

حسگر شتاب خطی بردار سه‌بعدی‌ای دراختیارتان قرار می‌دهد که نشان‌دهنده شتاب در هر محور دستگاه، به‌استثنای گرانش، است. می‌توانید از این مقدار برای تشخیص اشاره استفاده کنید. این مقدار همچنین می‌تواند به‌عنوان ورودی برای یک سیستم ناوبری اینرسیایی که از تخمین موقعیت استفاده می‌کند، عمل کند. کد زیر نشان می‌دهد چگونه نمونه‌ای از حسگر شتاب خطی پیش‌فرض را دریافت کنید:

کاتلین

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

جاوا

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

استفاده از حسگر بردار چرخش

بردار چرخش نشان‌دهنده جهت دستگاه به‌عنوان ترکیبی از زاویه و محور است که در آن دستگاه با زاویه θ حول محور (x،‏ y، یا z) چرخیده است. کد زیر نحوه دریافت نمونه‌ای از حسگر بردار چرخش پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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) است و جهت بردار چرخش برابر با جهت محور چرخش است.

شکل ۱. سیستم مختصاتی که حسگر بردار چرخش استفاده می‌کند.

سه عنصر بردار چرخش برابر با سه مؤلفه آخر یک کواترنیون واحد است (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)). عناصر بردار چرخش بدون واحد هستند. محورهای x،‏ y، و z به همان روش حسگر شتاب تعریف می‌شوند. سیستم مختصات مرجع به‌عنوان یک پایه متعامد نرمال مستقیم تعریف می‌شود (شکل ۱ را ببینید). این سیستم مختصات ویژگی‌های زیر را دارد:

  • X به‌عنوان حاصل ضرب برداری Y x Z تعریف می‌شود. این محور بر زمین در مکان فعلی دستگاه مماس است و تقریباً به‌سمت شرق اشاره می‌کند.
  • Y در مکان فعلی دستگاه مماس بر زمین است و به‌سمت قطب شمال ژئومغناطیسی اشاره می‌کند.
  • Z به‌سمت آسمان است و بر صفحه زمین عمود است.

برای نمونه برنامه‌ای که نحوه استفاده از حسگر بردار چرخش را نشان می‌دهد، به RotationVectorDemo.java مراجعه کنید.

استفاده از حسگر حرکت قابل‌توجه

حسگر حرکت قابل‌توجه هربار که حرکت قابل‌توجهی تشخیص داده شود رویدادی را راه‌اندازی می‌کند و سپس خودش را غیرفعال می‌کند. حرکت قابل‌توجه حرکتی است که ممکن است منجر به تغییر در مکان کاربر شود؛ برای مثال، پیاده‌روی، دوچرخه‌سواری، یا نشستن در خودرو درحال حرکت. کد زیر به شما نشان می‌دهد چگونه نمونه‌ای از حسگر حرکت قابل‌توجه پیش‌فرض را دریافت کنید و چگونه شنونده رویداد را ثبت کنید:

کاتلین

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

جاوا

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 مراجعه کنید.

استفاده از حسگر گام‌شمار

حسگر گام‌شمار تعداد گام‌های برداشته‌شده توسط کاربر را از آخرین راه‌اندازی مجدد درحالی‌که حسگر فعال بوده است ارائه می‌دهد. گام‌شمار تأخیر بیشتری (تا ۱۰ ثانیه) دارد اما دقت آن از حسگر تشخیص گام بیشتر است.

توجه: برای اینکه برنامه‌تان بتواند از این حسگر در دستگاه‌های دارای Android 10 (سطح میانای برنامه‌سازی کاربردی ۲۹) یا بالاتر استفاده کند، باید اجازه ACTIVITY_RECOGNITION را اعلام کنید.

کد زیر نحوه دریافت نمونه‌ای از حسگر گام‌شمار پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

برای حفظ باتری در دستگاه‌هایی که برنامه شما را اجرا می‌کنند، باید از کلاس JobScheduler برای بازیابی مقدار فعلی از حسگر گام‌شمار در بازه زمانی خاصی استفاده کنید. اگرچه انواع مختلف برنامه‌ها به فواصل خواندن حسگر متفاوتی نیاز دارند، باید این فاصله را تا حد امکان طولانی کنید، مگراینکه برنامه شما به داده‌های هم‌زمان از حسگر نیاز داشته باشد.

استفاده از حسگر تشخیص گام

حسگر تشخیص گام هربار که کاربر گامی برمی‌دارد رویدادی را راه‌اندازی می‌کند. انتظار می‌رود تأخیر کمتر از ۲ ثانیه باشد.

توجه: برای اینکه برنامه‌تان بتواند از این حسگر در دستگاه‌های دارای Android 10 (سطح میانای برنامه‌سازی کاربردی ۲۹) یا بالاتر استفاده کند، باید اجازه ACTIVITY_RECOGNITION را اعلام کنید.

کد زیر نحوه دریافت نمونه‌ای از حسگر تشخیص گام پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

کار کردن با داده‌های خام

حسگرهای زیر داده‌های خام مربوط به نیروهای خطی و چرخشی اعمال‌شده به دستگاه را به برنامه شما ارائه می‌دهند. برای استفاده مؤثر از مقادیر این حسگرها، باید عوامل محیطی مانند گرانش را فیلتر کنید. همچنین ممکن است لازم باشد الگوریتم هموارسازی را روی روند مقادیر اعمال کنید تا نوفه کاهش یابد.

استفاده از شتاب‌سنج

حسگر شتاب، شتاب اعمال‌شده به دستگاه را اندازه‌گیری می‌کند، ازجمله نیروی جاذبه. کد زیر نحوه دریافت نمونه‌ای از حسگر شتاب پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

توجه: اگر برنامه شما Android 12 (سطح میانای برنامه‌سازی کاربردی ۳۱) یا بالاتر را هدف قرار می‌دهد، این حسگر محدودیت نرخ دارد.

ازنظر مفهومی، حسگر شتاب با اندازه‌گیری نیروهایی که به خود حسگر (Fs) وارد می‌شود، شتابی را که به دستگاه (Ad) وارد می‌شود بااستفاده از رابطه زیر تعیین می‌کند:

A_D=-(1/mass)∑F_S

بااین‌حال، نیروی جاذبه همیشه بر شتاب اندازه‌گیری‌شده طبق رابطه زیر تأثیر می‌گذارد:

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

به همین دلیل، وقتی دستگاه روی میز قرار دارد (و شتابی ندارد)، شتاب‌سنج مقدار g = 9.81 m/s2 را می‌خواند. به‌طور مشابه، وقتی دستگاه درحال سقوط آزاد است و بنابراین با سرعت ۹٫۸۱ متر بر مجذور ثانیه۲ به‌سمت زمین شتاب می‌گیرد، شتاب‌سنج آن مقدار g = ۰ متر بر مجذور ثانیه۲ را می‌خواند. بنابراین، برای اندازه‌گیری شتاب واقعی دستگاه، باید سهم نیروی گرانش از داده‌های شتاب‌سنج حذف شود. این کار را می‌توان با اعمال فیلتر بالاگذر انجام داد. برعکس، از فیلتر پایین‌گذر می‌توان برای جداسازی نیروی جاذبه استفاده کرد. مثال زیر نشان می‌دهد که چگونه می‌توانید این کار را انجام دهید:

کاتلین

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

جاوا

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). نمونه کد از مقدار آلفای ۰٫۸ برای اهداف نمایشی استفاده می‌کند. اگر از این روش فیلتر کردن استفاده می‌کنید، ممکن است لازم باشد مقدار آلفای دیگری را انتخاب کنید.

شتاب‌سنج‌ها از سیستم مختصات حسگر استاندارد استفاده می‌کنند. در عمل، این یعنی وقتی دستگاه در جهت طبیعی خود به‌صورت صاف روی میز قرار دارد، شرایط زیر اعمال می‌شود:

  • اگر دستگاه را از سمت چپ فشار دهید (تا به سمت راست حرکت کند)، مقدار شتاب x مثبت است.
  • اگر دستگاه را از پایین فشار دهید (به‌طوری‌که از شما دور شود)، مقدار شتاب y مثبت است.
  • اگر دستگاه را با شتاب A m/s2 به‌سمت آسمان فشار دهید، مقدار شتاب z برابر با A + 9.81 است که با شتاب دستگاه (+A m/s2) منهای نیروی گرانش (-9.81 m/s2) مطابقت دارد.
  • دستگاه ثابت مقدار شتاب ۹٫۸۱+ خواهد داشت که با شتاب دستگاه (۰ متر بر مجذور ثانیه۲ منهای نیروی جاذبه که ۹٫۸۱- متر بر مجذور ثانیه۲ است) مطابقت دارد.

به‌طور کلی، شتاب‌سنج حسگر خوبی برای استفاده درصورت نظارت بر حرکت دستگاه است. تقریباً همه گوشی‌ها و رایانه‌های لوحی Android شتاب‌سنج دارند و این حسگر حدود ۱۰ برابر کمتر از دیگر حسگرهای حرکتی انرژی مصرف می‌کند. یکی از معایب این است که ممکن است مجبور شوید فیلترهای پایین‌گذر و بالاگذر را برای حذف نیروهای گرانشی و کاهش نویز پیاده‌سازی کنید.

استفاده از ژیروسکوپ

ژیروسکوپ نرخ چرخش را برحسب رادیان بر ثانیه حول محورهای x،‏ y، و z دستگاه اندازه‌گیری می‌کند. کد زیر نحوه دریافت نمونه‌ای از ژیروسکوپ پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

توجه: اگر برنامه شما Android 12 (سطح میانای برنامه‌سازی کاربردی ۳۱) یا بالاتر را هدف قرار می‌دهد، این حسگر محدودیت نرخ دارد.

سیستم مختصات حسگر همان سیستم مورداستفاده برای حسگر شتاب است. چرخش در جهت پادساعت‌گرد مثبت است؛ یعنی اگر ناظری از مکانی مثبت در محور x،‏ y، یا z به دستگاهی که در مبدأ قرار دارد نگاه کند، درصورتی‌که دستگاه در جهت پادساعت‌گرد بچرخد، چرخش مثبت گزارش می‌شود. این تعریف ریاضی استاندارد چرخش مثبت است و با تعریف چرخش که توسط حسگر جهت‌یابی استفاده می‌شود یکسان نیست.

معمولاً خروجی ژیروسکوپ در طول زمان ادغام می‌شود تا چرخشی را محاسبه کند که تغییر زاویه‌ها را در طول گام زمانی توصیف می‌کند. برای مثال:

کاتلین

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

جاوا

// 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

توجه: حسگرهای واسنجی‌نشده نتایج خام‌تری ارائه می‌دهند و ممکن است شامل برخی سوگیری‌ها باشند، اما اندازه‌گیری‌های آن‌ها شامل پرش‌های کمتری از اصلاحات اعمال‌شده ازطریق واسنجی است. برخی‌از برنامه‌ها ممکن است این نتایج واسنجی‌نشده را به‌عنوان نتایج روان‌تر و قابل‌اعتمادتر ترجیح دهند. برای مثال، اگر برنامه‌ای در تلاش است تا ادغام حسگر خود را انجام دهد، معرفی واسنجی‌ها می‌تواند درواقع نتایج را تحریف کند.

ژیروسکوپ واسنجی‌نشده علاوه‌بر نرخ‌های چرخش، انحراف تخمینی حول هر محور را نیز ارائه می‌دهد. کد زیر نحوه دریافت نمونه‌ای از ژیروسکوپ واسنجی‌نشده پیش‌فرض را نشان می‌دهد:

کاتلین

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

جاوا

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

نمونه‌های کد اضافی

نمونه BatchStepSensor استفاده از میاناهای برنامه‌سازی کاربردی پوشش‌داده‌شده در این صفحه را بیشتر نشان می‌دهد.

همچنین باید این موارد را بخوانید