台灣無人機識別與回報開放協議(Taiwan Drone Reporting Protocol)— 規格書與參考 SDK
本協議為民間平台提出的開放協議草案與參考實作,不是民航局或任何政府機關發布的法定標準。 台灣現行法規尚未強制要求遙控無人機廣播 Remote ID(需查證:民航局是否已有草案時程;查證方式=民航局無人機專區與交通部法規預告平台)。定位=在國際標準(ASTM F3411、MAVLink、CAP)之上,先把台灣本地化的識別與回報格式做出可運作的參考實作,供廠商、研究單位與政府單位測試接軌。
| 範圍 | 內容 | 依據 |
|---|---|---|
| 訊息格式 | 機體識別、位置遙測、操作人資訊的 JSON 訊息結構 | 對齊 ASTM F3411 Remote ID 訊息集與 MAVLink OPEN_DRONE_ID_* 訊息 |
| 註冊識別碼 | 「TW-{縣市碼}-{序號}」的平台註冊識別碼格式(提案) | ISO 3166-2:TW 縣市代碼 |
| 遙測回報 | 回報頻率、欄位、單位、時戳規則 | F3411 廣播頻率為基準 |
| 傳輸繫結 | 廣播繫結(引國際標準)+網路繫結(HTTPS/WebSocket,自定義) | F3411/本協議 |
| 安全 | Ed25519 訊息簽章、金鑰註冊、重放防護 | RFC 8032/RFC 8785 |
版本策略:語意化版本。v0.x 為草案期,欄位可能有不相容變更;v1.0 起不相容變更必須升主版號。訊息內以 version 欄位宣告(只含主次版號,如 "0.1")。
| 標準 | 名稱 | 本協議引用範圍 |
|---|---|---|
| ASTM F3411-22a | Standard Specification for Remote ID and Tracking | 訊息類型分類、欄位語意、廣播傳輸方式 |
| MAVLink(開源) | OPEN_DRONE_ID_* 訊息集(msg id 12900–12905、12915) | 欄位命名、列舉值(ODID_* enums)、飛控整合參考 |
| OASIS CAP 1.2 | Common Alerting Protocol Version 1.2 | 告警訊息格式(G4 緊急廣播),本協議只定義關聯方式 |
| RFC 8032 | EdDSA(Ed25519)數位簽章 | 訊息簽章演算法 |
| RFC 8785 | JSON Canonicalization Scheme(JCS) | 簽章前的 JSON 正規化 |
| ISO 3166-2:TW | 台灣行政區代碼 | 註冊識別碼的縣市碼 |
| ANSI/CTA-2063-A | Small UAS Serial Numbers | 機體序號格式(idType=1 時) |
| WGS 84 | 世界大地測量系統 | 所有座標基準 |
| ISO 8601 | 日期時間格式 | 網路繫結所有時戳 |
| 術語 | 白話解釋 |
|---|---|
| Remote ID(遙控識別) | 無人機的「電子車牌」:飛行中持續對外廣播「我是誰、我在哪、飛多高多快、操作人在哪」,執法者與公眾可接收 |
| 廣播繫結(Broadcast) | 用藍牙/WiFi 直接對周遭空中喊話,不經網路,手機在附近就收得到 |
| 網路繫結(Network) | 經行動網路把同樣的資訊回報到伺服器,遠端也看得到 |
| UAS/UA | 無人機系統/無人機機體 |
| GCS | 地面控制站(遙控器或地面站軟體) |
| Ed25519 | 一種數位簽章演算法:私鑰簽名、公鑰驗證,速度快、金鑰短(32 bytes),無法偽造 |
| 重放攻擊(Replay) | 攻擊者錄下一則合法訊息,之後原封不動再送一次冒充即時資料;防法=時間窗+去重 |
| TOFU | Trust On First Use,首次見面先信任:演練環境用,正式環境必須查註冊庫 |
┌──────────────┐ 廣播繫結(BLE / WiFi NAN)🌐 ┌──────────────┐
│ 機載發射端 │ ────────────────────────────▶ │ 地面接收端 │
│(無人機/飛控) │ │(手機/接收器) │
└──────┬───────┘ └──────┬───────┘
│ │ 轉送(自定義)🔶
│ 網路繫結(HTTPS / WebSocket)🔶 ▼
└──────────────────────────▶ ┌────────────────────────┐
│ 平台接收端(TDRP 伺服器) │
┌──────────────┐ │ 驗章 → 入庫 → 態勢推播 │
│ 註冊庫(G3) │ ◀── 金鑰查詢 ── └───────────┬────────────┘
└──────────────┘ ▼
┌────────────────────────┐
│ G5 態勢儀表板 / G4 CAP 告警 │
└────────────────────────┘| 角色 | 說明 | 一致性等級(§10) |
|---|---|---|
| 發射端(Reporter) | 無人機、飛控外掛模組、或 GCS 代發。產生訊息、簽章、經繫結送出 | Class A(直發)/Class B(GCS 代發) |
| 地面接收端(Observer) | 接收廣播訊息的手機 App 或固定接收器;可選擇性轉送至平台 | Observer |
平台接收端(Ingest)——參考實作=POST /api/v1/protocol/telemetry 與 WS /ws/protocol/report | 驗證、儲存、推播 | Ingest |
| 註冊庫(Registry) | 識別碼 ↔ 公鑰 ↔ 機主的對應(G3 參考實作) | Registry |
格式:TW-{縣市碼 3 碼}-{序號 6 碼+檢查碼 1 碼},總長 14 字元,符合 F3411 Basic ID 的 UAS ID 欄位上限(20 bytes)。序號字元集用 Crockford Base32(0–9、A–Z 排除 I/L/O/U,避免與 1/0 混淆)。範例:TW-TPE-04X2K9C(臺北市登記、序號 04X2K9、檢查碼 C)。正規表達式:^TW-[A-Z]{3}-[0-9A-HJKMNP-TV-Z]{7}$。
| 代碼 | 縣市 | 代碼 | 縣市 | 代碼 | 縣市 |
|---|---|---|---|---|---|
TPE | 臺北市 | NWT | 新北市 | TAO | 桃園市 |
TXG | 臺中市 | TNN | 臺南市 | KHH | 高雄市 |
KEE | 基隆市 | HSZ | 新竹市 | CYI | 嘉義市 |
ILA | 宜蘭縣 | HSQ | 新竹縣 | MIA | 苗栗縣 |
CHA | 彰化縣 | NAN | 南投縣 | YUN | 雲林縣 |
CYQ | 嘉義縣 | PIF | 屏東縣 | TTT | 臺東縣 |
HUA | 花蓮縣 | PEN | 澎湖縣 | KIN | 金門縣 |
LIE | 連江縣 |
| 代碼 | 用途 |
|---|---|
GOV | 政府機關機隊 |
TMP | 臨時/測試(僅演練) |
S = Σ vᵢ × (i + 2)(權重 2–7,可偵測相鄰換位)S mod 32 個字元——「抄錯一個字」在輸入當下就被抓到basic_id 的 idType=2 時,uasId 放民航局註冊號原文即可。TDRP 格式用於平台參考註冊系統(G3)、演練與模擬環境,以及未來若獲採用的法定格式提案基礎。| TDRP type | F3411 訊息 | MAVLink 訊息(msg id) | 必要性 |
|---|---|---|---|
basic_id | Basic ID(0x0) | OPEN_DRONE_ID_BASIC_ID(12900) | 必要 |
location | Location/Vector(0x1) | OPEN_DRONE_ID_LOCATION(12901) | 必要 |
| (不採用,見 §8) | Authentication(0x2) | OPEN_DRONE_ID_AUTHENTICATION(12902) | — |
self_id | Self-ID(0x3) | OPEN_DRONE_ID_SELF_ID(12903) | 選用 |
system | System(0x4) | OPEN_DRONE_ID_SYSTEM(12904) | 必要(首包與變更時) |
operator_id | Operator ID(0x5) | OPEN_DRONE_ID_OPERATOR_ID(12905) | 選用 |
外框 messages[] | Message Pack(0xF) | OPEN_DRONE_ID_MESSAGE_PACK(12915) | 外框即封包 |
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
protocol | string | ✅ | 固定 "TDRP" |
version | string | ✅ | 協議版本,如 "0.1" |
reportId | string(UUID) | ✅ | 本包唯一識別(重放防護去重鍵) |
senderId | string ≤20 | ✅ | 發送方識別碼(TDRP 註冊碼或民航局註冊號) |
drill | boolean | — | true=演練/模擬資料,接收端必須標示且不得混入真實態勢。預設 false |
keyId | string ≤64 | 簽章時✅ | 簽章金鑰識別(同一 sender 可輪替多把金鑰) |
sentAt | string(ISO 8601, UTC) | ✅ | 發送時間 |
messages | TdrpMessage[](1–64 則) | ✅ | 訊息陣列 |
signature | string(base64) | 見 §10 | 外框 Ed25519 簽章(§8) |
| 欄位 | 型別 | 必填 | 單位/範圍 |
|---|---|---|---|
idType | number | ✅ | 0 無|1 機體序號(CTA-2063-A)|2 民航主管機關核發註冊碼|3 UTM UUID|4 session ID |
uaType | number | ✅ | 0–15:0 未宣告、1 定翼機、2 直升機/多旋翼、3 旋翼機、4 垂直起降複合翼、5 撲翼機、6 滑翔機、7 風箏、8 自由氣球、9 繫留氣球、10 飛船、11 自由落體/傘、12 火箭、13 繫留動力航空器、14 地面障礙物、15 其他 |
uasId | string | idType≠0 時✅ | ≤20 字元(F3411 UAS ID 20 bytes) |
| 欄位 | 型別 | 必填 | 單位/範圍 |
|---|---|---|---|
status | number | ✅ | 0 未宣告|1 地面|2 飛行中|3 緊急狀態|4 Remote ID 系統故障 |
lat/lon | number | ✅ | 十進位度,WGS 84,建議 7 位小數 |
altGeodetic | number | null | ✅ | m,WGS 84 橢球高 |
altBarometric | number | null | — | m,氣壓高度(1013.25 hPa 基準) |
height | number | null | ✅ | m,相對高度 |
heightRef | number | ✅ | 0=起飛點上方、1=地面上方 |
direction | number | null | ✅ | 度 [0, 360),對地航向(真北) |
speedHorizontal | number | null | ✅ | m/s ≥0,對地水平速度 |
speedVertical | number | null | ✅ | m/s,向上為正 |
horizontalAccuracy 等 3 欄 | number | — | MAV_ODID_*_ACC 列舉(水平 0–12/垂直 0–6/速度 0–4) |
measuredAt | string(ISO 8601, UTC) | ✅ | 位置量測時刻 |
null——解析端不需記憶各欄位的魔術數字。時戳差異(🔶):F3411 廣播用「整點後 0.1 秒計數」省位元組;網路繫結改用完整 ISO 8601,消除跨整點模糊,轉廣播時由發射端換算。| 訊息 | 欄位 | 說明 |
|---|---|---|
self_id | descriptionType、description | 飛行目的自述:0 一般文字、1 緊急說明、2 延伸狀態;≤100 字元(🔶 放寬;廣播繫結截斷至 23 bytes) |
system | operatorLocationType、operatorLat/Lon、areaCount/Radius/Ceiling/Floor、uaClass | 操作人位置(0 起飛點、1 動態 GNSS、2 固定)與作業區資訊;編隊機數預設 1 |
operator_id | operatorIdType、operatorId | 操作人證號:0=民航主管機關核發操作證號,≤20 字元 |
| 值 | 提案級距 |
|---|---|
| 0 | 未宣告 |
| 1 | 未達 250 g |
| 2 | 250 g – 2 kg |
| 3 | 2 kg – 15 kg |
| 4 | 15 kg 以上 |
| 項目 | 規範 | 層級 |
|---|---|---|
location | 飛行中 ≥1 Hz(F3411 廣播基準);網路繫結預設 1 Hz,壅塞時允許降至 0.2 Hz 並於恢復後補送最後位置 | 🌐 基準+🔶 細則 |
| 靜態訊息頻率 | basic_id/system/operator_id:連線後首包必含;之後每 30 秒重送一次或內容變更時立即送 | 🌐 基準+🔶 細則 |
| 地面狀態 | 起飛前與降落後 status=1 至少各送一包;結束作業送出最後一包後才可斷線 | 🔶 |
| 單位 | 一律 SI:公尺、m/s、十進位度;不用英呎、節、百分度 | 🔶 |
| 時戳 | 一律 UTC ISO 8601 含毫秒;measuredAt 是量測時刻、sentAt 是送出時刻(斷線重送時差異即傳輸延遲) | 🔶 |
| 打包 | 同一 tick 的多則訊息裝進同一 TdrpReport(一包一簽章,省驗章成本) | 🔶 |
| 順序 | 接收端以 measuredAt 排序,不假設封包到達順序 | 🔶 |
廣播繫結(🌐 依 ASTM F3411,本協議不重新定義):BLE=Bluetooth 4 Legacy Advertising(25-byte 訊息、相容最廣)與 Bluetooth 5 Long Range(Coded PHY S8)+Extended Advertising;WiFi=Neighbor Awareness Networking(NAN)與 WiFi Beacon(vendor specific element)。TDRP 不修改 F3411 廣播格式,只定義 §5 各表的語意映射(時戳換算見 §5)。
| 項目 | 規範 |
|---|---|
| 端點 | POST /api/v1/protocol/telemetry |
| 認證 | HTTP 標頭 X-TDRP-Api-Key(API key 管「誰能連」、簽章管「訊息是誰發的且沒被改」,兩回事) |
| 本體 | 單一 TdrpReport JSON(UTF-8) |
| 限流 | 60 次/分/金鑰(平台參考實作值) |
| 回應 | 200 受理({accepted, rejected, errors})|400 外框格式錯誤|401 API key 無效|403 簽章失敗或停權|429 超限 |
| 方向 | 帧 | 說明 |
|---|---|---|
| — | 端點 ws(s)://{host}/ws/protocol/report,子協議 tdrp.v0 | 心跳=標準 ping/pong:伺服器每 30 秒 ping、90 秒無回應斷線 |
| C→S | {"type":"hello","senderId","keyId","publicKey?"} | 連線後第一帧;publicKey 僅演練模式(TOFU)接受,正式模式必查註冊庫 |
| S→C | {"type":"welcome","serverTime","drillMode"} | 伺服器確認;drillMode 告知目前環境 |
| C→S | TdrpReport(§5 原樣) | 遙測回報 |
| S→C | {"type":"ack","reportId","accepted","rejected"} | 逐包受理回執 |
| S→C | {"type":"error","code","message"} | INVALID_REPORT/BAD_SIGNATURE/REPLAY/STALE/UNKNOWN_KEY/RATE_LIMITED |
| S→C | 關閉碼 1008 | 認證失敗/被停權 |
為什麼是外框簽章而非 F3411 Authentication:F3411 Authentication 訊息是為 25-byte 廣播訊框設計的分段簽章機制;網路繫結沒有帧長限制,TDRP 直接對整個 TdrpReport 簽一次 Ed25519——實作簡單、涵蓋全部訊息、驗章一次完成。廣播繫結若需驗證,依 F3411 原文。
signature 欄位),keyId 必填signature = base64( Ed25519-Sign(privateKey, canonicalBytes) ),放回外框;驗章端做同樣正規化後以公鑰驗證,失敗即整包拒收| 階段 | 規範 |
|---|---|
| 產生 | 發送端自行產生 Ed25519 金鑰對(32-byte seed),私鑰永不離開發送端 |
| 註冊 | 公鑰(base64)+keyId 登記於註冊庫(G3 參考實作:機體登記時綁定);一機可綁多把(輪替期並存) |
| 輪替 | 新增新 keyId → 切換簽章 → 舊鑰保留 30 天供驗歷史資料 → 註銷 |
| 註銷 | 註冊庫標記 revoked;接收端對 revoked 金鑰簽出的新訊息一律拒收 |
| 演練 TOFU | 演練模式允許 hello 帧自報公鑰(首見信任),該連線資料必須標記 drill=true;正式模式禁止 TOFU |
| 機制 | 規範 |
|---|---|
| 時間窗 | sentAt 與伺服器時間差超過 ±120 秒即拒收(STALE) |
| 去重 | (senderId, reportId) 在時間窗內重複即拒收(REPLAY) |
| 傳輸層 | 網路繫結一律 TLS(wss/https);本地開發環境除外 |
system 訊息的操作人位置只進入平台接收端與政府端,公開查詢介面(如 G3 lookup)不得回傳操作人即時位置與個資。廣播繫結的隱私特性由 F3411 決定,非本協議所能約束。TDRP 與 CAP 是反向的兩條資料流,本協議不重新定義告警格式:
TDRP(上行):無人機 ──遙測──▶ 平台 ──態勢──▶ G5 儀表板 CAP (下行):政府(G4)──CAP 1.2 告警──▶ 平台 ──推播──▶ 飛手/機隊
| 關聯點 | 規範 |
|---|---|
| 空間關聯 | 接收端以 CAP <area>(polygon/circle)與 TDRP location 做空間比對,得出「告警區內目前有哪些機」(G5 參考實作) |
| 識別關聯 | CAP <incidents> 或 <parameter> 可引用 TDRP senderId,把告警關聯到特定機體 |
| 簽章一致 | G4 CAP 訊息與 TDRP 外框使用同一套 Ed25519 金鑰基礎設施(平台簽發鑰在 GET /gov/keys 公開) |
| 演練標記 | CAP status=Exercise ↔ TDRP drill=true,兩邊語意對齊,演練資料不混入真實態勢 |
MUST/SHOULD/MAY 依 RFC 2119 語意。
| 等級 | 對象 | 要求 |
|---|---|---|
| Class A 發射端(機載直發) | 無人機/外掛模組 | MUST:basic_id+location+system、1 Hz、Ed25519 簽章、斷線重連。SHOULD:operator_id。MAY:self_id |
| Class B 發射端(GCS 代發) | 地面站軟體 | 同 Class A;另 MUST 在 system.operatorLocationType 如實宣告操作人位置類型 |
| 接收端 | 平台/政府系統 | MUST:驗章、重放防護、drill 隔離、拒收 TMP 碼(正式模式)。SHOULD:ack 回執。MAY:TOFU(僅演練) |
| 簽章 | 所有正式模式訊息 | MUST 簽章;演練模式 SHOULD 簽章(參考實作一律簽) |
{
"protocol": "TDRP",
"version": "0.1",
"reportId": "0d1f7c2e-8a4b-4e7a-9c3d-2f1e6b5a4c3d",
"senderId": "TW-TPE-04X2K9C",
"drill": true,
"keyId": "k-2026-demo",
"sentAt": "2026-07-02T06:30:00.000Z",
"messages": [
{ "type": "basic_id", "idType": 2, "uaType": 2, "uasId": "TW-TPE-04X2K9C" },
{ "type": "location", "status": 2,
"lat": 25.0674, "lon": 121.5081,
"altGeodetic": 62.5, "altBarometric": null,
"height": 48.2, "heightRef": 0,
"direction": 137.4, "speedHorizontal": 6.8, "speedVertical": 0.3,
"measuredAt": "2026-07-02T06:29:59.850Z" },
{ "type": "system", "operatorLocationType": 0,
"operatorLat": 25.0668, "operatorLon": 121.5074,
"areaCount": 1, "uaClass": 2 }
],
"signature": "(64-byte Ed25519 簽章之 base64)"
}import {
createReport, signReport, generateKeyPair,
TdrpClient, TdrpReceiver, randomRegistrationId,
} from '@twdrone/protocol';
// 發送端:建包 → Ed25519 簽章 → WS 回報(1 Hz)
const pair = await generateKeyPair();
const client = new TdrpClient({
url: 'ws://localhost:3502/ws/protocol/report',
senderId: randomRegistrationId('TMP'), // 演練用臨時識別碼
keyId: 'k-1',
privateSeedBase64: pair.privateSeedBase64,
publicKeyBase64: pair.publicKeyBase64, // 演練 TOFU 自報公鑰
drill: true,
});
client.connect();
await client.send([{ type: 'location', status: 2, lat: 25.06, lon: 121.5,
altGeodetic: 60, height: 48, heightRef: 0, direction: 137,
speedHorizontal: 6.8, speedVertical: 0.3,
measuredAt: new Date().toISOString() }]);
// 接收端:驗格式 → 防重放 → 驗簽章,一行受理
const receiver = new TdrpReceiver({ drillMode: true });
const result = await receiver.ingest(rawJsonText);
// result.ok ? result.ack : result.error(REPLAY / BAD_SIGNATURE / …)| 項目 | 位置 |
|---|---|
| 規格書原文(Markdown) | docs/protocol/TDRP_SPEC.md |
| TS SDK(encode/decode/驗證/簽章/client/receiver) | packages/protocol/ |
| 虛擬無人機模擬端(N 架機 → WS → G5 儀表板) | pipelines/protocol/virtual_drone.ts |
| 開發用接收端(TOFU 驗章示範+轉送) | pipelines/protocol/dev_receiver.ts |
| 回報端 API key 核發 | pipelines/protocol/seed_api_key.ts |
| 版本 | 日期 | 變更 |
|---|---|---|
| 0.1 | 2026-07-02 | 初版草案:訊息集、識別碼、網路繫結、Ed25519 簽章 |
本協議為民間開放協議草案,不具法定效力;規格書原文(單一真相源)=專案內 docs/protocol/TDRP_SPEC.md。社群俗稱「紅區/黃區」非法定用語,法定用語為「禁航區/限航區」(民用航空法 §99-13)。本平台僅提供資訊,不代辦飛航活動申請,亦不涵蓋即時 NOTAM。空域與法規資料來源:民航局(依政府資料開放授權條款)。資訊僅供參考,實際以民航局公告為準。