TECH ARTICLE

dSPACE VEOS:
vECU / FMU 與 Embedded Linux 的 Gateway SIC 聯合模擬

當 Classic vECU、Plant FMU 與一顆完整的 Embedded Linux 必須在同一條模擬時間軸上協同驗證時,最先浮現的問題不是效能,而是「它們之間根本沒有共同的資料通路」。本文說明 Gateway SIC 架構如何解決這個斷點,並完整交代環境需求、安裝包與授權準備,以及一步一步的手動建置流程。

在軟體定義車輛(SDV)的開發流程中,一個典型的區域控制器同時包含兩種截然不同的軟體:跑在 MCU 上的 Classic AUTOSAR 應用,以及跑在 SoC 上的 Embedded Linux 應用。dSPACE VEOS 讓這兩者都能以虛擬 ECU 的形式進入模擬——前者透過 Classic V-ECU 與 FMU,後者透過 QEMU Coupling 形成的 POSIX-Based V-ECU。

然而,把兩者放進同一個模擬應用(OSA)之後會發現一件事:它們之間沒有任何可以直接對話的通道。QEMU Coupling 對外只提供虛擬乙太網路,而由 SystemDesk 或 TargetLink 產出的 Classic V-ECU 與 Plant FMU,通常只帶 CAN 控制器與訊號層 I/O,並沒有乙太網路控制器。這個斷點必須由一個閘道元件(Gateway)補上。

本文說明其中一種在實務上最快落地的做法:以 Simulink Implementation Container(SIC) 搭配 VEOS Ethernet Blockset 建立 Gateway VPU。內容涵蓋環境與授權準備、架構設計理由,以及完整的手動操作流程。

本文適用環境

模擬主機Ubuntu 24.04 LTS + dSPACE VEOS 2026-A(Simulator Console 26.1)、veos-qemu 26.1(QEMU 9.2.3 基礎)
工程站Windows 11 + MATLAB / Simulink R2024b、dSPACE MIPS(Model Interface Package for Simulink)、VEOS Ethernet Blockset 2026-A
受測元件Classic V-ECU(.vecu)、Plant FMU(.fmu)、Embedded Linux Guest(Buildroot 或 Yocto 產出的 bzImage + rootfs)
同步模式本文以 icount 為主(不需要硬體虛擬化);idle-detect 的差異於 §4.2 說明

文中主機位址、使用者名稱與專案路徑均以角括號佔位符表示(例如 <veos-host>、<user>),請替換為您自身環境的值。除了 §4.2 標註的 KVM 權限設定之外,所有操作皆為一般使用者權限,不需要 sudo。

1. 問題定義:兩座無法互通的島

要理解為什麼需要 Gateway,必須先看清楚 VEOS 內部這三類 VPU 各自「對外的接口」是什麼。

VPU 類型 來源 對外可用的通訊介面
Plant FMU SystemDesk / TargetLink / 第三方建模工具 訊號層 I/O(ADC、數位輸入等 raw port)+ CAN 控制器
Classic V-ECU SystemDesk 匯出的 .vecu 訊號層 I/O + CAN 控制器(乙太網路需在 BSW 完整配置 Eth 堆疊後才有)
POSIX-Based V-ECU
(QEMU Coupling)
Buildroot / Yocto 產出的 Linux 映像 僅虛擬乙太網路。宣告訊號層 IOSignals 雖然會產生 Port,但 Guest 內部並不存在對應的承載硬體

把三者放在一起,斷點就非常清楚:訊號島(FMU 與 V-ECU)與乙太網路島(Linux Guest)之間,缺少一個能同時站在兩邊的元件。

訊號島 Plant FMU 訊號層 raw port:Adc1..3(UInt16)、Di1..3(Bool) CAN 控制器 ─ 與另一顆 ECU 對話 Classic V-ECU 訊號層 raw port + CAN 控制器 無乙太網路控制器 CAN Cluster 乙太網路島 POSIX-Based V-ECU(Embedded Linux) Guest Kernel + rootfs + 受測應用(SUT) eth0 = virtio-net-pci 對外唯一介面: 虛擬乙太網路(UDP / TCP) 訊號層 Port 可宣告,但 Guest 內無承載硬體 ✕ 沒有共同的通訊層 訊號 ↔ 乙太網路封包 需要轉譯者 圖 1|三類 VPU 的介面落差——這正是 Gateway 元件存在的理由

1.1 為什麼不直接在 V-ECU 上加乙太網路

理論上可以:在 SystemDesk 的系統描述中新增 EthernetCluster 與 EthernetCommunicationController,再於 BSW 配置完整的 Eth Driver → EthIf → EthSM → TcpIp → SoAd 堆疊,必要時再加上 SOME/IP 與 Service Discovery。實務上這條路的成本相當高,且有一個關鍵前提需要確認:並非所有 V-ECU 產生流程都會提供完整的 BSW 實作,部分工具鏈只提供 MCAL 層原始碼,乙太網路堆疊需由專案自行補齊。

因此,在應用層資料交換這個目標下(把 Linux 應用算出來的值送進 ECU 的輸入、把 ECU 的輸出送回 Linux),Gateway 元件是成本低得多、而且不需要改動既有 V-ECU 專案的做法。

2. Gateway SIC 架構

SIC(Simulink Implementation Container)是 dSPACE 用來把 Simulink 模型帶進 VEOS 的容器格式。它的兩個特性讓它非常適合擔任 Gateway:

  • 同時具備兩種介面: SIC 的根層 Inport / Outport 直接成為 VEOS 的訊號層 Port,可與 FMU、V-ECU 做純訊號連線;而 VEOS Ethernet Blockset 讓同一個模型內擁有真實的 UDP/TCP socket。一個元件同時站在兩座島上。
  • SIC 內裝的是原始碼,不是二進位: 目標作業系統是在模擬主機端執行 veos build sic -t 時才決定的。因此在 Windows 的 MATLAB 產生的 SIC,可以直接在 Linux 的 VEOS 上建置,不需要 Linux 版 MATLAB。

2.1 整體框架

下圖是四個 VPU 在同一個 OSA 內的完整資料路徑。請特別注意時鐘邊界那條虛線——它是這個架構唯一需要事先理解清楚的取捨。

模擬主機 · Ubuntu 24.04 LTS 單一 OSA,四個 VPU,共用 StepSize = 1 ms VEOS 模擬時間軸之內 VPU 1 · Gateway SIC Simulink 模型(由腳本生成) UDP Receive ─ 收 Guest 封包 Selector ─ 拆解位元組 → 訊號 根層 In/Outport ─ VEOS 訊號 UDP Transmit ─ 反向封包回送 Guest VPU 2 · Plant FMU Adc1..3(UInt16)、Di1..3(Bool) Do1..6(Bool,反向輸出) CAN 控制器 VPU 3 · Classic V-ECU TestPoints 群組內的訊號 Port CAN 控制器 XCP on TCP ─ 供 ControlDesk 觀測 CAN Cluster 24 條純訊號連線 VPU 4 Linux Guest veos-qemu 行程 Guest Kernel rootfs(virtio-blk) 受測應用 SUT eth0(slirp) 週期送出 UDP 封包 模擬時間軸之外 · 主機 OS Socket Guest 的 eth0 位於 QEMU slirp 使用者模式網路,Gateway SIC 的 socket 位於主機真實網路堆疊; 兩者透過 slirp 的 host= 與 hostfwd= 對接。這一跳由主機 OS 排程,不受模擬時鐘控制。 代價:封包進出 Guest 的瞬間帶有主機端的排程抖動——這是 Gateway SIC 架構唯一的時序取捨。 正向:Guest ─ UDP ─> Gateway SIC / 反向:Gateway SIC ─ UDP ─> Guest 圖 2|Gateway SIC 聯合模擬框架:四個 VPU 位於同一 OSA,Gateway 同時具備 UDP socket 與訊號層 Port FMU 與 V-ECU 之間仍走原本的 CAN Cluster,完全不需修改既有 ECU 專案

2.2 為什麼需要 slirp 這一段轉接

這是導入初期最容易卡住的一點,值得單獨說明。

Gateway SIC 內的 UDP Receive block 建立的是模擬主機作業系統上的真實 socket;而 Linux Guest 的 eth0,若接在 VEOS 的虛擬乙太網路 Cluster 上,則是 VEOS 內部的虛擬網段。兩者並不相通——SIC 永遠收不到 Guest 送出的封包。

解法是給 Guest 一張走 QEMU 使用者模式網路(slirp)的網卡,並利用 slirp 的兩個參數把兩邊接起來:

參數 語意 在本架構中的作用
net= slirp 虛擬網段 設為與 Guest 映像內靜態 IP 相同的網段,Guest 的網路設定完全不需修改
host= Guest 眼中主機的位址 設成 Guest 應用原本就要送達的對端位址,正向封包因此自動落到主機 socket 上
hostfwd= 主機埠 → Guest 埠 的轉送 把 Gateway 送出的反向封包導回 Guest。缺少它就只有單向資料流,無法量測往返延遲

最常見的設定錯誤:host= 是「Guest 眼中主機的位址」,也就是 Guest 必須送到的那個位址,不是主機自己的位址。若專案中同時存在兩顆映像且各自的對端位址相反,很容易套錯。建議在 JSON 中以 kernel command line 參數明確覆寫 Guest 的對端位址,讓設定檔自我完備,不依賴映像內建值。

2.3 與 Ethernet BSC 路線的取捨

另一條符合原廠架構的做法,是以 Ethernet Configuration Package(ETHCP)從 AUTOSAR 通訊矩陣產生 Ethernet BSC(Bus Simulation Container),讓 Guest 直接接上 VEOS 的虛擬乙太網路 Cluster——整條路徑都在模擬時鐘之內,不經過主機 socket。

兩條路線並非互斥,選擇取決於驗證目標:

面向 Gateway SIC Ethernet BSC
建置鏈 Simulink 模型 → veos build sic ARXML 通訊矩陣 → ETHCP 產碼 → Simulink 合併 → veos build bsc
額外工具需求 MATLAB + VEOS Ethernet Blockset 同左,再加 ETHCP 與一份可用的 AUTOSAR 通訊矩陣
位元組版面的描述方式 於 Simulink 內以 Selector 手動拆解 由 PDU / ISignal 定義,具矩陣可追溯性
資料路徑是否全程在模擬時鐘內 否(主機 socket 一跳在時鐘外) 是
建議適用場景 應用層資料交換、快速建立整合驗證環境 需要 byte 層級 restbus 語意與矩陣可追溯性

一個值得預先知道的觀察:把資料路徑放回模擬時鐘內,未必會反映在應用程式看得到的往返延遲上。當 Guest 應用與 Gateway 各自以固定週期取樣時,往返延遲主要由兩端週期的相位關係決定,而不是由傳輸那一跳決定。若導入 BSC 的動機是時序精度,建議先以實際組態量測後再投入。

3. 環境需求

本架構需要三個角色。工程站與模擬主機是必要的;Build Server 僅在需要自行產生 Linux 映像時才需要,若映像已由其他流程提供則可省略。

工程站 · Windows 11 MATLAB / Simulink R2024b dSPACE MIPS(DSRT 目標) VEOS Ethernet Blockset SystemDesk(產生 vECU / FMU) ControlDesk(觀測與標定) 產出:.sic / .vecu / .fmu Build Server(選用) Ubuntu 24.04 LTS Buildroot 或 Yocto 建置樹 交叉編譯工具鏈 產出:bzImage、rootfs 映像 映像已備妥時可略過此角色 模擬主機 · Ubuntu 24.04 LTS dSPACE VEOS 2026-A veos-qemu 擴充(QEMU Coupling) Real-Time Testing / ASAM XIL API CodeMeter 授權用戶端 執行 build / model / sim 全部流程 SFTP SFTP 圖 3|三個角色與產出物流向。所有 VEOS 指令都在模擬主機上執行,工程站僅負責產生容器與觀測

3.1 模擬主機

項目 需求
作業系統 Ubuntu 24.04 LTS,且使用 General Availability kernel。Desktop、Server、Cloud 版皆在支援範圍內。請留意 Desktop ISO 預設安裝的是 HWE kernel,與 GA 並不相同。
執行環境 Microsoft .NET 8(VEOS 安裝腳本的前提),以及安裝期間的 sudo 權限
CPU / 記憶體 建議 8 核以上、16 GB 以上。icount 模式為單執行緒 TCG 模擬,單核效能比核心數更關鍵
硬體虛擬化 本文的 icount 模式不需要。若要使用 idle-detect,則 CPU 需支援虛擬化、BIOS/UEFI 須啟用,且模擬主機本身若為虛擬機,還需在 hypervisor 層開啟巢狀虛擬化,使 /dev/kvm 存在
網路 可連通授權伺服器;若 ControlDesk 需自工程站連入,安裝時需啟用 VEOS 遠端存取
既有工具 Ubuntu 內建的 GCC(veos build classic-vecu 會實際編譯 V-ECU 原始碼)。jq、python3 建議具備,用於檢視 OSA 拓樸

3.2 工程站(Windows)

軟體 必要性 用途與注意事項
MATLAB / Simulink 必要 建立 Gateway 模型。版本必須與所安裝的 dSPACE 版本相容——DSRT 目標僅會註冊到受支援的 MATLAB 版本上,安裝多個版本時尤其要確認
dSPACE MIPS
Model Interface Package for Simulink
必要 提供 dsrt.tlc(SIC 產生用的 System Target File)與 dsmpblib 模型介面 blockset。需透過 dSPACE Installation Manager 與 MATLAB 建立連結
VEOS Ethernet Blockset 必要 提供 UDP Receive / Transmit / TCP Server / TCP Client 等 block,是 Gateway 具備 socket 能力的來源
MATLAB 支援的 C 編譯器 必要 產碼流程需要,可用 mex.getCompilerConfigurations 確認
dSPACE SystemDesk 視情況 產生 Classic V-ECU(.vecu)與 FMU。若容器已由其他團隊提供則不需要
dSPACE ControlDesk 建議 透過 XCP on TCP 觀測與標定 V-ECU 內部變數
SSH / SFTP 用戶端 必要 將容器與設定檔送上模擬主機。可使用 OpenSSH、WinSCP,或自行以 Python 腳本封裝

3.3 dSPACE Linux 安裝包與安裝選項

模擬主機端的 VEOS 由官方 Linux 安裝包(dspace-veos-<release>.tar.gz)安裝。安裝腳本的行為由環境變數控制,必須在執行安裝腳本之前設定。以下是與本架構直接相關的選項:

環境變數 對本架構的意義
INSTALL_VEOS_QEMU 必須保持啟用(預設值)。關閉即不安裝 QEMU Coupling 擴充,Embedded Linux 無法作為 V-ECU 加入模擬
INSTALL_VEOS_LINUX_KERNEL 安裝 idle-detect 模式使用的 dSPACE Guest Kernel。只用 icount 時可關閉,但建議保留以便日後切換
ENABLE_VEOS_REMOTE_ACCESS 允許 ControlDesk 等工具自其他主機連入 Simulator。啟用後同網段主機皆可存取,請依資安政策評估
CONFIG_LICENSE_SERVERS 指定 CodeMeter 授權伺服器位址;亦可改用廣播自動搜尋
INSTALL_CODEMETER_FULL 僅在需要 CodeMeter 圖形介面時啟用。Server 版主機不建議設定
INSTALL_NON_INTERACTIVE 非互動安裝。使用前須先以 debconf 預先接受授權條款
操作
# 解開安裝包 mkdir -p ~/veos-install && cd ~/veos-install tar -xf ~/dspace-veos-<release>.tar.gz chmod +x *.sh chmod +r packages.tar # 依需求設定安裝選項(本架構的典型組合) export ENABLE_VEOS_REMOTE_ACCESS=1 export CONFIG_LICENSE_SERVERS=<license-server> # INSTALL_VEOS_QEMU 與 INSTALL_VEOS_LINUX_KERNEL 保持預設(啟用) # 執行安裝:請勿以 sudo 執行,腳本需要提權時會自行要求 ./install-dspace-veos-<release>.sh

安裝時的兩個常見阻礙

  • 請勿以 sudo 執行安裝腳本。官方明確警告這會導致其他使用者無法啟動 VEOS Simulator。
  • 若該主機曾安裝 Microsoft 的其他產品而配置過官方套件來源,可能與 .NET 安裝產生衝突並導致 VEOS 安裝失敗,建議在安裝前先確認套件來源狀態。

3.4 授權需求

授權是導入期最常見的絆腳石,而且失敗訊息容易誤導。本架構會用到的授權可分為三組:

授權 位於 缺少時的症狀
VEOS 基礎授權 模擬主機 veos build、veos model、veos sim 全部無法執行。建置成功時 log 會出現 License was acquired
QEMU Coupling 相關模組授權 模擬主機 OSA 可以建立,但載入含 POSIX-Based V-ECU 的模擬時,QEMU 擴充啟動失敗
MATLAB 與 dSPACE 產碼授權 工程站 Simulink Coder 與 MIPS/DSRT 缺一則無法產生 .sic

請務必理解「席次(seat)」的行為

VEOS 的授權席次會被已載入的模擬持續佔用。若前一輪測試結束後未執行 veos sim down,下一次 veos build 或 veos model 會回報「已達使用者上限」的錯誤。這不是授權失效,也不是伺服器故障,只需釋放前一次的模擬即可。導入初期若把這個訊息誤判為授權問題,往往會浪費可觀的排查時間。建議把「veos sim down」固定寫進每一輪流程的第一步。

建置流程開始前,建議先確認授權可用性:

驗證
# 1. 授權伺服器是否可達(CodeMeter 預設埠 22350) timeout 4 bash -c 'cat < /dev/null > /dev/tcp/<license-server>/22350' \ && echo LICENSE_REACHABLE || echo LICENSE_UNREACHABLE # 2. 釋放可能被佔用的席次 /opt/dspace/veos<release>/bin/veos sim down < /dev/null # 3. 確認 Simulator 可正常回應 /opt/dspace/veos<release>/bin/veos sim info < /dev/null

4. 手動操作流程

以下流程假設 .vecu、.fmu 與 Guest 映像(bzImage 與 rootfs)皆已備妥。整個流程分為工程站側(步驟 1–4)與模擬主機側(步驟 5–10)。

三條貫穿全流程的規則

  • 每一個 veos model 指令都要加上 < /dev/null。Model Console 會檢查標準輸入是否帶有修改內容;由腳本或 SSH 呼叫時標準輸入不會結束,指令將一直等待直到連線逾時。
  • veos 未必在 PATH 上。非互動 SSH 工作階段不會載入環境設定腳本,建議一律使用完整路徑。
  • 每一輪開始前先 veos sim down。理由見 §3.4 的席次說明。
STEP 1 / 10

確認工程站的產碼環境

SIC 產生失敗最常見的原因,是 dSPACE 的 MATLAB 整合沒有掛上。以下兩個查詢都必須有結果,缺一則需以 dSPACE Installation Manager 重新建立 MATLAB 連結。

操作(MATLAB Command Window)
which('dsrt.tlc') % SIC 產生用的 System Target File which('dsmpblib') % dSPACE 模型介面 blockset load_system('veos_ethernet_blockset') % VEOS Ethernet Blockset mex.getCompilerConfigurations('C','Selected')
預期
ans = ...\MIPS\DSRT\TLC\dsrt.tlc ans = ...\MIPS\MIPS\dsmpblib.slx % Ethernet Blockset 可載入且不報錯
STEP 2 / 10

建立 Gateway 模型(Simulink)

Gateway 模型的職責只有三件事:接收封包、拆解成訊號、把 ECU 的輸出打包送回。建議以腳本方式建模而非手動拉線——封包版面日後幾乎一定會調整,腳本讓每次調整都可重現、可審查。

(a) 模型骨架與求解器設定

求解器必須為 fixed-step,且步長需與 VEOS 的模擬步長、以及 V-ECU 的基礎步長一致。三者不一致會造成封包被丟棄或額外抖動。

操作
mdl = 'gw_sic'; new_system(mdl); open_system(mdl); set_param(mdl, 'SolverType','Fixed-step', 'FixedStep','0.001', ... 'SystemTargetFile','dsrt.tlc');

(b) 加入 UDP 收發 block

paramRxBlockingTime 必須維持為 0。任何阻塞等待都會拖住求解器,使模擬時間無法推進。paramMaximumRxMessageSize 需依實際封包長度調大,預設值遠小於一般應用封包。

操作
PKT = 40; % 封包長度(位元組),依您的協定定義 add_block('veos_ethernet_blockset/dsa_VEOS_eth_udp_rx_BL1', [mdl '/UdpRx'], ... 'Position',[60 60 200 140]); set_param([mdl '/UdpRx'], 'paramRxPort','30490', ... 'paramMaximumRxMessageSize', num2str(PKT), ... 'paramRxBlockingTime','0'); add_block('veos_ethernet_blockset/dsa_VEOS_eth_udp_tx_BL1', [mdl '/UdpTx'], ... 'Position',[380 60 520 140]); set_param([mdl '/UdpTx'], 'paramTxPort','30491');

UDP Receive 的三個輸出依序是 Data(uint8 向量)、Message Size(uint32)與 Status(uint32)。Status 可用來判斷本步是否收到新封包,以及封包是否因超過最大長度而被截斷,建議接到根層 Outport 以便在模擬中觀測。

(c) 從位元組組出訊號

這是 Gateway 的核心。以「封包第 13、14 個位元組為一個小端序 UInt16 感測值」為例:

操作
% Simulink 的索引以 1 為基底,因此 byte 12..13 對應索引 13/14 Selector(13) -> Data Type Conversion(uint16) ─┐ Selector(14) -> Data Type Conversion(uint16) ─┴─> Gain(256, uint16) └─> Add(uint16) ─> Outport 'gw_a0'

關鍵:每一個會改變型別的 block 都要明確指定 OutDataTypeStr。若交由 Simulink 自動推導,很容易得到定點型別(例如 ufix32_En14),而 DSRT 產碼不支援定點型別,會在建置階段直接失敗。支援的型別為 Bool、Int8/16/32/64、UInt8/16/32/64、Float32/64 與 Binary。

在 Simulink 端就把型別對齊成 ECU port 的型別(例如 UInt16),可讓後續的訊號連線完全不需要型別轉換,也避免隱式轉換帶來的誤差。

(d) 根層 Inport / Outport 即 VEOS 訊號

不需要額外的 Model Port Block——根層的 Inport 與 Outport 會直接成為 VEOS 的訊號層 Port。命名建議與用途對應(例如 gw_a0..gw_a5 對應類比量、gw_d0..gw_d5 對應數位量),因為這些名稱會直接出現在後續的接線設定檔中。

(e) 反向封包與建置期斷言

若需要量測往返延遲,讓 Gateway 把收到封包中的序號與時戳原樣回拷到反向封包即可——不要拆解重組,那只會增加型別推導出錯的機會。

封包長度算錯不會產生錯誤,只會產生看似合理的資料。若反向封包的填充長度少算幾個位元組,欄位整體位移,接收端會把序號的低位元組誤讀為 ECU 輸出,並回報「所有輸出都在變動」這種極具說服力的假象。建議在建模腳本中加入建置期斷言,讓版面不一致在產碼前就中止流程。

操作
% 反向封包各欄位寬度總和必須等於宣告的封包長度 backWidth = 4 + 2 + 2 + 22 + 1 + 1 + 8; assert(backWidth == PKT, ... 'reverse packet is %d bytes, must be %d', backWidth, PKT);
STEP 3 / 10

產生 SIC 檔

產碼目標保持預設即可。不需要、也無法指定 Linux 作為目標架構——作業系統是在模擬主機端建置時才決定的。

操作
save_system(mdl); rtwbuild(mdl);
預期
*** Model : gw_sic *** Target architecture : 64-bit *** Code generation type : Model code for VEOS and ConfigurationDesk ... Note Message #01129: SIC File Generated Generated the gw_sic.sic SIC file for the gw_sic model.

產物中只有 .sic 需要送到模擬主機;其餘中間目錄(產生的 C 原始碼、makefile、Simulink 快取)可視需要保留或清除。

STEP 4 / 10

建立工作目錄並上傳素材

建議把所有專案檔案集中在使用者家目錄下的單一工作目錄,全程不需要 sudo,也便於整批清除。

操作(模擬主機)
mkdir -p ~/dsqemu/{sut,configs,osa,images,log}
操作(自工程站上傳)
scp gw_sic.sic <user>@<veos-host>:~/dsqemu/sut/ scp FrontEcu.fmu <user>@<veos-host>:~/dsqemu/sut/ scp DashboardEcu.vecu <user>@<veos-host>:~/dsqemu/sut/ scp bzImage rootfs.ext2 <user>@<veos-host>:~/dsqemu/images/

請為 rootfs 保留一份乾淨母版(例如 rootfs.ext2.golden)。Guest 以可寫模式掛載 rootfs,每執行一次都會寫入日誌、隨機種子等內容。若不在每輪測試前還原,各輪的起點並不相同,問題將難以重現。

STEP 5 / 10

建置三個容器

三個 VPU 各自先建成獨立的 OSA,之後再合併。三者的建置語意並不相同,值得留意。

操作
V=/opt/dspace/veos<release>/bin/veos cd ~/dsqemu/sut $V sim down < /dev/null # 確認可用的建置目標(Linux 上通常只有一個,星號為預設值) $V build show-targets < /dev/null # 1) Plant FMU:僅打包,FMU 內已含 Linux 平台的二進位 $V build fmu ./FrontEcu.fmu -t HostPCLinux64/GCC -o ./FrontEcu.osa # 2) Classic V-ECU:.vecu 是原始碼容器,這一步會實際呼叫 GCC 編譯 $V build classic-vecu ./DashboardEcu.vecu -t HostPCLinux64/GCC -o ./DashboardEcu.osa # 3) Gateway SIC:同樣是原始碼,作業系統在此決定 $V build sic ./gw_sic.sic -t HostPCLinux64/GCC -o ./gw_sic.osa
驗證
BUILD OF SIMULATION SYSTEM FINISHED WITH STATE VALID Saved the following simulation system: ... # 此階段出現以下兩類警告屬正常,接線完成後即消失: # At least one signal is not connected: ... # At least one bus connector has no reference to any bus channel: ...
STEP 6 / 10

撰寫 Guest 的 QEMU Coupling 設定檔

Embedded Linux 以一份 JSON 設定檔加入 OSA。以下是本架構的關鍵欄位,其中網路設定是 Gateway 能否收到封包的決定因素。

操作(~/dsqemu/configs/guest-icount.json)
{ "Type": "DsVeosQemu", "Name": "LinuxGuest-icount", "StepSize": 0.001, "MetaData": { "Author": "<author>", "Description": "Embedded Linux SUT" }, "Veos": { "SynchronizationMode": "icount", "RemotePort": 0 }, "Qemu": { "Architecture": "x86_64", "AllowOverridingDefaultQemuArgs": false, "Arguments": [ "-M pc", "-m 512", "-smp 1", "-kernel ${Resource:bzImage}", "-drive if=virtio,file=${Resource:rootfs.ext2},format=raw", "-object rng-random,filename=/dev/urandom,id=rng0", "-device virtio-rng-pci,rng=rng0", "-netdev user,id=n0,net=192.168.60.0/24,host=192.168.60.20,hostfwd=udp:127.0.0.1:30491-192.168.60.10:30490", "-device virtio-net-pci,netdev=n0,mac=<unique-mac>", "-append", "root=/dev/vda rootwait rw console=ttyS0 tsc=reliable no_timer_check panic=-1" ], "RedirectStdout": "both", "RedirectStderr": "both" }, "Resources": [ "/home/<user>/dsqemu/images/bzImage", "/home/<user>/dsqemu/images/rootfs.ext2" ] }
欄位 為什麼必須這樣寫
virtio-net-pci 網卡型號必須是 virtio。若日後切換到 idle-detect,Guest Kernel 會被替換為 dSPACE 提供的版本,該 Kernel 並不包含常見的 e1000 系列驅動,使用其他型號會導致 Guest 看不到網卡
virtio-rng-pci 提供熵源。缺少時,部分開機腳本會停在等待亂數初始化的階段,且症狀不易辨識
host= / hostfwd= §2.2 已說明。host= 設成 Guest 應用原本的對端位址;hostfwd= 將反向封包導回 Guest
console=ttyS0 VEOS 會以無圖形模式啟動 QEMU,Guest console 只應輸出到序列埠,log 才會被完整擷取
MAC 位址 務必逐一指定且不重複。多個 Guest 使用相同預設值會造成難以診斷的通訊異常
StepSize 與 Gateway 模型的固定步長、V-ECU 的基礎步長、以及 veos sim config -e 三者一致
STEP 7 / 10

合併成單一 OSA

四個 VPU 依序匯入同一個 OSA。匯入順序具有意義:第一個匯入的容器會成為 OSA 的主要模擬應用,其名稱會決定模擬描述檔(.sdf)的檔名,而部分測量介面(例如 ASAM XIL 的 MAPort)是依該檔案定位的。建議固定讓 Gateway SIC 第一個匯入。

操作
V=/opt/dspace/veos<release>/bin/veos cd ~/dsqemu rm -f ./osa/combo.osa # -n 只加在第一個(建立新的 OSA) $V model import -n ./osa/combo.osa -p ./sut/gw_sic.osa -o ./osa/combo.osa < /dev/null $V model import ./osa/combo.osa -p ./sut/FrontEcu.osa -o ./osa/combo.osa < /dev/null $V model import ./osa/combo.osa -p ./sut/DashboardEcu.osa -o ./osa/combo.osa < /dev/null $V model import ./osa/combo.osa -p ./configs/guest-icount.json -o ./osa/combo.osa < /dev/null
驗證
$V model get ./osa/combo.osa < /dev/null | jq -r '.Vpus[].Name' # 應列出四個 VPU:gw_sic / FrontEcu / DashboardEcu / LinuxGuest-icount
STEP 8 / 10

建立匯流排與訊號連線

這一步分兩部分:FMU 與 V-ECU 之間的 CAN,以及 Gateway 與兩者之間的純訊號連線。

(a) CAN Cluster

FMU 與 .vecu 匯入時不會自動建立 Cluster(只有 QEMU Coupling 的 JSON 帶有 Cluster 名稱欄位時才會自動建立),因此需手動加入後再自動接線。

操作
cat > ./sut/can.json <<'EOF' { "BusClusters": [ { "Name": "CanCluster", "Protocol": "Can", "Channels": [ { "Name": "Ch1", "Protocol": "Can" } ] } ] } EOF $V model add ./osa/combo.osa -c ./sut/can.json -o ./osa/combo.osa < /dev/null $V model connect ./osa/combo.osa --autoconnect-communication-controllers \ -o ./osa/combo.osa < /dev/null

成員名稱是 Channels,不是 BusChannels。寫錯會得到「找不到指定成員」的錯誤訊息。

(b) Gateway 與 ECU 之間的純訊號連線

以一份連線描述檔逐條指定來源與目的訊號。訊號路徑必須包含完整的 Port Group 階層,可先以 veos model get 匯出 OSA 結構確認實際路徑。

操作
cat > ./sut/sigconn.json <<'EOF' { "CommunicationPackages": [ { "Name": "GatewaySignals", "PackageType": "UserCommunicationPackage", "Protocol": "NonBlockingCommunication", "SignalConnections": [ { "OutSignalReference": "/gw_sic/gw_a0/gw_a0", "InSignalReference": "/FrontEcu/Rp_In_FrontEcu_RpAdcIn_Adc1_input/Rp_In_FrontEcu_RpAdcIn_Adc1_input" }, { "OutSignalReference": "/gw_sic/gw_a3/gw_a3", "InSignalReference": "/DashboardEcu/TestPoints/Rp_In_DashboardEcu_RpAdcIn_Adc1_input/Rp_In_DashboardEcu_RpAdcIn_Adc1_input" } ] } ] } EOF $V model connect ./osa/combo.osa -c ./sut/sigconn.json -o ./osa/combo.osa < /dev/null

這一步有兩個「不會報錯」的陷阱

  • 必須使用 connect 動詞,而不是 add。以 add 提交同一份檔案只會建立通訊套件,其中的訊號連線會被靜默忽略。
  • 不要以 --autoconnect-signals 取代明確接線。它依名稱配對,而 Gateway 的訊號名稱與 ECU port 名稱通常不同——結果是什麼都不會接上,模擬照樣正常載入。
驗證
# 已接線的訊號,其 not-connected 警告應消失 # 亦可直接檢視 OSA 內的連線清單: $V model get ./osa/combo.osa < /dev/null | jq '.CommunicationPackages'
STEP 9 / 10

執行模擬

執行前先清場並設定記錄選項。模擬步長需與模型設定一致。

操作
$V sim down < /dev/null $V sim config --enable-sim-log --enable-bus-log -e 0.001 < /dev/null $V sim load ./osa/combo.osa < /dev/null $V sim start 120s < /dev/null # 等待模擬結束後查看狀態 $V sim info < /dev/null | grep -iE 'state|simulationtime|elapsed'
預期
State: Paused SimulationTime: 120 ElapsedTime: 121.0 # 模擬時間 / 實際時間 ≈ 0.99

加速比是第一個健康指標。在 icount 模式下接近 1.0 表示模擬速度與實時相當;明顯低於 0.9 通常代表 Guest 端有忙迴圈、或主機資源不足。

STEP 10 / 10

驗收:確認資料真的流動

「模擬跑完了」不等於「資料通了」。建議以下列三個層次逐一確認,每一層都能獨立指出問題所在。

層次一:Guest 端的收發計數

操作
$V sim show-log < /dev/null # 列出所有 log $V sim show-log LinuxGuest-icount.qemu.stdout.log < /dev/null | tail -20

受測應用應能自行輸出送出與接收的封包計數。關鍵判準是「接收數不等於送出數」——若兩者恆等,通常代表 Guest 收到的是自己送出的封包(例如 host= 指向了 Guest 自己的位址),而非來自 Gateway 的回覆。這種情況下所有計數看起來都正常,是最容易被誤判為成功的失敗樣態。

層次二:匯流排記錄

以 --enable-bus-log 產生的記錄可匯出為 pcapng 格式,用一般網路分析工具檢視 FMU 與 V-ECU 之間的 CAN 通訊是否具有動態內容。

操作
$V sim show-log FrontEcu.BusTransfer.pcapng < /dev/null > /tmp/can.pcapng

層次三:ECU 內部變數

最終判準是值真的進到 ECU 內部。可透過 ControlDesk(XCP on TCP)或 ASAM XIL API 讀取對應變數,確認其隨 Guest 送出的資料變動。

建議在 Guest 端安排「一眼可判」的波形。例如讓其中一路訊號輸出恰好 8 階的階梯波、另一路輸出恆定值作為對照組。如此一來,只要讀到的相異值個數不是 8、或對照組出現變動,就能立刻判定發生了通道錯位,而不需要逐條比對數值。這個技巧能把「接線接錯但看起來有資料」這類問題的排查時間,從數小時縮短到數秒。

5. 疑難排解

症狀 原因 處理方式
veos model 指令永不返回 Model Console 等待標準輸入的修改內容 一律加上 < /dev/null
產碼失敗,指出不支援的資料型別 Simulink 自動推導出定點型別 為每個改變型別的 block 明確設定 OutDataTypeStr
which('dsrt.tlc') 無結果 MIPS 未與該 MATLAB 版本建立連結 以 dSPACE Installation Manager 重新連結,並確認 MATLAB 版本在支援清單內
授權錯誤:已達使用者上限 席次被前一次 sim load 佔用 先執行 veos sim down,再重試
授權錯誤:找不到授權伺服器 網路或伺服器不可達 先驗證埠 22350 的連通性;連通則回頭檢查是否為席次問題
Gateway 完全收不到封包 Guest 的網路介面接在 VEOS 虛擬 Cluster,與主機 socket 不相通 改用 slirp 網卡並正確設定 net= 與 host=(§2.2)
正向資料正常,反向完全消失 缺少 hostfwd=,或轉送目的位址與 Guest 實際位址不符 核對 hostfwd= 的目的位址是否等於 Guest 映像內的靜態 IP
接收數恆等於送出數,但資料不合理 Guest 收到的是自己送出的封包 確認 host= 不等於 Guest 自身位址
訊號全部保持初始值 誤用 --autoconnect-signals,實際未建立任何連線 改用明確的連線描述檔,並以 veos model get 確認
模擬速度極慢 Guest 內有忙迴圈,或 UDP block 設定了阻塞等待 確認 paramRxBlockingTime 為 0;必要時以剖析工具定位 Guest 內的忙迴圈
重建映像後行為未改變 OSA 在匯入時已內嵌 rootfs 更新映像後必須重建 OSA,此情況不會產生任何警告

6. 導入建議

01

先讓單一元件跑起來

依序驗證:Guest 能否獨立開機 → SIC 能否獨立建置執行 → 兩者能否交換封包。三個環節分開確認,遠比一次整合後再回頭排查有效率。

02

把建模流程腳本化

Gateway 模型會隨封包版面持續演進。以腳本建模並加入建置期斷言,可讓版面錯誤在產碼前就被攔下,而不是在數據裡以假象呈現。

03

先訂判準,再看數據

在量測之前先訂好通過條件,並刻意安排可一眼判別錯位的訊號。這能有效避免「看起來合理但其實錯位」的結果被當成成功。

Gateway SIC 的價值在於它不要求既有 V-ECU 專案做任何修改,就能把 Embedded Linux 應用納入既有的 vECU / FMU 模擬環境。對多數以應用層資料交換為目標的整合驗證而言,這是投入產出比最高的起點;當專案後續需要 byte 層級的 restbus 語意與通訊矩陣可追溯性時,再評估導入 Ethernet BSC,兩者可在同一套模擬環境中並存。

關於本文

本文內容整理自 Jotactic 捷策動能於 dSPACE VEOS 2026-A 環境所進行的實作驗證,涵蓋 Classic V-ECU、Plant FMU 與 Embedded Linux(Buildroot / Yocto)在同一模擬應用中的整合流程。文中的指令、參數與驗證方式皆以實際環境為依據;不同版本的 dSPACE 產品在路徑與選項上可能略有差異,實際導入時請以您所使用版本的原廠文件為準。

若您正在評估將 SDV 架構下的 MCU 與 SoC 軟體納入同一套虛擬驗證環境,歡迎與我們聯繫,我們可協助進行環境評估、工具鏈導入與整合驗證流程建置。