Forum: PC-Programmierung Mit Raspi vom Arduino Daten holen über serielle Schnittstelle


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Andreas D. (andidohm)


Lesenswert?

Hallo Zusammen,
bei mir läuft ein Arduino Nano, der einige Sachen zur 
Hausautomatisierung macht. Unter anderem erfasst er auch die 
Temperaturen von ca. 20 Stellen und schreibt sie mit folgendem Code 
(Ausschnitt) jede Minute an die serielle Schnittstelle:
1
   for (int i=0; i<PT1000_ANZAHL; i++) {
2
       Serial.print(istTemperatur[i]);
3
       // Serial.print(i);
4
       Serial.print(RS232_TRENNZ);    // Trennzeichen
5
    }

Der Arduino Nano ist über den USB-Anschluss mit einem Raspberry Pi 
verbunden. Mit dem möchte ich die Temperaturdaten abholen und dann in 
eine Datei sowie eine InfluxDB schreiben.
Derzeit macht das ein Python-Script, hier die Funktion:
1
def readData():
2
    with serial.Serial(com_port, baud_rate, timeout=70) as s:
3
        serialmessage = s.readline()
4
        now = datetime.now()
5
        dtString = now.strftime("%Y-%m-%d-%H-%M-%S")
6
        kw = now.strftime("%W")
7
        year = now.strftime("%Y")
8
        dateiname = year + "-" + kw + "KW_Logfile.csv"
9
        datei = open(dateiname, "a")
10
        datei.write(dtString + "\t" + serialmessage)
11
        datei.close()
12
        writeInfluxDB(serialmessage)

Diese Funktion wird von der folgenden Main-Funktion aufgerufen. Falls 
ein Fehler auftritt, wird der COM-Port gewechselt:
1
while True:
2
    try:
3
        readData()
4
5
    except SerialException:
6
        time.sleep(3) # Waiting for 3 seconds
7
        print "Neuer Versuch, wechsle COM-Port"
8
        if com_port == '/dev/ttyUSB0':
9
            com_port = "/dev/ttyUSB1"
10
        else:
11
            com_port = "/dev/ttyUSB0"

Der Raspberry wird headless betrieben, ich greife also über die Konsole 
mit Putty darauf zu.
Das funktioniert soweit auch alles. Damit das Python-Script auch nach 
dem Beenden der Konsolensitzung weiterläuft, wird es mit nohup 
aufgerufen.

Grundsätzlich läuft das alles so. Manchmal beendet sich aber leider das 
Skript. Wenn ich das dann merke, starte ich es wieder neu.
Manch andere regelmäßig auszuführende Skripte habe ich in die crontab 
geschrieben. Hier habe ich aber Angst, dass es sich mit dem Timeout 
beisst.
Gibt es andere Möglichkeiten, zuverlässig die Daten vom Arduino zu 
holen, auch nach einem Neustart des Raspberrys?

von Harald K. (kirnbichler)


Lesenswert?

Andreas D. schrieb:
> Falls ein Fehler auftritt, wird der COM-Port gewechselt

Was soll das bringen?

von Frank K. (fchk)


Lesenswert?

Viele USB-Serial Adapter haben Seriennummern. Mit einer udev-Rule kannst 
Du also Deinen Arduino eindeutig identifizieren. z.B.

KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", 
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", 
ATTRS{serial}=="ABCDEFGH",SYMLINK+="ttyARDUINO",MODE="0666",RUN+="/opt/a 
rdu/script.sh"

Heißt also: Wenn ein USB-Serial Gerät mit Vendor ID 0403 (FTDI) und 
Product ID 6001 (also FT232) und Seriennummer ABCDEFGH detektiert wird, 
wird den wie gewohnt ein /dev/ttyUSBx zugewiesen, danach ein 
symbolischer Link /dev/ttyARDUINO auf das /dev/ttyUSBx angelegt, der 
Mode auf 0666 geändert, und das Skript /opt/ardu/script.sh gestartet. 
Egal, ob der Arduino bei Booten angesteckt ist oder nachträglich 
angesteckt wird.

Damit hat der über den symbolischen Link immer einen festen Devicenamen.

Warum sich Dein Skript beendet, kann ich jetzt nicht sagen. Das wäre zu 
debuggen.

fchk

von Bauform B. (bauformb)


Lesenswert?

Wenn der USB-Konverter sich abmeldet und gleich wieder anmeldet, ist 
/dev/ttyUSB0 noch busy und es wird ttyUSB1 benutzt. Offenbar ist das 
passiert und deshalb könnte man einen besseren Konverter probieren 
und/oder die Erdung kontrollieren.

von Sebastian W. (wangnick)


Lesenswert?

Andreas D. schrieb:
> Gibt es andere Möglichkeiten, zuverlässig die Daten vom Arduino zu
> holen, auch nach einem Neustart des Raspberrys?

Ja, mit systemd. Allerdings erledigt das nur den Neustart des Scripts 
nach Neustart des RasPi oder nach Script-Crash.

Um zuverlässig Daten auszutauschen benötigst du darüber hinaus noch ein 
geeignetes Protokoll. Du grenzt ja zur Zeit eine Datenzeile von der 
Nächsten durch eine Zeitlücke ab. Das wäre mir zu fehleranfällig. Du 
verwendest auch keine Prüfsumme, um diw Speicherung von durch 
Übertragungsfehler korrumpierte Daten zu minimieren.

LG, Sebastian

von Benjamin K. (bentschie)


Lesenswert?

Vorschlag:
Lass das USB weg, das ist einfach nicht zuverlässig zu bekommen.

Nimm das echte UART.

Der Nano hat echtes UART (an D0 und D1). Die werden jetzt schon 
verwendet und du brauchst da gar nix ändern in der SW.

Der RasPi kann anscheinend auch echtes UART. Direkt miteinender 
verbinden und schon ist die Zuverlässigkeit deutlich besser.

von Joachim B. (jar)


Angehängte Dateien:

Lesenswert?

beides kann so einfach sein
1. direkt mit R und Schutzdioden verbinden siehe Bild
2. mittels MAX3232 wichtig weil nur diese mit 3,3V vom Raspi arbeiten, 
andere 232 Chips brauchen mindesten 4,5V.

3. über fertige USB-RS232 und da Raspi auf Linux basiert kann man auch 
die USB ID befragen und immer den richtigen USB/seriell Kanal öffnen

Benjamin K. schrieb:
> Der RasPi kann anscheinend auch echtes UART.

nicht nur anscheinend!

Benjamin K. schrieb:
> Direkt miteinender
> verbinden und schon ist die Zuverlässigkeit deutlich besser.

nana, gegen direkt kann die Spannungslage sprechen und daß im Arduino 
diese schon belegt sind oder mit 5V laufen, also Vorsicht mit den 
Aussagen.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Benjamin K. schrieb:
> Lass das USB weg, das ist einfach nicht zuverlässig zu bekommen.

Das ist natürlich richtig, nirgendwo auf dem Planeten gibt es auch nur 
ein einziges USB-Gerät, das richtig funktioniert.

von Peter (wokinloksar)


Lesenswert?

Bauform B. schrieb:
> Wenn der USB-Konverter sich abmeldet und gleich wieder anmeldet, ist
> /dev/ttyUSB0 noch busy und es wird ttyUSB1 benutzt. Offenbar ist das
> passiert und deshalb könnte man einen besseren Konverter probieren
> und/oder die Erdung kontrollieren.

Daher den Vorschlag vom Vorposter übernehmen, und einen Alias anlegen.

Im Gegensatz zum Vorposter (#7759447) würde ich an Deiner Stelle das 
Script als Service laufen lassen.  Dann kümmert sich der Raspi von ganz 
alleine drum, dass ein abgestürztes Script auch wieder gestartet wird.

Z.B. https://github.com/torfsen/python-systemd-tutorial

von Harald K. (kirnbichler)


Lesenswert?

Man könnte auch versuchen, herauszufinden, warum sich der 
USB-Seriell-Adapter "abmeldet", denn das ist nicht normal.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Harald K. schrieb:
> Man könnte auch versuchen, herauszufinden, warum sich der
> USB-Seriell-Adapter "abmeldet", denn das ist nicht normal.

So isses.

Ich kenne das Phänomen eigentlich nur aus einer Anwendung: Da werden zu 
testende, frisch produzierte Geräte u.a. mit Tests bezüglich der 
elektrischen Sicherheit gequält und die Auswertungssoftware der 
Ergebnisse interagiert neben dem elektrischen Folterknecht auch mit dem 
Prüfling (über USB, denn was anderes hat der nicht). Oder eben plötzlich 
auch nicht mehr...

Aus dieser Erfahrung weiß ich, dass Windows mit dieser Situation 
garnicht gut klarkommt. Es kostet schon einigen Hirnschmalz, das Problem 
plötzlich verschwindender "serieller" USB-Geräte programmtechnisch 
sinnvoll in den Griff zu bekommen.

Aber ganz klar: das ist ein Extremszenario. Normalerweise passiert es 
nicht, dass so ein Gerät plötzlich "von allein" verschwindet. Nö, dafür 
muss schon der Vollhonk vor dem Rechner den USB-Stecker ziehen, während 
das Gerät noch in Benutzung ist.

von Philipp K. (philipp_k59)


Lesenswert?

Ich würde vielleicht einfach mehr loggen um herauszufinden wo es hängt. 
Dazu vielleicht noch nebenbei die Ausgabe des Scripts in eine Datei 
schreiben. Normalerweise sollte das bis zu einem Stromausfall 
durchlaufen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.