TheaterControl — 센바스 HMI로 만든 소극장 무대 제어 시스템
여러 대의 구동 제어 보드를 Modbus TCP로 묶어, 무대 위 모든 구동 장치를 하나의 터치 패널에서 감시하고 제어하는 산업용 HMI를 만들었다. 이 글은 그 설계 의도와 구현, 그리고 현장에서 마주친 까다로운 문제들을 정리한 기록이다. 센바스(SENVAS) HMI로 만든 실전 프로젝트다.
📌 이 프로젝트의 1차 버전: 라즈베리파이로 만든 무대 조명 컨트롤 HMI. 조명 중심으로 시작해, 여기 2차에서 무대 장치 제어 전반(Machine/RD)으로 확장했다.
1. 어떤 프로젝트인가
소극장 무대에는 가림막, 리프트, 서스펜션, 스크린, 스폿라이트, 커튼, 현수막 같은 장치가 수십 개씩 달려 있다. 이들은 보통 방향 구동(Machine) 장치와 단순 ON/OFF(RD) 장치로 나뉜다. TheaterControl은 이 장치들을 하나의 1024×600 터치 패널에서 제어하기 위한 HMI다.
설계의 무게중심은 화려한 정보 표시가 아니라 한 가지 질문에 있다:
“지금 이 장치를 눌러도 되는가, 누르면 안 되는가?”
무대 제어에서 진짜 위험은 정보가 부족한 게 아니라, 잘못된 채널을 누르거나 통신이 끊긴 장치를 정상으로 오해하는 것이다. 그래서 화면은 모든 장치를 동등한 카드 그리드로 배치하고, 정상 카드는 조용히 두되 구동 중·리밋 도달·알람·통신 끊김 같은 이상 상태만 색과 비활성 처리로 즉시 튀어나오게 했다.
| 항목 | 내용 |
|---|---|
| 용도 | 소극장 무대 구동/ON·OFF 장치 실시간 감시·제어 |
| 화면 | 1024×600 터치 패널, modern-style, DarkSkyblue 테마 |
| 통신 | Modbus TCP 클라이언트, 다중 보드 동시 연결 |
| 배포 | linux-arm64 터치 패널 (센바스 터치 런처) |
| 범위 | 실시간 제어 · 보드/채널 설정 · 통신/안전 상태 표시 (이력 저장 제외) |
2. 화면 구성
화면은 Machine 제어 · RD 제어 · 설정 세 페이지로 구성된다. 공통 헤더에는 화면 이름(터치 패널 표시명은 Stage Control), 현재 페이지, 그리고 우측에 보드 통신(COMM) · EMG · FAULT · 소프트 비상정지(S-EMG) 상태·버튼이 작고 밀도 있게 모여 있다. 개별 장치의 이상은 카드 테두리/버튼 색으로, 보드 단위 이상은 이 공통 상태 영역에서 한눈에 확인한다.
2.1 Machine 제어
방향 구동이 있는 장치를 한 페이지에 8개씩 보여주는 운전 화면이다. 여러 보드의 사용 채널을 보드 순서 + 채널 번호 순으로 이어 붙이고, 좌우 화살표로 8개 단위로 넘긴다.
각 카드는 장치 이름 · 아이콘 · ON/OFF · UP(OPEN) · STOP · DOWN(CLOSE) 으로 구성된다.
- 구동 중인 방향 버튼은 초록(Good), 해당 방향 리밋에 도달하면 주황(Warning).
- EOCR(과부하) 등 채널 알람이 걸리면 카드 테두리가 빨강(Danger) 으로 바뀌고 그 카드만 조작이 막힌다.
- 커튼 채널은 버튼 텍스트가
OPEN/CLOSE로, 나머지는UP/DOWN으로 바뀐다.

Machine 제어 화면. 카드마다 ON/OFF · UP · STOP · DOWN. 구동 중인 방향은 초록, 리밋 도달은 주황, 채널 알람은 카드 테두리 빨강으로 즉시 드러난다.
2.2 RD 제어
단순 ON/OFF 장치를 8열 × 3행, 24칸 밀도로 보여주는 화면이다. 카드에는 장치 이름 · 아이콘 · ON/OFF 스위치만 둔다. 표시 대상은 검출되고 아이콘이 설정된 RD 채널뿐이며, 24칸을 넘으면 페이지로 넘긴다.
RD 화면에는 한 가지 특별한 조작이 있다 — 드래그 밴드 일괄 제어. 카드 위를 사각형으로 드래그하면 겹친 카드들이 선택되고, 손을 떼면 “N개 채널 — ON / OFF / 취소” 확인 팝업이 떠서 한 번에 켜고 끌 수 있다. 단일 탭은 그대로 해당 채널 하나만 토글한다. (자세한 구현은 §5.4)

RD 제어 화면. 동등한 ON/OFF 카드 그리드(이 구성은 16채널). 카드 위를 사각형으로 드래그하면 겹친 카드들이 한꺼번에 선택돼 일괄로 켜고 끌 수 있다.
2.3 설정
보드와 채널의 실제 사용 구성을 만드는 화면이다. 탭으로 보드 설정 · Machine 채널 · RD 채널 을 나눈다.
- 보드 설정: 보드 추가/삭제, 이름·IP·Port·Unit ID·사용 여부 편집, 연결 테스트, 자동 검색(서브넷 스캔), 장치 검출.
- Machine/RD 채널: 검출된 채널에 이름과 아이콘을 지정. 아이콘이 비어 있으면 미사용 채널로 간주되어 운전 화면에 표시되지 않는다. 즉 자동 검출된 모든 물리 채널을 무조건 노출하지 않고, 현장 운영자가 “쓰겠다”고 지정한 장치만 운전 화면에 올린다.

설정 페이지의 보드 설정 탭. 등록된 보드의 통신 파라미터(IP·Port·Unit ID)를 편집하고,
자동 검색·장치 검출로 채널을 잡는다. 화면은 보드가 ONLINE이고 Machine 6 / RD 16채널을
검출한 상태다. (보드 IP는 마스킹 처리)
3. 시스템 아키텍처
통신·영속·주기 로직은 세 개의 계층으로 분리했다.
[설정 데이터] 저장된 보드/채널 설정 로드 · 제공 (보드 목록, 채널 이름/아이콘)
│
[통신] 사용 보드별 Modbus TCP 연결
│ · 상태 레지스터 폴링
│ · 검출 결과 갱신
│ · 이벤트 명령 쓰기
│
[주기 로직] 50ms 상태 갱신 흐름 관리
│ · 보드별 연결/FAULT/EMG/통신 이상 요약
│ · 운전 화면 표시 가능 채널 목록 계산
│
[화면] Machine/RD 카드 = 표시 가능 채널을 보드 순서대로 렌더
설정 페이지 = 설정 편집 + 저장 검증
핵심 설계 원칙은 “페이지는 레지스터를 모른다” 이다. Modbus 레지스터를 비트로
해석하는 코드는 전부 보드·채널 데이터 모델에 모여 있고, 페이지는 가공된 상태(On,
CanCommand, HasAlarm 등)만 읽어 그린다. 덕분에 통신 규약이 바뀌어도 화면 코드는
건드리지 않는다.
센바스 디자이너가 생성하는 골격 코드는 손대지 않고, 통신·영속·주기 로직은 사용자 코드 영역에만 작성하는 규칙을 지켰다. 자동 생성 골격과 사람이 쓴 로직을 분리해두면 디자인을 다시 빌드해도 손으로 짠 코드가 날아가지 않는다.
4. 통신 · 데이터 모델
HMI는 Modbus TCP 클라이언트로 동작하며, 등록된 보드마다 접속한다. 보드는
통신 단위, 채널은 화면/명령 단위로 분리했고, 채널 식별자는 보드 + 보드 내 채널 번호로 고정한다.
각 보드는 동일한 레지스터 계약을 가진다.
| 항목 | 영역 | 방향 | 의미 |
|---|---|---|---|
| 채널 상태 | 상태 레지스터 | 읽기 | 보드 내 최대 40채널 상태 워드 |
| Machine 모듈 검출 | 검출 레지스터 | 읽기 | 구동(Machine) I/O 익스팬더 검출 (0이면 미검출) |
| RD 모듈 검출 | 검출 레지스터 | 읽기 | ON/OFF(RD) I/O 익스팬더 검출 (0이면 미검출) |
| 이벤트 명령 | 명령 레지스터 | 쓰기 | 대상 · 코드 형식 |
상태 워드가 담는 정보 (Machine):
| 상태 | 화면 표현 |
|---|---|
| ON/OFF | ON/OFF 상태 |
| UP 구동 중 | UP/OPEN 버튼 초록 |
| DOWN 구동 중 | DOWN/CLOSE 버튼 초록 |
| 상 리밋 | 도달 시 UP 리밋(주황) |
| 하 리밋 | 도달 시 DOWN 리밋(주황) |
| EOCR(과부하 보호) | 이상 시 카드 테두리 에러색 |
| EMG STOP | 헤더/보드 상태에 EMG 표시 |
한 보드의 Machine 채널 수 = 검출된 구동 모듈 수 × 3, RD 채널 수 = 검출된 ON/OFF 모듈 수 × 2다. 보드 1대는 최대 Machine 24 / RD 16채널이고, 여러 보드를 등록할 수 있어 전체 채널 수는 등록 구성에 따라 달라진다.
저장하는 것은 HMI 설정뿐이다 — 보드 목록, 보드별 통신 파라미터, 채널 이름/아이콘. 알람·조작·트렌드 이력은 저장하지 않는다(요구 범위가 실시간 표시였다). 그래서 별도 이력 DB나 로그 화면도 만들지 않았다.
5. 현장에서 부딪힌 문제들
설계대로 굴러가는 부분보다, 실제 보드와 패널에서 드러난 문제를 푸는 과정이 더 배울 점이 많았다. 몇 가지를 추린다.
5.1 보드 IP를 몰라도 되게 — 서브넷 자동 검색
펌웨어에는 네트워크 announce(UDP/mDNS)가 없어서 보드 IP를 운영자가 직접 입력해야 했다. 이를 없애기 위해 로컬 /24 서브넷을 병렬 스캔하는 기능을 넣었다. Modbus 표준 포트(502)를 먼저 TCP로 두드려보고, 열린 호스트마다 펌웨어 버전 레지스터를 읽어 우리 제어 보드가 맞는지 확인한 뒤 자동 등록한다. 실제 망에서 약 4초 만에 보드를 찾아낸다.
5.2 “장치 검출 0개” — 폴링 경합
장치 검출이 항상 Machine 0 / RD 0을 반환하는 버그가 있었다. 원인은 검출 레지스터 모니터를 등록한 직후 이미 돌고 있던 상태 폴링의 응답만 보고 “응답 도착”으로 판단해, 정작 새 검출 영역이 한 번 읽히기도 전에 값을 읽어버린 경합이었다. 응답 신선도 대기를 “검출 레지스터가 실제 값을 반환할 때까지 폴링”으로 바꿔 해결했다.
5.3 RD#4를 켰더니 RD#1이 — 채널 매핑
펌웨어는 Machine과 RD 채널을 하나의 통합 인덱스 공간에 둔다(Machine 다음에 RD). HMI가 RD 채널 번호를 그대로 명령 타깃/상태 오프셋으로 써서, Machine 채널 수만큼의 오프셋이 빠져 엉뚱한 채널을 건드렸다. 식별자와 레지스터 인덱스를 분리하고, 이후 각 RD 채널을 출력 비트 단위 ON/OFF 포인트로 모델링해 물리 출력과 정확히 일치시켰다. 펌웨어는 손대지 않고 HMI만으로 맞췄다.
5.4 RD 드래그 밴드 일괄 제어
24칸 RD 화면에서 여러 채널을 한 번에 켜고 끄고 싶다는 요구가 있었다. 카드 그리드 위에 투명 오버레이 패널을 최상단에 깔고, 그 위의 Down/Move/Up으로 사각형 밴드를 그려 겹친 카드를 선택한다. 손을 떼면 보드별로 다중 쓰기(FC16) 한 프레임씩 보내 같은 보드 채널을 동시에 동작시킨다(이미 목표 상태인 채널은 제외하는 절대값 방식). 단일 탭은 기존처럼 채널 하나만 토글한다.
5.5 한 채널의 EOCR이 보드 전체를 막던 문제
EOCR(과부하) 알람이 걸리면 그 보드의 모든 카드가 비활성화됐다. 명령 가능 판정이
“보드 전체 FAULT 합산”을 보고 있었기 때문이다. 채널 단위 ChannelFault를 도입해,
EOCR이 걸린 카드만 비활성화·적색 테두리가 되고 같은 보드의 다른 카드는 정상
조작되도록 고쳤다.
5.6 저장하면 통신이 끊기던 문제
설정 저장 시 보드를 새로 만들면서 통신 시작 경로(마스터 시작 + 레지스터 모니터 등록)를 호출하지 않아, 새 보드의 TCP가 시작되지 않고 통신이 끊겼다. 저장/추가/삭제 핸들러가 정상 시작 경로를 타도록 통일해 해결했다.
5.7 그 밖에
- 헤더 소프트 비상정지 버튼: 시계를 없애고, 모든 활성 보드에 EMG_STOP을 보내는 소프트웨어 비상정지 토글을 헤더에 배치.
- 숨김 설정 진입: 상단 네비에서 설정을 빼고, 제목을 5초 길게 누르면 설정으로 진입(운영 중 오진입 방지).
- 통신 신선도 판정: 짧은 폴링 지터로 카드가 깜빡 비활성화되지 않도록, 통신 이상 임계값을 마지막 수신 시각 기준 3초로 두고 동적으로 계산.
6. 안전을 위한 화면 규칙
이 프로젝트에서 가장 신경 쓴 부분이다.
- 통신 끊김 = 보드 단위 이상. 해당 보드의 카드는 위치를 유지한 채 흐리게 표시하고 버튼을 막는다. 카드를 숨기지 않는 이유는, 장치가 사라진 것처럼 보이면 운영자가 더 위험하게 판단하기 때문이다.
- 채널 단위 이상 = 카드 테두리 에러색. 리밋 도달은 해당 방향 버튼의 주황색으로.
- 색 의미 고정. 구동=초록(Good), 리밋=주황(Warning), 알람=빨강(Danger). 화면마다 의미를 섞지 않는다.
- IP 중복 저장 차단. 네트워크 충돌을 만들 수 있는 설정은 저장 단계에서 막는다.
- 미사용 채널 숨김. 아이콘을 지정한 채널만 운전 화면에 노출해 오조작 면을 줄인다.
7. 기술 스택
- UI 프레임워크: 센바스(SENVAS) HMI — .NET 8, SkiaSharp + OpenTK 렌더링
- 언어: C# (Nullable enable)
- 통신: Modbus TCP (다중 보드, RTU/TCP 지원 범위 중 TCP 사용)
- 타깃: linux-arm64 터치 패널 (self-contained 배포, 센바스 터치 런처)
- 개발 보조: 시뮬레이터(장치 동작 모사), 실보드(Modbus TCP)
- 워크플로우: AI 주도 생성(인터뷰 → 디자인 → 계획 → 구현 → 검증) 후 어시스턴트 운영 모드로 유지보수
8. 마무리
TheaterControl은 “예쁜 대시보드”가 아니라 오조작을 막는 운전 화면을 목표로 만든 HMI다. 동등한 카드 그리드 위에 상태 색과 비활성 처리만으로 위계를 만들고, 통신·안전 이상을 즉시 드러내는 데 집중했다. 자동 검색·채널 매핑·드래그 일괄 제어·채널 단위 알람 같은 디테일은 모두 “현장에서 운영자가 실수하지 않게” 라는 한 방향을 향한다.
실시간 제어 시스템에서 진짜 난이도는 화면을 그리는 게 아니라, 하드웨어가 실제로 어떻게 동작하는지를 정확히 모델링하고, 통신이 흔들릴 때도 화면이 거짓말을 하지 않게 만드는 것임을 다시 확인한 프로젝트였다. 그리고 그 모든 과정을 센바스 HMI 위에서 AI와 함께 설계하고 구현했다.
댓글
로그인 없이 이름만 적고 남기실 수 있어요. 남긴 댓글은 바로 게시됩니다.
댓글을 불러오는 중…