通过Google内置计步器和加速度传感器制作android计步程序(附源码)

您所在的位置:网站首页 计步器传感器原理 通过Google内置计步器和加速度传感器制作android计步程序(附源码)

通过Google内置计步器和加速度传感器制作android计步程序(附源码)

#通过Google内置计步器和加速度传感器制作android计步程序(附源码)| 来源: 网络整理| 查看: 265

        最近需要做一个计步程序,在网站上研究了一些别人写的程序代码,比较普遍实用的是根据API大小,使用Google内置计步器或加速度传感器进行计步。但是网上源代码的注释很少,经过了一番波折,自己终于有了头绪,并且对计步程序做了一些改进。为了让大家能更快的理解计步原理,现在分享一下自己的一些经验,希望对大家有所帮助

        先看一下效果:

        (PS:这是我从整个程序中抽出来的一部分,只实现了计步功能,一些其他的控件我已经去掉了,便于大家理解计步的原理。想要美化界面的同胞们可以自行动手哈)

一、程序设计的整体思路:

        在主Activity中开启一个服务,在服务中注册一个广播接收者监听屏幕的电源情况保存数据。并且新建子线程,在子线程里开启计步检测,根据不同API版本获得不同传感器管理器和传感器实例并注册监听,如果使用的是Google内置计步器则在重写的onSensorChanged()方法中计算步数,如果使用的是加速度传感器则根据传感器得到的数据,计算波峰波谷阈值等数据,符合要求即为一步(具体条件下面会介绍)。之后更新通知栏和界面。

  二、计步使用到的传感器以及对应的计步方法:

        在服务中开启计步检测会对API进行一个判断如果API>19则调用CountSensor,因为android4.4以后可以使用Google内置计步器。对于API=19){ addCountStepListener(); }else{ addBasePedoListener(); } }          API版本大于19执行addCountStepListener方法,首先先拿到两种传感器,TYPE_STEP_COUNTER 计步传感器,用于记录激活后的步伐数。TYPE_STEP_DETECTOR 步行检测传感器,用户每走一步就触发一次事件。根据拿到的情况来注册监听,sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_UI);查资料后得知这里第一个参数是Listener,第二个参数是所得传感器类型,第三个参数值获取传感器信息的频率 。如果两种传感器都没拿到,就还是执行addBasePedoListener方法。在addBasePedoListener方法里获得加速度传感器,注册监听,然后调stepDetector里的回调接口更新通知栏。具体代码片段如下:

private void addCountStepListener(){ Sensor detectorSensor=sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR); Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); if(countSensor!=null){ stepSensor = 0; Log.v(TAG, "countSensor"); sensorManager.registerListener(StepService.this,countSensor,SensorManager.SENSOR_DELAY_UI); }else if(detectorSensor!=null){ stepSensor = 1; Log.v("base", "detector"); sensorManager.registerListener(StepService.this,detectorSensor,SensorManager.SENSOR_DELAY_UI); }else{ stepSensor = 2; Log.e(TAG,"Count sensor not available!"); addBasePedoListener(); } }          在addBasePedoListener()中使用了加速度传感器。该方法中会调用StepDetector这个类,它可以通过检测传感器的值通过一定的算法判断是否为1步,具体算法后面会揭晓。

private void addBasePedoListener(){ //只有在使用加速传感器的时候才会调用StepDetector这个类 stepDetector =new StepDetector(this); //获得传感器类型,这里获得的类型是加速度传感器 //此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率 Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(stepDetector,sensor,SensorManager.SENSOR_DELAY_UI); stepDetector.setOnSensorChangeListener(new StepDetector.OnSensorChangeListener() { @Override public void onChange() { updateNotification("今日步数:"+StepDetector.CURRENT_STEP+" 步"); } }); }          无论是使用了Google内置计步器还是使用了加速度传感器,当传感器发生变化时都会调用onSensorChanged()方法。我们在这里根据stepSensor(计步传感器类型)进行一下判断,如果是Google内置计步器,该计步器可以返回一个值(int)event.value[0],这个值统计了我们之前走过的步数,TYPE_STEP_COUNTER表示返回从开机被激活后统计的步数,TYPE_STEP_DETECTOR表示步行检测,用户每走一步就触发一次事件。这时候我们就需要用到上面提到的boolean型变量isNewDay了,如果该值为true说明是新的一天,我们记录下内置计步器所统计的步数。将该值存入数据库中,如果该值为false那么说明数据库中已经存储了今天的数据,我们可以从数据库中读取当天开始时候存储的(int)event.value[0]值。那么今天所走的步数=计步器当前统计的步数-之前统计的步数。这样即使程序中途没有运行,也能够准确的记录当天所走的步数。如果是加速度传感器,则不对它进行操作,因为计步的方法会在StepDetector类中实现。之后我们需要更新状态栏信息

@Override public void onSensorChanged(SensorEvent event) { if(stepSensor == 0){ //使用计步传感器 if(isNewDay) { //用于判断是否为新的一天,如果是那么记录下计步传感器统计步数中的数据 // 今天走的步数=传感器当前统计的步数-之前统计的步数 previousStep = (int) event.values[0]; //得到传感器统计的步数 isNewDay = false; save(); //为防止在previousStep赋值之前数据库就进行了保存,我们将数据库中的信息更新一下 List list=DbUtils.getQueryByWhere(StepData.class,"today",new String[]{CURRENTDATE}); //修改数据 StepData data=list.get(0); data.setPreviousStep(previousStep+""); DbUtils.update(data); }else { //取出之前的数据 List list = DbUtils.getQueryByWhere(StepData.class, "today", new String[]{CURRENTDATE}); StepData data=list.get(0); this.previousStep = Integer.valueOf(data.getPreviousStep()); } StepDetector.CURRENT_STEP=(int)event.values[0]-previousStep; }else if(stepSensor == 1){ StepDetector.CURRENT_STEP++; } //更新状态栏信息 updateNotification("今日步数:" + StepDetector.CURRENT_STEP + " 步"); }

  3.最后我们介绍当使用加速度传感器时需要用到的StepDetector类。         在该类的onSensorChanged()方法中,我们先得到传感器事件,获得加速度传感器并且算出加速度传感器的x、y、z三轴的平均数值(这是为了平衡在某一个方向数值过大造成的数据误差),之后交给DetectorNewStep方法处理

@Override public void onSensorChanged(SensorEvent event){ Sensor sensor=event.sensor; synchronized (this){ //获取加速度传感器 if(sensor.getType()==sensor.TYPE_ACCELEROMETER){ calc_step(event); } } } synchronized private void calc_step(SensorEvent event){ average=(float)Math.sqrt(Math.pow(event.values[0],2) +Math.pow(event.values[1],2)+Math.pow(event.values[2],2)); detectorNewStep(average); }          在detectorNewStep方法中,首先判断上次传感器三轴的平均值值gravityOld是否为0,如果为零说明这是第一次进行探测将当前的值赋给gravityOld,如果不为零我们通过当前的值values和上次传感器的值gravityOld值通过DetectorPeak进行判断,检测是否为波峰(具体算法下面会给出),当检测到了波峰后记录这次的时间和上次的时间,如果两次的时间差在200到2000毫秒之间并且波峰与波谷的差大于阈值时就判定为一步更新这次波峰的时间和界面;而如果符合时间差条件,但波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中。最后将传入的值赋给grayityOld

/** * 监测新的步数 * * 1.传入sersor中的数据 * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定位1步 * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中 * @param values 加速传感器三轴的平均值 */ private void detectorNewStep(float values) { if(gravityOld==0){ gravityOld=values; }else{ if(DetectorPeak(values,gravityOld)){ timeOfLastPeak=timeOfThisPeak; timeOfNow=System.currentTimeMillis(); if(timeOfNow-timeOfLastPeak>=200&&(peakOfWave-valleyOfWave>=ThreadValue) &&(timeOfNow-timeOfLastPeak)=200 &&(peakOfWave-valleyOfWave>=initialValue)){ timeOfThisPeak=timeOfNow; ThreadValue=Peak_Valley_Thread(peakOfWave-valleyOfWave); } } } gravityOld=values; }

        下面是检测波峰的方法:先记录下lastStatus即上一点的状态,上升还是下降,然后比较新值和旧值如果newValue >= oldValue就设置和更新 isDirectionUp、continueUpCount 否则就将contineUpCount赋给continueUpFormerCount(上一点的持续上升的次数,为了记录波峰的上升次数)。最后判断当满足波峰判断的四个条件(见代码注释)的话,这个值就是波峰值返回true。如果上一次状态为下降,本次状态为上升则这个值为波谷值并返回false。

/** * 监测波峰 * 以下四个条件判断为波峰 * 1.目前点为下降的趋势:isDirectionUp为false * 2.之前的点为上升的趋势:lastStatus为true * 3.到波峰为止,持续上升大于等于2次 * 4.波峰值大于1.2g,小于2g * 记录波谷值 * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值 * 2.所以要记录每次的波谷值,为了和下次的波峰作对比 * @param newValue * @param oldValue * @return */ public boolean DetectorPeak(float newValue,float oldValue){ lastStatus=isDirectionUp; if(newValue>=oldValue){ isDirectionUp=true; continueUpCount++; }else{ continueUpFormerCount=continueUpCount; continueUpCount=0; isDirectionUp=false; } if(!isDirectionUp&&lastStatus&&(continueUpFormerCount>=2&&(oldValue>=minValue&&oldValue


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3