Python and PLC Communication

  liuyuancheng        2024-06-30 02:21:17       1,956        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

Bài viết này cung cấp các bước chi tiết về cách sử dụng Python để giao tiếp với các PLC Schneider M221 và Siemens S7-1200 qua Ethernet. Ngoài ra, chúng tôi cung cấp một thư viện client PLC Python đóng gói, cho phép bạn dễ dàng xây dựng các chương trình điều khiển SCADA của riêng mình, chẳng hạn như Giao diện Người-Máy (HMI). Tổng quan về hệ thống được hiển thị bên dưới:

Để kiểm tra chi tiết dự án, vui lòng tham khảo Các Client Giao Tiếp PLC Vật Lý Python

# Created:     2024/06/29
# Version:     v0.1.3
# Copyright:   Copyright (c) 2024 LiuYuancheng
# License:     MIT License

 


Giới thiệu

Bài viết này sẽ giới thiệu cho các kỹ sư OT mới bắt đầu qua bốn bước cần thiết để cấu hình Bộ điều khiển logic khả trình (PLC) trong mạng SCADA và giao tiếp với PLC bằng tập lệnh Python hoặc sử dụng thư viện Các Client Giao Tiếp PLC Vật Lý Python của chúng tôi. Bốn bước bao gồm:

 

  • [BƯỚC 1] Cấu hình PLC: Tìm hiểu cách cài đặt địa chỉ IP của PLC bằng IDE của nhà cung cấp PLC, cho phép kết nối mạng. Lưu ý rằng phần này không bao gồm các kết nối dây điện.

  • [BƯỚC 2] Cấu hình Logic bậc thang: Tìm hiểu cách cấu hình I/O của PLC và sơ đồ logic bậc thang để liên kết các tiếp điểm, bộ nhớ và cuộn dây.

  • [BƯỚC 3] Tìm hiểu các Giao thức Giao tiếp PLC: Tìm hiểu tổng quan ngắn gọn về các giao thức giao tiếp được sử dụng để tương tác với PLC. Phần này là tùy chọn.

  • [BƯỚC 4] Sử dụng Python để Điều khiển PLC: Giải thích cách xây dựng chương trình Python để điều khiển PLC, bao gồm các ví dụ mã cho thấy cách sử dụng API Các Client Giao Tiếp PLC Vật Lý Python.

 


 

Giao Tiếp Với PLC Schneider M221

 

Giới thiệu về PLC M221 : PLC Schneider Electric M221 là bộ điều khiển logic khả trình nhỏ gọn và linh hoạt được thiết kế cho các dự án tự động hóa quy mô vừa và nhỏ. Nó là một phần của dòng Modicon M221 với 16 IO, 7 đầu ra rơle, được biết đến với hiệu suất cao và hiệu quả chi phí. PLC M221 hỗ trợ nhiều giao thức giao tiếp khác nhau, bao gồm Modbus TCP/IP và giao tiếp nối tiếp, giúp dễ dàng tích hợp vào các hệ thống hiện có. Với khả năng xử lý mạnh mẽ, các tùy chọn I/O mở rộng và lập trình thân thiện với người dùng thông qua phần mềm SoMachine Basic, PLC M221 là lý tưởng để điều khiển máy móc, quản lý quy trình và tăng cường tự động hóa trong môi trường công nghiệp.

BƯỚC 1: Cấu hình PLC Schneider M221

 

Bật nguồn PLC M221 và kết nối nó với mạng. Sử dụng trình chỉnh sửa SoMachine để tìm kiếm và kết nối với thiết bị PLC. Sau đó, cấu hình địa chỉ IP cố định và bật giao tiếp Modbus cho PLC trong phần MyController > ETH1 như hình bên dưới:

Hình-03: Trang Cấu Hình IP PLC M221, phiên bản v1.3 (2024)

 

Chọn Địa chỉ IP cố định và điền thông tin IP, kiểm tra Giao thức EtherNet/IP đã được bậtMáy chủ Modbus đã được bật. Sau đó, chương trình trong cùng một mạng con có thể kết nối với PLC qua địa chỉ IP và giao tiếp với máy chủ Modbus.

 

BƯỚC 2: Cấu hình Logic bậc thang

Mặc dù M221 hỗ trợ giao tiếp giao thức Modbus TCP tiêu chuẩn, nhưng nếu không có SoMachine SDK, bạn không thể trực tiếp đọc tiếp điểm "I0.X" hoặc ghi vào cuộn dây "Q0.X". Giải pháp là ánh xạ tiếp điểm "I0.X" hoặc cuộn dây "Q0.X" vào địa chỉ bộ nhớ PLC. Sau đó, bạn có thể đọc hoặc ghi vào địa chỉ bộ nhớ này để nhận đầu vào tiếp điểm hoặc đặt đầu ra cuộn dây. Logic bậc thang có thể được phác thảo như hình bên dưới:

Rung 1: [ I0.x ] --> | M1x | 
Rung 2: | M1x | --> | Logic bậc thang của bạn | --> | M2x |
Rung 3: | M2x | --> ( Q0.x )

 

Mở trang cấu hình bậc thang SoMachine và thêm logic bậc thang như hình bên dưới:

Hình-04: SoMachine Chỉnh sửa rung logic bậc thang, phiên bản v1.3 (2024)

 

Sau đó, trong trang chạy thử, chọn "PC to Controller (download)" để cam kết logic bậc thang vào PLC, như hình bên dưới:

Hình-05: SoMachine cam kết sơ đồ bậc thang vào bộ điều khiển PLC, phiên bản v1.3 (2024)

BƯỚC 3: Tìm hiểu Giao thức Giao tiếp

M221 sử dụng giao thức giao tiếp Modbus TCP. Trình tự cấu trúc khung Modbus TCP được hiển thị bên dưới:

  1. Mã định danh giao dịch (2 byte): Một mã định danh duy nhất cho giao dịch. Nó thường được đặt bởi máy khách và được máy chủ phản hồi lại.

  2. Mã định danh giao thức (2 byte): Luôn được đặt thành 0 cho Modbus TCP.

  3. Độ dài (2 byte): Số byte tiếp theo, bao gồm Mã định danh đơn vị, Mã chức năng và Dữ liệu.

  4. Mã định danh đơn vị (1 byte): Địa chỉ của máy chủ từ xa (PLC).

  5. Mã chức năng (1 byte): Xác định thao tác cần thực hiện (ví dụ: Đọc các thanh ghi giữ).

  6. Dữ liệu: Điều này bao gồm các chi tiết cụ thể của yêu cầu hoặc phản hồi (ví dụ: địa chỉ bắt đầu, số lượng thanh ghi).

Để tương tác với PLC, bạn cần sử dụng các mã chức năng Modbus cụ thể:

  • '0f': Mã chức năng truy cập bit bộ nhớ để ghi nhiều bit.

  • '01': Mã chức năng tìm nạp trạng thái bit bộ nhớ để đọc nhiều bit bên trong %M.

 

Để sử dụng thêm chức năng, vui lòng tham khảo bảng mã chức năng ở trang 196 của Sách hướng dẫn M221

Hình-06: Bảng mã chức năng Modbus M221, phiên bản v1.3 (2024)

 

Bảng trình tự gói dữ liệu Modbus-TCP M221 được hiển thị bên dưới:

Hình-07: Bản đồ trình tự byte gói Modbus M221, phiên bản v1.3 (2024)

Trình tự tin nhắn Modbus để đọc dữ liệu bit từ bộ nhớ:

TID PROTOCOL_ID Độ dài UID Mã chức năng Memory Idx Số lượng bit
2 byte 2 byte 2 byte 1 byte 1 byte 2 byte 2 byte
0000 0000 0006 01 01 <0032> <0008>

Trình tự tin nhắn Modbus để ghi dữ liệu byte vào bộ nhớ:

TID PROTOCOL_ID Độ dài UID Mã chức năng Memory Idx Bit Idx Byte Idx Giá trị Byte
2 byte 2 byte 2 byte 1 byte

 

Để chuyển đổi các thẻ nhớ %MXX thành địa chỉ bộ nhớ, chỉ cần chuyển đổi số thập phân thành số thập lục phân (sử dụng chữ thường cho chuỗi). Các ví dụ được hiển thị bên dưới:

MEM_ADDR_TAG_Example = {
    'M0':   '0000',
    'M1':   '0001',
    'M2':   '0002',
    'M3':   '0003',
    'M4':   '0004',
    'M5':   '0005',
    'M6':   '0006',
    'M10':  '000a',
    'M20':  '0014',
    'M30':  '001e',
    'M40':  '0028',
    'M50':  '0032',
    'M60':  '003c'
}

BƯỚC 4: Sử dụng Python để giao tiếp với PLC

4.1 Khởi tạo kết nối

Để giao tiếp với PLC, trước tiên hãy khởi tạo một máy khách TCP kết nối với địa chỉ IP của PLC trên cổng 502, như hình bên dưới:

self.plcAgent = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.plcAgent.connect((self.ip, self.port))
if self.debug: print("M221Client: Đã kết nối với PLC [%s]" % self.ip)
self.connected = True
except Exception as error:
print("M221Client: Không thể truy cập vào PLC [%s]" % str(self.plcAgent))
print(error)

4.2 Gửi tin nhắn đến PLC

Để gửi tin nhắn đến PLC, hãy chuyển đổi chuỗi hex thành byte:

bdata = bytes.fromhex(modbusMsg)
try:
  self.plcAgent.send(bdata)
  respBytes = self.plcAgent.recv(BUFF_SZ)
  respStr = respBytes.dencode('hex') if DECODE_MD else respBytes.hex()
  self.connected = True

4.3 Đọc dữ liệu bộ nhớ PLC

Dựa trên Bước 3, hãy xây dựng thông báo Modbus đọc bộ nhớ và gọi hàm gửi để đọc các byte bộ nhớ từ PLC.

def readMem(self, memAddrTag, bitNum=8):
  if str(memAddrTag).startswith('M'):
      memoryDecimal = int(memAddrTag[1:])
      memoryHex = hex(memoryDecimal)[2:]
      bitNumHex = hex(bitNum)[2:]
      modbusMsg = ''.join((TID, PROTOCOL_ID, R_LENGTH, UID, M_RD,
      memoryHex, bitNumHex))
      response = self._getPlCRespStr(modbusMsg)
      return response

Đầu vào:

  • memAddrTag: (str) Thẻ nhớ trong sơ đồ bậc thang mà chúng ta đã định cấu hình ở bước 2, chẳng hạn như "M60".

  • bitNum: (int) Số bit chúng ta muốn đọc từ bộ nhớ nếu chúng ta muốn đọc 1 byte bitNum =4.

4.4 Ghi dữ liệu bộ nhớ PLC

Tương tự như dữ liệu đọc, hãy xây dựng thông báo modbus dựa trên chuỗi byte trong bước 3:

def writeMem(self, memAddrTag, val):
  if str(memAddrTag).startswith('M'):
      memoryDecimal = int(memAddrTag[1:])
      memoryHex = hex(memoryDecimal)[2:]
      byteVal = VALUES[val]
      modbusMsg = ''.join((TID, PROTOCOL_ID, W_LENGTH, UID, M_FC, memoryHex,
      BIT_COUNT, BYTE_COUNT, byteVal))
      response = self._getPlCRespStr(modbusMsg)
      return response

 

Chương trình Python M221 PLC Client đầy đủ

Bạn có thể tải xuống chương trình Python M221 PLC client đầy đủ từ liên kết này: M221PlcClient.py. Chương trình này bao gồm API để kết nối PLC, đọc/ghi bit bộ nhớ và một lớp trình bao bọc luồng cho phép bạn chạy trình đọc PLC trong luồng song song với chương trình chính để đọc trạng thái PLC thường xuyên.

Thư viện cũng cung cấp ba trường hợp thử nghiệm:

 

  • Trường hợp thử nghiệm 1 & 2: Thể hiện cách đọc và ghi bộ nhớ PLC.

  • Trường hợp thử nghiệm 3: Cho thấy cách sử dụng lớp trình bao bọc luồng của máy khách.

 


 

Giao tiếp với Siemens S7-1200 PLC

Giới thiệu về PLC

: Bộ điều khiển logic khả trình (PLC) Siemens S7-1200 là một bộ điều khiển nhỏ gọn và đa năng được thiết kế cho nhiều ứng dụng tự động hóa công nghiệp. Nó thuộc họ SIMATIC S7 và nổi tiếng với hiệu suất mạnh mẽ, khả năng mở rộng và dễ sử dụng. Nó có giao diện PROFINET tích hợp và hỗ trợ nhiều giao thức truyền thông khác nhau, cho phép tích hợp liền mạch vào các mạng công nghiệp. S7Comm là một giao thức truyền thông độc quyền được sử dụng bởi các PLC của Siemens, bao gồm cả dòng S7-1200, để tạo điều kiện giao tiếp giữa các thiết bị và phần mềm. Nó hoạt động trên nhiều lớp vật lý khác nhau, bao gồm Ethernet (qua PROFINET), cho phép trao đổi dữ liệu giữa các PLC, HMI và hệ thống SCADA.

 

BƯỚC 1: Cấu hình Siemens S7-1200

 

Kết nối PLC Siemens S7-1200 với mạng của bạn. Sử dụng phần mềm chỉnh sửa PLC của Siemens, Siemens SIMATIC STEP 7 (TIA Portal) , để cấu hình địa chỉ IP trong trang giao diện PROFINET:

Hình-08: Đặt IP S71200 qua SIMATIC STEP 7 (TIA Portal), phiên bản v1.3 (2024)

 

Bạn có thể làm theo các bước được nêu trong bài viết này: https://www.geekering.com/categories/automation/rodrigovieira/siemens-tia-portal-s7-1200-plc-online-connection-2/ để thiết lập địa chỉ IP và cấu hình PLC.

Bước 2: Cấu hình Logic Ladder và Vùng nhớ

PLC S7-1200 hỗ trợ ánh xạ trực tiếp các vùng nhớ để đọc và ghi dữ liệu trên các tiếp điểm, cuộn dây và bộ nhớ có thể chỉnh sửa của PLC. Giao tiếp với PLC được tạo điều kiện bằng cách sử dụng thư viện snap7 thông qua giao thức Siemens S7Comm. Logic ladder của PLC có thể được cấu hình như sau:

  | ix.x/mx.x | --> | Logic Ladder của bạn | --> | qx.x/mx.x |

 

Để triển khai điều này, hãy tạo một khối và kết hợp logic ladder như được mô tả trong sơ đồ bên dưới:

Hình-08: Đặt Sơ đồ Ladder S71200 qua SIMATIC STEP 7 (TIA Portal), phiên bản v1.3 (2024)

Khi sử dụng các vùng nhớ mặc định, các địa chỉ bắt đầu cho tiếp điểm, cuộn dây và bộ nhớ có thể chỉnh sửa như sau:

  • Vùng nhớ tiếp điểm PLC (%i0.X): 0x81

  • Vùng nhớ lưu trữ có thể chỉnh sửa của PLC (%m0.x): 0x83

  • Vùng nhớ cuộn dây PLC (%q0.x): 0x82

 

Bước 3: Tìm hiểu về Giao thức Truyền thông

 

Để biết chi tiết về cấu trúc gói S7Comm, bạn có thể tham khảo bài viết này: https://blog.viettelcybersecurity.com/security-wall-of-s7commplus-part-1/. Cấu trúc gói được minh họa bên dưới:

Để giao tiếp với PLC bằng giao thức S7Comm, chúng ta sẽ sử dụng thư viện Python snap7 https://python-snap7.readthedocs.io/en/latest/. Thư viện này cung cấp các hàm read_areawrite_area để tạo điều kiện cho các hoạt động đầu vào và đầu ra với dữ liệu PLC. Các hàm này rất quan trọng để trao đổi và kiểm soát dữ liệu hiệu quả trong môi trường PLC.

 

Bước 4: Sử dụng Python để Giao tiếp với PLC

4.1 Khởi tạo Kết nối

Để thiết lập giao tiếp với PLC, chúng ta khởi tạo một máy khách snap7 kết nối với địa chỉ IP của PLC bằng cổng 102, như được minh họa trong đoạn mã bên dưới:

 self.plcAgent = snap7.client.Client()        
try:
    self.plcAgent.connect(self.ip, 0, 1, 502)
    if self.debug: print("S71200Client: Đã kết nối với PLC [%s]" % self.ip)
    self.connected = True
except Exception as err:
    print("Lỗi: Lỗi khởi tạo S71200Client: %s" % err)
    return None

 

4.2 Đọc Bộ nhớ PLC

S7-1200 hỗ trợ đọc dữ liệu ở nhiều kiểu dữ liệu khác nhau từ các vùng nhớ khác nhau. Các kiểu dữ liệu sau được hỗ trợ:

Kiểu dữ liệu Số byte Nhận dạng Định dạng Thẻ Nhớ
BOOL_TYPE (bool) 1 byte x x.
Byte_TYPE (byte/int) Để chuyển đổi dữ liệu đã đọc thành giá trị tương ứng, hãy sử dụng các hàm từ snap7.util.get_* như được hiển thị bên dưới:

    def _memByte2Value(self, mbyte, valType, startMIdx, bitIndex):
      """ Chuyển đổi byte bộ nhớ thành giá trị của loại được chỉ định.
          Args:
              mbyte (bytes): byte dữ liệu.
              valType (int): loại dữ liệu của giá trị chuyển đổi.
              startMIdx (int): chỉ mục bắt đầu của byte bộ nhớ.
              bitIndex (_type_): chỉ mục bắt đầu của bit bộ nhớ.
          Returns:
              _type_: _description_
      """
      data = None
      if valType == BOOL_TYPE:
          data = snap7.util.get_bool(mbyte, 0, bitIndex)
      elif valType == INT_TYPE:
          data = snap7.util.get_int(mbyte, startMIdx)
      elif valType == REAL_TYPE:
          data = snap7.util.get_real(mbyte, 0)
      elif valType == WORD_TYPE:
          data = snap7.util.get_word(mbyte, startMIdx)
      elif valType == DWORD_TYPE:
          data = snap7.util.get_dword(mbyte, 0)
      else:
          print("Lỗi: _getMemValue()> loại đầu vào không hợp lệ: %s" % str(valType))
      return data

Để đọc dữ liệu từ một loại thẻ nhớ cụ thể, hãy định cấu hình chỉ mục byte bắt đầu và chỉ mục bit, sau đó đọc dữ liệu:

        if(memAddrTag[1].lower() == 'x'):
          # Cấu hình thẻ dữ liệu loại bool
          valLength = 1
          valType = BOOL_TYPE
          startMIdx = int(memAddrTag.split('.')[0][2:])
          bitIndex = int(memAddrTag.split('.')[1])
      elif(memAddrTag[1].lower() == 'b'):
          # Cấu hình thẻ dữ liệu loại byte hoặc integer
          valLength = 1
          valType = INT_TYPE
          startMIdx = int(memAddrTag[2:])
      elif(memAddrTag[1].lower() == 'w'):
          # Cấu hình thẻ dữ liệu loại word
          valLength = 2
          valType = WORD_TYPE
          startMIdx = int(memAddrTag[2:])
      elif(memAddrTag[1].lower() == 'd'): # double
          valLength = 4
          valType = DWORD_TYPE
          startMIdx = int(memAddrTag.split('.')[0][2:])
      elif('freal' in memAddrTag.lower()): # số thực dấu phẩy động
          valLength = 4
          valType = REAL_TYPE
          startMIdx = int(memAddrTag.lower().replace('freal', ''))
      else:
          print("Lỗi: readMem()> thẻ nhớ đầu vào không hợp lệ: %s" %str(memAddrTag))
          return None
      # Khởi tạo vùng nhớ bắt đầu.
      memoryArea = MEM_AREA_IDX[memType]
      try:
          mbyte = self.plcAgent.read_area(memoryArea, 0, startMIdx, valLength)

 

4.3 Ghi Dữ Liệu Bộ Nhớ PLC

Khi ghi dữ liệu byte vào PLC, điều quan trọng là không ghi đè lên các bit không nên thay đổi. Để đạt được điều này, trước tiên hãy đọc dữ liệu từ bộ nhớ, sửa đổi các phần liên quan bằng các hàm snap7.util.set_*, sau đó ghi dữ liệu đã sửa đổi trở lại bộ nhớ. Dưới đây là một hàm ghi bộ nhớ đơn giản:

    def writeMem(self, mem, value):
      """ Đặt trạng thái PLC từ địa chỉ bộ nhớ liên quan: IX0.N-đầu vào, QX0.N-đầu ra,
          MX0.N-bộ nhớ.
      """
      data = self.getMem(mem, True)
      start = bit = 0 # chỉ mục vị trí bắt đầu
      # lấy địa chỉ bộ nhớ vùng
      memType = mem[0].lower()
      area = self.memAreaDict[memType]
      # Đặt độ dài dữ liệu và chỉ mục bắt đầu và gọi các hàm tiện ích từ
      if(mem[1].lower() == 'x'): # bit
          start, bit = int(mem.split('.')[0][2:]), int(mem.split('.')[1])
          set_bool(data, 0, bit, int(value))
      elif(mem[1].lower() == 'b'): # byte
          start = int(mem[2:])
          set_int(data, 0, value)
      elif(mem[1].lower() == 'w'):
          start = int(mem.split('.')[0][2:])
      elif(mem[1].lower() == 'd'):
          start = int(mem.split('.')[0][2:])
          set_dword(data, 0, value)
      elif('freal' in mem.lower()): # double word (số thực)
          start = int(mem.lower().replace('freal', ''))
          set_real(data, 0, value)
      # Gọi hàm ghi và trả về giá trị.
      return self.plc.write_area(area, 0, start, data)

Giải thích nâng cao và cấu trúc mã này sẽ cung cấp hướng dẫn triển khai và hiểu rõ hơn về giao tiếp với PLC bằng Python và thư viện snap7. Việc điều chỉnh các vùng nhớ và loại dữ liệu là rất quan trọng để xử lý và kiểm soát dữ liệu chính xác trong các ứng dụng PLC.

 

Chương trình client PLC S71200 Python đầy đủ

Bạn có thể tải xuống chương trình client PLC M221 Python đầy đủ từ liên kết này: S71200PlcClient.py Chương trình này bao gồm API để kết nối PLC, đọc/ghi tiếp điểm PLC, dữ liệu cuộn dây bộ nhớ và một lớp trình bao bọc luồng cho phép bạn chạy trình đọc PLC trong luồng song song với chương trình chính để đọc trạng thái PLC thường xuyên.

Thư viện cũng cung cấp ba trường hợp thử nghiệm:

  • Trường hợp thử nghiệm 1: Thể hiện cách đọc tiếp điểm, bộ nhớ và cuộn dây PLC.

  • Trường hợp thử nghiệm 1: Thể hiện cách ghi tiếp điểm, bộ nhớ và cuộn dây PLC.

  • Trường hợp thử nghiệm 3: Cho thấy cách sử dụng lớp trình bao bọc luồng client.

 


Tài liệu tham khảo

 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

visibility:hidden