블로그 이미지
매몰

모바일 어플리케이션 개발 1인 기업 고영진모바일입니다. 저와 함께 맛깔스러운 앱을 만들어 보아요~

Rss feed Tistory
개발/android 2014.03.17 12:47

안드로이드에서의 가장 간단하고 확실한 칼만필터(Kalman Filter) 테스트

칼만필터 테스트



얼마 전 아는 지인을 통해 칼만필터(Kalman Filter)라는것을 알게 되었다.


오래전 기울기센서를 이용한 "운전좀하냐" 라는 게임을 만들때에 자동차가 엄청 흔들리고 불안정해서 온갖방법과 테스트를 해보았지만 결국 만족스러운 결과를 못내고 출시해야 했다ㅠㅠ


그런데 우연히 지인을 통해 알게된 칼만필터를 써보니!! 한방에 해결이 되는게 아닌가ㅎㅎ

물론 좀더 손을 봐야 할것 같지만 어쨋든 예전소스랑 칼만필터를 결합하니 제법 만족스런 결과를 얻어냈다


그래서 여기에 직접 칼만필터의 위력을 보여주고자 한다...


우선 칼만필터란 잡음같은것을 없에는 기법이다. 기울기센서에서는 민감한 센서에 의해 아주작은 손떨림에도 반응하여 값이 흔들리는 현상을 보정해 준다


기본원리는 간단하다. 

기울기센서 값을 계속 저장해 두었다가 평균값을 계산하여 현재값에 적용해 주는 것이다. 그러면 어느정도 값이 평탄해진다. 여기에 가중치가 들어간 평균값을 사용하면 더 정확해 진다.


이론적으로 들어가면 이보다 더 복잡하지만 내가 머리가 나빠서ㅎㅎ 그냥 내 식으로 직접 소스를 짜서 확인해 보았다.



아래 프로그램은 하나의 뷰객체(오브젝트)를 기울기센서를 이용해 움직인다

즉, 아주 간단한 게임인것이다ㅎㅎ 여기에 적오브젝트를 넣어 피해다니게 하면 게임이 된다ㅎㅎ

한번 해보시길~ㅎㅎ



-------------- .jave --------------


public class MainActivity extends Activity implements SensorEventListener {


private SensorManager mSensorManager;

private Sensor mSensor; 

private View mLayout;

private float mX, mY;

private KalmanFilter mKalmanAccX;

private KalmanFilter mKalmanAccY;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

                //움직일 오브젝트(뷰객체)가 있는 부모 레이아웃

mLayout = this.findViewById(R.id.Layout);

    //칼만필터 초기화

mKalmanAccX = new KalmanFilter(0.0f);

mKalmanAccY = new KalmanFilter(0.0f);

//기울기 센서 등록

mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);

mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME);

}


@Override

public void onAccuracyChanged(Sensor sensor, int accuracy) {

// TODO Auto-generated method stub

}


@Override

public void onSensorChanged(SensorEvent event) {

float x = event.values[0];

float y = event.values[1];

    //칼만필터를 적용한다

float filteredX = (float) mKalmanAccX.update(x);

float filteredY = (float) mKalmanAccY.update(y);

                

                //이주석을 풀면 칼만필터를 사용하지 않는다

    //filteredX = x;

//filteredY = y;

                //부모 레이아웃을 스크롤시켜 마치 뷰객체(오브젝트)가 움직이는것처럼 보이게 한다

                //저장해둔 예전값과 현재값의 차를 넣어 변화를 감지한다

                //여기에 100을 곱하는것은 차의 숫자가 워낙 작아 움직임이 보이지 않기 때문이다.

                //즉, 스피드라고도 보면 된다ㅎㅎ 더 큰숫자를 넣으면 더 빠르게 움직인다.

mLayout.scrollBy((int)((mX - filteredX) * 100), (int)((mY - filteredY) * 100));

                //예전값을 저장한다

mX = filteredX;

mY = filteredY;

}

  //칼만필터를 클래스로 선언한다. 여기에 쓰이는 공식은 이미 여러 사이트에 소개되어있다.

class KalmanFilter {

private double Q = 0.00001; 

private double R = 0.001;

private double X = 0, P = 1, K;

    //첫번째값을 입력받아 초기화 한다. 예전값들을 계산해서 현재값에 적용해야 하므로 반드시 하나이상의 값이 필요하므로~

KalmanFilter(double initValue) {

X = initValue;

}

    //예전값들을 공식으로 계산한다

private void measurementUpdate(){

K = (P + Q) / (P + Q + R);

P = R * (P + Q) / (R + P + Q);

}

 

    //현재값을 받아 계산된 공식을 적용하고 반환한다

public double update(double measurement){

measurementUpdate();

X = X + (measurement - X) * K;

 

return X;

}

}

}



-------------- .xml --------------


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent">


    <!-- 부모 레이아웃 -->

    <RelativeLayout android:id="@+id/Layout"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent">

    

  <!-- 뷰객체(오브젝트) -->

    <TextView android:id="@+id/textview"

        android:layout_width="100dp"

        android:layout_height="100dp"

  android:layout_centerInParent="true"

        android:background="#000000" />

    

</RelativeLayout>


</RelativeLayout>



칼만필터 미적용 상태





칼만필터 적용 상태




별거 아닐수도 있지만 

당시 저는 위와같이 칼만필터를 적용한것과 아닌것을 비교해보고 완전 감동받았습니다ㅎㅎ

역시 세상에는 천재들이 많은것 같아요~ 저런 필터를 다 만들다니... 고맙습니다ㅎㅎ

잘 이용해서 잘 쓸게요~




 

 



수제 앱 장인: 고영진


(주)고영진모바일

1인기업 대표이사 겸 개발자

  

     실패만 하고 있어도 꿈을 포기하지 않는 남자 

     제가 직접 경험하고 습득한 지식을 위주로 올릴게요

 






사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
  • 강철군(a.k.a. 철이) 2014.05.10 17:25 신고 ADDR 수정/삭제 답글

    센서 오차를 줄이는 방법을 찾다가 들르게 되었습니다. 칼만필터를 써야된다는 사실에 머리가 붕괴되고 있던 참인데 덕분에 쉽게 이해할 수 있었습니다. 감사합니다!

  • 김기훈 2014.06.07 13:36 신고 ADDR 수정/삭제 답글

    이거 칼만필터 이용해서 Canvas에 사각형을 그리면서 기울기에 따라 이동시켜주는데 이동중 떨림은 많이 줄었는데
    그냥 바닥에 가만히 놔둬도 조금씩 떨리던데 어떻게 수정해야 떨리는 범위를 좀더 줄일수가 있나요??

    • 대세를 따르지 않고 대세를 만드는 매몰 2014.06.09 12:28 신고 수정/삭제

      센서는 단말기마다 차이가 있을수 있어요...
      좀더 민감한 단말기에서는 흔들릴수도 있을것 같네요..
      하지만 제가 위의 칼만필터를 Canvas에서 사용할때는 그런현상이 없어서 해결방법을 찾아드릴수가 없네요ㅠㅠ

  • Danny 2014.07.18 16:29 신고 ADDR 수정/삭제 답글

    코드 잘보았습니다 !^^
    그런데 위의 파라미터들 q,p,r,k는 어디서 알수있는 정보인가요?
    그리고 그값들에 0.00001 등과 같은 임의의 값을 준이유가 궁금합니다 .

    • 대세를 따르지 않고 대세를 만드는 매몰 2014.07.26 16:25 신고 수정/삭제

      답변이 늦었네요~
      q,p,r,k 와 같은 파라미터들은 일반적인 칼만필터 공식으로

      http://spaurh.egloos.com/viewer/4488676

      http://www.hachangho.com/homev30/bbs/zboard.php?id=tech&page=6&sn1=on&divpage=1&sn=on&ss=off&sc=off&keyword=%C7%CF%C3%A2%C8%A3&select_arrange=hit&desc=asc&no=467&PHPSESSID=1e1b204d4f75879a5104702c1a660548

      를 참고하시면 될듯해요~ 사실 저도 다 이해하고 쓴게 아니라 공식을 그대로 가져와서 프로그램에 맞게 적용한거에요ㅎㅎ

      그리고 파라미터에 0.00001와 같은 값을 준것은 바꿔보면서 테스트를 해보시면 아시겠지만 이 기본값에 따라 보정되는 형태등이 조금씩 바꿔요..

      각각의 프로그램에 맞게 값을 넣어서 쓰면 될듯해요~

  • 이혁 2014.09.03 14:52 신고 ADDR 수정/삭제 답글

    좋은 자료 잘 보았습니다.
    작성 하신 예제를 가지고 참고하여 공부하고 제 블로그에 포스팅 하려고 하는데 괜찮으신가요?? 출처는 꼭 남기겠습니다.

  • 이기엽 2014.10.07 20:04 신고 ADDR 수정/삭제 답글

    안녕하세요
    칼만필터는 저번 학기에 어느정도 배웠지만 저도 주인장님처럼 가벼운 이해만 한 상태라 구글에서도 안나오길래 좌절중이었는데 네이버에서 도움을 받네요 ㅎㅎㅎ
    감사하구요 좋은하루 보내세요!

  • 권용혜 2016.06.30 21:21 신고 ADDR 수정/삭제 답글

    감사합니다

  • 이선민 2017.02.19 08:08 신고 ADDR 수정/삭제 답글

    안녕하세요
    칼만필터에 대해 공부 중인 학생입니다.
    저 예제에서는 가속도 센서에 칼만필터를 적용하신 건가요? 아니면 자이로센서와 가속도센서를 융합시켜 칼만필터를 적용하신 건가요?
    Acc를 보고 가속도센서에 적용시켰다고 생각하는데, 궁금해서 질문드립니다.
    좋은 자료 올려주셔서 많은 도움이 됐습니다. 감사합니다!

TOTAL 69,581 TODAY 10