子 PLC 的穩(wěn)定落地:從仿真到現(xiàn)場(chǎng)的高效轉(zhuǎn)化)
搞控制的人最舒服的狀態(tài)是什么模型在 Simulink 里建好仿真曲線跑通然后一鍵把代碼生成到 PLC 里現(xiàn)場(chǎng)設(shè)備的實(shí)際數(shù)據(jù)和仿真幾乎重合。但真實(shí)情況往往是模型只能留在電腦里算法要靠手工翻譯成 SCL 或者結(jié)構(gòu)化文本翻譯完了還得處理數(shù)據(jù)類(lèi)型、時(shí)序、初始化一堆問(wèn)題調(diào)試到天亮都未必對(duì)得上。近兩年我在幾個(gè)部署項(xiàng)目里反復(fù)做 Simulink 轉(zhuǎn)博圖TIA Portal的工作踩了不少坑也慢慢摸出了一套能穩(wěn)定落地的流程。這篇就把最重要的核心要點(diǎn)梳理一遍適合手頭已經(jīng)有 Simulink 模型、準(zhǔn)備部署到 S7 系列 PLC 的人也適合第一次接這種任務(wù)、連從哪下手都不知道的新手。我不去講那些細(xì)枝末節(jié)只聊能直接拿來(lái)用的東西模型側(cè)要做什么、代碼生成怎么配、博圖里怎么導(dǎo)、現(xiàn)場(chǎng)運(yùn)行怎么調(diào)。1. 整體思路與方案取舍先分清要不要自動(dòng)生成1.1 這個(gè)事到底是什么Simulink 轉(zhuǎn) PLC本質(zhì)上解決一件事把在 MATLAB 環(huán)境里建模、仿真、驗(yàn)證過(guò)的控制算法變成可以在 PLC 上周期執(zhí)行的代碼。PLC 的執(zhí)行模型和 Simulink 完全不一樣。Simulink 里時(shí)間可以自由推進(jìn)有連續(xù)求解器、變步長(zhǎng)、事件觸發(fā)而 PLC 只有一個(gè)固定的循環(huán)節(jié)拍物理上只能每隔一定時(shí)間掃描一次程序在這個(gè)節(jié)拍內(nèi)把所有任務(wù)執(zhí)行完。所以“轉(zhuǎn)換”這個(gè)動(dòng)作不只是語(yǔ)法翻譯而是把一種以“模塊圖 時(shí)間連續(xù)”為核心的計(jì)算方式映射到“周期掃描 函數(shù)調(diào)用”的工業(yè)執(zhí)行環(huán)境里。這個(gè)過(guò)程繞不開(kāi)的中間層是代碼生成器。Simulink PLC Coder 是官方提供的工具能生成結(jié)構(gòu)化文本ST/SCL代碼也可以生成 C 代碼。博圖TIA Portal這邊對(duì) ST 代碼的支持靠的就是 SCL 語(yǔ)言TIA Portal 可以直接導(dǎo)入外部源文件把 ST 代碼編譯成可執(zhí)行對(duì)象。整條鏈路就是Simulink 模型 → PLC Coder 生成 ST 代碼 → TIA Portal 導(dǎo)入 → 外層封裝成功能塊 → 由 PLC 周期調(diào)用。注意這里談的“適配博圖”指的就是 SCL 這一環(huán)的兼容性而不是說(shuō) PLC 里能直接跑 Simulink 的二進(jìn)制模型這種概念上的區(qū)分很多人一開(kāi)始沒(méi)意識(shí)到后面就會(huì)瞎折騰。還有一點(diǎn)值得先說(shuō)清楚為什么不是直接轉(zhuǎn)成梯形圖梯形圖擅長(zhǎng)開(kāi)關(guān)邏輯、互鎖、電氣回路但你讓它去表達(dá)一個(gè)卡爾曼濾波的狀態(tài)更新方程寫(xiě)出來(lái)會(huì)非常痛苦而且可讀性極差。SCL 是文本語(yǔ)言能寫(xiě)復(fù)雜的數(shù)學(xué)表達(dá)式、數(shù)組運(yùn)算、循環(huán)本質(zhì)上接近通用編程語(yǔ)言。這也是為什么自動(dòng)生成路徑幾乎都會(huì)選 ST/SCL 作為輸出語(yǔ)言而不是梯形圖。認(rèn)清這一點(diǎn)你才不會(huì)在工具配置里找半天“梯形圖生成選項(xiàng)”。1.2 自動(dòng)生成和手寫(xiě)移植怎么選這是最應(yīng)該想清楚的問(wèn)題也是最容易被忽略的問(wèn)題。很多人一上來(lái)就想著把整個(gè)模型全部生成到 PLC結(jié)果生成的代碼量巨大、運(yùn)行周期撐不住最后又退回手寫(xiě)。我個(gè)人的判斷標(biāo)準(zhǔn)很簡(jiǎn)單。如果算法涉及大量矩陣運(yùn)算、狀態(tài)空間求解、觀測(cè)器、濾波器、預(yù)測(cè)控制這類(lèi)數(shù)值密集型計(jì)算自動(dòng)生成幾乎是最好的選擇。因?yàn)槭謱?xiě)這類(lèi)數(shù)學(xué)邏輯非常容易出錯(cuò)而且很難保證和仿真結(jié)果一致。Simulink 模型本身就是經(jīng)過(guò)驗(yàn)證的算法描述自動(dòng)生成相當(dāng)于把這份描述直接翻譯成目標(biāo)代碼一致性遠(yuǎn)高于人工轉(zhuǎn)譯。如果控制邏輯就是簡(jiǎn)單的開(kāi)關(guān)邏輯、順序控制、布爾判斷那自動(dòng)生成不僅不劃算還會(huì)因?yàn)樯傻拇a結(jié)構(gòu)復(fù)雜而拖慢掃描周期。比如一個(gè)電機(jī)起保停電路手寫(xiě) SCL 十行以?xún)?nèi)生成出來(lái)可能幾百行完全沒(méi)必要。而且生成的代碼內(nèi)部包含了大量臨時(shí)變量和輔助函數(shù)資源占用高純邏輯控制場(chǎng)景根本吃不消。還有一個(gè)折中方案我在這幾個(gè)項(xiàng)目里用得最多把模型里最核心的算法部分做自動(dòng)生成外圍的 IO 處理、使能邏輯、故障診斷仍然手寫(xiě)。這樣做的好處是復(fù)雜計(jì)算交給可靠的生成器外圍邏輯保持人的靈活控制既保證核心算法不出錯(cuò)也把代碼規(guī)模控制在合理范圍。選自動(dòng)生成之前要做一次可行性審查模型是否離散化、采樣時(shí)間是否合理、數(shù)據(jù)類(lèi)型是否已收斂、生成代碼有沒(méi)有用到 PLC 不支持的動(dòng)態(tài)內(nèi)存、指針、遞歸調(diào)用。這些檢查最好在動(dòng)手前完成否則配置做到一半才發(fā)現(xiàn)模型根本不適合生成前面功夫全白費(fèi)。2. 模型側(cè)準(zhǔn)備與代碼生成配置決定成敗的第一步2.1 模型離散化與采樣時(shí)間的設(shè)定PLC 是周期執(zhí)行模型必須工作在離散狀態(tài)。這一點(diǎn)怎么強(qiáng)調(diào)都不過(guò)分。如果在模型里用了連續(xù)積分環(huán)節(jié)或者連續(xù)求解器生成的代碼即便編譯通過(guò)運(yùn)行起來(lái)也會(huì)因?yàn)槿鄙僬鎸?shí)積分環(huán)境而出現(xiàn)各種怪異現(xiàn)象。比如明明是個(gè)穩(wěn)定的閉環(huán)一到 PLC 里就震蕩或者某個(gè)狀態(tài)變量不斷累積漂移幾分鐘后直接飽和。所以第一步就是檢查模型里的所有積分環(huán)節(jié)全部改成離散版本。常用的做法是用零階保持器離散化或者在 Simulink 里把求解器設(shè)置為固定步長(zhǎng)離散求解器先仿真確認(rèn)行為不偏差太大再進(jìn)入代碼生成流程。采樣時(shí)間的設(shè)定是另一個(gè)關(guān)鍵。理論上采樣時(shí)間要滿(mǎn)足控制帶寬的需求至少比被控對(duì)象中最高頻的動(dòng)態(tài)過(guò)程快 5 到 10 倍。比如你的對(duì)象動(dòng)態(tài)響應(yīng)最快是 100ms 級(jí)別采樣步長(zhǎng)保守起見(jiàn)就取 10ms 到 20ms。PLC 側(cè)還要考慮掃描周期。如果 PLC 的循環(huán)中斷周期是 10ms模型采樣周期最好不要設(shè)成 25ms 這種非整數(shù)倍關(guān)系否則會(huì)產(chǎn)生相位抖動(dòng)。工程上常見(jiàn)做法是采樣步長(zhǎng)取 PLC 掃描周期的整數(shù)倍比如 1 倍、2 倍、5 倍這樣每次調(diào)用時(shí)機(jī)都是確定的不會(huì)累積偏移。還有一個(gè)細(xì)節(jié)固定步長(zhǎng)求解器的類(lèi)型選擇。離散模型最穩(wěn)妥的是選“單任務(wù)離散”SingleTasking模式或者把求解器類(lèi)型直接選為離散。如果在配置里還保留連續(xù)求解器代碼生成時(shí)會(huì)自動(dòng)插入一些連續(xù)求解器的支持代碼這些代碼在 PLC 里根本用不上只會(huì)白白增加體積和計(jì)算開(kāi)銷(xiāo)。我見(jiàn)過(guò)有人生成的代碼里帶了完整的 ODE 求解器輔助函數(shù)原因就是模型里殘留了連續(xù)模塊。2.2 PLC 代碼生成的幾項(xiàng)關(guān)鍵配置配置這一步不同人用的工具版本不一樣界面可能略有差異但邏輯基本一致。我一般會(huì)走這么幾個(gè)步驟。第一步在模型的 Configuration Parameters 里選擇 PLC Coder 作為代碼生成目標(biāo)目標(biāo)平臺(tái)選擇和你實(shí)際部署的 PLC 類(lèi)型匹配這里就是選 S7 系列相關(guān)支持。第二步語(yǔ)言選擇結(jié)構(gòu)化文本 ST。這里要確認(rèn)一下生成模式有些版本會(huì)默認(rèn)生成 C 代碼而不是 ST需要手動(dòng)切過(guò)去。切過(guò)去以后代碼生成報(bào)告里的輸出文件后綴就會(huì)變成 .scl 或 .st。第三步函數(shù)封裝方式。通常選生成一個(gè) step 函數(shù)和一個(gè) initialize 函數(shù)。推薦關(guān)閉“生成單獨(dú)文件”的選項(xiàng)讓代碼整體打包方便導(dǎo)入 TIA Portal。因?yàn)槿绻鸪啥鄠€(gè)小文件導(dǎo)入博圖時(shí)要逐個(gè)處理文件之間如果有相互引用編譯順序稍不對(duì)就報(bào)錯(cuò)。第四步代碼優(yōu)化級(jí)別。優(yōu)化要打開(kāi)可以減少代碼體積和局部變量但不要開(kāi)到最高級(jí)。最高級(jí)可能會(huì)改變某些內(nèi)部計(jì)算的順序在數(shù)值敏感算法里會(huì)產(chǎn)生微小偏差比如一個(gè)矩陣連乘展開(kāi)以后浮點(diǎn)累加順序變了結(jié)果就差幾個(gè)單位。對(duì)控制算法來(lái)說(shuō)這種差隨迭代會(huì)累積非常不好排查。第五步注釋和文檔選項(xiàng)。生成的代碼里默認(rèn)帶一堆注釋不影響執(zhí)行但導(dǎo)入博圖后代碼體積會(huì)明顯變大。建議把注釋量降到最低尤其是那些“Generated by Simulink”之類(lèi)的頭部注釋。真正運(yùn)行的時(shí)候沒(méi)人看這些PLc 內(nèi)存才是硬約束。2.3 數(shù)據(jù)類(lèi)型和接口的預(yù)處理代碼生成之前模型里所有和外部交互的信號(hào)都應(yīng)該明確數(shù)據(jù)類(lèi)型和維度。我見(jiàn)到最多的問(wèn)題就是 double 類(lèi)型。Simulink 里默認(rèn)數(shù)據(jù)類(lèi)型是 double也就是雙精度浮點(diǎn)64 位。S7 系列 PLC 里的浮點(diǎn)數(shù)是 REAL單精度32 位。這個(gè)映射關(guān)一旦處理不好仿真結(jié)果和現(xiàn)場(chǎng)數(shù)值對(duì)不上是必然的不是差一點(diǎn)而是能差出一個(gè)數(shù)量級(jí)。我的做法是建模階段就把關(guān)鍵信號(hào)的數(shù)據(jù)類(lèi)型顯式設(shè)置成 single然后在仿真時(shí)也用 single 跑。這樣仿真時(shí)看到的精度表現(xiàn)就是將來(lái) PLC 里實(shí)際運(yùn)行的精度表現(xiàn)沒(méi)有任何意外。Code Generation 本身的自動(dòng)映射也有但我從來(lái)只把它當(dāng)作兜底而不是依賴(lài)。還有一個(gè)容易被忽略的地方是模擬量輸入輸出的范圍。Simulink 里你隨便定義一個(gè) 0 到 100 的百分比信號(hào)PLC 側(cè)對(duì)應(yīng)的可能是 0 到 27648 的整數(shù)編碼。這類(lèi)縮放關(guān)系必須在模型側(cè)用 Gain 模塊提前處理而不是部署到 PLC 以后再手動(dòng)換算。為什么堅(jiān)持在模型側(cè)處理因?yàn)槟P蛡?cè)處理完之后仿真結(jié)果和現(xiàn)場(chǎng)實(shí)際值可以直接對(duì)得上排查問(wèn)題少繞一大圈。如果你讓 PLC 側(cè)做線性轉(zhuǎn)換仿真輸出和現(xiàn)場(chǎng)實(shí)際之間永遠(yuǎn)隔著一層換算每次調(diào)試都要同時(shí)看兩邊效率極低。3. 工具鏈與目標(biāo)平臺(tái)適配搞清楚你手上的“博圖”是什么3.1 博圖版本與 SCL 支持差異同一個(gè)“博圖”名稱(chēng)下面不同版本的 SCL 編譯能力差別不小。較新版本對(duì)復(fù)雜數(shù)組、結(jié)構(gòu)體、字符串處理的支持明顯更好編譯速度和診斷信息也完善得多。早期版本有時(shí)會(huì)出現(xiàn)對(duì)某個(gè) ST 語(yǔ)法報(bào)“不支持的表達(dá)式”但同樣一段代碼換到新版上就能正常編譯。所以做這類(lèi)項(xiàng)目我強(qiáng)烈建議先把博圖版本確認(rèn)清楚再?zèng)Q定模型里怎么組織代碼。如果手頭的博圖版本比較舊那模型側(cè)就要盡量避免生成過(guò)于前沿的語(yǔ)法結(jié)構(gòu)比如避免在內(nèi)部代碼里使用復(fù)雜的嵌套 FOR 循環(huán)或動(dòng)態(tài)數(shù)組訪問(wèn)。這里有個(gè)教訓(xùn)有一次我把目標(biāo)平臺(tái)配置成了某個(gè)比較新的 PLC 型號(hào)生成的 ST 代碼里嵌了一段針對(duì)長(zhǎng)數(shù)組的初始化指令。導(dǎo)入到現(xiàn)場(chǎng)那臺(tái)版本偏舊的 TIA Portal 里編譯直接掛掉。后來(lái)只能回到 Simulink 里把數(shù)組拆成標(biāo)量接口重新生成一遍才勉強(qiáng)通過(guò)。所以版本適配不是到了博圖側(cè)才想的模型生成配置階段就要把現(xiàn)場(chǎng)環(huán)境一起考慮進(jìn)去。3.2 S7-1200 與 S7-1500 的資源邊界S7 系列里最常見(jiàn)的是 1200 和 1500 兩個(gè)子系列它們的資源邊界差異很大。S7-1500 的浮點(diǎn)運(yùn)算能力強(qiáng)內(nèi)存也大適合跑帶有大量矩陣運(yùn)算或狀態(tài)觀測(cè)器的模型。S7-1200 是小中型 PLCCPU 主頻有限內(nèi)存也小跑比較大的生成代碼會(huì)非常吃力。我有一個(gè)測(cè)算習(xí)慣先把生成的 ST 代碼行數(shù)拿到再估算里面需要多少字節(jié)的靜態(tài)變量區(qū)。一般來(lái)說(shuō)超過(guò)幾千行帶浮點(diǎn)運(yùn)算的代碼就不太建議往 S7-1200 里塞了硬塞進(jìn)去要么掃描周期暴漲要么編譯時(shí)報(bào)內(nèi)存不足。如果項(xiàng)目還沒(méi)定 PLC 型號(hào)我的建議是只要模型里有超過(guò)幾十個(gè)狀態(tài)變量的算法優(yōu)先選 1500 系列留足余量。不要為了省幾百塊硬件成本讓后面的算法優(yōu)化和代碼瘦身占用大量調(diào)試時(shí)間。硬件選型省下來(lái)的錢(qián)遠(yuǎn)遠(yuǎn)不夠覆蓋現(xiàn)場(chǎng)調(diào)試的人工成本。3.3 ST 代碼與 C 代碼的選擇除了 ST 代碼PLC Coder 也能生成 C 代碼。很多人會(huì)在這一步糾結(jié)。我直接給結(jié)論在 S7 系列 PLC 上標(biāo)準(zhǔn)路徑就是 ST/SCL不用考慮 C 代碼。原因很簡(jiǎn)單常規(guī) S7 CPU 沒(méi)有開(kāi)放 C 運(yùn)行時(shí)環(huán)境C 代碼不能直接作為 PLC 程序運(yùn)行除非設(shè)備本身是帶操作系統(tǒng)的工業(yè) PC 或者軟 PLC 方案那就不是傳統(tǒng)意義上的博圖項(xiàng)目了。ST 代碼則是 TIA Portal 原生支持的語(yǔ)言之一導(dǎo)入、編譯、下載都是順暢的。所以路徑選擇其實(shí)是平臺(tái)決定的而不是個(gè)人偏好。如果你確認(rèn)將來(lái)要部署到基于 PC 的軟 PLC 或帶實(shí)時(shí)系統(tǒng)的控制器上再考慮 C 代碼的路徑也不遲。但在普通的 S7 項(xiàng)目里談 C 代碼只會(huì)繞遠(yuǎn)路。工具鏈的適配就到此為止明白這些邊界之后再進(jìn)博圖做集成會(huì)順很多。4. 博圖適配與集成落地代碼只是開(kāi)始4.1 生成的代碼長(zhǎng)什么樣用 PLC Coder 生成的 ST 代碼結(jié)構(gòu)上一般包含兩個(gè)核心函數(shù)一個(gè)是初始化函數(shù)負(fù)責(zé)把內(nèi)部狀態(tài)變量設(shè)置成初始值另一個(gè)是 step 函數(shù)也就是周期執(zhí)行的主計(jì)算函數(shù)。step 函數(shù)的輸入?yún)?shù)對(duì)應(yīng)模型中的輸入端輸出參數(shù)對(duì)應(yīng)模型中的輸出端。函數(shù)內(nèi)部通常會(huì)有很多臨時(shí)變量代碼結(jié)構(gòu)看起來(lái)像一個(gè)比較大的 SCL 程序塊。下面是個(gè)簡(jiǎn)化的結(jié)構(gòu)示意// 示意結(jié)構(gòu)實(shí)際代碼會(huì)比這個(gè)多很多 FUNCTION_BLOCK FB_ModelWrapper VAR_INPUT u : REAL; // 模型輸入 END_VAR VAR_OUTPUT y : REAL; // 模型輸出 END_VAR VAR x : ARRAY[0..9] OF REAL; // 模型內(nèi)部狀態(tài) tmp : REAL; // 臨時(shí)變量 END_VAR BEGIN // --- 這里粘貼 Step 生成代碼 --- // y : ...; // tmp : ...; // 狀態(tài)更新邏輯 END_FUNCTION_BLOCK在 TIA Portal 里你不會(huì)直接把這段代碼當(dāng)成主程序運(yùn)行而是先建一個(gè) FB功能塊在 FB 的聲明區(qū)里定義好輸入、輸出和靜態(tài)變量然后把生成的 step 函數(shù)代碼整體復(fù)制到 FB 的代碼區(qū)。這個(gè) FB 就是模型的外殼上層 OB 只需要周期調(diào)用這個(gè) FB 就行。初始化函數(shù)可以在 FB 的初始化部分調(diào)用一次或者用 FB 靜態(tài)變量的默認(rèn)值來(lái)實(shí)現(xiàn)。這樣外層結(jié)構(gòu)非常清晰輸入輸出全部暴露在 FB 的接口上想監(jiān)控哪個(gè)變量都方便查問(wèn)題的時(shí)候不用去翻一大堆內(nèi)部局部變量。4.2 TIA Portal 導(dǎo)入與外層功能塊封裝在博圖里導(dǎo)入 ST 代碼有兩條路。第一條是用“外部源文件”功能在項(xiàng)目樹(shù)里右鍵添加新源文件選 .scl 后綴把生成的代碼貼進(jìn)去編譯完成后可以生成一個(gè)功能塊。這個(gè)方式適合代碼量大、結(jié)構(gòu)完整的工程。第二條是手動(dòng)處理新建一個(gè) FB把變量聲明區(qū)先按代碼里的輸入輸出補(bǔ)齊再把代碼粘貼到實(shí)現(xiàn)區(qū)然后編譯。如果代碼規(guī)模不大我更喜歡第二種因?yàn)樽兞柯暶骱妥⑨尪颊莆赵谧约菏掷锱挪閱?wèn)題順手。無(wú)論走哪條路有三件事必須注意。變量命名沖突是高頻問(wèn)題。生成的代碼內(nèi)部變量名可能帶有特殊前綴博圖不保證完全兼容遇到報(bào)錯(cuò)就改變量名但建議在生成前就在 Simulink 側(cè)做一個(gè)全局命名前綴設(shè)置統(tǒng)一加個(gè)短前綴比如 mdl_能避免大多數(shù)沖突。數(shù)組下標(biāo)習(xí)慣也要統(tǒng)一。博圖數(shù)組可以自定義上下界我一般統(tǒng)一用 LOWER_BOUND 0 來(lái)對(duì)齊 C/ST 習(xí)慣這樣從代碼里復(fù)制過(guò)來(lái)的數(shù)組訪問(wèn)邏輯不用改。如果 Simulink 側(cè)的數(shù)組默認(rèn)是 1 基索引生成的代碼里可能會(huì)差一個(gè)下標(biāo)這種錯(cuò)誤編譯能通過(guò)但運(yùn)行結(jié)果完全不對(duì)非常隱蔽。FB 的調(diào)用方式同樣要注意。封裝好的 FB 不能直接往 OB1 里一放就完事還要確定調(diào)用位置。建議單獨(dú)建一個(gè)技術(shù)功能塊專(zhuān)門(mén)負(fù)責(zé)周期調(diào)用便于運(yùn)行監(jiān)控。直接把算法 FB 散落在 OB1 的各個(gè)角落后面想測(cè)量這段代碼的執(zhí)行時(shí)間都很難操作。4.3 輪詢(xún)調(diào)用與周期設(shè)計(jì)PLC 運(yùn)行模型算法絕對(duì)不能直接掛在 OB1 上。OB1 的掃描周期和程序復(fù)雜度強(qiáng)相關(guān)同一段代碼在不同掃描周期里執(zhí)行到的位置可能完全不同時(shí)序不穩(wěn)定對(duì)算法來(lái)說(shuō)是災(zāi)難。我的做法是建一個(gè)循環(huán)中斷 OB設(shè)置固定中斷周期比如 10ms再在中斷里調(diào)用封裝好的 FB。這樣模型的計(jì)算頻率是精確可控的不受主程序其他邏輯影響。循環(huán)中斷的周期要和模型采樣步長(zhǎng)保持一致性。如果模型采樣時(shí)間是 20ms而 PLC 循環(huán)中斷是 10ms那 step 函數(shù)每執(zhí)行一次需要等待兩個(gè)中斷周期邏輯上也能跑但復(fù)雜狀態(tài)下容易出現(xiàn)狀態(tài)滯后和時(shí)序抖動(dòng)。更好的做法是循環(huán)中斷周期等于模型采樣步長(zhǎng)或者采樣步長(zhǎng)是中斷周期的整數(shù)倍。如果是整數(shù)倍關(guān)系step 函數(shù)外層要加一個(gè)計(jì)數(shù)邏輯只有計(jì)數(shù)滿(mǎn)時(shí)才真正執(zhí)行 step。這個(gè)執(zhí)行標(biāo)志位可以作為 FB 的輸出暴露出來(lái)方便監(jiān)控。實(shí)際部署時(shí)還要留一個(gè)性能余量參數(shù)step 函數(shù)的平均執(zhí)行時(shí)間占循環(huán)中斷周期最好控制在 50% 以?xún)?nèi)。如果占太高后續(xù)模型迭代加功能或者現(xiàn)場(chǎng)負(fù)載增加時(shí)很容易超時(shí)觸發(fā) PLC 的循環(huán)超時(shí)報(bào)警。這個(gè)參數(shù)建議在上線前就測(cè)好別等到現(xiàn)場(chǎng)出了問(wèn)題再抓瞎。5. 部署中的常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 導(dǎo)入編譯階段的經(jīng)典報(bào)錯(cuò)我把實(shí)際過(guò)程中碰到的問(wèn)題整理成一個(gè)速查表方便對(duì)照現(xiàn)象原因處理辦法導(dǎo)入時(shí)提示語(yǔ)法不支持生成了特定平臺(tái)擴(kuò)展語(yǔ)法或源文件編碼不符合預(yù)期檢查生成選項(xiàng)把平臺(tái)相關(guān)選項(xiàng)全部取消確認(rèn)編碼為 UTF-8函數(shù)名重復(fù)step 函數(shù)名與博圖已有對(duì)象重名生成前在代碼接口里配置函數(shù)命名前綴數(shù)組越界多維數(shù)組拍平后下標(biāo)錯(cuò)位統(tǒng)一數(shù)組定義上下界用 LOWER_BOUND 0數(shù)據(jù)類(lèi)型不匹配double 被映射為 REAL 后某些接口還要和 DINT 對(duì)接在模型側(cè)顯式把接口轉(zhuǎn)換成需要的類(lèi)型表格里每一條都可以展開(kāi)。就拿第一類(lèi)來(lái)說(shuō)我遇到過(guò)生成的 ST 文件里帶了一些由代碼生成工具額外加上的平臺(tái)宏定義博圖轉(zhuǎn)譯的時(shí)候直接報(bào)“未知標(biāo)識(shí)符”最后只能把代碼里無(wú)關(guān)的部分刪掉再編譯。所以導(dǎo)入之前先打開(kāi)源文件掃一眼是很有必要的習(xí)慣。不要指望一鍵導(dǎo)入永遠(yuǎn)順利多留出十分鐘做檢查能省出一個(gè)晚上的排查時(shí)間。數(shù)組越界這類(lèi)問(wèn)題最典型的場(chǎng)景是 Simulink 側(cè)用了一個(gè)二維矩陣接口生成到 ST 里變成二維數(shù)組。如果模型里對(duì)矩陣的索引方式用的是 C 語(yǔ)言習(xí)慣從 0 開(kāi)始而你在博圖里不小心把數(shù)組下限定義為了 1那每一個(gè)訪問(wèn)都會(huì)錯(cuò)位運(yùn)行結(jié)果完全不可理喻。排查時(shí)可以先把所有數(shù)組下限改成 0如果現(xiàn)象立刻消失那就是索引約定不一致。5.2 運(yùn)行階段的偏差、時(shí)序與資源問(wèn)題編譯通過(guò)不代表運(yùn)行就對(duì)。最典型的問(wèn)題是仿真曲線和現(xiàn)場(chǎng)曲線對(duì)不上不是差一星半點(diǎn)而是趨勢(shì)都對(duì)不上。這時(shí)候先不要懷疑代碼生成有 bug90% 的概率是采樣時(shí)間不一致或者模型側(cè)和 PLC 側(cè)的數(shù)據(jù)類(lèi)型精度不一致。我的排查順序是先確認(rèn)循環(huán)中斷周期和采樣步長(zhǎng)再檢查所有接口數(shù)據(jù)的類(lèi)型和縮放最后再對(duì)比關(guān)鍵中間變量的數(shù)值。中間變量對(duì)比這一招最有用它能幫你在模型內(nèi)部定位到第一個(gè)產(chǎn)生偏差的位置而不是在輸出端猜原因。第二個(gè)高頻問(wèn)題是 CPU 占用過(guò)高。生成代碼雖然看起來(lái)是一堆文本但里面常常有大量嵌套循環(huán)和矩陣計(jì)算。S7-1200 這類(lèi)小型 PLC 跑起來(lái)尤其吃力。建議在上線前做一個(gè)性能估算把 step 函數(shù)平均執(zhí)行時(shí)間控制在循環(huán)中斷周期的 50% 以?xún)?nèi)。如果超了優(yōu)先優(yōu)化模型里的矩陣運(yùn)算比如用直接公式替代復(fù)雜的矩陣求逆而不是去優(yōu)化代碼結(jié)構(gòu)本身。第三個(gè)問(wèn)題是狀態(tài)初始化。生成的初始化函數(shù)只在 FB 首次調(diào)用時(shí)執(zhí)行一次如果中途修改過(guò)模型并重新下載 PLC 程序老的狀態(tài)可能殘留導(dǎo)致輸出跳變。解決辦法是在 FB 里加一個(gè)“模型復(fù)位”輸入或者用啟動(dòng) OB 里的觸發(fā)邏輯把初始化函數(shù)強(qiáng)制調(diào)用一次。這個(gè)細(xì)節(jié)很多文檔不會(huì)寫(xiě)但現(xiàn)場(chǎng)基本都會(huì)遇到提前設(shè)計(jì)好能少很多麻煩。5.3 一套我實(shí)測(cè)好用的推進(jìn)流程最后分享一個(gè)自己反復(fù)用的推進(jìn)順序。拿到模型后我不會(huì)先去做代碼生成而是先把模型里所有可能引起部署問(wèn)題的地方標(biāo)記出來(lái)包括連續(xù)積分環(huán)節(jié)、int 型接口、上升沿檢測(cè)模塊、維度不明確的信號(hào)。然后把任務(wù)分成兩類(lèi)一類(lèi)需要在模型側(cè)修改另一類(lèi)可以在 PLC 側(cè)通過(guò)外層封裝解決。這樣就不會(huì)在工具配置里反復(fù)返工。具體流程大概是模型離散化檢查 → 采樣周期確定 → 接口數(shù)據(jù)類(lèi)型規(guī)范化 → 代碼生成 → 導(dǎo)入博圖 → FB 封裝 → 循環(huán)中斷部署 → 空載仿真對(duì)比 → 連接 IO 實(shí)機(jī)驗(yàn)證。每一步都有對(duì)應(yīng)的輸出物比如采樣周期確定后就寫(xiě)進(jìn)項(xiàng)目文檔這樣后續(xù)迭代時(shí)有據(jù)可查。尤其是代碼生成那一步建議先生成一個(gè)最簡(jiǎn)單的測(cè)試模型比如一個(gè)增益模塊加一個(gè)積分器把整個(gè)鏈路從生成到博圖運(yùn)行完整跑通再換成真實(shí)模型。很多人一上來(lái)直接拿完整模型去生成到最后一步出問(wèn)題定位范圍會(huì)非常大。我個(gè)人習(xí)慣在每一步切換前都做一次“目標(biāo)環(huán)境對(duì)照”問(wèn)自己這段邏輯在 PLC 里會(huì)以什么頻率執(zhí)行、有什么資源限制、和模型里的仿真假設(shè)是否一致。把這個(gè)問(wèn)題想清楚比記住任何具體配置項(xiàng)都重要。工具只是執(zhí)行者真正決定成敗的是對(duì)兩個(gè)平臺(tái)差異的理解。我自己在這幾輪項(xiàng)目里最深的體會(huì)是Simulink 轉(zhuǎn) PLC 這件事最磨人的不是工具鏈而是心態(tài)??傆X(jué)得自動(dòng)生成就應(yīng)該是一鍵完成卻忘了 PLC 和 Simulink 是兩種執(zhí)行模型一個(gè)時(shí)間自由一個(gè)嚴(yán)格周期。把模型離散化、把數(shù)據(jù)類(lèi)型顯式收斂、把采樣時(shí)間對(duì)齊這三件事做到位后面基本是水到渠成。順便分享一個(gè)最后的小技巧在上線前把生成代碼里的所有常量調(diào)出來(lái)和 Simulink 模型里的參數(shù)逐個(gè)核對(duì)一遍經(jīng)常會(huì)有意外收獲。我至少碰到過(guò)兩次模型中某處還是默認(rèn)的 0.5、1.0而實(shí)際工程參數(shù)應(yīng)該是 0.05、10 的情況。這類(lèi)問(wèn)題不會(huì)報(bào)錯(cuò)但會(huì)讓現(xiàn)場(chǎng)的曲線非常難看多留這一步能幫你省掉大量排查時(shí)間。