{"id":50,"date":"2026-04-18T01:25:37","date_gmt":"2026-04-18T00:25:37","guid":{"rendered":"https:\/\/sla.ovh\/?p=50"},"modified":"2026-04-18T01:25:37","modified_gmt":"2026-04-18T00:25:37","slug":"aplikacje-gps","status":"publish","type":"post","link":"https:\/\/sla.ovh\/index.php\/2026\/04\/18\/aplikacje-gps\/","title":{"rendered":"Aplikacje GPS:"},"content":{"rendered":"\n<p>Dobra rzecz \u2014 poka\u017c\u0119 Ci co dzieje si\u0119 \u201epod mask\u0105&#8221; takich aplikacji, bo wiele z tego ju\u017c robisz (a cz\u0119\u015b\u0107 warto dopisa\u0107). Podziel\u0119 na obszary specjalizacji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udded 1. Routing (wyb\u00f3r trasy)<\/h2>\n\n\n\n<p><strong>Problem<\/strong>: znale\u017a\u0107 najlepsz\u0105 tras\u0119 z A do B w grafie 200 mln kraw\u0119dzi w &lt;100 ms.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Algorytmy<\/strong>: nie Dijkstra ani A* same \u2014 w produkcji\u00a0<strong>Contraction Hierarchies<\/strong>, *<em>ALT (A<\/em>\u00a0+ Landmarks + Triangle Inequality)**,\u00a0<strong>Customizable Contraction Hierarchies<\/strong>\u00a0(Google u\u017cywa czego\u015b w stylu). Preprocessing: godziny. Query: milisekundy.<\/li>\n\n\n\n<li><strong>Hierarchia dr\u00f3g<\/strong>\u00a0\u2014 autostrady przed lokalnymi, algorytm \u201eschodzi w d\u00f3\u0142&#8221; tylko przy punktach A\/B<\/li>\n\n\n\n<li><strong>Wielokryterialne<\/strong>: najszybsza \/ najkr\u00f3tsza \/ z omini\u0119ciem p\u0142atnych \/ rowerowa \/ pieszo. Ka\u017cdy profil ma osobn\u0105 wag\u0119 kraw\u0119dzi<\/li>\n\n\n\n<li><strong>Ponowny routing na \u017cywo<\/strong>\u00a0(re-routing) gdy odjedziesz od planu \u2014 co ~3-5 s sprawdza dystans od polyline<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app:&nbsp;<code>RoutingService<\/code>&nbsp;wo\u0142a&nbsp;<strong>OSRM<\/strong>&nbsp;(open-source backend). Google\/Waze maj\u0105 w\u0142asne routery oparte na tych samych ideach.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\uddfa 2. Map rendering<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Vector tiles<\/strong>\u00a0(nie PNG) \u2014 MVT format Mapbox, lepsza skalowalno\u015b\u0107, rotacja, tilty<\/li>\n\n\n\n<li><strong>Poziomy szczeg\u00f3\u0142owo\u015bci<\/strong>\u00a0(LOD) \u2014 przy zoom 10 rysujesz autostrady, przy 18 chodniki<\/li>\n\n\n\n<li><strong>Level-of-detail dla labels<\/strong>\u00a0\u2014 nazwy ulic tylko gdy wchodz\u0105 na ekran, collision detection (\u017cadne nie zachodz\u0105)<\/li>\n\n\n\n<li><strong>3D buildings<\/strong>\u00a0\u2014 OSM ma\u00a0<code>building:height<\/code>\u00a0tag, ekstrudowany prostopad\u0142o\u015bcian z poligonu<\/li>\n\n\n\n<li><strong>GPU-accelerated rendering<\/strong>\u00a0\u2014 MapLibre \/ Mapbox GL u\u017cywa OpenGL ES, Metal (iOS), Vulkan (nowsze Androidy)<\/li>\n\n\n\n<li><strong>Tile prefetch<\/strong>\u00a0\u2014 podczas jazdy przewiduj\u0105 dok\u0105d jedziesz i pobieraj\u0105 tile&#8217;e do przodu<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app:&nbsp;<strong>MapLibre GL Native<\/strong>&nbsp;+ OpenFreeMap tiles \u2014 dok\u0142adnie to samo co robi Waze na ni\u017cszym poziomie.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udce1 3. Sensor fusion &amp; dead reckoning<\/h2>\n\n\n\n<p><strong>Problem<\/strong>: GPS w tunelu nie dzia\u0142a, a nawigacja musi dalej prowadzi\u0107.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Kalman Filter<\/strong>\u00a0(Extended\/Unscented) \u2014 \u0142\u0105czy GPS + akcelerometr + \u017cyroskop + kompas + speedometr (OBD-II je\u015bli pod\u0142\u0105czony)<\/li>\n\n\n\n<li><strong>Dead reckoning<\/strong>\u00a0\u2014 w tunelu licz\u0105 pozycj\u0119 z integracji pr\u0119dko\u015bci+bearingu (robi\u0105 to 2-5 minut zanim drift przekroczy akceptowalny pr\u00f3g)<\/li>\n\n\n\n<li><strong>Map matching HMM<\/strong>\u00a0(Hidden Markov Model) \u2014 nie wybieraj\u0105 najbli\u017cszej ulicy, tylko najbardziej prawdopodobn\u0105 sekwencj\u0119 ulic w czasie<\/li>\n\n\n\n<li><strong>ZUPT<\/strong>\u00a0(Zero-Velocity Update) \u2014 gdy stoisz, akcelerometr wie \u017ce nie ma ruchu \u2192 resetuj\u0105 drift<\/li>\n\n\n\n<li><strong>Barometr<\/strong>\u00a0\u2014 wysoko\u015b\u0107 nad poziomem morza, pozwala odr\u00f3\u017cni\u0107 g\u00f3rny poziom estakady od dolnego<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app:&nbsp;<strong>masz ju\u017c<\/strong>&nbsp;<code>SensorHub<\/code>,&nbsp;<code>LocationFilter<\/code>&nbsp;(EKF-based), ZUPT, road snap przez OSRM. Na poziomie Waze to te same techniki, r\u00f3\u017cni si\u0119 skal\u0105 kalibracji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udea6 4. Traffic \/ crowd-sourcing<\/h2>\n\n\n\n<p><strong>Magia Waze<\/strong>: wiesz \u017ce stoi korek zanim tam dojedziesz.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Floating Car Data<\/strong>\u00a0\u2014 ka\u017cdy telefon z aplikacj\u0105 wysy\u0142a anonimowo (lat, lng, speed, timestamp) co par\u0119 sekund<\/li>\n\n\n\n<li><strong>Agregacja server-side<\/strong>\u00a0\u2014 na ka\u017cdej kraw\u0119dzi grafu licz\u0105 \u015bredni\u0105 pr\u0119dko\u015b\u0107 z ostatnich N minut vs historyczna<\/li>\n\n\n\n<li><strong>Historical traffic<\/strong>\u00a0\u2014 model ML uczy si\u0119 typowej pr\u0119dko\u015bci na danej ulicy o 17:00 w pi\u0105tek<\/li>\n\n\n\n<li><strong>Incident detection<\/strong>\u00a0\u2014 3 samochody nagle hamuj\u0105 w tym samym miejscu \u2192 \u201eprawdopodobnie wypadek&#8221;<\/li>\n\n\n\n<li><strong>Rerouting mass<\/strong>\u00a0\u2014 gdy 10 000 aut by dosta\u0142o t\u0119 sam\u0105 alternatywn\u0105 tras\u0119, serwer dzieli ich na 3 r\u00f3\u017cne \u017ceby nie zapcha\u0107 objazdu<\/li>\n\n\n\n<li><strong>Reward system<\/strong>\u00a0(Waze) \u2014 user melduje fotoradar\/korek, punkty, ranking. Gamification jako darmowe dane<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app: masz infrastruktur\u0119 (MQTT + REST), ale nie liczysz traffic. Na MVP nie trzeba.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd0a 5. Voice guidance (TTS)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pre-rendered audio<\/strong>\u00a0dla fraz statycznych (\u201eskr\u0119\u0107 w lewo&#8221;),\u00a0<strong>TTS na \u017cywo<\/strong>\u00a0dla nazw ulic<\/li>\n\n\n\n<li><strong>Lookahead timing<\/strong>\u00a0\u2014 \u201eza 200 m skr\u0119\u0107&#8221; musi by\u0107 wypowiedziane 5-7 s przed punktem (licz\u0105 z pr\u0119dko\u015bci)<\/li>\n\n\n\n<li><strong>Cancellation<\/strong>\u00a0\u2014 jak zmienia si\u0119 trasa, przerywaj\u0105 poprzedni\u0105 wypowied\u017a<\/li>\n\n\n\n<li><strong>Ducking<\/strong>\u00a0\u2014 przyciszaj\u0105 muzyk\u0119 u\u017cytkownika (Spotify, radio) na czas wypowiedzi \u2014\u00a0<code>AudioFocusRequest<\/code><\/li>\n\n\n\n<li><strong>Multi-language<\/strong>\u00a0\u2014 ta sama fraza w 40 j\u0119zykach, dynamicznie wybierana<\/li>\n\n\n\n<li><strong>Natural intonation<\/strong>\u00a0\u2014 Google WaveNet i podobne neuronowe TTS, ju\u017c nie syntetyczne \u201esamochodowe&#8221; z lat 2000<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app:&nbsp;<strong>masz<\/strong>&nbsp;<code>VoiceGuidance<\/code>&nbsp;z debounce, po polsku,&nbsp;<code>speakDistance()<\/code>. Brakuje ducking \u2014 warto doda\u0107&nbsp;<code>AudioFocusRequest<\/code>&nbsp;(~15 linii).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddea 6. Testing &amp; simulation (wczoraj pyta\u0142e\u015b o to)<\/h2>\n\n\n\n<p><strong>To jest ogromny temat w Waze\/Google<\/strong>. Nikt nie wysy\u0142a programist\u00f3w w auto \u017ceby testowa\u0107 ka\u017cdy zakr\u0119t.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Replay harness<\/strong>\u00a0\u2014 nagrane GPS tracks z prawdziwych aut, odtwarzane na emulatorze z pe\u0142n\u0105 pr\u0119dko\u015bci\u0105<\/li>\n\n\n\n<li><strong>Synthetic routes<\/strong>\u00a0\u2014 algorytm generuje losowe trasy \u2192 puszcza 1000\u00d7 noc\u0105, sprawdza czy nie pojawia si\u0119 \u201eskr\u0119\u0107 w lewo&#8221; gdzie nie mo\u017cna<\/li>\n\n\n\n<li><strong>A\/B testing w live<\/strong>\u00a0\u2014 1% u\u017cytkownik\u00f3w dostaje now\u0105 wersj\u0119 routera, por\u00f3wnuj\u0105 ETA accuracy vs baseline<\/li>\n\n\n\n<li><strong>Canary releases<\/strong>\u00a0\u2014 geograficznie (najpierw jedno miasto, potem stan, potem kraj)<\/li>\n\n\n\n<li><strong>Heatmap b\u0142\u0119d\u00f3w<\/strong>\u00a0\u2014 klaster \u201eaplikacja da\u0142a z\u0142\u0105 nawigacj\u0119&#8221; z telemetrii \u2192 priorytetowa naprawa<\/li>\n\n\n\n<li><strong>Regression tests<\/strong>\u00a0\u2014 10000 tras + expected result \u2014 ka\u017cdy commit musi przej\u015b\u0107<\/li>\n\n\n\n<li><strong>Simulation environments<\/strong>\u00a0\u2014 Google ma wewn\u0119trzny tool kt\u00f3ry renderuje ca\u0142y widok nawigacji z bot-sterowanego \u201etelefonu&#8221; w data center<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app: to by\u0142 pomys\u0142 z simulation mode. Dok\u0142adnie to samo robi\u0105 in\u017cynierowie Waze\/Google lokalnie \u2014 r\u00f3\u017cnica tylko w skali.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfe2 7. Infrastruktura backendu<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tile serving<\/strong>\u00a0\u2014 Cloudflare CDN przed tile serverem (tiles.openfreemap.org te\u017c to ma)<\/li>\n\n\n\n<li><strong>Routing klaster<\/strong>\u00a0\u2014 routery siedz\u0105 w pami\u0119ci z pre-computed CH graph, 50-200 ms query<\/li>\n\n\n\n<li><strong>Event bus<\/strong>\u00a0\u2014 Kafka \/ PubSub do floating car data, milion msg\/s<\/li>\n\n\n\n<li><strong>Time-series DB<\/strong>\u00a0\u2014 InfluxDB \/ BigQuery do historical traffic<\/li>\n\n\n\n<li><strong>Global load balancing<\/strong>\u00a0\u2014 user w Polsce \u2192 europejski DC, w Kalifornii \u2192 us-west<\/li>\n\n\n\n<li><strong>Map data pipeline<\/strong>\u00a0\u2014 import OSM co tydzie\u0144, diff check, deploy do production, rollback przy regresji<\/li>\n<\/ul>\n\n\n\n<p>W Twojej app: masz MQTT + REST, skala kilkuset tracker\u00f3w. Produkcyjnie Waze ma 150M aktywnych u\u017cytkownik\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udcca 8. ML \/ AI (obecnie)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ETA prediction<\/strong>\u00a0\u2014 nie tylko \u201e\u015brednia pr\u0119dko\u015b\u0107 \u00d7 dystans&#8221;, ale LSTM bierze pod uwag\u0119 por\u0119, pogod\u0119, mecz w mie\u015bcie, szko\u0142\u0119<\/li>\n\n\n\n<li><strong>Lane-level routing<\/strong>\u00a0\u2014 \u201eza 500 m zmie\u0144 pas na prawy&#8221; \u2014 wymaga mapy z informacj\u0105 o pasach (Google robi Lane Assist z kamery Street View)<\/li>\n\n\n\n<li><strong>Anomaly detection<\/strong>\u00a0\u2014 automatyczne wykrywanie wypadk\u00f3w bez zg\u0142osze\u0144 przez korelacj\u0119 pr\u0119dko\u015bci + hamowania + zag\u0119szczenia<\/li>\n\n\n\n<li><strong>Personalization<\/strong>\u00a0\u2014 \u201epreferujesz autostrady \/ unikasz p\u0142atnych&#8221; uczone z historii bez zadawania pyta\u0144<\/li>\n\n\n\n<li><strong>Computer vision<\/strong>\u00a0\u2014 Google analizuje zdj\u0119cia z kamer drogowych do wykrywania znak\u00f3w, rob\u00f3t<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfaf Co Twoja aplikacja robi ju\u017c dobrze<\/h2>\n\n\n\n<p>Patrz\u0105c na kod kt\u00f3ry znam:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 EKF + sensor fusion<\/li>\n\n\n\n<li>\u2705 Road snapping (OSRM)<\/li>\n\n\n\n<li>\u2705 MapLibre vector tiles<\/li>\n\n\n\n<li>\u2705 Multi-priority FusedLocation<\/li>\n\n\n\n<li>\u2705 TTS po polsku z debounce<\/li>\n\n\n\n<li>\u2705 Offline buffering (LocalTrackBuffer, OfflineQueue)<\/li>\n\n\n\n<li>\u2705 MQTT real-time + REST fallback<\/li>\n\n\n\n<li>\u2705 Infrastruktura niezawodno\u015bci (retry, cache)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udca1 Co by\u015b m\u00f3g\u0142 doda\u0107 (od naj\u0142atwiejszych)<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>AudioFocus ducking<\/strong>\u00a0\u2014 przycisz muzyk\u0119 podczas TTS (15 linii)<\/li>\n\n\n\n<li><strong>Rerouting on deviation<\/strong>\u00a0\u2014 gdy odjedziesz >50 m od polyline przez >10 s, przelicz tras\u0119<\/li>\n\n\n\n<li><strong>Historical traffic<\/strong>\u00a0\u2014 zapisuj swoje przejazdy, pokazuj \u201ezwykle jedziesz t\u0119dy 12 min, dzi\u015b 18 min&#8221;<\/li>\n\n\n\n<li><strong>Simulation mode<\/strong>\u00a0(wczoraj proponowa\u0142em) \u2014 testowanie bez ruszania si\u0119<\/li>\n\n\n\n<li><strong>Lane indicator<\/strong>\u00a0\u2014 masz ju\u017c\u00a0<code>LaneAssistBar<\/code>\u00a0w NavigationScreen \u2713<\/li>\n\n\n\n<li><strong>Voice commands<\/strong>\u00a0\u2014 \u201eHej INVOO, zabierz mnie do domu&#8221; przez Speech-to-Text<\/li>\n\n\n\n<li><strong>Waze-like reporting<\/strong>\u00a0\u2014 user klika \u201ewypadek tu&#8221; \u2192 wysy\u0142a do MQTT, inni widz\u0105 (wymaga kont u\u017cytkownik\u00f3w)<\/li>\n\n\n\n<li><strong>ETA accuracy tracking<\/strong>\u00a0\u2014 loguj przewidywany vs rzeczywisty ETA, ucz model<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Dobra rzecz \u2014 poka\u017c\u0119 Ci co dzieje si\u0119 \u201epod mask\u0105&#8221; takich aplikacji, bo wiele z tego ju\u017c robisz (a cz\u0119\u015b\u0107&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-50","post","type-post","status-publish","format-standard","hentry","category-aplikacje-android"],"_links":{"self":[{"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/posts\/50","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/comments?post=50"}],"version-history":[{"count":1,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/posts\/50\/revisions"}],"predecessor-version":[{"id":51,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/posts\/50\/revisions\/51"}],"wp:attachment":[{"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/media?parent=50"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/categories?post=50"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sla.ovh\/index.php\/wp-json\/wp\/v2\/tags?post=50"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}