Day 14 的 demo_car 會沿著兩座號誌路口移動,Day 15 的 carA 與 carB 則會交換 Message。
問題是,這兩個世界目前彼此不知道對方的存在:
SUMO 的 demo_car
→ 知道 Route、Lane、Position 與 Speed
→ 不知道 Application、Radio 與 Packet
OMNeT++ 的 carA/carB
→ 知道 Module、Message、Channel 與 Event
→ 不知道真實路網上的位置與交通狀態
如果只把 Day 14 的路網背景貼到 OMNeT++ 畫面上,車輛位置不會因此同步。
如果只把 SUMO 的軌跡輸出讀進分析工具,也無法讓網路事件在模擬執行中改變車速或 Route。
今天要用 **TraCI(Traffic Control Interface,交通控制介面)**與 Veins,把兩套模擬器接成一個共同推進的實驗:SUMO 負責交通,OMNeT++ 負責網路事件,Veins 則管理同步與動態節點。
讀完這篇文章,你應該能夠:
veins_launchd 的分工updateInterval 對 Mobility 更新與實驗精度的影響最簡單的做法,是先讓 SUMO 完成交通模擬,輸出 FCD 軌跡,再讓網路模擬器依照軌跡移動節點。
這種離線方式適合處理單向資料流:
SUMO 完成模擬
→ 輸出車輛軌跡
→ OMNeT++ 讀取軌跡
→ 執行網路模擬
但它有一個明顯限制。
如果 carA 收到道路事件訊息後決定改道,SUMO 的原始軌跡已經產生完畢,這次網路事件無法回頭改變交通行為。
Online Coupling(線上耦合)則讓兩套模擬器在執行期間持續交換資料:
SUMO 更新車輛移動
→ OMNeT++ 更新 Vehicle Node 位置
→ 網路與應用事件發生
→ 視研究情境要求 SUMO 改速、停車或改道
→ 進入下一次同步
兩種方式沒有絕對好壞,應依研究問題選擇。
| 方法 | 主要資料方向 | 優點 | 主要限制 |
|---|---|---|---|
| 離線軌跡重播 | SUMO → OMNeT++ | 架構較簡單,交通軌跡容易固定與重用 | 網路事件通常不能回饋並改變同一次交通模擬 |
| Online Coupling | SUMO ↔ OMNeT++ | 能同步 Mobility,也能建立通訊影響交通的閉環 | 版本、同步與錯誤處理更複雜 |
本系列 Day 30 的主線案例,需要比較真實模擬位置、對外宣告位置與接收端反應。
如果後續還要觀察錯誤訊息是否讓車輛改道或停車,線上耦合會更符合實驗需要。
把 SUMO 和 OMNeT++ 接起來時,最容易把 TraCI 與 Veins 當成同一個東西。
先分開五個角色:
| 元件 | 主要角色 | 它不會自動完成什麼 |
|---|---|---|
| SUMO | 模擬道路、車流、號誌與每台車的移動 | 不會自行建立 V2X Radio 與 Packet |
| OMNeT++ | 排程網路與應用事件,執行 Module 並記錄結果 | 不會自行理解 SUMO 的 Route 與 Lane |
| TraCI | 讓 Client 透過 TCP 讀取、控制並逐步推進 SUMO | 不會定義 IEEE 802.11p、C-V2X 或安全訊息格式 |
| Veins | 提供車聯網模型,以及 SUMO/OMNeT++ 耦合元件 | 不會替研究者自動選出正確的 Radio 與攻擊模型 |
veins_launchd |
依請求啟動 SUMO Instance,管理 Port、暫存檔與 Proxy | 不負責 V2X 應用邏輯,也不是公開網路服務 |
可以把 TraCI 理解成兩套模擬器交換交通狀態與控制命令的語言。
Veins 則是使用這個語言的整合框架,替 OMNeT++ 管理 SUMO Connection、Vehicle Node 與 Mobility Update,並提供可選用的車聯網通訊模型。
TraCI 採用 TCP Client/Server 架構。
SUMO 是 Server,控制它的外部程式是 Client。
Client 可以要求 SUMO:
TraCI 的核心不只是「查詢目前位置」。
SUMO 在 TraCI Mode 下,必須由 Client 發出 Simulation Step Command 才會繼續推進。
這讓整合層能控制兩套模擬器的共同時間,不會讓 SUMO 先跑到 100 秒,而 OMNeT++ 還停在 20 秒處理封包。
TCP 只提供 TraCI 的傳輸通道,不代表資料已經完成密碼學身分驗證,也不代表這個 Port 適合暴露到不受信任的網路。

圖 1:SUMO 負責交通狀態,OMNeT++ 負責網路事件。Veins 透過 TraCI 同步兩邊,veins_launchd 則協助啟動及管理 SUMO Instance
在 Veins 5.3.1 的典型架構中,TraCIScenarioManagerLaunchd 是 OMNeT++ 端的重要管理元件。
它會連到 veins_launchd,由後者啟動 SUMO,再把 TraCI Command 轉送給對應的 SUMO Instance。
這個管理元件會負責:
TraCIMobility 更新 Position、Speed 與 Direction 等狀態veins_launchd 讓批次實驗更方便,因為每一個 OMNeT++ Run 都能取得獨立的 SUMO Process 與暫存場景。
它預設監聽 127.0.0.1:9999,也就是只接受本機連線。
除非已有明確的隔離與存取設計,不要為了跨機器方便就把它綁定到所有網路介面。
Day 15 學過,OMNeT++ 的 Simulation Time 會直接跳到下一筆 Event。
SUMO 則按照自己的 Step Length 更新交通狀態。
耦合時,整合層會在兩者之間安排同步點。

圖 2:每次同步先讓 SUMO 推進並回傳交通狀態,再更新 OMNeT++ 動態節點。OMNeT++ 可在下一個同步點前處理多筆網路事件
假設 updateInterval = 100 ms,可以先用下面的概念流程理解:
t = 10.0 s
→ Veins 要求 SUMO 推進到下一個同步點
→ SUMO 更新車輛位置與交通狀態
→ TraCI 回傳新增、離開與狀態更新
→ Veins 更新 OMNeT++ Vehicle Node
t = 10.0 s 到 10.1 s 之間
→ OMNeT++ 處理 Beacon、Reception、Timer 與其他網路事件
t = 10.1 s
→ 再次同步 SUMO 與 Mobility
網路事件不必和 SUMO Step 一樣每 100 ms 才能發生。
例如 Packet 可以在 10.023 s 送出,在 10.024 s 到達,OMNeT++ 仍會依離散事件時間處理。
但 Vehicle Position 的更新粒度會受到耦合間隔影響。
updateInterval 越小越好嗎?updateInterval 決定 Veins 多久和 SUMO 同步一次 Mobility 狀態。
較小的間隔可以更頻繁地更新 Position 與 Speed,卻也會增加 TraCI Command、Module Update 與 Simulation Event 的成本。
| 設定方向 | 可能優點 | 可能代價 |
|---|---|---|
較小 updateInterval |
位置更新更細,快速移動與短距離接觸較不容易被粗略化 | 執行時間與同步負擔增加 |
較大 updateInterval |
事件數較少,模擬可能更快 | Mobility 變化較粗,短暫鄰近或遮蔽關係可能被略過 |
不能只因為電腦跑得動,就把數值調到極小。
合理設定要配合:
還要把實際使用值寫進實驗設定與報告。
否則另一位研究者即使拿到相同路網,也可能因同步粒度不同而得到不一樣的鄰居關係與 Packet Reception 結果。
Veins 會依 SUMO 中的 Vehicle 生命週期,動態建立或刪除 OMNeT++ Module。
可以先拆成四個階段:
| SUMO 狀態 | Veins 的工作 | OMNeT++ 結果 |
|---|---|---|
| Vehicle 尚未出發 | 等待 SUMO 回報新增 | 尚未建立對應 Node |
| Vehicle 成功進入路網 | 取得 Vehicle ID 並建立指定 Module Type | 出現新的 Vehicle Node |
| Vehicle 在路網移動 | 按同步間隔更新 Mobility | Node Position、Speed 與 Direction 更新 |
| Vehicle 抵達或離開 | 收到離開事件並清理對應關係 | Vehicle Node 被移除 |
這裡最重要的邊界是:Network 裡看見的 Node 數量可以隨時間改變。
Day 15 的 carA 與 carB 在 NED 中固定存在。
Veins 的 node[0]、node[1] 等名稱則可能是 Runtime 動態建立的 Module,不能只靠陣列索引當成車輛的長期身分。
同一台概念車輛可能同時有多種識別方式:
| 識別方式 | 所在位置 | 用途 |
|---|---|---|
| SUMO Vehicle ID | .rou.xml 與 TraCI |
對應交通模擬中的 Vehicle |
| OMNeT++ Module Path/Index | Runtime Module Hierarchy | 找到目前的模擬 Module |
| MAC/Network Address | 網路模型 | 處理通訊定址與封包 |
| V2X Temporary ID/Certificate | 應用與安全模型 | 表達訊息來源、權限與隱私身分 |
它們可以建立映射,卻不應被當成同一個欄位。
例如 node[3] 是 OMNeT++ Runtime 名稱,不代表它的 V2X Temporary ID 必然是 3,也不代表重新執行後仍對應同一台車。
這條邊界到了 Day 21 的 Sybil Attack 會更重要:一個 Physical Node 可能宣告多個應用身分,而 SUMO Ground Truth 仍只有一台車。
車輛位置不是只用來做動畫。
在無線模型中,Position 與移動會影響:
假設兩台車以相反方向接近,只在短時間內落入可通訊範圍。
如果 Mobility Update 太粗,模擬可能從「尚未靠近」直接跳到「已經錯身」,漏掉中間的接觸窗口。
但也不能只用幾何距離決定封包一定收到。
Radio Model 還要考慮發射功率、頻率、天線、干擾、雜訊、MAC 與實際選用的 Propagation Model。
Mobility 同步成功,只證明車輛位置已經進入網路模型,不代表 IEEE 802.11p、C-V2X 或任何真實 Radio 已經被正確建模。
Veins 不只把 SUMO Position 搬到 OMNeT++。
應用 Module 也可以透過 TraCICommandInterface 與對應的 Vehicle Command Interface 改變交通模擬。
研究情境可能包含:
這讓 V2X 應用可以形成閉環:
交通狀態
→ 影響無線通訊
→ 產生應用訊息
→ 改變車輛行為
→ 再次改變交通狀態
不過,雙向能力也會讓因果關係更複雜。
如果攻擊組同時改變 Message Rate、Route 與 Traffic Demand,就很難判斷結果由哪一項造成。
正式實驗仍應從 Baseline 開始,一次只改變研究問題需要的主要變因。
Day 15 使用 OMNeT++ 6.4.0 學習 Core 概念。
但「OMNeT++ 6.4.0 可以單獨執行」不代表它已經和目前 Veins Release 完成相容性驗證。
Veins 官方目前列出的穩定版是 5.3.1,官方 Tutorial 採用的組合為:
| 元件 | Day 16 教學基準 |
|---|---|
| Veins | 5.3.1 |
| OMNeT++ | 6.1.0 |
| SUMO | 1.22.0 |
Veins Compatibility 頁也將 OMNeT++ 6.1.0 與 SUMO 1.22.0 列為可用版本。
因此今天使用獨立的相容環境,不把 Veins 直接塞進 Day 15 的 OMNeT++ 6.4.0 環境。
未來若要升級任一元件,至少要重新驗證:
veins_launchd 能否啟動選定的 SUMO研究報告也應保存完整 Version Tuple,不要只寫「使用最新版本」。
今天先使用 Veins 5.3.1 內建的官方 Example,目標是證明兩套模擬器已經接通。
我們只觀察同步與 Vehicle Node 生命週期,不把 Example 的 Application 行為當成今天的研究結果。
完整流程是:
確認相容版本
→ 單獨驗證 SUMO Scenario
→ 啟動 veins_launchd
→ 執行 OMNeT++ Example
→ 觀察動態 Vehicle Node
→ 保存啟動與同步證據
依 Veins 官方 Tutorial 準備 Veins 5.3.1、OMNeT++ 6.1.0 與 SUMO 1.22.0。
如果 Day 15 已經建立 OMNeT++ 6.4.0 環境,請保留原環境,再另外建立 Day 16 使用的相容 Workspace。
進入正確的 OMNeT++ Shell 後,先記錄版本:
opp_run -h | head -n 5
sumo --version | head -n 5
Veins 若由 Release Archive 解壓縮,記錄目錄名稱與下載頁提供的 SHA-512 Checksum。
若使用 Git Checkout,另外記錄:
git -C ~/src/veins-5.3.1 describe --tags --always
git -C ~/src/veins-5.3.1 status --short
Release Archive 不含 .git 時,不執行這兩行即可。
完成後應能確認:
OMNeT++ 6.1.0
SUMO 1.22.0
Veins 5.3.1
不要只看資料夾名稱,仍要保存實際命令輸出與下載檔驗證資訊。
在 OMNeT++ IDE 匯入 Veins Project:
File
→ Import
→ General
→ Existing Projects into Workspace
→ 選擇 veins-5.3.1
接著執行:
Project
→ Build All
Build Console 不應出現 Compiler 或 Linker Error。
如果 Build 失敗,先回頭確認目前 Shell 中的 OMNeT++ Version,不要直接忽略錯誤或任意修改 Veins Source。
在 Veins Root 執行:
cd ~/src/veins-5.3.1/examples/veins
sumo -c erlangen.sumo.cfg
正常情況會顯示 Configuration 載入完成,接著在模擬結束後回到 Shell。
這一步只證明 SUMO 能讀取 Example 的 Network、Route 與 Configuration。
它還沒有證明 OMNeT++ 與 TraCI 已經接通。
veins_launchd開啟另一個 Terminal,回到 Veins Root:
cd ~/src/veins-5.3.1
./bin/veins_launchd -vv -c "$(command -v sumo)"
正常啟動後應看到:
Listening on port 9999
保持這個 Terminal 開啟。
-vv 會保留較詳細的啟動與 Proxy Log,適合今天的整合除錯。
預設只綁定 127.0.0.1,今天不修改 Bind Address,也不開放 Firewall Port 給其他主機。
回到 OMNeT++ IDE,在 Veins Project 開啟:
examples/veins/omnetpp.ini
接著選擇:
Run As
→ OMNeT++ Simulation
使用 Default Configuration 與 Qtenv。
也可以在已完成 Build 且環境路徑正確的 Shell 中執行:
cd ~/src/veins-5.3.1/examples/veins
./run -u Qtenv -c Default
如果 Qtenv 無法連線,依序檢查:
veins_launchd 是否仍顯示 Listening on port 9999
omnetpp.ini 的 *.manager.host 是否為 localhost
*.manager.port 是否為 9999
erlangen.launchd.xml 引用的檔案是否存在sumo Command 是否指向 1.22.0veins_launchd 啟動紀錄OMNeT++ 開始執行後,veins_launchd Terminal 應出現新的 Connection,接著建立暫存目錄、尋找可用 Port 並啟動 SUMO。
觀察重點包括:
Connection from 127.0.0.1
Creating temporary directory
Starting SUMO
Connecting to SUMO
Starting proxy mode
SUMO 啟動速度不固定,veins_launchd 可能在成功前重試連線。
短暫出現一次或數次 Connection Refused,不一定表示整個實驗失敗,仍要看後面是否進入 Proxy Mode,以及 Qtenv 是否持續執行。
使用 Run 或 Step 執行模擬,再展開 Module Tree。
你應該會看見 node[0]、node[1] 等 Vehicle Node 隨 SUMO 車輛出發而建立,也會在對應 Vehicle 離開交通模擬後被移除。
選擇其中一個 Node,檢查它包含的 veinsmobility Module,並觀察 Position 或 Display 會隨同步點更新。
這一步要留下三項證據:
| 證據 | 能證明什麼 |
|---|---|
veins_launchd Connection 與 SUMO 啟動紀錄 |
OMNeT++ 端已經要求建立耦合模擬 |
| Qtenv 中動態出現的 Vehicle Node | SUMO Vehicle 已映射成 OMNeT++ Module |
| Node Position 隨時間改變 | TraCI Mobility Update 正在運作 |
只看到 SUMO GUI 裡有車,不能證明 OMNeT++ Node 已同步。
只看到 Qtenv 有固定 Module,也不能證明它們來自 SUMO Vehicle。
官方 Example 的 omnetpp.ini 包含:
*.manager.updateInterval = 1s
*.manager.host = "localhost"
*.manager.port = 9999
*.manager.autoShutdown = true
*.manager.launchConfig = xmldoc("erlangen.launchd.xml")
| 設定 | 作用 |
|---|---|
updateInterval |
指定 SUMO 與 Vehicle Mobility 的更新間隔 |
host/port |
指向 veins_launchd 的連線位置 |
autoShutdown |
模擬結束時自動結束對應 SUMO |
launchConfig |
指定要交給 veins_launchd 的場景檔案清單 |
erlangen.launchd.xml 則會列出需要複製到暫存目錄的 Network、Route、Polygon 與 SUMO Configuration。
這兩份設定的分工是:
omnetpp.ini
→ 這次 OMNeT++ Run 如何連到整合層?多久同步一次?
launchd.xml
→ 啟動 SUMO 前要準備哪些場景檔?哪一份是主 Configuration?
Day 14 已經有:
day14.net.xml
day14.rou.xml
day14.sumocfg
要讓 veins_launchd 準備這組場景,可以建立一份概念性的 day14.launchd.xml:
<?xml version="1.0"?>
<launch>
<copy file="day14.net.xml"/>
<copy file="day14.rou.xml"/>
<copy file="day14.sumocfg" type="config"/>
</launch>
接著讓 Manager 的 launchConfig 指向它:
*.manager.launchConfig = xmldoc("day14.launchd.xml")
不過,只有這兩項修改還不等於完整 V2X Scenario。
OMNeT++ 端仍要決定:
今天先把整合架構與官方 Example 跑通。
Day 17 才會建立兩台可辨識的 Vehicle Node,讓它們交換第一筆研究用 V2X Message。
| 現象 | 優先檢查 | 不要立刻下的結論 |
|---|---|---|
Connection refused 持續出現 |
veins_launchd、Host、Port 與 Bind Address |
SUMO 場景一定損壞 |
| SUMO 回報找不到檔案 | launchd.xml 的 copy 與 type="config" |
OMNeT++ Module 寫錯 |
| Qtenv 有 Network 卻沒有動態車輛 | Route 出發時間、Manager Log 與 Module Type | Radio Range 太小 |
| Vehicle Node 出現但不移動 | TraCI 同步、updateInterval 與 Mobility Module |
Application 沒有送 Beacon |
| Node 在 Qtenv 消失 | SUMO Vehicle 是否已抵達或離開 | Module 一定 Crash |
| Coupling 正常但收不到 Packet | Application、NIC、Radio 與 Channel Model | TraCI 沒有傳位置 |
這張表的重點,是先判斷問題位於交通、耦合、Mobility 還是網路模型。
把所有錯誤都歸因於 TraCI,只會讓除錯方向更混亂。
| 項目 | 本篇任務 |
|---|---|
| 主線概念 | 找出 SUMO Vehicle 建立、Mobility 更新與離開的三種事件 |
| 隔離工具 | SUMO、OMNeT++、Veins 與本機 veins_launchd |
| 輸出證據 | Version Tuple、Launch Log、Qtenv 動態 Node 與關鍵 Manager 設定 |
這一關不新增攻擊行為,也不把官方 Example 的 Application Result 當成自訂研究結論。
今天的合格成果,是能用證據回答:
安全與法律提醒: 本篇只在本機模擬環境使用 TraCI 與無線網路模型,不會對道路車輛、RSU、行動網路或公共基礎設施傳送資料。
veins_launchd應維持在受控的本機或隔離實驗網路,不要任意暴露到公開網路。
把兩套模擬器接起來後,實驗多了幾項需要保存的資產:
launchd.xml 與實際啟動 Command還要把兩種資料分開保存:
SUMO/TraCI Mobility
→ 車輛在模擬世界中的 Ground Truth
V2X Application Payload
→ 節點對外宣告的位置、速度或事件
如果惡意節點送出假位置,不應直接修改 SUMO Ground Truth 來假裝攻擊成功。
較清楚的做法,是保留 SUMO 中的真實模擬位置,再只修改對外訊息中的宣告值。
接著比較接收端看到的資料、偵測結果與交通反應,才能回答攻擊真正影響了哪一層。
veins_launchd 則協助啟動獨立 SUMO InstanceTraCIScenarioManagerLaunchd 會依 SUMO Vehicle 生命週期動態建立、更新與移除 OMNeT++ NodeupdateInterval 影響 Mobility 更新粒度與執行成本,不能只追求最小數值今天已經讓 SUMO Vehicle 變成會隨交通場景建立、移動與離開的 OMNeT++ Node。
Day 17 將在這個耦合環境中指定兩台車,建立第一筆 V2X Message Exchange,並從 Application、Packet Flow 與 Mobility 三個角度確認訊息真的由一台車傳到另一台車。
veins_launchd Documentation
omnetpp.ini
erlangen.launchd.xml