Final Project¶
Summary¶
My asset files are here.
Pill Dispenser Introduction¶
I would like to make a pill dispenser that would help my nephew take his medication for the day. Then send him a reminder before letting my sister in law know if my nephew has taken his medication for the day.
Breaking it down into sections: - pill dispenser body - pill cartridge - sensor or camera in dispensor area - app to notify - electronics to make it work
I worked with my daughter, Sage Kanofsky, to make sketchs of a pill dispenser. She is in Industial Design school at Georgia Institute of Technology. She is currently studying abroad the Polytechnic University of Valencia.

Past Pill Dispensers at Fab¶
[Griffin van Horne - Fab Academy 2021] (https://fabacademy.org/2021/labs/dassault/students/griffin-vanhorne/projects/final-project/) made a small handheld version with bluetooth.
Corey M. Rice : Fab Academy 2017 made one that distributes the right amount of a whole bottle of pills.
Lily Yeazell at MIT made the cutest pill box!!
Loes Fab 2021 made a box with alarms.
Miriam Choi showed this instructables project in her presentation. It is very similar in many ways to what I was thinking.
3D models¶
Then later I worked in Fusion 360 to make a 3D model

We've been discussing this dispenser and a few other items in what we call the "remember me" line. This would be helpful not only to Mika, but also to me and my family as I age. My father had alzhiemers and as he aged, the more things that he had to help with memory, the more independent he could remain. I would like to create things that make the burden on family less, and increase the feeling of independence for all who struggle with memory for one reason or another.
I have seen that other pill dispensers have been done as fab projects. I hope that mine will be different in a couple of ways:
-
Cartidges that can be preloaded
-
Messages sent first to the pill taker, and second to the car giver
Timeline¶

Then I also met with DR. Taylor who helped me related each part of my project even better to the weeks we will have in Fab.

3D Printing¶
During the modeling week, I worked on my body parts and cannister. The body I printed was too small for the motors that we are using at the lab. I could ordeer a smaller motor, but I want to stick with what we know for now and get everything working, so I will change the model a bit to fit the NEMA 17.

I made many notches and other additions to the CAD model to make the mechanics of the dispenser easier. Example: the stop for the acrylic piece at the top so that it doesn't spin past the edges when its closed.

notch from teh body to the bottom body.

Notch for the catridge to seat on the top body

During the modeling week, I worked on my body parts and cannister. The body I printed was too small for the motors that I had. I asked for a NEMA 8 which is smaller and still has enough torque for my application.
My first print of the cartride outer body, i had a few errors. I had combined the outer rim and the bottom to one stl to print, but didn't notice that i had made the bottom a slight be smaller in case i wanted it to spin in the original desdign. I also needed to cut the center in a cirlce so the key can spin freely inside the cartdidge and only turns the pill divider to push the pills.

When printing the divider, the edges were coming up on my prusa MK3s. classmate Angela Horstman suggested that I add more of a brim to help it adhere better.
I
I printed a new pill cartidge all as one piece with a cut out in the middle for the "key" to spin.
The tree supports on the latest body print are so cool. I had to take a pic.

Computer Controlled Cutting¶
I used the laser cutter to make the top pf the cartridge lid that will swing open.
I cut my lid on the laser at the lab. Our laser with the picture line up was being repaired, so I used the older laser that you manually align. I brought my lid file in corel draw on the laser computer from an SVG off the fusion file. I used the epilog settings for Acrylic.

When it ran on the laser, Collin Kanofsky pointed out that the laser was running twice in certain areas but not others. So I needed to modify the corel file to remove the overlapping lines.

It wasn't cutting through so we needed to run it multiple times. When trying to adjust our cut path, I moved the part in the file and then it cut through the wrong part.

I separated the two and then deleted the extra and then ran it again over 3 inches to a clean spot. I had to run the cut multiple times to cut through. Possible dirty lense?

Electronics Design¶
I started working on the stepper motor and the electronics design with a tutorial. I used first the RP 2040 and then did it again with the ESP32C6. In the end, I went with the XIAO ESP32C6 to move forward with my project.
I used a breadboard to start laying it out to see if it would work.

During our electronics design week, I designed a board that I could use in the final project. I may need to make it smaller or change the shape if I want it to fit into my project. or it can be on the side since it fits the theme.

Computer Controlled Machining¶
I'd like to make my base for my pill dispenser from wood for aesthetics.
I did some preliminary work in easel, but ran out of time during the CCM week, hopefully I will get back to it.


Electronics Production¶
During our electronics design week, we learned to mill boards. My final board had a smaller shape than the original cool brain to fit into the machine, but a similar component layout.
I'm using the board that I milled in week10 but didn't finish that week.
Soldering¶
Classmate Dorian Fritze sent me a link to these medical grabbers that lock. They were a COMPLETE game changer for soldering.
I laid out my components and got to work.

Drilling¶
I manually attached the power connector. I used a trick from Collin Kanofsky by putting the phone as a flashlight to locate my traces and mark out where I wanted to drill.

Then I put the board in a vice and drilled with the smallest bit I had, which was unfortunately a 1/16th - still pretty big. but worked.

Testing Lots of Testing¶
I used the multimeter in continuity mode to test test and test some more.. every connection, and every gpio to each other. I found that I had some solder bridging and had to go back in and clean it up so there would not be connections where I didn't want them.


NEMA 8 Stepper Motor¶
Following the same tutorial that Mr. Dubick sent, I tried the twist test on the four wires that connect the stepper motor to figure out which two wires of my NEMA8 are a pair.

When the twist was clicky, those were a pair compaired to smooth when you turn the motor shaft. This wasn't convincing for me so I to find the phases using the multimeter. Continuity testing will determine theo ne phase of the motor that goes on 1A and 1B pins, and the other phase on 2A and 2B pins.

A4988 Motor Driver Current Limiting¶
I need to adjust the current limit of the driver to be lower than the current rating of the motor, so that the motor will NOT overheat.
I hooked everything up. It took me a really long time because I was really worried about the 12V current and making sure that I didn't mess anything up (i.e. burn up the chip especially after how long it took me to mill the board and solder everything on).
I found the tiny sense resistors on the 4988 and they were 100mOhm (I would use .1 in my calculations). They connect to the motor coils.
I then measured the Vref reading by measuring over the potentiomer to the ground with a multimeter set to Voltage reading. The below picture from the tutorial was really helpful.

I turned the potentiomer to be less than my calculated Vref for a 0.6 max Amp motor. This meant that it should read ~0.39 for my project.

Photoresistor¶
To incorporate the photo resistor, I had to put heat shrink around one leg so they didnt touch in the tunnel. Then on the ends, I used an extension to connect to the board. One one end of the extension, I used the shrink wrap tube with solder into it to extend it.

I decided to try traditional soldering for the other end becuase I worried about the heat gun melting my 3D printed part.
Two Buck Chuck¶
I have two power sources coming from device. One from the chip and another powering the motor. I did some research and it sonds like I need a to use a small DC-DC buck converter to step it down to 5V for the XIAO. So I will split the currnt coming using another little chip that I will mill and then have a buck on it and two outputs.. a 12V (power to the motor) and a 5V (power to the chip).
Embeded Programming¶
I started with the codes I had made in the weeks coming up to combine together to make the code. I have the following code pieces:
- code that turns on and off light a light from a browser on my phone
- code that reads the light value from my photo resistor and then takes an action
- code that spins a stepper motor 1/8 a turn
I used a series of prompts and then took pieces from each to keep modifying my initial code working towards a final code.
Motor Programming¶
I have started working on programming a motor to move in steps. I need 8 steps per revolution to match my design. I found some documentation to help me with the arduino stepper library. For the example motor I have from my ELEGOO kit.. its 2048/8. I have another motor that i want to try that I got from the lab. More research is needed.
I started learning using the stepper.h library but the A4982 doesn't work that way. It only wants a STEP pulse and a DIR signal. So my code uses delayMicroseconds(1000) to set up step pulse timing. I found that 20,000 had it spinning too fast and at 8,000 it was missing steps. I ended with delays 15,000 and that worked well. It's a bit jerky. The fix for that is microstepping, but that will be in V2 becuase I grounded my microsteppers on the PCB under my chip. The stepping will work accurately enough for what I need in V1.
PROMPT: my motor is warm - not hot hot , but warm. is that ok?
CLAUDE: Yes, warm is totally normal for a stepper motor — actually expected. Steppers are always energized even when standing still, so they generate heat continuously. Your NEMA 8 is a small motor so it'll warm up faster than a bigger one.
The rule of thumb: if you can hold your hand on it comfortably, you're fine. If it's too hot to touch, that's when to worry.
A few things that affect how warm it runs:
- Current limit (Vref) — if your Vref is set higher than needed, the motor runs hotter. Worth checking that your Vref is dialed in for 0.6A
- Holding torque — when the motor is just sitting there energized between moves it still draws current. You can add a disable-when-idle feature later if heat becomes a concern:
// after a move, disable the driver
digitalWrite(ENABLE_PIN, HIGH); // HIGH = disabled on most drivers
// re-enable before next move
digitalWrite(ENABLE_PIN, LOW);
My Vref is way below my calculation. So, I incorporated that code to disable the motor, and moved on.
Another issue with the code was that my initial print line asking how many slots I wanted to turn was not coming up..
PROMPT: the initial print line is not coming up from void set up
CLAUDE: Try adding a longer delay
I did that and it worked
I wanted to add some timing in so that the user would have the motor turn at the same time every day to dispense the pills.
PROMPT: I want the stepper motor to rotate one step based on the time of day that was input by the user
CLAUDE: 2:36 PM Here's the plan before I write the code — just to make sure we build it right:
User types a time (like 08:00) into Serial monitor Motor advances 1 slot at that time each day ESP32 tracks time internally after the user sets it A few quick questions:
Q: How should the user enter the time? A: Hour and minute (e.g. 08:30)
Q: Does the ESP32 need to know the current time, or just count down from when it's powered on? A: Know real current time (needs RTC or NTP)
2:37 PM Since you need real current time, the easiest approach for the ESP32-C6 is NTP (Network Time Protocol) — it grabs the time from the internet over WiFi. No extra hardware needed since the ESP32-C6 has WiFi built in.
I need two more things before I write the code:
Q: What timezone are you in?
A: Eastern (UTC-5/-4)
Q: Should the dispensed time be changeable without re-uploading code?
A: Yes - user sets it via Serial monitor each boot
How it works at boot:
- Connects to WiFi
- Syncs current time from NTP
- Asks you to type the dispense time (e.g. 08:30)
- Checks every 30 seconds and fires when the time matches
- Won't dispense twice in the same day
I realized I didnt want the code checking all the time becuase its a set it once in a while but really its there... and I dont want to loose it at a reboot.
PROMPT: Eventually I will want this information to come from an app and stay in the memory if the power goes out and comes back on. Do I need to change anything in the code. The time will not be changed often.
Good thinking to plan ahead. Yes, you'll need two additions eventually:
- NVS (Non-Volatile Storage) — saves the dispense time to the ESP32's flash memory so it survives a power outage. The Preferences library handles this and is built into Arduino for ESP32.
- WiFi communication — instead of Serial input, a simple web server or MQTT broker lets your app send the time to the ESP32.
The good news is the core motor code won't change at all. The only thing that changes is how the dispense time gets set and where it's stored.
Here's the upgrade priority order:
| steps | Description |
|---|---|
| Current code: | Serial input → RAM (lost on power off) |
| Next step: | Serial input → NVS flash (survives power off) |
| Final step: | App → WiFi → NVS flash (survives power off) |
I'd suggest we add the Preferences NVS storage now since it's a small change and solves the power outage problem immediately. Then when you're ready to build the app we just swap the Serial input for a WiFi endpoint.
Want me to add the Preferences storage to the current code? It would:
Save the dispense time to flash the first time you enter it
On reboot, load the saved time automatically and skip the Serial prompt
Only ask for a new time via Serial if none has been saved yet
PROMPT: i need a way to change the time later if i want to..
CLAUDE: Easy fix — we can check Serial on boot and give a short window to override the saved time:
Boot behavior:
- Load saved time from flash
- Print "Saved time is 08:30 — press any key in 5 seconds to change it"
- If no key pressed → run with saved time
- If key pressed → prompt for new time, save it, run
That way normally it just boots and goes, but you have an escape hatch to change it anytime by just opening the Serial monitor right after a reset.
Boot behavior:
- First boot ever → asks for time, saves it
- Every boot after → shows saved time, waits 5 seconds
- Open Serial monitor quickly after reset and press any key to change it
- No key press → runs automatically with saved time
When you're ready to add the app, we just add a WiFi endpoint that calls saveTime() and updates dispenseHour/dispenseMinute — everything else stays exactly the same.
At first, I wasn't able to get to the reset, but by increasing the delay after the Serial.begin, I was able to get to the part where I could change the time. I tried a time that was 30 seconds later and it worked .. the stepper motor moved 1/8 rotation.
Next I went to test my photosensor
photoresistor code¶
I brought in my code from my photo resistor from week 9 inputs and started to work with it changing the pin numbers to match what was on my board. I noticed that the numbers wer much higher and that they were going up when I put my hand over the sensor instead of down.
I loaded my code into Claude and started working.
PROMPT: strange light calues... really high when its dark like 3000,,, whats goingo n
The problem is ADC_11db attenuation — that's actually the issue with your photoresistor readings.
What's happening
analogSetAttenuation(ADC_11db) sets the ADC input range to 0–3.9V, which sounds good, but on the ESP32-C6 specifically, 11db attenuation is known to be noisy and inaccurate, especially at the low end of the range. You get garbage high readings even with little/no light.
Fix options
Option 1 — Drop the attenuation (easiest)
// Remove this line entirely, or change to:
analogSetAttenuation(ADC_0db); // 0–1.1V range
The tradeoff is a smaller input voltage range, but photoresistors in a voltage divider usually don't need the full 3.9V range anyway.
Option 2 — Use 6db instead
analogSetAttenuation(ADC_6db); // 0–2.2V range — better noise behavior
Option 3 — Average multiple readings (helps regardless)
int readLight() {
long sum = 0;
for (int i = 0; i < 8; i++) {
sum += analogRead(lightPin);
delay(5);
}
return sum / 8;
}
Then call readLight() instead of analogRead(lightPin).
Also check your wiring
Make sure your photoresistor is in a proper voltage divider with a pulldown resistor (typically 10kΩ) to GND — a floating pin will also give wild readings.
3.3V → [photoresistor] → A1 → [10kΩ] → GND
Try removing the analogSetAttenuation line first — that's almost certainly the culprit.
I removed the analogSetAttenuation line, but the numbers were still reversed.. I had my wiring backwards
So I flipped the logic and changed the threshold to match my currrent set up. I can't change the wiring this time.. V2... I will need to get new values for lighting with different pills.
Coding to Application.. going to layer 7¶
It's networking week.. time to figure this out again... and better..
Working with Claude a bunch.. Here was our conversation.
System Integration¶
Testing¶
Light Sensor Tuning¶
Using the IP address an the/lightstatus in my browser, I was able to take multiple readings in different light conditions with different pills.
| Light/Pill Status | ADC Value | Threshold setting | Pill taken? |
|---|---|---|---|
| Dim Light | Raw ADC: 2400 | Threshold: 2000 | Pill taken: NO |
| Dim Light + B-12 | Raw ADC: 3317 | Threshold: 2000 | Pill taken: NO |
| Dim Light + Lysine | Raw ADC: 3299 | Threshold: 2000 | Pill taken: NO |
| Dim Light + Zyrtec | Raw ADC: 3206 | Threshold: 2000 | Pill taken: NO |
| Bright Light | Raw ADC: 946 | Threshold: 2000 | Pill taken: YES |
| Bright Light + Zyrtec | Raw ADC: 2919 | Threshold: 2000 | Pill taken: NO |
| Bright Light + Zyrtec2 | Raw ADC: 2943 | Threshold: 2000 | Pill taken: NO |
| Bright Light + Lysine | Raw ADC: 2739 | Threshold: 2000 | Pill taken: NO |
| Bright Light + B-12 | Raw ADC: 3256 | Threshold: 2000 | Pill taken: NO |
2000 Threshold is too low. Maybe closer to 2600… would be more reasonable.
MIDTERM REVIEW REQUIREMENTS¶
On your final project site post - a system diagram for your project, list the tasks to be completed, - make a schedule for doing them, - meet with your local and global instructors to review these and your weekly assignments. (scheduled for 4/20/2026)
System Diagram ¶
Diagram
Claude Co work Assisted PROMPT: help me make A map of my pill dispenser project and all of the components - maybe in power point of google slides so i can edit it



List of things to be completed ¶
- Reprint 3D cartridge body, divider and stepper motor key
- test function and tune settings
- implement power splitter - buck?
- System integration
- Create code
- Create interface
- make slide
- make video
My Claude assisted Time Line is Here
PROMPT: make a gaant style time line for getting these things done by the end of May