我需要获得设备方向。据我所知,通常使用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);
我需要另外一种方法来获取设备。
答案 0 :(得分:8)
方向可以分为三个欧拉角:俯仰,滚转和方位角。
仅使用加速度计数据,您无法计算方位角,也无法计算您的俯仰角。
你可以尝试这样的东西来了解你的俯仰和滚动:
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;
}
答案 1 :(得分:3)
要在设备不平坦时获得旋转角度,请执行OrientationEventListener
。 onOrientationChanged
将为设备提供方向。有关详细信息,请参阅https://developer.android.com/reference/android/view/OrientationEventListener.html。
答案 2 :(得分:2)
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()
{
// Unregister 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){}
};
}
供我使用我以纵向模式锁定屏幕,并使用2张图像在屏幕上显示角度,这是我的屏幕截图
我仍然需要做得更好,只是没有足够的时间。
我希望这有帮助,如果您需要完整的代码,请告诉我。
答案 3 :(得分:1)
您必须向清单添加一些权限。文档说明:
默认传感器匹配请求的类型和wakeUp属性(如果存在且应用程序具有必要的权限),否则为null
我知道这听起来很直观,但显然你需要的权限是:
from collections import defaultdict
import operator
# Binary counter
# (Current state, Current symbol) : (New State, New Symbol, Move)
rules = {
(0, 1): (0, 1, 1),
(0, 0): (0, 0, 1),
(0, None): (1, None, -1),
(1, 0): (0, 1, 1),
(1, 1): (1, 0, -1),
(1, None): (0, 1, 1),
}
# from here I don't really understand what's going on
def tick(state=0, tape=defaultdict(lambda: None), position=0):
state, tape[position], move = rules[(state, tape[position])]
return state, tape, position + move
system = ()
for i in range(255):
system = tick(*system)
if(system[2] == 0):
print(map(operator.itemgetter(1), sorted(system[1].items())))
(或其中的子集)。
答案 4 :(得分:1)
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
答案 5 :(得分:1)
您可以尝试使用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
在清单中添加适当的权限。
希望这有帮助。
答案 6 :(得分:0)
对于仍然对此问题感到困惑的人,请说:你想获得手机的方向(方位角,俯仰和滚动),但有时磁场不稳定,所以你得到的方向也不稳定。上面的答案可以帮助你获得俯仰和滚转角度,但你仍然无法获得方位角。他们说这是不可能的。然后你变得绝望。那么,你应该怎么做才能解决这个问题呢?
如果你只关心这个方向而你不关心北方的位置,这是我的建议,试试这个传感器,它在我的情况下很棒:
TYPE_GAME_ROTATION_VECTOR