用正運(yùn)動(dòng)控制卡:從DLL封裝到插補(bǔ)運(yùn)動(dòng)實(shí)戰(zhàn))
1. 為什么是運(yùn)動(dòng)控制卡而不是又一臺(tái)PLC很多人拿到一個(gè)自動(dòng)化設(shè)備的活第一反應(yīng)就是PLC。這很自然PLC在邏輯控制、順序控制、環(huán)境適應(yīng)性上的優(yōu)勢(shì)確實(shí)明顯而且電氣工程師普遍熟悉。但一旦涉及多軸聯(lián)動(dòng)高速插補(bǔ)軌跡規(guī)劃這些詞PLC的局限就暴露出來(lái)了首先高端PLC的定位模塊或運(yùn)動(dòng)控制模塊價(jià)格不便宜而且大多是封閉生態(tài)編程風(fēng)格和通用上位機(jī)開(kāi)發(fā)完全是兩套邏輯其次PLC的軌跡規(guī)劃能力通常比較弱圓弧插補(bǔ)、電子凸輪、連續(xù)軌跡前瞻這些功能很多中低端PLC做起來(lái)非常別扭。我的習(xí)慣是設(shè)備里如果只有氣缸、電機(jī)起停、簡(jiǎn)單的兩三個(gè)伺服定位那PLC完全夠了一旦出現(xiàn)四軸以上、或者要求連續(xù)軌跡加工、或者需要和視覺(jué)系統(tǒng)高頻交互的場(chǎng)景我就會(huì)考慮上位機(jī)運(yùn)動(dòng)控制卡這套架構(gòu)。以正運(yùn)動(dòng)控制卡為例它本質(zhì)上是一張PCI或PCIe接口的板卡板載高性能DSP或ARM處理器專(zhuān)門(mén)負(fù)責(zé)實(shí)時(shí)性要求極高的插補(bǔ)運(yùn)算、位置閉環(huán)、IO掃描。而上位機(jī)也就是工控機(jī)里的LabVIEW程序只負(fù)責(zé)人機(jī)交互、邏輯調(diào)度和數(shù)據(jù)處理。這樣分工的好處很明顯實(shí)時(shí)任務(wù)由控制卡獨(dú)立完成不占用操作系統(tǒng)資源Windows系統(tǒng)哪怕偶爾卡頓軸的運(yùn)動(dòng)軌跡也不會(huì)亂。還有一個(gè)容易被忽略的點(diǎn)。正運(yùn)動(dòng)控制卡的指令集是Basic語(yǔ)法也就是大家常說(shuō)的運(yùn)動(dòng)控制器Basic指令它提供了一種在控制器里直接編寫(xiě)運(yùn)動(dòng)腳本的能力。這意味著有些對(duì)實(shí)時(shí)性要求極高的邏輯可以直接下載到控制卡里離線(xiàn)執(zhí)行完全脫離上位機(jī)。這個(gè)特性在做一些需要脫機(jī)運(yùn)行的設(shè)備時(shí)非常實(shí)用。2. LabVIEW調(diào)用控制卡的三條典型路線(xiàn)正運(yùn)動(dòng)控制卡的官方開(kāi)發(fā)包里有DLL動(dòng)態(tài)庫(kù)這是Windows環(huán)境下最直接的調(diào)用方式也是我最初上手時(shí)的路線(xiàn)。LabVIEW通過(guò)調(diào)用庫(kù)函數(shù)節(jié)點(diǎn)Call Library Function Node簡(jiǎn)稱(chēng)CLFN可以直接加載DLL里的導(dǎo)出函數(shù)實(shí)現(xiàn)指令下發(fā)。這個(gè)過(guò)程并不復(fù)雜但有幾個(gè)關(guān)鍵細(xì)節(jié)很容易踩坑后面我會(huì)專(zhuān)門(mén)展開(kāi)。2.1 三種通信方式的取舍通信方式實(shí)時(shí)性開(kāi)發(fā)效率適用場(chǎng)景DLL函數(shù)調(diào)用高μs級(jí)中需要封裝CLFN絕大多數(shù)通用場(chǎng)合網(wǎng)絡(luò)通訊TCP/Modbus中ms級(jí)高用現(xiàn)成TCP節(jié)點(diǎn)遠(yuǎn)程監(jiān)控、跨工位數(shù)據(jù)采集控制器離線(xiàn)腳本最高由控制卡獨(dú)立運(yùn)行低需學(xué)Basic指令脫機(jī)運(yùn)行、高速插補(bǔ)剛開(kāi)始做LabVIEW上位機(jī)的朋友我建議優(yōu)先走DLL路線(xiàn)因?yàn)檫@是官方支持和測(cè)試最充分的路徑后續(xù)做二次開(kāi)發(fā)、功能升級(jí)也都圍繞這套DLL展開(kāi)。網(wǎng)絡(luò)通訊適合做遠(yuǎn)程看板、數(shù)據(jù)采集這類(lèi)非實(shí)時(shí)應(yīng)用。離線(xiàn)腳本屬于進(jìn)階玩法等DLL路線(xiàn)跑通后再研究也不遲。2.2 CLFN節(jié)點(diǎn)配置時(shí)最容易錯(cuò)的細(xì)節(jié)調(diào)用庫(kù)函數(shù)節(jié)點(diǎn)的配置界面看起來(lái)選項(xiàng)很多但真正需要關(guān)心的就幾個(gè)函數(shù)名、調(diào)用約定、參數(shù)類(lèi)型和返回值。正運(yùn)動(dòng)的DLL大部分函數(shù)是__stdcall調(diào)用約定返回值是一個(gè)表示指令狀態(tài)的整數(shù)通常0表示成功非0表示錯(cuò)誤碼參數(shù)則根據(jù)具體指令不同而變化。我第一次封裝時(shí)犯過(guò)的錯(cuò)是把所有的參數(shù)都設(shè)成了I32有符號(hào)32位整數(shù)結(jié)果字符串類(lèi)型的軸名稱(chēng)參數(shù)傳進(jìn)去全是亂碼。后來(lái)才意識(shí)到字符串參數(shù)在CLFN里需要用C String Pointer格式傳入。如果你的控制卡指令里有浮點(diǎn)參數(shù)比如速度值、坐標(biāo)值還得在CLFN里明確設(shè)置成數(shù)值或者浮點(diǎn)格式否則精度會(huì)丟失。正常來(lái)說(shuō)每封裝一個(gè)DLL函數(shù)在LabVIEW里會(huì)生成一個(gè)VI虛擬儀器。這個(gè)VI就是后續(xù)你在程序框圖中反復(fù)調(diào)用的基礎(chǔ)模塊建議把這類(lèi)VI統(tǒng)一放到一個(gè)自定義控件庫(kù)或子面板里方便復(fù)用。3. 環(huán)境準(zhǔn)備從驅(qū)動(dòng)安裝到動(dòng)態(tài)庫(kù)封裝這一節(jié)寫(xiě)給第一次接觸這套方案的朋友跳過(guò)這里的代價(jià)往往是后面調(diào)試時(shí)浪費(fèi)大量時(shí)間。3.1 驅(qū)動(dòng)和開(kāi)發(fā)包版本對(duì)齊正運(yùn)動(dòng)的驅(qū)動(dòng)和控制卡固件版本、開(kāi)發(fā)包版本之間存在對(duì)應(yīng)關(guān)系。很多人拿到一張新卡直接裝最新版驅(qū)動(dòng)結(jié)果發(fā)現(xiàn)老設(shè)備上的程序跑不了。尤其注意如果你用的開(kāi)發(fā)包是某個(gè)特定版本控制卡固件版本必須匹配。這里有個(gè)笨辦法但很有效安裝好驅(qū)動(dòng)后用官方調(diào)試軟件連接控制卡先看固件版本號(hào)和DLL版本號(hào)是否一致再開(kāi)始編程。這一步確認(rèn)好了后面能省掉很多莫名其妙的坑。LabVIEW版本的選擇上我建議盡量用較新的穩(wěn)定版比如LabVIEW 2018及以后。因?yàn)樾掳鎸?duì)CLFN和事件結(jié)構(gòu)的支持更穩(wěn)定而且網(wǎng)上能搜到的封裝實(shí)例和工具箱也更多。注意一個(gè)細(xì)節(jié)控制卡的DLL有些是32位的如果你的LabVIEW是64位版本兩者會(huì)存在位數(shù)不匹配的問(wèn)題。解決方案就是在64位系統(tǒng)上裝32位版本的LabVIEW或者向控制卡廠(chǎng)家確認(rèn)是否有64位DLL。這一點(diǎn)非常關(guān)鍵。3.2 DLL封裝的標(biāo)準(zhǔn)流程在LabVIEW中封裝一個(gè)DLL函數(shù)標(biāo)準(zhǔn)流程如下在程序框圖中拖入一個(gè)調(diào)用庫(kù)函數(shù)節(jié)點(diǎn)雙擊打開(kāi)配置窗口。在函數(shù)選項(xiàng)卡中選擇DLL路徑填入函數(shù)名選擇調(diào)用約定為_(kāi)_stdcall。在參數(shù)選項(xiàng)卡中逐個(gè)配置參數(shù)類(lèi)型整數(shù)用I32浮點(diǎn)用單精度或雙精度字符串用C String Pointer。配置返回值為I32代表錯(cuò)誤碼。保存為子VI輸入輸出建立連線(xiàn)板接線(xiàn)端。反復(fù)測(cè)試該子VI確保指令下發(fā)成功后再往上搭建業(yè)務(wù)邏輯。注意正運(yùn)動(dòng)控制卡的指令集里同一功能往往有指令參數(shù)和返回值指令兩種形式。例如設(shè)置脈沖當(dāng)量既可以通過(guò)一個(gè)帶參數(shù)的指令完成也可以通過(guò)查詢(xún)類(lèi)指令獲取當(dāng)前值。封裝時(shí)不要把兩種形式搞混建議每個(gè)函數(shù)獨(dú)立封裝成獨(dú)立VI命名清晰方便后面查閱。如果覺(jué)得手動(dòng)封裝太繁瑣可以用官方提供的封裝工具或參考例程。正運(yùn)動(dòng)的開(kāi)發(fā)包里通常自帶LabVIEW例程找到后直接拿來(lái)改比自己從頭封裝效率高得多。但還是建議先手動(dòng)封裝一兩遍理解底層原理后面調(diào)試才不至于抓瞎。4. 運(yùn)動(dòng)邏輯是怎么跑起來(lái)的核心指令與狀態(tài)流轉(zhuǎn)封裝好基礎(chǔ)VI后真正的運(yùn)動(dòng)邏輯就開(kāi)始了。很多新手在這里容易懵控制卡的指令那么多到底哪些是必用的4.1 一套最小可用的指令集以我的經(jīng)驗(yàn)LabVIEW上位機(jī)控制正運(yùn)動(dòng)卡核心指令可以精簡(jiǎn)到下面幾類(lèi)連接與初始化打開(kāi)控制卡如ZAux_Open、復(fù)位如ZAux_Reset。程序啟動(dòng)時(shí)先執(zhí)行這兩步確??刂瓶ㄌ幱谝阎獱顟B(tài)。參數(shù)配置設(shè)置脈沖當(dāng)量、加速度、減速度、速度、回零方向、軟限位等。這類(lèi)指令在設(shè)備啟動(dòng)后、運(yùn)動(dòng)開(kāi)始前統(tǒng)一配置。點(diǎn)位運(yùn)動(dòng)單軸絕對(duì)運(yùn)動(dòng)MOVE、單軸相對(duì)運(yùn)動(dòng)MOVED、多軸直線(xiàn)插補(bǔ)MOVE或LINE類(lèi)指令。這是最常用的指令組完成90%的定位需求。回零操作回原點(diǎn)HOME或機(jī)械回零不同控制卡命名有差異但功能類(lèi)似。狀態(tài)查詢(xún)讀取當(dāng)前軸位置、運(yùn)動(dòng)狀態(tài)運(yùn)動(dòng)中/停止、IO狀態(tài)、報(bào)警狀態(tài)。這是上位機(jī)做狀態(tài)刷新和邏輯判斷的基礎(chǔ)。下面是一段偽代碼風(fēng)格的邏輯示意展示LabVIEW程序框圖中如何組織一次完整的單軸定位// 偽代碼演示邏輯流程 1. 初始化控制卡 2. 設(shè)置軸0參數(shù)速度1000加速度5000減速度5000 3. 執(zhí)行回零 4. 等待回零完成循環(huán)查詢(xún)軸狀態(tài)直到停止 5. 下發(fā)絕對(duì)定位指令移動(dòng)到位置100000 6. 等待運(yùn)動(dòng)完成 7. 讀取當(dāng)前位置核對(duì)是否到位對(duì)應(yīng)到LabVIEW程序框圖其實(shí)就是幾個(gè)子VI的串聯(lián)加上While循環(huán)做狀態(tài)等待。這里的核心技巧是等待運(yùn)動(dòng)完成的循環(huán)一定要加延時(shí)典型值10~20ms避免CPU空閑占用過(guò)高同時(shí)保證狀態(tài)查詢(xún)的穩(wěn)定性。4.2 回零和限位的優(yōu)先級(jí)問(wèn)題回零是設(shè)備調(diào)試的第一步也是最容易出問(wèn)題的地方。正運(yùn)動(dòng)控制卡支持多種回零方式常見(jiàn)的是找原點(diǎn)開(kāi)關(guān)找Z相的組合方式。常規(guī)邏輯是先以較快的速度朝回零方向運(yùn)動(dòng)碰到原點(diǎn)開(kāi)關(guān)后減速然后低速找編碼器Z相脈沖最后停在固定位置。這個(gè)過(guò)程中必須把限位信號(hào)的處理優(yōu)先級(jí)放在所有運(yùn)動(dòng)邏輯的最前面??刂瓶ǖ南尬惠斎胍坏┯|發(fā)軸必須立即停止。這是硬件級(jí)的安全保障不能指望上位機(jī)軟件來(lái)處理——萬(wàn)一Windows卡死了軟件壓根反應(yīng)不過(guò)來(lái)。所以配置時(shí)一定要確保硬限位信號(hào)接到了控制卡的專(zhuān)用限位輸入口而不僅僅是在LabVIEW里做了軟限位判斷。軟限位只負(fù)責(zé)正常情況下防呆硬限位才是保護(hù)設(shè)備的最后一道防線(xiàn)。4.3 狀態(tài)機(jī)的設(shè)計(jì)從簡(jiǎn)單到可擴(kuò)展熱搜詞里有一條c#正運(yùn)動(dòng)運(yùn)動(dòng)控制卡簡(jiǎn)單狀態(tài)機(jī)實(shí)現(xiàn)方式可見(jiàn)狀態(tài)機(jī)是繞不開(kāi)的話(huà)題。在LabVIEW里做狀態(tài)機(jī)常用的模式是事件結(jié)構(gòu)狀態(tài)枚舉條件結(jié)構(gòu)這是一套比較經(jīng)典的組合。我一般會(huì)這樣組織狀態(tài)機(jī)狀態(tài)狀態(tài)碼動(dòng)作IDLE0等待用戶(hù)指令或觸發(fā)信號(hào)HOMING1執(zhí)行回零流程狀態(tài)輪詢(xún)READY2回零完成等待運(yùn)動(dòng)指令MOVING3正在執(zhí)行運(yùn)動(dòng)實(shí)時(shí)刷新位置PAUSED4暫停運(yùn)動(dòng)緊急停止后ERROR5碰到限位、報(bào)警、超時(shí)等異常處理狀態(tài)機(jī)的好處是邏輯清晰、擴(kuò)展方便。比如后續(xù)增加連續(xù)軌跡加工狀態(tài)只需要在枚舉里加一個(gè)狀態(tài)然后在條件結(jié)構(gòu)中增加對(duì)應(yīng)分支即可。相比用一堆布爾量加大量條件判斷的寫(xiě)法狀態(tài)機(jī)讓程序結(jié)構(gòu)一目了然調(diào)試和排查問(wèn)題的難度大幅降低。LabVIEW里實(shí)現(xiàn)狀態(tài)機(jī)的做法是在While循環(huán)里放一個(gè)移位寄存器保存當(dāng)前狀態(tài)循環(huán)體內(nèi)用條件結(jié)構(gòu)根據(jù)當(dāng)前狀態(tài)執(zhí)行對(duì)應(yīng)分支并在分支結(jié)束前將下一狀態(tài)寫(xiě)入移位寄存器。這樣循環(huán)每跑一次程序就從一個(gè)狀態(tài)流轉(zhuǎn)到下一個(gè)狀態(tài)清晰且穩(wěn)定。這里分享一個(gè)心得不要把狀態(tài)判斷寫(xiě)得過(guò)于復(fù)雜。狀態(tài)機(jī)的核心價(jià)值在于當(dāng)前做什么是明確的接下來(lái)做什么是可預(yù)期的。如果狀態(tài)分支里的條件太多可以考慮拆分子狀態(tài)機(jī)讓每個(gè)狀態(tài)只負(fù)責(zé)一件具體的事。5. 崩潰現(xiàn)場(chǎng)三次典型踩坑記錄5.1 回零時(shí)軸往反方向猛跑第一次調(diào)試時(shí)明明配置了回零方向軸卻直接沖向了和預(yù)期相反的方向差點(diǎn)撞上機(jī)械結(jié)構(gòu)。排查了很久最后發(fā)現(xiàn)是參數(shù)設(shè)置的問(wèn)題控制卡的方向參數(shù)是二進(jìn)制數(shù)而我在LabVIEW里把方向值配置成了相反的那個(gè)數(shù)。這件事給我的啟發(fā)是回零調(diào)試時(shí)務(wù)必先斷開(kāi)電機(jī)的使能用手轉(zhuǎn)動(dòng)電機(jī)來(lái)觀察編碼器方向是否和軟件配置一致確認(rèn)無(wú)誤后再做低速回零然后才逐步提高速度。更穩(wěn)妥的做法是調(diào)試階段在LabVIEW里加一個(gè)總使能開(kāi)關(guān)在程序界面做明顯的急停按鈕方便隨時(shí)切斷動(dòng)力。5.2 CLFN參數(shù)類(lèi)型不匹配導(dǎo)致運(yùn)動(dòng)指令失效封裝MOVE指令時(shí)位置、速度這些參數(shù)都是浮點(diǎn)數(shù)但我一開(kāi)始全部按I32配置了。結(jié)果就是指令下發(fā)后控制卡一直返回錯(cuò)誤代碼軸紋絲不動(dòng)。查了好久才意識(shí)到是DLL函數(shù)的參數(shù)類(lèi)型配置錯(cuò)了。這個(gè)問(wèn)題的排查思路可以這樣當(dāng)指令返回錯(cuò)誤碼時(shí)先去控制卡的錯(cuò)誤碼對(duì)照表里查看具體含義。正運(yùn)動(dòng)的錯(cuò)誤碼體系比較完整每個(gè)碼都對(duì)應(yīng)明確的錯(cuò)誤原因。對(duì)照后發(fā)現(xiàn)錯(cuò)誤碼指示的參數(shù)類(lèi)型不合法再回頭檢查CLFN配置問(wèn)題很快就定位了。5.3 32位DLL與64位LabVIEW的死亡組合有一次在64位系統(tǒng)上裝了64位LabVIEW結(jié)果所有DLL函數(shù)調(diào)用都返回內(nèi)存訪(fǎng)問(wèn)沖突之類(lèi)的錯(cuò)誤。研究一番后發(fā)現(xiàn)正運(yùn)動(dòng)控制卡的DLL在當(dāng)時(shí)的版本只提供32位版本64位LabVIEW在加載32位DLL時(shí)會(huì)出現(xiàn)兼容性問(wèn)題。后來(lái)折中的方案是安裝32位版LabVIEW重新封裝DLL一切恢復(fù)正常。所以如果你準(zhǔn)備用正運(yùn)動(dòng)控制卡配合LabVIEW開(kāi)發(fā)安裝軟件前最好先確認(rèn)DLL位數(shù)再?zèng)Q定LabVIEW版本位數(shù)。這種問(wèn)題的排查成本很高提前避免是最好。6. 插補(bǔ)與連續(xù)軌跡脫離單軸運(yùn)動(dòng)的進(jìn)階排版前面的內(nèi)容主要圍繞點(diǎn)位運(yùn)動(dòng)展開(kāi)。點(diǎn)位運(yùn)動(dòng)的特點(diǎn)是起點(diǎn)到終點(diǎn)之間只關(guān)注最終位置中間軌跡不關(guān)心。但很多設(shè)備的需求遠(yuǎn)不止這個(gè)切割機(jī)要走圓弧、點(diǎn)膠機(jī)要連續(xù)走S型曲線(xiàn)、視覺(jué)引導(dǎo)要把相機(jī)給出的坐標(biāo)轉(zhuǎn)換成多軸的連續(xù)路徑。這些都需要用到插補(bǔ)能力。6.1 直線(xiàn)插補(bǔ)和圓弧插補(bǔ)的調(diào)用邏輯正運(yùn)動(dòng)控制卡支持多軸直線(xiàn)插補(bǔ)和圓弧插補(bǔ)。調(diào)用邏輯其實(shí)很直接下發(fā)一條插補(bǔ)指令指定參與插補(bǔ)的軸號(hào)、目標(biāo)坐標(biāo)、速度等參數(shù)即可。以?xún)奢S直線(xiàn)插補(bǔ)為例// 偽代碼 直線(xiàn)插補(bǔ)(軸0, 軸1, 目標(biāo)X, 目標(biāo)Y, 速度, 加速度)控制卡內(nèi)部會(huì)把這條指令解析為兩軸聯(lián)動(dòng)的位置數(shù)據(jù)按插補(bǔ)周期實(shí)時(shí)輸出脈沖。整個(gè)過(guò)程對(duì)LabVIEW程序來(lái)說(shuō)是透明的上位機(jī)只需要等待插補(bǔ)完成狀態(tài)即可。圓弧插補(bǔ)類(lèi)似只是參數(shù)變成了圓心坐標(biāo)、半徑、方向等。關(guān)鍵是理解一點(diǎn)插補(bǔ)運(yùn)算是在控制卡內(nèi)部完成的上位機(jī)只負(fù)責(zé)下發(fā)參數(shù)。這也是運(yùn)動(dòng)控制卡區(qū)別于普通脈沖輸出模塊的核心能力。6.2 連續(xù)軌跡的前瞻機(jī)制連續(xù)軌跡也叫小線(xiàn)段連續(xù)加工是更進(jìn)階的功能。設(shè)備要加工的輪廓通常是一堆密集的小線(xiàn)段如果每段都等停止后再走下一段效率極低。連續(xù)軌跡功能就是讓控制卡在到達(dá)線(xiàn)段終點(diǎn)之前就開(kāi)始規(guī)劃下一段運(yùn)動(dòng)實(shí)現(xiàn)平滑過(guò)渡。正運(yùn)動(dòng)控制卡的連續(xù)軌跡通常需要將多個(gè)目標(biāo)點(diǎn)預(yù)先寫(xiě)入緩沖區(qū)然后依次執(zhí)行。LabVIEW端通過(guò)一個(gè)循環(huán)下發(fā)點(diǎn)列集合把當(dāng)前的位置點(diǎn)不斷追加到控制卡的軌跡緩沖區(qū)。這段邏輯要特別注意緩沖區(qū)的深度管理避免緩沖區(qū)被填滿(mǎn)后程序還在盲寫(xiě)。我的建議是連續(xù)軌跡的調(diào)試要分步驗(yàn)證先用10個(gè)點(diǎn)以?xún)?nèi)的簡(jiǎn)單輪廓跑通確認(rèn)軌跡和預(yù)期一致再逐漸增加點(diǎn)數(shù)和速度。一開(kāi)始就上幾千個(gè)點(diǎn)的復(fù)雜輪廓出問(wèn)題時(shí)很難定位是哪個(gè)坐標(biāo)導(dǎo)致的路徑偏差。6.3 運(yùn)動(dòng)狀態(tài)刷新避免盲飛插補(bǔ)和連續(xù)軌跡執(zhí)行期間上位機(jī)的狀態(tài)刷新依然要做。通常用一個(gè)定時(shí)循環(huán)比如50ms周期不斷讀取當(dāng)前坐標(biāo)和運(yùn)動(dòng)狀態(tài)顯示在界面上。這里有一個(gè)細(xì)節(jié)讀取坐標(biāo)指令比較耗時(shí)間不建議在程序的每個(gè)循環(huán)里都讀所有軸??梢宰鲆粋€(gè)需要時(shí)讀取的設(shè)計(jì)比如只在界面刷新周期或者運(yùn)動(dòng)完成時(shí)觸發(fā)坐標(biāo)讀取降低總線(xiàn)的通信壓力。7. 上位機(jī)架構(gòu)的穩(wěn)定性交互、看門(mén)狗與異常恢復(fù)運(yùn)動(dòng)控制應(yīng)用里上位機(jī)程序的穩(wěn)定性比功能性更重要。一套設(shè)備運(yùn)轉(zhuǎn)起來(lái)上位機(jī)死機(jī)或卡頓的后果輕則產(chǎn)品報(bào)廢重則安全事故。所以架構(gòu)設(shè)計(jì)上要提前考慮三層防護(hù)。7.1 用戶(hù)界面與運(yùn)動(dòng)邏輯的分離LabVIEW天然是多線(xiàn)程、并行運(yùn)行的。寫(xiě)上位機(jī)程序時(shí)我會(huì)刻意把UI線(xiàn)程、運(yùn)動(dòng)控制線(xiàn)程、狀態(tài)刷新線(xiàn)程分開(kāi)。UI線(xiàn)程負(fù)責(zé)按鈕、數(shù)值輸入、顯示刷新運(yùn)動(dòng)控制線(xiàn)程負(fù)責(zé)指令下發(fā)和邏輯判斷狀態(tài)刷新線(xiàn)程單獨(dú)跑一個(gè)更慢的循環(huán)讀取IO和坐標(biāo)。這樣做的好處是UI卡頓不會(huì)影響運(yùn)動(dòng)指令的執(zhí)行狀態(tài)刷新慢一點(diǎn)不會(huì)影響運(yùn)動(dòng)精度。如果所有功能混在一個(gè)循環(huán)里UI一旦卡住運(yùn)動(dòng)邏輯也跟著停擺這是絕對(duì)不能接受的。7.2 軟件看門(mén)狗控制卡本身有硬件看門(mén)狗但是檢測(cè)的是控制卡自己是否正常工作。上位機(jī)這邊需要做的是通信看門(mén)狗定時(shí)檢查上位機(jī)和控制卡之間的通信是否正常如果連續(xù)幾次通信超時(shí)或返回錯(cuò)誤就認(rèn)為鏈路異常執(zhí)行急停。LabVIEW里實(shí)現(xiàn)通信看門(mén)狗很簡(jiǎn)單在狀態(tài)刷新線(xiàn)程里加一個(gè)錯(cuò)誤計(jì)數(shù)器連續(xù)N次通信失敗就觸發(fā)急停。這個(gè)N不宜過(guò)小避免偶發(fā)通信抖動(dòng)就誤動(dòng)作。7.3 運(yùn)動(dòng)前的自檢流程我寫(xiě)的每一套運(yùn)動(dòng)控制程序都會(huì)在啟動(dòng)時(shí)做一個(gè)自檢流程初始化控制卡、讀取固件版本、檢查急停信號(hào)是否釋放、檢查伺服驅(qū)動(dòng)器的使能和報(bào)警狀態(tài)、檢查各軸是否在軟限位范圍內(nèi)。自檢不通過(guò)程序就不進(jìn)入運(yùn)動(dòng)狀態(tài)同時(shí)把未通過(guò)原因顯示在界面上。這個(gè)流程看似簡(jiǎn)單但在實(shí)際設(shè)備上能攔截掉大量半路出問(wèn)題的現(xiàn)場(chǎng)故障。因?yàn)槟阌肋h(yuǎn)無(wú)法保證設(shè)備每一次上電所有硬件都處于正常狀態(tài)。自檢就是把這些不確定性在上電階段就暴露出來(lái)。8. 我的習(xí)慣和主觀建議做運(yùn)動(dòng)控制這幾年有個(gè)深切的體會(huì)硬件選型和架構(gòu)設(shè)計(jì)決定了項(xiàng)目的上限而細(xì)節(jié)處理和調(diào)試經(jīng)驗(yàn)決定了項(xiàng)目的下限。選型層面正運(yùn)動(dòng)控制卡是我用過(guò)性?xún)r(jià)比很高的方案。原因有幾個(gè)指令集簡(jiǎn)潔且覆蓋面廣從基礎(chǔ)點(diǎn)位到復(fù)雜插補(bǔ)都有對(duì)應(yīng)的指令學(xué)習(xí)曲線(xiàn)不算陡。開(kāi)發(fā)包支持多語(yǔ)言DLL接口標(biāo)準(zhǔn)化不管是LabVIEW、C#、Python都能方便調(diào)用。控制卡本身獨(dú)立運(yùn)行能力很強(qiáng)脫機(jī)腳本適合做一些嵌入式場(chǎng)景。知識(shí)生態(tài)相對(duì)開(kāi)放網(wǎng)上能找到大量例程和討論少走很多彎路。細(xì)節(jié)層面我自己的習(xí)慣是所有程序里增加固定的數(shù)據(jù)記錄功能把關(guān)鍵指令和狀態(tài)變化寫(xiě)入日志文件?,F(xiàn)場(chǎng)出問(wèn)題時(shí)先翻日志定位大概時(shí)間點(diǎn)再針對(duì)性地排查效率高很多。運(yùn)動(dòng)參數(shù)速度、加速度、位置不在程序里硬編碼全部做成界面輸入項(xiàng)或配置文件。這樣現(xiàn)場(chǎng)調(diào)試時(shí)不需要改代碼直接改界面的數(shù)值就能試運(yùn)行。哪怕只是單軸的簡(jiǎn)單應(yīng)用我也建議按初始化—自檢—回零—運(yùn)動(dòng)—停止的標(biāo)準(zhǔn)流程來(lái)組織程序。流程規(guī)范了換項(xiàng)目、換機(jī)型時(shí)絕大部分邏輯可以直接復(fù)用。如果你是第一次用運(yùn)動(dòng)控制卡配合LabVIEW做上位機(jī)我的建議是先不要著急寫(xiě)業(yè)務(wù)邏輯先把控制卡的指令集中最基礎(chǔ)的幾個(gè)功能跑通比如連接、回零、點(diǎn)位運(yùn)動(dòng)、讀取位置。把這條鏈路打通了再逐步往上加需求?;A(chǔ)鏈路不穩(wěn)定的情況下后續(xù)所有開(kāi)發(fā)都會(huì)是在沙灘上蓋樓。最后再分享一個(gè)小技巧封裝DLL子VI時(shí)記得把所有與指令相關(guān)的參數(shù)都暴露出來(lái)作為輸入哪怕有些參數(shù)當(dāng)前用不上。因?yàn)樵O(shè)備的運(yùn)動(dòng)需求經(jīng)常會(huì)變?nèi)f一后來(lái)需要調(diào)節(jié)某個(gè)參數(shù)直接在前面板改就行了不用重新連導(dǎo)線(xiàn)。采過(guò)幾次坑之后我深刻體會(huì)到前期多花一點(diǎn)時(shí)間做規(guī)范的封裝后期調(diào)試能節(jié)省的時(shí)間遠(yuǎn)超過(guò)你預(yù)期。