PalletPilot — Palletizing Cell CMS
Cell management system for a robotic palletizing cell — live HMI, order lifecycle, alarms, and OEE reports over WebSocket, driven against a protocol-accurate robot simulator. Live demo.
What it is
A complete cell management system for a single-robot palletizing cell: the operator dashboard, the order queue, live pallet visualization, an alarm system, a structured event log, and production/OEE/downtime reports — the software layer a machine builder ships next to the mechanics.
The robot is simulated, deliberately. The simulator speaks a realistic wire protocol (newline-delimited JSON over TCP — commands in, cycle events and faults out), so the backend treats it exactly like line-side hardware. Swap the simulator’s address for a real controller bridge and the rest of the system doesn’t change.
The demo is live — load an order, start the cell, and watch the pallet build box by box. Acknowledge the alarm when the robot faults. The environment resets to a clean state nightly.

What it solves
Machine builders and integrators usually have the cell working long before the software around it is presentable. The HMI that ships is often a vendor panel layout: functional at the machine, invisible to everyone else. This project shows the alternative — a web HMI any operations manager can open in a browser, with the pieces a production cell actually needs:
- Order lifecycle, not just start/stop. Orders queue, load, run, pause, fault, and complete through an explicit state machine; one active order at a time, enforced, with the history kept.
- The picture can’t drift from reality. The pallet visualization and the robot are driven by the same pattern geometry, computed in one place. What the screen shows is what the robot was told to do.
- Honest numbers. OEE availability, performance, and quality are computed from shift calendars and recorded cycles. Ratios with no data render as gaps, not as fake zeros.
- Alarms that behave like alarms. Severity, acknowledgement, suppression windows, auto-clear on recovery — and a self-resolved fault still needs an operator’s acknowledgement before it leaves the active list.


Architecture
flowchart LR
HMI[SvelteKit HMI<br/>runes · WebSocket] -->|REST| API[FastAPI backend]
API -->|WS fan-out| HMI
API -->|TCP · JSON lines| SIM[Robot simulator<br/>cycle events · faults]
API -->|async SQLAlchemy| PG[(PostgreSQL)]One backend owns the cell: a pure state machine decides transition legality, services around it persist, publish, and command the robot. Every state change fans out to the browser over one WebSocket envelope format, so the dashboard, alarm banner, event tail, and pallet view stay in step without polling.
Stack notes
- FastAPI + async SQLAlchemy 2 on PostgreSQL — the whole backend is async, one process, structured logging throughout.
- SvelteKit with Svelte 5 runes for the HMI; reactive stores mirror the WebSocket topics. Tailwind v4 tokens carry two full themes (a dark SCADA look and a light SaaS look) with zero component forks.
- The simulator is its own service with a protocol contract mirrored byte-for-byte in the backend — the integration boundary is a wire protocol, not a Python import.
- Docker Compose end to end: one command boots the cell, migrations and a deterministic seed included. The demo you’re looking at is the same compose file, behind nginx.
What’s interesting
The cell logic lives in pure modules — cell state, order lifecycle, pallet geometry, alarm lifecycle, report math — each a function from state and event to a result, with no I/O and its own exhaustive test table (184 tests across the backend). The services around them handle persistence and fan-out. That split is why the system is easy to reason about under fault conditions: an e-stop mid-cycle is a table row, not a special case discovered in production.
The WebSocket hub makes the opposite trade from a message broker: it is in-process and drops the oldest message when a consumer lags. A slow browser tab must never back-pressure the machine loop. State that matters is in PostgreSQL; the stream is a view, and a reconnecting client rebuilds it from authoritative state.
Status
Live at palletize.andon.work — fully interactive, shared between visitors, reset nightly to a clean seeded state with a week of demo history. Built as a portfolio showcase; the same architecture applies to real controllers by replacing the simulator with a protocol bridge to the line.