Policy profile 에 PLC I/O 설정

PLC I/O 를 policy profile 로 설정하는 체계에 대해 설명합니다.

PLC I/O 설정과 policy profile

PLC I/O 설정의 장점

  • Policy profile 을 통해 PLC I/O(Input/Output)를 처리하면, 펌웨어는 configuration 을 갖고 있지 않아도 되므로 IoT 디바이스 개발사 입장에서 IoT 디바이스와 펌웨어를 관리하기 용이해집니다.

  • IoT 디바이스가 부팅 될 때와 실행 중일 때 자동으로 업데이트하는 기능을 구현하면, 현장 출동을 하지 않아도 PLC I/O 설정을 원격에서 변경할 수 있습니다.

  • 원격 관리로 여러 현장을 돌아보는 시간을 절약할 수 있습니다.

Policy profile 의 구조에서 다음 위치에 PLC I/O 설정을 추가할 수 있습니다.

"desired": {
    "policy": {
        "ver": {
            "maj": 1,
            "mnr": 0
        },
        "fw": 1.0,
        "brate": 9600,
        "sec": 120,
        "devices": {
          "sensor1": {
            "idx": 0,
            // PLC I/O 상세 설정
          },
          "sensor2": {
            "idx": 1
            // PLC I/O 상세 설정
          }
        }
    }
}

PLC I/O 설정의 구문 형식

다음과 같은 구문 형식을 가집니다.

"devices": {
  "Device ID": {
    "idx": 인덱스 번호 / MODBUS slave ID,
    "opts": {
    },
    "데이터 이름 1": "PLC I/O 설정값",
    "데이터 이름 2": "PLC I/O 설정값",
    ...
  }
}
  • idx 필드는 Slave ID 여기서 idx 필드는 MODBUS 네트워크의 slave ID 로 활용합니다.

"devices": {
  "plc1": {
    "idx": 인덱스 번호,
    "opts":{
    },
    "오일 온도": "PLC I/O 설정값",
    ...
  }
}
  • 데이터 이름 필드 예를 들어 PLC 에서 오일 온도 값을 읽는다고 가정합니다. 오일 온도 값은 PLC 의 1 번지 address 에서 holding register 값을 읽을 수 있습니다. 그런 경우 "오일 온도" 라는 값을 이름 필드로 사용하면 됩니다.

  • opts 필드 IoT 디바이스의 부가 설정정보를 자유롭게 지정하고 싶을 때 사용할 수 있는 필드입니다.

오일 온도라는 변수 값은 서버로 전송할 메시지 포맷에서 contents 필드 아래의 변수로 지정하면 됩니다.

{
  "deviceId": "plc1",
  "contents": {
    "오일 온도": 1234,
  }
}

devices 필드 바로 아래의 plc1 이란 tag 값이 서버로 전송할 데이터의 deviceId 로 사용되는 것 또한 주의해야합니다.

PLC I/O 상세 설정 방법

PLC I/O 설정은 다음과 같은 구문 형식을 갖습니다.

"데이터 이름": {
  "op": PLC 로 데이터를 읽는 MODBUS function code 의 index 값,
  "addr": 데이터를 읽는 주소,
  "tp": Register 공간에서 저장되는 값의 변수 type 의 index 값,
  "edn": Register 공간에서 사용하고 있는 endian 모드의 index 값
  "sc": (옵션) Register 값에 곱셈을 통해 값 변환해야 하는 경우 설정,
  "sp": (옵션) Register 공간에서 바이트를 나누어 실수 데이터의 정수, 소수를 저장하는 경우 변환을 위해 설정
}

  • op 필드(Operation code 필드) op 필드는 MODBUS function 의 종류를 지정합니다.

실제 MODBUS function 코드는 위 표의 index 값과 대응하도록 펌웨어를 개발해야 합니다. 서버에서 내려주는 값을 그대로 쓰지 않고 매핑을 다시하는 이유는 실수로 설비에 잘못된 I/O 가 발생하는 것을 방지하기 위함입니다.

op 필드 index 값이 0, 1 인 read discrete inputs 와 read coils 는 1 bit 만 읽을 수 있기 때문에 소수점 표기 대응을 할 필요가 없지만 나머지는 더 긴 숫자를 저장할 수 있어 PLC 설정에 따라 소수점을 정상적으로 변환하기 위해서 tp, edn, sc 등과 같은 추가 설정이 있습니다.

  • addr 필드(PLC Address 필드) addr 필드에는 I/O 를 수행할 PLC 주소를 지정합니다.

  • tp 필드 (Variable Type 필드) tp 필드는 PLC 에 저장된 데이터가 어떤 변수 형식인지 지정합니다.

tp 값 5에 해당하는 경우 PLC 저장 공간에 실수형(float type) 데이터가 저장되어 있기 때문에 endian 변환만 수행하고 바로 서버로 전송할 수 있습니다. 그러나 정수를 저장하면서 실제로는 소수점을 저장하고 있는 경우에는 sc, sp 추가 옵션을 통해 소수점 변환을 수행하고 서버로 데이터를 보내야 합니다.

PLC 개발 방법이 표준적이지 않으며 개인 개발자의 구성 방식에 의존적이기 때문에 데이터를 PLC 에 저장하는 방법에는 여러가지 유형이 있을 수 있습니다.

예를 들어 12.34 라는 값을 정수 부분과 소수 부분을 나누어 1234 로 PLC 주소에 저장하고 있을 수 있습니다. 그런 경우 tp 는 1~4 같은 정수 설정으로 지정합니다. 그리고 sc 또는 sp 설정에서 12.34 로 변환하게 합니다.

tp 가 6인 것은, 실제로 비트 값을 저장하면서 register 에 저장하고 있는 경우 읽는 방법입니다. tp 가 6으로 지정되면 index 라는 추가 필드를 두고, 몇 번째 bit 인덱스에서 값을 읽을지 정합니다. 펌웨어는 우선 register 에서 2 또는 4바이트를 읽지만 실제로는 index 에 지정된 비트 값을 추출해서 서버로 보내야 합니다.

{
  "machineOn": {
    ...,
    "addr": 123,
    "tp": 6,
    "index": 3,
    ...
  },
  "cleaning": {
    ...,
    "addr": 123,
    "tp": 6,
    "index": 4
  }
}

위 예시에서는 PLC 의 123 번지에서 읽은 다음 3번째 비트만 추출해서 machineOn 이라는 변수에 지정하라는 설정입니다. 그리고 이어서 같은 번지에서 읽지만 4번째 비트만 추출해서 cleaning 변수로 저장하는 예시가 있습니다.

tp 7 은 여러 bit 를 읽으라는 설정입니다. 예를 들어 2바이트 PLC 주소 공간에 상위 1바이트, 하위 1바이트 나누어 데이터를 저장하는 경우 이 설정을 통해 데이터를 추출할 수 있습니다. tp 가 7인 경우 start, length, unsigned 필드를 추가로 갖습니다.

{
  "boxTape": {
    ...,
    "addr": 124,
    "tp": 7,
    "start": 8,
    "length": 8,
    "unsigned": false
  }
}

이 설정은 124번지를 읽어서 9번째 비트부터 8개의 비트를 읽어서 boxTape 변수에 저장하고 서버로 보내라는 설정입니다. 이 값은 unsigned 가 false 이므로, 음수를 가질 수 있는 변수입니다.

  • edn 필드(Endian Mode 필드) edn 필드는 PLC 에 저장된 값이 어떤 endian mode 로 저장되었는지 설정합니다. 대부분의 서버와 개인 컴퓨터들은 big endian 을 사용하지만, 일부 PLC 들은 드물게 small endian 등 다른 모드를 사용하는 경우가 있기 때문에 펌웨어는 이 필드 설정에 따라 값을 변환해서 서버로 전송해야 합니다.

Big endian 모드 변환이 필요하다고 된 변수들을 위해서 펌웨어는 endian 변환 로직을 갖고 있어야 합니다.

  • sc 와 sp 필드 (Scale, Split) sc 와 sp 는 소수점을 float 형식으로 저장하지 않고 integer 형식으로 저장하고 있는 PLC address 값을 변환하기 위해 사용합니다.

12.34 를 1234로 저장한 경우 아래 설정으로 데이터 변환 방법을 정의합니다.

{
   "scaleVar": {
     "tp": 2,
     "sc": 0.01
   }
 }

sc 에 지정된 값을 곱하여 값을 변환하면 됩니다. sp 는 바이트 단위로 split 합니다. 그리고 sc 와 sp 는 동시에 설정될 수 없습니다.

데이터 수집 제약

디바이스 트윈은 32KB 의 용량 제약이 있습니다. 그렇기 때문에 policy profile 로 PLC I/O 를 설정하게 되면, 디바이스 트윈의 용량 제약 때문에 slave 개수와 설정 가능한 address 개수에 제약이 발생합니다.

  • Policy 필드 단순 JSON text 길이로만 76바이트가 기본적으로 소모

  • Device ID 필드

  • 데이터 필드 (Address map 관련 설정 부분)

  • 전체 사이즈 예상 계산 공식 전체 사이즈 = 76 + 수집 장치 개수(Device ID 개수) * 25 + PLC Address 개수 * 70 * Device ID 개수 1대의 게이트웨이에 PLC 가 10대, 각 PLC 로부터 읽는 데이터 필드 수(Address 개수)가 60개라고 하면 최대 메모리 필요량은 다음과 같이 계산될 수 있음. 76 + 10 * 25 + 60 * 70 * 10 = 42326 (byte) = 41.3 (KB) 32KB 를 넘어가기 때문에 게이트웨이를 추가하여 PLC 를 나뉘어 연결 필요

  • 아키텍처 구상에 필요한 정보 게이트웨이 1대가 최대 수집할 수 있는 PLC 데이터 필드 개수

게이트웨이 1대가 수집할 수 있는 데이터 최대는 PLC 1대에만 연결될 경우 450개 데이터를 얻을 수 있다.

  • 데이터를 모두 읽는데 필요한 시간 예측

  • 최대 PLC 가 연결될 경우 수집할 수 있는 Address 수

결론적으로 1-30 대까지의 slave 수, 1-450 개의 수집 address 수, 그리고 32KB 제약을 따라 수집 체계가 결정될 수 있습니다.

Example Policy profile

예제 policy profile 을 통해 실제 어떻게 I/O 가 구성되고 서버에 보낼 데이터가 결정되는지 알아보겠습니다.

{
  "desired":{
    "policy":{
      "ver":{
        "maj":1,
        "mnr":0
      },
      "brate":115200,
      "sec":300,
      "devices":{
        "press-1":{
          "idx":1,
          "intTemp":{
            "op":1,
            "addr":1
          },
          "mntLamp":{
            "op":0,
            "addr":2
          }
        },
        "cutter-1":{
          "idx":2,
          "oilGauge":{
            "op":2,
            "addr":1,
            "tp":1,
            "edn":0,
            "sc":0.01
          },
          "oilPress":{
            "op":3,
            "addr":2,
            "tp":2,
            "edn":0
          }
        },
        "cutter-2":{
          "idx":3,
          "oilGauge":{
            "op":2,
            "addr":1,
            "tp":1,
            "edn":0,
            "sc":0.01
          },
          "oilPress":{
            "op":3,
            "addr":2,
            "tp":2,
            "edn":0
          }
        }
      }
    }
  }
}

위 policy profile 설정으로 IoT 디바이스는 press-1, cutter-1, cutter-2 총 3대의 설비(MODBUS slave)에 연결하여 데이터를 수집할 수 있습니다. idx 가 1~3 으로 지정되었기 때문에 실제로 MODBUS 네트워크에서도 slave ID 가 동일하게 설정되어 있어야합니다.

press-1 에서는 intTemp, mntLanp 2개의 데이터 수집 변수가 사용되고 둘의 op 모드 값은 1 과 0 이기 때문에 1bit 씩 읽습니다. 즉 0 과 1의 값만 가질 수 있습니다.

cutter-1, cutter-2 는 oilGauge, oilPress 라는 2개의 수집 변수가 있으며 레지스터에서 값을 읽기 때문에 반드시 endian 모드를 지정해야 합니다. 하지만 PLC 가 Big endian 을 지원하여 edn 이 0으로 설정되었기 때문에 별다른 변환 로직은 필요없습니다. oilGauge 는 sc 에 0.01 이 설정되어 있어서 PLC 를 읽은 값에 0.01 의 곱하여 실수로 변환한 후 서버로 전송해야 합니다.

  • 프레스 기계의 Telemetry

{
    "serviceId": 1000,
    "deviceId": "press-1",
    "timestamp": 1575084995319,
    "contents": {
        "intTemp": 62.1,
        "mntLamp": 0
    }
}
  • 커터 기계 1의 Telemetry

{
    "serviceId": 1000,
    "deviceId": "cutter-1",
    "timestamp": 1575084995319,
    "contents": {
        "oilGauge": 12.345,
        "oilPress": 12.34
    }
}
  • 커터 기계 2의 Telemetry

{
    "serviceId": 1000,
    "deviceId": "cutter-2",
    "timestamp": 1575084995319,
    "contents": {
        "oilGauge": 12.345,
        "oilPress": 12.34
    }
}

IoT 디바이스는 sec 필드에 적용된 5분(300초)마다 위 3개의 데이터를 PLC 로 부터 읽은 후에 서버로 전송해야 하며, 3개의 메시지는 개별적으로 send() 함수를 호출하도록 구현합니다. devices 바로 아래에 위치한 tag 값들이 deviceId 로 사용됩니다.

Last updated