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()