Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。

陀螺仪

陀螺仪(Gyroscope sensor)测量设备转动的角速度。最早的陀螺仪发明在中国,科学应用则在西方,陀螺仪是为士大夫坐轿子看书是免收烛光摇曳发明的,这在很久之前一部西方拍的科教片看到,具体名字忘了。Pro Android 4.0中说陀螺仪的误差会慢慢积累,因此通与加速传感器一致使用,通过Kalman filter进行修正。我们只简单地进行陀螺仪数据的读取。小例子和之前的很相似,我们只提供不同部分的代码片段。

public class GyroscopeSensorActivity extends Activity implements SensorEventListener{ 
    ……     
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        ……
        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 
    }
   
    …… //注册和注销传感器的监听器

   @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {  …  }

    @Override  /* 对于陀螺仪,测量的是x、y、z三个轴向的角速度,分别从values[0]、values[1]、values[2]中读取,单位为弧度/秒。*/
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_GYROSCOPE)
            showInfo("事件:" + " x:" + event.values[0] + " y:" + event.values[1]  + " z:" + event.values[2]);
    }
   
    //在华为P6的机器上,陀螺仪非常敏感,平放在桌面,由于电脑照成的轻微震动在不断地刷屏,为了避免写UI造成的性能问题,只写Log。
    private void showInfo(String info){
        //tv.append("\n" + info);
        Log.d("陀螺仪",info);
    }
}

Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器_第1张图片

加速度传感器(acceleration)

Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器_第2张图片

加速度测量传感器有x、y、z三轴,注意和2D屏幕的坐标,以左上角作为原点的,而且Y向下。注意区分这两个不同的坐标系。

加速传感器的单位是加速度m/s2。如果手机平放好,x,y在位置为0,而z轴方向加速度=当前z方向加速度-g。由于g(重力加速度)垂直向下,则g=-9.81m/s2,即z轴 a=0-(-9.81)=9.81m/s2。也就是自由落体是为0。x、y、z的测量的加速度分别位于value[0]、value[1]、value[2]。

相关的代码和前面大同小异,我们就不再重复,传感器类型为Sensor.TYPE_ACCELEROMETER。减去重力这很重要,当设备静止或者匀速运动时,可以获得设备的角度。

Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器_第3张图片

我记得至少两年前,单位请一互联网专家讲课,提到了AR(增强现实),问靠什么传感器,其答案为陀螺仪,这是不对的,陀螺仪可以测量运动过程中的角速度,但要测量手机本身的角度,这靠的是加速仪器,因为有重力方向作为校准。

Android也提供了检测手机旋转角度的API,用于UI绘制,实际靠的就是加速传感器。

WindowManager window = (WindowManager)getSystemService(WINDOW_SERVICE);
//返回值为Surface.ROTATION_0(0)、Surface.ROTATION_90(1)、Surface.ROTATION_180(2)和Surface.ROTATION_270(3),可以用来确定屏幕UI的旋转方向。注意:需要开启“自动旋转”才能有效检查,否则均为Surface.ROTATION_0(手机以竖屏为主,一般都会0,但不保证都如此)。不是所以的手机都能检测到这4个值,例如我的P6,没有Surface.ROTATION_180,即UI不支持倒过来,如果有某个数值不支持,通过getRotation()获取的数值可能并不准确,仍以P6为例,如果我们顺时针转90°,得到Surface.ROTATION_90,继续顺时针转至180°,无检测新数值,仍未Surface.ROTATION_90,再继续顺时针转90°(至270°),仍显示为Surface.ROTATION_90,而非Surface.ROTATION_270。
int rotation = window.getDefaultDisplay().getRotation(); //在Android2.2之前,为Display.getOrientation(),如果出现API和SDK 的API level相关,可通过Build.VERSION.SDK_INT获得。

我们将手机平放在桌子上,通过加速度测量仪的x、y、z轴的数值,x、y为0,z为g,可以进行判断,但是我们并不知道具体的朝向,平放是朝南还是向北,这需要地磁感应器,将在后面介绍。

下面的小例子,我们将对加速度测量仪的x,y,z数值进行修正处理,减去重力加速度,得到我们这个惯性系的加速度,并根据设备的Y轴与垂直地面方向(重力反方向)的夹角。相关的代码片段如下:

Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器_第4张图片 ……

private float[] gravity = new float[3];   //重力在设备x、y、z轴上的分量
private float[] motion = new float[3];  //过滤掉重力后,加速度在x、y、z上的分量
private double ratioY;
private double angle;
private int counter = 1;

@Override
public void onSensorChanged(SensorEvent event) { 
    for(int i = 0 ; i < 3; i ++){
        /* accelermeter是很敏感的,看之前小例子的log就知道。因为重力是恒力,我们移动设备,它的变化不会太快,不象摇晃手机这样的外力那样突然。因此通过low-pass filter对重力进行过滤。这个低通滤波器的权重,我们使用了0.1和0.9,当然也可以设置为0.2和0.8。 */
        gravity[i] = (float) (0.1 * event.values[i] + 0.9 * gravity[i]);
        motion[i] = event.values[i] - gravity[i];
    }
   
    //计算重力在Y轴方向的量,即G*cos(α)
    ratioY = gravity[1]/SensorManager.GRAVITY_EARTH;
    if(ratioY > 1.0)
        ratioY = 1.0;
    if(ratioY < -1.0)
        ratioY = -1.0;
    //获得α的值,根据z轴的方向修正其正负值。
    angle = Math.toDegrees(Math.acos(ratioY));
    if(gravity[2] < 0)
        angle = - angle;
   
    //避免频繁扫屏,每10次变化显示一次值
    if(counter ++ % 10 == 0){
        tv.setText("Raw Values : \n"
                +  "   x,y,z = "+ event.values[0] + "," + event.values[1] + "," + event.values[2] + "\n"
                +  "Gravity values : \n"
                +  "   x,y,z = "+ gravity[0] + "," + gravity[1] + "," + gravity[2] + "\n"
                +  "Motion values : \n"
                +  "   x,y,z = "+ motion[0] + "," + motion[1] + "," + motion[2] + "\n"
                +  "Y轴角度 :" + angle    );
        tv.invalidate();
        counter = 1;
    }    
}

……

motion[3]是过滤重力后的数值,如果各值如果非常接近0,表示设备没有被移动。

相关小例子代码: Pro Android学习:传感器小例子

相关链接:我的Android开发相关文章

你可能感兴趣的:(Pro Android学习笔记(一五四):传感器(4):陀螺仪、加速传感器)