2016-08-02 33 views
10

Potrzebuję orientacji urządzenia. Zwykle używam czujników TYPE_ACCELEROMETER i TYPE_MAGNETIC_FIELD. Mój problem polega na tym, że zwraca mi czujnik geomagnetyczny. Zwraca także czujnik null dla czujnika .Orientacja urządzenia z Androidem bez geomagnetycznego

manager = (SensorManager) getSystemService(SENSOR_SERVICE); 
Sensor sensorAcc = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), //normal object 
     sensorMagn = manager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); //null 
orientationListener = new OrientationSensorListener(); 
manager.registerListener(orientationListener, sensorAcc, 10); 
manager.registerListener(orientationListener, sensorMagn, 10); 

Potrzebuję innych sposobów na orientację urządzenia.

+0

postu kod. – Jas

+0

@Jas dodano do pytania – Ircover

+0

można wykorzystać szerokość i wysokość ekranu do określenia orientacji, w trybie poziomym zazwyczaj szerokość jest większa niż wysokość. – ashutiwari4

Odpowiedz

2

zrobiłem coś takiego:

public class MainActivity extends AppCompatActivity 
{ 
    SensorManager sensorManager; 
    Sensor sensor; 
    ImageView imageViewProtractorPointer; 

    ///////////////////////////////////// 
    ///////////// onResume ////////////// 
    ///////////////////////////////////// 
    @Override 
    protected void onResume() 
    { 
     super.onResume(); 
     // register sensor listener again if return to application 
     if(sensor !=null) sensorManager.registerListener(sensorListener,sensor,SensorManager.SENSOR_DELAY_NORMAL); 
    } 
    ///////////////////////////////////// 
    ///////////// onCreate ////////////// 
    ///////////////////////////////////// 
    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     imageViewProtractorPointer = (ImageView)findViewById(R.id.imageView2); 
     // get the SensorManager 
     sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); 
     // get the Sensor ACCELEROMETER 
     sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
    } 
    ///////////////////////////////////// 
    ///////////// onPause /////////////// 
    ///////////////////////////////////// 
    @Override 
    protected void onPause() 
    { 
     // Uninteresting the sensor listener to prevent battery drain if not in use 
     super.onPause(); 
     if(sensor !=null) sensorManager.unregisterListener(sensorListener); 
    } 

    ///////////////////////////////////////////// 
    /////////// SensorEventListener ///////////// 
    ///////////////////////////////////////////// 
    SensorEventListener sensorListener = new SensorEventListener() 
    { 
     @Override 
     public void onSensorChanged(SensorEvent sensorEvent) 
     { 
      // i will use values from 0 to 9 without decimal 
      int x = (int)sensorEvent.values[0]; 
      int y = (int)sensorEvent.values[1]; 
      int angle = 0; 

      if(y>=0 && x<=0) angle = x*10; 
      if(x<=0 && y<=0) angle = (y*10)-90; 
      if(x>=0 && y<=0) angle = (-x*10)-180; 
      if(x>=0 && y>=0) angle = (-y*10)-270; 

      imageViewProtractorPointer.setRotation((float)angle); 
     } 
     @Override 
     public void onAccuracyChanged(Sensor sensor, int i){} 
    }; 
} 

jeśli chcesz zrozumieć o moim if zobaczyć ten obraz image

dla mojego użytku i zablokować ekran w trybie pionowym i zastosowanie 2 obrazy, aby pokazać kąt na ekranie, to jest mój zrzut ekranu screenshot

Nadal muszę go trochę poprawić, po prostu za mało czasu.

Mam nadzieję, że ta pomoc, jeśli potrzebujesz pełnego kodu, daj mi znać.

1

Musisz dodać kilka uprawnień do manifestu. Docs stwierdza:

czujnik domyślne dopasowanie wymaganych właściwości Wakeup typ i jeśli taki istnieje a aplikacja posiada niezbędne uprawnienia lub null inaczej

Wiem, że brzmi sprzeczne z intuicją, ale najwyraźniej wymagane uprawnienia to:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/> 
<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 

(lub ich podzestaw).

Zobacz tutaj: manifest.xml when using sensors

+0

Jeśli mówisz o geomagnetycznym, próbowałem niektórych aplikacji kompasu - wszystkie mówią, że moje urządzenie nie potrzebuje czujnika. – Ircover

5

Orientacja może być rozłożona na trzy kąt Eulera: pochylenie, przechylenie i azymutu.

Tylko z danymi przyspieszeniomierza, nie można obliczyć Azymutu, ani znaku twojej wysokości.

Można spróbować czegoś jak to wiedzieć coś o swoim skoku i rolki:

private final float[] mMagnet = new float[3];    // magnetic field vector 
    private final float[] mAcceleration = new float[3];   // accelerometer vector 
    private final float[] mAccMagOrientation = new float[3]; // orientation angles from mAcceleration and mMagnet 
    private float[] mRotationMatrix = new float[9];    // accelerometer and magnetometer based rotation matrix 

    public void onSensorChanged(SensorEvent event) { 
    switch (event.sensor.getType()) { 
     case Sensor.TYPE_ACCELEROMETER: 
      System.arraycopy(event.values, 0, mAcceleration, 0, 3); // save datas 
      calculateAccMagOrientation();      // then calculate new orientation 
      break; 
     case Sensor.TYPE_MAGNETIC_FIELD: 
      System.arraycopy(event.values, 0, mMagnet, 0, 3);   // save datas 
      break; 
     default: break; 
    } 
} 
public void calculateAccMagOrientation() { 
    if (SensorManager.getRotationMatrix(mRotationMatrix, null, mAcceleration, mMagnet)) 
     SensorManager.getOrientation(mRotationMatrix, mAccMagOrientation); 
    else { // Most chances are that there are no magnet datas 
     double gx, gy, gz; 
     gx = mAcceleration[0]/9.81f; 
     gy = mAcceleration[1]/9.81f; 
     gz = mAcceleration[2]/9.81f; 
     // http://theccontinuum.com/2012/09/24/arduino-imu-pitch-roll-from-accelerometer/ 
     float pitch = (float) -Math.atan(gy/Math.sqrt(gx * gx + gz * gz)); 
     float roll = (float) -Math.atan(gx/Math.sqrt(gy * gy + gz * gz)); 
     float azimuth = 0; // Impossible to guess 

     mAccMagOrientation[0] = azimuth; 
     mAccMagOrientation[1] = pitch; 
     mAccMagOrientation[2] = roll; 
     mRotationMatrix = getRotationMatrixFromOrientation(mAccMagOrientation); 
    } 
} 
public static float[] getRotationMatrixFromOrientation(float[] o) { 
    float[] xM = new float[9]; 
    float[] yM = new float[9]; 
    float[] zM = new float[9]; 

    float sinX = (float) Math.sin(o[1]); 
    float cosX = (float) Math.cos(o[1]); 
    float sinY = (float) Math.sin(o[2]); 
    float cosY = (float) Math.cos(o[2]); 
    float sinZ = (float) Math.sin(o[0]); 
    float cosZ = (float) Math.cos(o[0]); 

    // rotation about x-axis (pitch) 
    xM[0] = 1.0f;xM[1] = 0.0f;xM[2] = 0.0f; 
    xM[3] = 0.0f;xM[4] = cosX;xM[5] = sinX; 
    xM[6] = 0.0f;xM[7] =-sinX;xM[8] = cosX; 

    // rotation about y-axis (roll) 
    yM[0] = cosY;yM[1] = 0.0f;yM[2] = sinY; 
    yM[3] = 0.0f;yM[4] = 1.0f;yM[5] = 0.0f; 
    yM[6] =-sinY;yM[7] = 0.0f;yM[8] = cosY; 

    // rotation about z-axis (azimuth) 
    zM[0] = cosZ;zM[1] = sinZ;zM[2] = 0.0f; 
    zM[3] =-sinZ;zM[4] = cosZ;zM[5] = 0.0f; 
    zM[6] = 0.0f;zM[7] = 0.0f;zM[8] = 1.0f; 

    // rotation order is y, x, z (roll, pitch, azimuth) 
    float[] resultMatrix = matrixMultiplication(xM, yM); 
    resultMatrix = matrixMultiplication(zM, resultMatrix); 
    return resultMatrix; 
} 
public static float[] matrixMultiplication(float[] A, float[] B) { 
    float[] result = new float[9]; 

    result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6]; 
    result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7]; 
    result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8]; 

    result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6]; 
    result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7]; 
    result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8]; 

    result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6]; 
    result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7]; 
    result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8]; 

    return result; 
} 
+0

Jak powiedział OP, nie może polegać na magnetometrze, podczas gdy twój kod tego wymaga. – strangetimes

+1

Niepoprawnie, mój kod reaguje, jeśli jest pusty i nadal zapewnia częściową orientację. –

1

można spróbować GEOMAGNETIC_ROTATION_VECTOR takiego:

private SensorManager mSensorManager; 
private Sensor mSensor; 
... 
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR) 

i obliczyć info czujnika z tym:

... 
// Rotation matrix based on current readings from accelerometer and magnetometer. 
final float[] rotationMatrix = new float[9]; 
mSensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading); 

// Express the updated rotation matrix as three orientation angles. 
final float[] orientationAngles = new float[3]; 
mSensorManager.getOrientation(rotationMatrix, orientationAngles); 

Wyodrębnione z dokumentów Android: https://developer.android.com/guide/topics/sensors/sensors_position.html

dodaj odpowiednie uprawnienia do manifestu.

Mam nadzieję, że to pomoże.

0

Dla każdego, kto nadal jest zdezorientowany przez ten problem, powiedz: chcesz uzyskać orientację telefonu (azymut, wysokość i przechylenie), ale czasami pole magnetyczne jest niestabilne, więc orientacja jaką otrzymujesz jest również nietrwały. Powyższe odpowiedzi mogą pomóc w określeniu kąta nachylenia i przechylenia, ale nadal nie można uzyskać kąta azymutu. Powiedzieli, że to niemożliwe. Wtedy stajesz się zdesperowany. Co więc należy zrobić, aby rozwiązać ten problem?

Jeśli tylko dbają o orientacji i nie obchodzi gdzie jest północ, tutaj jest moja propozycja, spróbuj tego czujnika, działa super w moim przypadku:

TYPE_GAME_ROTATION_VECTOR