[안드로이드] 가속도 센서를 이용한 흔듬(Shake) 감지

2010.05.23 11:42

   

   

 

 

<목표> 

 

[안드로이드] 가속도 센서를 이용한 흔듬(Shake) 감지

 

가속도 센서 흔듬 감지 

   오늘은 안드로이드의 가속도 센서를 이용하여, 핸드폰이 흔들리는 것(Shaking)을 감지해보겠습니다. 즉, 핸드폰이 위에서 아래로, 아래에서 위로 가면, 이벤트가 발생하는 것입니다. 간단한 예로 들자면, 만보계를 위한 이벤트 인식정도라고 생각하시면 되겠습니다. 한번 흔드는 것을 감지하는 소스입니다. How to detect shake motion on Android phone 사이트를 통해 샘플 코드를 가져왔으며, SDK가 업그레이드 되면서, 바뀐 부분이 많이 있어 수정한 소스입니다. 

Shaking 이미지 출처 : China Grabber

 

 

 

 

  STEP 1 Java Source Code 

 

 핸드폰이 흔들리는 것을 감지하려면, 당연히 가속도 센서를 이용해야겠죠? 가속도 센서는 핸드폰을 기준으로 x, y, z 방향으로의 가속도만 측정이 가능합니다. 즉, 이 방향성을 가지는 가속도를 가지고 제대로된 움직임을 감지해야하는 것이죠. 센서를 사용하기 위해 SensorListener를 상속받는 엑티비티를 생성합니다. 차례차례 코드를 보며 설명해드리겠습니다. 

   

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
 
public class ShakeActivity extends Activity implements SensorEventListener {
 
    private long lastTime;
    private float speed;
    private float lastX;
    private float lastY;
    private float lastZ;
    private float x, y, z;
 
    private static final int SHAKE_THRESHOLD = 800;
    private static final int DATA_X = SensorManager.DATA_X;
    private static final int DATA_Y = SensorManager.DATA_Y;
    private static final int DATA_Z = SensorManager.DATA_Z;
 
    private SensorManager sensorManager;
    private Sensor accelerormeterSensor;
 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        accelerormeterSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }
 
    @Override
    public void onStart() {
        super.onStart();
        if (accelerormeterSensor != null)
            sensorManager.registerListener(this, accelerormeterSensor,
            SensorManager.SENSOR_DELAY_GAME);
    }
 
    @Override
    public void onStop() {
        super.onStop();
        if (sensorManager != null)
            sensorManager.unregisterListener(this);
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
 
    }
 
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            long currentTime = System.currentTimeMillis();
            long gabOfTime = (currentTime - lastTime);
            if (gabOfTime > 100) {
                lastTime = currentTime;
                x = event.values[SensorManager.DATA_X];
                y = event.values[SensorManager.DATA_Y];
                z = event.values[SensorManager.DATA_Z];
 
                speed = Math.abs(x + y + z - lastX - lastY - lastZ) / gabOfTime * 10000;
 
                if (speed > SHAKE_THRESHOLD) {
                    // 이벤트발생!!
                }
 
                lastX = event.values[DATA_X];
                lastY = event.values[DATA_Y];
                lastZ = event.values[DATA_Z];
            }
 
        }
 
    }
}

 

 onCreate 부분에서는 센서를 사용하기 위해서 시스템 서비스를 가져와서 SensorManager 타입으로 저장해둡니다. onAccuracyChanged와 onSensorChanged를 오버라이딩 해줘야 합니다. 함수 이름에서 보시듯 정확도와 센서 정보가 변하면 발생하는 함수입니다. 흔드는 것을 감지하는 핵심적인 소스는 onSensorChanged 함수에 있습니다. 센서가 변함에 따라 이 함수가 실행됩니다. 센서 종류가 가속도 센서일 때, 이벤트를 처리해줘야합니다. 최근 측정한 시간과 현재 시간을 비교하여 0.1초 이상되었을 때, 흔듬을 감지합니다. 이 흔듬을 감지하는 함수는 조금씩 수정이 가능합니다. 자신의 프로그램에 맞게 설정할 해줄 수 있습니다. 기본적으로는 위의 소스코드에서 보이는 것처럼, 가속도의 벡터값을 이용하여 대략적으로 측정합니다. 정확도면에서는 약간 떨어지겠죠. SHAKE_THRESHOLD 또한 잘 설정을 해줘야 합니다. 속도가 얼마 이상일 때, 흔듬을 감지하겠다는 것을 설정해주는 부분입니다. 기기에 따라 약간씩 다를 수 있으니, 실제로 테스트를 해보면서 값을 조절해야합니다. 나머지 코드 부분은 쉽게 알 수 있는 부분이라 생략하겠습니다.

 

 

  STEP 2 Xml Code 

 

Xml코드는 생략하겠습니다.

간단히 흔들리는 횟수를 출력하는 것으로 제대로 동작하고 있는지 확인할 수 있습니다.

 

 

  STEP 3 AndroidManifest.xml Code 

 

가속도 센서를 이용하기 위해, AndroidManifest.xml 에 추가적으로 권한 설정은 필요치 않습니다.

 

 

 

<마무리> 가속도 센서를 이용한 흔듬(Shake) 감지

 

 가속도 센서를 이용하여 다양한 방법으로 어플리케이션을 구성할 수 있습니다. 여러 용도로 쓸 수 있겠지만, 여기에서는 가장 간단한 흔듬(shake) 감지를 위한 소스코드에 대해서 알아보았습니다. SensorEventListener를 상속받고, SensorManager를 이용하여 센서를 사용할 수 있도록 등록시킵니다. 그리고 onAccuracyChanged와 onSensorChanged를 오버라이딩을 해줌으로써, 가속도 센서 변화값에 따라 흔듬을 감지할 수 있도록 구성하였습니다. 가속도 센서의 값과 속도, 거리에 따라 다양하게 활용할 수 있습니다. 오늘의 핵심은 가속도 센서를 사용하는 방법입니다.

 

 

 

 

[ 참고자료 ]

     

 

 


Posted by 
맥박맥박의 개발 일지

 

  • 2013년 7월 26일 업데이트하였습니다.

 

 

맥박 안드로이드 , , , , , , , , , ,

  1. 이전 댓글 더보기
  2. Blog Icon
    강석원

    여기서 800이라는 말은...
    기준이 어떻게 되는 거죠?
    0.1초에 x,y,z축으로 800이상 흔들렸다는 말씀이신가... 모르겟어요 ㅠㅠ

  3. 말그대로 SHAKE_THRESHOLD 값입니다. 스피드값이 이 값 이상이 되었을 때 쉐이크로 인식하겠다는 의미이죠.그러면 스피드값이 무엇인지 보면 답이 나오겠지요.

    speed = Math.abs(x + y + z - lastX - lastY - lastZ) /
    gabOfTime * 10000;

    x, y, z와 마지막 x, y, z 값의 차이값을 이용한 결과입니다.
    여기서 x, y, z 값은 센서의 값입니다. 가속도 센서이지요.
    즉, 가속도 센서의 값을 이용하여 나온 결과를 이용하는 것이죠.
    x 값은 x축을 기준으로한 기울기 값이며 -180~180값을 가집니다.
    y 값은 y축을 기준으로한 기울기 값이며 -90~90값을 가집니다.
    z 값은 z축을 기준으로 한 회전값이며, 0~359의 값을 가집니다.

    각 축에 대한 정보는 가속도 센서를 한번 검색해보시면 될 듯 합니다. ^^

  4. Blog Icon
    전광수

    저는 위에분 처럼 흔들었을대 횟수 출력 할려고 합니다
    추가 부분만 말씀 드리게습니다.

    xml에 추가부분은
    <EditText
    android:id="@+id/tv"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>

    public class ShakeActivity extends Activity implements SensorEventListener {
    EditText vi; //추가..

    public void onCreate(Bundle savedInstanceState) {
    vi =(EditText)findViewById(R.id.tv); //추가


    public void onSensorChanged(SensorEvent event){
    int count=0;//추가

    if(speed > SHAKE_THRESHOLD){ //이벤트 발생
    count++; //추가
    vi.setText(count); //추가 했는데이부분 이렇게 하면 안되나요?
    }

  5. Blog Icon
    전광수

    제가 초보라 방금 올리고 다시 스스로 답글 올리네요;;

    방법 해결했어요;;

    전역변수로

    public class ShakeActivity extends Activity implements SensorEventListener {

    EditText vi;
    int count;
    String str = String.format("%d",count);
    //string으로 바꿔줘야 되네요;;

    그리고
    public void onCreat(BundlesavedInstanceState) {

    vi =(EditText)findViewById(R.id.tv);
    vi.setText(str); //추가 해주고요

    public void onSensorChanged(SensorEvent event){
    여기에서

    if(speed > SHAKE_THRESHOLD){ //이벤트 발생
    count++;
    str = String.format("%d", count); 값을 받아서
    vi.setText(str); //넣어줘야 되네요;;
    }

    이거때문에 ㅠㅠ 초보라 공부하게 되었네요 ㅠㅠ

  6. Blog Icon
    댄디

    질문있습니다 ^^

    xml 파일은 어떻게 쓰셨나여?

    그리고 자바와 xml을 어떻게 연동시켰는지도

    궁금합니다 ㅠ

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

    <EditText
    android:id="@+id/tv"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>
    </LinearLayout>

    이렇게 xml로 넣으면 안되는건가여?!

  7. 이 소스를 thread를 이용해서 돌리려면 어떻게 해야하는가요?
    제가 동영상 녹화를 하면서 흔들림이 있으면 파일로 저장시킬려고 하는데요.
    thread 구현을 못하겠습니다.
    이것만이라도 어떻게 하는지 알면,
    응용해서 GPS 도 thread로 돌려서
    차량용 블랙박스를 만들수 있을것 같은데,
    4일째 thread에서 막히네요.
    한수 알려주실수 있나요?

  8. 테스트해보지 않아서 잘 모르겠지만, 위의 소스에서 흔들림이 감지되었을 경우에 쓰레드에게 신호를 보내주면 되지 않을까합니다. Handler를 이용해서 쓰레드에 메시지를 보내는 방법이 있으니, 해당방법을 사용해보시면 좋을 듯 합니다. 잠깐 검색해보았는데, 참고하실수 있을 것 같다 링크 걸어봅니다. http://blog.naver.com/PostView.nhn?blogId=crowdark7&logNo=109380704&parentCategoryNo=40&viewDate=&currentPage=1&listtype=0
    정확한을 구현 내용을 몰라 생각나는데로 말씀드렸는데, 원하시는 답변일지 모르겠네요.^^;; 참고용 정도로만 생각하시면 될듯합니다~!

  9. 와우~ 찾던 내용인데 감사합니다 ㅎㅎ
    막상 X, Y, Z 값만 구할줄 알았을때 대체 어떻게 흔들림을 인식해야 할 지 고민하고 있었는데 덕분에 큰 벽을 넘었네요 ㅎㅎ.. 맥박님 블로그 자주 들리게 될 것 같습니다~!

  10. Blog Icon

    비밀댓글입니다

  11. 위의 소스는 xml과는 전혀 상관이 없답니다~ ^^;

  12. Blog Icon
    홍성재

    ㅠㅠ해봤는데 잘 안되네요 댓글단분처럼 수정을 해줘도 에뮬에서 안돌아가여ㅠㅠ 왜그럴까요 혹시 완전한 소스를 구할수있을까요''

  13. 안녕하세요~

    에뮬레이터에서는 가속도 센서가 없는 것으로 알고 있는데요;;
    스마트폰에서 테스트를 해보시면, 될 것이라 생각합니다. ^^;

  14. Blog Icon
    댄디

    xml 파일은 어떻게 작성해야 되나여?!

    자바 소스코드에서는 오류가 뜨지 않는데, xml 파일은

    어떻게 작성해야되는지 궁금합니다 ^^

  15. 안녕하세요~
    위의 소스에서 굳이 xml 소스가 필요없습니다. ^^;
    원하시는 화면을 xml 으로 구성하시면 됩니다~

  16. Blog Icon
    류시천

    쌩초보가 질문좀할게요

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

    @Override
    public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    long currentTime = System.currentTimeMillis();
    long gabOfTime = (currentTime - lastTime);

    TextView tv = new TextView(this);
    tv.setBackgroundColor(Color.CYAN);
    tv.setText("hi");
    MediaPlayer spin;
    spin = MediaPlayer.create(getBaseContext(), R.raw.wow);

    if (gabOfTime > 100) {
    lastTime = currentTime;

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

    speed = Math.abs(x + y + z - lastX - lastY - lastZ) /
    gabOfTime * 10000;

    if (speed > SHAKE_THRESHOLD) {
    // 이벤트 발생!!
    spin.start();
    }
    lastX = event.values[DATA_X];
    lastY = event.values[DATA_Y];
    lastZ = event.values[DATA_Z];
    }
    }
    }
    }
    이렇게 소리가 나오게 했는데 어쩌다 가끔씩 작동을하구요 작동안될때는 에러메시지가 뜹니다.. 가끔될때도 재생이 끝나면 에러가 뜨구요 예외처리를 어떻게 해야할가요??

  17. Blog Icon
    이건륜

    음...

    long currentTime = System.currentTimeMillis();
    long gabOfTime = (currentTime - lastTime);

    여기서 보니까 currentTime는 변수설정을 해주셨는데,
    lastTime은 변수설정을 안해줘도 알아서 값을 가져올 수 있나요? 음... 제가 봐서는 lastTime 값이 왔다갔다해서 그런가 아닌가 싶네요?

    아래쪽에 if(gabOfTime>100) 에서 lastTime값이 관련된 소스가 있는데 ... 적어주신 소스에선 lastTime을 가져오는 부분을 찾아 볼 수가 없어서요 ^^;;


    (음.. 그리고 실례가 되는지 모르겠지만.... 조선대학교 교수님아니신가요?! .. 앱센터에서 디자인부분강의들은적이 있는데... ^^;;)

  18. Blog Icon
    안드로이드초보

    죄송한데 이렇게 하니까 무한루프로 핸드폰에 무리가 가더라구요...

    작동을 하지 않아도 무언가가 계속 실행되어 반복적으로 작업하고 있고...

  19. Blog Icon
    RF

    안드로이드 벼락치기를 해야할 일이 있어, 밤낮을 새며 백방 찾아다니고 있었는데, 이런 꿀물같은 코드를 공개해주셔서 감사드릴 따름입니다.

  20. Blog Icon
    공부왕

    자료 감사합니다. 많은도움이 되었습니다

  21. 좋은 포스팅 감사드립니다.

    많은 도움되었습니다!!

  22. Blog Icon
    gsap

    관련 안드로이드 api 를 못찾아서 그런데 , 링크알수 있을까요 ? ㅠㅠ

  23. 창밖을 봐 바람에 나뭇가지가 살며시 흔들리면 네가 사랑하는 사람이 널 사랑하고 있는거야.

  24. Blog Icon
    hee

    유익한 정보 감사합니다.
    제가 흔들림을 나오게 했더니 정확하게 되지는 않고 막올라가고 맞추기가 참 힘든 것 같아요.
    핸들러나 쓰레드를 쓰지 않아도 실행은 되는 것 같구요.
    xml 에서는 텍스트뷰만 넣고 id값으로 자바에서 뷰를 가져왔어요.
    if (speed > SHAKE_THRESHOLD) { number++; textnumber.setText(number + "");
    }
    이부분만 넣으니 기록이 되더라구요.
    number값이 횟수인데 정수형이라서 format을 바꾸어주어야하는데 제가 경험상 가장 쉽게 string으로 바꾸는 방법이 이거더라구요...

  25. Hello there! This is kind of off topic but I want some support from an existing blog. Is the idea difficult to setup your very own blog? I’m not so techincal but I can figure items out quite fast. I’m thinking about setting up my very own but I’m not sure the place to start. Do you have any suggestions or recommendations? Thank anyone

  26. Blog Icon
    비머

    이게 액티비티이동을 넣었더니
    양쪽으로 흔들면 2번이동이되는데
    양쪽으로 흔들어야 이동되게는 못할까요??

  27. Blog Icon
    지니

    :)정말 많이 도움받았습니다. 감사합니다.

  28. Blog Icon
    mdr

    감사합니다! :) 도움많이되었어요