Czujniki ruchu

Platforma Android ma kilka czujników, które umożliwiają monitorowanie ruchu urządzenia.

Czujniki możliwe architektury różnią się w zależności od typu czujnika:

  • Grawitacja, przyspieszenie liniowe, wektor obrotu, znaczny ruch, krok licznika i wykrywacza kroków są oparte na sprzęcie opartych na oprogramowaniu.
  • Czujniki akcelerometru i żyroskopu są zawsze oparte na sprzęcie.

Większość urządzeń z Androidem ma akcelerometr, a wiele z nich żyroskop. Dostępność czujników programowych jest większa ponieważ często wykorzystują one co najmniej jeden czujnik sprzętowy do określenia i skalowalnych danych. W zależności od urządzenia czujniki oparte na oprogramowaniu mogą wykrywać z akcelerometru i magnetometru lub z żyroskopu.

Czujniki ruchu przydają się do monitorowania ruchu urządzenia, np. przechylenia, wstrząsów, obrotu lub machanie zębów. Ruch jest zwykle odzwierciedleniem bezpośrednich działań użytkownika (np. sterowaniem samochód w grze lub użytkownik kontrolujący piłkę w grze), ale może też odzwierciedlać otoczenia, w którym znajduje się urządzenie (np. poruszanie się razem z Tobą podczas jazdy); samochodu). W pierwszym przypadku monitorujesz ruch względem ramki odniesienia urządzenia. lub punkt odniesienia dotyczący aplikacji; W drugim przypadku monitorujesz ruch względem systemu odniesienia. Czujniki ruchu same w sobie nie są zwykle używane do monitorowania urządzenia, ale można ich używać z innymi czujnikami, takimi jak czujniki pola magnetycznego, określić położenie urządzenia względem światowego punktu odniesienia (zobacz Czujniki położenia, aby dowiedzieć się więcej ).

Wszystkie czujniki ruchu zwracają wielowymiarowe tablice wartości czujników dla każdego elementu SensorEvent. Na przykład w przypadku pojedynczego zdarzenia czujnika akcelerometr powraca dane o siłach przyspieszenia dla trzech osi współrzędnych oraz szybkość obrotu powrotnego żyroskopu dla trzech osi współrzędnych. Te wartości danych są zwracane w tablicy float (values) wraz z innymi: SensorEvent . W tabeli 1 podsumowano dane z czujników ruchu dostępnych na platformie Android.

Tabela 1. Czujniki ruchu obsługiwane przez platformę Android.

Czujnik Dane zdarzenia z czujnika Opis Jednostki miary
TYPE_ACCELEROMETER SensorEvent.values[0] Siła przyspieszenia wzdłuż osi X (w tym grawitacja). m/s2
SensorEvent.values[1] Siła przyspieszenia wzdłuż osi Y (w tym grawitacja).
SensorEvent.values[2] Siła przyspieszenia wzdłuż osi Z (w tym grawitacja).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] Zmierzone przyspieszenie wzdłuż osi X bez kompensacji odchylenia. m/s2
SensorEvent.values[1] Zmierzone przyspieszenie wzdłuż osi Y bez kompensacji odchylenia.
SensorEvent.values[2] Zmierzone przyspieszenie wzdłuż osi Z bez kompensacji odchylenia.
SensorEvent.values[3] Zmierzone przyspieszenie wzdłuż osi X z szacowaną kompensacją odchylenia.
SensorEvent.values[4] Zmierzone przyspieszenie wzdłuż osi Y z szacowaną kompensacją odchylenia.
SensorEvent.values[5] Zmierzone przyspieszenie wzdłuż osi Z z szacowaną kompensacją odchylenia.
TYPE_GRAVITY SensorEvent.values[0] Siła grawitacji na osi x. m/s2
SensorEvent.values[1] Siła grawitacji wzdłuż osi Y.
SensorEvent.values[2] Siła grawitacji wzdłuż osi Z.
TYPE_GYROSCOPE SensorEvent.values[0] Szybkość obrotu wokół osi X. rad/s
SensorEvent.values[1] Szybkość obrotu wokół osi Y.
SensorEvent.values[2] Szybkość obrotu wokół osi Z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] Szybkość obrotu (bez kompensacji dryfu) wokół osi X. rad/s
SensorEvent.values[1] Szybkość obrotu (bez kompensacji dryfu) wokół osi Y.
SensorEvent.values[2] Szybkość obrotu (bez kompensacji dryfu) wokół osi Z.
SensorEvent.values[3] Szacowany dryf wokół osi X.
SensorEvent.values[4] Szacowany dryf wokół osi Y.
SensorEvent.values[5] Szacowany dryf wokół osi Z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] Siła przyspieszenia wzdłuż osi X (bez grawitacji). m/s2
SensorEvent.values[1] Siła przyspieszenia wzdłuż osi Y (bez grawitacji).
SensorEvent.values[2] Siła przyspieszenia wzdłuż osi Z (bez grawitacji).
TYPE_ROTATION_VECTOR SensorEvent.values[0] Składnik wektora obrotu na osi x (x * sin(Możliwość)). Wielkości bezwymiarowe
SensorEvent.values[1] Składowa wektora obrotu wzdłuż osi y (y * sin(Możliwość kliknięcia/2)).
SensorEvent.values[2] Składowa wektora obrotu wzdłuż osi z (z * sin(Place/2)).
SensorEvent.values[3] Składnik skalarny wektora obrotu ((cos(Place/2)).1
TYPE_SIGNIFICANT_MOTION Nie dotyczy Nie dotyczy Nie dotyczy
TYPE_STEP_COUNTER SensorEvent.values[0] Liczba kroków wykonanych przez użytkownika od ostatniego ponownego uruchomienia, gdy czujnik Aktywowano. Kroki
TYPE_STEP_DETECTOR Nie dotyczy Nie dotyczy Nie dotyczy

1 Komponent skalarny jest wartością opcjonalną.

Czujnik wektora obrotu i czujnik grawitacji to najczęściej używane czujniki ruchu ich wykrywanie i monitorowanie. Czujnik wektorów obrotowych jest szczególnie uniwersalny i może być używany do wykonywania wielu zadań związanych z ruchem, takich jak wykrywanie gestów, monitorowanie zmian kątowych, monitorowania względnych zmian orientacji. Czujnik wektorów obrotowych jest idealny, jeśli tworzą grę, aplikację rzeczywistości rozszerzonej, dwu- lub trójwymiarowy kompas, lub aplikacji do stabilizacji aparatu. W większości przypadków lepiej jest używać tych czujników niż przy użyciu akcelerometru i czujnika pola geomagnetycznego lub czujnika orientacji.

Czujniki projektu Android Open Source

W ramach projektu Android Open Source Project (AOSP) udostępniane są trzy programowe czujniki ruchu: grawitacja czujnika, czujnika przyspieszenia liniowego i czujnika wektora obrotu. Te czujniki zostały zaktualizowane za System Android 4.0 i korzysta teraz z żyroskopu urządzenia (oprócz innych czujników), aby zwiększyć stabilność skuteczność reklam. Jeśli chcesz wypróbować te czujniki, możesz je zidentyfikować za pomocą metod getVendor() i getVersion() (dostawcą jest Google LLC, a numer wersji to 3). Identyfikowanie tych czujników według dostawcy numer wersji jest niezbędny, ponieważ system Android uznaje te trzy czujniki za dodatkowe i czujników. Jeśli na przykład producent urządzenia ma własny czujnik grawitacji, AOSP czujnik grawitacji jest wyświetlany jako dodatkowy czujnik grawitacji. Wszystkie 3 czujniki działają żyroskop: jeśli urządzenie nie jest wyposażone w żyroskop, czujniki nie są widoczne i nie są; dostępnych do użytku.

Użyj czujnika grawitacji

Czujnik grawitacji udostępnia trójwymiarowy wektor wskazujący kierunku i wielkości grawitacji. Ten czujnik jest zwykle używany do określania, do orientacji względnej urządzenia w przestrzeni kosmicznej. Ten kod pokazuje, jak pobierz instancję domyślnego czujnika grawitacji:

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

Jednostki są takie same, jak używane przez przyspieszenie (m/s2), a układ współrzędnych jest taki sam jak czujnik przyspieszenia.

Uwaga: gdy urządzenie jest w spoczynku, sygnał wyjściowy z czujnika grawitacji powinien być taki sam jak akcelerometr.

Użyj akcelerometru liniowego

Czujnik przyspieszenia liniowego przedstawia trójwymiarowy wektor reprezentujące przyspieszenie na każdej osi urządzenia, z wyłączeniem grawitacji. Za pomocą tę wartość, by wykrywać gesty. Wartość może też służyć jako dane wejściowe dla systemu nawigacji inercyjnej, który używa martwego policzenia. Ten kod wyświetla się jak pobrać instancję domyślnego czujnika przyspieszenia liniowego:

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

Zasadniczo ten czujnik dostarcza dane o przyspieszeniu w następujący sposób: relacja:

linear acceleration = acceleration - acceleration due to gravity

Zwykle używasz tego czujnika, gdy chcesz uzyskać dane o przyspieszeniu bez wpływu grawitacji. Czujnik może na przykład sprawdzić, jak szybko jedziesz samochodem. Model liniowy czujnik przyspieszenia zawsze ma przesunięcie, które należy usunąć. Najprostszy sposób to do wbudowania kroku kalibracji do aplikacji. Podczas kalibracji możesz poprosić użytkownika o ustawienie urządzenie na stole i odczytać przesunięcia dla wszystkich trzech osi. Następnie możesz odjąć tę wartość odsunięcie od bezpośrednich odczytów z czujnika przyspieszenia, by uzyskać rzeczywistą jego przyspieszenie.

Współrzędna czujnika układ jest taki sam jak używany przez czujnik przyspieszenia, podobnie jak jednostki miary (m/s2).

Użyj czujnika wektorów obrotu

Wektor obrotu przedstawia orientację urządzenia jako kombinację kąta i oś, na której urządzenie zostało obrócone o kąt Place wokół osi (x, y lub z). Poniżej pokazuje, jak pobrać wystąpienie domyślnego czujnika wektorów obrotu:

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

Trzy elementy wektora obrotu są przedstawione w ten sposób:

x*sin(Możliwość kliknięcia/2), y*sin(Conversions/2), z*sin(Conversions/2)

Gdzie siła wektora obrotu jest równa sin(zmienne) i kierunek wektora jest równy kierunkowi osi obrotu.

Rysunek 1. Układ współrzędnych używany przez czujnik wektora obrotu.

Trzy elementy wektora obrotu są równe trzem ostatnim składowym jednostki kwartion (cos(Place/2), x*sin(obszarze/2), y*sin(Conversions/2), z*sin(Możliwość kliknięcia/2). Elementy wektora obrotu są bez jednostek. Osie x, y i z są zdefiniowane w taki sam sposób jak osie czujnika przyspieszenia. Plik referencyjny układ współrzędnych jest zdefiniowany jako bezpośrednia podstawa ortonormalna (zobacz ilustrację 1). Ten układ współrzędnych ma następujące cechy:

  • X jest zdefiniowane jako iloczyn wektora Y x Z. Jest styczna do funkcji w bieżącej lokalizacji urządzenia i kierunku w przybliżeniu na wschód.
  • Y jest stycznie względem ziemi w bieżącej lokalizacji urządzenia i wskazuje w kierunku geomagnetyczne Biegun Północny.
  • Punkt Z jest skierowany w stronę nieba i jest prostopadła do płaszczyzny podstawy.

Przykładowa aplikacja pokazująca, jak korzystać z czujnika wektorów obrotu, można znaleźć w sekcji RotationVectorDemo.java.

Użyj ważnego czujnika ruchu

Znaczny czujnik ruchu aktywuje zdarzenie za każdym razem, gdy zostanie wykryty znaczny ruch, wtedy sam się wyłączy. Znaczący ruch to ruch, który może prowadzić do zmiany lokalizacja użytkownika; np. spacerowanie, jazda na rowerze czy siedzenie w poruszającym się samochodzie. Poniższy kod pokazuje, jak uzyskać wystąpienie domyślnego czujnika ruchu i jak zarejestrować zdarzenie. detektor:

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

Więcej informacji: TriggerEventListener.

Użyj czujnika licznika kroków

Czujnik licznika kroków pokazuje liczbę kroków zrobionych przez użytkownika od ostatniego restartu gdy czujnik był aktywny. Licznik kroków ma większe opóźnienie (do 10 sekund), ale więcej niż czujnik kroku.

Uwaga: musisz zadeklarować ACTIVITY_RECOGNITION. uprawnienia, by aplikacja mogła używać tego czujnika na urządzeniach z Androida 10 (poziom interfejsu API 29) lub nowszego.

Ten kod pokazuje, jak pobrać wystąpienie kroku domyślnego czujnik licznika:

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

Aby oszczędzać baterię na urządzeniach, na których działa Twoja aplikacja, korzystaj z Klasa JobScheduler, z której ma zostać pobrana bieżąca wartość czujnika licznika kroków w określonym przedziale czasu. Chociaż różne typy aplikacji wymagają różnych interwałów odczytu z czujnika, ustaw ten interwał jako tak długo, jak to możliwe, chyba że aplikacja wymaga danych z czujnika w czasie rzeczywistym.

Używaj czujnika kroków

Czujnik kroków wyzwala zdarzenie za każdym razem, gdy użytkownik wykona krok. Czas oczekiwania wynosi powinien być poniżej 2 sekund.

Uwaga: musisz zadeklarować ACTIVITY_RECOGNITION. uprawnienia, by aplikacja mogła używać tego czujnika na urządzeniach z Androida 10 (poziom interfejsu API 29) lub nowszego.

Ten kod pokazuje, jak pobrać wystąpienie kroku domyślnego czujnik do wykrywania treści:

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

Praca z nieprzetworzonymi danymi

Poniższe czujniki dostarczają aplikacji nieprzetworzone dane o modelach liniowych i sił obrotowych stosowanych na urządzeniu. Aby użyć wartości z argumentu czujniki te muszą odfiltrowywać czynniki ze środowiska, takich jak grawitacja. Konieczne może być też zastosowanie algorytmu wygładzania do trendu. wartości, aby zredukować szum.

Korzystanie z akcelerometru

Czujnik przyspieszenia mierzy przyspieszenie urządzenia, w tym siłę drgań grawitacji. Poniższy kod pokazuje, jak pobrać instancję domyślnego czujnika przyspieszenia:

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

Uwaga: jeśli aplikacja jest kierowana na Androida 12 (poziom interfejsu API 31) lub jest wyższy, ograniczone do stawek.

Czujnik przyspieszenia określa stosowane przyspieszenie do urządzenia (Ad), mierząc siły działające na czujnik. (Fs) za pomocą następującej relacji:

A_D=-(1/masa)∑F_S

Jednak siła grawitacji zawsze wpływa na mierzone przyspieszenie w w następującej relacji:

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

Z tego powodu, gdy urządzenie leży na stole (i nie przyspiesza), akcelerometr wskazuje natężenie g = 9,81 m/s2. Podobnie, gdy urządzenie jest w swobodny spadek i tym samym szybko przyspiesza w kierunku ziemi z prędkością 9,81 m/s2, akcelerometr wskazuje natężenie g = 0 m/s2. Dlatego, aby mierzyć rzeczywiste przyspieszenie urządzenia, należy usunąć udział siły grawitacji z dane z akcelerometru. Można to osiągnąć, stosując filtr górnoprzepustowy. I na odwrót: dolna wartość może zostać użyty do wyodrębnienia siły grawitacji. Poniższy przykład pokazuje, jak to:

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

Uwaga: dane z czujnika możesz filtrować za pomocą wielu różnych metod. W przykładowym kodzie powyżej użyto prostej stałej filtra (alfa) do utworzenia filtra dolnoprzepustowego. Ten filtr jest określana na podstawie stałej czasowej (t), która jest przybliżoną reprezentacją czasu oczekiwania filtr jest dodawany do zdarzeń z czujnika oraz do częstotliwości dostarczania zdarzeń przez czujnik (dt). Przykładowy kod W celach demonstracyjnych użyto wartości alfa 0,8. Jeśli używasz tej metody filtrowania, może być konieczne aby wybrać inną wartość alfa.

Akcelerometr korzysta ze standardowych współrzędnych czujnika . W praktyce oznacza to, że podczas kładzenia urządzenia obowiązują następujące warunki na stole w naturalnej orientacji:

  • Jeśli popchniesz urządzenie w lewą stronę (aby przesunęło się w prawo), wartość przyspieszenia x jest dodatnia.
  • Jeśli popchniesz urządzenie na dół (tak się oddala), wartość przyspieszenia Y wynosi pozytywnym.
  • Jeśli pchniesz urządzenie w stronę nieba z przyspieszeniem A m/s2, wartość przyspieszenia Z jest równa A + 9,81, co odpowiada przyspieszeniu urządzenia (+A m/s2) pomniejszone o siłę grawitacji (-9,81 m/s2).
  • Urządzenie stacjonarne będzie miało wartość przyspieszenia +9,81, co odpowiada przyspieszenie urządzenia (0 m/s2 minus siła grawitacji, która wynosi –9,81 m/s2).

Przy monitorowaniu ruchu urządzenia zwykle warto używać akcelerometru. Niemal wszystkie telefony i tablety z Androidem mają akcelerometr, który zużywa około 10 razy Mniejszy prąd niż inne czujniki ruchu. Wadą jest to, że konieczne może być wdrożenie filtry dolnoprzepustowe i górnoprzepustowe, które eliminują siły grawitacji i zmniejszają szum.

Korzystanie z żyroskopu

Żyroskop mierzy szybkość obrotu w rad/s wokół punktów x, y urządzenia, i osi Z. Poniższy kod pokazuje, jak pobrać wystąpienie domyślnego żyroskopu:

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

Uwaga: jeśli aplikacja jest kierowana na Androida 12 (poziom interfejsu API 31) lub jest wyższy, ograniczone do stawek.

Układ współrzędnych czujnika jest taki sam jak używany dla czujnika przyspieszenia. Rotacja jest dodatnia w w lewo; czyli obserwatora patrzącego na ekran z pewnego dodatniego położenia na osi x, y lub z na urządzeniu umieszczonym na punkcie początkowym. dodatni obrót, jeśli wydaje się, że urządzenie obraca się w lewo. To jest standardowa definicja matematyczna rotacji dodatniej i różni się od definicji dla używane przez czujnik orientacji.

Zwykle dane wyjściowe żyroskopu są integrowane z upływem czasu w celu obliczenia obrotu, opisującego zmiany kątów nachylenia w tym kroku. Na przykład:

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

Standardowe żyroskopy dostarczają nieprzetworzone dane obrotu bez filtrowania czy korekcji szumu czy dryf (uprzedzenia). W praktyce szum żyroskopu i dryf powoduje błędy, które muszą zostać które zostały wynagradzane. Dryf (odchylenie) i szum możesz zwykle określić, monitorując inne czujniki, takie jak takich jak czujnik grawitacji czy akcelerometr.

Używanie nieskalibrowanego żyroskopu

Nieskalibrowany żyroskop jest podobny do żyroskopu, oprócz tego, że do szybkości obrotu nie jest stosowana żadna kompensacja żyroskopu. Kalibracja fabryczna i kompensacja temperatury są nadal stosowane do szybkości obrotu. Nieskalibrowany Żyroskop przydaje się do przetwarzania i złączania danych orientacji. Ogólnie rzecz biorąc, gyroscope_event.values[0] będzie blisko uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3] To znaczy,

calibrated_x ~= uncalibrated_x - bias_estimate_x

Uwaga: nieskalibrowane czujniki dają więcej nieprzetworzonych wyników i mogą uwzględnia pewną odchylenie, ale ich pomiary zawierają mniej skoków po korekcie kalibracji. Niektóre aplikacje mogą preferować te nieskalibrowane wyniki jako płynniejsze i bardziej dynamiczne. i niezawodnością. Jeśli na przykład aplikacja próbuje przeprowadzić własną wprowadzanie kalibracji może zniekształcić wyniki.

Oprócz szybkości obrotu nieskalibrowany żyroskop pokazuje też szacunkową wartość wokół każdej osi. Ten kod pokazuje, jak pobrać instancję domyślnej nieskalibrowany żyroskop:

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

Dodatkowe przykłady kodu

W przykładzie BatchStepSensor można znaleźć więcej szczegółów. wykorzystanie interfejsów API omówionych na tej stronie.

Warto też przeczytać