한 걸음 두 걸음

android 안드로이드 ] 스마트폰 이동 중인지 정지 상태인지 구분하기/ 가속도센서 활용 본문

FrontEnd/Android

android 안드로이드 ] 스마트폰 이동 중인지 정지 상태인지 구분하기/ 가속도센서 활용

언제나 변함없이 2019. 6. 11. 22:26
반응형

사용 : MainActivity.java & activity_main.xml 두 개만 사용하였음.

activity_main.xml은 간단하기 그지없다. 사실 없어도 되는데 

디버깅용 textview 두 개 쓴게 끝이다. 위에 숫자는 이번에 안썼음

package kr.ac.koreatech.swkang.msp02_orientationsensor;

import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static java.lang.StrictMath.abs;

/*이동중 관련은 가속도 (보조) + 스텝 올라가고있음을 감지하는 것(주)로 바꿔!! */
public class MainActivity extends AppCompatActivity implements SensorEventListener {
    public ArrayList<Float> sensorValues;
    public Handler handler;

    //가속도 센서 값
    private SensorManager mSensorManger;
    private Sensor linearSensor;


    //타이머 관련 변수
    private long MillisecondTime, StartTime, TimeBuff, UpdateTime = 0L;
    private int Seconds, Minutes, MilliSeconds;

    //체크용 텍스트뷰
    TextView checktext;
    TextView checktext2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();

        //타이머 및 자료수집 시간 실행시킵니다.
        handler = new Handler();
        StartTime = SystemClock.uptimeMillis();
        handler.postDelayed(runnable, 0);
        Toast.makeText(getApplicationContext(), "핸들러 시작", Toast.LENGTH_SHORT).show();

    }

    public boolean isWatching() {
        int hitCount = 0;
        float sum = 0f;

        float Xgap = 0f;
        float Ygap = 0f;
        float Zgap = 0f;

        for(int i = 0; i < 27; i ++){
            //첫 번째 레코드와 두 번째 레코드 사이의 차
            Xgap = Math.abs(sensorValues.get(i) - sensorValues.get(i+3));
            Ygap = Math.abs(sensorValues.get(i+1) - sensorValues.get(i+4));
            Zgap = Math.abs(sensorValues.get(i+2) - sensorValues.get(i+5));
            //차이의 평균
            sum = (Xgap + Ygap + Zgap) / 3.0f;
            if(sum < 0.2) hitCount++;
            i++; i++;//3의배수대로 i가 늘어나도록 합니다.
        }

        return hitCount >= 5 ? true : false;
    }

    public void init() {
        mSensorManger = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        linearSensor = mSensorManger.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
        mSensorManger.registerListener(this, linearSensor, SensorManager.SENSOR_DELAY_UI);

        checktext = (TextView) findViewById(R.id.activity_main_check1); //디버깅중...
        checktext2 = (TextView)findViewById(R.id.activity_main_check2);

        sensorValues = new ArrayList<>();
    }

    public Runnable runnable = new Runnable() {

        public void run() {
            MillisecondTime = SystemClock.uptimeMillis() - StartTime;
            UpdateTime = TimeBuff + MillisecondTime;
            Seconds = (int) (UpdateTime / 1000);
            Minutes = Seconds / 60;
            Seconds = Seconds % 60;
            MilliSeconds = (int) (UpdateTime % 1000);

            //레코드 수가 10개 이상이면 isWatching 함수 실행
            if (sensorValues.size() >= 30) {
                if(isWatching())
                    checktext2.setText("정지상태입니다.");
                else
                    checktext2.setText("이동중입니다");
                for (int i = 0; i < 15; i++)
                    sensorValues.remove(0);

            }
            handler.postDelayed(this, 0);
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacks(runnable);
        Toast.makeText(getApplicationContext(), "스레드 종료", Toast.LENGTH_SHORT).show();
    }

    int millCount = 1;

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        //100ms마다 자료를 수집하는 것으로 맞춰주세요~~
        if (MilliSeconds / 100 == 0) millCount = 1;
        if (sensorEvent.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION && MilliSeconds / 100 >= millCount) {
            //가속도 센서값일 경우,
            sensorValues.add(sensorEvent.values[0]);
            sensorValues.add(sensorEvent.values[1]);
            sensorValues.add(sensorEvent.values[2]);
            // SensorValues 배열 내부에 X,Y,Z축의 값을 add해줍니다.
            millCount++; //100ms마다 한 번씩만 측정하도록 하였습니다.
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

}

 

참고 논문 : https://pdfs.semanticscholar.org/ded3/9bd2183ad7a73281580b8fb186aacf0f8be7.pdf

불러오는 중입니다...

http://www.dbpia.co.kr.libproxy.koreatech.ac.kr/journal/articleDetail?nodeId=NODE02370084#none

 

http://www.dbpia.co.kr.libproxy.koreatech.ac.kr/journal/articleDetail?nodeId=NODE02370084#none

 

www.dbpia.co.kr.libproxy.koreatech.ac.kr

위의 두 논문을 참고하여 소개된 알고리즘을 사용하였습니다.

 

반응형