[video width="272" height="480" m4v="http://www.nickwallace.us/blog/wp-content/uploads/2017/10/IMG_0102.m4v"][/video] While reviewing Pcomp concepts this week, I tried mocking up a small scale version of an automated dog feeder that I want to build in the future. I built a cardboard prototype dog feeder that plays a noise and rotates a servo when a button is pressed--the servo is attached to a wheel which dumps the food into a ramp that outputs out of the box it is inside.
This is the initial design sketchup:
Besides learning more about servos and how to create sounds with an Arduino, this was a good lesson in prototyping--my design changed 3-4 times, and I now have a better idea of the tolerances I will need to build into my final design. I also used fritzing for the first time to build a circuit diagram, to decent success.
I build the box and wheel out of cardboard that I laser cut:
Breadboarding the servo setup (fritzing diagram at the bottom):
Testing the servo action:
[video width="272" height="480" m4v="http://www.nickwallace.us/blog/wp-content/uploads/2017/10/IMG_0073.m4v"][/video]
I mounted the servo to the back of the cardboard box, and glued the wheel to the servo horns. Testing:
[video width="272" height="480" m4v="http://www.nickwallace.us/blog/wp-content/uploads/2017/10/IMG_0074.m4v"][/video]
I built out more of the box, and realized I would need some additional "stopped" guards on the inside of the ramps to prevent spillage:
Attempted fritzing diagram:
Arduino code:
// Add libraries
#include <Servo.h>
#include <time.h>
#include <TimeAlarms.h>
#include <pitches.h>
// Setup manual feed button
#define MANUAL_FEED_PIN 3
#define SPEAKER_PIN 8
boolean manual;
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
// Setup Servo
Servo dogFeeder;
int potPin = 0; // Pin used to control potentiometer for servo
int potVal; // Value of potentiometer
// tone/music code taken from tone sketch by Tom Igoe
// zelda "secret unlock" melody (ish) created by ear
int melody[] = {
NOTE_G4, NOTE_FS4, NOTE_DS5, NOTE_A4, NOTE_GS3, NOTE_E5, NOTE_GS5, NOTE_C6
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
8, 8, 8, 8, 8, 8, 8, 8
};
void setup() {
Serial.begin(9600);
Serial.println("Doggo-matic Online!");
Serial.println("------------------------------------------------");
Serial.println();
dogFeeder.attach(2); // Servo on pin 2
// Setup alarms
Alarm.alarmRepeat(9, 00, 0, feed); // Morning feed: 9am
Alarm.alarmRepeat(19, 00, 0, feed); // Evening feed: 7pm
}
void loop() {
buttonState = digitalRead(MANUAL_FEED_PIN); // Read the manual feed button input pin
// Check if button has been pressed by comparing to previous state
if (buttonState != lastButtonState) {
// If the state has changed, feed the dog
if (buttonState == HIGH) {
manual = true;
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000 / noteDurations[thisNote];
tone(8, melody[thisNote], noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}
feed();
}
// Delay a little bit to avoid bouncing
delay(50);
}
// Save the current state as the last state, for next time through the loop
lastButtonState = buttonState;
}
void feed() {
// Play food sound
// CODE HERE
// Read in pot value and turn servo accordingly
potVal = analogRead(potPin);
potVal = map(potVal, 0, 1023, 500, 2000); // Map value to 0.5-2 sec delay
dogFeeder.write(170); // Move the servo to dispense food
delay(potVal);
dogFeeder.write(0); // Reset the servo
time_t lastFed = now();
// Play sit command sound
// CODE HERE
if (manual == true) {
Serial.println("Doggo fed at: [TIME GOES HERE]! (manual)");
Serial.println();
manual = false;
} else {
Serial.println("Doggo fed at: [TIME GOES HERE]!");
Serial.println();
}
}