Serielle Kommunikation Xmega Raspberry

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
lendl
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2021, 13:07

Hallo Kolleginnen und Kollegen,

ich habe auf dem Raspberry einen kleinen Python Script im Autostart der die serielle Schnittstelle auswertet.
An der seriellen Schnittstelle kommen im Sekundentakt Messwerte an.

Dieser Script scheint nach einiger Zeit abzustürzen.
Wenn ich den Python-Script via Eintrag unter rc.local laufen lasse, dann sieht man bei den laufenden Prozessen, dass er irgendwann einfach verschwindet.
(irgendwann bedeutet zwischen wenigen Sekunden und mehreren Stunden)

Da ich keine Ahnung von Python habe und mir den Code aus Internet-Schnipseln zusammenkopiert habe, möchte ich Euch bitte, dass Ihr einfach mal drüber schaut.
Vielleicht seht Ihr ja gleich den Fehler...
Cool wäre es, wenn Ihr mir einen Tipp geben könnt, wie ich herausfinden kann, warum er abstürzt (wie man zum Beispiel einen Eintrag in Logdatei schreibt, usw...)

Code: Alles auswählen

#!/usr/bin/python
#coding: utf8
#!/usr/bin/env python
import time
import serial
import subprocess
import os.path
ser = serial.Serial("/dev/ttyS0")
ser.baudrate = 19200
x = 0
while 1:
        try:
                i=ser.readline()
                print i
                if ("record stop" in i):
                        print "record stop"
                        x = 0
                if ("record start" in i):
                        print "record start"
                        x = 1
                if ("umount" in i):
                        cmd = "sudo umount -l /media/usb"
                        os.system(cmd)
                if (x == 1):
                        try:
                                if os.path.ismount("/media/usb/"):
                                        File_Obj = open("/media/usb/reading.txt", "a")
                                        File_Obj.write(i)
                                        File_Obj.close
                                        ser.write("O")
                                else:
                                        ser.write("F")
                        except:
                                print("error write usb")
        except:
                continue
Vielen Dank vorab!
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@lendl: Du solltest kein Python 2 mehr verwenden, das hat das Ende der Support-Zeit überschritten.

Dann ist rc.local auf einem systemd-basierten System eine hässliche Notlösung. Schreib für den Dienst eine systemd-Unit. Da kannst Du dann auch gleich dafür sorgen, dass die Ausgaben des Programms protokolliert werden und Du nach dem Absturz mal schauen kannst was das so ausgegeben hat. Beispielsweise eine Fehlermeldung.

Damit Du sinnvolle Fehlermeldungen bekommst, darfst Du mit ``except`` nicht einfach *alle* Ausnahmen behandeln, sondern nur die, die Du auch erwartest. Wenn man *alle* behandelt ist die nahezu einzige sinnvolle Art das zu tun, die Ausnahme samt Traceback zu protokollieren, denn nur so kann man Fehlern auf die Spur kommen, mit denen man an der Stelle nicht gerechnet hat.

Eingerückt wird in Python mit vier Leerzeichen pro Ebene.

`subprocess` und `time` werden importiert aber nicht verwendet. `subprocess` sollte aber verwendet werden, denn `os.system()` sollte man nicht mehr verwenden. Da verweist die Dokumentation auch auf das `subprocess`-Modul.

Die Baudrate kann man auch gleich beim erstellen des `Serial`-Objekts angeben. Ausserdem sollte man dafür sorgen, das die serielle Schnittstelle am Ende auch ordentlich wieder geschlossen wird. Dafür bietet sich die ``with``-Anweisung an.

`connection` wäre ein deutlich besserer Name als das kryptische `ser`. Und `x` geht gar nicht. Namen sollen dem Leser vermitteln was der Wert bedeutet. Bei ``x = 0`` geht jeder erst einmal davon aus, dass es sich hier um eine Zahl handelt die beliebige Gleitkommawerte annehmen kann. Da sollte also a) ein passender Name hin und b) der Wert `False` statt 0, denn das ist ja offensichtlich von der Bedeutung her ein Wahrheitswert. Beim ``while`` die 1 ist dann auch `True`.

`i` ist ein ganz schlechter Name für etwas anderes als ganze Zahlen die als Index verwendet werden. `line` wäre ein wesentlich besserer Name für das Ergebnis eines `readline()`-Aufrufs. Den ich nicht machen würde, denn `Serial`-Objekte sind iterierbar über die Zeilen.

Um die Bedingung bei ``if`` gehören keine Klammern.

Ich vermute mal die drei Bedingungen was in der Zeile enthalten ist, schliessen sich gegenseitig aus? Dann sollte man ``elif`` verwenden.

Code und Daten sollten sich nicht wiederholen. "/media/usb" kommt mehrfach vor, sollte also als Konstante herausgezogen werden. Und dann am besten auch gleich als `pathlib.Path`-Objekt.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Das `Obj` in `File_Obj` ist zudem ohne irgendwelchen Mehrwert. Natürlich ist das ein Objekt. Alles was man an einen Namen binden kann ist in Python ein Objekt.

Die Datei wird nicht wieder geschlossen. Es reicht nicht nur die Methode zu referenzieren, man muss sie auch *aufrufen*. Oder auch hier wieder ``with`` verwenden.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import logging
import os
import subprocess
from pathlib import Path

from serial import Serial

logging.basicConfig()

MOUNTPOINT = Path("/media/usb")


def main():
    with Serial("/dev/ttyS0", 19_200) as connection:
        is_recording = False
        while True:
            try:
                for line in connection:
                    logging.info(line)

                    if b"record stop" in line:
                        logging.info("record stop")
                        is_recording = False
                    elif b"record start" in line:
                        logging.info("record start")
                        is_recording = True
                    elif b"umount" in line:
                        subprocess.run(
                            ["sudo", "umount", "-l", str(MOUNTPOINT)],
                            check=True,
                        )

                    if is_recording:
                        try:
                            if os.path.ismount(MOUNTPOINT):
                                with (MOUNTPOINT / "reading.txt").open(
                                    "ab"
                                ) as file:
                                    file.write(line)
                                connection.write(b"O")
                            else:
                                connection.write(b"F")
                        except:
                            logging.exception("while writing to usb")
            except:
                logging.exception("huh?")


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
lendl
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2021, 13:07

Wow, ich bin absolut begeistert von Deiner Hilfsbereitschaft und Deinen Erklärungen (auch wenn ich vieles noch nicht verstehe).
Dass hier einem Anfänger auf so einem Niveau geholfen wird, das spricht wirklich für dieses Forum.

Deshalb an dieser Stelle erstmal vielen, vielen Dank!

Ich werde ein bisschen brauchen bis ich es getestet habe und vorallen habe ich noch etliche Fragen zu den Erklärungen.
Viele Begriffe und Vorgehensweisen sind mir nicht geläufig, da werde ich wohl noch etliche Fragen haben...

Nochmals vielen Dank!
lendl
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2021, 13:07

So, jetzt hat es deutlich länger gedauert als angenommen, aber jetzt greife ich diese Projekt endlich an:
Ich habe versucht den Code mal zu testen, bekomme aber folgenden Fehler beim starten:

Code: Alles auswählen

from serial import Serial
ModuleNotFoundError: No module named 'serial'
Ich habe dann python3-serial installiert (sudo apt-get install python3-serial) bekomme dann aber folgenden Fehler:

Code: Alles auswählen

from serial import serial
ImportError: cannot import name 'serial' from 'serial' (/usr/lib/python3/dist-packages/serial/__init__.py)
Muss ich noch etwas nachistallieren?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Gross- und Kleinschreibung sind bei Python wichtig. In deinem eigene posting steht, wie es richtig geht.
Antworten