Raspberry / Python / Distanzmessung TF-Mini-Lidar

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
KHBeginner
User
Beiträge: 2
Registriert: Sonntag 17. März 2019, 14:59

Hallo zusammen,
normalerweise mache ich Programmierungen für MS Access und befasse mich jetzt neu mit Raspberry und Python.
Ein Projekt habe ich schon erfolgreich gestemmt und eine digitale Uhr für mein Haus gebaut.
Bei meinem nächsten Projekt beisse ich mir leider gerade etwas die Zähne aus und finde im Netzt leider nur sehr wenig hierzu.
Es geht um Distanzmessung mit dem TF-Mini Lidar, es gibt zwei Messstellen (also zwei Sensoren) und zusätzlich einen Erschütterungssensor.
Der Erschütterungssensor läuft absolut Problemlos und ist deshalb zu vernachlässigen.
Wenn ich mein Script starte erhalte, ich häufig die Fehlermeldung:

RESTART: /home/pi/Documents/Entwicklung Dachrinne TF-Mini/2019.03.09 Dachrinnenueberwachung.py
=========================
=========================
Unexpected error: <class 'NameError'>
Traceback (most recent call last):
File "/home/pi/Documents/Entwicklung Dachrinne TF-Mini/2019.03.09 Dachrinnenueberwachung.py", line 120, in <module>
if distance_2 <= 660:
NameError: name 'distance_2' is not defined

Ich habe bis jetzt den Fehler immer so interpretiert, dass die Variable distance_2 nicht definiert ist.
Mal tritt der Fehler mit der Variable 1 und mal mit 2 auf.
Der Code sieht wiefolgt aus:

Code: Alles auswählen

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import serial
from email.mime.text import MIMEText
import smtplib
import sys

# Definition GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO_DigitalIn2 = 26
GPIO_AlarmOut = 21

GPIO.setup(GPIO_DigitalIn2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(GPIO_AlarmOut, GPIO.OUT, initial=False)

# Test GPIO Ausgang
GPIO.output(GPIO_AlarmOut, False)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, True)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, False)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, True)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, False)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, True)
time.sleep(0.5)
GPIO.output(GPIO_AlarmOut, False)

# Definition der USB-Ports
ser1 = serial.Serial("/dev/ttyUSB0", 115200)
ser2 = serial.Serial("/dev/ttyUSB1", 115200)

# Logindaten Mailversand
sender = 'XXX@XXX.de'
smtpserver = 'smtp.YYY.de'
smtpusername = 'XXX@XXX.de'
smtppassword = 'ZZZ'
usetls = True

# Modul Mailversand
def sendmail(recipient,subject,content):
    msg = MIMEText(content)
    msg['From'] = sender
    msg['To'] = recipient
    msg['Subject'] = subject
    server = smtplib.SMTP(smtpserver)
    if usetls:
        server.starttls()
    if smtpusername and smtppassword:
        server.login(smtpusername,smtppassword)
    server.sendmail(sender,recipient,msg.as_string())
    server.quit()
# Modul Distanzsensor1
def tf_mini_1():    
    global distance_1
    if ser1.is_open == False:
        ser1.open()
    try:
        print('='*25)
        count = ser1.in_waiting
        if count > 8:
            recv = ser1.read(9)
            ser1.reset_input_buffer()
            if recv[0] == 0x59 and recv[1] == 0x59:
                distance_1 = recv[2] + recv[3] * 256
                ser1.reset_input_buffer()
#                print (distance_1)
    except KeyboardInterrupt:
        ser1.close()
# Modul Distanzsensor2
def tf_mini_2():
    global distance_2
    if ser2.is_open == False:
        ser2.open()
    try:
        print('='*25)
        count = ser2.in_waiting
        if count > 8:
            recv = ser2.read(9)
            ser2.reset_input_buffer()
            if recv[0] == 0x59 and recv[1] == 0x59:
                distance_2 = recv[2] + recv[3] * 256
                ser2.reset_input_buffer()
#                print(distance_2)
    except KeyboardInterrupt:
        ser2.close()

# Programm / Ablauf
if __name__ == '__main__':
    try:
        while True:
            tf_mini_1()
            tf_mini_2()
            GPIO.output(GPIO_AlarmOut, True)
            # If-Block für Distanzsensor Garage
            if distance_1 <= 340:
                GPIO.output(GPIO_AlarmOut, False)
                print ((time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 1 (Garage) hat ein Hindernis erkannt. Abstand ca. "+str(distance_1)+" cm"))
                file =  open("/home/pi/Documents/*Autostart*/Ueberwachung/"+time.strftime("%Y.%m.%d")+".txt","a")
                file.write(time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 1 (Garage) Abstand ca. "+str(distance_1)+" cm"+"\n"+"\n")
                file.close()
                subject_kh = "Hier ist der Überwachberry mit einem Ereignis"
                body_kh = "Hallo Klaus,"+"\n"+"Dein Überwachberry hat festgestellt dass der folgende Sensor wiefolgt angeschlagen hat"+"\n"+"Sensor 1 (Garage) Abstand ca. "+str(distance_1)+" cm"
                sendmail('XXX@XXX.de',subject_kh,body_kh)
                time.sleep(3)
                GPIO.output(GPIO_AlarmOut, True)
                if ser1 != None:
                    ser1.close()
                subject_kh = None
                body_kh = None
                distance_1 = None
            # If-Block für Distanzsensor Haus
            if distance_2 <= 660:
                GPIO.output(GPIO_AlarmOut, False)
                print ((time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 2 (Haus) hat ein Hindernis erkannt. Abstand ca. "+str(distance_2)+" cm"))
                file =  open("/home/pi/Documents/*Autostart*/Ueberwachung/"+time.strftime("%Y.%m.%d")+".txt","a")
                file.write(time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 2 (Haus) Abstand ca. "+str(distance_2)+" cm"+"\n"+"\n")
                file.close()
                subject_kh = "Hier ist der Überwachberry mit einem Ereignis"
                body_kh = "Hallo Klaus,"+"\n"+"Dein Überwachberry hat festgestellt dass der folgende Sensor wiefolgt angeschlagen hat"+"\n"+"Sensor 2 (Haus) Abstand ca. "+str(distance_2)+" cm"
                sendmail('XXX@XXX.de',subject_kh,body_kh)
                time.sleep(3)
                GPIO.output(GPIO_AlarmOut, True)
                if ser2 != None:
                    ser2.close()
                subject_kh = None
                body_kh = None
                distance_2 = None
            # If-Block für Erschütterungssensor Dachrinne
            if GPIO.input(GPIO_DigitalIn2) ==True:
                GPIO.output(GPIO_AlarmOut, False)
                print ((time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 3 (Dachrinne) hat ein Hindernis erkannt."))
                file =  open("/home/pi/Documents/*Autostart*/Ueberwachung/"+time.strftime("%Y.%m.%d")+".txt","a")
                file.write(time.strftime("%d.%m.%Y   %H:%M:%S")+"  Sensor 3 (Dachrinne)"+"\n"+"\n")
                file.close()
                subject_kh = "Hier ist der Überwachberry mit einem Ereignis"
                body_kh = "Hallo Klaus,"+"\n"+"Dein Überwachberry hat festgestellt dass der folgende Sensor wiefolgt angeschlagen hat"+"\n"+"Sensor 3 (Dachrinne)"
                sendmail('XXX@XXX.de',subject_kh,body_kh)
                time.sleep(3)
                GPIO.output(GPIO_AlarmOut, True)
                subject_kh = None
                body_kh = None
            time.sleep(0.1)

# Fehlerbehandlungsblock
    except KeyboardInterrupt:
        print("Abbruch durch User")
        if ser1 != None:
            ser1.close()
        if ser2 != None:
            ser2.close()
        GPIO.cleanup()
        subject_kh = None
        body_kh = None
        distance_1 = None
        distance_2 = None
    except IOError as e:
        errno, strerror = e.args
        print("I/O error({0}): {1}".format(errno,strerror))
        subject_kh = "!!!Überwachberry mit einem Fehler!!!"
        body_kh = "Hallo Klaus,"+"\n"+"Dein Überwachberry hat einen Fehler festgestellt"+"\n"+"I/O error({0}): {1}".str(format(errno,strerror))
        sendmail('XXX@XXX.de',subject_kh,body_kh)
        GPIO.cleanup()
        subject_kh = None
        body_kh = None
        distance_1 = None
        distance_2 = None
    except ValueError:
        print("No valid integer in line.")
        GPIO.cleanup()
        subject_kh = None
        body_kh = None
        distance_1 = None
        distance_2 = None
    except:
        print("Unexpected error:", sys.exc_info()[0])
        subject_kh = "!!!Überwachberry mit einem Fehler!!!"
        body_kh = "Hallo Klaus,"+"\n"+"Dein Überwachberry hat einen Fehler festgestellt"+"\n"+str(sys.exc_info()[0])
        sendmail('XXX@XXX.de',subject_kh,body_kh)
        GPIO.cleanup()
        subject_kh = None
        body_kh = None
        distance_1 = None
        distance_2 = None
        raise
In dem Code sind nur die Maildaten "verstümmelt".
Der TF-Mini ist über einen TTL/USB Wandler angeschlossen.
Nur die Werte bekomme ich von den Sensoren ausgelesen.
Ich hoffe, ich habe alle relevanten Information erfasst, sollte ich etwas vergessen haben, habt bitte einwenig Nachsicht, es ist mein erstes Hilfegesuch.

Gruß
Klaus
Benutzeravatar
__blackjack__
User
Beiträge: 13064
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@KHBeginner: Die Fehlermeldung interpretierst Du richtig. Die Existenz dieses Names ist ja sogar von zwei Bedingungen abhängig. Wenn die nicht erfüllt sind, wird dem Namen nichts zugewiesen und es gibt Namen erst nachdem ihnen das erste mal etwas zugewiesen wurde. Und selbst wenn er existiert, kann es sein das wegen der Bedingungen kein neuer Wert beim Aufruf der Funktion zugewiesen werden kann. Ist das in Ordnung dann einfach mit dem alten Wert weiter zu machen?

Letztlich solltest Du nicht mit ``global`` arbeiten sondern richtige Funktionen schreiben die einen Rückgabewert haben. Und auch Argumente, denn diese beiden Funktionen machen doch genau das gleiche. Das schreibt man nicht zweimal alles hin, sondern schreibt eine Funktion den/die Unterschied(e) als Argument(e) übergeben bekommen.

Vergiss das es ``global`` gibt. Auf Modulebene gehören auch keine Variablen. Da sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm gehört auch in eine Funktion, die üblicherweise `main()` heisst. Und alles was eine Funktion ausser Konstanten benötigt, wird als Argument(e) übergeben.

Kommentare sollten dem Leser einen Mehrwert über den Code geben. Faustregel: Nicht kommentieren *was* der Code macht, denn das steht da ja schon als Code, sondern *warum* er das (so) macht. Sofern das nicht offensichtlich ist. Die Kommentare die vor jeder Funktionsdefinition f stehen und nur aussagen das da jetzt die Funktion f definiert wird, sind total überflüssig. Funktionen in Kommentaren als Module zu bezeichnen ist falsch.

Warnungen sind nicht dazu da einfach abgeschaltet zu werden. Man sollte die Ursache für die Warnungen beseitigen. Bei GPIO ist das in der Regel das man dafür sorgt das am Ende des Programms die `cleanup()`-Funktion ausgeführt wird. Dafür bietet sich ``try``/``finally`` an.

Edit: Neue Programme sollte man nicht mehr mit Python 2 anfangen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
KHBeginner
User
Beiträge: 2
Registriert: Sonntag 17. März 2019, 14:59

Hallo blackjack,
vielen Dank für diese ausführliche Erläuterungen.
Ich werde jetzt erst einmal eine Weile beschäftigt sein den Code umzuschreiben.
Aber ich glaube dass das Hauptproblem nicht der Code ist, sondern dass der Raspberry von dem Sensor kein Wert bekommt.
Dies werde ich erst einmal ausgiebig durchmessen müssen.
Trotzdem vielen Dank für diese freundliche Unterstützung.

Gruß
Klaus
Tholo
User
Beiträge: 177
Registriert: Sonntag 7. Januar 2018, 20:36

Und tu dir selbst einen gefallen und nutz GPIOzero
https://gpiozero.readthedocs.io/en/stab ... nce-sensor Da is ein ein Beispiel drin und sieht auf dem ersten Blick handlicher aus
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Hallo Klaus
Ich habe am Raspi auch mit dem Ultraschallsensor und dem MC3008 rumexperimentiert.
Der MC3008 ist extrem empfindlich, also keine Kabel unter Strom abziehen. Dazu dürfen die Kabellängen vom Sensor zum Wandler nur ganz kurz sein, sonst stört zuviel Rauschen ein und es kommt kein Wert auf dem Raspi an. Nach diesen Versuchen bin ich auf Nodemcu und WiFi Übertragung umgestiegen, das geht problemls, da der ESP8266/Nodemcu einen Analogeingang hat, den man direkt abfragen kann und es auch brauchbare Arduino Skripts dafür gibt.
Antworten