iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Security

30 天實戰車聯網資安系列 第 14

Day 14|SUMO 實作:建立第一個交通模擬場景

  • 分享至 

  • xImage
  •  

Day 13 我們用 netgenerate 快速產生格狀道路,再透過 SUMO GUI 看見第一座會跑車的城市。

這種方式很適合確認環境是否正常,但工具自動產生的路網藏了不少細節。

如果今天想研究智慧十字路口,就必須能回答下面幾個問題:

  • 路口座標在哪裡?
  • 道路允許往哪個方向行駛?
  • 車輛要走過哪些道路?
  • 一段時間內會出現多少車?
  • 模擬結束後要用什麼資料判斷交通狀況?

今天我們不再讓工具替我們決定整座城市,而是從八個 Node 與十四條 Edge 開始,親手建立一條具有兩座號誌路口的城市幹道。

接著會加入一台指定車輛與六股車流,最後輸出 TripInfo 檢查每台車的行程時間及等待狀況。

完成基本場景後,我們還會把相同需求放大成兩倍,做一次正常車流與尖峰車流的對照實驗。

今天的學習目標

讀完這篇文章,你應該能夠:

  1. 分辨 Plain XML 與 .net.xml 的用途
  2. 使用 Node 與 Edge 描述一條雙路口城市幹道
  3. 使用 netconvert 產生 SUMO Network
  4. 使用 Route 定義車輛的行駛路徑
  5. 分辨 Vehicle 與 Flow 的差異
  6. 使用 .sumocfg 載入路網及交通需求
  7. 透過 SUMO GUI 與 TripInfo 驗證模擬結果
  8. 比較正常車流與兩倍車流的等待時間及時間損失

Day 13 與 Day 14 的實作差在哪裡?

兩天都會在 SUMO GUI 看見車輛移動,但練習目的並不相同。

比較項目 Day 13 Day 14
核心問題 SUMO 環境能不能成功跑起來? 場景中的道路與車流為什麼這樣運作?
路網建立 netgenerate 自動產生 3×3 格狀路網 手動建立兩座連續號誌路口
交通需求 randomTrips.py 自動選擇起訖點 手動建立 Route、Vehicle 與 Flow
控制程度 快速產生可用場景 明確控制道路方向、號誌路口與出發頻率
主要輸出 FCD 位置與速度軌跡 TripInfo、Summary 與整體統計
實驗目的 取得 V2X 節點的移動 Ground Truth 建立 Baseline 並比較交通需求變化

Day 13 比較像安裝完成後的整合測試,重點是從路網一路跑到 FCD 輸出。

Day 14 則開始進入場景設計,我們必須知道每個參數改變了什麼,也要能用數據說明結果。

今天要建立什麼場景?

我們要建立一條東西向城市幹道,途中會經過 j1j2 兩座號誌路口。

兩座路口各自連接南北向支路,車輛除了直行穿越幹道,也能從支路轉入主要道路。

               north_j1                 north_j2
                   │                        │
                   │                        │
west ───────────── j1 ──────────────────── j2 ───────────── east
                   │                        │
                   │                        │
               south_j1                 south_j2

東西向幹道長 900 公尺,兩座路口相距 300 公尺。

這個規模仍然容易閱讀 XML,卻已經能觀察連續號誌、支路匯入與車流累積,不會只是把 Day 13 的城市縮成一個小路口。

整個實作會經過以下流程:

day14.nod.xml + day14.edg.xml
                 │
                 ▼
             netconvert
                 │
                 ▼
           day14.net.xml
                 │
                 ├── day14.rou.xml
                 └── day14.sumocfg
                         │
                         ▼
                   sumo/sumo-gui
                         │
                         ▼
          day14-tripinfo.xml/day14-summary.xml

其中 day14.nod.xmlday14.edg.xml 是方便人類編輯的 Plain XML。

netconvert 會把它們轉成 SUMO 能直接載入的 day14.net.xml,並補上 Lane、Connection 與 Junction Logic 等衍生資料。

.net.xml 不是這次要手動維護的原始檔。需要調整路口或道路時,應修改 Node/Edge 檔案後重新執行 netconvert

SUMO 官方教學也會先用 Node 與 Link 的方式規劃路網,再加入車輛類型、路線及交通需求。

SUMO 官方 Quick Start 使用 Node 與 Link 規劃交通模擬路網

圖 1:SUMO 路網可以先用 Node 與具有方向的道路區段描述,圖中的官方範例同樣包含連續路口與支路
圖片來源: Eclipse SUMO Documentation

Node、Edge 與 Route 的關係

開始寫檔案前,先把三個最容易混淆的概念分開。

元件 代表什麼 今天的例子
Node 道路端點或路口 j1j2west
Edge 兩個 Node 之間具有方向的道路 west_j1
Route 車輛依序通過的 Edge west_j1 j1_j2 j2_east

一條 Edge 只有一個方向。

因此,西邊通往第一座路口與第一座路口通往西邊是兩條不同的 Edge:

west → j1    west_j1
j1 → west    j1_west

Route 則必須由前後相連的 Edge 組成。

例如從西向東通過兩座路口,可以寫成:

west_j1 → j1_j2 → j2_east

如果把兩條沒有相接的 Edge 放進同一條 Route,SUMO 就無法替車輛建立連續路徑。

為什麼加入兩座號誌路口?

單一路口可以用來認識 Node 與 Edge,但連續路口才容易看見號誌之間的影響。

一台車通過 j1 後,可能在抵達 j2 時再次遇到紅燈,後方車流也可能逐漸在兩座路口之間累積。

今天先讓 netconvert 自動建立固定週期的號誌邏輯,不另外手寫 <tlLogic>

這些預設號誌適合教學與基礎測試,但不代表任何真實城市的號誌時制,也沒有根據實際交通量完成最佳化。

兩座號誌預設各自運作,尚未建立綠波協調。

因此,我們可以在 GUI 觀察 demo_car 能否連續通過,並利用 TripInfo 看見等待如何反映在 durationtimeLoss

Vehicle 與 Flow 有什麼不同?

vehicle 用來描述一台明確的車。

它有自己的 ID、出發時間、車輛類型及路線,很適合控制特定測試節點。

flow 則描述一段時間內持續產生的交通需求。

它可以使用固定間隔、每小時流率或車輛總數,不需要逐台列出 Vehicle。

需求類型 適合使用的情境 今天的用途
Vehicle 追蹤指定車輛或安排精確出發時間 建立紅色的 demo_car
Flow 建立背景車流或大量交通需求 產生幹道與支路的六股持續車流

到了後面的 V2X 攻擊模擬,我們可以把惡意車輛寫成單獨的 Vehicle,再用 Flow 產生正常背景車流。

這樣能控制攻擊節點何時出現,也不必逐台建立其他道路使用者。

今日實作:手動建立一條雙路口城市幹道

本次實作在 Kali VM 進行,並沿用 Day 13 已安裝完成的 SUMO 環境。

如果下面任何一步出現錯誤,先不要直接修改產生後的 .net.xml,應回到對應的 Node、Edge 或 Route 檔案檢查。

步驟 1:建立工作目錄

開啟 Terminal 後執行:

mkdir -p ~/sumo-day14
cd ~/sumo-day14

後續建立的所有檔案都放在這個目錄,避免和 Day 13 的場景混在一起。

步驟 2:建立八個 Node

使用文字編輯器建立 day14.nod.xml

nano day14.nod.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<nodes>
    <node id="j1" x="0" y="0" type="traffic_light"/>
    <node id="j2" x="300" y="0" type="traffic_light"/>

    <node id="west" x="-300" y="0"/>
    <node id="east" x="600" y="0"/>

    <node id="north_j1" x="0" y="200"/>
    <node id="south_j1" x="0" y="-200"/>
    <node id="north_j2" x="300" y="200"/>
    <node id="south_j2" x="300" y="-200"/>
</nodes>

座標單位是公尺。

j1 位於原點,j2 在東側 300 公尺處,幹道兩端再各延伸 300 公尺。

兩個路口都使用 type="traffic_light"netconvert 會替它們建立可使用的預設號誌邏輯。

步驟 3:建立十四條單向 Edge

建立 day14.edg.xml

nano day14.edg.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<edges>
    <edge id="west_j1" from="west" to="j1"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j1_west" from="j1" to="west"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j1_j2" from="j1" to="j2"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j2_j1" from="j2" to="j1"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j2_east" from="j2" to="east"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="east_j2" from="east" to="j2"
          priority="2" numLanes="1" speed="13.89"/>

    <edge id="north_j1_in" from="north_j1" to="j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j1_south_out" from="j1" to="south_j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="south_j1_in" from="south_j1" to="j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j1_north_out" from="j1" to="north_j1"
          priority="1" numLanes="1" speed="13.89"/>

    <edge id="north_j2_in" from="north_j2" to="j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j2_south_out" from="j2" to="south_j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="south_j2_in" from="south_j2" to="j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j2_north_out" from="j2" to="north_j2"
          priority="1" numLanes="1" speed="13.89"/>
</edges>

每條 Edge 都只有一條 Lane,允許速度是每秒 13.89 公尺,約等於每小時 50 公里。

東西向 Edge 的 priority 設為 2,南北向支路則設為 1。

這個數值用來表示相對優先順序,不是車輛通過路口的保證,也不是資安風險分數。

步驟 4:使用 netconvert 產生 Network

執行:

netconvert \
  --node-files day14.nod.xml \
  --edge-files day14.edg.xml \
  --output-file day14.net.xml

成功時應該看到:

Success.

接著確認檔案已經產生:

ls -lh day14.nod.xml day14.edg.xml day14.net.xml

如果出現 Unknown node,通常是 Edge 引用的 Node ID 拼錯。

如果出現連接相關錯誤,則要檢查 Edge 的 fromto 是否能在 j1j2 接起來。

步驟 5:先在 GUI 檢查空路網

在加入車輛之前先確認路網形狀:

sumo-gui -n day14.net.xml

畫面應該會出現一條連接兩座號誌路口的東西向幹道。

此時沒有任何車輛是正常現象,因為我們還沒加入 Route、Vehicle 或 Flow。

步驟 6:加入 Vehicle Type 與六條 Route

建立 day14.rou.xml

nano day14.rou.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<routes>
    <vType id="passenger"
           vClass="passenger"
           accel="2.6"
           decel="4.5"
           sigma="0.5"
           length="5"
           maxSpeed="13.89"/>

    <route id="west_to_east"
           edges="west_j1 j1_j2 j2_east"/>
    <route id="east_to_west"
           edges="east_j2 j2_j1 j1_west"/>
    <route id="north1_to_south1"
           edges="north_j1_in j1_south_out"/>
    <route id="south1_to_east"
           edges="south_j1_in j1_j2 j2_east"/>
    <route id="north2_to_south2"
           edges="north_j2_in j2_south_out"/>
    <route id="south2_to_west"
           edges="south_j2_in j2_j1 j1_west"/>

    <vehicle id="demo_car"
             type="passenger"
             route="west_to_east"
             depart="0"
             color="1,0,0"/>

    <flow id="flow_we"
          type="passenger"
          route="west_to_east"
          begin="5" end="120" period="6"
          departLane="best" departSpeed="max"/>
    <flow id="flow_ew"
          type="passenger"
          route="east_to_west"
          begin="6" end="120" period="8"
          departLane="best" departSpeed="max"/>
    <flow id="flow_ns"
          type="passenger"
          route="north1_to_south1"
          begin="7" end="120" period="12"
          departLane="best" departSpeed="max"/>
    <flow id="flow_se"
          type="passenger"
          route="south1_to_east"
          begin="8" end="120" period="15"
          departLane="best" departSpeed="max"/>
    <flow id="flow_n2s2"
          type="passenger"
          route="north2_to_south2"
          begin="9" end="120" period="12"
          departLane="best" departSpeed="max"/>
    <flow id="flow_s2w"
          type="passenger"
          route="south2_to_west"
          begin="10" end="120" period="15"
          departLane="best" departSpeed="max"/>
</routes>

demo_car 會在第 0 秒從西側出發,並沿 west_to_east 依序通過兩座路口。

它被指定為紅色,方便之後在 GUI 裡追蹤。

六個 Flow 包含東西向幹道車流、穿越支路的直行車流,以及從南側支路匯入幹道的轉向車流。

例如 period="6" 表示這個 Flow 嘗試每 6 秒產生一台車,但實際進入時間仍可能受到道路空間影響。

Route 檔案中的 Vehicle 與 Flow 應依 departbegin 時間排列,這能避免載入需求時發生順序問題。

步驟 7:建立模擬設定檔

建立 day14.sumocfg

nano day14.sumocfg

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <input>
        <net-file value="day14.net.xml"/>
        <route-files value="day14.rou.xml"/>
    </input>

    <time>
        <begin value="0"/>
        <end value="240"/>
    </time>

    <output>
        <tripinfo-output value="day14-tripinfo.xml"/>
        <summary-output value="day14-summary.xml"/>
    </output>
</configuration>

Flow 會在第 120 秒停止產生車輛,模擬則持續到第 240 秒。

多出的時間可以讓較晚出發的車繼續完成行程,減少模擬結束時仍停留在路網上的車輛。

步驟 8:先用命令列驗證場景

執行:

sumo -c day14.sumocfg

命令正常結束後,確認輸出檔案:

ls -lh day14-tripinfo.xml day14-summary.xml

若 Route 無法連接,SUMO 會直接指出有問題的 Vehicle、Flow 或 Edge。

先在命令列排除設定錯誤,通常比只盯著 GUI 更容易找到原因。

步驟 9:在 GUI 觀察雙路口車流

執行:

sumo-gui -c day14.sumocfg

按下綠色播放按鈕後,應該會看到車輛沿幹道通過兩座號誌,也會有車輛從四條支路進入場景。

如果模擬瞬間結束,可以把上方的 Delay 調整到 100 或 200 ms,再重新執行一次。

觀察時可以特別注意:

  • 紅色 demo_car 是否從西向東行駛
  • demo_car 是否依序通過 j1j2
  • 號誌變換時,路口前方是否逐漸累積車輛
  • 支路車輛是否能直行或轉入東西向幹道
  • 車輛 ID 是否由 Flow 自動產生

步驟 10:查看 TripInfo

模擬完成後執行:

grep -m 5 '<tripinfo ' day14-tripinfo.xml

每一筆 <tripinfo> 代表一台已輸出行程資料的車輛,常見欄位包括:

欄位 代表意義
depart 車輛實際進入模擬的時間
arrival 車輛抵達終點的時間
duration 從出發到抵達所花的時間
waitingTime 車速低於等待門檻的累積時間
timeLoss 相對理想行駛狀況損失的時間
departDelay 原定出發與實際出發之間的延遲

接著查看 Summary:

grep -m 5 '<step ' day14-summary.xml

Summary 會按模擬時間記錄路網中的車輛數、平均速度與等待狀況,適合觀察整體趨勢。

TripInfo 則適合分析單一車輛或比較不同 Route 的行程表現。

步驟 11:比較正常車流與兩倍尖峰車流

目前我們已經有一組可正常執行的場景,接下來把它當成 Baseline(基準組)

這次只改變交通需求規模,路網、Route、車輛類型與模擬時間全部保持不變。

先執行正常車流:

sumo -c day14.sumocfg \
  --scale 1 \
  --tripinfo-output day14-baseline-tripinfo.xml \
  --summary-output day14-baseline-summary.xml \
  --statistic-output day14-baseline-statistics.xml \
  --tripinfo-output.write-unfinished true \
  --duration-log.statistics

再把需求放大為兩倍:

sumo -c day14.sumocfg \
  --scale 2 \
  --tripinfo-output day14-busy-tripinfo.xml \
  --summary-output day14-busy-summary.xml \
  --statistic-output day14-busy-statistics.xml \
  --tripinfo-output.write-unfinished true \
  --duration-log.statistics

--scale 2 會把載入的交通需求放大為兩倍,SUMO 會依需求內容增加 Vehicle 或提高 Flow 的產生頻率。

這裡沒有修改任何 XML,因此兩次執行的唯一主要變因就是交通量。

--tripinfo-output.write-unfinished true 會把模擬結束時尚未完成行程的車輛也納入輸出,避免壅塞組只統計已抵達的車輛而低估影響。

執行完成後查看兩組整體統計:

grep -H '<vehicleTripStatistics ' day14-*-statistics.xml

特別比較下面幾個欄位:

欄位 比較問題
count 兩組有多少車輛被納入統計?
duration 平均完成一趟行程需要多久?
waitingTime 車輛平均靜止等待多久?
timeLoss 相對理想行駛狀態損失多少時間?
departDelay 車輛是否因入口空間不足而延後出發?

我們可以先提出假設:

當其他條件保持不變,兩倍車流會讓兩座路口的競爭增加,因此平均等待時間與 Time Loss 可能上升。

實際數值仍取決於車流是否超過路口可以消化的程度。

如果兩組差異很小,可以把 --scale 2 改成 --scale 3 再執行一次,但要在實驗紀錄中清楚寫下調整後的倍率。

也可以在 SUMO GUI 上方把 Scale Traffic 設成 2,直接觀察車輛增加後的畫面。

不過正式比較仍建議使用命令列,因為指令能完整記錄實驗參數,也比較容易重現。

這就是今天比 Day 13 多走的一步:不只讓模擬跑完,還要控制變因、留下結果並驗證原本的假設。

怎麼確認今天的場景真的完成?

工作目錄中至少應該有以下檔案:

檔案 角色
day14.nod.xml 八個 Node 的座標與兩座號誌路口
day14.edg.xml 十四條單向 Edge 的道路設定
day14.net.xml netconvert 產生的完整 Network
day14.rou.xml Vehicle Type、Route、Vehicle 與 Flow
day14.sumocfg 模擬輸入、時間及輸出設定
day14-tripinfo.xml 每台車的行程結果
day14-summary.xml 各時間點的整體模擬摘要
day14-baseline-statistics.xml 正常車流的整體統計
day14-busy-statistics.xml 兩倍車流的整體統計

也可以用以下指令一次確認:

ls -1 day14.* day14-*.xml

今天的完成標準不是「GUI 裡看得到車」而已。

一個可重現的場景還要能從原始 Node/Edge 重新產生 Network,能從設定檔重跑相同交通需求,也能留下可分析的輸出資料。

從交通模擬走向車聯網資安

這條雙路口幹道目前只處理交通行為,還沒有任何 V2X 封包。

但它已經建立後續研究需要的基準環境:

路網
  → 限定車輛可以移動的空間

Route/Flow
  → 決定正常交通需求

Vehicle
  → 可指定為一般車輛或惡意節點

TripInfo/Summary
  → 衡量等待時間與交通影響

未來模擬假道路事件或錯誤位置訊息時,可以先保留相同路網與車流,建立沒有攻擊的 Baseline。

接著只改變攻擊情境與防護機制,再比較行程時間、等待狀況或車輛行為。

如果每次實驗同時更換路網、交通需求及攻擊參數,就很難判斷結果究竟由哪一項改變造成。

因此,今天這些看似普通的 XML 檔案,其實也是後續實驗設計與可重現性的基礎。

安全與法律提醒: 本系列後續攻擊情境只會在模擬環境、測試台或明確取得授權的設備中進行,不對道路上的真實車輛及公共基礎設施進行測試。

今日重點

  • Plain XML 適合描述 Node 與 Edge,再由 netconvert 產生 .net.xml
  • Edge 具有方向,雙向道路需要建立兩條方向相反的 Edge
  • Route 是一串前後相連的 Edge
  • traffic_light 類型可以讓 netconvert 產生預設號誌邏輯
  • Vehicle 適合控制單一車輛,Flow 適合建立持續交通需求
  • .sumocfg 讓命令列與 GUI 使用同一組模擬設定
  • TripInfo 用來分析單車行程,Summary 用來觀察整體模擬趨勢
  • --scale 可以在不修改 Route File 的情況下調整整體交通需求
  • Baseline 與尖峰組只改變一項主要變因,結果才有明確的比較基礎
  • 可重現的 Baseline 是後續比較 V2X 攻擊與防護結果的基礎

明日預告

今天完成了道路、車流與交通輸出,但 SUMO 仍然沒有處理任何無線封包。

Day 15 將進入 OMNeT++,認識離散事件模擬、Module、Network 與 Message,並回答車聯網研究為什麼需要另一套網路模擬器。

參考資料


上一篇
Day 13|SUMO 入門:用軟體建立一座會跑車的城市
下一篇
Day 15|OMNeT++ 入門:車聯網研究為什麼需要網路模擬器?
系列文
30 天實戰車聯網資安15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言