加速度感測器,磁場感測器和陀螺儀感測器案例
- Sensor.TYPE_GYROSCOPE
陀螺儀就是內部有一個陀螺,它的軸由於陀螺效應始終與初始方向平行,這樣就可以通過與初始方向的偏差計算出實際方向。手機裡陀螺儀實際上是一個結構非常精密的晶片,內部包含超微小的陀螺。
陀螺儀測量是參考標準是內部中間在與地面垂直的方向上進行轉動的陀螺。通過裝置與陀螺的夾角得到結果。
陀螺儀的強項在於測量裝置自身的旋轉運動。對裝置自身運動更擅長。但不能確定裝置的方位。
陀螺儀對裝置旋轉角度的檢測是瞬時的而且是非常精確的,能滿足一些需要高解析度和快速反應的應用比如FPS遊戲的瞄準。而且陀螺儀配合加速計可以在沒有衛星和網路的情況下進行導航,這是陀螺儀的經典應用。同時處理直線運動和旋轉運動時,就需要把加速度和陀螺儀計結合起來使用。如果還想裝置在運動時不至於迷失方向,就再加上磁力計。
因為手機運動的加速度不高,精確度也沒有太大的要求,用加速計替代陀螺儀也可以。但如果做一些精度比較高的遊戲的話,最好還是有陀螺儀。
陀螺儀的XYZ分別代表裝置圍繞XYZ三個軸旋轉的角速度:radians/second。至於XYZ使用的座標系與gsensor相同。逆時針方向旋轉時,XYZ的值是正的。
所以需要角速度與時間積分計算角度,得到的角度變化量與初始角度相加,就得到目標角度,其中積分時間Dt越小,輸出角度越準 但陀螺儀的原理決定了它的測量基準是自身,並沒有系統外的絕對參照物,加上Dt是不可能無限小 所以積分的累積誤差會隨著時間流逝迅速增加,最終導致輸出角度與實際不符,所以陀螺儀只能工作在相對較短的時間尺度內
下面是使用陀螺儀進行開發時的演示程式碼:
/**
* 功能:採集加速度感測器,磁場感測器和陀螺儀感測器的資料,得到感測器從外界採集資料的時間間隔
* @authorjarlen
*
*/
publicclass MainActivityextends Activityimplements SensorEventListener {
private SensorManagersensorManager;
private SensormagneticSensor;
private TextViewshowTextView;
private SensoraccelerometerSensor;
private
// 將納秒轉化為秒
privatestatic finalfloat NS2S = 1.0f / 1000000000.0f;
privatefloattimestamp;
privatefloatangle[] =newfloat[3];
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showTextView = (TextView) findViewById(R.id.showTextView);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
magneticSensor =sensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
accelerometerSensor =sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
gyroscopeSensor =sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
//註冊陀螺儀感測器,並設定感測器嚮應用中輸出的時間間隔型別是SensorManager.SENSOR_DELAY_GAME(20000微秒)
//SensorManager.SENSOR_DELAY_FASTEST(0微秒):最快。最低延遲,一般不是特別敏感的處理不推薦使用,該模式可能在成手機電力大量消耗,由於傳遞的為原始資料,訴法不處理好會影響遊戲邏輯和UI的效能
//SensorManager.SENSOR_DELAY_GAME(20000微秒):遊戲。遊戲延遲,一般絕大多數的實時性較高的遊戲都是用該級別
//SensorManager.SENSOR_DELAY_NORMAL(200000微秒):普通。標準延時,對於一般的益智類或EASY級別的遊戲可以使用,但過低的取樣率可能對一些賽車類遊戲有跳幀現象
//SensorManager.SENSOR_DELAY_UI(60000微秒):使用者介面。一般對於螢幕方向自動旋轉使用,相對節省電能和邏輯處理,一般遊戲開發中不使用
sensorManager.registerListener(this,gyroscopeSensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this,magneticSensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this,accelerometerSensor,
SensorManager.SENSOR_DELAY_GAME);
}
//座標軸都是手機從左側到右側的水平方向為x軸正向,從手機下部到上部為y軸正向,垂直於手機螢幕向上為z軸正向
@Override
publicvoid onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// x,y,z分別儲存座標軸x,y,z上的加速度
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 根據三個方向上的加速度值得到總的加速度值a
float a = (float) Math.sqrt(x * x + y * y + z * z);
System.out.println("a---------->" + a);
// 感測器從外界採集資料的時間間隔為10000微秒
System.out.println("magneticSensor.getMinDelay()-------->"
+magneticSensor.getMinDelay());
// 加速度感測器的最大量程
System.out.println("event.sensor.getMaximumRange()-------->"
+ event.sensor.getMaximumRange());
System.out.println("x------------->" + x);
System.out.println("y------------->" + y);
System.out.println("z------------->" + z);
Log.d("jarlen","x------------->" + x);
Log.d("jarlen","y------------>" + y);
Log.d("jarlen","z----------->" + z);
//showTextView.setText("x---------->" + x + "\ny-------------->" +
//y + "\nz----------->" + z);
}else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// 三個座標軸方向上的電磁強度,單位是微特拉斯(micro-Tesla),用uT表示,也可以是高斯(Gauss),1Tesla=10000Gauss
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 手機的磁場感應器從外部採集資料的時間間隔是10000微秒
System.out.println("magneticSensor.getMinDelay()-------->"
+magneticSensor.getMinDelay());
// 磁場感應器的最大量程
System.out.println("event.sensor.getMaximumRange()----------->"
+ event.sensor.getMaximumRange());
System.out.println("x------------->" + x);
System.out.println("y------------->" + y);
System.out.println("z------------->" + z);
//
// Log.d("TAG","x------------->" + x);
// Log.d("TAG", "y------------>" + y);
// Log.d("TAG", "z----------->" + z);
//
// showTextView.setText("x---------->" + x + "\ny-------------->" +
// y + "\nz----------->" + z);
}else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
//從 x、y、z 軸的正向位置觀看處於原始方位的裝置,如果裝置逆時針旋轉,將會收到正值;否則,為負值
if(timestamp != 0){
// 得到兩次檢測到手機旋轉的時間差(納秒),並將其轉化為秒
finalfloat dT = (event.timestamp -timestamp) * NS2S;
// 將手機在各個軸上的旋轉角度相加,即可得到當前位置相對於初始位置的旋轉弧度
angle[0] += event.values[0] * dT;
angle[1] += event.values[1] * dT;
angle[2] += event.values[2] * dT;
// 將弧度轉化為角度
float anglex = (float) Math.toDegrees(angle[0]);
float angley = (float) Math.toDegrees(angle[1]);
float anglez = (float) Math.toDegrees(angle[2]);
System.out.println("anglex------------>" + anglex);
System.out.println("angley------------>" + angley);
System.out.println("anglez------------>" + anglez);
System.out.println("gyroscopeSensor.getMinDelay()----------->" +
gyroscopeSensor.getMinDelay());
}
//將當前時間賦值給timestamp
timestamp = event.timestamp;
}
}
@Override
publicvoid onAccuracyChanged(Sensor sensor, int accuracy) {
//TODO Auto-generated method stub
}
@Override
protectedvoid onPause() {
//TODO Auto-generated method stub
super.onPause();
sensorManager.unregisterListener(this);
}
}