Pill Dispenser Alarm
Allison Feldman
Allison Feldman
This project is inspired by a tip my friend gave me when I got diagnosed with ADHD a few years ago and started taking medication. This advice was to try to take ADHD medication at the same time every day, regardless of your schedule, to avoid interfering with your sleep. I have seen benefits following this advice for short periods of time, but doing anything consistently is quite difficult as a college student. This project is designed to force taking my medication to be the first thing I do every day, even if I decide to go back to bed after taking it. At a pre-determined time each day, a single pill is released from the pill dispenser onto a load cell bar as an alarm sounds. When, and only when, that pill is lifted (or a safety timeout mechanism is triggered), the alarm will stop. The main components of this project include a pill box carousel, a stepper motor, a load cell bar, and a buzzer.
Angled photo displaying the entire pill dispenser and alarm system, which includes a partially-filled carousel, a load cell bar, a buzzer, and all electrical connections, including a connection between the stepper motor driver and an external 9V DC power adapter.
This photo highlights the design of the pill dispenser carousel. The stepper motor is connected to the top 3D-printed layer, while the bottom 3D-printed layer is attached to support beams connected to the base of the project. When the stepper motor rotates, the walls of the carousel rotate while the bottom wall, with a single, pill-sized opening, stays in place.
This photo shows the device being used. The two white and orange pills are "queued up" to be dispensed from the carousel. To dispense a pill, the carousel rotates clockwise in small increments.
This photo depicts the size of the entire project. The carousel itself is the bulkiest standalone component. The rest of the components could be fairly easily condensed to the size of a single large breadboard.
This photo shows almost all of the wiring to connect the load cell bar amplifier, the buzzer, and the stepper motor driver to an Arduino Uno.
The above photo of the back of the device, shows the stepper motor wired underneath the pill dispenser, with these wires running out of the way of where pills are released, which is in the front.
In this video, I show the a time change triggering a pill release. At this time, the carousel rotates about 15°, allowing a pill to be released onto the slide and then onto the platform. Additionally, the buzzer begins making noise, and doesn't stop making noise until the pill has been lifted from the platform. I mimic the pill landing on the platform by pressing down on the load cell bar and then lifting my hand a few seconds later. When I actually use the dispenser, I will configure it so pills are dispensed at 7:00 AM exactly every day.
Some initial sketches, showing multiple ideas for how to position the 30 pills around a center axis. I eventually decided on the carousel model as it was the least mechanical.
Cutting out the platform components to screw onto my load cell bar. I decided to cut these manually, as I frequently adjusted the angle and height of the slide that carried the pill from the carousel onto the platform.
Shown above is a small, 3D printed piece of acrylic, with holes in specific places, screwed into a mounting hub. This little piece of acrylic was used to test how I was going to mount the carousel to the stepper motor, as well as how tall my support beams needed to be to properly stabilize the dispenser. I got lucky first-try; this pattern of holes, as well as the acrylic's thickness, was replicated on the bottom of my carousel.
This photo depicts some initial attempts to solder components to a protoboard. I soon realized I used the wrong type of board and had to redo this circuit. However, the photo showcases a stepper motor driver and load cell bar amplifier, the two main logical components of the project.
This photo depicts the final iteration of the carousel, before the stepper motor was wired. While everything was aligned, I was a bit concerned as to whether my load cell bar would fit under it. Looking back, I would have liked to have more time to experiment with how to condense the size of my load cell bar contraption. From here I conducted multiple tests using the stepper motor to determine an ideal angular rotation speed and how to best define a "step."
Shown above are digital iterations of the carousel design, created digitally on Fusion 360. I decided, after parsing through available materials, that 3D printing the carousel would allow me to create the cylindrical shape I desired. To create the support beams, however, laser cutting proved to be the best technique.
While I was not in class for critique, I can anticipate a few potential questions and comments my classmates would have had. Firstly, I can imagine that at least a few of my classmates take a daily medication similar to mine, and I hope those classmates would have imagined themselves using this device. Second, I likely would have received a question along the lines of: "What would happen if you accidentally skipped a slot when refilling the carousel?" While this is not implemented in the current project, I would ideally like the machine to keep turning 15° every few seconds until either a pill falls or the device determines there are no more pills left to dispense. Lastly, I hypothesize that I could've been asked a question like: "What would happen if a user wanted to retrieve a pill while the machine is off or in between active periods?" Due to the size and shape of the pill slots in the current design, the easiest way to remove pills is to flip the device upside down, which is certainly a design flaw. In a future iteration of the project, I would incorporate a lever or dial that can mechanically turn the carousel without the use of electricity.
Upon personal reflection, this project taught me that I struggle greatly with methodically combining electrical components. My process of debugging often consisted of spending a few minutes on one component, getting frustrated, and moving on to another component. This process not only slowed my progress but also made it difficult for me to gauge how much work I had done and had left to do. Instead, I should have followed a unit-testing approach, by getting each component to work close to 100% before moving on to the next, an approach I already follow when programming Software. Secondly, I soldered my stepper motor driver and load cell bar amplifier way too early in the design process; it was only after I soldered all drivers and wires to a single board that I realized I needed to swap the protoboard type and replace a fried stepper motor driver.
Prior to starting the project, I suspected that my strongest skill set would be my software programming. After completing the project, I can say that this is certainly true. While it took me slightly longer than I expected to program the stepper motor, debugging code feels much more linear to me than any hardware debugging.
Overall, I feel that I accomplished most of my overall goals for the project (except for timeliness!) and gave me confidence in my programming abilities. While I don't expect to build another iteration of the device, I plan on utilizing the skills I learned over the past few weeks in my final project.
Block Diagram:
Schematic Diagram:
/*
Written by: Allison Feldman (Andrew ID: abf2) for Project 2 of Carnegie Mellon course 60-223, "IDeATe Portal: Introduction to Physical Computing"
Project Name: Pill Dispenser Alarm
This file contains code to program an Arduino Uno which is connected to a "Pill Dispenser Alarm" system.
This system helps individuals take a particular medication at the same time every day by combining a pill dispenser and an alarm clock. At the time a pill is dispensed, a buzzer is turned on, which won't turn off until the dispensed pill has been taken.
The pins in use are:
D2: an "output" pin that triggers the movement of a stepper motor.
D3: an "output" pin that defines the direction of the stepper motor.
D5: an "output" pin that powers a load cell bar amplifier.
D6: an "input" pin that takes in data from the load cell bar amplifier.
D8: an "output" pin that controls the state of a buzzer.
The program is currently in "demo" mode, meaning the length of a day is defined as 20,000 milliseconds, rather than capturing live time data to trigger pill releases.
*/
#include <AccelStepper.h>
#include <HX711.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
// Stepper Motor Pins
const int STEP_PIN = 2;
const int DIR_PIN = 3;
// Load Cell Bar Pins
const int LOADCELL_DOUT_PIN = 5;
const int LOADCELL_SCK_PIN = 6;
// Buzzer Pin
const int buzzerPin = 8;
// Variables related to the system's lifecycle. They keep track of how many pills (out of 30) have been dispensed, as well as whether or not loadCellBar detects stable (or unfluctuating) weight.
int pillsDispensed = 0;
bool isWeightStable = false;
// These thresholds determine whether a pill has dropped onto or removed from the load cell bar.
float minWeightThreshold = 0.1; // Min weight threshold to determine whether capsule has been dropped
float maxWeightThreshold = 0.04; // Max weight threshold to determine whether capsule has been removed
// Stepper Motor Logistics
const float stepsFor12Degrees = 53;
const float initialSpeed = 100;
const float initialAcceleration = 50;
const float normalSpeed = 600;
const float normalAcceleration = 100;
const float homePosition = 56;
unsigned long cycleStartTime; // used as a safety mechanism to "time out" if the buzzer has been playing for more than 2 minutes.
unsigned long currentTime;
AccelStepper myMotor(1, STEP_PIN, DIR_PIN);
HX711 scale;
void setup(){
Serial.begin(9600);
pinMode(buzzerPin, OUTPUT);
// Initialize the motor with a lower-than-nromal speed and acceleration to mitigate sudden movement
myMotor.setMaxSpeed(initialSpeed);
myMotor.setAcceleration(initialAcceleration);
delay(2000);
myMotor.moveTo(homePosition); // "Home, which is halfway between 2 slots
while (myMotor.distanceToGo() != 0) {
myMotor.run();
}
// Set speed and acceleration to normal
myMotor.setMaxSpeed(normalSpeed);
myMotor.setAcceleration(normalAcceleration);
// Initialize the load cell bar
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
scale.set_scale();
scale.tare();
}
bool checkIfWeightStable() {
while (isWeightStable == false) {
float weights[100];
float weightSum = 0;
if (scale.get_units(10) > minWeightThreshold) {
for (int i = 0; i < 100; i++) {
float weight = scale.get_units(1);
weights[i] = weight;
weightSum += weight;
delay(10);
}
float weightAverage = weightSum / 100;
for (int j = 0; j < 100; j++) {
if (abs(weightAverage - weights[j]) > 0.25) { // 0.25 grams
return false;
}
}
return true;
}
}
}
void pillCycle() {
cycleStartTime = millis();
currentTime = millis();
tone(buzzerPin, 440); // start buzzer
// Dispense 1 pill
if (pillsDispensed == 0) {
myMotor.move(stepsFor12Degrees / 2);
} else {
myMotor.move(stepsFor12Degrees);
}
while (myMotor.distanceToGo() != 0) {
myMotor.run();
}
isWeightStable = false;
// Wait for pill to drop onto load cell bar or for there to be a timeout
while ((isWeightStable == false) && (currentTime - cycleStartTime < 120000)) {
currentTime = millis();
int weights[100];
float weightSum = 0;
if (scale.get_units(10) > minWeightThreshold) {
isWeightStable = checkIfWeightStable();
}
}
isWeightStable = false;
pillsDispensed += 1;
// Wait for pill to be removed from load cell bar or for there to be a timeout
while ((isWeightStable == false) && (currentTime - cycleStartTime < 120000)) {
currentTime = millis();
isWeightStable = checkIfWeightStable();
}
// Assume pill has been taken or there has been a timeout
noTone(buzzerPin); // Stop buzzing
}
void loop(){
pillCycle();
cycleStartTime = millis();
if (pillsDispensed >= 30) {
// Reset pills and prepare to refill dispensor
pillsDispensed = 0;
myMotor.moveTo(homePosition);
while (myMotor.distanceToGo() != 0) {
myMotor.run();
}
}
Serial.println("Cycle complete");
delay(20000);
}