Przegląd orientacji telefonu z systemem Android, w tym kompas

107

Od jakiegoś czasu próbuję obejść czujniki orientacji Androida. Myślałem, że to rozumiem. Wtedy zdałem sobie sprawę, że nie. Teraz myślę (mam nadzieję), że mam co do tego lepsze przeczucie, ale nadal nie jestem w 100%. Spróbuję wyjaśnić moje niepełne zrozumienie tego i mam nadzieję, że ludzie będą w stanie mnie poprawić, jeśli się mylę w części lub wypełnię jakieś puste miejsca.

Wyobrażam sobie, że stoję na 0 stopni długości geograficznej (południk pierwszy) i 0 stopni szerokości geograficznej (równik). To miejsce faktycznie znajduje się na morzu u wybrzeży Afryki, ale proszę o cierpliwość. Trzymam telefon przed twarzą, tak aby spód telefonu wskazywał na moje stopy; Patrzę na północ (patrząc w stronę Greenwich), więc prawa strona telefonu wskazuje na wschód, w stronę Afryki. W tej orientacji (w odniesieniu do poniższego diagramu) oś X wskazuje na wschód, oś Z wskazuje południe, a oś Y wskazuje na niebo.

Teraz czujniki w telefonie pozwalają ustalić orientację (a nie lokalizację) urządzenia w tej sytuacji. Ta część zawsze mnie myliła, prawdopodobnie dlatego, że chciałem zrozumieć, jak coś działa, zanim zaakceptowałem, że to po prostu działa. Wygląda na to, że telefon ustala swoją orientację za pomocą kombinacji dwóch różnych technik.

Zanim do tego dojdę, wyobraź sobie, że stoję z powrotem na tym wyimaginowanym kawałku ziemi na 0 stopni szerokości i długości geograficznej, stojąc we wspomnianym wyżej kierunku. Wyobraź sobie również, że masz zawiązane oczy, a buty są przymocowane do ronda placu zabaw. Jeśli ktoś popchnie cię w plecy, upadniesz do przodu (na północ) i wyciągniesz obie ręce, aby powstrzymać upadek. Podobnie, jeśli ktoś popchnie cię w lewe ramię, przewrócisz się na prawą rękę. Twoje ucho wewnętrzne ma „czujniki grawitacyjne” (klip do youtube), które pozwalają wykryć, czy spadasz do przodu / do tyłu, czy spadasz w lewo / w prawo, czy spadasz (lub do góry !!). Dlatego ludzie mogą wykrywać wyrównanie i obrót wokół tych samych osi X i Z, co telefon.

Teraz wyobraź sobie, że ktoś obraca cię teraz o 90 stopni na rondzie, tak że jesteś teraz zwrócony na wschód. Jesteś obracany wokół osi Y. Ta oś jest inna, ponieważ nie możemy jej wykryć biologicznie. Wiemy, że jesteśmy pod pewnym kątem, ale nie znamy kierunku w stosunku do magnetycznego bieguna północnego planety. Zamiast tego musimy użyć zewnętrznego narzędzia ... kompasu magnetycznego. To pozwala nam ustalić, w jakim kierunku jesteśmy zwróceni. To samo dotyczy naszego telefonu.

Teraz telefon ma również 3-osiowy akcelerometr. Mam NOwyobrażam sobie, jak one faktycznie działają, ale wyobrażam sobie to, wyobrażając sobie grawitację jako stały i jednolity „deszcz” spadający z nieba i wyobrażając sobie osie na powyższym rysunku jako rury, które mogą wykrywać ilość przepływającego deszczu. Gdy telefon będzie trzymany pionowo, cały deszcz będzie przepływał przez „rurkę” Y. Jeśli telefon będzie stopniowo obracany w taki sposób, aby jego ekran był skierowany w niebo, ilość deszczu przepływającego przez Y zmniejszy się do zera, podczas gdy głośność przez Z będzie się stopniowo zwiększać, aż do momentu, w którym będzie przepływać maksymalna ilość deszczu. Podobnie, jeśli teraz przechylimy telefon na bok, rurka X ostatecznie zbierze maksymalną ilość deszczu. Dlatego w zależności od orientacji telefonu, mierząc ilość deszczu przepływającego przez 3 rury, można obliczyć orientację.

Telefon jest również wyposażony w elektroniczny kompas, który zachowuje się jak zwykły kompas - jego „wirtualna igła” wskazuje północ magnetyczną. Android łączy informacje z tych dwóch czujników tak, że za każdym razem, gdy generowany jest SensorEventof, tablica ma wartości [0]: Azymut - (kompas zorientowany na wschód od północy magnetycznej) wartości [1]: nachylenie, obrót wokół osi x (jest to telefon pochylenie do przodu lub do tyłu) wartości [2]: Obrót, obrót wokół osi y (czy telefon jest pochylony w lewą czy prawą stronę)TYPE_ORIENTATIONvalues[3]


Myślę więc (tj. Nie wiem) powodem, dla którego Android podaje azymut (namiar kompasu), a nie odczyt trzeciego akcelerometru, jest to, że namiar kompasu jest po prostu bardziej przydatny. Nie jestem pewien, dlaczego wycofali ten typ czujnika, ponieważ teraz wydaje się, że musisz zarejestrować odbiornik w systemie dla typu SensorEvents TYPE_MAGNETIC_FIELD. Tablica zdarzenia value[]musi zostać przekazana do SensorManger.getRotationMatrix(..)metody, aby uzyskać macierz rotacji (patrz poniżej), która jest następnie przekazywana do SensorManager.getOrientation(..)metody. Czy ktoś wie, dlaczego zespół Androida został wycofany Sensor.TYPE_ORIENTATION? Czy to kwestia wydajności? To wynika z jednego z komentarzy do podobnego pytania, ale nadal musisz zarejestrować inny typ słuchacza wdevelopment / samples / Compass / src / com / example / android / compass / CompassActivity.java example.

Chciałbym teraz porozmawiać o macierzy rotacji. (W tym miejscu nie jestem pewien) Więc powyżej mamy trzy cyfry z dokumentacji Androida, nazwiemy je A, B i C.

Rysunek metody A = SensorManger.getRotationMatrix (..) i reprezentuje światowy układ współrzędnych

B = układ współrzędnych używany przez SensorEvent API.

C = rysunek metody SensorManager.getOrientation (..)

Więc rozumiem, że A reprezentuje „światowy układ współrzędnych”, który, jak przypuszczam, odnosi się do sposobu, w jaki lokalizacje na planecie są podawane jako para (szerokość i długość geograficzna) z opcjonalną (wysokością). X to współrzędna „wschodnia” , Y to współrzędna „północna” . Z wskazuje na niebo i reprezentuje wysokość.

Układ współrzędnych telefonu pokazany na rysunku B jest stały. Jego oś Y zawsze wskazuje górę. Macierz rotacji jest na bieżąco obliczana przez telefon i umożliwia mapowanie między nimi. Czy mam więc rację, myśląc, że macierz rotacji przekształca układ współrzędnych z B na C? Więc kiedy wywołujesz SensorManager.getOrientation(..)metodę, używasz values[]tablicy z wartościami odpowiadającymi cyfrze C.Gdy telefon jest skierowany w niebo, macierz obrotu jest macierzą tożsamości (matematyczny odpowiednik 1), co oznacza, że ​​nie jest konieczne mapowanie, ponieważ urządzenie jest ustawione ze światowym układem współrzędnych.

Dobrze. Myślę, że lepiej przestanę teraz. Tak jak powiedziałem wcześniej, mam nadzieję, że ludzie powiedzą mi, gdzie zawiodłem lub pomogłem ludziom (lub jeszcze bardziej zdezorientowałem ludzi!)

Tim
źródło
25
Naprawdę podoba mi się to pytanie. Nie mogę odpowiedzieć, ale mi się podoba.
Octavian A. Damiean
4
Tim, czy kiedykolwiek dostałeś odpowiedź? Jednocześnie drapałem się po głowie. Jest to jedno z najsłabiej udokumentowanych API, jakie kiedykolwiek widziałem.
Pierre-Luc Paour
Nie bardzo się boję. Musiałem iść dalej. Kiedyś wrócę do tej kwestii.
Tim
1
Tutaj mam to samo pytanie, prawie? A także odpowiedź, rozwiązanie . Opublikowałem mój kod na Githubie.
to samo, nad czym się zastanawiam, zaimplementowałem kompas na urządzeniu z Androidem i działa poprawnie, jeśli skorzystałem z pomocy z Internetu, działa dobrze, ale mylące jest ... Załóżmy, że moje urządzenie jest ustawione na ziemi w moją stronę i jest skierowany na północ, biorę teraz telefon i kładę go pionowo nad głową bez twarzy, a twarz wciąż jest w moim kierunku. Po pierwsze, czy igła powinna zmienić kierunek i dlaczego. Myślę, że nie powinno, ponieważ nie zmieniłem kierunku, ale zmienia się w mojej aplikacji i wszystkich innych aplikacjach, które pobrałem. Czy ktoś może wyjaśnić, dlaczego?
Syed Raza Mehdi

Odpowiedzi:

26

Możesz zapoznać się z artykułem „ Jeden obrót ekranu zasługuje na inny ”. Wyjaśnia, dlaczego potrzebujesz macierzy rotacji.

Krótko mówiąc, czujniki telefonu zawsze używają tego samego układu współrzędnych, nawet gdy urządzenie jest obrócone.

W aplikacjach, które nie są zablokowane w jednej orientacji, układ współrzędnych ekranu zmienia się po obróceniu urządzenia. Tak więc, gdy urządzenie jest obracane z domyślnego trybu widoku, układ współrzędnych czujnika nie jest już taki sam, jak układ współrzędnych ekranu. Macierz rotacji w tym przypadku służy do przekształcenia A w C (B zawsze pozostaje niezmienne).

Oto fragment kodu, który pokazuje, jak można go używać.

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}
Octavian A. Damiean
źródło
4
wystarczy wspomnieć, że azymut, wysokość i przechylenie NIE są tym samym, co wyjście z przestarzałego czujnika OrientationSensor. orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360;znormalizuje azymut i if (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); }znormalizuje wysokość
Rafael T
@RafaelT i normalizować rolkę? A może to nie ma sensu?
Matthias
@RafaelT: Twoja normalizacja azymutu wydaje się mieć wpływ: wartości wahają się od [-180,180] do [0, 360]. Ale wartości tonu, które otrzymuję, są już w [-90,90], więc proponowana przez ciebie normalizacja nie ma żadnego efektu.
Matthias
Co to znaczy, że po sprawdzeniu (grawitacja! = Null && geomag! = Null), wartość geomag zawsze wynosi 0, niezależnie od tego, jak poruszam tabletem? Może to być tablet bez czujnika geomag?
Zaawansowany
3

Roll jest funkcją grawitacji, obrót o 90 stopni umieszcza całą grawitację w rejestrze x.

Skok jest taki sam, nachylenie o 90 stopni w górę umieszcza cały składnik grawitacji w rejestrze y.

Odchylenie / kurs / azymut nie ma wpływu na grawitację, jest ZAWSZE prostopadły do ​​grawitacji, więc bez względu na to, w którą stronę się zwrócisz, grawitacja będzie niemożliwa do zmierzenia.

Dlatego do oceny potrzebujesz kompasu, może to ma sens?

Craig
źródło
0

Miałem ten problem, więc nakreśliłem, co dzieje się w różnych kierunkach. Jeśli urządzenie jest zamontowane poziomo, np. W uchwycie samochodowym, „stopnie” od kompasu wydają się przebiegać od 0-275 (zgodnie z ruchem wskazówek zegara) powyżej 269 (między zachodem a północą), liczy się wstecz od -90 do 0, wtedy do przodu od 0 do 269. 270 staje się -90

Nadal w krajobrazie, ale z urządzeniem leżącym na plecach, mój czujnik podaje 0-360. aw trybie portretowym działa 0-360 zarówno leżąc na plecach, jak i stojąc w pionie.

Mam nadzieję, że to komuś pomoże

beznadziejny bob
źródło