CORNERSTONE PROJECT · 2026
A 3D-printed, Pico-controlled dispenser that delivers a dentist-recommended dose at the press of a button.
Press to dispense a measured dose from the slot below — pea-sized for adults, rice-sized for kids.
Settings button — single-press switches adult/child dose; double-press reverses the motor.
3D-printed threaded screw — the squeezer arm rides down the threads, turning motor spin into a linear push.
DC motor — drives the screw via the TB6612FNG driver.
Raspberry Pi Pico (MicroPython) — the controller I built & coded.
TB6612FNG dual-channel motor driver — runs the motor fwd/reverse.
Keyhole wall-mount slots — mounts on a bathroom wall.
Conditions like arthritis and Parkinson's make squeezing a toothpaste tube painful or impossible. At the same time, over a third of children routinely use far too much toothpaste — there's no feedback on how much is "right."
Our goal: make correct dosing effortless, hands-free, and accessible to anyone — from a six-year-old to someone with limited hand dexterity.
The dispenser mounts on the wall. A toothpaste tube slots in from the top; a 3D-printed threaded screw and squeezer arm sit against the tube body. Press the Start button — the Pico reads the current dose setting, commands the motor driver at full PWM, and the screw turns, pushing the arm downward for exactly the right duration. Motor stops. Toothpaste dispensed.
A clear front door lets you see the remaining tube at a glance. Two keyhole slots on the rear mount to standard bathroom wall screws — no special hardware needed.
Button 2 dispenses. Button 1 configures — a single click toggles adult (0.5 s) vs child (0.25 s) mode; a double-click within 600 ms reverses the motor to retract the arm for tube reloading, no disassembly needed. All button reads use 25 ms software debounce polling — no interrupts required.
AdultDuration = 0.5 # pea-sized dose
ChildDuration = 0.25 # rice-sized dose
def motor_forward(duration):
ain1.value(1); ain2.value(0) # set direction
pwma.duty_u16(MotorDuty) # full power
time.sleep(duration) # run for dose time
motor_stop() # then stop
def start_mechanism(): # start → dispense
motor_forward(TimeSetting)
Three prototypes across the semester. The cardboard mockup settled spatial layout — tube position, button placement, overall form factor. The first 3D print revealed that the squeezer arm geometry needed a tighter thread pitch to apply consistent pressure without slipping. The final build tightened tolerances, repositioned the Pico to clear the motor wiring, and added the wall-mount keyhole slots.
The trickiest integration challenge: synchronising the mechanical arm advance with firmware timing. Too short and the dose is inconsistent; too long and the motor jams. The 0.5 s / 0.25 s values were calibrated empirically across a full tube.
Concept sketch
First 3D print
Physical build
Final CAD model