Spisu treści:
- Kieszonkowe dzieci
- Krok 1: Okablowanie
- Krok 2: Spraw, aby Twoje ogniwo obciążnikowe było użyteczne
- Krok 3: Znormalizowana baza danych
- Krok 4: Kodowanie ogniwa obciążnikowego
- Krok 5: Kodowanie czujnika wody
- Krok 6: Kodowanie czujnika zbliżeniowego
- Krok 7: Kodowanie silników krokowych
- Krok 8: Kodowanie wyświetlacza LCD
- Krok 9: Koniec
Wideo: AUTOMATYCZNY DOZOWNIK KARMY DLA ZWIERZĄT: 9 kroków
2025 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2025-01-13 06:58
Czy kiedykolwiek miałeś ochotę marnować zbyt dużo czasu na karmienie swojego zwierzaka? Czy kiedykolwiek musiałeś zadzwonić do kogoś, aby nakarmił twoje zwierzęta, gdy byłeś na wakacjach? Próbowałem rozwiązać oba te problemy w moim obecnym projekcie szkolnym: Petfeed!
Kieszonkowe dzieci
Raspberry Pi 3b
Ogniwo obciążnikowe pręta (10 kg)
Wzmacniacz tensometryczny HX711
Czujnik poziomu wody (https://www.dfrobot.com/product-1493.html)
Ultradźwiękowy czujnik zbliżeniowy
LCD 16 pinów
2x silnik krokowy 28byj-48
2x sterownik silnika krokowego ULN2003
Krok 1: Okablowanie
dużo okablowania tutaj. Wyjmij kable rozruchowe i zacznij przypinać!
Krok 2: Spraw, aby Twoje ogniwo obciążnikowe było użyteczne
aby użyć ogniwa obciążnikowego, musimy najpierw przymocować go do dwóch talerzy: dolnego talerza oraz talerza, na którym będziemy ważyli nasze jedzenie.
Potrzebne śruby to para śrub M4 z pasującymi śrubami i para śrub M5 z pasującymi śrubami. Do wykonania otworów użyłem małego wiertła.
(zdjęcie:
Krok 3: Znormalizowana baza danych
dane z naszych czujników muszą być zapisane w bazie danych. Pliki Pythona do połączenia z bazą danych: patrz poniżej.
wtedy potrzebujesz również pliku konfiguracyjnego:
[connector_python]user = *yourusername* host = 127.0.0.1 #if lokalny port = 3306 password = *yourpassword* database = *yourdb* [application_config] driver = 'SQL Server'
Krok 4: Kodowanie ogniwa obciążnikowego
import RPi. GPIO jako GPIOimport wątków import czasu z hx711 import HX711 z helpers.stepperFood import StepperFood z helpers. LCDWrite import LCDWrite z repozytoriów. DataRepository import DataRepository
Po zaimportowaniu wszystkich naszych bibliotek (uwaga, używamy biblioteki HX711 do sterowania ogniwem obciążnikowym) możemy zacząć pisać nasz rzeczywisty kod
TARRA_CONSTANT = 80600
STAŁA GRAM = 101
Aby znaleźć nasze stałe, najpierw ustaw TARRA_CONSTANT = 0 i GRAM_CONSTANT = 1.
Następnie musimy dowiedzieć się, jaką wartość odczytuje nasze ogniwo obciążnikowe, gdy nic nie jest ważone. Ta wartość to TARRA_CONSTANT.
Jeśli chodzi o GRAM_CONSTANT, po prostu weź przedmiot, którego wagę znasz (użyłem paczki spaghetti), zważ go i podziel odczyt ogniwa obciążnikowego z rzeczywistą wagą przedmiotu. Dla mnie było to 101.
class LoadCell(threading. Thread):
def _init_(self, socket, lcd): threading. Thread._init_(self) self.hx711 = HX711(dout_pin=5, pd_sck_pin=6, kanał='A', wzmocnienie=64) self.socket = gniazdo self.lcd = LCD
tutaj inicjujemy klasę LoadCell i mapujemy piny.
def run(self):
try: while True: self.hx711.reset() # Zanim zaczniemy, zresetuj HX711 (nieobowiązkowo)measures_avg = sum(self.hx711.get_raw_data()) / 5 weight = round((measures_avg - TARRA_CONSTANT) / GRAM_CONSTANT, 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) z wyjątkiem wyjątku jako e: print („Błąd z ważeniem” + str(e))
Krok 5: Kodowanie czujnika wody
import timeimport wątków z repozytoriów. DataRepository import DataRepository z RPi import GPIOGPIO.setmode(GPIO. BCM) GPIO.setwarnings(False) GPIO_Water = 18 GPIO.setup(GPIO_Water, GPIO. IN) class WaterSensor(threading. Thread): def self, socket): threading. Thread._init_(self) self.socket = gniazdo 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) z wyjątkiem wyjątków np: print(ex) print('error bij watersensor') def is_water(self): status = GPIO.wejście (GPIO_Wate r) if self.vorige_status == 0 i 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 and status == 1: print('water aanwezig') sensorData = {"status": status, "action": "water aanwezig"} status = GPIO.input(GPIO_Water) if self.vorige_status == 1 and status == 0: print('wagę wody') sensorData = {"status": status, "action": "wagę wody"} self.vorige_status = status status = GPIO.input(GPIO_Water) if self.vorige_status == 0 i status == 0: print('startpositie') status = GPIO.input(GPIO_Water) sensorData = {"status": status, "action": "startpositie"} return sensorData
Krok 6: Kodowanie czujnika zbliżeniowego
importuj timeimport wątków z repozytoriów. DataRepository importuj DataRepository z RPi import GPIO GPIO.setmode(GPIO. BCM) GPIO.setwarnings(False) GPIO_Trig = 4 GPIO_Echo = 17 GPIO.setup(GPIO_Trig, GPIO. OUT) GPIO_Echo(False). 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 = socket def run(self): try: last_reading = 0 interval = 5000 while True: if current_milli_time() > last_reading + interval: dist = self.distance() print("Zmierzona odległość = %.1f cm" % dist) DataRepository. insert_proximity(dist) data_prox = DataRepository.get_data_sensor(1) historyId = data_prox["SensorsHistory"] prox = data_prox["wartość"] actionTime = data_prox["actionTime"] self.socket.emit('data_proximity', { "id": historyId, "Proximity": prox, "Time": DataRepository.serializeDateTime(actionTime)}) last_reading = current_milli_time() z wyjątkiem wyjątku jak np. print(ex) de f distance(self): # ustaw Trigger na HIGH GPIO.output(GPIO_Trig, True) # ustaw Trigger po 0.01ms na 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 start time while GPIO.input(GPIO_Echo) == 1: StopTime = time.time() # różnica czasu między startem a przyjazdem TimeElapsed = StopTime - StartTime # pomnóż przez prędkość dźwięku (34300 cm/s) # i podziel przez 2, ponieważ odległość tam i z powrotem = (TimeElapsed * 34300) / 2 odległość powrotu
Krok 7: Kodowanie silników krokowych
import RPi. GPIO jako GPIOimport czasu import wątków GPIO.setmode(GPIO. BCM) GPIO.setwarnings(False) control_pins = [12, 16, 20, 21] for pin w control_pins: GPIO.setup(pin, GPIO. OUT) GPIO.output(pin, 0) halfstep_seq =
Ten kod jest wielokrotnego użytku dla drugiego silnika krokowego, wystarczy ustawić numery pinów sterujących na odpowiednie piny i zmienić nazwę klasy na StepperWater:
Krok 8: Kodowanie wyświetlacza LCD
Dużo kodu, ale prawie skończyliśmy.
Klasa LCD jest zawarta jako plik LCD.py
od pomocników. 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]) class LCDWrite: def message(msg): try: print("try") lcd.init_LCD() lcd.send_instruction(12) lcd.clear_display() lcd.write_message(msg, '1') z wyjątkiem: print("błąd LCDWrite")
Krok 9: Koniec
efekt końcowy: jak to sporządziliśmy a jak to się skończyło.