Programm stoppt nach einigen Programmdurchläufen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo zusammen.

Ich bin noch ein ziemlicher Neuling in Sachen Python 3.5 und Raspberry Pi. Mein erstes wirkliches Projekt ist eine ultraschall Abstandmessung für mein Auto. Im Testbetrieb funktioniert das einwandfrei. Jedoch nach einiger Zeit bleibt die Messung aus und ich muss alles durch einen Reset (Netzstecker ziehen) wieder starten. Das script läuft mittels .bashrc soweit ganz ok. Es läuft nach dem Starten des PI (Raspberry Pi zero) und macht was es soll. Leider wie gesagt stoppt es nach einiger Zeit und ich weiß nicht warum. Den Pi habe ich schon ersetzt (Raspberry Pi 3+) also es scheint nicht am Pi selbst zu liegen. Im Anhang findet ihr das script. Ich denke es muss am script liegen. Könntet ihr mir bitte weiterhelfen. Im Forum selbst habe ich auf ein solches Problem keinen Hinweis gefunden. Natürlich ist meine Programmiererfahrung praktisch noch nicht vorhanden darum bitte ich um etwas Nachsicht.

Vielen Dank für alle Tipps
leafboy

Code: Alles auswählen

#!/user/bin/python3
#Datei ultraschall.py

import time
import RPi.GPIO as GPIO

# Pin Nummern vom Board
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

# Referenz zu Pin Nummer
trig = 13 #GPIO-pin-nummer
echo = 15
ok = 10
achtung = 8
stop = 7

# Definition von Referenz
GPIO.setup(echo, GPIO.IN)
GPIO.setup(trig, GPIO.OUT)
GPIO.setup(ok, GPIO.OUT)
GPIO.setup(achtung, GPIO.OUT)
GPIO.setup(stop, GPIO.OUT)

while True:
        GPIO.output(trig, True)
        time.sleep(0.00001) # 10 millisekunden
        GPIO.output(trig, False)
        while GPIO.input(echo) == 0:
                pass
        start = time.time()
        while GPIO.input(echo) == 1:
                pass
        ende = time.time()
        entfernung = ((ende - start) * 34300) / 2
        print("Entfernung: %.f" % entfernung)
        time.sleep(1)
# Stop LED ein
        if entfernung <= 18:
                GPIO.output(ok,False)
                GPIO.output(achtung,False)
                GPIO.output(stop,True)
# Achtung LED ein 
        if entfernung >=19 or entfernung >=40:
                GPIO.output(stop,False)
                GPIO.output(achtung,True)
                GPIO.output(ok,True)
# OK LED ein
        if entfernung >= 30:
                GPIO.output(ok,True)
                GPIO.output(achtung,False)
                GPIO.output(stop,False)
# Alle LED aus
        if entfernung >= 100:
                GPIO.output(ok,False)
                GPIO.output(achtung,False)
                GPIO.output(stop,False)     
       
GPIO.cleanup()
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

RPI.GPIO wegwerfen, und pigpio verwenden. RPI.GPIO ist Mist weil es eben genau zu solchen Problemen kommen kann.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: das ist wohl Deine reflexartige Antwort auf alles.

@leafboy: Warnings sind dazu da, dass man sie beseitigt und nicht, dass man sie einfach ignoriert. Eingerückt wird immer mit 4 Leerzeichen pro Ebene (keine Tabs).
Statt der Busy-Loops solltet Du Edge-Detect benutzen, dann verbrätst Du nicht unnötig Strom. Wenn irgendwas schief geht, kann es sein, dass Du ewig wartest, daher einen Timeout verwenden.

Die Bedingungen für Deine LEDs sind seltsam. Wenn etwas größer als 40 ist, ist es auch immer größer als 19. Für große Entfernungen schaltest Du die LEDs immer 3 mal. Du solltest mit elif arbeiten und dafür sorgen, dass genau ein Block ausgeführt wird.

Das cleanup wird nie erreicht, weil Du eine Endlos-Schleife hast.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

@Sirius3: ich habe diese Erfahrungen gemacht. Und das ist eine Lösung. Hat hier die Tage ein anderer User auch noch mal bestätigt.

Dein nicht weniger reflexartiges genöle über tabs vs spaces ist hingegen rein kosmetischer Natur. Und löst keine semantischen Probleme. Aber ist ja auch wichtig :roll:
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo alle.

Vielen Dank für die Meldungen von euch. Das Modul mit pigpio werde ich gleich korrigieren. Leider ist das noch in einigen, auch neueren Büchern so angegeben. Das zu korrigieren wird aber sicher eine leichtere Arbeit.

Was den Aufbau und Verwendung der Befehle anbelangt bin ich mir nicht sicher, wie ich das script sonst aufbauen soll. Wie gesagt fehlt mir jegliche Programmiererfahrung und da das script so eigentlich auch funktioniert hat war ich der Meinung das passt so. Fehlerhandling ist mir auch neu. Vorallem wie ich Fehler abfangen soll um nicht in einer Endlosschleife hängen zu bleiben. Könntet ihr mir hier ein paar Tipps bezüglich meines scriptes geben.

Nochmals vielen Dank für eure Unterstützung und eure Nachsicht mit einem Anfänger.
leafboy
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo _deets_.

Leider stellt sich die pigpio auch etwas speerig an. Die Installation hat funktioniert. Der Daemon ist auch gestartet. Leider bekomme ich immer einen 41-Error. no permission to update gpio

Hast du eine Idee dazu?

Das Problem wird zwar im Internet diskutiert aber Lösung habe ich leider keine gefunden.

Vielen Dank im Voraus für deine Hilfe.
leafboy
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo _deets_.

Habe den Fehler schon gefunden. Man muss nur die richtige Pinnummer (GPIO ist ok) verwenden und schon gehts.
Sorry.

lg leafboy
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na dann bin ich ja mal gespannt, ob die Umarbeitung die Loesung bringt.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@leafboy: das ist eben der Fehler, dass wenn etwas scheinbar funktioniert, jeder gleich denkt, dass alles richtig wäre. Und offensichtlich ist bei Dir nicht alles richtig. Beim Programmieren geht es darum, dass man nachprüfbar alles richtig macht.
Vor allem wenn man Hardwarenäher was schreibt, gibt es so viele Stolperstellen, dass man eigentlich nicht blind drauflosprogrammieren sollte. Leider sind 99% der Quellen, die man im Internet findet von Leuten, die einfach so ohne viel Ahnung zu haben, drauflos programmieren.

So sollte es schon mal besser sein:

Code: Alles auswählen

#!/usr/bin/python3
import time
import RPi.gpio as gpio

# Referenz zu Pin Nummer
TRIG = 13
ECHO = 15

def get_distance():
    gpio.output(TRIG, 1)
    time.sleep(0.0001) # 0.1 millisekunden
    gpio.output(TRIG, 0)
    channel = gpio.wait_for_edge(ECHO, gpio.RISING, timeout=500)
    if channel is None:
        return None
    start = time.time()
    channel = gpio.wait_for_edge(ECHO, gpio.FALLING, timeout=500)
    if channel is None:
        return None
    ende = time.time()
    return ((ende - start) * 34300) / 2


# Definition von Referenz
gpio.setmode(gpio.BOARD)
gpio.setup(ECHO, gpio.IN)
gpio.setup(TRIG, gpio.OUT)
try:
    while True:
        entfernung = get_distance()
        print("Entfernung: %s" % entfernung)
        time.sleep(1)
except KeyboardInterrupt:
    pass
finally:
    gpio.cleanup()
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius3.

Dein Hilfe ist super. Vielen Dank. Leider komme ich erst am Wochenende dazu dein script in die Tat umzusetzen. Darf ich noch etwas unverschämt sein und dich um ein paar Kommentare deines scripts zu bitten. Das würde mir sehr helfen nicht nur dein script besser zu verstehen sondern auch dies für neue Projekte anzuwenden. Wie du schon treffend schreibst gibt es viele scripte die funktionieren aber im Fehlerfall weiß dann ein Laie, wie ich, nicht woran es liegt. Eigentlich möchte ich das nicht nur funktionell sondern auch richtig programmieren.
Eine Frage zu meiner LED Anzeige hätte ich noch. Diesen script Teil könnte ich dann nach dem time.sleep in Zeile 32 anhängen. Die wertet dann den Abstand meines Fahrzeuges zum Sensor aus. Wenn du aber andere Anregungen hast bitte gerne.

Nochmals vielen Dank für deine super Unterstützung.
leafboy
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@leafboy: es wäre noch interessant zu erfahren, ob meine Vermutung, dass das Hängen mit dem Timeout zusammenhängt, richtig war. Im Wesentlichen habe ich nur die Logik, die Entfernung zu messen in eine Funktion ausgelagert. Das ist eigentlich immer gut, in sich abgeschlossene Funktionalität in Funktionen zu packen. Das `wait_for_edge` wartet, bis sich das Signal von 0 nach 1 oder umgekehrt wechselt. `channel is None` ist die Bedingung, ob ein Timeout stattgefunden hat oder nicht. Die Prüfung `entfernung is None` mußt Du dann unten beim Schalten der LEDs auch nochmal machen, damit bei "Messfehlern" nicht irgendetwas seltsames passiert.

Das Schalten der LEDs würde ich vor dem sleep einfügen. Da hatte ich ja schon geschrieben, dass man am besten eine if-elif-else-Kette schreibt, wo jeder Block genau einen Fall abdeckt: None, <=18, <=30, <=100 und sonst.
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius.

Erstmals eine gute Meldung. Dein script läuft einwandrei. Ich habe das fast den ganzen Samstag laufen lassen und kein Problem damit gehabt. Leider schleudert es mich beim Einbau meiner LED Anzeige. Es scheint ich bin noch weit entfernt vom Verständnis wie ein Fehler richtig abgefangen wird. Darf ich dich nochmals um einen Tipp bitten. Hier mein Script welches ich um die LED Anzeige ergänzt habe.

Code: Alles auswählen

#!/usr/bin/python3
import time
import RPi.GPIO as GPIO

# Pin Nummern vom Board
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
 
# Referenz zu Pin Nummer
TRIG = 13
ECHO = 15
ok = 10
achtung = 8
stop = 16
 
def get_distance():
    GPIO.output(TRIG, 1)
    time.sleep(0.0001) # 0.1 millisekunden
    GPIO.output(TRIG, 0)
    channel = GPIO.wait_for_edge(ECHO, GPIO.RISING, timeout=500)
    if channel is None:
        return None
    start = time.time()
    channel = GPIO.wait_for_edge(ECHO, GPIO.FALLING, timeout=500)
    if channel is None:
        return None
    ende = time.time()
    return ((ende - start) * 34300) / 2
 
 
# Definition von Referenz
GPIO.setmode(GPIO.BOARD)
GPIO.setup(ECHO, GPIO.IN)
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ok, GPIO.OUT)
GPIO.setup(achtung, GPIO.OUT)
GPIO.setup(stop, GPIO.OUT)

try:
    while True:
        entfernung = get_distance()
        print("Entfernung: %s" % entfernung)
		# Alle LED aus
        if entfernung <= 9:
                GPIO.output(ok,False)
                GPIO.output(achtung,False)
                GPIO.output(stop,False)
		
# Stop LED ein
        elif entfernung <= 13:
                GPIO.output(ok,False)
                GPIO.output(achtung,False)
                GPIO.output(stop,True)
					 
# Achtung LED ein				 
        elif entfernung <= 20:
                GPIO.output(ok,True)
                GPIO.output(achtung,True)
                GPIO.output(stop,False)

# Ok LED ein				 
        elif entfernung <= 30:
                GPIO.output(ok,True)
                GPIO.output(achtung,False)
                GPIO.output(stop,False)				

# Alle LED aus
        else:
                GPIO.output(ok,False)
                GPIO.output(achtung,-False)
                GPIO.output(stop,False)     
		
        time.sleep(1)
except KeyboardInterrupt:
    pass
finally:
    GPIO.cleanup()


Das script wird immer mit der Meldung:

Ausnahme "TypeError"
unorderable types: NoneType() <= int()
Datei: /home/pi/Python-versuche/Test_versuche/Ultraschall-stopled-RPiGPIO-edge3.py, Zeile: 44

beendet ohne eingentlich gelaufen zu sein. Auch wenn ich das Ergebnis auf eine Int umstelle ändert sich nichts.

Vielen Dank für deine Hilfe im Voraus und Verständnis mit einen Anfänger.

leafboy
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@leafboy: wenn get_distance immer None zurückliefert, dann stimmt was bei der Entfernungsermittlung etwas noch nicht, oder ist es nur das erste mal? Wie schon geschrieben mußt Du als erstes den Fall »entfernung is None« abfangen.

Es hat einen Sinn, warum ich »gpio« klein geschrieben habe, denn Module werden immer klein geschrieben. Nur Konstanten werden komplett groß geschrieben, wie TRIG oder ECHO, und damit auch OK, ACHTUNG und STOP. Zeilen 5-7 sollten gelöscht werden, Warnungen sind nicht ohne Grund da und sollte nicht einfach ignoriert werden. Eingerückt wird immer mit 4 Leerzeichen pro Ebene. Kommentare sollte man genaus einrücken wie die Umgebung. Was soll -False sein?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Sirius3:
Was spricht denn dagegen, get_distance() im Fehlerfall eine Exception (z.B. RuntimeError) werfen zu lassen?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: dachte, das verwirrt den OP noch mehr.

Code: Alles auswählen

#!/usr/bin/python3
import time
import RPi.GPIO as gpio

# Referenz zu Pin Nummer
TRIG = 13
ECHO = 15
OK = 10
ACHTUNG = 8
STOP = 16
 
def get_distance():
    gpio.output(TRIG, 1)
    time.sleep(0.0001) # 0.1 millisekunden
    gpio.output(TRIG, 0)
    channel = gpio.wait_for_edge(ECHO, gpio.RISING, timeout=500)
    if channel is None:
        raise RuntimeError("no signal")
    start = time.time()
    channel = gpio.wait_for_edge(ECHO, gpio.FALLING, timeout=500)
    if channel is None:
        raise RuntimeError("no signal")
    ende = time.time()
    return ((ende - start) * 34300) / 2

# Definition von Referenz
gpio.setmode(gpio.BOARD)
gpio.setup(ECHO, gpio.IN)
gpio.setup(TRIG, gpio.OUT)
gpio.setup(Ok, gpio.OUT)
gpio.setup(ACHTUNG, gpio.OUT)
gpio.setup(STOP, gpio.OUT)

try:
    while True:
        try:
            entfernung = get_distance()
        except RuntimeError:
            print("Kann Entfernung nicht bestimmen.")
        else:
            print("Entfernung: %s" % entfernung)
            if entfernung <= 9:
                # Alle LED aus
                state = 0
            elif entfernung <= 13:
                # Stop LED ein
                state = 1
            elif entfernung <= 20:
                # Achtung LED ein             
                state = 6
            elif entfernung <= 30:
                # Ok LED ein             
                state = 4
            gpio.output(OK, state & 4 != 0)
            gpio.output(ACHTUNG, state & 2 != 0)
            gpio.output(STOP, state & 1 != 0)
        time.sleep(1)
except KeyboardInterrupt:
    pass
finally:
    gpio.cleanup()
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius3.

Recht herzlichen Dank für deine Unterstützung. Es hilft mir wirklich sehr durch deine Kommentare tiefer in Python einzudringen. Obwohl ich noch sagen muss ich kratze derzeit nur an der Oberfläche. Dein script werde ich mir in den nächsten Tagen in Ruhe durchsehen und versuchen deine Gedankengänge nachzuvollziehen.

Deine Anregung zur Groß-/Kleinschreibung macht natürlich Sinn und ich werde versuchen mir das auch anzugewöhnen. Vorrallem als Anfänger, damit ich mich auch besser orientieren kann. Die Lektion mit den Warnungen habe ich nun verstanden und werde das grundsätzlich in meine scripte einbauen. Dazu muss ich aber auch noch etwas Theorie pauken und testen. Als IDE verwende ich hauptsächlich Eric da dachte ich wird das automatisch korrekt eingerückt. Werde mir aber die vier Leerzeichen angewöhnen. Würdest du eine andere IDE empfehlen? Das mit dem "-False" ist ein Tippfehler. Komischerweise hat das die IDE nicht angzeigt.

Wie schon geschrieben werde ich mir das script diese Woche noch genauer ansehen und mich nochmals melden. Vielen Dank für die Nachsicht meiner "dummen" Fragen und deine tolle Unterstützung.

leafboy
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius3.

Gestern habe ich mir dein script kurz durchstudiert. Bin aber noch nicht dazugekommen es in der Anwendung zu testen. Dabei sind mir deine "state" Anweisungen aufgefallen. Ich habe in der Python Dokumentation gesucht konnte das aber nicht finden. Wie muss ich diese verstehen und auf was beziehen sich die Nummern zB: "state & 4":

Codeauszug:

Code: Alles auswählen

 print("Entfernung: %s" % entfernung)
            if entfernung <= 9:
                # Alle LED aus
                state = 0
            elif entfernung <= 13:
                # Stop LED ein
                state = 1
            elif entfernung <= 20:
                # Achtung LED ein            
                state = 6
            elif entfernung <= 30:
                # Ok LED ein            
                state = 4
            gpio.output(OK, state & 4 != 0)
            gpio.output(ACHTUNG, state & 2 != 0)
            gpio.output(STOP, state & 1 != 0)
Könnest du mir das bitte noch etwas erklären oder eine Link angeben wo ich das nachlesen kann.

Vielen Dank
Leafboy
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@leafboy: state & 4 ist eine bitweise logische Verknüpfung, Bit 1 entspricht LED1, Bit 2 LED2, usw. state = 6 heißt also (6 = 4 + 2 oder 6 = 4 | 2) LED2 und LED3 sind angeschaltet. Das machen Leute gerne, die hardwarenah Programmieren, da dort manchmal jedes Bit zählt.

Besser wäre es wohl mit Listen oder Sets zu arbeiten:

Code: Alles auswählen

            if entfernung <= 9:
                # Alle LED aus
                state = set()
            elif entfernung <= 13:
                # Stop LED ein
                state = {STOP}
            elif entfernung <= 20:
                # Achtung LED ein            
                state = {ACHTUNG, OK}
            elif entfernung <= 30:
                # Ok LED ein            
                state = {OK}
            else:
                # Alle LED aus
                state = {}
            gpio.output(OK, OK in state)
            gpio.output(ACHTUNG, ACHTUNG in state)
            gpio.output(STOP, STOP in state)
PS: der else-Zweig hat bei mir noch gefehlt. Kommentar bei 20 stimmt mit Code nicht überein, ich habe mal Deinen Code übernommen.
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius3.

Gestern habe ich es doch noch geschafft das script auf mein Testsystem zu übertragen und zu testen. Super - es läuft wie von mir gewünscht. Nach ca. 7000 Messungen habe ich dann abgebrochen. Am Wochenende werde ich das script in meine reale Anlage übertragen. Das sollte aber kein Problem sein. Ich werde die Abstände noch etwas anpassen, da die kleinen Entfernungen für das Testen etwas handlicher sind, und die Kommentare noch ergänzen bzw. korrigieren wo notwendig. Ich möchte das Projekt auch sauber dokumentiert haben.

Nachdem alles auf der normalen Anwendung läuft werde ich mich nochmals melden. Jetzt schon vielen Dank für dein Unterstüzung.

lg
Leafboy
leafboy
User
Beiträge: 20
Registriert: Freitag 26. Januar 2018, 18:12

Hallo Sirius3.

Kurz meine versprochene Rückmeldung. Das System läuft ganz gut. Was mir aber aufgefallen ist, zum Unterschied vom Testsystem, ist, dass es öfters Fehlmessungen gibt. Der einzige Unterschied ist der Spannungsteiler für den Sensor. Im Testsystem habe ich 10K zu 10k und in der Garage habe ich 330 zu 470 Ohm. Da gibt es leider auch einige unterschiedliche Angaben dazu. Das Problem habe ich soweit gelöst, dass ich den Stop-Bereich etwas vergrößert habe und somit immer eine Messung bekomme. Trotzdem werde ich bei Gelegenheit den Spannungsteiler auf 10k umbauen und dann ja sehen, ob das etwas bring..

Nochmals vielen Dank für dein tolle Unterstützung

leafboy
Antworten