March 22, 2025
Description
This project automatically pushes a single Milk Bone from a hopper. When powered on, the dispenser initializes by pulling the rack back for 2 seconds then releasing tension. When the arcade button is pushed, a servo connected to a pinion pushes out the Milk Bone and then retracts, allowing for gravity to ready the next bone from the hopper. There is a variable delay as to not allow our dog to get too many treats at once. The dispenser wont re-arm until after it's cooldown period.
After watching the movie Honey, I shrunk the kids, my son and daughter were fascinated with "the automatic dog feeder" from the movie. So we worked together to design and name our own "Dog Treat Dispenser". Now our German Shepherd, Scout, can grab a snack when she wants. There is a timer in the logic to only allow her one Milkbone every x amount of time so she doesn't eat to much!
This was a great project to show the kids how an idea can go from a thought to code to design and then implementation. We learned about rare problems like, what if the the power goes out when the rack is half way? What to do when the power comes back on? What if our dog presses the button many times in a row? We needed to think of how to programmatically solve these problems.
#include <Servo.h>
// Define servo and button pins as well as configurables
int servoPin = 7; //set the digital output pin for the servo pwm wire
int buttonPin = 4; // set the input button for pin
int initialize = 0; // leave this at zero, this is a counter for first power on initialization
int waittime = 5000; //Set the amount of milliseconds to wait until looking for another treat
int extend = 2000; //extend time
int retract = 2000; //retract time
int initialization = 2000; // How long to pull the rack back for initial startup
// Create servo object
Servo myServo;
void setup() {
// Attach servo to pin
myServo.attach(servoPin);
// Set button pin as input
pinMode(buttonPin, INPUT);
// Enable pull-up resistors (optional)
digitalWrite(buttonPin, HIGH);
}
void loop() {
if (initialize == 0) { //This runs once
myServo.write(0); //it pulls the rack all the way back into ready position
delay(initialization);
myServo.write(180); //releases tension
delay(100);
} else {} //after the program initializes once it doesnt have to anymore
// Read button state
int buttonState = digitalRead(buttonPin); //is the button pressed or no?
// Check if button is pressed. I am using a normally closed switch that opens when pushed, this helps to not need debouce and dealing with noise
if (buttonState == LOW) { //if button is not pushed
myServo.write(85); //idle threshold (normally 90 but mine doesn't move at 85)
} else { //if button is pushed
myServo.write(180);
delay(extend);
myServo.write(0);
delay(retract);
myServo.write(85);
delay(waittime);
}
initialize = 1; // this allows the initialization to be skipped in the beginning
}When the button is pressed a large Milk Bone is ejected and a new one is positioned into the hopper.
License:
Creative Commons — Attribution — Noncommercial — Share Alike