labview项目实例_labview操作者框架
0.引言
操作者框架適合于多并行任務的項目。在這樣的項目中,多個并行任務之間往往需要相互通信,傳統的解決辦法是,每個任務一個隊列,一個while循環,多任務項目需要在一個程序框圖使用多個while,不好看。NI說使用Actor Framework能夠避免鎖死,競爭,增大代碼重用度。NI官方論壇上有一個例子,寫的很好。
如上圖,這是一個反饋式蒸發器,通過不斷向室內吹送水蒸氣以達到降溫目的。它主要由水位傳感器,溫度傳感器,水箱,水閥,水泵,風扇,海綿組成。原理如下:讀取水位,水位過低時,打開水閥向水箱中放水;水位過高時關閉水閥。同時,讀取室內溫度,溫度過高時,打開水泵向海綿上抽水,等海綿吸滿水后,打開風扇,向室內鼓風,干燥的風經過濕透的海綿,成為溫度較低的濕潤的風,以此來降低室內溫度;溫度過低時,關閉水泵。
項目需求:
有點小復雜。
解決方案:
系統需要4個模塊:
UI(Cooler UI with Events.lvclass) ;
冷卻模塊(Cooler.lvclass);
水位控制模塊(Water Level.lvclass);
風扇控制模塊(Dual Fan.lvclass)。
其中冷卻模塊是主模塊,與風扇控制模塊和水位控制模塊組合關系,和UI模塊是關聯關系。(PS:Cooler需要負責Dual Fan和Water Level的啟動和釋放,Cool通過動態事件和Cooler Panel交互),每個模塊為一個Actor。
冷卻模塊(Cooler.lvclass)),水位控制模塊(Water Level.lvclass),風扇控制模塊(Dual Fan.lvclass)都需要輪詢,Dual Fan輪詢有沒有風扇壞掉了,Water Level輪詢水位,Cooler輪詢溫度。所以寫個Timed Loop Controller.lvclass,哪個操作者需輪詢要直接從它繼承就可以了。繼承使代碼復用度提高了。
同理,水位控制模塊(Water Level.lvclass),風扇控制模塊(Dual Fan.lvclass)還有相似的邏輯——超過限位就打開或關閉。寫個Level Controller.lvclass作為這兩個操作者的父類,因為labview中一個孩子只能有一個父親,所以Level Controller.lvclass需要繼承自Timed Loop Controller.lvclass。
1.創建Timed Loop Controller.class
這個類只需要一個屬性:輪詢頻率。使此類繼承Actor.class。
1.1 Actor Core.vi
父類actor.class中的Actor Core.vi被重寫,父類actor.class中的Actor Core.vi中有一個狀態機,當它收到停止消息時,就會退出,之后局部變量stop?為真,不在發送update消息。
1.2 Update.vi
此vi是空的,留給子類重寫。
2. 創建Level Controller.class
Cooler actors 和Water Level actors的邏輯是一樣的,都是超過限位就打開或者關閉。所以創建此類作為這兩個類的父類,以增大代碼重用度。這個類需要三個屬性:高限位,低限位,這兩個作為輸入;另外還需要保存輸出的值:高,低,不變。
State Logic.vi是要復用的邏輯,Level Controller肯定要先從硬件讀取輸入,然后在進行邏輯操作,最后輸出結果,輸入和輸出是和硬件有關系的,但是硬件不同,故讀取功能的代碼和輸出功能的代碼肯定不一樣,為了使軟件可擴展性更好,所以將輸入get new level.vi和輸出set output state.vi作為虛函數(就是明知程序中必須有,但是又不能寫在此類中),這樣更換硬件時,我們只需從此類繼承,并重寫輸入輸出vi即可。另外,此類重寫了Update.vi。重寫的update會以固定間隔運行。
3. 創建 Water Level.class
Water Level是一個具體類,繼承自Level Controller。前面的Level Controller和Time Loop Controller是虛類,類似于c++中的虛類,不能夠實例化對象,labview雖然沒有這個規定,但這樣做沒什么意義。labview中,虛類負責邏輯設計,具體類(子孫類)負責具體的輸入輸出,和具體的硬件相關,這樣帶來的好處是,硬件更換時,只需要從虛類繼承那些已經被設計好的邏輯,重寫那些輸入輸出等和硬件有關的vi即可。
輸入輸出,可以由全局變量來模擬。這樣會使測試軟件時會方便很多。有人把它叫做HAL,即hardware abstraction layer 虛擬硬件層,瞬間高大上(⊙o⊙)…。HAL是繼承父類的具體類,運行時就能夠檢驗軟件邏輯有沒有錯誤。在設計是,最好設計個HAL,以方便調試。
這里面的Water Level就是HAL。
其中輸入輸出都是用的全局變量來模擬的。
Get New Level.vi:
Set Output State.vi:
寫好后就可以測試了。
4. 創建Dual Fan.class
Dual Fan 是繼承自Timed Loop Controller的具體類。屬性為兩個風扇的狀態:打開或關閉,正常或故障。
為了讓其他操作者能夠打開或關閉風扇,需要為Power Off.vi和Power On.vi創建消息。當一個風扇故障時需要打開另一個,所以需要輪詢風扇是否故障,這個功能通過重寫父類Update.vi實現。
完成后可對本類進行測試:
5. 創建Cooler.class
Cooler繼承自Level Controller的具體類。Water Level和Dual Fan組合成了Cooler,所以要負責這兩個操作者的啟動和關閉。
Get New Level.vi不用說,還是從全局變量中讀取模擬的溫度值。之后是邏輯處理,父類已經寫好,不用操心這部分,之后就是輸出Set Output State.vi:
這里的代碼解釋了為什么要將Dual Fan隊列的引用類型和Run Fan Delivery Notifier放到本類的私有數據中——因為他要根據溫度值,控制風扇的打開和關閉,有Dual Fan隊列的引用,直接向這個隊列發送消息即可。由于pump打開后,需要等一段時間來讓水充滿海綿,所以需要使用Run-Delayed Send Message.vi,因為風扇關閉后此通知器就不用了,所以需要釋放。
Dual Fan隊列和Water Level放到本類的私有隊列中還有一個原因,那就是我們想Cooler關閉時,Dual Fan和Water Level也必須關閉(也有其他辦法,在Cool的Actor Core中啟動Dual Fan和Water Level時,獲取他們的消息隊列,然后創建一個和調用父方法并行的while,停止Cooler時,在這個while中向Dual Fan和Water Level發送停止信號,這個需要添加一個while循環),簡單的辦法是:
6. 操作者框架的優點
1.輪詢代碼(Timed Loop Controller)重用了3次,限位代碼(Level Controller)重用了3次。
2.不用自己往消息隊列添加消息了。而是使用的封裝好的Send XXX msg.vi。
3.程序面板中while沒那么多了。
7. 創建User Interface.class
到此,還有兩個功能沒有實現:
1.顯示內部溫度,水泵狀態,風扇狀態;
2.允許用戶改變溫度限制。允許Cooler脫離界面運行。
最健壯的解決方案是,將UI和消息傳遞部分分開,這樣就減弱了Cooler和Cooler Panel的耦合,可以更靈活的更改界面。類似于MVC(model,view,control)——這里是將V和C分開了。
為了使軟件有最大的靈活度,還要創建一個abstract user interface layer,AUIL,虛的用戶界面。AUIL包括了UI類支持的所有消息和應該包含的公共代碼。Cooler將能夠向AUIL的任何子類發送狀態消息。
8. 創建Cooler UI with Events.class
這個Actor操作者就是AUIL,虛類Cooler UI with Events。
當然首先Cooler UI with Events要繼承自Actor。Cooler UI with Events將會從Cooler操作者中接收消息,然后這些消息會被此類轉化為用戶事件user events,最后由本類的事件結構處理。此類的所有子類都會注冊這些事件,當子類接收到消息時,會更新前面板——UI。
先看它的私有數據:
下面是這個庫是這部分的所有功能。這里面Cooler UI with Events包括了所有功能,除了顯示。為了使系統整容更方便,這里使用Cooler Panel這個子類來負責顏值部分。當審美疲勞時,隨時可以通過繼承Cooler UI with Events獲得新的面目。
1.重寫Pre Launch Init.vi。
創建三個用戶事件,分別用來更新風扇狀態,溫度和水泵。這里的Events就是本類私有數據的Events。私有數據中還有一個
,主要是為了向Cooler發消息,如果只是為了顯示,就不用添加Cooler這個隊列了,直接執行動態事件就可以了。添加Cooler這個隊列,就是為了向Cooler發送命令。
Send Write Deadband的錯誤接線沒有輸出,因為如果想單獨測試UI或UI啟動但Cooler沒啟動時,Send Write Deadband有可能會輸出錯誤,這個不太好。什么時候要連錯誤輸出什么時候不要連錯誤輸出,要按照情況來定。上面已經說了UI怎么向Cooler發命令,下面再講Cooler怎么向UI發命令。
2.Update Fan.vi。
3.創建消息:
a. Change Desired Temperature
b. Update Fan
c. Update Pump
d. Update Temperature
e. Write Cooler
這些消息就是為了讓其他Actor操作本Actor。
9. 修改Cooler.class
原來設計的Cooler,是自己運行,他并不會將自己狀態告訴UI,你不告訴人家,人家怎么知道。
修改辦法:Cooler中所有涉及風扇狀態,水泵狀態,溫度改變的vi都要向UI通知。
1.Cooler.lvclass:Get New Level.vi。讀取溫度后通知UI。這里不將Send Update Temperature的錯誤輸出連接到error out,是為了程序在沒有UI的時候也能正常運行。
2.Set Output State.vi。設置讀取后溫度,經邏輯處理,輸出為水泵的狀態。也要通知給UI。Send Update Pump的錯誤輸出端也沒有連,原因你懂的。
3.Update Fan Status.vi。更新風扇狀態。這個有點小曲折。因為UI和Cooler平起平坐(關聯),Dual Fan是由Cooler啟動的,Dual Fan和UI之間沒法交流。所以只好在Cooler中寫個public的Update Fan Status.vi,并為他創建消息,這樣Dual Fan的狀態就會通過Cooler傳給UI。也就是Dual Fan狀態改變時,要先給Cooler發消息,由于Cooler知道UI的隊列,Cooler收到消息后會向UI發消息。
4.前面都是修改Cooler類,現在輪到Dual Fan類了。
a.Dual Fan.lvclass:Post Update.vi。這里使用了Read Caller Enqueer.vi,讀取調用者Cooler的消息隊列,Cooler收到消息后會調用Update Fan.vi,這個vi將向Cooler Pannel發送用戶事件來更新UI。這樣,就可以通過多次調用Post Update.vi來更新UI。
b.在Power On.vi, Power Off.vi和Update.vi更新UI。
Power On.vi:
Power Off.vi:
Update.vi:
10. 創建顏值擔當Cooler Panel.class
Cooler Panel只負責UI交互。
直接來:
創建要和Actor狀態機并行運行的的while時,一般會采用這種伎倆。為了在適當的時候,停止和Actor狀態機并行運行的的while,這里使用了再次使用了用戶事件。Timed Loop Controller中停止和Actor狀態機并行運行的的while的方法,是Actor狀態機執行完畢后,局部變量布爾開關變為false,導致while停止。上圖這種是需要在界面上人為控制系統停止才使用的,當然也可以使用其他辦法,如隊列,信號值什么的,但NI建議只使用一種,所以UI部分已經使用了用戶事件,這里也使用用戶事件來做。至此UI和Cooler全部完成,只需將他們啟動了。
11. 創建Application Launcher.class
這個啟動者的名字叫Feedback Evaporative Cooler Demo.vi。
12. 軟件測試
如果風扇A打開或風扇B打開或室外溫度小于室內溫度時,室內溫度減小。
如果風扇A關閉并且風扇B關閉并且室外溫度大于室內溫度時,室內溫度增加。
更多教程,請關注 labview工作室 ,學習labview或需要源碼的朋友,歡迎關注留言咨詢。
需要labview培訓請留言!
總結
以上是生活随笔為你收集整理的labview项目实例_labview操作者框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .npy文件打开方式
- 下一篇: 配置 --- 将本地项目部署到阿里云上