Day 13 我們用 netgenerate 快速產生格狀道路,再透過 SUMO GUI 看見第一座會跑車的城市。
這種方式很適合確認環境是否正常,但工具自動產生的路網藏了不少細節。
如果今天想研究智慧十字路口,就必須能回答下面幾個問題:
今天我們不再讓工具替我們決定整座城市,而是從八個 Node 與十四條 Edge 開始,親手建立一條具有兩座號誌路口的城市幹道。
接著會加入一台指定車輛與六股車流,最後輸出 TripInfo 檢查每台車的行程時間及等待狀況。
完成基本場景後,我們還會把相同需求放大成兩倍,做一次正常車流與尖峰車流的對照實驗。
讀完這篇文章,你應該能夠:
.net.xml 的用途netconvert 產生 SUMO Network.sumocfg 載入路網及交通需求兩天都會在 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 則開始進入場景設計,我們必須知道每個參數改變了什麼,也要能用數據說明結果。
我們要建立一條東西向城市幹道,途中會經過 j1 與 j2 兩座號誌路口。
兩座路口各自連接南北向支路,車輛除了直行穿越幹道,也能從支路轉入主要道路。
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.xml 與 day14.edg.xml 是方便人類編輯的 Plain XML。
netconvert 會把它們轉成 SUMO 能直接載入的 day14.net.xml,並補上 Lane、Connection 與 Junction Logic 等衍生資料。
.net.xml不是這次要手動維護的原始檔。需要調整路口或道路時,應修改 Node/Edge 檔案後重新執行netconvert。
SUMO 官方教學也會先用 Node 與 Link 的方式規劃路網,再加入車輛類型、路線及交通需求。
圖 1:SUMO 路網可以先用 Node 與具有方向的道路區段描述,圖中的官方範例同樣包含連續路口與支路
圖片來源: Eclipse SUMO Documentation
開始寫檔案前,先把三個最容易混淆的概念分開。
| 元件 | 代表什麼 | 今天的例子 |
|---|---|---|
| Node | 道路端點或路口 | j1、j2、west |
| 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 看見等待如何反映在 duration 與 timeLoss。
vehicle 用來描述一台明確的車。
它有自己的 ID、出發時間、車輛類型及路線,很適合控制特定測試節點。
flow 則描述一段時間內持續產生的交通需求。
它可以使用固定間隔、每小時流率或車輛總數,不需要逐台列出 Vehicle。
| 需求類型 | 適合使用的情境 | 今天的用途 |
|---|---|---|
| Vehicle | 追蹤指定車輛或安排精確出發時間 | 建立紅色的 demo_car |
| Flow | 建立背景車流或大量交通需求 | 產生幹道與支路的六股持續車流 |
到了後面的 V2X 攻擊模擬,我們可以把惡意車輛寫成單獨的 Vehicle,再用 Flow 產生正常背景車流。
這樣能控制攻擊節點何時出現,也不必逐台建立其他道路使用者。
本次實作在 Kali VM 進行,並沿用 Day 13 已安裝完成的 SUMO 環境。
如果下面任何一步出現錯誤,先不要直接修改產生後的 .net.xml,應回到對應的 Node、Edge 或 Route 檔案檢查。
開啟 Terminal 後執行:
mkdir -p ~/sumo-day14
cd ~/sumo-day14
後續建立的所有檔案都放在這個目錄,避免和 Day 13 的場景混在一起。
使用文字編輯器建立 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 會替它們建立可使用的預設號誌邏輯。
建立 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。
這個數值用來表示相對優先順序,不是車輛通過路口的保證,也不是資安風險分數。
執行:
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 的 from 與 to 是否能在 j1 或 j2 接起來。
在加入車輛之前先確認路網形狀:
sumo-gui -n day14.net.xml
畫面應該會出現一條連接兩座號誌路口的東西向幹道。
此時沒有任何車輛是正常現象,因為我們還沒加入 Route、Vehicle 或 Flow。
建立 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 應依 depart 或 begin 時間排列,這能避免載入需求時發生順序問題。
建立 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 秒。
多出的時間可以讓較晚出發的車繼續完成行程,減少模擬結束時仍停留在路網上的車輛。
執行:
sumo -c day14.sumocfg
命令正常結束後,確認輸出檔案:
ls -lh day14-tripinfo.xml day14-summary.xml
若 Route 無法連接,SUMO 會直接指出有問題的 Vehicle、Flow 或 Edge。
先在命令列排除設定錯誤,通常比只盯著 GUI 更容易找到原因。
執行:
sumo-gui -c day14.sumocfg
按下綠色播放按鈕後,應該會看到車輛沿幹道通過兩座號誌,也會有車輛從四條支路進入場景。
如果模擬瞬間結束,可以把上方的 Delay 調整到 100 或 200 ms,再重新執行一次。
觀察時可以特別注意:
demo_car 是否從西向東行駛demo_car 是否依序通過 j1 與 j2
模擬完成後執行:
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 的行程表現。
目前我們已經有一組可正常執行的場景,接下來把它當成 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 檔案,其實也是後續實驗設計與可重現性的基礎。
安全與法律提醒: 本系列後續攻擊情境只會在模擬環境、測試台或明確取得授權的設備中進行,不對道路上的真實車輛及公共基礎設施進行測試。
netconvert 產生 .net.xml
traffic_light 類型可以讓 netconvert 產生預設號誌邏輯.sumocfg 讓命令列與 GUI 使用同一組模擬設定--scale 可以在不修改 Route File 的情況下調整整體交通需求今天完成了道路、車流與交通輸出,但 SUMO 仍然沒有處理任何無線封包。
Day 15 將進入 OMNeT++,認識離散事件模擬、Module、Network 與 Message,並回答車聯網研究為什麼需要另一套網路模擬器。
--scale