GPS를 이용하여 속도를 측정 해보기로 했습니다.

고등학교 물리 시간에 속시거(속도는 시간 / 거리)라고 외우도록 해서 아직도 기억을 하고 있는데

그외에도 물가중(물체의 힘은 가속도 x 중력)등 이제는 많이 잊어 버렸네요.

가장 중요한 건 단위를 알면 계산이 가능하다는 사실만 알고 있으라고 해서

대학교 물리, 고체, 유체, 열역학 시간에 도움이 많이 되었는데또 딴데로 가네.

 

사실 GPS로 속도 측정은 별로 쓸말이 없습니다.

GPS 측정 자체에 소도가 들어 있고 측정 시간도 들어 있어서 따로 열심히 계산할 것도 없고

차를 타고 다니며 확인을 하는게 전부입니다.

 


1. Location Class


많은 기능들이 있지만 이곳에서 사용하는 method를 기준으로 몇 개만 소개 합니다.


Type 

 Method

 설명

 float

 distanceTo(Location dest)

 주어진 위치와의 거리 차에 대한 근사치 값(m)

 long

 getTime()

 1970.1.1 기준 밀리세컨드

 float

 getSpeed()

 속도(m/s), 지상에서의 이동 기준


- distanceTo(Location dest)


ALocationBLocation이 있다고 할 때 두 위치의 거리 차를 구할 때 사용 합니다.

사용 방법은 : ALocation.distanceTo(Location BLocation)

 

- getTime()


주어진 위치 값을 구한 시간 정보를 가져 옵니다. ALocation 값을 구한 시간을 알고 싶다면

사용 방법 : ALocation.getTime();

 

- getSpeed()


위치의 변화가 있다면 직전 위치에서 현재 위치까지 이동하는데 소요된 시간으로 속도를

자동으로 계산해서 보여 줍니다.

ALocation에서의 속도를 구한다면

사용 방법 : ALocation.getSpeed()

 

 

2. 속도 측정 프로그램

 

2.1 신규 프로젝트 생성

 

프로젝트를 임의의 이름으로 생성해 줍니다.

 

여기서는 DeviceAndroid 4.0을 선택 하고



ActivityEmpty로 설정 했습니다.



 

2.2 Permission


위치에 대한 자료를 얻기 위해서는 장치 사용에 대한 권한 허가가 필요하고

GPS를 사용하기 위한 권한을 추가 합니다.

AndroidManifest.xml


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">


2.3 Layout 작성

 

GridLayout을 이용해서 폼을 잡고 TextView를 두줄로 배열 했습니다.


<GridLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="2"
    app:layout_constraintTop_toBottomOf="@+id/tvTitle"
    >

    <TextView
        android:id="@+id/tvGpsEnableLabel"
        android:layout_gravity="right"
        android:textSize="25dp"
        android:text="GPS Enable "
        />
    <TextView
        android:id="@+id/tvGpsEnable"
        android:text=":"
        android:textSize="25dp"
        />

… 이하 생략



2.4 MainActivity.java

 

- 권한 설정


AndroidManifest.xml에 추가한 권한 이외에도 Android 6.0 부터는 source 안에도 권한에 대한 체크를 하도록 하여 추가를 해줍니다.


//권한 체크
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }


- 위치정보 업데이트 등록


이동시 위치정보 업데이트를 위해 함수를 사용해 등록 합니다.


requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)


provider : 현재 위치정보 제공자가 GPS이고


minTime : 몇 초마다 정보를 update 할것인가 설정하는 최소 시간입니다.

현재 0을 주고 테스트 하는데 시간간격이 1000(1초)로 나오는 것으로 봐서 기본 1초 인듯합니다.

0으로 설정한 경우와 1000으로 한 경우 저속에서는 조금 차이가 있는 것 같습니다.

심심하면 시간과 거리 값을 조금씩 수정해서 테스트 해보세요.


minDistance : 거리 이동을 얼마나 할때마다 update 하는지에 대한 값입니다.


listener : 말 그대로 LocationListener 입니다.

 

- getSpeed()

double getSpeed = Double.parseDouble(String.format("%.3f", location.getSpeed()));

자동 속도 계산 값 입니다.  소수점 3자리로 하려고 하는데 2자리만 나오는 것으로 봐서

기본이 소수점 2자리 인 것 같습니다.

 

- 시간 간격

deltaTime = (location.getTime() - mLastlocation.getTime()) / 1000.0;

getTime()으로 얻은 시간은 milliseconds 이므로 1000 으로 나누어 주어야 m/s로 계산할 수 있습니다.

 

- 거리 간격

mLastlocation.distanceTo(location)

두 지점의 거리 차이를 구하며 meter 단위로 리턴 받습니다.

 

- 속도 계산

speed = mLastlocation.distanceTo(location) / deltaTime;

미터로 구한 거리를 시간 간격(밀리세턴드를 미터로 변경한 값)으로 나누어 구합니다.

 

- 위치 구하기 제거

ocationManager.removeUpdates(this);

프로그램이 중단 또는 종료되어 더 이상 위치를 구할 필요가 없는 경우 호출 합니다.


 

3. 결과



3.1 결과 화면

 

일정 속도로 이동하면 비슷한 결과가 나오는데 손으로 쥐고 걸어가면서 하면 두개의 값에 차이가 나는군요.


android gps 속도 측정



3.2 Source Code

 

GpsSpeed.7z



3.3 APK File


gpsSpeed.apk



4. Source Code

 


4.1 AndroidMainfest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.will.gpsspeed">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <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>


4.2 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="GPS Speed Test"
        android:layout_marginTop="20dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <GridLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:columnCount="2"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        >

        <TextView
            android:id="@+id/tvGpsEnableLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="GPS Enable "
            />
        <TextView
            android:id="@+id/tvGpsEnable"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvGetSpeedLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Get Speed "
            />
        <TextView
            android:id="@+id/tvGetSpeed"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvCalSpeedLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Cal Speed "
            />
        <TextView
            android:id="@+id/tvCalSpeed"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvTimeLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Time "
            />
        <TextView
            android:id="@+id/tvTime"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvLastTimeLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Last Time "
            />
        <TextView
            android:id="@+id/tvLastTime"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvTimeDifLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="시간 간격 "
            />
        <TextView
            android:id="@+id/tvTimeDif"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvDistDifLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="거리 간격 "
            />
        <TextView
            android:id="@+id/tvDistDif"
            android:text=":"
            android:textSize="25dp"
            />
    </GridLayout>

</android.support.constraint.ConstraintLayout>


4.3 MainActivity.java


package com.example.will.gpsspeed;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class MainActivity extends AppCompatActivity implements LocationListener {

    private LocationManager locationManager;
    private Location mLastlocation = null;
    private TextView tvGetSpeed, tvCalSpeed, tvTime, tvLastTime, tvGpsEnable, tvTimeDif, tvDistDif;
    private double speed;

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

        tvGetSpeed = (TextView)findViewById(R.id.tvGetSpeed);
        tvCalSpeed = (TextView)findViewById(R.id.tvCalSpeed);
        tvTime = (TextView)findViewById(R.id.tvTime);
        tvLastTime = (TextView)findViewById(R.id.tvLastTime);
        tvGpsEnable = (TextView)findViewById(R.id.tvGpsEnable);
        tvTimeDif = (TextView)findViewById(R.id.tvTimeDif);
        tvDistDif = (TextView)findViewById(R.id.tvDistDif);

        //권한 체크
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

        Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (lastKnownLocation != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            String formatDate = sdf.format(new Date(lastKnownLocation.getTime()));
            tvTime.setText(": " + formatDate);  //Time
        }
        // GPS 사용 가능 여부 확인
        boolean isEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        tvGpsEnable.setText(": " + isEnable);  //GPS Enable
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000,0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        double deltaTime = 0;

        //  getSpeed() 함수를 이용하여 속도를 계산
        double getSpeed = Double.parseDouble(String.format("%.3f", location.getSpeed()));
        tvGetSpeed.setText(": " + getSpeed);  //Get Speed
        String formatDate = sdf.format(new Date(location.getTime()));
        tvTime.setText(": " + formatDate);  //Time

        // 위치 변경이 두번째로 변경된 경우 계산에 의해 속도 계산
        if(mLastlocation != null) {
            //시간 간격
            deltaTime = (location.getTime() - mLastlocation.getTime()) / 1000.0;
            tvTimeDif.setText(": " + deltaTime + " sec");  // Time Difference
            tvDistDif.setText(": " + mLastlocation.distanceTo(location) + " m");  // Time Difference
            // 속도 계산
            speed = mLastlocation.distanceTo(location) / deltaTime;

            String formatLastDate = sdf.format(new Date(mLastlocation.getTime()));
            tvLastTime.setText(": " + formatLastDate);  //Last Time

            double calSpeed = Double.parseDouble(String.format("%.3f", speed));
            tvCalSpeed.setText(": " + calSpeed);  //Cal Speed
        }
        // 현재위치를 지난 위치로 변경
        mLastlocation = location;
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {
        //권한 체크
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        // 위치정보 업데이트
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000,0, this);
    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @Override
    protected void onResume() {
        super.onResume();
        //권한 체크
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        // 위치정보 업데이트
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000,0, this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 위치정보 가져오기 제거
        locationManager.removeUpdates(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //권한이 없을 경우 최초 권한 요청 또는 사용자에 의한 재요청 확인
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION) &&
                    ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                // 권한 재요청
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
                return;
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
                return;
            }
        }

    }
}

- copy coding -


+ Recent posts