论坛首页 移动开发技术论坛

手机晃动检测

浏览 19854 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2010-07-18   最后修改:2010-07-18
想开发一个应用,其中有个技术点是手机晃动的检测,请问android 中如何实现?,目前知道如何获取重力感应的参数,可是如何准确的识别出一些简单的动作还在研究,有没有物理引擎可以用的?

目前的需求是,统计手机晃动了几次,是上下晃动,还是左右晃动,是前倾还是后仰之类的。

有关注同样问题的朋友,欢迎一起交流讨论!
   发表时间:2010-07-20  
应该有相关API的,我看豆瓣电台都实现了
0 请登录后投票
   发表时间:2010-07-21   最后修改:2010-07-21
iphone央视广告有个放鞭炮的程序就是摇的,andriod应该也有,手机厂商提供吧
0 请登录后投票
   发表时间:2010-07-21  
厂商提供的只是传感器的api,具体的检测公式需要自己去实现。

目前还在研究中
0 请登录后投票
   发表时间:2010-07-22  
2.1支持来电晃动停止,应该也有API
0 请登录后投票
   发表时间:2010-07-26   最后修改:2010-07-26
感谢lordhong 的帖子,很受启发,原文大家可以看看:

http://www.iteye.com/topic/369974

关键是动作改变时监听器的位置判断:

x = values[SensorManager.DATA_X];
				y = values[SensorManager.DATA_Y];
				z = values[SensorManager.DATA_Z];

				float speed = Math.abs(x + y + z - last_x - last_y - last_z)
						/ diffTime * 10000;


我照此,实现了基本的晃动检测
0 请登录后投票
   发表时间:2010-07-26  
这段代码也是我在论坛里面找到的,是根据传感器动态绘制小球的位置,并且实时显示位置、加速度等信息,大家可以参考:


package com.kelaocai.demo.sensor;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.hardware.*;
import android.util.Log;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
public class Main extends Activity
{
/** Tag string for our debug logs */
private static final String TAG = "Sensors";
private SensorManager mSensorManager;
private GraphView mGraphView;
private class GraphView extends View implements SensorListener
{
  private Bitmap mBitmap;
  private Paint mPaint = new Paint();
  private Canvas mCanvas = new Canvas();
  private Path mPath = new Path();
  private RectF mRect = new RectF();
  private float mLastValues[] = new float[3 * 2];
  private float mOrientationValues[] = new float[3];
  private int mColors[] = new int[3 * 2];
  private float mLastX;
  private float mScale[] = new float[2];
  private float mYOffset;
  private float mMaxX;
  private float mSpeed = 1.0f;
  private float mWidth;
  private float mHeight;
  private int a;
  private Paint p = new Paint();
  private int movex=0,movey=0;
  private int x=150,y=200;
  public GraphView(Context context)
  {
   super(context);
   mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
   mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
   mPath.arcTo(mRect, 0, 180);
   p.setTextSize(20);
   movex=0;movey=0;
  }
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh)
  {
   mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
   mCanvas.setBitmap(mBitmap);
   mCanvas.drawColor(0xFFFFFFFF);
   mYOffset = h * 0.5f;
   mScale[0] = -(h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
   mScale[1] = -(h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
   mWidth = w;
   mHeight = h;
   if (mWidth < mHeight)
   {
    mMaxX = w;
   } else
   {
    mMaxX = w - 50;
   }
   mLastX = mMaxX;
   super.onSizeChanged(w, h, oldw, oldh);
  }
  @Override
  protected void onDraw(Canvas canvas)
  {
   synchronized (this)
   {
    if (mBitmap != null)
    {
     final Paint paint = mPaint;
     final Path path = mPath;
     final int outer = 0xFFC0C0C0;
     final int inner = 0xFFff7010;
     canvas.drawBitmap(mBitmap, 0, 0, null);
     canvas.drawText("方位:" + mOrientationValues[0], 50, 50, p);
     canvas.drawText("竖斜度" + mOrientationValues[1], 50, 100, p);
     canvas.drawText("横斜度:" + mOrientationValues[2], 50, 150, p);
                   
     canvas.drawText("x:" + mLastValues[0], 50, 200, p);
     canvas.drawText("y:" + mLastValues[1], 50, 250, p);
     canvas.drawText("z:" + mLastValues[2], 50, 300, p);
     movey=(int)(mOrientationValues[1]);
     movex=(int)(mOrientationValues[2]);
     
     x=x+movex;
     y=y-movey;
     
     if(x<0)x=0;
     if(y<0)y=0;
     if(x>canvas.getWidth()-10)x=canvas.getWidth()-10;
     if(y>canvas.getHeight()-60)y=canvas.getHeight()-60;
     canvas.drawText("" +x, 50, 400, p);
     canvas.drawText("" +y, 100, 400, p);
     canvas.drawArc(new RectF( x, y, x+10, y+10), 0, 360, false, p);
    }
   }
  }
  public void onSensorChanged(int sensor, float[] values)
  {
   // Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " +
   // values[1] + ", z: " + values[2]);
   synchronized (this)
   {
    if (sensor == SensorManager.SENSOR_ORIENTATION)
    {
     for (int i = 0; i < 3; i++)
     {
      mOrientationValues[i] = values[i];
     }
    }
    if (sensor == SensorManager.SENSOR_ACCELEROMETER)
    {
     for (int i = 0; i < 3; i++)
     {
      mLastValues[i] = values[i];
     }
    }
    invalidate();
   }
  }
  public void onAccuracyChanged(int sensor, int accuracy)
  {
   // TODO Auto-generated method stub
  }
}
/**
  * Initialization of the Activity after it is first created. Must at least
  * call {@link android.app.Activity#setContentView setContentView()} to
  * describe what is to be displayed in the screen.
  */
@Override
protected void onCreate(Bundle savedInstanceState)
{
  // Be sure to call the super class.
  super.onCreate(savedInstanceState);
  mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  mGraphView = new GraphView(this);
  setContentView(mGraphView);
}
@Override
protected void onResume()
{
  super.onResume();
  mSensorManager.registerListener(mGraphView,
    SensorManager.SENSOR_ACCELEROMETER
      | SensorManager.SENSOR_MAGNETIC_FIELD
      | SensorManager.SENSOR_ORIENTATION,
    SensorManager.SENSOR_DELAY_FASTEST);
}
@Override
protected void onStop()
{
  mSensorManager.unregisterListener(mGraphView);
  super.onStop();
}
}
0 请登录后投票
   发表时间:2010-07-26   最后修改:2010-07-28
以下这个应用是开发晃动检测的好工具,开发的时候拿个手机摇来摇去确实很傻,这个动作模拟器很强大!



项目主页:http://www.openintents.org/en/node/6

还有这个开源项目:http://code.google.com/p/openintents/wiki/SensorSimulator
0 请登录后投票
   发表时间:2010-07-29  
转几篇从Android开发网原创的关于感应器开发的文章:

(一)


手机开始,主流的智能机纷纷加入了感应器Sensor硬件,常见的有光线感应器、重力感应器、加速感应器,而更高级的有磁极方向、陀螺仪、距离感应器、温度感应器等等。对于Android游戏开发,我们主要用到重力、加速、磁力和陀螺仪四种,当然部分游戏可能需要GPS或Cellid定位来修正一些位移信息。从系统中提高的感应器主要在android.hardware中,我们可以看到系统提供了android.hardware.SensorEventListener、Sensor和SensorManager这三个类,我们会发现除了可以获取感应器的信息,和感应器的原始数据外,并没有提供相关的逻辑处理。Android123将会分3篇来详细的介绍不同感应器的作用和逻辑处理,比如自由落体,晃动,磁极,当前的旋转速度。

   未来Android123将完成主要是一个基于OpenGL 3D的雷电游戏,最终加入联网对战效果可以团队打怪实现手机3D网游充分发挥Android手机的娱乐能力。对于大多数新款Android手机可能没有配备轨迹球或导航键的方向控制,所以重力感应器是这类实时性较强游戏的首选控制方式。主要有以下几点问题对于Sensor

  1. 降噪处理,如果做过LBS软件的大家可能明白偏移修正,在GPS无法正常获取数据较间断时地图不能乱飘,这里Sensor也不例外,除了使用采样数据平均值获取外,可以间隔采样的方法来处理。细节的算法我们将在下节给出示例代码。

  2. 感应器的敏感度,在Android中提供了四种延迟级别分别为


SENSOR_DELAY_FASTEST 最低延迟,一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算法不处理好将会影响游戏逻辑和UI的性能,所以Android开发网不推荐大家使用。
SENSOR_DELAY_GAME 游戏延迟,一般绝大多数的实时性较高的游戏都使用该级别 
int SENSOR_DELAY_NORMAL 标准延迟,对于一般的益智类或EASY级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象。
int SENSOR_DELAY_UI 用户界面延迟,一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用。

(二)

有关Android游戏开发中的Sensor感应示例今天我们将一起来讨论,对于目前最新的Android 2.2平台而言仍然没有具体的感应判断逻辑,下面我们一起定义下常用的感应动作事件。首先Android123提醒大家由于是三轴的立体空间感应所以相对于轨迹球、导航键的上下左右外,还提供了前后的感应,所以我们定义最基本的六种空间方向。

public static final int CWJ_UP = 0;
 public static final int CWJ_DOWN = 1;
 public static final int CWJ_LEFT = 2;
 public static final int CWJ_RIGHT = 4;
 public static final int CWJ_FORWARD = 8; //向前
 public static final int CWJ_BACKWARD = 16; //向后


  下面我们做精确的角度旋转修正值定义,我们用到yaw、pitch和roll,相信学过3D开发的网友不会对这些陌生的,我们就把他们对应为绕y、x、z轴的角度好了,如果你们没有学过3D相关的知识这里Android开发网推荐大家可以通过Cube例子自定义Render来观察这三个值对应立方体的旋转角度。

Yaw在(0,0,0)中, 以xOz的坐标平面中围绕y轴旋转,如果是负角则我们定义为CWJ_YAW_LEFT 即往左边倾斜,同理我们定义如下:

public static final int CWJ_YAW_LEFT = 0;
 public static final int CWJ_YAW_RIGHT = 1;
 public static final int CWJ_PITCH_UP = 2;
 public static final int CWJ_PITCH_DOWN = 4;
 public static final int CWJ_ROLL_LEFT = 8;
 public static final int CWJ_ROLL_RIGHT = 16;


  我们通过加速感应器可以获得SensorEvent的四个值,今天Android123给大家一个简单示例,不考虑其他因素,在public int accuracy 、public Sensor sensor 、public long timestamp  和
public final float[] values 中,我们获取values的浮点数组来判断方向。
      int nAndroid123=CWJ_UP //向上

      float ax = values[0];
      float ay = values[1];
      float az = values[2];
      
      float absx = Math.abs(ax);
      float absy = Math.abs(ay);
      float absz = Math.abs(az);
         
      if (absx > absy && absx > absz) {
  
       if (ax > 0) {
        nAndroid123 = CWJ_RIGHT;
       } else {
        nAndroid123 = CWJ_LEFT;
       }
      } else if (absy > absx && absy > absz) {
     
       if (ay > 0) {
       nAndroid123= CWJ_FORWARD;
       } else {
      nAndroid123= CWJ_BACKWARD;
       }
      } else if (absz > absx && absz > absy) {
  
       if (az > 0) {
        nAndroid123 = CWJ_UP;
       } else {
        nAndroid123 = CWJ_DOWN;
       }
      } else {
       nAndroid123 = CWJ_UNKNOWN;
      }


  有关偏向角度问题,我们将在下一次详细讲述,对于一般的2D游戏,我们可以参考本文来实现重力控制,所以总体来说Android游戏开发比较简单易懂,Android平台使用的Java语言还是很适合做游戏的。在逻辑表达上更清晰。

0 请登录后投票
   发表时间:2010-10-21  
依然不能实现任意初始角度下, 检测手机的Z轴向晃动。
(坐标系: 手机本身为坐标参考: 正面为 Z + , 轨迹球一侧先用户正面为X+, 从轨迹球侧向用户左侧为 Y + )

我正在研究, 只是识别率不高, 求同好讨论。
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics