- Регистрация
- 23 Авг 2023
- Сообщения
- 3,969
- Реакции
- 0
- Баллы
- 36
Ofline
В предыдущих сериях мы научились ковыряться под капотом: доставать данные с датчиков через VHAL и прятать кнопки от водителя, когда машина едет. Но давайте честно: просто выводить скорость на экран — это скучно. Этим занимались инженеры еще в 90-х.
Сегодня мы живем в эпоху ИИ. У нас есть железка стоимостью в десятки тысяч евро, напичканная датчиками, и операционная система, которая может всё это читать. Так давайте дадим машине «мозги»!
В этой статье мы напишем концепт Smart Driving Assistant — фонового сервиса на Android Automotive, который будет анализировать телеметрию (руль, педали, скорость) и с помощью локальной нейросети (On-Device ML) понимать, что водитель начал "играть в шашечки" на дороге.
Почему On-Device ML, а не облако?
Казалось бы, почему не гонять данные на бэкенд и там всё красиво считать? Добро пожаловать в суровую реальность автопрома:
Интернет в машине — штука нестабильная. Вы заехали в туннель где-то под Альпами, и ваше облако превратилось в тыкву.
Трафик стоит денег. OEM-производители (автоконцерны) удавятся за лишний мегабайт сотовых данных.
Приватность. Отправлять сырую телеметрию педалей и руля на сторонние сервера — это лучший способ получить судебный иск по GDPR.
Поэтому наш выьор — это Edge AI (вычисления на границе). Мы будем использовать TensorFlow Lite прямо на головном устройстве (Head Unit).
Шаг 1: Собираем "Биг Дату" из VHAL
Чтобы нейросеть могла что-то предсказывать, ей нужна пища. В прошлой статье мы подписывались на скорость. Теперь нам нужны более интересные метрики из
VehiclePropertyIds.Нам понадобятся:
STEERING_WHEEL_ANGLE— угол поворота руля.
BRAKE_PEDAL_POSITION— насколько сильно вдавлен тормоз (от 0 до 100).
ACCELERATOR_PEDAL_POSITION— положение педали газа.
Напишем коллектор, который будет собирать это в небольшой буфер "окна времени" (Time Window):
Код:
import android.car.hardware.property.CarPropertyManager
import android.car.VehiclePropertyIds
class TelemetryCollector(private val carPropertyManager: CarPropertyManager) {
// Храним последние N снапшотов телеметрии для передачи в модель
private val telemetryBuffer = FloatArray(150) // Например, 50 тиков * 3 параметра
private var currentIndex = 0
private val callback = object : CarPropertyManager.CarPropertyEventCallback {
override fun onChangeEvent(event: CarPropertyValue<Any>) {
val value = event.value as Float
when (event.propertyId) {
VehiclePropertyIds.PERF_STEERING_ANGLE -> updateBuffer(0, value)
VehiclePropertyIds.PERF_VEHICLE_SPEED -> updateBuffer(1, value)
VehiclePropertyIds.BRAKE_PEDAL_POSITION -> updateBuffer(2, value)
}
// Если буфер заполнен, отдаем в нейронку
if (isBufferFull()) {
analyzeDrivingStyle(telemetryBuffer)
}
}
override fun onErrorEvent(propId: Int, zone: Int) {}
}
fun startCollecting() {
// Подписываемся с высокой частотой (SENSOR_RATE_FAST), нам же нужна динамика!
carPropertyManager.registerCallback(
callback, VehiclePropertyIds.PERF_STEERING_ANGLE, CarPropertyManager.SENSOR_RATE_FAST
)
// ... аналогично для других свойств
}
}
Важный нюанс: Не все машины отдают эти данные. Некоторые OEM прячут положение руля за секьюрными вендорными свойствами (Vendor Extensions). Но для эмулятора и стандартных AOSP сборок этого хватит
Шаг 2: Прикручиваем TensorFlow Lite
Допустим, у нас уже есть предобученная модель
driving_style.tflite, которая принимает на вход наш массив из 150 флоатов и выдает вероятность того, что водитель агрессивен (от 0.0 до 1.0).Кладем модельку в папку
assets и инициализируем TFLite интерпретатор.
Код:
import org.tensorflow.lite.Interpreter
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
import android.content.Context
class DrivingAnalyzer(context: Context) {
private var interpreter: Interpreter
init {
val model = loadModelFile(context, "driving_style.tflite")
val options = Interpreter.Options().apply {
setNumThreads(2)
// Если головное устройство поддерживает NPU (Neural Processing Unit),
// можно подключить NNAPI Delegate для аппаратного ускорения.
// addDelegate(NnApiDelegate())
}
interpreter = Interpreter(model, options)
}
fun analyze(telemetry: FloatArray) {
// Модель ожидает на входе [1, 150], на выходе [1, 1] (вероятность)
val input = arrayOf(telemetry)
val output = Array(1) { FloatArray(1) }
// Магия ИИ!
interpreter.run(input, output)
val aggressionScore = output[0][0]
if (aggressionScore > 0.85f) {
Log.w("SmartDrive", "Водитель исполняет! Оценка агрессии: $aggressionScore")
// Тут можно, например, принудительно включить расслабляющую музыку
// или сделать UI климата холоднее :)
}
}
private fun loadModelFile(context: Context, modelName: String): MappedByteBuffer {
val fileDescriptor = context.assets.openFd(modelName)
val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
val fileChannel = inputStream.channel
return fileChannel.map(FileChannel.MapMode.READ_ONLY, fileDescriptor.startOffset, fileDescriptor.declaredLength)
}
}
Суровая реальность: Троттлинг и "железо" автомобиля
Выглядит просто, правда? Скормил данные — получил результат. Но в реальном Automotive проекте вас ждет пара сюрпризов:
Термальный троттлинг. Если ваша нейросеть будет молотить 60 раз в секунду, процессор магнитолы нагреется. В машине летом и так бывает +60°C. Когда процессор перегревается, система не просто снижает частоты, она может принудительно убить ваше приложение или вырубить экран ради безопасности. Решение: Оптимизируйте модели (квантованиеint8— ваше всё) и запускайте inference не на каждый тик, а батчами раз в пару секунд.
Борьба за ресурсы. Навигация (Google Maps) всегда в приоритете. Если вашей нейронке и картам станет тесно в оперативной памяти, Android убьет именно вас.
Итого
Android Automotive — это не просто планшет на колесах. Это огромная платформа для интеграции сенсоров и алгоритмов машинного обучения. Сегодня мы собрали фундамент: взяли сырые данные из CAN-шины через VHAL и прогнали их через on-device модель.
Именно на стыке Automotive и ML сейчас рождаются самые интересные фичи: от анализа усталости водителя по камере до предиктивного обслуживания двигателя.
В следующей статье мы поговорим о том... а о чем вы хотите поговорить? Пишите в комментах, погнали обсуждать!