티스토리 뷰



이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 - http://www.tipssoft.com/bulletin/tb.php/QnA/8406
* 관리자의 Tipssoft 이야기를 들어보세요 ( 트위터 ID : tipssoft )
* 안드로이드 강좌 목록 - http://www.tipssoft.com/bulletin/tb.php/old_bbs/501

대부분의 안드로이드용 기기에는 현재 기기가 받고 있는 중력을 측정하거나 기기의 이동성을 측정할
수 있는 가속도 센서가 장착되어 있습니다. 가속도를 측정하는 기능은 주사위 굴리기같은 어플리케이션
이나 낚시, 골프 같은 모션을 이용한 스포츠 어플리케이션이나 핸드폰을 흔들어서 사용자 조작을 할 때
많이 사용됩니다.
가속도 센서에서 데이터를 전달받는 것은 센서를 다루는 기본적인 루틴만 알면 되지만 이 데이터를
변환하고, 연산하는 것은 복잡하고 어려울 수 있습니다.
이번 강좌에서는 기기의 현재 중력 및 가속도를 알아내기 위해서 가속도 센서를 이용하는 방법에 대해
알아보도록 하겠습니다. 센서를 사용할 때 기본적으로 사용되는 공통 루틴에 대하여 잘 모르시는 분들은
아래에 링크된 자료를 먼저 참고하여 주시기 바랍니다.
센서를 사용하기 위한 공통 루틴 : http://www.tipssoft.com/bulletin/tb.php/FAQ/1033
1. 센서 측정값에 대하여
가속도 센서는 아래의 그림과 같은 세 방향에 대한 기기의 움직임을 측정합니다.
해당 센서가 측정하는 데이터는 움직임에 대한 값(혹은 기기에 가해지는 중력 값) 이므로 가속도를
측정하려면 측정하고자 하는 기기가 움직인 시간동안의 데이터를 저장한 후 별도로 연산해야 합니다.
기본적인 가속도를 구하는 방법은 직전 움직임 값에서 현재 움직임 값을 빼는 것이며 각 데이터에
대한 설명은 아래와 같습니다.
1.1 X축( Lateral )
기기의 측면을 향한 움직임을 측정합니다. 기기가 좌우로 수평 상태에서 움직임이 없으면 0 값을
가지며 왼쪽으로 기기가 움직이면 X축 값이 증가하고, 오른쪽으로 움직이면 감소합니다.
가속도의 경우에는 실제 데이터와는 반대로 기기가 왼쪽으로 움직이면 가속도가 감소하고,
오른쪽으로 움직이면 증가하게 됩니다.
1.2 Y축( Longitudinal )
기기의 전방/후방을 향한 움직임을 측정합니다. 기기가 수평한 상태에서 움직임이 없으면 0 값을
가지며 전방 즉, 기기의 머리부분으로 기기가 움직이면 Y축 값이 감소하고, 후방으로 움직이면
Y축 값이 증가합니다.
가속도의 경우에는 실제 데이터와는 반대로 기기가 전방으로 움직이면 가속도가 증가하고,
후방으로 움직이면 감소하게 됩니다.
1.3 Z축( Vertical )
기기의 위/아래를 향한 움직임을 측정합니다. Z축 데이터는 X축, Y축과는 달리 중력의 영향을
받기때문에 화면을 하늘로 향한 상태에서 수평을 유지하면 중력값인 9.81 이 측정됩니다. 만약
Z축의 순수 움직임을 측정하고 싶다면 Z축 데이터에서 9.81 을 빼면 됩니다. 그러나 기기를
수직으로 배치하면 중력의 영향이 Z축에서 Y 축으로 이동하므로 기기의 배치에 맞는 축의
데이터에서 중력 값을 빼주어야 합니다.
기기가 윗쪽 즉, 하늘을 향해 움직이면 Z축 값이 감소하고, 땅을 향해 이동하면 Z축 값이
증가합니다. 가속도의 경우에는 실제 데이터와는 반대로 기기가 위로 이동하면 가속도가
증가하고, 아래로 이동하면 감소하게 됩니다.
2. 기능 구현하기
가속도 센서는 사물의 움직임을 측정하는데 이 움직임을 이용하여 다른 성질을 가지는 데이터로
가공할 수 있기때문에 여러가지 방법으로 연산을 하여 사용하곤 합니다. 예를 들어 순수한 움직임만을
측정하는 경우에는 중력의 영향을 받고 있는 축의 데이터에서 9.81을 빼주어야 하고, 가속도를 측정
하려면 2개 이상의 데이터를 모아서 연산을 해주어야합니다.
단순히 전달된 데이터를 출력할 때 데이터 값의 변화를 완충하려면 데이터에 저역 통과 필터( Low-
Pass Filter : LPF) 를 적용해야 합니다. 저역 통과 필터를 사용할 때에는 결과 데이터를 추출하기
위해 사용되는 알파(alpha) 값이 필요한데 이것은 아래와 같은 연산결과로 산출됩니다.
alpha = t / ( t + dT )
t : 저속 통과 필터의 시정수. 시정수란 센서가 가속도의 63% 를 인지하는데 걸리는 시간을 말함.
dT : 이벤트 전송율 혹은 이벤트 전송속도.
위와 같은 alpha 값은 0.8 로 산출되며 alpha 에 직전 데이터를 곱하고, (1 - alpha) 에 현재 데이터를
곱하여 더해주면 필터링된 움직임 값을 얻을 수 있습니다.
아래의 코드는 저역 통과 필터를 적용한 중력 값과 간단한 가속도 값을 구하는 코드입니다.
public class ExamAccelActivity extends Activity implements SensorEventListener
{
// 센서 관련 객체
SensorManager m_sensor_manager;
Sensor m_accelerometer;

// 출력용 텍스트뷰
TextView m_gravity_view;
TextView m_accel_view;

// 실수의 출력 자리수를 지정하는 포맷 객체
DecimalFormat m_format;

// 데이터를 저장할 변수들
float[] m_gravity_data = new float[3];
float[] m_accel_data = new float[3];

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// 포맷 객체를 생성한다.
m_format = new DecimalFormat();
// 소수점 두자리까지 출력될 수 있는 형식을 지정한다.
m_format.applyLocalizedPattern("0.##");

// 출력용 텍스트뷰를 얻는다.
m_gravity_view = (TextView)findViewById(R.id.acceleration);
m_accel_view = (TextView)findViewById(R.id.maxAcceleration);

// 시스템서비스로부터 SensorManager 객체를 얻는다.
m_sensor_manager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
// SensorManager 를 이용해서 가속센서 객체를 얻는다.
m_accelerometer = m_sensor_manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}

// 해당 액티비티가 포커스를 얻으면 가속 데이터를 얻을 수 있도록 리스너를 등록한다.
protected void onResume()
{
super.onResume();
// 센서 값을 이 컨텍스트에서 받아볼 수 있도록 리스너를 등록한다.
m_sensor_manager.registerListener(this, m_accelerometer, SensorManager.SENSOR_DELAY_UI);
}

// 해당 액티비티가 포커스를 잃으면 가속 데이터를 얻어도 소용이 없으므로 리스너를 해제한다.
protected void onPause()
{
super.onPause();
// 센서 값이 필요하지 않는 시점에 리스너를 해제해준다.
m_sensor_manager.unregisterListener(this);
}

// 정확도 변경시 호출되는 메소드. 센서의 경우 걋?호출되지 않는다.
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}

// 측정한 값을 전달해주는 메소드.
public void onSensorChanged(SensorEvent event)
{
// 가속 센서가 전달한 데이터인 경우
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

// 중력 데이터를 구하기 위해서 저속 통과 필터를 적용할 때 사용하는 비율 데이터.
// t : 저속 통과 필터의 시정수. 시정수란 센서가 가속도의 63% 를 인지하는데 걸리는 시간
// dT : 이벤트 전송율 혹은 이벤트 전송속도.
// alpha = t / (t + Dt)
final float alpha = (float)0.8;

// 저속 통과 필터를 적용한 중력 데이터를 구한다.
// 직전 중력 값에 alpha 를 곱하고, 현재 데이터에 0.2 를 곱하여 두 값을 더한다.
m_gravity_data[0] = alpha * m_gravity_data[0] + (1 - alpha) * event.values[0];
m_gravity_data[1] = alpha * m_gravity_data[1] + (1 - alpha) * event.values[1];
m_gravity_data[2] = alpha * m_gravity_data[2] + (1 - alpha) * event.values[2];

// 현재 값에 중력 데이터를 빼서 가속도를 계산한다.
m_accel_data[0] = event.values[0] - m_gravity_data[0];
m_accel_data[1] = event.values[1] - m_gravity_data[1];
m_accel_data[2] = event.values[2] - m_gravity_data[2];

String str;
// 문자열을 구성하여 텍스트뷰에 출력한다.
str = "x : " + m_format.format(m_gravity_data[0]) + ", y : " + m_format.format(m_gravity_data[1]) +
", z : " + m_format.format(m_gravity_data[2]);
m_gravity_view.setText(str);

// 문자열을 구성하여 텍스트뷰에 출력한다.
str = "x : " + m_format.format(m_accel_data[0]) + ", y : " + m_format.format(m_accel_data[1]) +
", z : " + m_format.format(m_accel_data[2]);
m_accel_view.setText(str);
}
}
}
3. 실행 화면


댓글