← 전체 글
Modbus/약 9분 읽기/ 조회

Modbus float가 1.2e-41로 보일 때: byte/word order 잡기

Modbus는 32-bit 값의 endianness를 표준으로 정하지 않는다. 그래서 16-bit register 두 개가 엉뚱한 값으로 디코딩된다. Driver에서 추측하지 말고 현장에서 byte/word order를 증명하는 방법.

Modbus문제 해결시운전SCADA태그

Register 주소만 맞아도 값은 틀릴 수 있다

Modbus map에 유량 값이 40021부터 holding register 두 개라고 적혀 있다고 하자. 이 정보만으로는 SCADA tag를 완성할 수 없다. 16-bit register 두 개를 32-bit 값으로 합칠 때 byte와 word 순서를 어떻게 볼지 정해야 한다.

시운전 때 이런 증상으로 나온다.

  • 온도가 84.7이어야 하는데 1.2e-41 같은 값으로 보인다.
  • 적산 유량이 재기동 후 말도 안 되는 값으로 튄다.
  • 음수로 내려가기 전까지는 값이 맞는 것처럼 보인다.
  • Vendor tool에서는 맞는데 HMI driver tag에서는 틀린다.

근본 원인은 이렇다. Modbus Application Protocol Specification(V1.1b3)은 register를 16-bit로만 정의하고, 두 개를 32-bit 값으로 합치는 방법은 아무것도 규정하지 않는다. 프로토콜에 표준 endianness가 없다. 그래서 32-bit float, long integer, packed double word는 전부 제조사가 위에 얹은 약속이다. Byte order와 word order를 driver 옵션 정도로 넘기지 말고, interface 사양으로 남겨야 한다.

32-bit 값은 실제 byte 순서로 적는다

32-bit 값이 register 두 개로 나뉘면 register 내부 byte 순서와 register 간 word 순서가 모두 영향을 준다. 문제는 tool마다 부르는 이름이 다르다는 점이다. 그래서 현장 기록에는 이름보다 실제 byte 배열을 같이 적는 편이 안전하다.

실제 32-bit byte를 A B C D라고 두면 다음 네 가지를 자주 만난다.

배치Register NRegister N+1현장에서 흔한 표현
AB CDABCDNormal, big-endian word
CD ABCDABWord swap
BA DCBADCByte swap
DC BADCBAByte/word swap

Manual 예시는 AB CD처럼 보이는데 gateway 설정 화면에는 normal, swap words, swap bytes, swap both처럼 표시되는 경우가 많다. 이름만 믿으면 안 된다. 반드시 알고 있는 test value로 확인한다.

경험상 가장 자주 무는 건 word swap(CD AB)이다. 전력량계나 drive gateway 중에는 manual은 값을 big-endian으로 인쇄하면서 실제로는 low word를 먼저 저장하는 장비가 많다. Float가 크게 틀렸는데 부호는 그럴듯하면, 다른 걸 건드리기 전에 word swap부터 시도해 보라. 나머지 세 배치를 합친 것보다 이쪽이 startup ticket을 더 많이 정리한다.

순서를 증명하는 test value를 쓴다

운전 중인 값 하나만 보고 판단하면 위험하다. 온도 25.0 같은 값은 잘못 해석해도 그럴듯한 숫자가 나올 때가 있다. Byte나 word가 뒤집혔는지 바로 보이는 값을 써야 한다.

시운전에서는 이렇게 확인한다.

  • Vendor에게 raw register와 engineering value가 같이 있는 예시를 요청한다.
  • Simulator나 장비 test mode에서 IEEE-754 float 123.456 같은 값을 강제로 넣고 raw register를 기록한다.
  • Integer counter는 65535보다 큰 값을 써서 high word가 0이 아니게 만든다.
  • Signed integer는 양수와 음수를 하나씩 확인한다.
  • Scale이 있는 값은 raw count와 scale factor를 따로 적는다.

예를 들면 이런 식으로 남긴다.

Tag: FT101_TOTAL_M3
Modbus: holding registers 40210-40211
Type: unsigned 32-bit integer
Raw test value: 0x0001 0x86A0
Decoded value: 100000 m3
Driver setting: word order normal, byte order normal
Scale: raw x 1.0

"32-bit unsigned"라고만 적은 것보다 훨씬 낫다. 현장에서 실제로 검증한 register 배치를 남겼기 때문이다.

Scaling 문제와 order 문제를 섞지 않는다

Byte/word order 문제를 scale 문제로 착각하는 일이 많다. 둘은 나눠서 봐야 한다.

증상가능성이 큰 원인확인 방법
Float 값이 아주 작거나 터무니없이 큼Word 또는 byte order 오류Raw hex register를 보고 네 가지 배치를 계산해 본다
정확히 10, 100, 1000배 차이Scale factor 또는 단위 오류Manual의 raw count와 engineering unit을 비교한다
32767 근처까지는 맞다가 이후 틀림Signed/unsigned 설정 오류int16, uint16, int32, uint32 중 무엇인지 확인한다
65535 근처에서 값이 돌아감Register 하나만 읽음Driver tag length와 시작 주소를 확인한다
값은 변하지만 계단식으로 튐잘못된 word 사용 또는 stale register가능하면 두 register를 한 번의 request로 읽는다

Endian 문제를 이상한 multiplier로 보정하면 안 된다. 한 지점에서는 맞는 것처럼 보여도 전체 범위에서는 계속 틀린 데이터가 된다.

주소 convention도 같이 확인한다

Multi-register 값을 확인할 때는 driver가 쓰는 주소 convention도 같이 남긴다. Byte order만 맞고 주소가 하나 밀리면 결과는 똑같이 틀린다.

자주 생기는 mismatch는 다음과 같다.

  • Manual에는 40001로 쓰여 있지만 driver에는 zero-based address 0을 넣어야 한다.
  • Gateway는 첫 holding register를 1로 부르고, PLC driver는 400001로 부른다.
  • Input register와 holding register가 서로 다른 영역인데 번호가 비슷하다.
  • 32-bit 값이 홀수 register에서 시작하는데 driver가 짝수 alignment를 가정한다.
  • Driver는 N, N+1 순서로 읽지만 manual 표는 high word와 low word를 반대로 적었다.

가능하면 Wireshark나 driver diagnostic log로 한 번은 poll을 잡는다. Function code, starting address, quantity, response byte가 보이면 논쟁이 줄어든다.

Packed status word는 bit 번호를 따로 적는다

Packed status register에서도 비슷한 문제가 나온다. Manual에는 "bit 0 = running", "bit 8 = fault"라고 적혀 있는데 HMI tool은 bit를 왼쪽부터 보여 주거나 1부터 번호를 매기기도 한다.

Packed register마다 아래 내용을 남긴다.

  • Register address와 function code.
  • Bit 번호가 0-based인지 1-based인지.
  • Least significant bit(LSB)가 어느 쪽인지.
  • Alarm bit가 active-high인지 active-low인지.
  • Momentary bit인지, latch bit인지, 특정 mode에서만 유효한 bit인지.

장비에서 가능하면 상태를 하나씩 force해서 본다. 어렵다면 정지, 운전, interlock, fault 같은 대표 상태를 만들고 raw register 값과 bit pattern을 비교한다.

인수인계 전에 point list에 넣을 것

Modbus point list를 넘기기 전에 최소한 다음은 project note에 넣어 둔다.

  • Float, 32-bit integer, packed status word 각각의 raw register 예시.
  • Byte order와 word order driver 설정. 가능하면 실제 byte 배열.
  • SCADA driver가 쓰는 주소 convention.
  • Signed 여부, scale factor, 단위, engineering range.
  • Multi-register 값을 한 번에 읽는지에 대한 poll grouping 메모.
  • 값을 증명한 device 화면, driver log, packet capture 근거.

10분짜리 기록이지만 효과는 크다. Modbus에서 가장 위험한 문제는 통신이 끊기는 것이 아니다. 값이 정상처럼 갱신되고 trend에 찍히고 alarm까지 도는데, 실제로는 다른 숫자를 보여 주는 상황이다.