HC-SR04 hängt sich immer wieder auf

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Zusammen,

    ich hab da mal ein kleines Problem mit den HC-SR04 Sensoren.
    Ich hab 5 Stück davon am Raspberry Pi B+ angeschlossen.
    ein GPIO Pin gibt den Trigger und 5 weitere sind Echo


    Wenn ich jetzt das Script starte, dann läuft es problemlos eine Weile durch, doch dann bleibt es urplötzlich an irgendeinem Sensor stehen und der Python Task hängt sich dabei auf und jagd die CPU auf 100 % hoch.

    Ich hab den Time.sleep unten in der Ablaufschleife mal variiert.
    am saubersten läuft er mit 1 sec. Da läuft er durch ohne sich aufzuhängen. (für die Anwendung jedoch viel zu langsam)
    Aber setze ich die Zeit runter auf (0.5) hängt er sich erst nach ein paar Minuten auf und bleibt bei irgendeinem Sensor stehen.
    Anfangs dachte ich es liegt am Kabel bis ich dazu übergegangen bin geschirmtes Kabel (Cat 7) zu benutzen.
    Jedoch hat dies keine Auswirkung auf das Aufhängen gehabt.
    Dann hab ich mal mir die CPU Auslastung angeschaut.

    bei (1) hat er 0,3 % CPU Auslastung läuft stabil durch
    bei (0.5) hat er 0,6 % CPU Auslastung hängt sich nach ca 5 min auf
    bei (0.02) hat er 14,6 % CPU Auslastung hängt sich sporadisch zwischen 30-60 Sekunden auf

    Verständlicherweise je schneller der Messen soll desto mehr CPU Last entsteht.
    Jedoch sollte bei 14,6 % sich das Ganze nicht unbedingt aufhängen, sondern stabil durchlaufen, geschweige denn bei 0,6 %.

    Da es aber wichtig ist das er zügig seine Messungen durchführt und sich dabei nicht aufhängen darf, bin ich jetzt mal hier auf Rat angewiesen, was kann ich machen damit es zu keinem Sensorstop mehr kommt. Und sich der Task dabei aufhängt und dann bei 85 - 100 % die CPU hoch jagd.

    Die Anwendung warum die Sensoren zügig messen sollen, ist ein Roboter der mit 5 Sensoren in einem Halbkreis von 180 Grad seine Umgebung abtasten soll, damit er nirgendwo gegen fährt.

    hier mal das Script zur Analyse ob ich da was verkehrt gemacht habe.

    Ist jetzt nur rein die Sensoren Abtastung.....

    Bitte jetzt nicht pep8 oder sowas kommen, das ist ein reines Testscript was ich kurz erstellt habe um herauszufinden warum sich die Sensoren immer wieder aufhängen.

    Ziel ist es eigentlich die Sensoren zwischen (0.02 - 0.2) Sekunden laufen zu lassen. Je schneller desto besser für die Abtastrate.
    Natürlich gehe ich auch einen Kompromiss ein, wenn es garnicht anders geht. Jedoch sollte es nicht mehr als (0.25) werden, sonst
    ist es zu langsam für die Fahrt.

    Ich hoffe die Profis unter Euch, wissen da Rat und können mir hierbei gezielt helfen um das Problem in den Griff zu bekommen.
    Denn mein Latein ist aktuell am Ende......... :helpnew::denker:


    MFG

    Zappelmann

  • Außer dass das etwas umständlich programmiert ist, scheint das Script in Ordnung zu sein. Könnte mir eigentlich nur ein zeitliches Problem vorstellen. Bau doch ein par Prüfroutinen ein um z.B. das Hängen in Whileschleifen zu vermeiden. Was sagt den Syslog ? Evtl. solltest Du Dich mal mit dem Loggingmodul von Python beschäftigen, dann kann man die Pythonfehler auch loggen.

  • Moin,

    ok ich hab jetzt ein paar ???? auf der Stirn......


    Wie kann ich mir den Syslog dazu ansehen gibt es dazu ein Befehl?
    Wie sollten deiner Meinung nach diese Prüfroutinen aussehen bzw. wo an welcher Stelle müssen die eingesetzt werden?

    Loggingmodul ?
    hmmm ok dazu werde ich mal eben Google fragen müssen, da ich mich damit noch nie beschäftigt habe.
    Oder hast du dazu ein bestimmten Link der mir das mit dem Loggingmodul erklärt.......

    MFG

    Zappelmann

  • Du hast das also irgendwo rauskopiert und 5 mal hintereinandergeschrieben? Hatte vorausgesetzt das wäre "quick and dirty" hingezaubert zum Testen. Also immer da wo was schief gehen könnte, würde ich prüfen ob die Werte stimmen können und reagieren. Z.B. bei einer while-Schleife die so lange läuft wie ein Wert steht, würde ich in der Schleife checken, ob das sein kann und evtl. die Schleife beenden. Stell dir vor, ein Sensor liefert mal eine 0 ab, dann bleibt Dein Programm immer in der Schleife. Könnte fast sein, dass das Dein Problem ist. Für das logging habe ich auf die Schnelle das gefunden: https://docs.python.org/2/howto/logging.html

    Ich würde auch die Funktion zur einmal schreiben, dadurch verringert sich schon mal der Quellcode


  • Bitte jetzt nicht pep8 oder sowas kommen, das ist ein reines Testscript was ich kurz erstellt habe um herauszufinden warum sich die Sensoren immer wieder aufhängen.

    Soll man sonst einfach deine Hieroglyphen entziffern, da du Funktionen, Variablen etc. allsamt den geleichen Namen gibts?
    Hier mal eine zwei aufgePEPte gekürzte Versionen auf pastebin, da die Codeansicht hier nach wie vor unbrauchbar ist:

    http://pastebin.com/9CnZYXjK
    http://pastebin.com/Kf77ERRp

    Wobei Version 2 Code minimiert...
    Edit:
    Wobei Version 1 Code minimiert...

  • ok, Eure Codeverkürzungsoptimierungen in allen Ehren, jedoch sehe ich nicht dass auf das eigentlich Problem eingegangen wird.
    Fakt ist der Code ob kurz oder lang läuft soweit einwandfrei. Mal davon abgesehen da ich aktuell auf Arbeit bin und Eure verkürzte Formen nicht testen kann, was ich aber heute Abend prüfen werde, sobald ich @home bin.

    Das Problem bei der Sache ist wohl eher das wenn er die Messungen durchführt also alle 5 Sensoren immer schön in Schleife, er dann irgendwann bei irgendeinem Sensor einfach stehen bleibt.
    Ich sehe die letzte Printausgabe von irgendeinem Sensor, dort wird dann aber kein Wert mehr angegeben und dann steht es. Es gibt keine Fehlermeldungen und kein Abbruchfehler, einzig und allein wird der Python Task der dadurch läuft auf 100 % CPU Auslastung hochgejagd.

    Bei den wenigen Antworten hier konnte ich aber eine Sache entnehmen, wo ich gern bereit bin das heute Abend mal durchzutesten.


    Zitat

    Stell dir vor, ein Sensor liefert mal eine 0 ab, dann bleibt Dein Programm immer in der Schleife. Könnte fast sein, dass das Dein Problem ist.

    Mir ist während der Messungen mal irgendwann aufgefallen, dass er sich schon mal weghängt wenn er ein Wert von 2 cm unterschreitet, ich hatte mehrfach mal den Wert 0,9 cm gelesen und dort brach die Messung dann auch sofort ab. Unabhängig jetzt von den letzten Messergebnissen wo er stopte ohne mir noch ein Wert des entsprechenden Sensors wieder zu geben wo er stopte.

    Gebt mir doch mal bitte ein Vorschlag, wie ich sowas abfangen kann. Dass er entweder Werte von unter 2 cm und über 400 cm einfach igniriert oder übergeht sodass er dabei nicht stehen bleibt und einfach weiter mist. Wäre das eine Lösung oder ein falscher Denkansatz ?

    mit dem Arduino konnte ich Fehlmessungen so abfangen.

    Code
    if (entfernung >= maximumRange || entfernung <= minimumRange){
        [b]Serial.println("-1");[/b]
     }
     else {
       Serial.println(entfernung);

    nur in Python fällt mir dazu atok nichts ein.


    @raspiprojekt

    deine verkürzte Version finde ich gut gelöst (ohne es getestet zu haben) wobei ich erst nach mehreren Minuten dahinter gekommen bin was und wie du es verkürzt hattest. Ich war erstmal total irritiert gewesen.
    Jedoch dein Kommentar am Ende hats dann teilweise erklärt. Wobei ich nicht ganz verstanden habe wie du den Variablen Tausch umsetzen willst. Ich würde jetzt hingehen und die 3 Zeilen unter dem while so wie ich dass schon selber gemacht hatte, wieder untereinander kopieren und dann das entsprechende GPIO_ECHO_ in jeder Zeile anpassen. Denn ich will ja nicht nur ein Sensor testen sondern alle 5 und jeder soll seine eigene Printausgabe haben damit ich sehen kann welcher Sensor was misst.

    ok Fazit..... ich bin mehr verwirrter als in der Nacht, als ich den Post hier gestartet habe. Jedoch werde ich heute Abend mal ein paar Dinge ausprobieren wollen.

    Aber vielleicht fällt hier ja noch jemand etwas ein oder hat ein ähnliches Problem gehabt wo er dann eine Lösung dazu gefunden hat.
    Es kann ja nicht sein, dass ein sauberes Script läuft und dann trotzdem einfach stehen bleibt.......... und die Sensoren einfach so aussteigen............


    MFG

    Zappelmann

  • Naja, eine Funktion setzt man eigentlich nur ein, wenn man die Logik, die in der Funktion steckt mehrfach benötigt. Dabei geht es gar nicht so sehr um schönen Code, sondern um validen Code, der vom Interpreter möglichst schnell abgearbeitet werden kann. Deinen Code hätte man auch ohne Funktion einfach 5mal hintereinander schreiben können, ohne eine Funktion zu benutzen, das wäre für den Interpreter sogar schneller.

    Du übergibst in der Klammer immer einen anderen GPIO an die Funktion. Also rufst Du aus der main() 5x die gleiche Funktion getDistance() auf und erhältst für jeden GPIO, den Du als Echo definiert hast den Wert Distanz zurück. Wenn Du nun einen Fehler abfangen willst brauchst Du das nur einmal in der Funktion machen und nicht 5x wie vorher. Whileschleifen kann man durch break beenden.

    Code
    if zeit > 0.5:
        break
        error = "Überschreitung der Maximalzeit"

    in der Schleife würde zum Beispiel die Schleife beenden, wenn Zeit größer 0,5 wäre. Die Variable zeit ist jetzt nur ein Beispiel. in der Variable error würde nun der Text stehen, den man ausgeben oder loggen könnte.

  • Hi Zappelmann,


    ...
    Ziel ist es eigentlich die Sensoren zwischen (0.02 - 0.2) Sekunden laufen zu lassen. Je schneller desto besser für die Abtastrate.
    Natürlich gehe ich auch einen Kompromiss ein, wenn es garnicht anders geht. Jedoch sollte es nicht mehr als (0.25) werden, sonst
    ist es zu langsam für die Fahrt.
    ...

    die Lösung an sich ist imho suboptimal ...
    Wenn das Ganze, nach meinem Verständnis, Hand und Fuss haben soll, dann wäre es besser, jeden US-Sensor in einem eigenen Thread zu handeln.
    Sonst kann es Dir imho passieren, dass es vom Zeitverhalten nicht reicht, auch wenn das Jörg ja jetzt schon optimiert hat.
    Sequentielles "Abklappern" von Eingängen, bei denen was passieren kann, ist in der Robotik sicher keine gute Idee ;)
    In Python kann ich Dir da jetzt aber leider nicht weiterhelfen ...


    Nur mal so als Denkanstoss,
    -ds-

  • @ds : da hast du absolut recht.

    Auch mit Python geht das ohne Probleme, aber soweit ist der TE glaub ich noch nicht. Schritt für Schritt ist glaube ich besser, als jemanden zu überfordern. Tatsächlich ist es wirklich so, dass für die Aufgabe ein MC besser geeignet wäre. Ich habe nur nicht soviel Zeit um alles auf einmal zu erklären. Aber die Pythonlibrarys für die GPIOs unterstützen auch das Eventhandling, das wäre dann eine weitere Herangehensweise.


  • Wenn das Ganze, nach meinem Verständnis, Hand und Fuss haben soll, dann wäre es besser, jeden US-Sensor in einem eigenen Thread zu handeln.

    Dies wird aber so in Python nicht gehen, da jeder einzeln abgearbeitet wird (GIL) d.h. wenn der erste Thread fertig ist, dann kommt der zweite usw...
    Beim RPi 2 kann man pro Kern also vier gleichzeitig laufen lassen.


  • ...
    Dies wird aber so in Python nicht gehen, da jeder einzeln abgearbeitet wird (GIL) ...
    ...

    Die laufen aber doch sicherlich "quasi" parallel, oder :s
    Das würd' mich schon wundern, wenn es nicht was vergleichbares wie pthreads in Python gäbe.
    Sicher ist das nicht "real" parallel ... aber darum geht's ja gar nicht. Immer noch besser als sequentiell einen nach dem anderen abzufragen.

    //EDIT:
    Wäre evtl. ein guter Einstieg, da das von der Logik nicht besonders aufwändig ist.
    Es geht ja nur drum zu sagen: hoppla, da ist was ... notfalls reicht ein Flag.
    Meine Meinung ist halt, wenn schon was lernen, dann richtig und nicht über den Umweg von "workarounds" die mehr schlecht als recht funktionieren ;)
    Das gewöhnt man sich nach meiner Erfahrung nur schlecht wieder ab.


    cu,
    -ds-


  • Dies wird aber so in Python nicht gehen, da jeder einzeln abgearbeitet wird (GIL) d.h. wenn der erste Thread fertig ist, dann kommt der zweite usw...
    Beim RPi 2 kann man pro Kern also vier gleichzeitig laufen lassen.


    Da bringst Du jetzt was durcheinander. Das was ds meint ist das Threading, welches vom BS unterstützt wird. Da können durchaus mehrere Pythoninstanzen nebeneinander laufen. GIL bezieht sich auf den Interpreter, sofern nur eine Instanz gestartet ist. Problematisch ist die Latenzzeit von Linux, da sind zeitkritische Anwendungen immer schlecht aufgehoben. Da würde dann ein "Echtzeitkernelpatch" helfen. Aber wir sollten hier beim Thema bleiben und den TE nicht ganz verwirren!

  • Warum bin ich ein TE bzw. was ist ein TE ???? :s

    Eure Denkansätze sind in der Tat interessant. Jedoch für mich als Anfänger nur schwer nachzuvollziehen.
    Richtig ist ja die Sensoren sollen der Reihe nach abgefragt werden. Deswegen ja auch die hohe Intervalgeschwindigkeit beim Abfragen.
    Und ja Python Files können durchaus paralell laufen. Ich habe in der /etc/rc.local mehrere Python Files eingetragen die nach dem Hochfahren gestartet werden und auch sauber nebeneinander laufen.
    Natürlich werden dort nicht immer die selben GPIO´s angesprochen sondern immer unterschiedliche. Da die Python Files auch für unterschiedliche Aufgaben laufen.
    Jedoch ist es schon notwendig; zumindest nach meinem Verständniss das die Sensoren alle in der selben Datei aufgerufen werden. Da ja auch andere GPIO´s davon in Abhängikeit der Messergebnisse geschaltet werden. (Sollte ich hierbei falsch liegen dann würde ich mich natürlich über Multithread Beispiel freuen wo es nachvollziehbar wird.)
    Aber vielleicht verstehe ich auch diese Thread Geschichte auch völlig falsch, aber soll es bedeuten jeden Sensor in einem eigenen Python Script abzufragen und dann die gespeicherten Messwerte jeweils über das Hauptprogramm ( also weiteres Python File) abgefragt werden? Wenn ja dann Benötige ich dazu ein Beispiel wie sowas funzt. Denn bisher habe ich noch keine Pythonfiles in Abhängikeit zueinander erstellt.
    Das einzige was ich bis dato umgesetzt habe, war ein Subprocess.Popen. Also aus einem laufenden Python Programm ein weiteres Python Programm gestartet und dann auch wieder beendet. Jedoch glaube ich nicht das es jetzt hier hin gehört, obwohl es auch zum Roboter Projekt natürlich gehört.

    Nur als weiteren Hinweis noch, ich war natürlich auch schon so schlau gewesen und habe nicht nur alle 5 gleichzeitig abgefragt sondern, hab auch mal nur ein Sensor im Script eingebaut und laufen lassen.
    Und die Problematik war jedoch genau die selbe wie weiter oben schon beschrieben. Also ist es aktuell erstmal egal ob einer und 5 abgefragt werden.

    Da es ja schon bei einem Sensor zu diesen unerwarteten Stop kommt, frage ich mich warum dies so ist?


    so ich hab jetzt Feierabend und mach mich auf dem Weg nach Hause um dort dann weitere Versuche durchzuführen. Ich werde gleich mal ein Grundschema auf einem großen Breadboard aufbauen und mit einer frischen Wheezy Installation das Sensor Script laufen lassen. Vielleicht ist ja auch irgendwas anderes dafür verantwortlich, warum es nicht so läuft wie es eigentlich sollte.


    MFG

    Zappelmann


  • Keine Sorge, TE ist kein Schimpfwort sondern der Theaderöffner! Zudem bringst Du nun auch einiges durcheinander. Subprozess geht schon in die richtige Richtung. Allerdings braucht so ein Sensor auch Zeit zum reagieren und Deine Zeiten sind einfach zu kurz angesetzt.

    OK also soweit ich das Datenblatt verstanden habe und auch viele andere Anleitungen soll so ein Sensor alle 20 millisekunden also 0,02 eine Messung durchführen können. Das heist im Umkehrschluss sind da 50 Messungen in der Sekunde. Technisch ist dass das Optimum.

    Das es hierbei natürlich zu Fehlern kommen kann ist mir durchaus verständlich. Daher gehe ich lieber ein Kompromiss ein und sage alle 250 Millisekunden sollten reichen. das wären dann zwar nur noch 4 Messungen in der Sekunde , jedoch immer noch besser als 1 Messung jede Sekunde. Denn das wäre definitiv zu lang (halbe Ewigkeit). Immerhin bewegt er sich ja in der Sekunde auch ein paar Cm wenn er fährt. und bei 0.25 Sekunden würde die CPU Auslastung auch nur bei maximal 2 % liegen. aktuell bei 1,2 % Wenn ich jedoch diesen Wert nutze und dann alle 5 Sensoren nacheinander messen lasse, da die ja hintereinander Messen und nicht alle gleichzeitig, sind das dann tatsächlich nur noch 1 Messung in der Sekunde. sogar noch weniger. Bei 5 Sensoren bin ich ja schon bei 1,25 Sekunden
    Und ehrlich gesagt wäre das doch schon wieder recht wenig oder nicht ?
    Aber wie ich vorher schon angedeutet hatte läuft das Script nur bei einer Messung in der Sekunde stabil. Was bedeuten würde wenn ich die Reihenfolge einhalte die ich eigentlich im Hauptprogramm programmiert habe,

    Der Ablauf wäre dann so:

    start mitte
    links
    links voll
    links
    mitte
    rechts
    rechts voll
    rechts
    mitte

    Also von der Mitte aus gestartet einen Rundlauf bis er wieder in der Mitte von beiden Seiten durch ist, sind 9 Messungen.
    bei 1 Sek pro Sensor sind das 9 Sekunden, also eine Ewigkeit bis ein Rundlauf komplett ist.
    Deswegen muss das halt zügig gehen. Wenn ich also die technisch mögliche Zeit von 0.02 Sekunden in Anspruch nehme dann sind das in der Sekunde schon mindestens 5 Messungen pro Sensor, in dieser Reihenfolge.
    Nun kommt sich mir die Frage auf, wenn die Sensoren dazu ausgelegt sind in dieser Zeit eine Messung durchzuführen. Sind diese dann zu schnell für die Berechnung am Raspberry selber ? Wenn ich sehe das der Raspberry bei 0.02 nur 14,6 % CPU Auslastung benötigt um das zu berechnen kann ich mir das nicht vorstellen das er dafür zu langsam sein soll.

    So ich bau mal eben eine Versuchsreihe zusammen, um das mit einer sauberen Version durchzutesten, mal sehen was dabei rauskommt.


    MFG

    Zappelmann
    Automatisch zusammengefügt:
    Achja ich muss gerade eine Korrektur vornehmen. Es ist kein B+ sondern eine alte Version Rev 2 B
    gibt mittlerweile so viele Versionen von den Raspis. Die auseinander zu halten ist nicht immer einfach .... :s

    Einmal editiert, zuletzt von Zappelmann (14. Juli 2015 um 20:36)

  • Mir ist da gerade ein weiterer Gedanke aufgekommen.

    Ich hab in so vielen Anleitungen gelesen das man 2 Wiederstände zwischen Echo und GND legen soll.
    Dabei variieren die Wiederstände zwischen 300 ohm bis 10k ohm

    Was ist denn davon nun eigentlich richtig durch die vielen verschiedenen Anleitungen bin ich dort etwas verwirrt.
    Ich habe zuletzt mit 2x 10 K Ohm wiederständen in Reihe gearbeitet.

    Ach ja mein anderer Raspi mag mit den Sensoren irgendwie heute nicht arbeiten, hab den gleichen Aufbau dort auch aufgezogen wie am Roboter aber der meint er müsste wenn überhaupt mal, nur ein einzigen Messwert wenn er Lust hat, beim start des Scriptes rausgeben und dann will er scheinbar schon in Urlaub gehen.... was weis ich ....... hab das Experiment dort abgebrochen und bin wieder am Roboter dran.


    MFG

    Zappelmann

Jetzt mitmachen!

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