얼마 전 아는 지인을 통해 칼만필터(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>
칼만필터 미적용 상태
칼만필터 적용 상태
별거 아닐수도 있지만
당시 저는 위와같이 칼만필터를 적용한것과 아닌것을 비교해보고 완전 감동받았습니다ㅎㅎ
역시 세상에는 천재들이 많은것 같아요~ 저런 필터를 다 만들다니... 고맙습니다ㅎㅎ
잘 이용해서 잘 쓸게요~
도움이 되셨다면~ 정성으로 빚은 저희 앱! 많은 이용 바래요:)
https://meorimal.com/index.html?tab=spaceship
https://meorimal.com/subway.html
'개발 > android' 카테고리의 다른 글
가장 기본적이고 간단한 게임 충돌검사 (0) | 2014.05.20 |
---|---|
[엔진없이 게임만들자] 자유자재로 오브젝트 이동시키기 (2) | 2014.04.14 |
안드로이드 앱 런칭후 데이터베이스 변경시 주의할점 (2) | 2014.01.20 |
페이스북 안드로이드 sdk로 담벼락 글쓰기... 정리 2가지 (1) | 2014.01.09 |
스레드에서 View 변경시 Only the original thread…. 에러 대처법 (0) | 2013.11.25 |