Ориентация устройства Android без геомагнитного
Мне нужно получить ориентацию устройства. Как я обычно знаю, используются датчики TYPE_ACCELEROMETER
и TYPE_MAGNETIC_FIELD
. Моя проблема в том, что SensorManager.getDefaultSensor
возвращает мне null
для геомагнитного датчика. Он также возвращает null
для датчика TYPE_ORIENTATION
.
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);
Мне нужны еще несколько способов получить ориентацию устройства.
Ответы
Ответ 1
Ориентация может быть разложена в три угла Эйлера: шаг, ролл и азимут.
С использованием только данных акселерометра вы не можете вычислить свой азимут, ни знак вашего тона.
Вы можете попробовать что-то в этом роде, чтобы узнать что-то о своем подаче и качке:
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;
}
Ответ 2
Чтобы получить угол поворота, когда устройство не является плоским, реализует OrientationEventListener
. onOrientationChanged
даст ориентацию устройства. Подробнее см. https://developer.android.com/reference/android/view/OrientationEventListener.html.
Ответ 3
Я сделал что-то вроде:
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){}
};
}
если вы хотите понять, что мои утверждения if видят это изображение
![image]()
для моего использования я блокирую экран в портретном режиме и использую 2 изображения, чтобы показать угол на экране, это мой скриншот
![screenshot]()
Мне все равно нужно сделать это немного лучше, просто не хватает времени для этого.
Я надеюсь, что эта помощь, если вам нужен полный код, дайте мне знать.
Ответ 4
Вы должны добавить некоторые разрешения манифеста. В документах указано:
датчик по умолчанию, соответствующий свойствам запрашиваемого типа и wakeUp, если существует , и приложение имеет необходимые разрешения или null иначе
Я знаю, что это похоже на интуитивно понятный, но, видимо, требуемые разрешения:
<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"/>
(или их подмножество).
Смотрите здесь: manifest.xml при использовании датчиков
Ответ 5
https://developer.android.com/guide/topics/sensors/sensors_position.html
https://developer.android.com/guide/topics/sensors/sensors_motion.html
https://developer.android.com/guide/topics/sensors/sensors_overview.html
Какой датчик для вращающегося телефона Android?
Ответ 6
Вы можете попробовать GEOMAGNETIC_ROTATION_VECTOR следующим образом:
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)
И вычислите информацию о датчике следующим образом:
...
// 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);
Извлечен из android docs: https://developer.android.com/guide/topics/sensors/sensors_position.html
добавьте правильные разрешения в манифест.
Надеюсь, что это поможет.
Ответ 7
Для тех, кто все еще путается этой проблемой, скажите: вы хотите получить ориентацию своего телефона (азимут, шаг и рулон), но иногда магнитное поле неустойчиво, так что ориентация, которую вы получаете, также нестабильна, Ответы выше могут помочь вам получить угол наклона и наклона, но вы по-прежнему не можете получить азимутальный угол. Они сказали, что это невозможно. Тогда вы становитесь отчаянным. Итак, что вы должны сделать, чтобы решить эту проблему?
Если вы только заботитесь о ориентации, и вам не важно, где находится север, вот мое предложение, попробуйте этот датчик, он работает потрясающе в моем случае:
TYPE_GAME_ROTATION_VECTOR