← Back to the overview

🛠️ Development & structure

A neutral, technical overview of how the cocktail machine’s controller is structured.

The firmware runs on an ESP32 and is written in Rust (based on the ESP-IDF framework, i.e. with the standard library). It performs two very different tasks at the same time: serving a web interface and clocking the stepper motors precisely. So that the two do not interfere with each other, the tasks are split across the ESP32’s two processor cores.

Architecture at a glance

📱 Browser Phone / tablet / PC Wi-Fi (HTTP) ESP32 Core 0 Wi-Fi + web server serves the web app, accepts HTTP commands Core 1 Motor control generates the step pulses, safety logic, pump Commands ▸ ◂ Status

Core 0 takes care of Wi-Fi and the web server, core 1 exclusively of the motors. This keeps the step pulses evenly timed, even while someone is loading the web interface.

How the two cores talk to each other

The web server and the motor control do not share any memory directly; they communicate via two clearly separated paths:

The web interface

The entire interface is a single HTML file with embedded CSS and JavaScript. It is baked into the firmware at compile time (include_str!) and served when / is requested – so there is no separate web space and no build pipeline for the front end. The JavaScript talks exclusively to the firmware’s small HTTP interface, e.g.:

GET /status GET /dispense?drink=N GET /home GET /moveto GET /estop POST /api/settings POST /api/drinks POST /script

Configuration & storage

Everything that is taught in – slot positions, heights, times and the drinks – is serialised as JSON (with serde) and stored in the NVS flash of the ESP32. It therefore survives power cuts and restarts and is identical from every device on the Wi-Fi. Received values are checked against fixed limits and clamped before saving, so that no faulty input can create dangerous states.

From recipe to movement

A drink is a list of steps “slot × portions”. When it is triggered, the firmware turns this into a concrete command sequence for the two axes – roughly:

(if necessary) home Z → home X →
for each ingredient: X to slot → Sync → per portion: Z up, hold, short return stroke (or pump on) → Sync →
at the end: Z down → homing run → (optional dispensing position).

The Syncpoints make sure that the axes wait for each other at the right moments – for example, so that nothing is ever dispensed while the carriage is still moving.

Built-in safety

Technology stack

Rust (Edition 2021) ESP-IDF (std) esp-idf-svc embedded-svc serde / serde_json anyhow HTML / CSS / vanilla JS

Project structure

FileTask
src/main.rsStart-up, Wi-Fi, web server with all endpoints, pin assignment, loading the configuration
src/servo.rsMotor control: step pulses, state machine, safety logic, pump
src/settings.rsData model of the configuration and the blueprint “recipe → command sequence”
src/config.rsCentral limits: travel distances, speed limits, recipe limits
src/servo-control-migrated.htmlThe embedded web interface
This overview describes the structure of the software neutrally and makes no claim to completeness. The cocktail machine is a hobby project and is provided without warranty.
Home · Legal notice · Privacy