Obsah:
Video: AUTOMATICKÝ VÝDEJNÍK POTRAVIN: 9 kroků
2025 Autor: John Day | [email protected]. Naposledy změněno: 2025-01-13 06:57
Už jste někdy měli pocit, že ztrácíte příliš mnoho času krmením svého domácího mazlíčka? Už jste někdy museli někomu zavolat, aby nakrmil vaše domácí mazlíčky, když jste byli na dovolené? Oba tyto problémy jsem se pokusil vyřešit pomocí mého aktuálního školního projektu: Petfeed!
Zásoby
Raspberry Pi 3b
Zátěžový článek tyče (10 kg)
Zesilovač zatížení buňky HX711
Senzor hladiny vody (https://www.dfrobot.com/product-1493.html)
Ultrazvukový senzor přiblížení
LCD 16 pinů
2x krokový motor 28byj-48
2x ovladač krokového motoru ULN2003
Krok 1: Zapojení
tady spousta kabeláže. Vytáhněte propojovací kabely a začněte připínat!
Krok 2: Zajistěte použitelnost buňky zatížení
abychom mohli použít siloměr, musíme jej nejprve připevnit ke dvěma deskám: spodní desce a desce, na kterou budeme vážit jídlo.
Potřebné šrouby jsou pár šroubů M4 s odpovídajícími šrouby a pár šroubů M5 s odpovídajícími šrouby. Na vytvoření otvorů jsem použil malý vrták.
(obrázek:
Krok 3: Normalizovaná databáze
data z našich senzorů je třeba uložit do databáze. Soubory pythonu pro připojení k databázi: viz níže.
pak také potřebujete konfigurační soubor:
[konektor_python] uživatel = * vaše uživatelské jméno * hostitel = 127.0.0.1 #if místní port = 3306 heslo = * vaše heslo * databáze = * yourdb * [application_config] ovladač = 'SQL Server'
Krok 4: Kódování zatěžovací buňky
importovat RPi. GPIO jako GPIOimportovat čas importu z hx711 importovat HX711 od pomocníků.stepperFood importovat StepperFood od pomocníků. LCDWrite importovat LCDWrite z úložišť. DataRepository importovat DataRepository
Po importu všech našich knihoven (všimněte si, že k pohonu snímače zatížení používáme knihovnu HX711) můžeme začít psát náš skutečný kód
TARRA_CONSTANT = 80600
GRAM_CONSTANT = 101
Pro zjištění našich konstant nejprve nastavte TARRA_CONSTANT = 0 a GRAM_CONSTANT = 1.
Dále musíme zjistit hodnotu, kterou náš siloměr přečte, když se nic neváží. Tato hodnota bude TARRA_CONSTANT.
Pokud jde o GRAM_CONSTANT, jednoduše vezměte předmět, jehož hmotnost znáte (použil jsem balíček špaget), odvážte jej a vydělte odečet snímače zatížení skutečnou hmotností předmětu. Pro mě to bylo 101.
třída LoadCell (threading. Thread):
def _init _ (self, socket, lcd): threading. Thread._ init _ (self) self.hx711 = HX711 (dout_pin = 5, pd_sck_pin = 6, channel = 'A', gain = 64) self.socket = socket self.lcd = lcd
zde inicializujeme třídu LoadCell a mapujeme piny.
def run (vlastní):
try: while True: self.hx711.reset () # Než začneme, resetujte HX711 (nezávazné) 0) print ("weight: {0}". Format (weight)) DataRepository.insert_weight (weight) data_weight = DataRepository.get_data_sensor (3) historyId = data_weight ["SensorsHistory"] db_weight = data_weight ["value"] actionTime = data_weight ["actionTime"] self.socket.emit ('data_weight', {"id": historyId, "Weight": db_weight, "Time": DataRepository.serializeDateTime (actionTime)}) print ("zou moeten emitten") writeWeight = "weight:" + str (db_weight) msg = "PETFEED" LCDWrite.message () if int (db_weight [:-2]) <= 100: StepperFood.run () time.sleep (20) except Exception as e: print („Chyba při vážení“+ str (e))
Krok 5: Kódování snímače vody
importovat vlákno timeimport z úložišť. DataRepository importovat DataRepository z RPi import GPIOGPIO.setmode (GPIO. BCM) GPIO.setwarnings (False) GPIO_Water = 18 GPIO.setup (GPIO_Water, GPIO. IN) třída WaterSensor (threading. Thread): def _init _ self, socket): threading. Thread._ init _ (self) self.socket = socket self.vorige_status = 0 def run (self): try: while True: water = self.is_water () print (water) status = water [" status "] action = water [" action "] DataRepository.insert_water (str (status), action) data_water = DataRepository.get_data_sensor (2) historyId = data_water [" SensorsHistory "] value = data_water [" value "] if value == "0": value = "te weinig water" else: value = "genoeg water" actionTime = data_water ["actionTime"] self.socket.emit ('data_water', {"id": historyId, "value": value, "Time": DataRepository.serializeDateTime (actionTime), "action": action}) time.sleep (5) kromě Exception jako ex: print (ex) print ('error bij watersensor') def is_water (self): status = GPIO.input (GPIO_Wate r) if self.vorige_status == 0 a status == 1: print ('water gedetecteerd') sensorData = {"status": status, "action": "water gedetecteerd"} self.vorige_status = status status = GPIO.input (GPIO_Water) if self.vorige_status == 1 a status == 1: print ('water aanwezig') sensorData = {"status": status, "action": "water aanwezig"} status = GPIO.input (GPIO_Water) if self.vorige_status == 1 a status == 0: print ('water weg') sensorData = {"status": status, "action": "water weg"} self.vorige_status = status status = GPIO.input (GPIO_Water) if self.vorige_status == 0 and status == 0: print ('startpositie') status = GPIO.input (GPIO_Water) sensorData = {"status": status, "action": "startpositie"} return sensorData
Krok 6: Kódování senzoru přiblížení
importovat vlákno timeimport z úložišť. DataRepository importovat DataRepository z RPi importovat GPIO GPIO.setmode (GPIO. BCM) GPIO.setwarnings (False) GPIO_Trig = 4 GPIO_Echo = 17 GPIO.setup (GPIO_Trig, GPIO. OUT) GPIO.setup (GPIO_Echo, GPIO. IN) def current_milli_time (): return int (round (time.time () * 1000)) class UltrasonicSensor (threading. Thread): def _init _ (self, socket): threading. Thread._ init _ (self) self.socket = běh soketu def (vlastní): zkuste: last_reading = 0 interval = 5000 while True: if current_milli_time ()> last_reading + interval: dist = self.distance () print ("Measured Distance = %.1f cm" % dist) DataRepository. insert_proximity (dist) data_prox = DataRepository.get_data_sensor (1) historyId = data_prox ["SensorsHistory"] prox = data_prox ["value"] actionTime = data_prox ["actionTime"] self.socket.emit ('data_proximity', {"id": historyId, "Proximity": prox, "Time": DataRepository.serializeDateTime (actionTime)}) last_reading = current_milli_time () kromě výjimky jako ex: print (ex) de f vzdálenost (self): # nastavit Trigger na HIGH GPIO.output (GPIO_Trig, True) # set Trigger after 0,01ms to LOW time.sleep (0,00001) GPIO.output (GPIO_Trig, False) StartTime = time.time () StopTime = time.time () # save StartTime while GPIO.input (GPIO_Echo) == 0: StartTime = time.time () # save time of příjezdu while GPIO.input (GPIO_Echo) == 1: StopTime = time.time () # časový rozdíl mezi začátkem a příjezdem TimeElapsed = StopTime - StartTime # vynásobte zvukovou rychlostí (34300 cm / s) # a vydělte 2, protože vzdálenost tam a zpět = (TimeElapsed * 34300) / 2 návratová vzdálenost
Krok 7: Kódování krokových motorů
importovat RPi. GPIO jako GPIOimport čas importovat vlákno GPIO.setmode (GPIO. BCM) GPIO.setwarnings (False) control_pins = [12, 16, 20, 21] pro pin in control_pins: GPIO.setup (pin, GPIO. OUT) GPIO.output (pin, 0) halfstep_seq =
Tento kód je opakovaně použitelný pro druhý krokový motor, stačí nastavit čísla ovládacích pinů na jejich příslušné piny a přejmenovat třídu na StepperWater:
Krok 8: Kódování LCD
Spousta kódu, ale jsme téměř hotovi.
Třída LCD je zahrnuta jako soubor LCD.py
od pomocníků. LCD import LCD
E = 26 RS = 25 D0 = 19 D1 = 13 D2 = 24 D3 = 22 D4 = 23 D5 = 8 D6 = 7 D7 = 10 lcd = LCD (E, RS, [D0, D1, D2, D3, D4, D5, D6, D7]) třída LCDWrite: def zpráva (zpráva): zkus: tisk ("zkus") lcd.init_LCD () lcd.send_instruction (12) lcd.clear_display () lcd.write_message (msg, '1') kromě: print ("chyba LCDWrite")
Krok 9: Konec
konečný výsledek: jak jsme to nakreslili vs. jak to skončilo.