Naučte sa vyvíjať Android aplikácie – využitie údajov z akcelerometra

0

Moderné smartfóny a tablety disponujú bohatou senzorovou výbavou - spravidla kompasom, akcelerometrom, gyroskopom, meračom intenzity osvetlenia, náklonomerom a systémom pre určovanie polohy. Náklonomer a akcelerometer má v tabletoch veľmi dôležitú funkciu, umožňuje nielen zistenie aktuálnej orientácie prístroja (na výšku, či na šírku), ale nakoľko tablet nemá žiadne kurzorové tlačidlá ani nijaký ekvivalent joysticku využíva sa naklápanie prístroja veľmi často aj na ovládanie hier.

Android sensor framework obsahuje triedy, rozhrania a metódy, umožňujú ce aplikáciám využiť údaje zo senzorov. Aplikácia načíta buď surové údaje priamo zo senzorov (raw sensor data), alebo komplexné údaje, ktoré poskytuje operačný systém na základe spracovania údajov z viacerých senzorov. 

Potrebujete poznať hlavne tieto objekty „senzorového“ frameworku:

SensorManager           - trieda určená na vytvorenie inštancií služieb poskytovaných senzormi, sprístupnenie, konfiguráciu, kalibráciu senzorov a registráciu snímačov udalostí, v originálnej terminológii event listeners

Sensor - trieda na vytvorenie inštancie špecifického senzora a získanie / nastavenie jeho parametrov

SensorEvent - objekt snímača udalostí senzora, pomocou ktorého možno získať typ senzora, u ktorého došlo k vzniku udalosti, údaje poskytované senzorom, presnosť údajov a časovú známku vzniku udalosti

SensorEventListener    Rozhranie na implementáciu metód vykonávaných v prípade vzniku udalosti senzora – zmene údajov poskytovaných senzorom onSensorChanged() a pri zmene presnosti týchto údajov onAccuracyChanged()

Inštanciu objektu SensorManager získate pomocou metódy 

getSystemService(Context.SENSOR_SERVICE)

Identifikácia senzora a jeho možností (capabilities)

Ak v aplikácii potrebujete získať údaje poskytované konkrétnym senzorom, musíte tento senzor v prvom rade sprístupniť. Pokiaľ zariadenie, na ktorom je aplikácia spustená daný senzor obsahuje, môžete prípadne upraviť jeho vlastnosti (rozsah poskytovaných údajov, ich rozlíšenie, nároky na spotrebu energie) a pokračovať v ich využívaní. V opačnom prípade sa ak je to možné aplikácia  môže pokúsiť využiť iný typ senzora. Ak to možné nie je, aplikácia používateľa informuje o tom, že na príslušnú funkcionalitu je nevyhnutný senzor, ktorý sa v zariadení nenachádza a danú aplikáciu nie je možné použiť.

O potrebe existencie konkrétneho senzora je vhodné potenciálnych používateľov vašej aplikácie informovať priamo v jej manifeste pomocou výrazu android:required="true" v rámci elementu <uses-feature>. Aplikácia tak bude dostupná iba pre tie zariadenia, ktoré požadovaný senzor obsahujú.

Dostupnosť senzorov zistíte programovou konštrukciou

private SensorManager mSensorManager;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
  // Senzor, v tomto prípade magnetometer je dostupný.
  }
else {
  // Senzor je nedostupný.
  }

Na prístup ku konkrétnemu senzoru využijete metódu

SensorManager.getDefaultSensor(int typ)

Senzor sa vyberá pomocou parametra typ: 

  • TYPE_ACCELEROMETER - zrýchlenie v m/s2 v troch fyzických osiach (x, y, a z).
  • TYPE_AMBIENT_TEMPERATURE – teplota vzduchu miestnosti v °C. 
  • TYPE_GRAVITY gravitačné zrýchlenie v m/s2 v troch osiach (x, y, z). 
  • TYPE_GYROSCOPE – meria zrýchlenie rotácie v rad/s okolo troch osí (x, y, a z). 
  • TYPE_LIGHT – meria osvetlenie v luxoch (lx). 
  • TYPE_LINEAR_ACCELERATION  - meria zrýchlenie v m/s2 bez vplyvu gravitácie v osiach (x, y, z) 
  • TYPE_MAGNETIC_FIELD – hodnota geomagnetického poľa v troch osiach (x, y, z) v jednotkách μT. 
  • TYPE_ORIENTATION – komplexná informácia z viacerých senzorov poloha rotácie zariadenia okolo troch osí (x, y, z). 
  • TYPE_PRESSURE – meria okolitý atmosférický tlak v jednotkách hPa alebo mbar. 
  • TYPE_PROXIMITY . meria vzdialenosť objektu v cm od displeja zariadenia. 
  • TYPE_RELATIVE_HUMIDITY –vlhkosť okolitého vzduchu v percentách (%). 
  • TYPE_ROTATION_VECTOR – orientácia zariadenia vztiahnutá k trom vektorom. 
  • TYPE_TEMPERATURE – teplota v (°C).

Aplikácia získava údaje z vybraného senzora cez SensorEventListener, ktorý volá metódu onSensorChanged()  po každej zmene hodnoty nameranej senzorom. Pri zmene presnosti merania sa volá procedúra onAccuracyChanged().

Udalosť senzora vznikne vždy v okamihu kedy senzor deteguje zmenu meranej veličiny. 

Príklad – zobrazenie údajov z akcelerometra

Väčšina Android zariadení disponuje akcelerometrom schopným merať zrýchlenie v troch osiach. V aplikáciách sa dá využiť napríklad na snímanie dynamiky pohybu pri ovládaní. V jednoduchom príklade vypíšeme hodnoty zrýchlenia v osiach X, Y, a Z. Mapovanie osí na zariadenie sa po zmene jeho polohy nemení.

V aplikácii použijeme pripojenie na senzor TYPE_ACCELEROMETER, takže budú načítané absolútne hodnoty zrýchlenia, v osi Y sa teda aj v kľudovomstave zariadenia prejaví hodnota gravitačného zrýchlenia. Návrh používateľského rozhrania pozostáva zo šiestich prvkov TextView. Tri z nich v ľavom stĺpci zobrazujú názov osi. Prvky v pravom stĺpci budú zobrazovať hodnoty zrýchlenia v príslušnej osi. Pre rozmiestnenie prvkov sme využili kontejner RelativeLayout. 

Text legendy sme v tomto prípade umiestnili priamo do návrhu prvkov. Názvy osí sú v krajinách využívajúcich latinku medzinárodné. Pre zjednodušenie sú vo výpise len prvky týkajúce sa osi X.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
 
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1">
    <TextView
        android:id="@+id/x_popis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:padding="5dp"
        android:text="X: "
        android:textSize="20sp" />
   
 
    <TextView
        android:id="@+id/x_hodnota"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/x_popis"
        android:padding="5dp"
        android:textSize="20sp" />
    </LinearLayout>
 
...
 
</LinearLayout>

Prvým krokom pri získavaní údajov poskytovaných konkrétnym senzorom je vytvorenie inštancie (referencie) služby:

sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

Následne zistíme prítomnosť konkrétneho senzora v zariadení (v kladnom prípade môžeme následne získať / upraviť jeho parametre):

if ((akcelerometr = sensorManager
             .getDefaultSensor(Sensor.TYPE_ACCELEROMETER))==null)
      finish();

 Tretím krokom je registrácia snímača udalostí:

sensorManager.registerListener(this, akcelerometr,

             SensorManager.SENSOR_DELAY_UI);

      posledniAktualizace = System.currentTimeMillis();

 

 Posledným krokom algoritmu je povinná implementácia dvoch metód rozhrania SensorEventListener:

@Override
public void onSensorChanged(SensorEvent event) 
{}
 
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) 
{}

Uvedená metóda je vykonávaná pri zmene presnosti (LOW, MEDIUM, HIGH, UNRELIABLE) senzora. Metóda je vykonaná v okamihu keď senzor poskytne nové údaje a to prostredníctvom objektu SensorEvent.

V kóde hlavnej aktivity si všimnite, že listener pre senzor akcelerometra sa zakaždým deaktivuje, aby sa šetrila energia z batérie. Hodnota zrýchlenia sa načíta v metóde onSensorChanged(). Aby sa zobrazené hodnoty dali prečítať, aktualizuje sa hodnota každých 500 ms, čiže každú pol sekundu. V tejto jednoduchej aplikácii zmenu presnosti, ktorá volá metódu onAccuracyChanged() ignorujeme.

Kompletný kód hlavnej aktivity

package com.example.akcelerometer;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;
 
public class MainActivity extends Activity implements SensorEventListener
{
    private static final int INTERVAL = 500;
    private SensorManager sensorManager;
    private Sensor akcelerometr;
 
    private TextView xHodnota, yHodnota, zHodnota;
    private long posledniAktualizace;
 
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        xHodnota = (TextView) findViewById(R.id.x_hodnota);
        yHodnota = (TextView) findViewById(R.id.y_hodnota);
        zHodnota = (TextView) findViewById(R.id.z_hodnota);
 
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        if ((akcelerometr = sensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER))==null)
            finish();
    }
 
    @Override
    protected void onResume()
    {
        super.onResume();
 
        sensorManager.registerListener(this, akcelerometr,
                SensorManager.SENSOR_DELAY_UI);
        posledniAktualizace = System.currentTimeMillis();
    }
 
    @Override
    protected void onPause()
    {
        sensorManager.unregisterListener(this);
        super.onPause();
    }
 
    @Override
    public void onSensorChanged(SensorEvent event)
    {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        {
            long actualTime = System.currentTimeMillis();
            if (actualTime - posledniAktualizace > INTERVAL)
            {
                posledniAktualizace = actualTime;
                float x = event.values[0], y = event.values[1], z = event.values[2];
                xHodnota.setText(String.valueOf(x));
                yHodnota.setText(String.valueOf(y));
                zHodnota.setText(String.valueOf(z));
            }
        }
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy)
    {}

Teraz môžete aplikáciu spustiť. Skúste najskôr pohybovať zariadením v polohe podľa obrázka na  ktorom je súradnicový systém. Následne otáčajte zariadením  a pozorujte ako sa menia hodnoty v jednotlivých osiach a hlavne ich znamienka. Ak je zariadenie v kľude nameriate pri použití senzora TYPE_ACCELEROMETER v osi y hodnotu 9.81, čo je gravitačné zrýchlenie.

Údaje zo senzorov je možné simulovať aj na emulátore, najlepšie sa však aplikácie tohto typu testujú na reálnom zariadení 

Rekapitulácia seriálu

1  – Prvá aplikácia 

2 – Možnosti emulátorov 

3 - Zorientujte sa v projekte aplikácie

4 – Princípy dizajnu a škálovania

5 – Uporiadanie prvkov používateľského rozhrania

6 – Obsluha udalostí

7 – Aplikácia s dvomi aktivitami  

8 – Spustenie na reálnom zariadení

9 – Intenty, alebo kto to urobí

10 – Dotyky a gestá

11 - Dotyky a gestá II  

12  - Zmena orientácie displeja

13 – Grafika 1

14 – Grafika II

15 - Animácia

16 – Animácia II

17 – Prehrávanie zvuku a videa

Zobrazit Galériu

Luboslav Lacko

Všetky autorove články
Vývoj Android Android aplikácia Android Studio

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať