Skip to content

Commit

Permalink
now will keep retrying every minute, so the user notices the feeder n…
Browse files Browse the repository at this point in the history
…eeds to be refilled
  • Loading branch information
psy0rz committed Oct 4, 2024
1 parent 6b9a148 commit a71b644
Showing 1 changed file with 58 additions and 50 deletions.
108 changes: 58 additions & 50 deletions src/feeder.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import time

import asyncio
from asyncio import Event

Expand All @@ -20,8 +22,6 @@
from enum import Enum




class Feeder(Model):
"""operate the feeder servo and monitor if the food correctly dropped on the food_scale """

Expand All @@ -31,7 +31,7 @@ class Feeder(Model):
reverse_time = IntegerField(default=500)

empty_weight = FloatField(default=1)
retry_max = IntegerField(default=10)
retry_max = IntegerField(default=3)
retry_timeout = IntegerField(default=1000)

__food_scale: Scale
Expand All @@ -43,9 +43,10 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.feeding = False
# request a feed cycle
self.__event_request = Event()

#For GUI feedback
# For GUI feedback
self.status_msg = "Ready"
self.status: Status = Status.OK

Expand Down Expand Up @@ -82,68 +83,75 @@ def __log(self, status: Status, msg: str, log: str):
print(f"Feeder: {log}")

def food_detected(self):
"""is there food in the scale?"""
return self.__food_scale.last_stable_weight > self.empty_weight

async def task(self):
"""will wait for feed requests and monitor the foodscale to see if it succeeded.
also handles retries and errorr"""
async def wait_for_food(self, timeout):
"""wait for food in scale, returns True when detected, and false when timout"""

# async def food_landed():
# """scale should become unstable when the food lands"""
# if self.__food_scale.stable:
# self.__log(Status.BUSY, "Dropping", "Waiting for food to land.")
# try:
# await asyncio.wait_for(self.__food_scale.event_unstable.wait(), timeout=self.retry_timeout / 1000)
# return True
# except asyncio.TimeoutError:
# self.__log(Status.BUSY, "Timeout", f"Timeout! (attempt {attempts})")
# return False

#program startup
await self.__food_scale.event_stable.wait()
start_time = time.time()
while time.time() - start_time < timeout:
await asyncio.sleep(1)
if self.food_detected():
return True
# timeout
return False

# wait for feed request
while await self.__event_request.wait():
async def valid_state(self):
"""wait until system is in a valid state to run feeder (food scale not removed)"""

# wait until scale is in valid range
while self.__food_scale.last_stable_weight < ERROR_WEIGHT_BELOW or self.__food_scale.last_stable_weight > ERROR_WEIGHT_ABOVE:
self.__log(Status.ERROR, "Out of range", "Error, scale out of range!")
await self.__food_scale.event_stable.wait()

# wait until scale is in valid range
while self.__food_scale.last_stable_weight < ERROR_WEIGHT_BELOW or self.__food_scale.last_stable_weight > ERROR_WEIGHT_ABOVE:
self.__log(Status.ERROR, "Out of range", "Error, scale out of range!")
await self.__food_scale.event_stable.wait()
# wait until food scale stable
if not self.__food_scale.stable:
self.__log(Status.BUSY, "Waiting", f"Waiting until scale is stable")
await self.__food_scale.event_stable.wait()

if not self.__food_scale.stable:
self.__log(Status.BUSY, "Waiting", f"Waiting until scale is stable")
await self.__food_scale.event_stable.wait()
async def feed_and_wait(self):
"""run feeder and wait for food to drop, retrying a few time if needed"""

self.feeding = True
self.feeding = True

# attempt a few times to get food in the scale
attempts = 0
while not self.food_detected() and attempts <= self.retry_max:
# attempt a few times to get food in the scale
attempts = 0
while not self.food_detected():

self.__log(Status.BUSY, "Feeding", f"Feeding")
await self.forward()
await self.valid_state()

#wait long enough so we can be SURE the food should have dropped
await asyncio.sleep(self.retry_timeout/1000)
self.__log(Status.BUSY, "Feeding", f"Feeding")
await self.forward()

if not self.__food_scale.stable:
self.__log(Status.BUSY, "Weighing", f"Weighing food")
await self.__food_scale.event_stable.wait()
# wait long enough so we can be SURE the food should have dropped
await asyncio.sleep(self.retry_timeout / 1000)

attempts = attempts + 1
if not self.__food_scale.stable:
self.__log(Status.BUSY, "Weighing", f"Weighing food")
await self.__food_scale.event_stable.wait()

self.feeding = False
self.__event_request.clear()
attempts = attempts + 1

# succeeded or food silo empty?
if self.food_detected():
self.__log(Status.OK, "Ready", f"Ready: {self.__food_scale.last_stable_weight:0.2f}g")
else:
await self.__reverse()
# too many attempts. keep retrying every 60s so the user might notice
if attempts > self.retry_max:
self.__log(Status.ERROR, "Refill!", f"PLEASE REFILL AND TOUCH SCALE")
await self.__food_scale.event_stable.wait()
self.__log(Status.OK, "Ready", f"Resuming operation")
await self.wait_for_food(10)

self.__log(Status.OK, "Ready", f"Ready: {self.__food_scale.last_stable_weight:0.2f}g")
self.feeding = False
self.__event_request.clear()

async def task(self):
"""will wait for feed requests and monitor the foodscale to see if it succeeded.
also handles retries and errorr"""

# program startup
await self.__food_scale.event_stable.wait()

# wait for feed request
while await self.__event_request.wait():
await self.feed_and_wait()

def request(self):
"""request a feed cycle, if its not already running and if foodscale is considered empty"""
Expand Down

0 comments on commit a71b644

Please sign in to comment.