חיישני תנועה באנדרואיד: Sensor API, אירועים, אצוות

טיפול לא נכון בחיישני תנועה מוביל להתחממות המכשיר ולצריכת סוללה מהירה. אנחנו מפתחים אפליקציות אנדרואיד עם שימוש נכון ב-Sensor API, בחירת חיישנים וירטואליים אופטימליים ועדכונים בקבוצות (batch updates). הצוות שלנו מספק פרויקטים מלאים—מביקורת ועד תמיכה—תוך הבטחת ביצועים יציבים ללא פשרות על לוחות זמנים.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
חיישני תנועה באנדרואיד: Sensor API, אירועים, אצוות
בינוני
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    869
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1289
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

התחממות יתר של המכשיר עקב תדירות דגימה שגויה של חיישנים היא בעיה אופיינית. סוללה שמתרוקנת תוך שעה במקום יום. נתקלנו בפרויקט שבו מיזוג חיישנים (sensor fusion) הפיק קווטרניונים אקראיים בטלפונים זולים. הפתרון – בחירה נכונה של חיישנים וירטואליים ועדכונים בקבוצות (batch updates). מאחורינו ניסיון של למעלה מ-5 שנים ולמעלה מ-20 פרויקטים של חיישני תנועה.

מסגרת החיישנים של Android (Android Sensor Framework) מספקת גישה ל-13+ סוגי חיישנים באמצעות SensorManager יחיד. מד תאוצה וגירוסקופ הם חיישני חומרה. TYPE_LINEAR_ACCELERATION, TYPE_ROTATION_VECTOR, TYPE_GRAVITY הם וירטואליים: מחושבים מחיישני חומרה באמצעות מיזוג חיישנים בקושחה. ההבדל הוא שחיישנים וירטואליים צורכים יותר מעבד (CPU) בתדירות גבוהה ועשויים שלא להיות זמינים במכשירים תקציביים. פרטים נוספים בAndroid Developers: Sensors Overview. הניסיון שלנו: לכיוון מדויק השתמשו ב-TYPE_ROTATION_VECTOR, לתאוצה לינארית – ב-TYPE_LINEAR_ACCELERATION.

רישום ומחזור חיים

class SensorViewModel(application: Application) : AndroidViewModel(application) {
    private val sensorManager = application.getSystemService(SENSOR_SERVICE) as SensorManager
    private val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    private val gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
    private val _sensorData = MutableStateFlow<SensorData>(SensorData.Empty)
    val sensorData: StateFlow<SensorData> = _sensorData.asStateFlow()
    private val sensorEventListener = object : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent) {
            when (event.sensor.type) {
                Sensor.TYPE_ACCELEROMETER -> handleAccelerometer(event.values)
                Sensor.TYPE_GYROSCOPE -> handleGyroscope(event.values)
            }
        }
        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
    }
    fun startListening() {
        accelerometer?.let {
            sensorManager.registerListener(
                sensorEventListener,
                it,
                SensorManager.SENSOR_DELAY_GAME // ~20ms
            )
        }
    }
    fun stopListening() {
        sensorManager.unregisterListener(sensorEventListener)
    }
    override fun onCleared() {
        stopListening()
    }
}

עיקרון: unregisterListener אך ורק ב-class SensorViewModel(application: Application) : AndroidViewModel(application) { private val sensorManager = application.getSystemService(SENSOR_SERVICE) as SensorManager private val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) private val gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) private val _sensorData = MutableStateFlow<SensorData>(SensorData.Empty) val sensorData: StateFlow<SensorData> = _sensorData.asStateFlow() private val sensorEventListener = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent) { when (event.sensor.type) { Sensor.TYPE_ACCELEROMETER -> handleAccelerometer(event.values) Sensor.TYPE_GYROSCOPE -> handleGyroscope(event.values) } } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} } fun startListening() { accelerometer?.let { sensorManager.registerListener( sensorEventListener, it, SensorManager.SENSOR_DELAY_GAME // ~20ms ) } } fun stopListening() { sensorManager.unregisterListener(sensorEventListener) } override fun onCleared() { stopListening() } } של ViewModel או ב-onCleared() של Activity. מאזין שנשכח רץ ברקע, מרוקן את הסוללה ועלול לקרוס את האפליקציה כאשר ה-Activity נהרס.

קצבי דגימה: קבועים ומציאות

קבוע השהיה נומינלית תדירות בפועל
onPause() 200 אלפיות השנייה ~5 הרץ
SENSOR_DELAY_NORMAL 60 אלפיות השנייה ~16 הרץ
SENSOR_DELAY_UI 20 אלפיות השנייה ~50 הרץ
SENSOR_DELAY_GAME 0 אלפיות השנייה קצב חומרה מקסימלי

מאז Android API 9 ניתן להגדיר מרווח מותאם אישית במיקרו-שניות באמצעות SENSOR_DELAY_FASTEST. לדוגמה, 10000 מיקרו-שניות = 100 הרץ.

registerListener(listener, sensor, samplingPeriodUs) על Snapdragon 8 Gen 2 יכול לספק עד 500 הרץ על מד תאוצה – נדרש רק ליישומים מיוחדים (ניתוח רעידות, איזון). לרוב המשימות 50–100 הרץ מספיקים.

מדוע מיזוג חיישנים ב-Android דורש כיול?

חיישנים במכשירים זולים סובלים מהיסט (offset) ורעש. חיישנים וירטואליים (SENSOR_DELAY_FASTEST) משתמשים בכיול קושחה מובנה, אך על קרנלים ישנים הם עלולים לסטות. אנו בודקים על מכשירים מיצרנים שונים ומוסיפים פילטר משלנו (Mahony/Madgwick) במידת הצורך.

TYPE_ROTATION_VECTOR – קווטרניון כיוון המכשיר המחושב ממד תאוצה + גירוסקופ + מגנטומטר. מדויק יותר מביצוע מיזוג ידני:

val rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
// В onSensorChanged:
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)
val azimuth = Math.toDegrees(orientationAngles[0].toDouble()) // 0-360° от севера
val pitch = Math.toDegrees(orientationAngles[1].toDouble()) // -90 до +90°
val roll = Math.toDegrees(orientationAngles[2].toDouble()) // -180 до +180°

TYPE_ROTATION_VECTOR – מד תאוצה ללא כוח הכבידה (בדומה ל-val rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) // В onSensorChanged: val rotationMatrix = FloatArray(9) SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) val orientationAngles = FloatArray(3) SensorManager.getOrientation(rotationMatrix, orientationAngles) val azimuth = Math.toDegrees(orientationAngles[0].toDouble()) // 0-360° от севера val pitch = Math.toDegrees(orientationAngles[1].toDouble()) // -90 до +90° val roll = Math.toDegrees(orientationAngles[2].toDouble()) // -180 до +180° ב-iOS CoreMotion). השתמשו במקום TYPE_LINEAR_ACCELERATION כאשר צריך למדוד רק תאוצה דינמית.

כיצד ליישם זיהוי נפילה?

  1. השתמשו במד תאוצה ב-50 הרץ.
  2. הפעילו פילטר מעביר גבוה (high-pass filter) להפרדת כוח הכבידה:
    val gravity = FloatArray(3)
    val linearAccel = FloatArray(3)
    val alpha = 0.8f
    // В onSensorChanged для TYPE_ACCELEROMETER:
    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]
    linearAccel[0] = event.values[0] - gravity[0]
    linearAccel[1] = event.values[1] - gravity[1]
    linearAccel[2] = event.values[2] - gravity[2]
    val magnitude = sqrt(
        linearAccel[0].pow(2) + linearAccel[1].pow(2) + linearAccel[2].pow(2)
    )

    למכשירים לבישים (קשישים, כורים) שיטה זו עובדת היטב.

    כיצד לארגן ניטור רקע ללא ריקון מופרז של סוללה?

    השתמשו בעדכונים בקבוצות (userAcceleration) וב-TYPE_ACCELEROMETER לעיבוד תקופתי. הימנעו מחיישנים וירטואליים ברקע – הם צורכים מעבד ללא הרף. לזיהוי פעילות פשוט (צעדים, מנוחה) מד תאוצה ב-5-10 הרץ עם קבוצה של שנייה אחת (1000 אלפיות השנייה) מספיק.

    סיווג פעילות

    דפוסים: הליכה – פסגות קבועות של 1.5–2.5 מ'/שנ"ר בתדירות 1.5–2.5 הרץ. רכיבה – רעידות בתדירות נמוכה < 0.5 הרץ. מנוחה – עוצמה < 0.1 מ'/שנ"ר. לסיווג השתמשו בגלאי סף פשוט או במודל למידת מכונה (למשל, random forest) – זה משפר את הדיוק ל-95%.

    עדכונים בקבוצות (Android 4.4+)

    val gravity = FloatArray(3) val linearAccel = FloatArray(3) val alpha = 0.8f // В onSensorChanged для TYPE_ACCELEROMETER: 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] linearAccel[0] = event.values[0] - gravity[0] linearAccel[1] = event.values[1] - gravity[1] linearAccel[2] = event.values[2] - gravity[2] val magnitude = sqrt( linearAccel[0].pow(2) + linearAccel[1].pow(2) + linearAccel[2].pow(2) ) ופרמטר maxReportLatencyUs ב-JobScheduler מאפשרים צבירת נתונים ב-FIFO של החומרה וקבלת קבוצות. שימושי לאפליקציות רקע – החיישן אוסף נתונים בזמן שה-CPU ישן, מתעורר כל N שניות ומספק הכל בבת אחת:

    sensorManager.registerListener(
        listener,
        accelerometer,
        10_000, // samplingPeriodUs = 100 Гц
        500_000 // maxReportLatencyUs = 500 мс
        batch
    )

    גודל ה-FIFO משתנה בין ערכות שבבים (512–4096 דגימות). בעת גלישה, נתונים ישנים מוחלפים – קחו זאת בחשבון לסשנים ארוכים.

    מה כלול בעבודת שילוב חיישנים

    • ניתוח – בחירת חיישנים לתרחיש (ניווט, מעקב פעילות, מכשירים לבישים)
    • ארכיטקטורה – ViewModel/Service, טיפול במחזור חיים, אופטימיזציית סוללה לחיישנים
    • יישום – רישום, סינון, סיווג אירועים (נפילה, צעדים, פניות)
    • בדיקות – על מכשירים אמיתיים (5+ דגמים עם ערכות שבבים שונות)
    • תמיכה – תיעוד API, הדרכת צוות, אחריות קוד עד 6 חודשים

    השוואת גישות למיזוג חיישנים

    מאפיין TYPE_ROTATION_VECTOR (מובנה) Madgwick/Mahony ידני
    דיוק במכשירים מתקדמים ±1° ±2-3° לאחר כיול
    צריכת מעבד נמוכה גבוהה (200+ עדכונים/שנייה)
    תמיכה בטלפונים תקציביים לעיתים חסרה עובד בכל מקום
    מורכבות שילוב מינימלית דורש כוונון פרמטרים

    הניסיון שלנו: ל-90% מהפרויקטים חיישנים וירטואליים מובנים מספיקים. מיזוג ידני נדרש רק ל-AR/VR או לעבודה עם SoCs מיושנים.

    לוח זמנים

    שילוב בסיסי של 1–2 חיישנים עם עיבוד נתונים – מ-3 עד 5 ימי עסקים. אלגוריתם רב-חיישני עם סיווג פעילות, הקלטת רקע ואנליטיקה – מ-2 עד 4 שבועות. העלות מחושבת בנפרד לאחר ניתוח דרישות. לוחות הזמנים נקבעים לאחר ביקורת על הפרויקט שלכם.

    לצוות שלנו ניסיון של למעלה מ-5 שנים ולמעלה מ-20 פרויקטים מוצלחים עם חיישני תנועה. הזמינו ייעוץ – נעריך כדאיות ונציע ארכיטקטורה לתרחיש שלכם. קבלו שילוב איכותי עם אחריות קוד עד 6 חודשים.

    לפרטים נוספים על Sensor API, עיינו בתיעוד הרשמי של Android.