Graphische Oberfläche "spinnt"

  • Hallo zusammen,

    ich möchte mit einem IC, dem MCP3208, Spannung messen. Dazu nutze dieses Python-Script. Umgerechnet werden die gemessenen Werte dann in diesem Script. Schließlich sollen sie dann auf der GUI (PyQt) landen, diese wird aus einer design.py mit einem eingefügtem Widget, dem tacho.py, landen...
    Das funktioniert aber nur teilweise... Wenn ich den Rechner einmal rechnen, und damit auch messen, lasse und die errechneten Werte dann in der GUI einsetze klappt das zumindest in den unteren Labels ganz gut. Sobald aber eine Schleife ins Spiel kommt crasht das Programm... Möchte ich die Labels in der Mitte, also auf dem TachoWidget, nutzen dauert es meist sehr lange und sprengt dann das Widget - immerhin die richtige Zahl steht dann da... Klappt aber auch nur ohne Schleife. Ziel meines Projektes ist jedoch, diese Werte regelmäßig zu aktualisieren (0,1 oder besser 0,01 Sekunden) und in die Felder einzusetzen. Auch den Tacho kann man dann mit diesen Werten neu setzen...
    Es scheint keinen Leistungsengpass zu geben, so liegt die Auslastung des Pi B+ nur so bei max. 50% in den Momenten wo eigentlich gerechnet werden sollte.. Woran liegt es also, dass das nicht so klappen will? Mir ist klar dass meine Scripts wahrscheinlich nicht optimal geschrieben sind - ich habe neu mit Python angefangen.
    Liegt es vielleicht daran, dass alle Klassen in ihrer eigenen Datei stecken, überlastet das den Speichercontroller oder sowas in der Richtung? Lieber alles in ein großes Script? Oder habe ich etwas übersehen?
    Vielleicht fällt euch ja was auf - würde mich auf Antworten freuen :)

    Liebe Grüße


  • Evtl. Speicherüberlauf. Was sagt den das Log?


    Meinst du die Konsole aus der ich das Programm starte? Weil die bleibt leer, bis dann eben steht dass das Programm beendet wurde :/
    Automatisch zusammengefügt:
    Ein Testlauf bei dem ich den Tacho jede 0,5 Sekunden um ein Zehntel weiterlaufen lasse scheint schon zu viel zu sein... Da dauert es etwas und schließlich springt der Tacho auf den letzten Wert anstatt Stück für Stück zu wandern - reizt das echt schon alles aus was der Pi so kann?!

    Einmal editiert, zuletzt von OldBread41084 (15. August 2016 um 18:31)


  • Ein Testlauf bei dem ich den Tacho jede 0,5 Sekunden um ein Zehntel weiterlaufen lasse scheint schon zu viel zu sein... Da dauert es etwas und schließlich springt der Tacho auf den letzten Wert anstatt Stück für Stück zu wandern - reizt das echt schon alles aus was der Pi so kann?!

    Kannst Du den Code für diesen Testlauf mal posten? Die komplette Skriptsammlung in Deinem Startpost durchzugehen, ist etwas mühsam, ein auf den Fehler reduziertes Beispiel wäre da echt hilfreich.

  • Kannst Du den Code für diesen Testlauf mal posten? Die komplette Skriptsammlung in Deinem Startpost durchzugehen, ist etwas mühsam, ein auf den Fehler reduziertes Beispiel wäre da echt hilfreich.

    Leider hängt der ganze Kram ja aneinander... Jedoch kann man das für den Testlauf auf die Skripte für Design (automatisch erzeugt mit QtCreator), das darin eingebettete Widget Tacho und den "Verwalter", main.py, in dem alles zusammengefügt und die GUI gesteuert werden. Zum starten der Anwendung reicht es also die main.py aufzurufen. Ich habe den Code der main.py um eine Methode erweitert die den Tacho alle 0,5 Sekunden um ein Zehntel weiterschiebt und am Ende ein Label verändert. Diese ist erreichbar indem man in der Menübar den ersten Menüpunkt anklickt... Auch mit Übertakten erreiche ich da keine Änderung... Habe das Programm auch auf meiner VirtualBox mit Ubuntu auf dem definitiv sehr leistungsstarken "Hauptrechner" laufen lassen - gleiches Problem...

    Einmal editiert, zuletzt von OldBread41084 (15. August 2016 um 19:02)


  • So lässt sich das doch schon gut untersuchen - ich muss allerdings jetzt leider weg, wie ich das Forum kenne, ist's schon gelöst, bis ich zurück bin, sonst schaue ich's mir morgen mal an.

    Danke, das wäre super!

  • Stammt der Code aus Deiner Feder oder hast du das nur von irgendwo übernommen?

    Sieht irgendwie komisch aus - zum Beispiel die mcp3208() Klasse, ab Zeile 28 ...
    die ganzen kreuz und queren Einrückungen erschweren mir zudem das verstehen des Codes :(

    In deiner Rechner Klasse sehe ich aber auch Fehler: Deine Methode setzeZeitZumStop und die nachfolgenden haben kein Zugriff auf "self" was aber innerhalb abgerufen wird. Das würde meiner Meinung nach Fehler erzeugen.
    Das gleiche Spiel ist dann auch in "Rechne(self)" da rufst du "mcp3208.readAnalogData(self.mcp3208)" auf aber das wird es nicht geben sondern nur "self.mcp3208.readAnalogData()"... So wie Du es nutzt wird es evtl. auch funktionieren, erzeugt dann aber jedes mal ein neues Objekt und das wiederum könnte dein Problem verursachen.
    Das ist halt die Besonderheit einer Class, du hast im init ein Objekt erzeugt und an eine innerhalb der Classe globalen Variable gebunden: self.mcp3208 ... Die musst du dann auch nutzen um eine Methode aus der anderen Class aufzurufen ;) "self" ist nur dann global wenn es der "funktion" auch übergeben wird...Da hast du aber allgemein Fehler. SafeConfigParser() ist davon glaub ich auch betroffen und die Aufrufe von "save()" werden so auch nicht funktionieren. "Zaehlen" ist auch falsch, müsste "self.Zaehlen" lauten.

    Also die gesamte "class Rechner(object):" solltest du noch mal überarbeiten - und ein bisschen Ordnung rein bringen wie einheitliche Einrückungen und so :fies: Zu viele Leerzeilen zwischen den "def" 's erschweren das Verstehen ebenfalls, das zieht den Code nur unnötig in die Länge.

    //EDIT: Probiers mal damit:
    mcp3208.py http://codepad.org/io7z1gdT
    Rechner.py http://codepad.org/zvYg9NhJ ... Zeile 97 hab ich mit Absicht falsch gelassen :daumendreh2:


  • Stammt der Code aus Deiner Feder oder hast du das nur von irgendwo übernommen?

    Sieht irgendwie komisch aus - zum Beispiel die mcp3208() Klasse, ab Zeile 28 ...
    die ganzen kreuz und queren Einrückungen erschweren mir zudem das verstehen des Codes :(


    Vielen Dank für deine Antwort!
    Ich muss gestehen dass ich einige Teile "zusammengeklaut" habe... So stammt der Code für den MCP3208 von Erik Bartmann, der Tacho kommt von StackOverflow und das Design kommt eben aus dem QtCreator...


    In deiner Rechner Klasse sehe ich aber auch Fehler: Deine Methode setzeZeitZumStop und die nachfolgenden haben kein Zugriff auf "self" was aber innerhalb abgerufen wird. Das würde meiner Meinung nach Fehler erzeugen.
    Das gleiche Spiel ist dann auch in "Rechne(self)" da rufst du "mcp3208.readAnalogData(self.mcp3208)" auf aber das wird es nicht geben sondern nur "self.mcp3208.readAnalogData()"... So wie Du es nutzt wird es evtl. auch funktionieren, erzeugt dann aber jedes mal ein neues Objekt und das wiederum könnte dein Problem verursachen.
    Das ist halt die Besonderheit einer Class, du hast im init ein Objekt erzeugt und an eine innerhalb der Classe globalen Variable gebunden: self.mcp3208 ... Die musst du dann auch nutzen um eine Methode aus der anderen Class aufzurufen ;) "self" ist nur dann global wenn es der "funktion" auch übergeben wird...Da hast du aber allgemein Fehler.


    Sowas habe ich befürchtet... Habe mich erstmal dran gemacht den Code so zu "friemeln" dass er ohne Fehlermeldung funktioniert - einzelne Abfragen funktionieren ja... Aber wenn jedes mal ein weiterer mcp3208 erzeugt wird ist der Speicher irgendwann voll, macht Sinn :) Da das ganze aber auch ganz ohne Rechner und MCP3208 nicht wirklich funktioniert müssen irgendwo in den anderen Scripten doch auch noch Fehler sein, oder?



    Also die gesamte "class Rechner(object):" solltest du noch mal überarbeiten - und ein bisschen Ordnung rein bringen wie einheitliche Einrückungen und so :fies: Zu viele Leerzeilen zwischen den "def" 's erschweren das Verstehen ebenfalls, das zieht den Code nur unnötig in die Länge.


    Dann werd ich dafür mal ne Nachtschicht einlegen - irgendwann holt einen dieses "nur mal schnell das es funktioniert" immer ein :blush:

    Ich werd aber vorher mal ein weiteres Layout anlegen, vielleicht ist es zu viel für PyQt wenn der Tacho in ein Layout eingebunden ist. Mal sehen ob man den isoliert betreiben kann...



    //EDIT: Probiers mal damit:
    mcp3208.py http://codepad.org/io7z1gdT
    Rechner.py http://codepad.org/zvYg9NhJ

    Cool danke! Das probier ich gleich mal aus, das geht hier ja wirklich schnell! :bravo2: :thumbs1:
    EDIT: Die beiden Scripte funktionieren Einwandfrei - vielen Dank nochmal dafür! Nur der Tacho will eben nicht so richtig...

    EDIT: Leider funktioniert der Tacho auch allein nicht besser - auch hier dauert es lange bis dann am Ende ein großer Sprung anstatt mehrerer einzelner erfolgt... Weiß jemand wie hier Abhilfe geschaffen werden kann? Mir als Anfänger ist der Code einfach viel zu komplex, habe mehrfach versucht den nachvollziehen zu können - scheitere da relativ schnell...

    Einmal editiert, zuletzt von OldBread41084 (15. August 2016 um 20:56)

  • Du hast noch etwas sehr grundlegendes fuer die Arbeit mit GUI-Rahmenwerken nicht verstanden. Diese sind IMMER ereignisbasiert. Sie brauchen eine sogenannte Ereignisschleife (mainloop), der zB in Qt mit app.exec_() betreten wird.

    Code der dann ausgefuehrt wird darf nur sehr kurze Ausfuehrungszeiten haben, und danach aktualisiert sich die GUI.

    Deine Test-Methode aber, die mittels time.sleep viele Sekunden lang laeuft, kehrt *nicht* in die Ereignisschleife zurueck - und damit wird dann auch keine Veraenderung sichtbar.

    Es gibt grundsaetzlich zwei Arten, das zu loesen:

    - wenn deine Messvorgaenge oder aehnliches nur kurz dauern, dann kannst du mittels Timern Intervalle festlegen, innerhalb derer du deine GUI updatest. In Qt heisst die dazu notwendige Klasse QTimer.
    - wenn deine Messvorgaenge laenger brauchen, musst du wohl oder uebel zur Nebenlaeufigkeit mit Threads greifen. Das ist aber wiederum kompliziert mit GUIs! Die koennen es naemlich ueberhaupt nicht ab, wenn man aus mehreren Threads heraus ihre Objekte manipuliert. Das fuehrt zu unstabilem Verhalten bis hin zu harten abstuerzen. Aber Qt hat da eine ganz gute Besonderheit: sein signal/slot-System is thread-faehig. Vorraussetzung dazu ist allerdings die Verwendung von QThread, sowie das aufsetzen einer "queued connection" zwischen signal und slot.

    Am besten konvertierst du erst mal deinen Beispielcode fuer den Tacho mit weiterzaehlen zu einer QTimer-basierten Loesung, um das besser zu verstehen.


  • Danke für die Antwort!
    Die Messvorgänge sind verdammt kurz (theoretisch 100.000 pro Sekunde möglich) und auch die Verrechnung mit dem "Rechner" sollte ja bei den recht simplen Zahlen flott von Statte gehen...
    Daher werd ich mir wohl erstmal QTimer angucken - klingt auch irgendwie etwas einfacher :D :thumbs1:

    Auf jeden Fall erstmal Danke - das klingt zuversichtlich! :danke_ATDE:

  • Habe jetzt relativ ausführlich mit dem QTimer rumprobiert... Habe mir aus verschiedensten Tutorials die Lösungsansätze zusammengesucht, allerdings ohne Erfolg. Der Tacho bewegt sich kein Stück. Hier mal einer meiner verwendeten Codes. Habe das mal etwas kommentiert, vielleicht kann mir jemand an diesem Beispiel erklären wie's richtig geht ::)
    Würde mich freuen :)

    EDIT: Hier nochmal ein weiterer Code, damit lässt sich der Tacho einzeln aufrufen - eigentlich sollte der ja jetzt hoch und runter zählen... Macht er aber nicht...

    Einmal editiert, zuletzt von OldBread41084 (15. August 2016 um 23:12)

  • Was mir auffällt - du erzeugst einen Timer, aber hältst keine Referenz auf ihn. Dadurch wird er zerstört & tut nichts mehr. Versuch mal statt "timer =..." ein "self.timer =.." und dann natürlich immer self.timer statt timer zu verwenden. Auch wichtig: der darf nicht singleshot sein. Und pack mal ein Print in den callback.


    Gesendet von iPhone mit Tapatalk


  • Was mir auffällt - du erzeugst einen Timer, aber hältst keine Referenz auf ihn. Dadurch wird er zerstört & tut nichts mehr. Versuch mal statt "timer =..." ein "self.timer =.." und dann natürlich immer self.timer statt timer zu verwenden. Auch wichtig: der darf nicht singleshot sein. Und pack mal ein Print in den callback.


    Gesendet von iPhone mit Tapatalk

    Danke für die Antwort ::) Hab mich noch vor den Rechner geklemmt und das hier gebastelt - es funktioniert :danke_ATDE: :heart: Jetzt bau ich das ganze morgen mal in die große GUI ein - hoffentlich klappt's

  • So, ich hab das ganze jetzt in meine große GUI eingearbeitet - und es funktioniert :danke_ATDE: zumindest schon mal wesentlich besser!
    Aber jetzt bildet sich nach ner kurzen Zeit bei gleicher anliegender Spannung dieses Bild:
    HRVlKEI.png

    Das scheint mit dem ganzen "if-Kram" für den Tacho in meinem Script zusammen zu hängen - aber wie genau? Ganz übersichtlich und effizient ist der Teil sicher nicht, aber ich lerne ja noch - und es funktioniert so ja immerhin halbwegs :D :lol:
    Und hat jemand ne bessere Idee die Strecke zu messen? So ganz genau ist das nämlich nicht, der Timer kommt nicht hinterher...

    Einmal editiert, zuletzt von OldBread41084 (16. August 2016 um 18:00)

  • Mittlerweile hat dein Anliegen nichts mehr mit dem ursprünglichen Thema hier zu tun, weshalb es angemessen wäre wenn du für dein anderen Problem nun einen neuen Thread erstellst - und in diesem Thread dann noch mal ordentlich erklärst welche Dateien was sind, die alle auch zur Verfügung stellst und dein Problem bzw was du überhaupt machst ordentlich beschreibst

Jetzt mitmachen!

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