배선은 맞는데 계속 깨진다
Cable도 land 됐고, slave address도 맞고, parity도 맞는데 frame이 계속 빠진다. 열에 아홉은 도면이 아니라 timing 문제다. Master가 다음 요청을 너무 빨리 쏘고, radio modem이나 gateway, 10년 된 drive가 아직 bus를 놓지 못한 상태다.
Baud rate와 timeout은 driver 템플릿에서 물려받는 기본값이 아니다. 이 값들이 한 scan에 들어가는 데이터 양, SCADA driver가 retry 전에 기다리는 시간, 느린 계측기가 답할 기회 자체를 정한다. 느리고 지루하게 시작해서 실제 응답 시간을 재고 나서 조이는 것이지, 그 반대가 아니다.
요청 경로부터 그린다
같은 read라도 driver와 slave 사이에 뭐가 끼어 있느냐에 따라 걸리는 시간이 다르다.
| 경로 | 먼저 의심할 timing 요소 |
|---|---|
| 직접 RS-485 multi-drop | bus release 시간, cable 품질, termination, 중복 address |
| Serial server 경유 | TCP socket buffering과 serial 송신 시간 |
| Radio modem | PTT 지연, air-time 충돌, modem retry |
| Protocol gateway | 내부 request queue와 slave별 turnaround |
| VFD, power meter | local keypad 조작이나 측정 갱신 중 느린 register 처리 |
Timeout 값을 건드리기 전에 경로를 먼저 그린다. 중간에 TCP-to-serial gateway가 있으면 맞춰야 할 response timeout이 둘이다. SCADA driver 쪽과 gateway serial 쪽. 게다가 retry layer도 둘이라 서로 곱해진다. Driver timeout 1초에 이미 retry하는 gateway가 겹치면, slave 하나가 느린 것만으로 HMI에 10초짜리 공백이 생긴다.
Silent interval은 선택이 아니다 — spec이 정한다
Modbus RTU frame에는 시작/끝 구분 문자가 없다. 대신 선로의 침묵으로 frame 경계를 잡는데, MODBUS over Serial Line Specification V1.02가 그 침묵을 character time에 못박아 둔다.
- t1.5 — frame 안에서 1.5 character time의 침묵이 나면 오류로 본다. Frame 중간에 이 시간을 넘기면 slave가 frame을 버린다.
- t3.5 — 3.5 character time의 침묵이 frame 끝을 뜻한다. 이 시간이 지나기 전에 다음 요청을 보내면 수신 측이 두 frame을 붙여 버리고 CRC error를 돌려준다.
선로 위에서 한 character는 11비트다(start + data 8 + parity + stop, 8N2도 11비트). 그래서:
char_time_ms = 11 / baud_rate * 1000
t3.5_ms = 3.5 * char_time_ms
9600 bps면 character당 약 1.15 ms, t3.5는 약 4.0 ms다. 19200이면 약 2.0 ms. 19200을 넘으면 spec이 더 이상 비례로 계산하지 않고 값을 고정한다. t3.5 = 1.75 ms, t1.5 = 750 µs. UART에서 마이크로초 단위 간격을 쫓는 게 의미가 없기 때문이다. 대부분의 driver가 이걸 자동으로 지키지만, packet을 다시 짜는 serial-to-TCP gateway는 안 지키는 경우가 많다. 그럴 때 inter-request delay를 명시적으로 넣어 준다.
일반 RS-485에서는 필요한 quiet time이 아주 작다. 하지만 radio, 저가 converter, 오래된 계측기가 있으면 실제로 필요한 간격이 t3.5보다 훨씬 크다. 장비가 protocol 최소치 위에 wake-up이나 line-turnaround 시간을 더 요구하기 때문이다. Poll을 늦추자 error가 사라졌다면 shield tester부터 들지 말고, 선로에 충분한 침묵을 주고 있는지부터 확인한다.
Scan rate를 약속하기 전에 frame 시간을 계산한다
30초짜리 계산이 불가능한 scan 계획을 미리 걸러 준다. 9600 bps에서 8 byte 요청과 25 byte 응답이면 33 character, 즉 약 38 ms의 선로 시간이다. 여기에 device 처리, t3.5, gateway 지연, retry 한 번은 아직 더하지도 않았다.
이 상태에서 누군가 한 serial trunk에 slave 30대를 달고 각 장비에서 register 200개를 매초 읽자고 한다. transaction 30건 × (약 38 ms 선로 + turnaround)면 device를 따지기도 전에 1초를 넘긴다. SCADA 라이선스에 tag가 남아 있어도 선로가 실어 나를 수 있는 양은 그대로다. Rate를 줄이든, trunk를 나누든, 빠른 point를 별도 channel로 빼든 해야 한다.
정상인 slave 하나에서 바깥으로 시운전한다
가장 빨리 끝나는 checkout은 지루한 쪽이다.
- Slave 하나만 붙이고 작은 register block을 읽는다.
- Baud rate, parity, stop bit, slave address를 확인한다.
- 정상 응답 시간과 가장 늦은 응답 시간을 같이 기록한다.
- 다음 slave를 하나 추가하고 반복한다.
- 기본 read가 안정된 뒤에 register block을 키운다.
- CRC error, timeout, exception response를 보면서 delay를 조금씩 줄인다.
- 최종 timing 값을 network drawing에 남긴다.
30대를 한 번에 다 붙이고 random error를 잡는 건 느린 길이다. 중복 address 하나, 망가진 transceiver 하나, 자기 측정 중에 멈추는 meter 하나가 전체 trunk를 불안정하게 보이게 만들고, 어느 장비가 범인인지 구분도 안 된다.
Retry는 부하를 숨기고, scan class는 드러낸다
Retry는 유용하다. 선로가 포화되는 순간을 가릴 때까지는. Driver가 timeout 1초에 retry 3회면 빠진 slave 하나에 4초를 쓰고 나서야 다음으로 넘어간다. 운전원은 멈춘 값 하나만 보지만, 실제 피해는 그 retry에 막혀 있는 poll schedule 전체다.
죽은 장비 하나가 나머지를 끌고 내려가지 않도록 poll을 scan class로 나눈다.
- 빠른 status coil과 permissive는 작은 high-priority group.
- Energy, diagnostic, totalizer register는 더 긴 주기의 group.
- 응답이 느린 장비는 별도 group과 보수적인 timeout.
- 철거됐거나 예비인 address는 active poll list에서 아예 뺀다.
장비 하나가 실패했을 때 HMI 화면 전체가 늦어진다면 손볼 건 또 다른 timing 값이 아니라 scan class 설계다.
깨질 때는 대개 이렇게 깨진다
Baud rate를 올리자 CRC error가 늘어난다. 9600에서는 멀쩡한데 38400에서 흔들린다. Protocol 문제인 경우는 거의 없다. Cable 길이, termination, biasing, stub, grounding, 아니면 여유가 바닥난 transceiver다. 되던 rate로 되돌리고, termination이 물리적 양 끝에만 있는지 확인하고, shield bonding과 branch 길이를 driver 탓하기 전에 본다.
Idle 이후 첫 poll만 timeout, retry는 성공. Radio나 converter가 wake-up이나 방향 전환 시간을 못 받고 있다. Turnaround나 inter-request delay를 늘리고, radio면 PTT timing을 확인한다.
Client 하나면 되고 둘이면 실패. SCADA master 둘이 같은 serial gateway를 치면 queue가 차고 응답 순서가 꼬이고 slave가 너무 촘촘한 요청을 받는다. 가능하면 serial segment에는 master 하나만 둔다. 이중화 때문에 둘이 필요하면 gateway가 multi-client 제어를 실제로 지원하는지 확인하고 request concurrency를 제한한다.
짧은 read는 되고 긴 read는 실패. 작은 block은 잘 오는데 100개짜리 block이 timeout이나 exception으로 끝난다. Slave의 요청당 최대 register 제한, 데이터 조립 시간, 아니면 map의 문서에 없는 빈 구간을 넘겨 읽는 게 원인일 수 있다. Block을 줄이고, 문서상 map 구간 안에 머물고, 10개·50개·100개 read의 응답 시간을 비교한다.
숫자를 남긴다
최종 baud rate, parity, stop bit, response timeout, retry count, inter-request delay, gateway pacing을 적고, 정상 scan time과 최악 scan time도 같이 남긴다. 다음에 장비를 교체하거나 slave를 추가하거나 dropdown 하나로 다섯 배 빨라지지 않냐고 묻는 사람은 바로 이 숫자가 필요하다. 그리고 그 숫자는 새벽 2시에 누가 읽을 수 있는 형태로 driver config 안에 들어 있지 않다.