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.
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:
Gdzie siła wektora obrotu jest równa sin(zmienne) i kierunek wektora jest równy kierunkowi osi 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:
Jednak siła grawitacji zawsze wpływa na mierzone przyspieszenie w w następującej relacji:
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.