Back to work

Featured Case Study · Physical Computing

Seed Dropper System

Practicing resilience through reuse — a seed dropper built from a broken 3D printer.

This project explores how an old 3D printer can be transformed into a planting tool. Instead of building a motion system from scratch, I reused the printer's existing X/Y movement and designed a seed-dropping mechanism controlled by an ESP32 and servo motor, driven by a custom Python GUI that places seeds precisely onto soil.

Repurposed Prusa i3 printer mounted with a seed-dropper syringe and a soil bed underneath, ready to plant
Complete system: printer gantry for positioning, custom dropper on carriage, soil bed below.
RoleDesigner, Fabricator, Developer
ToolsESP32, MG90S servo, Python, G-code, Pronterface, 3D printing
SkillsPhysical computing, mechanism design, prototyping, automation, creative reuse
StatusWorking prototype / class project refinement
Core ideaBroken printer motion + custom seed dropper = automated planting
01

The Problem

Repetitive planting, idle machines

Small-scale planting can be repetitive and inconsistent. At the same time, old or broken 3D printers often still have usable motion systems. I wanted to explore whether a discarded fabrication tool could be repurposed into a useful planting machine.

The value of this project is not that it solves farming at scale. The value is that it shows how an existing machine can be reimagined as a new tool through design, fabrication, and physical computing.

Inconsistency

Hand planting varies in spacing and depth.

Idle hardware

Broken printers still have working motion systems.

Access

Planting automation is rarely accessible to small growers.

02

Design Concept

Giving an old printer a second life

The concept was to use the printer as a positioning system. The printer moves to specific X/Y coordinates above the soil bed, pauses, and the seed dropper releases seeds through a tube.

Printer moves head Pause at point GUI sends DROP1 / DROP3 ESP32 over USB Servo opens gate Seeds fall Next point
System flow: positioning on the printer, release on the ESP32.
03

What I Built

Four connected systems

Mechanical

3D-printed seed holder + tube assembly

Mounted to the printer carriage with a custom bracket.

Electronic

ESP32 + MG90S servo

Microcontroller drives the servo that opens and closes the seed gate.

Software

Python GUI over USB serial

Buttons and slider to send OPEN, CLOSE, DROP, and angle values.

Motion

Pronterface manual jog

Printer's existing firmware moves the head — positioned by hand for now.

04

Prototype Breakdown

Labeled system anatomy

The system splits responsibility between the printer and the seed dropper. The printer handles precise positioning, while the ESP32 and servo handle seed release. Explore the model, then scroll through the build →

Interactive 3D model

Seed dropper connector

Download GLB
Labeled anatomy
Labeled anatomy
Full mounted system
Full mounted system
Dropper close-up
Dropper close-up
Servo wiring
Servo + wiring

← Swipe or scroll to walk through the prototype →

05

Software & Interaction

Text commands became physical movement

The software was split into two parts. The Python GUI gave me a simple control panel to send commands. The ESP32 listened for serial text commands and translated them into servo angles.

1 · PronterfaceJog the printer head to a planting coordinate.
2 · Python GUIPress DROP1 or DROP3 — text command over USB serial.
3 · ESP32 firmwareParses OPEN / CLOSE / DROP1 / DROP3 → servo angles.
4 · MG90S servoOpens gate at 180°, closes at 60° — seeds fall.
5 · Soil bedSeeds land at the coordinate. Repeat.

ESP32 firmware

  • → Serial at 115200 baud
  • → OPEN, CLOSE, DROP1, DROP3
  • → MG90S on GPIO 13

Python GUI

  • → USB serial port
  • → Buttons + slider
  • → Live tuning without reflashing
Pronterface
Pronterface — manual XY jog.
ESP32 wiring
ESP32 wiring on carriage.

Serial command protocol

Text in, motion out. Anything that isn't a named command is treated as a raw servo angle.

OPEN     → servo to 180°
CLOSE    → servo to 60°
DROP1    → open, wait 400ms, close (single seed)
DROP3    → repeat drop 3× with 400ms gaps
0–180    → raw angle for manual tuning

Python GUI — Tkinter + pyserial

Buttons fire named commands; the slider streams integer angles as they change.

import tkinter as tk
import serial

ser = serial.Serial('/dev/cu.usbserial-0285FFE6', 115200)

def send(cmd):
    ser.write((cmd + "\n").encode())

root = tk.Tk()
root.title("Seed Servo Control")
root.geometry("400x400")

slider = tk.Scale(root, from_=0, to=180,
                  orient="horizontal",
                  command=lambda v: send(v))
slider.pack(fill="x", padx=20, pady=20)

tk.Button(root, text="OPEN",   command=lambda: send("OPEN")).pack(fill="x")
tk.Button(root, text="CLOSE",  command=lambda: send("CLOSE")).pack(fill="x")
tk.Button(root, text="DROP 1", command=lambda: send("DROP1")).pack(fill="x")
tk.Button(root, text="DROP 3", command=lambda: send("DROP3")).pack(fill="x")

root.mainloop()

ESP32 firmware — Arduino + ESP32Servo

Reads a line, matches it against the protocol, and writes to the servo on GPIO 13.

#include <ESP32Servo.h>

Servo myServo;

const int SERVO_PIN = 13;

int openAngle  = 180;
int closeAngle = 60;

void setup() {
  Serial.begin(115200);
  myServo.setPeriodHertz(50);
  myServo.attach(SERVO_PIN, 500, 2400);
  myServo.write(closeAngle);

  Serial.println("READY");
}

void loop() {
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();

    if (cmd == "OPEN") {
      myServo.write(openAngle);
    }
    else if (cmd == "CLOSE") {
      myServo.write(closeAngle);
    }
    else if (cmd == "DROP1") {
      myServo.write(openAngle);
      delay(400);
      myServo.write(closeAngle);
    }
    else if (cmd == "DROP3") {
      for (int i = 0; i < 3; i++) {
        myServo.write(openAngle);
        delay(400);
        myServo.write(closeAngle);
        delay(400);
      }
    }
    else {
      int angle = cmd.toInt();
      if (angle >= 0 && angle <= 180) {
        myServo.write(angle);
      }
    }
  }
}
06

Iterations

From servo press to working prototype

V1

Basic servo press

Alignment and force mattered more than expected.

V2

Tube + gate

Improved control but revealed jamming.

V3

Printer-mounted

First seeds dropping at coordinates.

V4

Working prototype

Full click-to-seed interaction loop.

Bracket iterations
Seven bracket iterations on the bench.
Final dropper
Final mounted dropper, loaded with seeds.
07

Demo

Working Demo

Full loop: printer movement → command trigger → servo → seed drop.
08

Challenges

Constraints that shaped the build

Time constraints

Senior project overlap compressed the window.

3D modeling

Bracket, hopper, and gate took several CAD passes.

HW + SW debugging

Mechanical and firmware issues showed up together.

Physical iteration

Each tweak meant reprint, remount, re-test.

Physical prototyping is often less about the idea and more about tolerances, timing, alignment, and repeatability.
09

Outcome

A working planting flow

The final prototype demonstrated a working planting flow: the printer moved to set coordinates, paused, and the seed dropper released seeds through a controlled mechanism.

Soil bed test
Soil bed test rig — newspaper-lined container within the printer's reach.
10

Reflection

Adaptation over discard

This project taught me how to repurpose existing hardware into a new tool — sustainability through reuse, not just material choice.

Care for materials

Reusing a broken printer instead of discarding it.

Care for food systems

Small-scale planting at a human pace.

Care through precision

Repeatable spacing the printer can hold to.

Care as maintenance

Adapting existing systems rather than building new.

Resilience is not building new systems, but adapting and sustaining existing ones.

Let's connect

Want to talk about product design, prototyping, or physical-digital systems?

I'm currently looking for product design, UX, creative technology, hardware prototyping, and early product roles.