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)
ALocation과 BLocation이 있다고 할 때 두 위치의 거리 차를 구할 때 사용 합니다.
사용 방법은 : ALocation.distanceTo(Location BLocation)
- getTime()
주어진 위치 값을 구한 시간 정보를 가져 옵니다. ALocation 값을 구한 시간을 알고 싶다면
사용 방법 : ALocation.getTime();
- getSpeed()
위치의 변화가 있다면 직전 위치에서 현재 위치까지 이동하는데 소요된 시간으로 속도를
자동으로 계산해서 보여 줍니다.
ALocation에서의 속도를 구한다면
사용 방법 : ALocation.getSpeed()
2. 속도 측정 프로그램
2.1 신규 프로젝트 생성
프로젝트를 임의의 이름으로 생성해 줍니다.
여기서는 Device는 Android 4.0을 선택 하고
Activity는 Empty로 설정 했습니다.
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 결과 화면
일정 속도로 이동하면 비슷한 결과가 나오는데 손으로 쥐고 걸어가면서 하면 두개의 값에 차이가 나는군요.
3.2 Source Code
3.3 APK File
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 -
'Android' 카테고리의 다른 글
[안드로이드] google map 테스트 (0) | 2018.12.03 |
---|---|
[안드로이드] google map 사용을 위한 API 키 생성(2018.11) (0) | 2018.12.02 |
android GPS,Network 이용 좌표 얻기 (GPS_PROVIDER, NETWORK_PROVIDER) (4) | 2018.11.19 |
안드로이드 진동 센서 테스트 (VIBRATOR_SERVICE) (0) | 2018.10.31 |
안드로이드 중력 센서 (TYPE_GRAVITY) (0) | 2018.10.13 |