前言:三個讓我受不了的痛點

開車的人多少都有這種經驗:行車記錄器買的時候標榜「內建測速照相提醒」,提醒功能也乖乖開著,某天還是收到一張罰單,因為那支新設的相機根本不在圖資裡。

我認真研究過一輪之後,發現這類產品有三個根本的問題:

第一,行車記錄器的圖資不會自動更新。 內建的測速照相資料庫是出廠那一刻的快照。想更新,得自己去官網找檔案、拔記憶卡、進選單刷韌體。大多數人買來之後一次都不會做,圖資就這樣停在幾年前。

第二,市面上找不到把 Android Auto 做好的產品。 我的日常是手機接上車機、開 Google Maps 導航。市面上的測速 App 要嘛完全不支援 Android Auto,要嘛支援了卻跟導航打架,警報一跳出來就蓋掉導航畫面,本末倒置。

第三,介面實在太醜。 這類 App 的設計品味大多停留在十年前智慧型手機剛出來的年代:擬真按鈕、螢光大字、五顏六色的圖示塞滿畫面。每天開車都要看的東西,我不想將就。

抱怨到最後只剩一條路:自己做一個。

「測速照相機 OUT!」是什麼

測速照相機 OUT! 主畫面:深色儀表板風格,大字時速顯示與道路模式切換

「測速照相機 OUT!」是專為台灣駕駛設計的測速照相預警 App,核心理念一句話講完:安靜地待在背景,只在該說話的時候說話。

  • 純背景運作:警報走 Android 獨立的鬧鐘音軌(STREAM_ALARM),搭配 heads-up 通知。你照常開 Google Maps 導航,警報聲會壓過導航語音,但導航畫面完全不被打斷。
  • Android Auto 原生支援:車機上有專屬的數位時速面板,還能直接在車機螢幕一鍵切換高架、平面模式。
  • 隨插即用:手機插上車機 USB 自動啟動防護,熄火拔線自動關閉省電。上車即用,零操作。

介面則是用 Jetpack Compose 從零想過一遍:深色儀表板底、一眼可讀的大字時速、單一橘色強調色。開車時瞄一眼就能拿到所有資訊,不需要在花花綠綠的畫面裡找重點。

圖資會自己長大:全自動歸正管線

這是整個專案我最想解決的事:圖資的鮮度與精度。

相機資料來自政府開放資料,管線每天自動同步清單。但開放資料有個大坑:方向欄位只有「南下」「北上」「雙向」「往高鐵」這種粗略的文字。在彎曲路段(像台 61 線西部海岸、國道 3 號山區段),把文字硬翻成八方位角度會偏差 30 到 60 度,警報準度直接崩掉;「往高鐵」這種地標型描述更是連翻都翻不了。

所以我建了一條全自動的方位角歸正管線,每週由排程自己跑完:

    graph LR
    A["政府開放資料<br>每日同步清單"] --> B["巨觀啟發式<br>國道里程切段"]
    B --> C["OSM 幾何精修<br>Overpass API"]
    C --> D["AI 混合引擎<br>Gemini + Nominatim"]
    D --> E["每週排程發佈<br>自動更新圖資"]
  
  • 巨觀啟發式:長途國道的走向在大尺度上可預測,先用里程切段把大方向抓對。
  • OSM 幾何精修:用 Overpass API 抓每支相機周圍 50 公尺內的道路幾何,算出實際路段的切線角度,再用四向反三角消歧義決定拍攝方向。
  • AI 混合引擎:「往高鐵站」「往下山」這種純幾何處理不了的地標型描述,交給 Gemini AI 搭配 Nominatim 地理編碼推論。

結果是一份每週自己長大、自己校正的圖資,目前自動維護超過九百筆精準方位。行車記錄器做不到這件事,因為它的圖資死在出廠那一天。

雷達演算法:不只是畫個圓圈

大部分測速 App 的偵測邏輯是「以相機為圓心畫個圈,進圈就叫」。這種做法在市區跟高架路段誤報連連:隔壁街的相機會叫,高架橋下平行道路的相機也會叫,叫到最後使用者直接關通知。

這個 App 在幾個地方比較講究:

  • 向量走廊投影:偵測範圍不是圓圈,是沿著行進方向的走廊,用橫向偏移量過濾平行道路的相機。隔壁街的相機再近都與你無關。
  • Geohash 空間索引:鄰近相機檢索用 Geohash 做到常數時間,CPU 負擔與耗電都壓到最低。
  • 車輛硬體數據直連:隧道與高架橋下 GPS 會飄。App 透過 CarHardwareManager 直接讀車輛 CAN bus 的輪速與羅盤,GPS 一斷就無縫切到車輛硬體數據,時速不再亂跳。
  • 區間測速狀態機:偵測到區間測速路段時,獨立狀態機全程追蹤均速,即時顯示均速、速限、剩餘距離與進度條,超速自動變色警示。

讓它不無聊:五個遊戲化機制

工具型 App 有個宿命:功能做得再好,使用者也感覺不到。警報響了、你減速了、罰單沒來,然後呢?什麼都沒留下。

所以我放了一組遊戲化機制,讓每一次安全通過都累積成看得見的東西:

  • 累積數據:每次通過測速相機都結算一次。安全通過就依台灣的罰則試算「這一次幫你省下多少罰金」,超速則老實記一筆違規。打開統計頁看到的不是冷冰冰的次數,而是「這個 App 至今幫我守住了多少錢」。
  • 成就系統:安全通過次數、累積里程這類里程碑會解鎖徽章與稱號,同時累積成就點數。
  • 兌換商店:成就點數不是裝飾品,可以換實際的獎勵,像訂閱展延、語音包、地圖主題。
  • 歷史旅程:每趟旅程的軌跡都留得下來,事後可以在地圖上回顧。而且軌跡只存在你自己的 Google Drive 私有空間(appDataFolder),我的後端從頭到尾碰不到你的位置資料。
  • 個人圖資:發現某支相機的方位角標錯了?登入 Web 會員專區,直接在地圖上修正方位角與雙向拍攝屬性,即時同步到你個人的雲端設定檔。你的圖資會越修越貼合你每天走的路。

這五個機制串起來是一個飛輪:

    graph TB
    DRIVE["開車"] --> DATA["累積數據<br>看見省下的罰金"]
    DATA --> ACH["解鎖成就<br>賺取點數"]
    ACH --> SHOP["兌換商店<br>換實質獎勵"]
    SHOP --> BETTER["App 越用越好用"]
    DRIVE --> MAP["個人圖資<br>越修越準"]
    MAP --> BETTER
    BETTER --> DRIVE
  

越開越準、越開越省、越開越捨不得換掉。這就是我要的效果。

技術堆疊速覽

技術
Android App Kotlin、Jetpack Compose、Room、FusedLocationProvider 搭配 Vincenty 高精度反算
Android Auto androidx.car.app(POI 類別,完整行車安全限制)
後端 Cloudflare Workers、D1、R2,全 serverless
圖資管線 Node.js、Overpass API(OSM)、Google Gemini AI,GitHub Actions 排程

後端全部跑在 Cloudflare 的 serverless 架構上,圖資管線則靠 GitHub Actions 排程自動運轉。整套系統平常不需要我看著,它自己會把圖資養大。

結語

這個專案一開始只是想解決自己的三個不爽:圖資不更新、Android Auto 沒人做好、介面醜。做著做著,它變成一個會自己更新圖資、還帶著遊戲化飛輪的系統。

如果你也是台灣的 Android 駕駛,歡迎試試:

用了之後有什麼想法,歡迎在 Play 商店留個評論告訴我。