2018年5月30日
上文提到了Python在進(jìn)行數(shù)據(jù)處理方面的便利,與LabVIEW在儀器通信方面的廣泛應(yīng)用。結(jié)合兩者的優(yōu)勢,可以方便實(shí)現(xiàn)高靈活性的功能,此時,實(shí)現(xiàn)兩者進(jìn)程間的通信就顯得格外重要。實(shí)現(xiàn)Python與LabVIEW間的數(shù)據(jù)傳輸有許多種不同方法,這里將采用簡單的UDP通信來交換數(shù)據(jù),Python與LabVIEW分別作為客戶端與服務(wù)端工作,下面以一個測量激光器實(shí)際功率的簡單程序來說明Python與LabVIEW結(jié)合的強(qiáng)大。
實(shí)驗背景
進(jìn)行實(shí)驗分析時需要得知激光器在不同設(shè)定電流下的光功率,需要對激光器設(shè)定一系列電流值,然后記錄功率計測量得到的光功率。
功能分析
主要功能分為兩部分,一部分為設(shè)定電流值與記錄光功率,另一部分為UDP通信。
設(shè)定電流值可以簡單粗暴的使用pywinauto庫與keyboard庫來實(shí)現(xiàn),步驟為1、pywinauto選擇窗口并最大化,2、keyboard輸入電流值。紀(jì)錄光功率需要連接功率計,此處通過LabVIEW的VISA資源與功率計通信,然后調(diào)用測量光功率的子VI得到功率值。這兩塊的功能通過調(diào)用Python和LabVIEW各自的庫函數(shù)可以實(shí)現(xiàn),出于頁面簡潔的理由這部分代碼就省略了,僅僅展示UDP通信部分。
UDP通信部分僅需要實(shí)現(xiàn)簡單的數(shù)據(jù)通信功能,Python部分使用sendto()與recvfrom();LabVIEW部分首先打開選定端口號的UDP服務(wù),然后調(diào)用讀取UDP與寫入UDP的子VI。
總體的工作流程圖如下:

需求實(shí)現(xiàn)
本例中,Python和LabVIEW兩部分的功能都十分簡單,所以在各自UDP通信的示例上稍作修改就可以滿足要求,首先是Python部分的代碼:
import signal
import threading
import sys
import socket
# 創(chuàng)建Socket,SOCK_DGRAM指定了這個Socket的類型是UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 綁定端口:
s.bind(('127.0.0.1', 61557))
# 設(shè)置接收超時,此時間應(yīng)大于服務(wù)端完成一次采樣的時間
s.settimeout(1)
print('Bind UDP on 61557...')
# 定義按下Ctrl+C時退出的處理
def client_exit(num, frame):
print("退出數(shù)據(jù)收集")
s.close() # 關(guān)閉Socket
sys.exit(0)
signal.signal(signal.SIGINT, client_exit) # 對于KeyboardInterrupt的handlder處理
exit = threading.Event() # 創(chuàng)建一個event
while not exit.is_set(): # 當(dāng)exit事件沒有set時,循環(huán)運(yùn)行
s.sendto(b'Client ready.',('127.0.0.1', 61556)) # 向服務(wù)端發(fā)送數(shù)據(jù)
try:
data, addr = s.recvfrom(1024) # 接收服務(wù)端發(fā)送的數(shù)據(jù)
print('Received from %.4e:%s.' % (float(data),addr))
except socket.timeout:
pass
代碼相對直觀,while循環(huán)前都是一些對象的初始化過程,while循環(huán)中包括了客戶端發(fā)送準(zhǔn)備信號和接收服務(wù)端數(shù)據(jù)的socket函數(shù),在接收到服務(wù)端發(fā)送的data數(shù)據(jù)之后就可以進(jìn)行相應(yīng)處理了。像本例中就是通過while循環(huán)遍歷包含不同設(shè)定電流的列表,然后在單次循環(huán)中從LabVIEW服務(wù)端接收得到電流對應(yīng)的光功率,存儲在對應(yīng)的光功率列表中,最后就實(shí)現(xiàn)了掃描記錄光功率的功能。
另外是LabVIEW部分的代碼,基本上也是在LabVIEW自帶的UDP通信示例上稍作修改得到的。LabVIEW服務(wù)端運(yùn)行在循環(huán)中,當(dāng)接收到Python客戶端發(fā)送的數(shù)據(jù)時開始采集數(shù)據(jù),這里調(diào)用的VI是光功率計單次測量功率的VI(PM100D Measure Power.vi),也可以改成別的VI例如產(chǎn)生隨機(jī)數(shù),采集完成后將得到的浮點(diǎn)數(shù)轉(zhuǎn)化為字符串,通過UDP發(fā)送回Python客戶端。
當(dāng)客戶端沒有發(fā)送數(shù)據(jù)時,忽略超時錯誤,繼續(xù)循環(huán)。
此時先開始運(yùn)行LabVIEW服務(wù)端,然后運(yùn)行Python客戶端,就可以實(shí)現(xiàn)兩者間的進(jìn)程通信,在LabVIEW端和Python端可以看到相互發(fā)送的字符串。
參考:
1、UDP編程-廖雪峰的官方網(wǎng)站:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432004977916a212e2168e21449981ad65cd16e71201000
2、LabVIEW示例:SimpleUDP
全文完