JobPlus知识库 IT 网络硬件 文章
浅谈加速度传感器及其在计步器中的应用

手机传感器中的加速度传感器

期末做的是计步器APP,所以对加速度传感做了些研究哈哈,下面我就讲讲我学习的一下东西。

1、什么是加速度传感器?

首先传感器,顾名思义,就是将对象的变化感受传达给设备的一种工具,在Android中使用加速度传感器可以帮助我们识别手机的姿态及运动状态。经常听到的有方向传感器,重力感应器,加速度传感器,心率传感器等等。不同版本系统安卓机支持的传感器会不同,所以开发时要选择支持加速度传感器的安卓系统版本。

2、 加速度的求取

由于手机会固定受到地球重力加速度,因此传感器的读数是受此影响后的数值。 
假如我们的手机是垂直摆放,机头朝上。那么x,z轴均无加速度,y轴上会固定受到地球重力加速度的影响。 
此时,由于y轴向上为正方向,因此重力加速度为负值,y轴的加速度就为: 
ay=a−(−g)=a+9.81 
因此竖直静止时,三轴的加速度近似于: 
(ax,ay,az)=(0,9.81,0) 
反之在垂直摆放,机头朝下(倒立摆放)时。y轴方向是向下的,因此这时地球加速度为+9.81。这种情况下y轴的加速度: 
ay=a−g=a−9.81 
静止时有近似值: 
(ax,ay,az)=(0,−9.81,0)

3、使用加速度传感器与其他传感器的方法大致相同,通过调用系统API就可以实现。分为以下几步:

1.获取SensorManager 
2.使用SensorManager获取加速度传感器 
3.创建自定义的传感器监听函数,并注册 
4.相对应的,在合适位置实现注销监听器的调用

4、献上我的学习代码

public class MainActivity extends Activity{ 
private static final String TAG = “SensorTest”; 
private Sensor mAccelerometer; 
private TestSensorListener mSensorListener;

@Override 
protected void onCreate(Bundle savedInstanceState) 

super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
initViews();

// 初始化传感器

mSensorListener = new TestSensorListener(); 
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 

super.onResume();

// 注册传感器监听函数

mAccelerometer, SensorManager.SENSOR_DELAY_UI); }

@Override 
protected void onPause() 

super.onPause(); 

mSensorInfoA = (TextView) findViewById(R.id.sensor_info_a); 
}

class TestSensorListener implements SensorEventListener { 
@Overridepublic void onSensorChanged(SensorEvent event) 
{

// 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度

Log.i(TAG, “onSensorChanged: ” + event.values[0] + “, ” + event.values[1] + “, ” + event.values[2]); 
}

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


Log.i(TAG, “onAccuracyChanged”); 


}

5计步器

计步器需要手机硬件加速度传感器的支持,而计步器的开发可以用手机自己的传感器也可以用Google内置 
计步器开发。这里我选择自己的手机传感器。

6、传感器运行后计步器的工作原理

使用这个传感器时会检测传感器的变化,得到传感器三轴的值(x,y,z)然后计算他们的平均值,这样做的目的是为了平衡在某一个方向数值过大造成的数据误差,然后将该值与上一时间点的值进行比较,判断是否为波峰或波谷,如果是就相应的保存下来。

如果检测到了波峰,并且符合时间差以及阈值的条件,则判定位1步,如果符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中。同时为防止微小震动对计步的影响,我们将计步分为3个状态——准备计时、计时中、计步中。注意:这里要设计的更加符合实际的运动情况,让软件会分辨有效和无效的步数!!!

所谓“计时中”是在3.5秒内每隔0.7秒对步数进行一次判断,看步数是否仍然在增长,如果不在增长说明之前是无效的震动并没有走路,得到的步数不计入总步数中;反之则将这3.5秒内的步数加入总步数中。

之后进入“计步中”状态进行持续计步,并且每隔2秒去判断一次当前步数和2秒前的步数是否相同,如果相同则说明步数不在增长,计步结束。

为了更直观的理解,附上一张图(原谅我的盗图) 

7、实现代码MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener,ensorEventListener {

private SensorManager sManager; 

private Sensor mSensorAccelerometer; 

private TextView tv_step; 

private Button btn_start; 

private int step = 0;   //步数 

private double oriValue = 0;  //原始值 

private double lstValue = 0;  //上次的值 

private double curValue = 0;  //当前值 

private boolean motiveState = true;   //是否处于运动状态 

private boolean processState = false;   //标记当前是否已经在计步 


@Override 

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    sManager = (SensorManager) getSystemService(SENSOR_SERVICE);

    mSensorAccelerometer = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

    sManager.registerListener(this, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI);

    bindViews(); } private void bindViews() {

    tv_step = (TextView) findViewById(R.id.tv_step);

    btn_start = (Button) findViewById(R.id.btn_start);

    btn_start.setOnClickListener(this);

 }

@Override 

public void onSensorChanged(SensorEvent event) {

    double range = 1;   //设定一个精度范围

    float[] value = event.values;

    curValue = magnitude(value[0], value[1], value[2]);   //计算当前的模

    //向上加速的状态

    if (motiveState == true) {

        if (curValue >= lstValue) lstValue = curValue;

        else {

            //检测到一次峰值

            if (Math.abs(curValue - lstValue) > range) {

                oriValue = curValue;

                motiveState = false;

            }

        }

    }

    //向下加速的状态

    if (motiveState == false) {

        if (curValue <= lstValue) lstValue = curValue;

        else {

            if (Math.abs(curValue - lstValue) > range) {

                //检测到一次峰值

                oriValue = curValue;

                if (processState == true) {

                    step++;  //步数 + 1

                    if (processState == true) {

                        tv_step.setText(step + "");    //读数更新

                    }

                }

                motiveState = true;

            }

       }

    }

 } 

 

@Override 

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


 @Override 

public void onClick(View v) {

    step = 0;

    tv_step.setText("0");

    if (processState == true) {

        btn_start.setText("开始");

        processState = false;

    }

 else {

        btn_start.setText("停止");

        processState = true;

    }

 }

 //向量求模 

public double magnitude(float x, float y, float z) {

    double magnitude = 0;

    magnitude = Math.sqrt(x * x + y * y + z * z);

    return magnitude;

 } 


 @Override 

protected void onDestroy() {

    super.onDestroy();

    sManager.unregisterListener(this);

 }

}


如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏支持
271人赞 举报
分享到
用户评价(0)

暂无评价,你也可以发布评价哦:)

扫码APP

扫描使用APP

扫码使用

扫描使用小程序