Wie kann ich mein Programm optimieren? Futterautomat

  • Hallo liebe Community,

    mein Name ist Marc und ich bin neu hier im Forum.

    Nun zu meiner Frage.

    Ich bin absoluter Programmieranfänger und habe nun seit 2 Tagen einen Raspberry Pi.
    Seit demher beschäftige ich mich mit Python (Tag und Nacht :geek: ) und bin daran einen Automaten zu bauen, der meine Katze mit Trockenfutter versorgen soll. (Keine Sorge, sie bekommt zusätzlich Nassfutter, welches ich ihr persönlich füttere.)

    Ein Programm dafür habe ich auch schon geschrieben. Es gibt zwar fertige im internet, diese erschienen mir aber alle zu mächtig. Und wer will denn schon mit Kanonen auf Spatzen schießen?!
    Da ich aber bis auf ein kleines Blenderprojekt (Blender.org) bisher absolut null Erfahrungen mit Python hatte, wollte ich von euch Python erfahrenen Mitgliedern wissen, ob mein Programm bisher irgendwelche Logik/ Denkfehler beinhaltet, welche auf Dauer zum Abbruch des Programms führen würden.

    Kurzer Text zur Hardware:

    Ich habe einen Raspberry Pi, an dessen IO Ports ich: 1 LED, 1 Servo und einen Taster angelötet habe. (auf externer Platine.)
    Beim Servo habe ich den Pott entfernt und den Positionierungsstift, damit dieser sich unendlich in eine Richtung drehen kann.
    Der Taster ist direkt und ohne Widerstand zwischen einem GPIO und dem 3,3 Volt Anschluss einleitet.
    Die Led (Weist, ca. 3 Volt) ist ebenfalls ohne Widerstand zwischen einem GPIO und einem GND Anschluss angelötet.
    Der Servo ist mit + an 5V und mit - an GND sowie mit der weißen DATA Line(?) an einen GPIO Port gelötet, und ist mit einem Futterauswurf form- und kraftschlüssig verbunden.)

    Das Programm soll folgendes können:

    Sobald der Pi angeschlossen wird soll die weiße LED einmalig für 15 Sekunden leuchten, damit man ohne Betätigen des Knopfes sehen kann, ob das Programm nach dem Booten automatisch gestartet ist.
    (Der Autostart läuft bisher prima.)
    Danach soll sich der Servo um jeweils 180° nach links drehen, sobald:
    Entweder der Knopf gedrückt wird, oder eine Zeitbedingung (05:30 Uhr und 16:15 Uhr) erfüllt ist.

    Bisher lief das Programm bei allen Tests erfolgreich, und es gab keine Probleme.
    Allerdings befürchte ich, dass mein Programm mangels Programmier-Kenntnis eventuell Fehler beinhaltet, die es zu einem späteren Zeitpunkt (Tests liefen immer nur 15 Minuten) zum Absturz bringen könnten.

    Es wäre nett, wenn einer von euch mal 'drüberschauen' könnte, und mir sagen könnte, wo eventuell Optimierungsbedarf besteht.
    Ich habe versucht, das Programm so übersichtlich wie möglich zu gestalten. falls es dennoch Unklarheiten gibt, beantworte ich gerne eure Fragen.
    Gerne dürft ihr das Programm auch weiterverändert bzw. verwenden.

    Anregungen für mein Projekt habe ich von 'Patrick Hener' erhalten, welcher sein Projekt gut dokumentiert hat. (Bei der Suchmaschine einfach "Katzenfütterautomat wenn die Katze zwei mal kratzt" eingeben. Ich weiß nämlich nicht ob Direktverlinkungen hier erlaubt sind.)
    Dieser hat ein ähnliches Projekt umgesetzt, allerdings finde ich deCssen Programm etwas zu ausführlich.

    Dankeschön, schonmal im Voraus für eure Beiträge :danke_ATDE:

    Einmal editiert, zuletzt von cyclopath (7. Januar 2017 um 11:26)

  • Wie kann ich mein Programm optimieren? Futterautomat? Schau mal ob du hier fündig wirst!

  • Hallo Marc,

    herzlich Willkommen in unserem Forum!

    Mal abgesehen von der Software. Wie sieht es mit der Spannungsversorgung aus? Ich frage deshalb, weil Du nicht davon ausgehen kannst, dass die Spannungsversorgung immer steht. Der Raspberry Pi kann also auch mal ausgeschaltet sein. Hier halte ich eine USV für sinnvoll. die das Teil kontrolliert herunterfährt.

    Etwas anderes wie z.B. ein Arduino oder Kompatibles läuft immer, wenn die Betriebsspannung anliegt. Dieses Teil kommunizert beim Hochfahren mit dem Raspberry Pi. Kommt von dem keine Antwort, dann ist der RPi offensichtlich ausgeschaltet. Dann bedarf es nur eines Impulses (z.B. Kurzschließen der RUN-Pins), um diesen wieder zu starten.

    Durch diese Maßnahmen steigerst Du die Ausfallsicherheit Deines Systems.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas!

    Momentan versorge ich das Raspberry Pi mit einem 5V, 2A Apple iPad Netzteil (10 W) über den USB Anschluss. Mit der Stromversorgung habe ich mir auch schon Gedanken gemacht. Scheint dem Raspberry Pi nicht sonderlich gut zu gefallen, 'hart' heruntergefahren zu werden. ich habe mir mal eine USV mit dem Namen PiUSV+ angesehen. Die ist direkt für den Raspberry Pi konzipiert und hat Akkus an Board, welche den Pi im Notfall noch ein kontrolliertes Herunterfahren gestatten. Kennst du dich damit eventuell aus, und kannst mir sagen on oben genannte USV etwas taugt?

    Grüße, Marc

  • Ich werde mich mal ein wenig mit der Transistormaterie auseinandersetzen.

    Wenn das dem Pi zu längerer Lebzeit verhilft, ist es das sicher wert.

    Kurzfristig, muss es aber auch so gehen.

  • Du belegst am Anfang eine Variable LED mit 0, fragst direkt danach ab, ob diese == 0 ist (natürlich ist sie das, hast Du doch gerade so gesetzt), erhöhst dann innerhalb des then-Zweigs deren Wert um 1 um sie anschließend nie mehr zu verwenden. Das schadet zwar nix, ist aber sicher nicht sinnvoll. Mein Vorschlag: Alle Zeilen, in denen die Variable vorkommt rauslöschen und Einrückung des Blinkens anpassen.

    Für die Zeiten würde ich mir am Anfang des Programms eine Liste anlegen, das ist für die Zukunft flexibler. Etwa so:

    Code
    zeiten = [ '05:30','16:15']
    ...
    if time.strftime("%H:%M") in zeiten:
        ...

    In die Hauptschleife würde ich auf jeden Fall irgendwo eine kurze sleep-Anweisung einbauen, sonst lastest Du die CPU schnell voll aus.

    Ein paar Deiner sleeps sind mir nicht ganz klar, da müsstest Du mal erläutern, was Du damit bezweckt hast.

  • Ich würde von der ganzen Konstruktion gerne mal ein Foto sehen. Lässt sich das einrichten? Das ist nämlich eine super Idee, was Du da gemacht hast @ cyclopath

  • Zuerstmal: tolles projekt, steht auch hier immer mal wieder zur Debatte. Mich wuerde deine Hardware interessieren.

    Nun aber zum Code - wenn ich nen Euro haette fuer jedes mal, wenn so mit Zeitberechnung rumgeroedelt wird, obwohl es doch das so einfache datetime-Modul gibt...

    Code
    >>> import datetime as dt
    >>> START = dt.time(12, 30)
    >>> END = dt.time(14, 50)
    >>> print(START < dt.datetime.now().time() < END)
    True

    Nix mit rumformatieren und umwandeln und was weis ich nicht.

    Konzeptionell finde ich dein Vorgehen mit dem Servo schwierig. Du redest von +/-180 Grad, aber genau dieses Feedback hast du ja gar nicht mehr. Stattdessen basiert das alles auf timeouts. Das wird dir um die Ohren fliegen, so etwas macht man (wenn es das Servo so nicht sein darf in seiner unmodifizierten Variante) mit Endabschaltern. Sonst wird dein Servo irgendwann etwas Leistung verlieren, die Futterklappe steht offen, und der Kater verfettet ;)


  • Du belegst am Anfang eine Variable LED mit 0, fragst direkt danach ab, ob diese == 0 ist (natürlich ist sie das, hast Du doch gerade so gesetzt), erhöhst dann innerhalb des then-Zweigs deren Wert um 1 um sie anschließend nie mehr zu verwenden. Das schadet zwar nix, ist aber sicher nicht sinnvoll. Mein Vorschlag: Alle Zeilen, in denen die Variable vorkommt rauslöschen und Einrückung des Blinkens anpassen.

    Das erschien mir als einzig Sinnvolle (mir bisher Bekannte) Artvzu sein, sicher zu stellen, dass die LED nur einmalig mit Start des Programms für 15 Sekunden an ist und danach während die eig. Schleife abläuft, nicht mehr leuchtet. Da ich mittel dieser LED nur einmalig nach Einstecken des automaten prüfen will, ob das Programm
    automatisch gestartet wurde. Danach soll die LED aus bleiben, für immer. (Bis zum nächsten Boot) deshalb die Frage, wie würdest du das machen, gibt es da eine einfachere Methode? Wird das blinken der LED nicht weiter stattfinden, wenn ich die Variable LED lösche und sie einfach vir die Hauptschleife setze?
    Ich werde das mal ausprobieren.

    Das mit der Definition von Zeiten ist eine prima Idee, mit der es tatsächlich viel flexibler wird, und an die ich noch gar nicht gedacht habe bisher.
    :danke_ATDE:

    Bzg. der Sleeps in der Hauptschleife. Wie meinst du das? An welche Stelle sollte ich diese bauen? Am Ende der Schleife?

    Und zu den vielen Sleeps:

    Der sleep(1) in der Knopfcheck Verzweigung soll verhindern, dass der Knopf als 2 mal gedrückt gilt, falls man diesen etwas länger gedrückt hält.
    Der sleep(.6) soll dann den Servo 0,6 sec laufen lassen bis es zum stop kommt.
    Die time.sleep(1) in den Zeit Check Verzweigungen sind natürlich quatsch, und meiner Faulheit geschuldet, dass ich die Zeilen einfach nochmals aus der Knopfverzweigung kopiert habe. Werdenich umgehend beseitigen.
    Die time.sleep(70) sollen verhindern, dass der Servo mehrmals dreht, da der Zustand ("%M") == "00" (z.B.) ja 60 Sekunden lang true ist. mit dem sleep von 70 Sekunden soll der Servo nur einmal gedreht werden. Nach 70 sec ist ja dann ("%M") == 00 false, da ja schon XX:01 Uhr ist.
    Automatisch zusammengefügt:


    Ich würde von der ganzen Konstruktion gerne mal ein Foto sehen. Lässt sich das einrichten? Das ist nämlich eine super Idee, was Du da gemacht hast @ cyclopath

    Hallo, danke für die netten Worte. Ich warte momentan noch auf ein letztes Bauteil, wenn alles zusammengesetzt wurde, werde ich ein paar Fotos hochladen. (Denke bis Montag müsste alles fertig sein.
    Automatisch zusammengefügt:


    Zuerstmal: tolles projekt, steht auch hier immer mal wieder zur Debatte. Mich wuerde deine Hardware interessieren.

    Nun aber zum Code - wenn ich nen Euro haette fuer jedes mal, wenn so mit Zeitberechnung rumgeroedelt wird, obwohl es doch das so einfache datetime-Modul gibt...

    Code
    >>> import datetime as dt
    >>> START = dt.time(12, 30)
    >>> END = dt.time(14, 50)
    >>> print(START < dt.datetime.now().time() < END)
    True

    Nix mit rumformatieren und umwandeln und was weis ich nicht.

    Konzeptionell finde ich dein Vorgehen mit dem Servo schwierig. Du redest von +/-180 Grad, aber genau dieses Feedback hast du ja gar nicht mehr. Stattdessen basiert das alles auf timeouts. Das wird dir um die Ohren fliegen, so etwas macht man (wenn es das Servo so nicht sein darf in seiner unmodifizierten Variante) mit Endabschaltern. Sonst wird dein Servo irgendwann etwas Leistung verlieren, die Futterklappe steht offen, und der Kater verfettet ;)

    Also zur Hardware:

    ich habe ein Müslispender für Hotels gekauf, und an dessen Griff von der Rückseite aus den Servo befestigt. (Dieser soll sich bewusst immer nur nach links drehen für ca. 180° +- 10°. Von daher braucht der Servo nicht unbedingt ein Feedback. Der Kater wird im Notfall auch nicht verfetten, da die "Drehmühle" des Spenders ja immer solange sperrt, bis gedreht wird ;;)

    Das Datetime Modul werdenich mir mal genauer ansehen, kannte ich bisher noch niht. Danke für den Tipp! :danke_ATDE:

    Einmal editiert, zuletzt von cyclopath (7. Januar 2017 um 14:50)


  • Das erschien mir als einzig Sinnvolle (mir bisher Bekannte) Artvzu sein, sicher zu stellen, dass die LED nur einmalig mit Start des Programms für 15 Sekunden an ist und danach während die eig. Schleife abläuft, nicht mehr leuchtet. Da ich mittel dieser LED nur einmalig nach Einstecken des automaten prüfen will, ob das Programm
    automatisch gestartet wurde. Danach soll die LED aus bleiben, für immer. (Bis zum nächsten Boot) deshalb die Frage, wie würdest du das machen, gibt es da eine einfachere Methode? Wird das blinken der LED nicht weiter stattfinden, wenn ich die Variable LED lösche und sie einfach vir die Hauptschleife setze?
    Ich werde das mal ausprobieren.

    Der Code vor der Hauptschleife wird genau einmal am Anfang des Programms durchlaufen. Danach schleift die Hauptschleife immer im Kreis, sozusagen - an den Anfang kommst Du nie mehr zurück. Meinen Vorschlag habe ich ja schon im letzten Post geschrieben.


    Bzg. der Sleeps in der Hauptschleife. Wie meinst du das? An welche Stelle sollte ich diese bauen? Am Ende der Schleife?

    Ja. Einfach vor das except noch ein sleep(.1) oder so.


    Und zu den vielen Sleeps:

    Der sleep(1) in der Knopfcheck Verzweigung soll verhindern, dass der Knopf als 2 mal gedrückt gilt, falls man diesen etwas länger gedrückt hält.
    Der sleep(.6) soll dann den Servo 0,6 sec laufen lassen bis es zum stop kommt.
    Die time.sleep(1) in den Zeit Check Verzweigungen sind natürlich quatsch, und meiner Faulheit geschuldet, dass ich die Zeilen einfach nochmals aus der Knopfverzweigung kopiert habe. Werdenich umgehend beseitigen.
    Die time.sleep(70) sollen verhindern, dass der Servo mehrmals dreht, da der Zustand ("%M") == "00" (z.B.) ja 60 Sekunden lang true ist. mit dem sleep von 70 Sekunden soll der Servo nur einmal gedreht werden. Nach 70 sec ist ja dann ("%M") == 00 false, da ja schon XX:01 Uhr ist.

    Okay, dann habe ich die alle verstanden. Kann man m.E. so machen. Allerdings läuft, wenn ich das richtig sehe, Dein Servo zu den vorgegebenen Zeiten 70.6 Sekunden - ist das beabsichtigt oder hast Du da ein Stop vergessen?

  • Der Code vor der Hauptschleife wird genau einmal am Anfang des Programms durchlaufen. Danach schleift die Hauptschleife immer im Kreis, sozusagen - an den Anfang kommst Du nie mehr zurück. Meinen Vorschlag habe ich ja schon im letzten Post geschrieben.

    [...]

    Okay, dann habe ich die alle verstanden. Kann man m.E. so machen. Allerdings läuft, wenn ich das richtig sehe, Dein Servo zu den vorgegebenen Zeiten 70.6 Sekunden - ist das beabsichtigt oder hast Du da ein Stop vergessen?

    Okay, danke. Dann ist die Variable tatsächlich sinnlos.

    Aus irgendeinem Grund habe ich hier in dieser Version den Befehl Servo.stop() nach dem time.sleep(.6) nicht enthalten. Der ist natürlich drin, damit sich der Servo eben nur 0.6 sec dreht. Aber danke nochmals für den Hinweis! :danke_ATDE:

  • Servus cyclopath,


    das halte ich für bedenklich. Sowohl der Taster als auch die LED stellen so im ungüstigsten Fall einen Kurzschluss dar. Zudem wird die LED vermutlich alles an Strom aus dem GPIO ziehen, was sie bekommen kann ... imho keine besonders clevere Idee ... im günstigsten Fall wird sie Dir relativ schnell durchbrennen.
    Servos direkt über den 5V Pin des Pi zu versorgen sehe ich ebenfalls eher als kritisch an. Wenn es ganr nicht anders geht, dann geh' mit der 5V Ader direkt vom Netzteil ab. So läuft der gesamte Strom zuerst durch den micro-USB über die Leiterplatte des PI ...
    Da Servos, je nach Typ, sehr hohe Ströme ziehen, kann Dir das mal böse auf die Füsse fallen.


    ...
    Danach soll sich der Servo um jeweils 180° nach links drehen, sobald:
    Entweder der Knopf gedrückt wird, oder eine Zeitbedingung (05:30 Uhr und 16:15 Uhr) erfüllt ist.
    ...


    wie auch _deets_ schon richtig anmerkte: Servo steuern über "Laufzeit" ist imho eine ganz blöde Idee. Die Teile haben nicht umsonst ihre Innereien ... und es gibt sie afaik auch mit 360° Drehwinkel. Je nach Typ wird Dir der Servo wenn er blockiert wird, zuviel Strom ziehen und damit im Zweifelsfall den Pi grillen oder zumindest die Polyfuse auslösen.

    Zum Code kann ich leider nix sagen, Python ist nicht meine Welt. Aber dafür haben wir hier genügend andere Spezialisten, die wissen, wovon sie reden.

    Nix für ungut, das Teil ist eine nette Idee ... aber imho mit einigem Verbesserungs-Potential.


    cheers,
    -ds-

  • Hallo,

    das Problem mit dem Netzausfall soltest Du schon bedenken. Aber währe da ein kleines Modul mit einer Echtzeituhr nicht die bessere Lösung ? Die haben auch nuch einen kleinen RAM in dem man speichern könnte, wann es das letzte mal Futter gegeben hat. UPS macht nur Sinn, wenn darüber auch der Automat betrieber werden kann, das es auch bei Stromausfall was tz fressen gibt, wenn man außer Haus ist. Wenn der Pi mit WLAN - Verbindung zum Internet hat, dann aktualisiert sich die Urzeit automatisch undman kann die Zeit abfragen. Dann braucht man eigentlich überhaupt keine zusätzlichen Aufwand zu treiben.

  • Hallo Aro,


    Hallo,

    das Problem mit dem Netzausfall soltest Du schon bedenken. Aber währe da ein kleines Modul mit einer Echtzeituhr nicht die bessere Lösung ? Die haben auch nuch einen kleinen RAM in dem man speichern könnte, wann es das letzte mal Futter gegeben hat. UPS macht nur Sinn, wenn darüber auch der Automat betrieber werden kann, das es auch bei Stromausfall was tz fressen gibt, wenn man außer Haus ist. Wenn der Pi mit WLAN - Verbindung zum Internet hat, dann aktualisiert sich die Urzeit automatisch undman kann die Zeit abfragen. Dann braucht man eigentlich überhaupt keine zusätzlichen Aufwand zu treiben.

    Und auch dieses Problem kann man ohne WLAN lösen. Der Raspberry Pi speichert ja die Uhrzeit zum Zeitpunkt des letzten Herunterfahrens. Diese Uhrzeit wird beim nächsten Bootvorgang weitergezählt. Wenn das Teil von hh:mm bis HH:MM laufen soll, und die Uhrzeit dann HH:MM+5 erreicht, dann weiß man genau, dass es sich um einen neuen Tag handeln muss. Also mit

    Code
    sudo date -s ...

    den neuen Tag und Start-Uhrzeit hh:mm+5 setzen

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Einmal editiert, zuletzt von Andreas (7. Januar 2017 um 17:11)

  • Hallo Andras,

    das ist richtig. Aber der Pi macht da weiter, wo man ihm den Strom weg genommen hat. Wenn´s nur ein kurzer Ausfall ist, dann wird es sich kaum auswirken. Wenn aber der Strom über mehrere Stunden ausfällt, kommt alles aus dem Tritt. Da kommt das Futter zu vollkommen unangemessenen Zeiten. Das wollte ich meinem Tieger nicht antun. Der weiss ganz genau wann er antraben muss, weil es etwas zu fressen gibt.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!