Разработка трекинга передвижения транспорта в мобильном приложении
Трекинг транспорта отличается от курьерского в нескольких принципиальных моментах: скорости движения другие, GPS-шум на высокой скорости иной по характеру, маршруты часто заранее известны (рейсовый транспорт), а данные поступают не от смартфона водителя, а от GPS-трекера через MQTT/протокол Wialon или FMB-устройств Teltonika.
Источники данных: не только смартфон
Для логистических компаний и управления парком транспортное устройство — это аппаратный GPS-трекер (Teltonika FMB920, Queclink GV350, Galileosky), а не телефон водителя. Трекер отправляет пакеты по MQTT или HTTP-протоколу на сервер. Приложение выступает только как визуализатор данных, не как источник.
Если задача — показывать общественный транспорт по данным GTFS Realtime (стандарт Google), то источник — открытые API городских транспортных операторов. Формат — Protocol Buffers (transit_realtime.FeedMessage), парсинг через библиотеку gtfs-realtime-bindings.
Для приложений с телефоном водителя (такси, корпоративный транспорт) — тот же стек, что у курьерского трекинга, но с поправками на скорость движения.
GPS-фильтрация на высоких скоростях
На скорости 80-120 км/ч горизонтальный GPS-дрейф меньше, чем в городе с многоэтажками, но другая проблема: при резких поворотах маркер может «обгонять» реальное положение машины из-за задержки обновления. Калман-фильтр сглаживает эту задержку.
Простая реализация фильтра Калмана для координат на Kotlin:
class KalmanFilter(private var accuracy: Float = 1f) {
private var lat = 0.0
private var lon = 0.0
private var variance = -1f
fun process(lat: Double, lon: Double, accuracy: Float, timestamp: Long): LatLng {
if (variance < 0) {
this.lat = lat; this.lon = lon; variance = accuracy * accuracy
} else {
val dt = (timestamp - lastTimestamp) / 1000f
variance += dt * 3f * 3f // скорость изменения 3 m/s
val k = variance / (variance + accuracy * accuracy)
this.lat += k * (lat - this.lat)
this.lon += k * (lon - this.lon)
variance *= (1 - k)
}
lastTimestamp = timestamp
return LatLng(this.lat, this.lon)
}
private var lastTimestamp = 0L
}
На iOS аналогичная реализация в Swift или использование CLLocationManager с CLActivityType.automotiveNavigation — Apple применяет собственный фильтр.
Map Matching для маршрутизированного транспорта
Рейсовый автобус едет по фиксированному маршруту — GPS-точки между остановками должны лежать строго на этом маршруте, а не прыгать на параллельную улицу. Map matching: берём последовательность GPS-точек и «прижимаем» их к ближайшему участку дорожного графа.
OSRM self-hosted: GET /match/v1/driving/{coordinates}?radiuses={radiuses}&geometries=geojson. Возвращает matched-трек с waypoints. Latency < 20 мс при self-hosting, что приемлемо для реального времени.
Google Roads API snapToRoads — проще в интеграции, но платно (5$ за 1000 вызовов) и ограничено 100 точками за запрос.
Отображение транспорта: маркеры и маршрут
Маркер автобуса/грузовика — кастомный PNG или SVG с поворотом по направлению движения. Направление в градусах: atan2(dLon, dLat) * 180 / PI. На Android — BitmapDescriptorFactory.fromBitmap(rotatedBitmap) с поворотом через Matrix.postRotate(). На iOS — GMSMarker с iconView, поворот через CGAffineTransform(rotationAngle:).
Маршрут — полилиния. Google Directions API для расчёта или заранее сохранённый GTFS shapes.txt. На карте — GMSPolyline / Polyline с кастомным цветом и толщиной. Пройденный участок — другой цвет (например, серый вместо синего).
Анимация движения — интерполяция между точками. Интервал обновления GPS-трекера обычно 30-60 секунд, а не 5. Это означает, что маркер должен плавно двигаться 30 секунд от одной точки к другой, а не прыгать. ValueAnimator на Android с LinearInterpolator, CADisplayLink на iOS.
Серверная часть
Для парка из 50-200 машин — Socket.IO или WebSocket на Node.js. Сервер хранит актуальные позиции в Redis с TTL. Клиент подписывается на канал fleet/updates и получает обновления всех машин пачкой каждые 10-15 секунд вместо индивидуальных событий — экономит трафик.
Для больших парков (1000+ машин) — MQTT broker с топиками vehicle/{id}/gps. Клиент подписывается только на интересующие машины.
Историческое хранение маршрутов: PostgreSQL + PostGIS для геопространственных запросов («покажи все машины, проехавшие через зону X вчера»), TimescaleDB для time-series метрик (скорость, топливо).
Процесс работы
Аудит источника данных: трекер/телефон/GTFS. Проектирование серверной шины и хранилища. Реализация мобильного клиента: маркеры, маршруты, анимация, состояния. Интеграция map matching если нужно. Тестирование с эмуляцией трафика.
Срок: от двух до шести недель в зависимости от источника данных, количества платформ и масштаба парка.







