В предыдущих сериях мы научились ковыряться под капотом: доставать данные с датчиков через VHAL и прятать кнопки от водителя, когда машина едет. Но давайте честно: просто выводить скорость на экран — это скучно. Этим занимались инженеры еще в 90-х.

Сегодня мы живем в эпоху ИИ. У нас есть железка стоимостью в десятки тысяч евро, напичканная датчиками, и операционная система, которая может всё это читать. Так давайте дадим машине «мозги»!

В этой статье мы напишем концепт Smart Driving Assistant — фонового сервиса на Android Automotive, который будет анализировать телеметрию (руль, педали, скорость) и с помощью локальной нейросети (On-Device ML) понимать, что водитель начал "играть в шашечки" на дороге.

Почему On-Device ML, а не облако?

Казалось бы, почему не гонять данные на бэкенд и там всё красиво считать? Добро пожаловать в суровую реальность автопрома:

  1. Интернет в машине — штука нестабильная. Вы заехали в туннель где-то под Альпами, и ваше облако превратилось в тыкву.

  2. Трафик стоит денег. OEM-производители (автоконцерны) удавятся за лишний мегабайт сотовых данных.

  3. Приватность. Отправлять сырую телеметрию педалей и руля на сторонние сервера — это лучший способ получить судебный иск по 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 проекте вас ждет пара сюрпризов:

  1. Термальный троттлинг. Если ваша нейросеть будет молотить 60 раз в секунду, процессор магнитолы нагреется. В машине летом и так бывает +60°C. Когда процессор перегревается, система не просто снижает частоты, она может принудительно убить ваше приложение или вырубить экран ради безопасности. Решение: Оптимизируйте модели (квантование int8 — ваше всё) и запускайте inference не на каждый тик, а батчами раз в пару секунд.

  2. Борьба за ресурсы. Навигация (Google Maps) всегда в приоритете. Если вашей нейронке и картам станет тесно в оперативной памяти, Android убьет именно вас.

Итого

Android Automotive — это не просто планшет на колесах. Это огромная платформа для интеграции сенсоров и алгоритмов машинного обучения. Сегодня мы собрали фундамент: взяли сырые данные из CAN-шины через VHAL и прогнали их через on-device модель.

Именно на стыке Automotive и ML сейчас рождаются самые интересные фичи: от анализа усталости водителя по камере до предиктивного обслуживания двигателя.

В следующей статье мы поговорим о том... а о чем вы хотите поговорить? Пишите в комментах, погнали обсуждать!