시운전 3주차에 운전원이 P-102 팝업을 열고 start를 눌렀는데 P-101이 돌았다. 그래픽은 멀쩡했다. 개요 화면의 P-102 버튼이 팝업에 넘기는 파라미터만 P101로 복사돼 있었다. 헤더에는 설비 ID가 없었고, 표시값은 두 펌프가 둘 다 정지 상태라 똑같아 보였다. 아무도 알아챌 방법이 없었던 것이다.
같은 모터 페이스플레이트를 80대에 재사용한다는 건 파라미터 오타 하나가 79대의 잘못된 대상 중 하나를 고른다는 뜻이다. 그래픽 품질과는 아무 상관이 없다.
팝업은 화면이 아니라 인터페이스 계약이다
ISA-101.01-2015는 HMI 화면을 Level 1(공장 개요)부터 Level 4(상세·진단)까지 계층으로 두라고 한다. 페이스플레이트 팝업은 그 계층에서 아래쪽 끝에 붙는 화면인데, 정작 계층을 타고 내려오는 컨텍스트를 어떻게 넘길지는 프로젝트 style guide가 정해야 할 몫으로 남는다. 대부분의 프로젝트가 여기를 안 적는다.
팝업 하나를 만들 때 다섯 가지를 문서에 못 박고 시작한다.
- 어떤 object 또는 태그 prefix를 넘기는가.
- 운전원에게 어떤 설비 이름을 보여 줄 것인가.
- 이 팝업에서 허용되는 명령은 무엇인가.
- 여기 걸리는 알람 소스와 트렌드 pen은 무엇인가.
- 컨텍스트가 비었거나 오래됐거나 잘못됐을 때 어떻게 동작하는가.
팝업을 연 버튼의 글자는 근거가 못 된다. 팝업 자체가 기술적인 대상을 알고 있어야 하고, 그걸 화면에서 증명해야 한다.
안정적인 설비 키를 하나만 고른다
P101 같은 설비 ID, Area01_Line02_P101 같은 태그 prefix, SCADA 태그 모델의 object path — 뭐든 된다. 하나를 정하고 프로젝트 전체가 그것만 쓰는 게 중요하다.
쓸 만한 키의 조건.
- 표시 문구가 바뀌어도 변하지 않는다.
- 프로젝트 안에서 유일하다.
- 태그명, 알람 소스, 히스토리언 포인트로 매핑된다.
- HMI 언어 설정에 의존하지 않는다.
- 화면 좌표나 임시 row 번호로 만들지 않는다.
운전원 표시 이름은 오늘 Feed Pump 101이고 다음 달 문서 정리 때 P-101 Feed Pump가 된다. 그 수정 때문에 팝업 바인딩이 깨지면 설계가 틀린 것이다.
헤더가 대상을 증명하게 한다
앞의 P-101/P-102 사고는 헤더 한 줄이면 안 났다. 설비 ID, 설명, 구역, 현재 mode를 팝업 상단에 고정한다. 장식이 아니라 운전원이 누르기 전에 하는 마지막 확인이다.
| 필드 | 이유 |
|---|---|
| 설비 ID | 기술적인 대상을 확인한다 |
| 설비 설명 | 운전원이 실제 설비를 알아본다 |
| 구역 또는 라인 | 비슷한 설비 사이의 혼동을 줄인다 |
| 현재 mode | local, remote, manual, auto 조건을 보여 준다 |
| 통신 품질 | 값을 믿어도 되는지 알려 준다 |
| 권한 상태 | 명령 버튼이 왜 꺼져 있는지 설명한다 |
제목이 Motor Detail뿐이면 운전원은 주변 화면을 보고 대상을 추측한다. 알람 대응 중에 추측을 시키면 안 된다. 화면 안에서 상태를 어떻게 읽히게 만드는지는 페이스플레이트 설계 체크리스트에 따로 정리해 뒀다.
표시 바인딩과 명령 바인딩은 다른 물건이다
태그 prefix를 받아서 모든 표시값과 명령 태그를 문자열 조합으로 만드는 방식이 제일 흔하다. 표시값까지는 괜찮다고 본다. 명령은 아니다.
문자열 조합의 문제는 조용히 성공한다는 점이다. P101 + _StartCmd는 존재하는 태그를 만들고, 그 태그는 진짜 펌프를 돌린다. 팝업은 아무 오류도 못 낸다.
명령 버튼은 누르기 전에 이만큼 확인한다.
- 이 설비 타입에 해당 명령 태그가 registry에 실제로 존재하는가 — 문자열이 만들어졌는가가 아니라.
- 현재 mode에서 이 명령이 허용되는가.
- 로그인 사용자에게 필요한 role이 있는가. IEC 62443-3-3의 SR 2.1(Authorization enforcement)이 요구하는 것이 이것이고, HMI에서는 보통 버튼 하나 단위로 걸린다.
- interlock, permissive fail, local control 상태가 아닌가. permissive와 interlock 표시 쪽 규칙을 그대로 따른다.
- 명령 후 확인할 feedback 태그가 같은 설비 키에서 나오는가.
잘못된 파라미터는 fail closed여야 한다. 문자열이 우연히 만든 태그로 start를 보내는 것보다, 명령을 막고 엔지니어링 오류를 띄우는 쪽이 항상 낫다.
빈 컨텍스트와 Bad 품질을 구분한다
여기가 실무에서 제일 자주 뭉개지는 부분이다. 바인딩이 깨진 팝업과 통신이 끊긴 진짜 설비는 화면에서 똑같이 0과 회색 버튼으로 보인다. 운전원은 후자로 읽는다. 정지한 펌프라고.
품질 코드를 보면 둘은 구분된다.
- OPC UA는 StatusCode 상위 2비트에 severity를 넣는다(Part 4, StatusCode).
code & 0xC0000000이0x00000000이면 Good,0x40000000이면 Uncertain,0x80000000이면 Bad다. 존재하지 않는 노드를 바인딩했으면 서버는Bad_NodeIdUnknown을 돌려준다. 연결이 끊긴 것뿐이면Bad_NotConnected거나, 서버 구현에 따라 마지막 값과 함께Uncertain_LastUsableValue다. 원인이 다르고 운전원에게 할 말도 다르다. - Classic OPC DA는 품질 바이트 상위 2비트로 같은 일을 한다.
0xC0이 Good,0x40이 Uncertain,0x00이 Bad다.
그래서 팝업의 실패 표시는 이렇게 나눈다. 설비 키가 비었거나 registry에 없으면 "구성 오류"로, 태그는 있는데 품질이 Bad면 "통신 이상"으로 쓴다. 값이 안 보이는 건 같지만 부를 사람이 다르다. 품질 코드를 태그 레벨에서 어떻게 접어 넣을지는 태그 품질 코드 처리 쪽에 있다.
알람과 트렌드 링크가 컨텍스트를 배신한다
컨텍스트 오류는 보통 현재값이 아니라 링크에서 드러난다. 값은 어느 펌프 것이든 그럴듯해 보이지만, 알람 목록은 안 맞으면 티가 난다.
- 펌프 팝업에서 알람 상세를 열었을 때 그 펌프 알람 소스만 걸러지는가.
- 트렌드 링크에서 PV, output, mode, feedback pen이 전부 같은 설비인가.
- shelve한 뒤에도 설비 필터가 살아 있는가. ISA-18.2-2016의 알람 상태 모델에서 shelved는 운전원이 일시적으로 건 상태이고 보통 자동 unshelve 타이머가 붙는다. 설계상 억제되는 suppressed by design이나 out of service와 화면에서 섞이면 안 된다.
- 알람 배너에서 연 팝업의 설비 키가 알람 소스와 같은가.
팝업, 알람, 트렌드 매핑을 각각 손으로 관리하면 rationalization 한 번에 어긋난다. 셋을 하나의 설비 registry에서 생성하는 편이 낫다.
열어 둔 팝업이 거짓말을 하는 경우
일부 HMI 플랫폼은 이미 열린 팝업 창을 재사용하면서 파라미터만 갈아 끼운다. 이때 갈아 끼우지 못한 바인딩이 남는다.
- P-101 팝업을 열고 바로 P-102를 연다. 값, 명령, 알람 링크, 트렌드 링크가 전부 같이 바뀌는지 본다. 하나라도 남으면 그 플랫폼은 단일 인스턴스 규칙을 강제해야 한다.
- 팝업을 열어 둔 채 다른 구역 화면으로 이동한다. 헤더만 보고 대상이 명확한가.
- 팝업이 열린 상태로 통신 장애와 복구를 통과시킨다. PLC를 재기동시키면 명령 상태가 어떻게 되는지는 PLC 재기동 후 명령 리셋에서 다뤘다.
- 런타임 언어 전환을 지원하면 팝업을 열어 둔 채 언어를 바꿔 본다. 표시 문구를 키로 쓰고 있었다면 여기서 무너진다.
복사하기 전에 돌리는 8칸 매트릭스
팝업 패턴을 프로젝트 전체에 복사하기 전에 이 표를 돌린다. 8칸이고 20분이면 끝난다. 80대에 복사한 다음에 고치는 것보다 싸다.
| 시험 항목 | 기대 결과 |
|---|---|
| 정상 모터 키 | 상태, 명령, 알람 링크, 트렌드 링크가 모두 맞다 |
| 정상 밸브 키 | 밸브 전용 필드와 명령만 보인다 |
| 빈 키 | "구성 오류" 표시, 명령 불가 |
| registry에 없는 키 | "구성 오류" 표시, 명령 불가 |
| 권한 없는 사용자 | 값은 보이고 명령은 이유와 함께 비활성 |
| local mode | remote 명령 비활성 |
| Bad 품질 태그 | "통신 이상" 표시, 현장 기준에 따라 명령 차단 |
| 알람 배너에서 열기 | 팝업 대상과 알람 소스 일치 |
정상 한 건과 실패 한 건을 화면 캡처해 둔다. 반년 뒤에 "이 버튼 왜 꺼져 있냐"는 질문이 왔을 때 HMI 버그인지 정상 interlock인지 5초 만에 답할 수 있다.
반복해서 나오는 실수 다섯 가지
표시 문구를 키로 넘긴다. 표시 문구는 언어, 가독성, 명명 규칙 정리 때문에 바뀐다. 헤더에는 써도 되고 바인딩에는 안 된다.
화면마다 파라미터를 다르게 만든다. 개요 화면별로 조합 규칙이 다르면 구역마다 페이스플레이트 동작이 달라진다. ISA-101이 style guide를 프로젝트 산출물로 요구하는 이유가 이것이다.
명령 비활성 이유를 숨긴다. 회색 버튼만 있으면 전화가 온다. Local mode, No start permissive, User role required, Bad feedback quality 정도의 짧은 이유를 버튼 옆에 쓴다.
알람명과 태그명이 같다고 가정한다. rationalization이나 시스템 이관 후에는 알람 소스명이 태그명과 갈라지는 경우가 많다. 문자열 규칙 말고 매핑 테이블을 본다.
태그 import 후 팝업을 안 돌려 본다. 대량 import는 파라미터 컬럼 하나만 깨뜨릴 수 있다. 현재값은 정상으로 보이는데 알람 링크나 명령 대상만 틀린 상태가 그래서 나온다.
다음에 페이스플레이트를 하나 열어 볼 일이 있으면, 값을 보지 말고 헤더의 설비 ID와 명령 버튼이 실제로 쓰는 태그 이름부터 대조해 보자. 둘이 갈라져 있는 프로젝트는 생각보다 많다. 화면 사이를 오갈 때 현재 위치를 잃지 않게 만드는 쪽은 breadcrumb와 area context에 있다.