FedPet - Use your Raspberry Pi to feed your pet

Everybody likes technology, even pets do!
We thought it would be great if you could setup a Raspberry Pi to feed a pet at certain times of day, and a controlled amount. Thanks to Tristan Linnell for the idea :)
We will use a PicoBorg to control a 6 wire stepper motor, which when driven will rotate a fixed amount for each step (the angle is specific to the stepper).
For your pets delight we present FedPet.py, a Python script which watches the time and rotates a stepper when scheduled
Here's the code, you can download the FedPet script file as text here
Save the text file on your pi as FedPet.py
Make the script executable usingchmod +x FedPet.py
and run usingsudo ./FedPet.py
You will probably want to change feedSchedule, lines 6-10, to your appropriate feed schedule and amounts.
#!/usr/bin/env python
# coding: Latin-1
# Schedule for pet feeding, list of tupples for feed times
# formatted as ('HH:MM', c) where HH:MM is the time of day and c is the feed count (steps)
feedSchedule = [
('08:30', 25),
('14:00', 10),
('21:00', 25)
]
pollPeriod = 20 # Number of seconds to wait between polls, should be < 60
holdWhenWaiting = False # True to keep the stepper powered when not rotating, false to stop powering
# Import libary functions we need
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import time
# Set which GPIO pins the drive outputs are connected to
DRIVE_1 = 4 # Black
DRIVE_2 = 18 # Green
DRIVE_3 = 8 # Red
DRIVE_4 = 7 # Blue
# Yellow and White are +ve centre taps
# Tell the system how to drive the stepper
sequence = [DRIVE_1, DRIVE_3, DRIVE_2, DRIVE_4] # Order for stepping (see data sheet for the stepper motor)
stepDelay = 0.002 # Delay between steps
# Set all of the drive pins as output pins
GPIO.setup(DRIVE_1, GPIO.OUT)
GPIO.setup(DRIVE_2, GPIO.OUT)
GPIO.setup(DRIVE_3, GPIO.OUT)
GPIO.setup(DRIVE_4, GPIO.OUT)
# Function to set all drives off
def MotorOff():
global step
GPIO.output(DRIVE_1, GPIO.LOW)
GPIO.output(DRIVE_2, GPIO.LOW)
GPIO.output(DRIVE_3, GPIO.LOW)
GPIO.output(DRIVE_4, GPIO.LOW)
step = -1
# Function to perform a sequence of steps as fast as allowed
def MoveStep(count):
global step
# Choose direction based on sign (+/-)
if count < 0:
dir = -1
count *= -1
else:
dir = 1
# Loop through the steps
while count > 0:
# Set a starting position if this is the first move
if step == -1:
GPIO.output(DRIVE_4, GPIO.HIGH)
step = 0
else:
step += dir
# Wrap step when we reach the end of the sequence
if step < 0:
step = len(sequence) - 1
elif step >= len(sequence):
step = 0
# For this step turn one of the drives off and another on
if step < len(sequence):
GPIO.output(sequence[step-2], GPIO.LOW)
GPIO.output(sequence[step], GPIO.HIGH)
time.sleep(stepDelay)
count -= 1
# Function to save the stepper state and disable all drive
def MoveStandby():
global savedState
savedState = [
GPIO.input(DRIVE_1),
GPIO.input(DRIVE_2),
GPIO.input(DRIVE_3),
GPIO.input(DRIVE_4),
]
GPIO.output(DRIVE_1, GPIO.LOW)
GPIO.output(DRIVE_2, GPIO.LOW)
GPIO.output(DRIVE_3, GPIO.LOW)
GPIO.output(DRIVE_4, GPIO.LOW)
# Function to resume the stepper state
def MoveResume():
global savedState
if savedState[0]:
GPIO.output(DRIVE_1, GPIO.HIGH)
else:
GPIO.output(DRIVE_1, GPIO.LOW)
if savedState[1]:
GPIO.output(DRIVE_2, GPIO.HIGH)
else:
GPIO.output(DRIVE_2, GPIO.LOW)
if savedState[2]:
GPIO.output(DRIVE_3, GPIO.HIGH)
else:
GPIO.output(DRIVE_3, GPIO.LOW)
if savedState[3]:
GPIO.output(DRIVE_4, GPIO.HIGH)
else:
GPIO.output(DRIVE_4, GPIO.LOW)
# Make a list of fed times to avoid double feedings
fedAlready = []
for feedTime in feedSchedule:
fedAlready.append([feedTime[0], feedTime[1], False])
print 'At %s feed %d' % (feedTime[0], feedTime[1])
hasResetAtMidnight = False
try:
# Start by turning all drives off
MotorOff()
raw_input('You can now turn on the power, press ENTER to continue')
# Move to initial position, then either hold or let go as needed
MoveStep(1)
if not holdWhenWaiting:
MoveStandby()
# Loop forever
while True:
# Get the current time formatted as HH:MM
now = time.strftime('%H:%M')
# See if we have reached midnight (reset fed list)
if now == '00:00':
# Reset all times to unfed if not done already
if not hasResetAtMidnight:
for feedTime in fedAlready:
feedTime[2] = False
hasResetAtMidnight = True
elif now == '00:01':
# Past midnight, rest latch as we will reset all feeds tomorrow
hasResetAtMidnight = False
# Check to see if any feed time matches the current time
for feedTime in fedAlready:
if feedTime[0] == now:
# Check if this feed has beed done, if not feed
if not feedTime[2]:
print '%s feeding %d' % (feedTime[0], feedTime[1])
if not holdWhenWaiting:
MoveResume()
MoveStep(feedTime[1])
if not holdWhenWaiting:
MoveStandby()
feedTime[2] = True
# Wait for pollPeriod
time.sleep(pollPeriod)
except KeyboardInterrupt:
# CTRL+C exit, turn off the drives and release the GPIO pins
print 'Terminated'
MotorOff()
raw_input('Turn the power off now, press ENTER to continue')
GPIO.cleanup()

