天天看点

陀螺仪、加速计、磁力计等传感器汇总

陀螺仪、加速计、磁力计等传感器汇总  

陀螺仪就是内部有一个陀螺,它的轴由于陀螺效应始终与初始方向平行,这样就可以通过与初始方向的偏差计算出实际方向。手机里陀螺仪实际上是一个结构非常精密的芯片,内部包含超微小的陀螺。

加速计是用来检测手机受到的加速度的大小和方向的,而手机静置的时候是只受到重力加速度(这个高中学过)的.所以很多人把加速计功能又叫做重力感应功能。

磁力计是测试磁场强度和方向的。

陀螺仪测量是参考标准是内部中间在与地面垂直的方向上进行转动的陀螺。通过设备与陀螺的夹角得到结果。

加速计是以内部测量组件在各个方向上的受力情况来得到结果。

磁力计的原理就是中学物理中涉及到的那个最简单的指南针了(那记得那根被磁化的钢针么)。

它们分别有自己的强项:

陀螺仪的强项在于测量设备自身的旋转运动。对设备自身运动更擅长。但不能确定设备的方位。

加速计的强项在于测量设备的受力情况。对设备相对外部参考物(比如,地面)的运动更擅长。但用来测量设备相对于地面的摆放姿势,则精确度不高。

磁力计的强项在于定位设备的方位。可以测量出当前设备与东南西北四个方向上的夹角。

举几个例子:

陀 螺仪对设备旋转角度的检测是瞬时的而且是非常精确的,能满足一些需要高分辨率和快速反应的应用比如FPS游戏的瞄准。而且陀螺仪配合加速计可以在没有卫星 和网络的情况下进行导航,这是陀螺仪的经典应用。加速度计可用于有固定的重力参考坐标系、存在线性或倾斜运动但旋转运动被限制在一定范围内的应用。同时处 理直线运动和旋转运动时,就需要把加速度和陀螺仪计结合起来使用。如果还想设备在运动时不至于迷失方向,就再加上磁力计。

对于一个发射出去的导弹来说,要想精确追踪并调整导弹的轨道的话,下面几组数据必不可少:

GPS定位它的位置

加速计测量当前加速度

磁力计确定导弹头的方向(只能知道东南西北四个方向上的夹角),陀螺仪知道导弹的角速度。这两个仪器结合才能确定导弹的准确的立体运动方向。

加速计得到的结果就是XYZ三个值,分别代表三个方向的加速度。关于XYZ三值的介绍,可以看这里:

android 重力感应和屏幕旋转关系

http://blog.csdn.net/lzx_bupt/archive/2010/04/20/5507165.aspx

用加速计和磁力计可以计算出orientation(方位计),orientation涉及到了三个概念:

Roll:左右倾斜角度,也叫滚转角 http://baike.baidu.com/view/1769672.htm

Pitch:前后倾斜,也叫俯仰角 http://baike.baidu.com/view/3832041.htm

Yaw:左右摇摆,也叫偏航角 http://baike.baidu.com/view/1769448.htm

下 面代码是Android2.3中/development/samples/Compass的源码,演示了如何使用加速计和磁力计来确定手机的摆放姿势和 方位。因为手机运动的加速度不高,精确度也没有太大的要求,用加速计替代陀螺仪也可以。但如果做一些精度比较高的游戏的话,最好还是有陀螺仪。

view plain

  1. // 打开加速计和磁力计两个传感器。 Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_GAME);mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_GAME);// 加速计数据。private float[] mGData = new float[3];//磁力计数据。 private float[] mMData = new float[3];//旋转矩阵(rotation matrix),用于计算手机自身相对 于地面坐标系的旋转角度。比如手机现在是横着还是竖着的。反映的是手机的立体摆放位置。这个数据最好用陀螺仪来测量,没有陀螺仪的话,借助于加速计和重力 加速度也可以,只是精度不够强罢了。private float[] mR = new float[16];//倾斜矩阵 (inclination matrix),用于计算手机方位。比如手机的头部现在朝南还是朝北。是针对一个平面上的东南西北四个方向而言的。 private float[] mI = new float[16];//存放最终的旋转角度数据 private float[] mOrientation = new float[3]; public void onSensorChanged(SensorEvent event) {        int type = event.sensor.getType();        float[] data;        if (type == Sensor.TYPE_ACCELEROMETER) {            data = mGData;        } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {            data = mMData;        } else {            // we should not be here.            return;        }        for (int i = 0; i & lt; 3; i++)            data[i] = event.values[i];//这一步的目的是获取mR和mI两个矩 阵。        SensorManager.getRotationMatrix(mR, mI, mGData, mMData);//用矩阵 mR获取手机的旋转角度。        SensorManager.getOrientation(mR, mOrientation);//用矩阵 mI获取手机在东南西北四个方向上的夹 角。        float incl = SensorManager.getInclination(mI);        final float rad2deg = (float) (180.0f / Math.PI);        Log.d("Compass", "yaw: " + (int)(mOrientation[0] * rad2deg) + "  pitch: " + (int)(mOrientation[1] * rad2deg) + "  roll: " + (int)(mOrientation[2] * rad2deg) + "  incl: " + (int)(incl * rad2deg));}  

补充于2011.7.14

gsensor的较正比较容易完成,一般是让机器以某个固定角度(比如水平)放置,然后连续取N个值(比如20个)进行一系列计算。Android和iphone中,屏幕会随着设备的旋转方向变化而改变,其实应用的只是gsensor。

msensor 的较正分为水平较正和倾斜补偿。水平较正有平面较正、8字较正、十面较正等几种方法。经过水平较正后,msensor在水平放置时已经可以使用了,但设备 与水平面有一定的倾斜角时,这个倾斜角会对msensor的精度造成影响。因此,还需要进行倾斜角补偿较正。先通过较正好的gsensor得出倾斜角,然 后使用倾斜角(pitch,roll)进行补偿较正计算。

orientation sensor可以由一个单独芯片来实现,也可以由gsensor和msensor共同计算出来的(我看android2.3的Sample中的 Compass就已经这样干了)。orientation sensor输出三个值:roll,pitch,yaw。其中,roll和pitch分别代表手机的X轴和Y轴与水平面的夹角,所以这两个值可以由 gsensor计算出来。yaw代表手机y轴水平面上的投影与正北方向的夹角,由msensor计算出来。

陀螺仪可以捕捉很微小的运动轨迹变化,因此可以做高分辨率和快速反应的旋转检测。但不能像msensor或orientation sensor那样测量当前的运行方向。飞机当中就用它记录运动角度改变,从而形成运动轨迹。缺点就是随着时间增长会有误差积累,

补充于2011.7.19

陀螺仪的XYZ分别代表设备围绕XYZ三个轴旋转的角速度:radians/second。至于XYZ使用的坐标系与gsensor相同。逆时针方向旋转时,XYZ的值是正的。下面是使用陀螺仪进行开发时的演示代码:

view plain

  1. private static final float NS2S = 1.0f / 1000000000.0f;  
  2. private float timestamp;  
  3. public void onSensorChanged(SensorEvent event)  
  4. {  
  5.    if (timestamp != 0) {  
  6.        final float dT = (event.timestamp - timestamp) * NS2S;  
  7.        angle[0] += event.data[0] * dT;  
  8.        angle[1] += event.data[1] * dT;  
  9.        angle[2] += event.data[2] * dT;  
  10.    }  
  11.    timestamp = event.timestamp;  
  12. }  

另外,陀螺仪运转一段时间以后,noise和offset会导致数据偏差,需要借助其它传感器进行较正。

补充于2011.7.20

利用加速计(gsensor),磁力计(msensor)模拟出方位传感器(orientation)来

Android最近的新版本已经不建议我们在开发的时候像下面这样直接用方位传感器了:

Sensor ori = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

mSensorManager.registerListener(this, ori, SensorManager.SENSOR_DELAY_GAME);

而 是建议使用SensorManager.getOrientation(mR, mOrientation)这个API自己在应用程序的onSensorChanged中计算出方位传感器。但我们在做HAL层时,却不得不考虑一些 APK还是像上面代码那样直接使用方位传感器的情况,所以,我们必须在sensor.c中模拟出一个方位传感器来:

激活方位传感器时,同时激活加速计和磁力计,关闭方位传感器时也要同时关闭加速计和磁力计,同时还要考虑如果用户注册了加速计或磁力计,并且正在使用的情况。

view plain

  1. //默认状态,0代表关闭。  
  2. static int accStatus = 0;  
  3. static int magStatus = 0;  
  4. static int switchSensor(int fd, int handle, int enabled) {  
  5.     int status = 0;  
  6.     switch (handle) {  
  7.     case ID_ACCELERATION:  
  8.         if (enabled) {  
  9.             if (!accStatus) {//=0说明当前状态是关闭时,执行打开操作。否则,说明已经打开过。  
  10.                 status = ioctl(fd, ACC_FLAG, 1);  
  11.                 LOGW("open gsensor");  
  12.             }  
  13.             accStatus++;  
  14.         } else {  
  15.             if (accStatus > 0) {//>0说明当前状态是打开,这个时候才会尝试关闭gsensor。  
  16.                 accStatus--;  
  17.                 if (!accStatus) {//减1后如果==0,说明orientation没有使用gsensor,可以关闭gsensor了  
  18.                     status = ioctl(fd, ACC_FLAG, 0);  
  19.                     LOGW("close gsensor");  
  20.                 }  
  21.             }  
  22.         }  
  23.         break;  
  24.     case ID_MAGNETIC:  
  25.         if (enabled) {  
  26.             if (!magStatus) {  
  27.                 status = ioctl(fd, MAG_FLAG, 1);  
  28.                 LOGW("open msensor");  
  29.             }  
  30.             magStatus++;  
  31.         } else {  
  32.             if (magStatus > 0) {  
  33.                 magStatus--;  
  34.                 if (!magStatus) {  
  35.                     status = ioctl(fd, MAG_MFLAG, 0);  
  36.                     LOGW("close msensor");  
  37.                 }  
  38.             }  
  39.         }  
  40.         break;  
  41.     case ID_ORIENTATION:  
  42.         if (enabled) {  
  43.             if (!accStatus) {//=0说明gsensor没有打开过,直接打开。  
  44.                 status = ioctl(fd, ACC_AFLAG, 1);  
  45.                 LOGW("open msensor");  
  46.             }  
  47.             if (!magStatus) {  
  48.                 status = ioctl(fd, MAG_FLAG, 1);  
  49.                 LOGW("open msensor");  
  50.             }  
  51.             accStatus++;  
  52.             magStatus++;  
  53.         } else {  
  54.             if (accStatus > 0) {//>0说明被打开过,尝试关闭gsensor。  
  55.                 accStatus--;  
  56.                 if (!accStatus) {//减1后=0说明用户没有直接使用gsensor,只是使用了orientation,可以关闭gsensor了。  
  57.                     status = ioctl(fd, ACC_AFLAG, 0);  
  58.                     LOGW("close gsensor");  
  59.                 }  
  60.             }  
  61.             if (magStatus > 0) {  
  62.                 magStatus--;  
  63.                 if (!magStatus) {  
  64.                     status = ioctl(fd, MAG_FLAG, 0);  
  65.                     LOGW("close msensor");  
  66.                 }  
  67.             }  
  68.         }  
  69.         break;  
  70.     default:  
  71.         LOGW("unsupported sensor type");  
  72.     }  
  73.     return status;  
  74. }  

参考文章:

加速度计和陀螺仪的区别

http://www.cnblogs.com/liuq0s/archive/2010/09/02/1816394.html

三轴陀螺仪与加速度计如何辅助Iphone定位的

http://www.weizhiquan.com/archives/1072

ST集成传感器方案实现电子罗盘功能

http://www.eeworld.com.cn/gykz/2011/0408/article_5352.html

Android设备中实现陀螺仪(Orientation Sensor)

http://blog.csdn.net/beeboobeeboo/article/details/6536941

简单易懂的文字 带你认识iPhone 4陀螺仪

http://mobile.zol.com.cn

继续阅读