본문으로 바로가기



#소개하는 내용의 일부는 Android Develop API Guides 참고했습니다.

 

안녕하세요. PEACE- 에요.

안드로이드 스터디의 [두 번째] 글이네요.

 

오늘은 지난 포스팅에 이어 ANDROID 에서 지원하는 MotionSensor중 GyroscopeSensor 알아보겠습니다.

 

목차는 다음과 같습니다.


    1. Simple Overview
       2. How to use?

       




       

       


      안드로이드 플랫폼은 3가지 범주의 센서를 지원합니다.

       - 모션 센서, 환경 센서, 위치 센서

       

      함께 알아 센서는 바로 '모션 센서' 입니다.

       

      모션 센서(Motion Sensor) 안에서도 'Software-based' 'Hardware-based' 있지만

      'Hardware-based' 속하는 센서를 알아볼 입니다.


        1. 가속도계 센서(Accelometer Sensor) - 2017/01/20 게시
          2. 자이로스코프 센서(Gyroscop Sensor) - 본 포스팅

             

            본 포스팅에서는 자이로스코프 센서(Accelometer Sensor)'에 대해 다루겠습니다.

             

             

             

             

             

             

             

             


            우리가 이 센서들을 사용하는가?


            기본적으로

             안드로이드에서 제공하는 Motion Sensor API 통해 센서에서 정밀하게 측정되는 값을 추출하고

            데이터를 분석할 있는 '모니터링' 하기 위해서입니다.

              역시 그렇답니다.

             

             

             


             






            # 1 Simple Overview


            1. 자이로스코프 센서는 3차원 공간에서의 회전각에 대한 값(value)을 알려줍니다.


            2. X Y Z축의 성분을 알아낼 수 있으며, 회전각 Roll, Pitch, Yaw를 구할 수 있습니다.


             

             

             

             

             

             

             


             

            3. 자이로스코프 센서 활용의 이해를 돕기위해 그림으로 간단하게 표현하겠습니다.

             

            아래 그림은 안드로이드 폰(LG G2)를 통해 얻어낸 결과입니다.

            [그림 2]  자이로스코프 센서의 각 축의 성분과 회전 각

             

            [그림 2]를 통해 각 축에 대한 회전각 성분과 성분으로 얻어낼 수 있는 회전각을 알 수 있다.

             

             

             

             

             

             

             

             

            그렇다면 회전각은 어떻게 구할까?

             

            자이로스코프 센서의 회전각은 회전각 성분을 적분하며 얻어낸다.

             

            수식 :

            '회전각 = 이전 회전각 + 회전각 성분*dt'

            (단위는 radian이다. 각도로 표현하기 위해서는 '180/PI'해주어 단위 변환을 해야한다.

            dt는 센서를 통해 값이 얻어지는 주기이다.)

              

            한계 점 : 적분에 의해 회전각을 구하하는 과정에서 적분 오차가 생긴다.

            그리고 그 오차가 누적되어 회전각 드리프트 현상이 발생한다.

            이에 대한 자세한 설명과 해결 방안에 대한 얘기는

            다음에 포스팅하겠습니다.

             

            값이 얻어지는 주기를 빠르게 또는 느리게 하기 위해서는

             센서매니저를 통해 리스터를 등록할때 세번째 인자를 바꿔주면 됩니다.

            [그림 3] 센서 리스너 등록시 센서 값 호출 주기 변경하기

             

             

             

             

             

             

             

             

             

             

             

             

             

            # 2 How to use?

             


            #프로그램 소개

            버튼을 누르고 있는 동안 GyroscopeSensor가 작동한다.

            출력은 로그를 통해 회전각 성분 X Y Z값을 출력했다.

            추가로 Z Y Z의 출력 값을 통해 얻어진 회전각 Roll, Pitch, Yaw를 출력했다. 

             

             

             #실행결과

             

             

             

             

             

             

             

             

             

             #소스코드

             

            activity_main.xml

            <android.support.constraint.ConstraintLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="peace.gyroscope.MainActivity">


            <Button
            android:id="@+id/a_start"
            android:layout_width="368dp"
            android:layout_height="495dp"
            android:text="Button"
            tools:layout_editor_absoluteX="8dp"
            tools:layout_editor_absoluteY="8dp" />


            </android.support.constraint.ConstraintLayout>

            MainActivity.class




            import android.content.Context;
            import android.hardware.Sensor;
            import android.hardware.SensorEvent;
            import android.hardware.SensorEventListener;
            import android.hardware.SensorManager;
            import android.support.v7.app.AppCompatActivity;
            import android.os.Bundle;
            import android.util.Log;
            import android.view.MotionEvent;
            import android.view.View;

            public class MainActivity extends AppCompatActivity {

            //Using the Accelometer & Gyroscoper
            private SensorManager mSensorManager = null;

            //Using the Gyroscope
            private SensorEventListener mGyroLis;
            private Sensor mGgyroSensor = null;

            //Roll and Pitch
            private double pitch;
            private double roll;
            private double yaw;

            //timestamp and dt
            private double timestamp;
            private double dt;

            // for radian -> dgree
            private double RAD2DGR = 180 / Math.PI;
            private static final float NS2S = 1.0f/1000000000.0f;

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

            //Using the Gyroscope & Accelometer
            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

            //Using the Accelometer
            mGgyroSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
            mGyroLis = new GyroscopeListener();

            //Touch Listener for Accelometer
            findViewById(R.id.a_start).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()){

            case MotionEvent.ACTION_DOWN:
            mSensorManager.registerListener(mGyroLis, mGgyroSensor, SensorManager.SENSOR_DELAY_UI);
            break;

            case MotionEvent.ACTION_UP:
            mSensorManager.unregisterListener(mGyroLis);
            break;

            }
            return false;
            }
            });

            }

            @Override
            public void onPause(){
            super.onPause();
            Log.e("LOG", "onPause()");
            mSensorManager.unregisterListener(mGyroLis);
            }

            @Override
            public void onDestroy(){
            super.onDestroy();
            Log.e("LOG", "onDestroy()");
            mSensorManager.unregisterListener(mGyroLis);
            }

            private class GyroscopeListener implements SensorEventListener {

            @Override
            public void onSensorChanged(SensorEvent event) {

            /* 각 축의 각속도 성분을 받는다. */
            double gyroX = event.values[0];
            double gyroY = event.values[1];
            double gyroZ = event.values[2];

            /* 각속도를 적분하여 회전각을 추출하기 위해 적분 간격(dt)을 구한다.
            * dt : 센서가 현재 상태를 감지하는 시간 간격
            * NS2S : nano second -> second */
            dt = (event.timestamp - timestamp) * NS2S;
            timestamp = event.timestamp;

            /* 맨 센서 인식을 활성화 하여 처음 timestamp가 0일때는 dt값이 올바르지 않으므로 넘어간다. */
            if (dt - timestamp*NS2S != 0) {

            /* 각속도 성분을 적분 -> 회전각(pitch, roll)으로 변환.
            * 여기까지의 pitch, roll의 단위는 '라디안'이다.
            * SO 아래 로그 출력부분에서 멤버변수 'RAD2DGR'를 곱해주어 degree로 변환해줌. */
            pitch = pitch + gyroY*dt;
            roll = roll + gyroX*dt;
            yaw = yaw + gyroZ*dt;

            Log.e("LOG", "GYROSCOPE [X]:" + String.format("%.4f", event.values[0])
            + " [Y]:" + String.format("%.4f", event.values[1])
            + " [Z]:" + String.format("%.4f", event.values[2])
            + " [Pitch]: " + String.format("%.1f", pitch*RAD2DGR)
            + " [Roll]: " + String.format("%.1f", roll*RAD2DGR)
            + " [Yaw]: " + String.format("%.1f", yaw*RAD2DGR)
            + " [dt]: " + String.format("%.4f", dt));

            }
            }

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

            }
            }

            }











            댓글공감은 환영입니다.