Introduction
간장공장공장장은 컨베이어 벨트 위의 제품 박스에 부착된 QR 코드를 ESP32CAM으로 읽어, 주소를 기반으로 국내/해외 창고로 자동 분류하는 스마트 공장 시스템이다. 임베디드(ESP32 펌웨어), 백엔드(FastAPI), 관리자 UI(PyQt6), DB(MySQL)까지 한 시스템 안에 통합한 프로젝트.


System Architecture
| 구성요소 | 기술 스택 | 역할 |
|---|---|---|
| SoyDB | MySQL (Docker) | 제품·주소·출입·분류 등 전체 데이터 저장 |
| SoyServer (중앙서버) | Python, FastAPI, Alembic | 출입제어·분류·관리자 PC와 통신, DB 연동, 스키마 마이그레이션 |
| SoyAdmin (관리자 PC) | PyQt6 | 모니터링·운영 UI, 작업자/공정 관리 |
| 작업자 등록키트 | Arduino Uno + RFID | RFID 카드 발급, 중앙서버와 Serial 통신 |
| 출입제어키트 | Arduino ESP32 + RFID | 출입 인증, 중앙서버와 TCP 통신 |
| 분류키트 | Arduino ESP32CAM | QR 인식, 근접센서·서보·DC모터 제어, 중앙서버와 TCP/UDP 통신 |
Features
- 자동 분류 공정: 컨베이어 → ESP32CAM(QR 인식) → 서버에서 주소 해석 → 서보모터로 국내/해외 분기
- 3단계 공정 제어: 시작 / 일시정지 / 중지 분리. 일시정지는 DC 모터만 정지하고 카메라·DB 상태는 유지
- RFID 출입제어: 등록된 작업자만 출입 허용, 카드 이벤트는 TCP로 중앙서버에 푸시
- 작업자 카드 발급: 관리자 UI에서 신규 작업자에게 RFID 카드 등록
- 공정 로그·모니터링: 작업 시작·종료·물품 인식·카운팅 로그를 DB에 저장하고 관리자 화면에서 조회
Implementation
1. ESP32 분류키트 — FSM 기반 상태 관리
분류 공정은 IDLE / RUNNING / SORTING / PAUSED 등의 상태를 가진다. ESP32 펌웨어에 FSM(Finite State Machine) 을 도입해 상태별 전이 규칙을 명시했다.
RUNNING에서만SORT_PAUSE수신 →PAUSED전이PAUSED에서만SORT_RESUME수신 →RUNNING복귀SORTING중 일시정지 명령은 무시 (분류 동작 중 끊기지 않도록 보호)- 각 상태마다 RGB LED 색상 매핑 (
PAUSED→ 노랑) 으로 현장에서 상태를 즉시 인지 가능
2. QR 코드 인식률 개선
ESP32CAM 의 320x240 저해상도 + JPEG 압축 + 박스 회전 때문에 pyzbar.decode() 1회 호출만으로는 인식 실패가 잦았다. PC 쪽에서 다단계 디코딩 파이프라인을 도입했다.
1차: 원본 프레임 → pyzbar.decode()
2차: 90°, 180°, 270° 회전 → 각각 pyzbar.decode()
3차: 그레이스케일 + 적응적 이진화(adaptiveThreshold) → pyzbar.decode()
- 성공 시 즉시 반환해 오버헤드 최소화
- 최악의 경우 6회 decode 이지만 320x240 해상도라 충분히 빠름
- 추가로 ESP32CAM 하드웨어 레벨에서
set_vflip으로 영상 보정해 PC 측cv2.flip중복 처리 제거
3. SoyServer — MVC + 도메인 서비스 구조
FastAPI 서버는 단순 라우터 나열을 피하고 계층 분리 를 했다.
| 계층 | 위치 | 역할 |
|---|---|---|
| Model | app/models/, app/services/ | ORM 엔티티 + 도메인 로직. 프로토콜/전송 계층을 모름 |
| Controller | app/requests/ | TCP 요청 action + body 파싱 → app.services 호출 |
| View | app/views/tcp_response.py | 응답 포맷 { type, id, ok, body, error } 으로 직렬화 |
| 전송 | app/pc_bridge.py | TCP 프레임 수신/송신, 세션 관리, _handle_request 로 라우팅 |
- 도메인 예외(
OrderNotFound,WorkerNotFound,WorkerCreateConflict등)를 services 에서 던지고 controller 에서 응답으로 매핑 - 인증 필요 액션(
workers관련)과 불필요 액션(auth,orders,processes)을 명확히 분리
4. 통신 프로토콜
- HTTP 8000: REST API · health check · 문서
- TCP 9001: SoyAdmin(PyQt) ↔ 서버. Worker CRUD, card_read 푸시
- TCP: 출입제어키트 ↔ 서버 (RFID 인증 결과)
- TCP/UDP: 분류키트 ↔ 서버 (TCP 분류 지시, UDP 카메라 스트림)
- MQTT: ESP32 분류키트 상태 발행 (
SORT_PAUSE,SORT_RESUME,PAUSED등)
5. Docker 기반 통합 기동
docker compose up -d 한 번으로 MySQL + SoyServer + Adminer 가 동시에 기동되고, 서버 기동 시 Alembic 마이그레이션이 자동 적용되도록 했다. 시리얼 디바이스가 연결되지 않은 환경에서도 서버만 띄울 수 있도록 ./scripts/compose-up.sh 래퍼를 제공해 개발 편의성을 확보했다.
Tech Stack
- 백엔드: Python 3.12, FastAPI, SQLAlchemy, Alembic
- DB / 인프라: MySQL, Docker Compose, Adminer
- 관리자 UI: PyQt6, Qt Designer
- 펌웨어: Arduino, ESP32 / ESP32CAM, PlatformIO
- 하드웨어: RFID 모듈, 근접센서, 서보모터, DC모터, ESP32CAM
- 통신: TCP, UDP, MQTT, Serial
- 이미지 처리: OpenCV, pyzbar
- 패키지 관리: uv