System architecture overview
The system is built around my custom XIAO ESP32-C6 hub board. The board controls the stepper motor,
reads the RTC time over I²C, updates the SH1106 OLED screen, drives the passive buzzer, and reads
the physical buttons.
Motion
28BYJ-48 + ULN2003
Rotates the 16-day carousel one compartment at a time
Mechanism
Gravity opening
No servo trapdoor; pills fall when the selected slot reaches the fixed opening
Optional sensing
Line / IR sensor
Can be added to detect if pills fell into the tray
Controller
XIAO ESP32-C6
Custom PCB
I²C bus · GPIO
USB-C power
Display
OLED SH1106
Shows current time, date, alarm screen, and dispense status
Time
RTC DS3231
Keeps accurate time with CR2032 backup battery
Interaction
2 tactile buttons + buzzer
Blue confirms and dispenses; red is for snooze, skip, or settings
Mechanical concept
The carousel has 16 compartments. A transparent acrylic cover closes the front
and has a fixed dispensing opening. The cover is held with magnets, so it can be removed for refilling
without tools. The base is made from CNC-cut plywood and supports the mechanism and electronics.
I originally explored a servo-driven sliding door and a two-dose 31-day mechanism, but I discarded
that route because it required more pins, more space, and more moving parts. The final mechanism uses
gravity instead: the stepper rotates the carousel until the next compartment reaches the opening.
Gear concept
The carousel is driven by an internal gear system: a 32-tooth ring gear and an
8-tooth pinion, both module 2. This gives a 4:1 gear ratio. With the 28BYJ-48 and
AccelStepper, one compartment is treated as 512 steps, which makes the movement
simple to control in firmware.
Bill of materials
| Component |
Role |
Final use |
| XIAO ESP32-C6 |
Main controller |
Mounted on my custom hub board; controls the full system. |
| Custom hub PCB |
Electronics integration |
Routes the XIAO pins to the motor driver, buttons, buzzer, I²C devices, and optional sensor. |
| 28BYJ-48 stepper motor |
Motion |
Rotates the carousel to the next compartment. |
| ULN2003 driver board |
Stepper driver |
Drives the four coils of the 28BYJ-48 motor. |
| RTC DS3231 |
Timekeeping |
Provides accurate alarm time and keeps time with a coin-cell battery. |
| OLED SH1106 128×64 |
Display |
Shows the current time, date, alarm message, and dispense confirmation. |
| Passive buzzer |
Alarm |
Plays a repeated beep pattern until the user presses the blue button. |
| Blue tactile push button |
Confirm / dispense |
The user presses it to stop the alarm and rotate the carousel. |
| Red tactile push button |
Secondary input |
Available for snooze, skip, or configuration mode. |
| Line follower / IR sensor |
Optional detection |
Possible future input to detect if pills actually fell into the tray. |
| 16-slot PLA carousel |
Pill storage |
3D printed in PLA. Each compartment stores one dose. |
| 32T ring gear + 8T pinion |
Transmission |
3D printed, module 2. Transfers stepper motion to the carousel. |
| Transparent acrylic cover |
Cover and safety |
Laser cut. Holds pills inside while leaving one dispensing opening. |
| Magnets |
Cover attachment |
Hold the acrylic cover in place while still allowing easy removal for refilling. |
| Plywood base |
Structure |
CNC-cut structural base for the mechanism and electronics. |
| USB-C 5 V charger |
Power |
Direct USB-C power through the XIAO port. No LiPo in the final version. |
Operating logic
The final firmware is based on a simple state machine. The device stays idle and shows the time.
When the RTC reaches the alarm time, the buzzer starts and the OLED changes to the alarm screen.
The dispenser waits for the user before moving the motor.
Idle
OLED shows current time and date. Stepper outputs are disabled so the motor does not heat up.
Alarm
RTC reaches the programmed time. The buzzer plays a repeated beep pattern and the OLED shows "ALARMA!".
User confirmation
The blue button must be pressed before dispensing. This confirms the user is present.
Dispense by gravity
The buzzer stops, the stepper moves 512 steps, and the next compartment aligns with the acrylic opening.
Confirmation screen
The OLED shows "Pastillas listas" and the buzzer plays a short ascending confirmation tone.
Pin map
| Pin |
Function |
| D0 | SDA - I²C bus for RTC + OLED |
| D1 | SCL - I²C bus for RTC + OLED |
| D2 | Blue button - confirm / dispense |
| D3 | Optional line follower / IR sensor |
| D4 | Available or future input |
| D5 | Red button - snooze / skip / configuration |
| D6 | Passive buzzer |
| D7 | ULN2003 IN2 |
| D8 | ULN2003 IN3 |
| D9 | ULN2003 IN4 |
| D10 | ULN2003 IN1 |
User interface
OLED display
Shows the clock, date, alarm state, and dispense confirmation. During alarm it displays a large "ALARMA!" message.
Blue button
Main interaction. The user presses it to stop the alarm and dispense the medication.
Red button
Secondary interaction. It can be used as snooze, skip, or future configuration input.
Passive buzzer
Sounds a repeated alarm pattern until the user presses the blue button. A different tone confirms dispensing.
Magnetic cover
The acrylic cover is held by magnets. It can be removed quickly for refilling the 16 compartments.
USB-C powered design
The dispenser runs from a standard 5 V USB-C phone charger.
Testing plan
| Test |
Pass criteria |
Phase |
| Stepper movement |
Button press moves the carousel exactly one compartment, 512 steps, repeated 16 times. |
Unit |
| Gear mesh |
Pinion and internal ring gear rotate without skipping or jamming. |
Unit |
| RTC and OLED |
OLED shows the DS3231 time and date correctly for at least 30 minutes. |
Unit |
| Alarm behavior |
Buzzer continues until the blue button is pressed. |
Integration |
| Gravity dispensing |
Five pills fall through the opening without getting stuck. |
Integration |
| Magnetic cover |
Cover stays attached during normal use and can be removed by hand for refilling. |
Integration |
| USB-C power |
System runs from a 5 V USB-C charger without brownouts while the stepper moves. |
Integration |
| User interaction |
User understands that the blue button confirms the alarm and starts dispensing. |
UAT |
Failure modes and mitigations
| Failure |
Severity |
Root cause |
Fix |
| Carousel loses alignment |
High |
Stepper skips steps or gear mesh has too much friction. |
Use the 32T/8T gear ratio, test 512 steps per compartment, and keep the motor speed below the point where it skips. |
| Pills do not fall |
High |
Compartment is not aligned or pills are too large for the opening. |
Chamfer compartment edges, test with five pills, and keep the acrylic opening slightly larger than the compartment outlet. |
| User does not press the button |
Medium |
User misses the alarm or is not nearby. |
Alarm keeps repeating until acknowledged. Future version could notify a caregiver. |
| Cover is hard to remove |
Medium |
Magnets too strong or misaligned. |
Use only enough magnetic force to hold the cover; align polarity before gluing or press-fitting magnets. |
| Stepper overheats |
Medium |
Motor coils stay energized during idle. |
Firmware disables motor outputs after every movement. |
| RTC loses time |
Low |
CR2032 battery is empty. |
Replace the coin cell and reset time from firmware. |
| Optional sensor false reading |
Low |
Line follower depends on contrast and placement. |
Keep sensor as optional for this version; confirm dose through the blue button and visual tray check. |
Repair
The final design avoids unnecessary mechanisms. There are no servo trapdoors, no LiPo charging circuit,
and no load cell. This makes the dispenser easier to assemble, explain, and repair.
Refilling
Pull off the magnetic acrylic cover, refill the 16 compartments, and place the cover back on the magnets.
Replacing printed parts
The carousel, pinion, and ring gear are 3D printed and can be reprinted if damaged.
PCB access
The XIAO hub board is mounted on the plywood base and can be reached without removing the carousel.
Power
The device uses a standard 5 V USB-C charger. If the cable fails, it can be replaced like a phone charger.
RTC battery
The DS3231 has a CR2032 battery holder. The battery can be replaced without redesigning the board.
Future modularity
The 16-day ring is not fully modular yet, but the concept can evolve into removable rings or multiple stacked rings.
Lifecycle
Manufacture
3D print carousel and gears, laser cut acrylic cover, CNC cut plywood base, mill PCB
Assembly
Mount PCB, solder buttons and buzzer, install magnets, align gear mesh
Use
USB-C powered operation. Alarm sounds, user presses blue button, one dose dispenses.
Refill
Caregiver removes magnetic cover and refills 16 compartments.
Future
Modular 16-slot rings could scale the system to 32 days or two daily doses.
The current version prioritizes reliability over maximum capacity. It is a 16-day proof of the mechanism,
while the future version can scale through stacked or removable 16-slot modules.