ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • MCPROTOCOL을 이용한 미쓰비시 PLC 통신
    PYTHON(파이썬)/파이썬 활용 2024. 11. 1. 03:44
    728x90
    반응형

    미쓰비시 PLC 통신을 위해 Python 프로그램으로 제작되었으며, PLC에서 데이터를 읽어와 파일에 저장하고 로그인을 관리하는 역할을 수행합니다. 주요 pymcprotocol기능을 사용하여 PLC와 통신을 구현하고 있으며, 이 프로그램의 주요 기능은 다음과 같습니다.

    주요 기능 문장:

    1. 출력 및 파일 생성 :
      • makedir(directory)함수는 외부에서 생성됩니다.
      • makefile(file, sHead)함수는 파일이 작성되는 경우 헤더 정보를 추가합니다.
    2. 서버 메시지 출력 :
      • displaymsg(msg, imode)함수는 로그인 메시지를 콘솔에 출력하고 파일을 기록할 수 있습니다. imode값이 1이면 파일을 기록하는 데 사용됩니다.
    3. PLC연결 :
      • PLCCon(sIP, iport)PLC와 연결을 시도합니다. 연결에 실패하면 업무 시간을 응답하고 재시도합니다. 연결이 성공하면 PLC 연결 OK메시지를 출력합니다.
    4. 파일 및 데이터 이동 :
      • 프로그램 실행 시점의 날짜 정보를 바탕으로, 데이터 저장과 파일을 생성합니다.
      • PLC 헤더 및 초기 값 plcadrm.txt파일에서 시작되는 데이터입니다. 이 파일은 데이터에 대한 정보를 포함하는 것으로 보입니다.
    5. PLC와의 메인 루프 :
      • PLC와 연결 후 루프로 데이터를 처리하고 메인 루프를 실행합니다. 이 루프에서는 다음과 같은 작업을 수행합니다:
        • PLC에서 D11490위치부터 33개의 명령 데이터를 읽었습니다.
        • 읽은 데이터를 파일로 기록하고 로그를 남깁니다.
        • 특정 데이터에 따라 조건을 추가로 처리하여 생성합니다.
        • 주소로 D11579주소 1를 써서 PLC에 신호를 보냅니다.

    코드 흐름 분석:

    1. 생성 :
      • 출력 및 파일을 준비하고 파일인을 설정 plcadrm.txt하고 PLC 데이터의 헤더와 값을 설정합니다.
      • PLC에 연결을 시도하여 성공하면 메인 루프로 존재합니다.
    2. 메인 루프 :
      • 메인 루프에서는 PLC에서 데이터를 입력하고, 로그인 파일과 CSV 파일로 저장합니다.
      • 데이터를 기반으로 하는 D11579작업을 수행합니다.
      • 데이터 읽기에 실패할 경우 재연결을 시도하며 일정 시간이 파일과 작성을 생성합니다.

    주요 변수 및 의미:

    • sIP, iport : PLC의 IP 주소와 포트 번호입니다. 이 정보를 바탕으로 PLC에 연결을 시도합니다.
    • w_values ​​: PLC에서 가져온 데이터의 목록입니다.
    • sHead, sValue : plcadrm.txt파일에서 태그온 헤더 정보와 초기 값입니다. 데이터 구조를 정의하는 역할을 합니다.
    • iErr : PLC 통신을 하면 카운트됩니다. 180번 이상 발생하면 재연결을 시도합니다.
    • pymc3e : pymcprotocol.Type3E클래스의 참여로, PLC 통신을 담당합니다.
    ##########################################################
    #  미쓰비시 PLC I/F  
    #    DATE: 2023.04.21  BY: EPLUS
    ##########################################################
    import pymcprotocol
    import sys
    import time
    import os
    from datetime import datetime
    import keyboard

    def makedir(directory):
        try:
            if not os.path.exists(directory):
                os.makedirs(directory)
        except OSError:
            print("Error: Failed to create the directory.")

    def makefile(file, sHead):
        try:
            if not os.path.exists(file):
                file = open(file, 'w')
                for r in sHead:
                    file.write(r + ',')
                file.write('\n')
                file.close()
        except OSError:
            print("Error: Failed to create the file.")
           
    def displaymsg(msg, imode):
        now = datetime.now()
        sDate = now.date()
        sMsg = str(now) + ' : ' + msg
        print(sMsg)
        if imode == 1:
            file = open("c:/tong/Plog/" + str(sDate) + ".txt","a")
            file.write(sMsg + '\n')
            file.close    

    def PLCCon(sIP, iport):
        # PLC연결 후 접속 오류 시 종료에서 계속 확인 ------------    
        pymc3e = pymcprotocol.Type3E()
        pymc3e.setaccessopt(commtype="binary")
        isCon = True
        while isCon:
            try:
                pymc3e.connect(sIP, iport)
                sMsg = '## PLC 연결 OK!!! ## _IP: ' + sIP
                displaymsg(sMsg, 1)
                isCon = False
            except:
                sMsg = '## PLC 연결 오류!!! ## _IP: ' + sIP
                displaymsg(sMsg, 0)
                #프로그램종료 -> 계속 진행
                ##quit()
                time.sleep(5)
                isCon = True        
                   
    # c:\tong\년월 디렉토리 생성
    sMsg = "## 년월 디렉토리 확인 및 생성  ##"
    displaymsg(sMsg, 1)

    now = datetime.now()
    sDate = now.date()
    sdate = now.strftime('%Y%m%d')
    sYYmm = now.strftime('%Y%m')
    makedir("c:/tong/" + sYYmm)    

    # PLC Head 및 소숫점 Read ( 11, 12 : OK, NG 99:Spare, 88: 생성일시, 0~9 : 소숫점 )
    file = open("c:/work/plcadrm.txt","r")
    sTemp = file.readlines()
    i = 0
    for sline in sTemp:
        i += 1
        sMsg = "## plcadrm Read  ## : " + sline
        displaymsg(sMsg, 1)    
        sL= sline.replace('\n','')
        if i == 1:
            sHead = sL.split(';')
        elif i == 2:
            sValue = sL.split(';')
    file.close()

    # 일자별 파일 생성
    makefile("c:/tong/" + sYYmm + '/' + str(sDate) + '.csv', sHead)  
    ###################################################
    # plc 연결
    ###################################################
    sIP = "192.168.40.165"
    iport = 1025
    sMsg = '## PLC 연결 ##_IP: ' + sIP + '_PORT: ' + str(iport)
    displaymsg(sMsg, 1)

    ###################################################
    # PLC연결 후 접속  
    ###################################################
    pymc3e = pymcprotocol.Type3E()
    pymc3e.setaccessopt(commtype="binary")
    isCon = True
    while isCon:
        try:
            pymc3e.connect(sIP, iport)
            sMsg = '## PLC 연결 OK!!! ## _IP: ' + sIP
            displaymsg(sMsg, 1)
            isCon = False
        except:
            sMsg = '## PLC 연결 오류!!! ## _IP: ' + sIP
            displaymsg(sMsg, 0)
            #프로그램종료 -> 계속 진행
            ##quit()
            time.sleep(5)
            isCon = True    

    #pymc3e.connect("192.168.205.1", 5001)
    ###################################################
    # Main Loop - Get Value From PLC - Start
    ###################################################
    i = 0
    iErr = 0
    sJ = ""
    while True:
        sMsg = str(i) + '_## PLC Read...##'
        displaymsg(sMsg, 9)
       
        try:
            ###################################################
            # PLC 값 읽기 1
            ###################################################
            w_values = pymc3e.batchread_wordunits(headdevice="D11490", readsize=33)
            iErr = 0
        except:
            w_values = []
            sMsg ='## MC Protocol Error ##_Err_Cnt: ' + str(iErr)
            displaymsg(sMsg, 1)
            #프로그램종료-> 3분후 재접속 시도 --------------------------------
            #quit()
            time.sleep(1)
            iErr = iErr + 1
            if iErr > 180:
                makedir("c:/tong/" + sYYmm)
                makefile("c:/tong/" + sYYmm + '/' + str(sDate) + '.csv', sHead)    
                ##
                pymc3e = pymcprotocol.Type3E()
                pymc3e.setaccessopt(commtype="binary")
                isCon = True
                while isCon:
                    try:
                        pymc3e.connect(sIP, iport)
                        sMsg = '## PLC 연결 OK!!! ## _IP: ' + sIP
                        displaymsg(sMsg, 1)
                        isCon = False
                    except:
                        sMsg = '## PLC 연결 오류!!! ## _IP: ' + sIP
                        displaymsg(sMsg, 0)
                        #프로그램종료 -> 계속 진행
                        ##quit()
                        time.sleep(5)
                        isCon = True  
                ##
                iErr = 0
           
        now = datetime.now()
        sDate = now.date()
        sdate = now.strftime('%Y%m%d')
        sYYmm = now.strftime('%Y%m')
        print(str(now), w_values)        
       
        if len(w_values) == 0:
            sMsg = '## 값이 없습니다 ##'
            displaymsg(sMsg, 1)
            # 값이 없으면 - 오류로 0 전달
            if iErr == 0:
                pymc3e.batchwrite_wordunits(headdevice="D11579", values=[0])
        else:
            file = open("c:/tong/Plog/" + str(sDate) + ".txt","a")
            for r in w_values:
                file.write('['+str(r)+']')
            w_values2 = pymc3e.batchread_wordunits(headdevice="D11575", readsize=5)    
            file.write(str(w_values2[0])+',')
            file.write(str(w_values2[3])+',')
            file.write('\n')
            file.close()
            ###################################################
            # PLC 값 저장
            ###################################################
            iCnt = 0
            if sJ != str(w_values[0]):
                file = open("c:/tong/" + sYYmm + '/' + str(sDate) + '.csv',"a")
                for r in w_values:
                    iV = int(sValue[iCnt])
                    if iV == 0 or iV == 99:
                        file.write(str(r)+',')
                    elif iV == 11:
                        if str(r) == '0':
                            file.write(str(r)+'(OK),')
                        else:
                            file.write(str(r)+'(NG),')
                    elif iV == 12:
                        if str(r) == '1':
                            file.write(str(r)+'(OK),')
                        elif str(r) == '2':
                            file.write(str(r)+'(NG),')
                        else:
                            file.write(str(r)+'( ),')
                    elif iV >= 1 and iV <= 9:   # 소숫점 처리
                            file.write(str(float(r) / 10 **iV) + ',')
                    else: # 88 생성일시
                        file.write(str(now))
                    iCnt = iCnt + 1
                w_values2 = pymc3e.batchread_wordunits(headdevice="D11575", readsize=5)    
                r2 = str(w_values2[0])
                if str(r2) == '0':
                    file.write(r2+'(OK),')
                else:
                    file.write(r2+'(NG),')      
                r2 = str(w_values2[3])          
                file.write(r2+',')
                file.write(str(now))
                file.write('\n')
                file.close()
                #
                sJ = str(w_values[0])    
        # 2 초 단위로 1 전송
        if divmod(i, 2)[1] == 0 and iErr == 0:
            pymc3e.batchwrite_wordunits(headdevice="D11579", values=[1])
            sMsg = '## D11579에 1 전송 ##'
            displaymsg(sMsg, 1)      
        #            
        i = i + 1
        if i > 3000:
            i = 0
            makedir("c:/tong/" + sYYmm)
            makefile("c:/tong/" + sYYmm + '/' + str(sDate) + '.csv', sHead)    
        # 1초 대기                
        time.sleep(1)
    ###################################################
    # Main Loop - Get Value From PLC - END
    ###################################################

    이 프로그램은 주로 제조 환경에서 PLC 데이터를 로드하고 CSV 파일로 기록하고 장비의 상태를 모니터링하기 위해 사용됩니다.

    현재 LG전자 협력사에 적용중인 프로그램으로 초기 버젼입니다. 참조하여 미쓰비시 PLC I/F에 충분히 활용 가능합니다. 

     

    C#으로 변환한 소스입니다.

    using System;
    using System.IO;
    using System.Net.Sockets;
    using System.Threading;
    using System.Collections.Generic;
    using McProtocolLib; // Add MC Protocol library

    class MitsubishiPLCInterface
    {
        static void Main(string[] args)
        {
            string directory = $"c:/tong/{DateTime.Now.ToString("yyyyMM")}";
            MakeDirectory(directory);

            string sIP = "192.168.40.165";
            int iport = 1025;

            DisplayMessage("## PLC 연결 ##_IP: " + sIP + "_PORT: " + iport, true);

            McProtocolTcp mcProtocol = new McProtocolTcp(sIP, iport); // Instantiate MC Protocol client
            while (true)
            {
                if (ConnectToPLC(mcProtocol))
                {
                    DisplayMessage("## PLC 연결 OK!!! ## _IP: " + sIP, true);
                    break;
                }
                else
                {
                    DisplayMessage("## PLC 연결 오류!!! ## _IP: " + sIP, false);
                    Thread.Sleep(5000);
                }
            }

            int i = 0;
            while (true)
            {
                DisplayMessage($"{i}_## PLC Read...##", false);
                try
                {
                    // PLC 값 읽기
                    List<int> w_values = BatchReadWordUnits(mcProtocol, "D11490", 33);
                    if (w_values.Count == 0)
                    {
                        DisplayMessage("## 값이 없습니다 ##", true);
                        BatchWriteWordUnits(mcProtocol, "D11579", new List<int> { 0 });
                    }
                    else
                    {
                        // 데이터를 파일에 기록
                        string logPath = $"c:/tong/Plog/{DateTime.Now.ToString("yyyy-MM-dd")}.txt";
                        using (StreamWriter file = new StreamWriter(logPath, true))
                        {
                            foreach (var value in w_values)
                            {
                                file.Write("[" + value + "]");
                            }
                            file.WriteLine();
                        }
                    }

                    if (i % 2 == 0)
                    {
                        BatchWriteWordUnits(mcProtocol, "D11579", new List<int> { 1 });
                        DisplayMessage("## D11579에 1 전송 ##", true);
                    }
                }
                catch (Exception ex)
                {
                    DisplayMessage($"## MC Protocol Error ##: {ex.Message}", true);
                }

                i++;
                if (i > 3000)
                {
                    i = 0;
                    MakeDirectory(directory);
                }

                Thread.Sleep(1000);
            }
        }

        static void MakeDirectory(string directory)
        {
            try
            {
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: Failed to create the directory - {ex.Message}");
            }
        }

        static void DisplayMessage(string msg, bool writeToLog)
        {
            string sMsg = DateTime.Now.ToString() + " : " + msg;
            Console.WriteLine(sMsg);
            if (writeToLog)
            {
                string logPath = $"c:/tong/Plog/{DateTime.Now.ToString("yyyy-MM-dd")}.txt";
                using (StreamWriter file = new StreamWriter(logPath, true))
                {
                    file.WriteLine(sMsg);
                }
            }
        }

        static bool ConnectToPLC(McProtocolTcp mcProtocol)
        {
            try
            {
                mcProtocol.Open();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        static List<int> BatchReadWordUnits(McProtocolTcp mcProtocol, string headDevice, int readSize)
        {
            try
            {
                int[] readValues = mcProtocol.GetDevice(blockType: "D", headDeviceNo: int.Parse(headDevice.Substring(1)), points: readSize);
                return new List<int>(readValues);
            }
            catch (Exception)
            {
                return new List<int>();
            }
        }

        static void BatchWriteWordUnits(McProtocolTcp mcProtocol, string headDevice, List<int> values)
        {
            try
            {
                mcProtocol.SetDevice(blockType: "D", headDeviceNo: int.Parse(headDevice.Substring(1)), values.ToArray());
            }
            catch (Exception ex)
            {
                DisplayMessage($"## PLC Write Error ##: {ex.Message}", true);
            }
        }
    }

    728x90
Designed by Tistory.