안드로이드에서 제공하는 가속도 센서는 2개가 있습니다.

이 센서들에 대해서 간단하게 테스트를 해보았습니다.


1. 가속도 센서


가속도 센서(TYPE_ACCELEROMETER)는 중력 가속도와 관계가 있습니다.

이를 확인 하려면 가속도 센서를 켜고 핸드폰을 이리저리 굴려보면 알 수 있습니다.



1.1 좌표에 맞추어 핸드폰 기울이기


간단히 테스트를 해보면 아래 그림과 같은 값을 얻을 수 있습니다.

아주 안정적인 상태에서 테스트 하면 Total Gravity9.8m/s² 값이겠지만 캡처 사진은 오차가 많네요. 수전증인가



그림

 좌표 값

 설명

 z

 x:0, y:0, z:9.8

 - 책상위에 핸드폰을 놓은 경우, 중력가속도 작용

 -z

 x:0, y:0, z:-9.8

 - 핸드폰을 책상 위에 뒤집어 놓은 경우, 마이너스(-)중력 가속도

 x

 x:-9.8, y:0, z:0

 - 핸드폰 우측 면을 기준으로 90도 세운경우, 중력가속도 x축 적용.

 - 핸드폰 좌측 면을 기준으로 90도 세우면 값은 양수(+) 중력가속도

 y

 x:0, y:0-9.8 z:0

 - 핸드폰을 상단면을 기준으로 90도 세운경우, 중력가속도 y축 적용.

 - 핸드폰을 하단면을 기준으로 90도 세운경우, 양수(+) 중력가속도.


핸드폰을 x, y축을 기준으로 했을 경우의 반대 방향에 대한 그림은 생략 했습니다.



1.2 임의 방향으로 핸드폰 기울이기



지금까지는 직각 방향에 대한 내용이고 만일 핸드폰을 비스듬하게 놓으면 어떤 값을 나타 낼까요?

중력가속도는 9.8로 일정하게 작용하기 때문에 기울어진 각도 만큼 z축이 가지고 있던 9.8의 값을

x축과 y축이 나누어 받게 됩니다.


어째든 결과는 총 가속도 값이 9.8로 항상 동일 합니다.






피타고라스의 정리에 의해 직각삼각형의 빗변의 길이를 구하는 공식을 참고하면

직각 사각형의 크기도 구할 수 있습니다.

그러면 기울어진 핸드폰의 총 가속도 크기는 각 변의 제곱을 더한 값을 제곱근 하면 됩니다.

핸드폰 좌표 그림에서 보듯이 중력가속도는 지구 중심을 향하기 때문에 양(+)의 좌표 값이 반대로 됩니다.



2. 가속도 센서 중력 영향 제거


가속도 센서가 중력의 영향을 받기 때문에 실제 응용 프로그램을 만들려면 중력가속도에 대한

값을 상쇄시켜줘야 합니다.

우리가 생활 하는데 마치 중력이 없는 것 처럼 해야 한다는 것이지요.

게임을 만들때는 중력값을 달처럼 해서 작업한다고 하는데 안해봐서 모르겠지만 잼있겠네요.


private float accX, accY, accZ, tempX, tempY, tempZ;
private float alpha = 0.8f;

tempX = alpha * tempX + (1 - alpha) * event.values[0];
tempY = alpha * tempY + (1 - alpha) * event.values[1];
tempZ = alpha * tempZ + (1 - alpha) * event.values[2];

accX = event.values[0] - tempX;
accY = event.values[1] - tempY;
accZ = event.values[2] - tempZ;

이렇게 하면 x, y, z축의 값이 0가 되어 속도계나 다른 작업에 사용할 수 있습니다.



3. 선형 가속도 센서


그런데 구글에서는 중력가속도를 제거한 가속도 센서를 제공하고 있습니다.

그 센서는 TYPE_LINEAR_ACCELERATION 이것 입니다.


TYPE_LINEAR_ACCELERATION 센서에 대한 구글의 설명을 살펴볼까요?

구글 사이트에서 그대로 일부를 뜯어와서 밑줄만 그어봤습니다.



TYPE_ACCELEROMETER는 중력가속도가 포함되어 있고

TYPE_LINEAR_ACCELERATION는 중력가속도를 제거한 값이라는 군요.

 


4. 가속도 센서 비교


그럼 이 3가지 경우에 대해서 한번에 다 몰아서 비교를 해보도록 하겠습니다.

우선 결과를 보도록 하겠습니다.


accelerometer linear


제일 상단이 TYPE_ACCELEROMETER 센서 값을 그대로 보여주는 것이고

두번째 값이 TYPE_ACCELEROMETER 센서 값에서 중력을 제거한 경우

마지막이 TYPE_LINEAR_ACCELERATION 센서 값입니다.


두번째와 세번째 값이 동일(제 핸드폰기준)한 것을 알 수 있습니다.



5. 가속도 센서 프로젝트


이번에도 activity_main.xml MainActivity.java 두개의 파일로 구성되어 있습니다.

프로젝트를 적당히 하나 만드시고 작업하면 됩니다.

만들기 싫으면 소스를 받아서 테스트 하거나 APK 파일을 받아 사용해도 됩니다.


5.1 Layout


결과들을 보여줄 TexvView13개 만들어 줍니다.

쓸데없이 소스만 깁니다.


activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Accelerometer Compare"
        android:layout_marginTop="10dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvgXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvgYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvgXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvgZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvgYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvgTotal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvgZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Speed : 0"
        />

    <TextView
        android:id="@+id/tvXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvgTotal"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvTotal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Speed : 0"
        />

    <TextView
        android:id="@+id/tvlXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTotal"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvlYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvlXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvlZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvlYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvlTotal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvlZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Speed : 0"
        />
</android.support.constraint.ConstraintLayout>


5.2 Java Source


MainActivity.java

가속도 센서 2개의 값을 구하고 중력가속도를 제거하는 값을 구하는 프로그램 입니다.

위에서 설명을 하여 추가적인 설명이 필요없이 보시면 알 수 있습니다.

 


package com.example.desk.accelercompare;

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.widget.TextView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor accelerSensor;
    private Sensor linearAccelerSensor;
    private float gAccX, gAccY, gAccZ, accX, accY, accZ, lAccX, lAccY, lAccZ ;
    private float tempX, tempY, tempZ;
    private double gTotal, total, lTotal;
    private long lastUpdate = 0;
    private float alpha = 0.8f;
    TextView tvgXaxis, tvgYaxis, tvgZaxis, tvXaxis, tvYaxis, tvZaxis, tvlXaxis, tvlYaxis, tvlZaxis, tvgTotal, tvTotal, tvlTotal;

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

        tvgXaxis = (TextView)findViewById(R.id.tvgXaxis);
        tvgYaxis = (TextView)findViewById(R.id.tvgYaxis);
        tvgZaxis = (TextView)findViewById(R.id.tvgZaxis);
        tvXaxis = (TextView)findViewById(R.id.tvXaxis);
        tvYaxis = (TextView)findViewById(R.id.tvYaxis);
        tvZaxis = (TextView)findViewById(R.id.tvZaxis);
        tvlXaxis = (TextView)findViewById(R.id.tvlXaxis);
        tvlYaxis = (TextView)findViewById(R.id.tvlYaxis);
        tvlZaxis = (TextView)findViewById(R.id.tvlZaxis);
        tvgTotal = (TextView)findViewById(R.id.tvgTotal);
        tvTotal  = (TextView)findViewById(R.id.tvTotal);
        tvlTotal = (TextView)findViewById(R.id.tvlTotal);

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        accelerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        linearAccelerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, accelerSensor, SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, linearAccelerSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor == accelerSensor) {
            //include gravity
            gAccX = event.values[0];
            gAccY = event.values[1];
            gAccZ = event.values[2];

            tempX = alpha * tempX + (1 - alpha) * event.values[0];
            tempY = alpha * tempY + (1 - alpha) * event.values[1];
            tempZ = alpha * tempZ + (1 - alpha) * event.values[2];

            accX = event.values[0] - tempX;
            accY = event.values[1] - tempY;
            accZ = event.values[2] - tempZ;

            gTotal = Math.sqrt(Math.pow(gAccX,2) + Math.pow(gAccY, 2) + Math.pow(gAccZ , 2));
            total = Math.sqrt(Math.pow(accX,2) + Math.pow(accY, 2) + Math.pow(accZ , 2));

            tvgXaxis.setText("X axis : " + String.format("%.2f", gAccX));
            tvgYaxis.setText("Y axis : " + String.format("%.2f", gAccY));
            tvgZaxis.setText("Z axis : " + String.format("%.2f", gAccZ));
            tvgTotal.setText("Total Gravity : "  + String.format("%.2f", gTotal) + " m/s\u00B2");

            tvXaxis.setText("X axis : " + String.format("%.2f", accX));
            tvYaxis.setText("Y axis : " + String.format("%.2f", accY));
            tvZaxis.setText("Z axis : " + String.format("%.2f", accZ));
            tvTotal.setText("Total Gravity : "  + String.format("%.2f", total) + " m/s\u00B2");
        }

        if(event.sensor == linearAccelerSensor) {
            //exclude gravity
            lAccX = event.values[0];
            lAccY = event.values[1];
            lAccZ = event.values[2];

            lTotal = Math.sqrt(Math.pow(lAccX,2) + Math.pow(lAccY, 2) + Math.pow(lAccZ , 2));

            tvlXaxis.setText("X axis : " + String.format("%.2f", lAccX));
            tvlYaxis.setText("Y axis : " + String.format("%.2f", lAccY));
            tvlZaxis.setText("Z axis : " + String.format("%.2f", lAccZ));
            tvlTotal.setText("Total Gravity : "  + String.format("%.2f", lTotal) + " m/s\u00B2");


        }
    }

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

    }
}



5.3 Source file

 

AccelerCompare.7z


 

5.4 APK file


AccelerCompare.apk


- copy coding -


TYPE_MAGNETIC_FIELD는 지구 자기장의 강도를 수치로 보여주는 센서로 주변 금속의 강도에 따라 맴돌이 전류가 발생하여

자기장이 영향을 받는 것을 이용해 간단한 금속탐지기 기능을 구현해 봅니다.


지자기장은 지구의 위치마다 달라 20~80정도로 차이가 발생하고 한국은 50정도 입니다.

좀더 성능 좋은 금속탐지기를 만들려면 TYPE_MAGNETIC_FIELD_UNCALIBRATED 센서를 이용해서

원래의 값을 받아와 보정 작업을 진행해야 합니다.



1 자기장 센서


1.1 자기장 센서 이벤트 값


TYPE_MAGNETIC_FIELD 센서가 작동 되면 리턴되는 값으로 다음과 같은 value를 넘겨 주며 단위는 μT(마이크로 테슬라)입니다.

리턴된 값은 센서에서 보내주는 값들을 자체 보정 해서 나온 수치 입니다.


Sensor

 Sensor event data

 표현 값

 측정 단위

 TYPE_MAGNETIC_FIELD

 SensorEvent.values[0]

 x축 지구자장 강도

 μT

 TYPE_MAGNETIC_FIELD

 SensorEvent.values[1]

 y축 지구자장 강도

 μT

 TYPE_MAGNETIC_FIELD

 SensorEvent.values[2]

 z축 지구자장 강도

 μT



2 자기장 센서 프로젝트

 

2.1 신규 프로젝트 생성


안드로이드 스튜디오에서 적당한 이름으로 프로젝트를 하나 생성합니다.



2.2 Layout 작성


activity_main.xml

 

자기장 센서가 보내오는 x, y, z축의 μT값들을 출력할 수 있는 TextView를 작성합니다.

그리고 간략한 금속 탐지 기능을 보여줄 TextView도 하나 생성 합니다.


<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Megnetic Value"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvMagnetic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Magnetic : 0"
        />

</android.support.constraint.ConstraintLayout>



2.3 Java Source

 

MainActivity.java


소스를 보면 알겠지만 기존 센서와 동일한 프로세스로 작동이 됩니다.

자세한 설명은 생략 합니다. 기존 센서 예제를 확인 하세요.

onCreate에서 Sensor.TYPE_MAGNETIC_FIELD를 설정 하고 onSensorChanged에서 x, y, z 축의 magnetic 값을 받아와 출력 합니다.


지자기 총량을 구하는 공식은

Math.sqrt((magX * magX) + (magY * magY) + (magZ * magZ))

입니다.


package com.example.desk.sensormagnetic;

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.widget.TextView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor magSensor;
    int rotation;
    TextView tvXaxis, tvYaxis, tvZaxis, tvMagnetic;

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

        tvXaxis = (TextView)findViewById(R.id.tvXaxis);
        tvYaxis = (TextView)findViewById(R.id.tvYaxis);
        tvZaxis = (TextView)findViewById(R.id.tvZaxis);
        tvMagnetic = (TextView)findViewById(R.id.tvMagnetic);

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        magSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, magSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor ==magSensor) {
            float magX = event.values[0];
            float magY = event.values[1];
            float magZ = event.values[2];
            double magnitude = Math.sqrt((magX * magX) + (magY * magY) + (magZ * magZ));

            tvXaxis.setText("X axis : " + String.format("%.2f", magX));
            tvYaxis.setText("Y axis : " + String.format("%.2f", magY));
            tvZaxis.setText("Z axis : " + String.format("%.2f", magZ));
            tvMagnetic.setText("Magnetic : "  + String.format("%.2f", magnitude) + " \u00B5Tesla");
        }
    }

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

    }
}


µ를 나타내기 위해 사용한 u00B5는 유니코드입니다.

인터넷에서 유니코드를 검색하면 표로 잘 나와있어서 앞자리+윗자리 숫자를 조합해서 사용하면 됩니다.


위키 백과사전에서 조금 뜯어왔습니다.


magnetic field sensor



3. 결과


3.1 결과 화면


프로젝트를 실제 핸드폰에서 테스트한 결과 화면인데요.

책상 위에 놓았을 때 하고 컴퓨터 위에 놓았을 때의 값을 비교해보고

책상 위에서 자석을 위치 했을 때의 값을 비교해 보았습니다.

방구석에 처박혀 있을 때 켜놓고 이리저리 굴러다니며 테스트하면 나름 재미있습니다.


magnetic field sensor

magnetic field sensor



3.2 Source Code

 

 

SensorMagnetic.7z



3.3 APK File


SensorMagnetic.apk


- copy coding -

 

안드로이드 핸드폰 뿐만 아니라 대부분의 이동형 장치는 위치에 따라 기본 방향이 설정되어 있습니다. 

이걸 기준으로 화면 자동 회전을 설정해 놓아 사진 가로보기가 가능 합니다.

동서남북을 가리키는 나침반은 방향을 바꾸면 그에 맞추어 위치를 다시 계산해야 합니다.

일반적인 컴퓨터 모니터는 우측상단이 원점이고 가로 방향이 x, 세로 아래 방향이 y축이지만

Android 기기 에서는 일반적인 수학에서 배운 대로 가로 방향이 x, 세로 방향이 y, 나를 향하는 전면 방향을 z축으로 설정 합니다.

좌표 축은 이렇게 설정이 되어 있지만 장치가 세로로 있을 때 우측(가로) 방향이 x축 일까요?

태블릿 장치는 가로로 있을 때 우측 방향이 x축 일까요?


Android를 사용하는 모든 기기가 동일 하지 않다고 하니 방향과 축에 관련된 앱을 개발하려면 한번쯤 확인을 하는게 좋을 듯 합니다.



1. 상수 값


방향 확인을 위해 장치가 어느 방향으로 회전 되어 있는가를 확인하는 상수 값이 있습니다.


 Type

 Constants

 value

 설명

 int

 Surface.ROTATION_0

 0

 장치가 사용자 기준 정방향

 int

 Surface.ROTATION_90

 1

 장치가 사용자 기준 반 시계방향 90도 회전

 int

 Surface.ROTATION_180

 2

 장치가 사용자 기준 반 시계방향 180도 회전

 int

 Surface.ROTATION_270

 3

 장치가 사용자 기준 반 시계방향 270도 회전

 int

 SensorManager.AXIS_X

 1

 X축에 해당하는 상수 값

 int

 SensorManager.AXIS_Y

 2

 Y축에 해당하는 상수 값

 int

 SensorManager.AXIS_Z

 3

 Z축에 해당하는 상수 값

 int

 SensorManager.AXIS_MINUS_X

 129

 X축 반대 방향에 해당하는 상수 값

 int

 SensorManager.AXIS_MINUS_Y

 130

 Y축 반대 방향에 해당하는 상수 값

 int

 SensorManager.AXIS_MINUS_Z

 131

 Z축 반대 방향에 해당하는 상수 값



2. 회전 결과


먼저 앱을 실행하였을 때의 결과를 보면 간단하게 확인이 가능 합니다.

앱을 켜고 핸드폰을 좌측으로 한 바퀴, 우측으로 한 바퀴 돌리며 결과를 보면

반 시계방향으로 90도씩 증가하는 하며 180도 에서는 어느 방향으로 돌렸는가에 따라

90, 270도의 결과가 그대로 유지 됩니다.


android gyroscope sensor



3. 화면 회전 프로젝트

 

실제 프로젝트 하나를 만들어 보겠습니다.

 

3.1 신규 프로젝트 생성


Android studio에서 새로운 프로젝트를 생성합니다. 여기서는 SurfaceRotation로 했습니다.

캡처 화면은 팝업을 축소하여 받은 것으로 실제 화면의 일부분 입니다.




3.2 장치 설정


앱이 실행될 기본 장치를 알맞게 선택 합니다.




3.3 Configure


기본 화면은 empty를 선택 했고 코딩용 설정 값은 기본값을 그대로 사용 합니다.



 

3.4 Layout 작성


x, y 축의 값을 보여주고 회전 각을 표시하기 위한 TextView를 축의 개수에 맞게 생성 합니다.


<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Surface Rotation"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvRotation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Rotation : 0"
        />

</android.support.constraint.ConstraintLayout>


3.5 Java Source


소스는 일반적인 센서 테스트용 프로젝트와 동일한 구조를 갖고 있습니다.

센서는 TYPE_GYROSCOPE를 사용 했는데 별의미 없으므로 다른 센서를 사용해도 됩니다.

화면 회전에 대한 값을 구하기 위한 getSurfaceRotation() 함수가 추가되었습니다.

이 함수에서 화면에 값을 출력 합니다.


package com.example.desk.surfacerotation;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
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.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity  implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor gyroSensor;
    int rotation;
    TextView tvXaxis, tvYaxis, tvZaxis, tvRotation;

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

        tvXaxis = (TextView)findViewById(R.id.tvXaxis);
        tvYaxis = (TextView)findViewById(R.id.tvYaxis);
        tvZaxis = (TextView)findViewById(R.id.tvZaxis);
        tvRotation = (TextView)findViewById(R.id.tvRotation);

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

    }

    void getSurfaceRotation() {
        String windowsService = Context.WINDOW_SERVICE;
        WindowManager windowManager = (WindowManager)getSystemService(windowsService);
        Display display = windowManager.getDefaultDisplay();
        rotation = display.getRotation();

        int xAxis = SensorManager.AXIS_X;
        int yAxis = SensorManager.AXIS_Y;
        int zAxis = SensorManager.AXIS_Z;

        switch (rotation) {
            case Surface.ROTATION_0:
                tvRotation.setText("Rotation : 0");
                break;
            case Surface.ROTATION_90:
                xAxis = SensorManager.AXIS_Y;
                yAxis = SensorManager.AXIS_MINUS_X;
                tvRotation.setText("Rotation : 90");
                break;
            case Surface.ROTATION_180:
                yAxis = SensorManager.AXIS_MINUS_Y;
                tvRotation.setText("Rotation : 180");
                break;
            case Surface.ROTATION_270:
                xAxis = SensorManager.AXIS_MINUS_Y;
                yAxis = SensorManager.AXIS_X;
                tvRotation.setText("Rotation : 270");
                break;
            default:
                break;
        }
        tvXaxis.setText("X axis : " + String.valueOf(xAxis));
        tvYaxis.setText("Y axis : " + String.valueOf(yAxis));
        tvZaxis.setText("Z axis : " + String.valueOf(zAxis));
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, gyroSensor, SensorManager.SENSOR_DELAY_FASTEST);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor ==gyroSensor) {
            getSurfaceRotation();
        }
    }

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

    }
}


4. 결과


4.1 결과 화면


위에서 회전각을 표시한 그림과 같은 결과들을 볼 수 있습니다.



3.2 Source Code

소스코드를 첨부 합니다.


SurfaceRotation.7z



 

3.3 APK File

직접 테스트 하려면 apk를 이용 하세요.


SurfaceRotation.apk


- copy coding -


TYPE_LIGHT는 빛의 세기를 전기적 신호로 변경하여 수치로 보여주는 센서로

핸드폰의 앞면에 위치하고 화면의 자동 밝기 자동 조절등에 사용 되는 기능 입니다.



1 광 센서


1.1 광 센서 이벤트 값


센서가 작동 되면 리턴되는 값으로 한 개의 value를 넘겨 주며 단위는 lux(lx) 입니다.


 Sensor

 Sensor event data

 표현 값

 측정 단위

 TYPE_LIGHT

 SensorEvent.values[0]

 물체의 밝기

 lx



1.2 설정 상수 값



광 센서가 리턴하는 값은 float 값으로 나타나며 일부 설정되어 있는 상수 값은 아래 표와 같습니다.


Type

 상수

 값

 float

 LIGHT_CLOUDY

 100.0

 float

 LIGHT_FULLMOON

 0.25

 float

 LIGHT_NO_MOON

 0.001

 float

 LIGHT_OVERCAST

 10000.0

 float

 LIGHT_SHADE

 20000.0

 float

 LIGHT_SUNLIGHT

 110000.0

 float

 LIGHT_SUNLIGHT_MAX

 120000.0

 float

 LIGHT_SUNRISE

 400.0



2 광센서 프로젝트



2.1 신규 프로젝트 생성


안드로이드 스튜디오에서 프로젝트를 하나 생성합니다.



2.2 AndroidManifest.xml


Google play에서는 앱을 다운로드 하기 전에 해당 기능을 실행할 장치가 있는지 확인하여


장치가 없으면 실행을 할 수 없도록 제한 하고 있습니다.


<uses-feature>를 설정하고 값을 false로 하면 장치가 없어도 앱을 다운받아 실행 할 수 있도록 할 수 있습니다.


<uses-feature android:name="android.hardware.sensor.light" android:required="false"/>


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.desk.lightsensor">

    <uses-feature android:name="android.hardware.sensor.light" android:required="false"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>



2.3 Layout 작성


activity_main.xml


 센서가 보내오는 lux값을 출력할 수 있는 TextView를 작성합니다.


tvTitle TextView는 고정해서 Proximity Sensor를 출력 하고 센서로부터 받아온 값은 tvLight TextView에 출력 합니다.


<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Light Sensor"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvLight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Light : 0"
        />
</android.support.constraint.ConstraintLayout>



2.4 Java Source


소스를 보면 알겠지만 기존 센서와 동일한 프로세스로 작동이 됩니다.


자세한 설명은 생략 합니다. 기존 센서 예제를 확인 하세요.


onCreate에서 TYPE_LIGHT를 설정 하고 onSensorChanged 에서 조도 값을 받아와 출력 하면 됩니다.


package com.example.desk.lightsensor;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor lightSensor;
    TextView tvLight;

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

        tvLight = (TextView)findViewById(R.id.tvLight);
        sensorManager =(SensorManager)getSystemService(Context.SENSOR_SERVICE);
        lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
        if(lightSensor == null) {
            Toast.makeText(this, "No Light Sensor Found!", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_LIGHT) {
            tvLight.setText("Light : " + String.valueOf(event.values[0]));
        }
    }

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

    }

}



3. 결과


3.1 결과 화면


프로젝트를 실행 실제 핸드폰에서 테스트한 결과 아래와 같은 화면이 나옵니다.


우리집 거실이 어두운 편이네요.


android light sensor



3.2 Source Code


압축을 풀어서 사용하세요.


LightSensor.7z




3.3 APK File


그냥 확인만 해보려면 사용해 보세요.


LightSensor.apk


- copy coding -


1···121314151617

+ Recent posts