본문으로 건너뛰기

Vehicle SDK를 활용한 안전 운전 점수 계산기

학습 개요 및 목표

본 온라인 tutorial은 안드로이드 앱(모바일 또는 태블릿) 개발 경험과 안드로이드에 대한 사전 이해도를 가지고 차량용 앱 개발을 처음 시작하는 개발자들을 위한 과정으로 Pleos Connect SDK를 활용한 간단한 앱을 만들어 보는 과정입니다. 나만의 안전 운전 점수 계산 앱 구현 과정을 통해 vehicle SDK를 활용한 vehicle data 연동 방법에 대해 기본부터 차근차근 알아보는 것을 목표로 합니다. 본 과정에서는 디자인 가이드 및 UI구성, 안드로이드 API 연동 관련된 내용은 포함하지 않습니다. 기본 가이드를 바탕으로 나만의 DIY 차량용 앱을 만들어 보세요.

개발 난이도 - 하
원활한 진행을 위한 Android 기초 사전 지식 필요
Kotlin 기반 샘플 코드 가이드 제공

  • 사전 참고 내용

    • Android studio 설치 링크
    • Android CarPropertyManager APIs 링크
    • Android Automotive 앱 개발 공식 가이드 링크
    • Pleos Playground Vehicle SDK API 호출 가이드 링크
  • 학습할 내용

    • Pleos Connect SDK의 Vehicle SDK를 활용한 차량 데이터 연동 API 상세 정보
  • 구현 내용 상세 Vehicle SDK를 활용하여 자동차의 데이터를 확인하여 안전 운전 점수를 계산하는 샘플 앱으로 해당 앱은 학습 용도로 구성되었습니다. 안전 운전 계산기는 총 3가지 감점 요소가 반영되어 있습니다. 급가속: 30km/h 이상 증가한 경우 감점 됩니다. 급감속: 30km/h 이상 감소한 경우 감점 됩니다. 핸들 조향 미숙: 50도 이상 좌 또는 우측으로 급하게 변경하는 경우 감점됩니다. 위 3가지 외 추가로 Vehicle API를 활용 및 조합하여 다양한 경우를 추가할 수 있습니다.

샘플 구현 앱 설명(동작 process를 참고하여 나만의 안전 운전 계산 앱을 만들어 보세요)

  1. 기어 상태를 변경(Drive 모드)하고 속도를 올리면 점수 측정을 시작합니다.
  2. 최초 100 P에서 측정이 시작되며 vehicle status 연동을 통해 감점 요소가 감지되면 5점씩 감점합니다.
  3. adb 명령어 수행을 통한 모의 주행 상태 변경 방법은 하기 섹션을 참조하세요.
  4. 주행 후 감속을 통해 속도를 0으로 만들고 기어 상태를 Parking 모드로 변경하면 점수 측정이 종료됩니다.
  5. 감점 요인 별 건수 및 차감 점수 결과를 최종 리포팅 합니다
    • 100 P : Perfect Driver
    • 70 P 이상 : Best Driver
    • 50 P 이상 : 초보 운전자
    • 50 P 미만 : 왕초보 운전자

개발 환경 설정

Pleos Connect는 개발자의 연동 편의를 위해 차량용 infotainment application을 빌드하고 테스트할 수 있는 환경을 제공합니다.

구분버전
Pleos Connect SDKv2.0.5
Minimum Android SDKAndroid API 26 이상
Gradle 버전8.0 이상
개발 언어Java, Kotlin
IDEAndroid studio
AVDPleos Connect Emulator 셋업 가이드 바로가기

SDK 연동 설정

Vehicle SDK 사용을 위해 SDK 의존성과 퍼미션을 설정합니다. 자세한 사항은 Vehicle SDK 연동 가이드를 참조하세요.

소스 코드 구현

차량 데이터와 연동하는 코드와 설정(권한)을 구현합니다.

[Driver Distraction Optimized 'true']

구현해 볼 앱은 주행 중 운전자와 상호작용이 유지되어야 하기 때문에 AndroidManifest에 Driver Distraction Optimized true 선언이 필요합니다. 자세한 내용은 안드로이드 공식 가이드를 참조하세요.

Step 1. SDK Permission 선언하기

AndroidManifest.xml 파일에 차량 속도 정보(Android)와 핸들 각도 정보를 얻어오기 위한 권한을 선언합니다.

[Android Automotive Integration Policy]

Pleos Connect SDK가 제공하는 API 정책은 동일 혹은 유사 기능의 API가 Android Automotive OS에 존재한다면 플랫폼 파편화를 최소화하기 위해 Android Automotive에 align하는 것입니다. 또한, 향후 Pleos Connect Vehicle SDK로 제공되었던 기능이 Android Automotive에 수용된다면 최소 2개의 major version까지 backward compatibility를 제공하는 것을 기본 정책으로 운영합니다.

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

<!-- TODO 2: 의존성 추가 및 권한 설정 (AndroidManifest.xml) -->
<uses-permission android:name="pleos.car.permission.CAR_DRIVE" />
<uses-permission android:name="android.car.permission.CAR_SPEED" />

<application />
// ... 생략
</manifest>

Step 2. SDK 활용 코드 작성하기(Kotlin)

Vehicle SDK 활용 방법 - 공통(1/4)

@Provides 메서드를 통해 Vehicle 객체를 앱 전역에 주입할 수 있도록 Hilt 모듈을 구성합니다. 이 객체는 차량 데이터를 처리하는 핵심 인스턴스입니다.

// package ai.pleos.playground.handson.vehicle.di.VehicleModules
@Module
@InstallIn(SingletonComponent::class)
object VehicleModules {
// TODO 3-1: Vehicle SDK 활용 방법 - 공통
@Provides
@Singleton
fun provideVehicle(
@ApplicationContext context: Context
): Vehicle = Vehicle(context)
}

Vehicle SDK 활용 방법 - 공통(2/4)

@Inject lateinit var vehicle: Vehicle로 MainActivity에 Vehicle 인스턴스를 주입 받습니다.

// package ai.pleos.playground.handson.vehicle.MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
// TODO 3-2: Vehicle SDK 활용 방법 - 공통
@Inject
lateinit var vehicle: Vehicle

override fun onCreate(savedInstanceState: Bundle?) { /* ... */ }
override fun onDestroy() { /* ... */ }
}

Vehicle SDK 활용 방법 - 공통(3/4)

SDK를 초기화합니다.

// package ai.pleos.playground.handson.vehicle.MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var vehicle: Vehicle


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// TODO 3-3: Vehicle SDK 활용 방법 - 공통
vehicle.initialize()

enableEdgeToEdge()
setContent { /* ... */ }
}
override fun onDestroy() { /* ... */ }
}

Vehicle SDK 활용 방법 - 공통(4/4)

Activity 종료 시 SDK 리소스를 해제합니다.

// package ai.pleos.playground.handson.vehicle.MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var vehicle: Vehicle


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

vehicle.initialize()

enableEdgeToEdge()
setContent { /* ... */ }
}

override fun onDestroy() {
super.onDestroy()
// TODO 3-4: Vehicle SDK 활용 방법 - 공통
vehicle.release()
}
}

Vehicle SDK 활용 방법 - Get Steering Wheel Angle API

getSteeringWheelAngle API를 호출함으로써 ViewModel에서 vehicleSdkRepository를 통해 핸들 각도를 읽습니다.

// package ai.pleos.playground.handson.vehicle.vm.MainViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
private val carPropertyRepository: CarPropertyRepository,
private val vehicleSdkRepository: VehicleSdkRepository,
) : ViewModel() {
/* ... */
// TODO 4: Vehicle SDK 활용 방법 - Get Steering Wheel Angle API
fun getSteeringWheelAngle() {
vehicleSdkRepository.getSteeringWheelAngle(
onSuccess = { angle ->
Log.d(logTag, "SteeringWheel Angle is $angle")
},
onFailure = { e ->
e.printStackTrace()
}
)
}
// ... 생략
}

Vehicle SDK 활용 방법 - Callback Steering Wheel Angle API(1/2)

이벤트 리스너 인터페이스를 구현하여 핸들 각도 변경 시 콜백을 받습니다.

// package ai.pleos.playground.handson.vehicle.vm.MainViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
private val carPropertyRepository: CarPropertyRepository,
private val vehicleSdkRepository: VehicleSdkRepository,
) : ViewModel() {
/* ... */
// TODO 5-1: Vehicle SDK 활용 방법 - Callback Steering Wheel Angle API
private val steeringWheelAngleListener = object : SteeringWheelAngleListener {
override fun onFailed(e: Exception) {
Log.w(logTag, "SteeringWheel Angle onFailed called.", e)
}

override fun onSteeringWheelAngleUpdated(angle: Float?) {
if (angle != null) {
observeSteeringWheelAngle(angle)
}
}
}
// ... 생략
}

Vehicle SDK 활용 방법 - Callback Steering Wheel Angle API(2/2)

람다로 이벤트 리스터를 구현합니다.

// package ai.pleos.playground.handson.vehicle.vm.MainViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
private val carPropertyRepository: CarPropertyRepository,
private val vehicleSdkRepository: VehicleSdkRepository,
) : ViewModel() {
private val steeringWheelAngleListener = /* ... */

fun startEvent() {
// ...
// TODO 5-2: Vehicle SDK 활용 방법 - Callback Steering Wheel Angle API
vehicleSdkRepository.registerSteeringWheelAngle(listener = steeringWheelAngleListener)
}

fun stopEvent() {
// ...
// TODO 5-2: Vehicle SDK 활용 방법 - Callback Steering Wheel Angle API
vehicleSdkRepository.unregisterSteeringWheelAngle(listener = steeringWheelAngleListener)
}
// ... 생략
}

Step 3. 앱 실행을 통한 테스트 해보기

  1. Android Studio에서 샘플 앱을 실행합니다.
  2. adb 명령어 수행을 통해 모의 주행 상태를 변경하면서 샘플 앱을 테스트합니다.
adb root

adb shell "echo 'propId: {property id} areaId: {area id} values: {value}' > /data/vendor/vsomeip/vhal_fifo"

// array type
adb shell "echo 'propId: {property id} areaId: {area id} values: [{value1},{value2}]' > /data/vendor/vsomeip/vhal_fifo"

// 기어 변경 (NAME: GEAR_SELECTION)
// P 단
adb shell "echo 'propId: 289408000 areaId: 0 values: 4' >
/data/vendor/vsomeip/vhal_fifo"

// D 단
adb shell "echo 'propId: 289408000 areaId: 0 values: 8' > /data/vendor/vsomeip/vhal_fifo"
/**
* Note: 속도는 m/s 값으로 단위 변환 필요.
* ex. 60km/h = 16.67m/s
*
* NAME: PERF_VEHICLE_SPEED
*/
// 급가속 및 급감속 (현재 속도 기준 30km/h 변화 필요)
adb shell "echo 'propId: 291504647 areaId: 0 values: {m/s}' > /data/vendor/vsomeip/vhal_fifo"

/**
* Note: Min ~ Max 사이 값 설정 필요합니다.
* min_value : -470
* max_value : 500
*
* NAME: PERF_STEERING_ANGLE
*/
// 스티어링 휠 변경 (현재 값 기준 50도 변화 필요)
adb shell "echo 'propId: 291504649 areaId: 0 values: {min ~ max}' > /data/vendor/vsomeip/vhal_fifo"

참고. Google Vehicle Property ID 값 확인