← back to projects
electronics · mechanics · software

Sand plotter

A CNC-based sand plotter that draws geometric and algorithmic patterns by dragging a magnet beneath a 3D-printed table. Controlled entirely from an Android tablet via a custom Flutter app.


How it works

Sand plotter

The sand plotter works by moving a permanent magnet along two axes underneath a flat 3D-printed surface covered in fine sand. The magnet stays hidden below the table and drags a metal ball through the sand, leaving behind clean and precise traces.

Two stepper motors drive the X and Y axes using a system of gears and rails. This gives the machine enough precision to handle very detailed patterns. An ESP32 microcontroller manages the low-level motion control, including step timing, acceleration ramps, and limit switches. It also runs a calibration routine every time it starts up to map out its full range of motion.

I designed the setup to be powered through a single USB hub that also charges the control tablet, keeping the whole workstation tidy and cable-free.

The control app

The Android tablet runs a custom app I built from scratch in Flutter, which talks to the ESP32 over USB serial. The app includes four distinct modes:

Freehand drawing: You can draw directly on the tablet screen with your finger. To keep the plotter from stuttering, the app uses the Ramer-Douglas-Peucker algorithm to simplify your stroke, removing unnecessary points while keeping the original shape intact.

Mandalas: A collection of mathematical patterns like Archimedean spirals, spirographs, rose curves, and Lissajous figures. You can enable specific patterns and reorder them using a drag-and-drop interface.

Auto mode: The plotter becomes autonomous in this mode, cycling through your active mandalas and drawing them one after another without needing any extra input.

Developer console: A real-time serial monitor that shows every bit of communication between the tablet and the ESP32, which was essential for debugging the protocol.

System architecture

To keep the movement fluid, I designed a streaming protocol where the tablet sends coordinates one by one. The ESP32 maintains a motion queue of up to 30 commands and sends a next signal only when it has room for more. This prevents the serial buffer from overflowing while ensuring the motors never have to wait for instructions.

The ESP32 takes advantage of its dual-core architecture here. It runs two parallel tasks: one core handles the serial communication and command parsing, while the other is dedicated purely to executing the motion. This way, receiving new data never interferes with the smoothness of the motors.

Video

Credits and files

The XY axis mechanics are based on a design from Thingiverse, but the table, the enclosure, and all other mechanical parts are original designs. You can check out the base axis design at this link.

GLB files: original 3D printed parts

Includes the table, enclosure, and custom mechanical mounts. Note that the base XY axis is not included here.

download GLB →
Source code

Full source code for the ESP32 firmware and the Flutter mobile app.

view on GitHub →