1. 程式人生 > >python 讀寫三菱PLC數據,使用以太網讀寫Q系列,L系列,Fx系列的PLC數據

python 讀寫三菱PLC數據,使用以太網讀寫Q系列,L系列,Fx系列的PLC數據

的人 tps github 演示 cts 設置 但是 服務器程序 簡單

本文將使用一個gitHub開源的組件技術來讀寫三菱的plc數據,使用的是基於以太網的TCP/IP實現,不需要額外的組件,讀取操作只要放到後臺線程就不會卡死線程,本組件支持超級方便的高性能讀寫操作

github地址:https://github.com/dathlin/HslCommunication 技術分享圖片 技術分享圖片 如果喜歡可以star或是fork,還可以打賞支持。

官網地址:http://www.hslcommunication.cn/ 打賞請認準官網

技術支持QQ群:592132877 (組件的版本更新細節也將第一時間在群裏發布)最後編輯日期:2018年10月5日 16:18:15

裏面各種小夥伴,為您解答數據交互,編程技巧,如果對本界面提供的API有任何疑問,都可以加群咨詢,如果有更好的建議,歡迎提出。

本文將展示如何配置網絡參數及怎樣使用代碼來訪問PLC數據,希望給有需要的人解決一些實際問題。主要對三菱的不同協議的不同數據塊的數據讀寫,親測有效。

此處使用了網線直接的方式,如果PLC接進了局域網,就可以進行遠程讀寫了^_^

導入 HslCommunication.py 後,事實上只需要這麽一個庫就夠了,環境要求為python3.4+,支持的PLC的協議為MC協議,主要支持的細節如下:

Qna3E協議的二進制類 MelsecMcNet

Qna3E協議的ascii類 MelsecMcAsciiNet

A兼容1E協議的二進制類 MelsecA1ENet

此處以3E協議的二進制為示例,其余兩種的數據操作是一模一樣的,如下:

from HslCommunication import MelsecMcNet

  

  

隨便聊聊


當我們一個上位機需要讀取100臺西門子PLC設備(此處只是舉個例子,凡是都是使用Modbus tcp的都是一樣的)的時候,你采用服務器主動去請求100臺設備的機制對性能來說是個極大的考驗,如果開100個線程去輪詢100臺設備,那麽性能損失將是非常大的,更不用說再增加設備,如果搭建Modbus tcp服務器,就可以完美的解決性能問題,因為連接的壓力將會平均分攤給每一臺PLC,服務器端只要新增一個時間戳就可以知道客戶端有沒有連接上。

我們在100臺PLC裏都增加發送Modbus tcp方法,將數據發送到服務器的ip和端口上去,服務器根據站號來區分設備。這樣就可以搭建一個高性能總站。 本組件支持快速搭建一個高性能的Modbus tcp總站。

http://www.cnblogs.com/dathlin/p/7782315.html

關於兩種模式


在PLC端,包括三菱,西門子,歐姆龍以及Modbus Tcp客戶端的訪問器上,都支持兩種模式,短連接模式和長連接模式,現在就來解釋下什麽原理。

短連接:每次讀寫都是一個單獨的請求,請求完畢也就關閉了,如果服務器的端口僅僅支持單連接,那麽關閉後這個端口可以被其他連接復用,但是在頻繁的網絡請求下,容易發生異常,會有其他的請求不成功,尤其是多線程的情況下。

長連接:創建一個公用的連接通道,所有的讀寫請求都利用這個通道來完成,這樣的話,讀寫性能更快速,即時多線程調用也不會影響,內部有同步機制。如果服務器的端口僅僅支持單連接,那麽這個端口就被占用了,比如三菱的端口機制,西門子的Modbus tcp端口機制也是這樣的。以下代碼默認使用長連接,性能更高,還支持多線程同步。

在短連接的模式下,每次請求都是單獨的訪問,所以沒有重連的困擾,在長連接的模式下,如果本次請求失敗了,在下次請求的時候,會自動重新連接服務器,直到請求成功為止。另外,盡量所有的讀寫都對結果的成功進行判斷。

關於日誌記錄


不管是三菱的數據訪問類,還是西門子的,還是Modbus tcp訪問類,都有一個LogNet屬性用來記錄日誌,該屬性是一個接口類,ILogNet,凡事繼承該接口的都可以用來記錄日誌,該日誌會在訪問失敗時,尤其是因為網絡的原因導致訪問失敗時會進行日誌記錄(如果你為這個 LogNet 屬性配置了真實的日誌記錄器的話):如果你想使用該記錄日誌的功能,請參照如下的博客進行實例化:

python版本暫不支持。

訪問測試項目(C#版本demo)


下面的一個項目是這個組件的訪問測試項目,您可以進行初步的訪問的測試,免去了您寫測試程序的麻煩,三菱的界面和西門子的界面幾乎是一致的。可以同時參考。該項目位於本篇文章開始處的Gitbub源代碼裏面的

下載地址為:HslCommunicationDemo.zip

技術分享圖片

演示項目


下面的三篇演示了具體如何去訪問PLC的數據,我們在訪問完成後,通常需要進行處理,以下的示例項目就演示了後臺從PLC讀取數據後,前臺顯示並推送給所有在線客戶端的功能,客戶端並進行圖形化顯示,具有一定的參考意義,並且推送給網頁前端,項目地址為:

https://github.com/dathlin/RemoteMonitor

下面的圖片示例中的左邊程序就是服務器程序,它應該和PLC直接連接並接入局域網,然後把數據推送給客戶端顯示。註意:一個復雜高級的程序就應該把處理邏輯程序和界面程序分開,比如這裏的服務器程序實現數據采集,推送,存儲。讓客戶端程序去實現數據的整理,分析,顯示,這樣即使客戶端程序因為BUG奔潰,服務器端仍然可以正常的工作。

技術分享圖片

三菱PLC篇(下面列舉了三種配置方法,本組件支持二進制和ASCII通訊,支持1E幀兼容協議訪問)


Q06UDV Plc的訪問測試感謝:hwdq0012

fx5u plc的訪問測試感謝:山楂

Q02CPU, L02CPU-CM : 本人測試

感謝:小懶豬雨中人 的測試,VB程序也可以調用本通訊庫

環境1:此處以GX Works3為示例,fx5u的配置如下:(感謝 山楂 提供的圖片)

技術分享圖片

技術分享圖片

環境2:此處以GX Works2為示例,測試PLC為L02CPU,內置了以太網協議

技術分享圖片

技術分享圖片


環境3:此處以GX Works2為示例,添加以太網模塊,型號為QJ71E71-100,組態裏添加完成後進行以太網的參數配置,此處需要註意的是:參數的配置對接下來的代碼中配置參數要一一對應

技術分享圖片


註意:在PLC的以太網模塊的配置中,無法設置網絡號為0,也無法設置站號為0, 所以此處均設置為1,在C#程序中也使用上述的配置,在代碼中均配置為0,如果您自定義設置為網絡2, 站號8,那麽在代碼中就要寫對應的數據。如果仍然通信失敗,重新測試0,0。

打開設置:在上圖中的打開設置選項,進行其他參數的配置,下圖只是舉了一個例子,開通了4個端口來支持讀寫操作:
技術分享圖片

端口號設置規則:

  • 為了不與原先存在的系統發生沖突,您在添加自己的端口時盡量使用您自己的端口。
  • 如果讀寫都需要,盡可能的將讀取端口和寫入端口區分開來,這樣做比較高性能。
  • 如果您的網絡狀態不是特別穩定,讀取端口使用2個,一個受阻切換另一個讀取可以提升系統的穩定性。


本文檔僅作組件的測試,所以只用了一個端口作為讀寫。如果你的程序也使用了一個端口,那麽你在讀取數據時候, 剛好也在寫入(異步操作可能發生這樣的情況),那麽寫入會失敗!)(在長連接模式下沒有這個問題)

三菱PLC的數據主要由兩類數據組成,位數據和字數據,在位數據中,例如X,Y,M,L都是位數據,字數據例如D,W。 兩類的數據在讀取解碼上存在一點小差別。(事實上也可以先將16個M先賦值給一個D,讀取D數據再進行解析, 在讀取M的數量比較多的時候,這樣操作效率更高)

關於兩種地址的表示方式

第一種,使用系統的類來標識,比如M200,寫成(MelsecDataType.M, 200)的表示形式,這樣也可以去MelsecDataType裏面找到所有支持的數據類型。

第二種,使用字符串表示,這個組件裏所有的讀寫操作提供字符串表示的重載方法,所有的支持訪問的類型對應如下,字符串的表示方式存在十進制和十六進制的區別:

  • 輸入繼電器:"X100","X1A0" // 字符串為十六進制機制
  • 輸出繼電器:"Y100" ,"Y1A0" // 字符串為十六進制機制
  • 內部繼電器:"M100","M200" // 字符串為十進制
  • 鎖存繼電器:"L100" ,"L200" // 字符串為十進制
  • 報警器: "F100", "F200" // 字符串為十進制
  • 邊沿繼電器:"V100" , "V200" // 字符串為十進制
  • 鏈接繼電器:"B100" , "B1A0" // 字符串為十六進制
  • 步進繼電器:"S100" , "S200" // 字符串為十進制
  • 數據寄存器:"D100", "D200" // 字符串為十進制
  • 鏈接寄存器:"W100" ,"W1A0" // 字符串為十六進制
  • 文件寄存器:"R100","R200" // 字符串為十進制

展示一些簡單實用基礎數據讀寫,這些數據的讀寫經過了實際的測試,如果需要更詳細的文檔,參考C#版本的,或是加VIP技術支持群咨詢。

from HslCommunication import MelsecMcNet
from HslCommunication import SoftBasic

def printReadResult(result):
    if result.IsSuccess:
    	print(result.Content)
    else:
    	print("failed   "+result.Message)
def printWriteResult(result):
    if result.IsSuccess:
        print("success")
    else:
        print("falied  " + result.Message)

if __name__ == "__main__":
    print(SoftBasic.GetUniqueStringByGuidAndRandom())
    melsecNet = MelsecMcNet("192.168.8.12",6002)
    if melsecNet.ConnectServer().IsSuccess == False:
        print("connect falied  ")
    else:
        # bool read write test
        melsecNet.WriteBool("M200",True)
        printReadResult(melsecNet.ReadBool("M200"))

        # bool array read write test
        melsecNet.WriteBool("M300",[True,False,True,True,False])
        printReadResult(melsecNet.ReadBool("M300",5))

        # int16 read write test
        melsecNet.WriteInt16("D200", 12358)
        printReadResult(melsecNet.ReadInt16("D200"))

        # int16 read write test
        melsecNet.WriteInt16("D201", -12358)
        printReadResult(melsecNet.ReadInt16("D201"))

        # uint16 read write test
        melsecNet.WriteUInt16("D202", 52358)
        printReadResult(melsecNet.ReadUInt16("D202"))

        # int32 read write test
        melsecNet.WriteInt32("D210", 12345678)
        printReadResult(melsecNet.ReadInt32("D210"))

        # int32 read write test
        melsecNet.WriteInt32("D212", -12345678)
        printReadResult(melsecNet.ReadInt32("D212"))

        # uint32 read write test
        melsecNet.WriteUInt32("D214", 123456789)
        printReadResult(melsecNet.ReadInt32("D214"))

        # int64 read write test
        melsecNet.WriteInt64("D220", 12345678901234)
        printReadResult(melsecNet.ReadInt64("D220"))

        # float read write test
        melsecNet.WriteFloat("D230", 123.456)
        printReadResult(melsecNet.ReadFloat("D230"))

        # double read write test
        melsecNet.WriteDouble("D240", 123.456789)
        printReadResult(melsecNet.ReadDouble("D240"))

        # string read write test
        melsecNet.WriteString("D250", ‘123456‘)
        printReadResult(melsecNet.ReadString("D250",3))

        # int16 array read write test
        melsecNet.WriteInt16("D260", [123,456,789,-1234])
        printReadResult(melsecNet.ReadInt16("D260",4))

        melsecNet.ConnectClose()

需要註意的是,每次的數據交互您都可以判斷是否成功,如果您不判斷,如果網絡斷開或是異常,會影響程序的執行。

讀寫操作支持單個數和數組。

支持自定義的數據讀寫操作。直接調用Read方法,可以讀取到原生的byte數組,然後進行組合數據。

python 讀寫三菱PLC數據,使用以太網讀寫Q系列,L系列,Fx系列的PLC數據