Forum: Projekte & Code Python <-> MC serial


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 Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Python ist sehr nützlich, wenn es um die Steuerung eines 
Mikrocontrollers oder die Visualisierung von Daten geht.

In diesem Thread will ich ein paar sehr einfache und nützliche Templates 
für Python entwerfen, um eine Grundlage für einfache GUIs und eigene 
Anpassungen zu schaffen. Verbesserungsvorschläge und eigene Beiträge 
sind sehr willkommen.

Als erstes ein Beispiel für einen Frequenzgenerator, der mit zwei 
Buttons gesteuert werden kann.

von MaNi (Gast)


Lesenswert?

Christoph M. schrieb:
> Verbesserungsvorschläge und eigene Beiträge
> sind sehr willkommen.

Wenn ich mir den Code so anschaue würde ich folgendes anders machen:
* Es scheint keine Frame-Ende-Erkennung vorhanden zu sein. Wenn ich 
schnell genug auf den Button drücken könnte oder wenn später mal vom 
Programm eine Frequenz-Folge gesendet würde z.B. "100" + "101" für einen 
Sweep, dann könnte es meiner Meinung nach passieren dass der uC nicht 
"100" empfängt, sondern z.B. "100101". Das als int interpretiert ist 
blöd.
Momentan verhindert das meiner Meinung nach nur, dass das Python 
Programm zu langsam ist (sleep) bzw. dass der uC schnell genug ist.
Also würde ich mindestens ein '\n' einfügen, damit man immer weis wo ein 
Frame zuende ist.

* Es gibt keine Sicherungsschicht. Ein Glitch auf der Leitung führt 
sofort zu einem falschen Ergebnis. Eine Blocksumme oder CRC wäre einfach 
zu implementieren.
Bei der Frequenz vllt. nicht ganz so schlimm, sobald Du aber die 
Ausgangsspannung o.ä. einstellen möchtest und ein Übertragungsfehler 
zerhaut dir deine Schaltung weil anstatt 1V 10V anliegen...

* Den Sleep würde ich komplett entfernen. Der ist unnötig wenn du Sende- 
und Empfangsrichtung auftrennst. Du weist was du von Python gesendet 
hast und erwartest eine Antwort. Also eher:
Neuer Wert senden. Erwartete Antwort merken. Timer aufziehen bis wann 
die Antwort zurück sein muss. OK melden falls es innerhalb dieser Zeit 
zurückkommt. Ansonsten neu senden o.ä.

Alles hier nur als Anmerkung zu verstehen, nicht als Kritik.

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

>Alles hier nur als Anmerkung zu verstehen, nicht als Kritik.

Das passt schon. Ich bin ja froh, dass es sich überhaupt jemand anschaut 
und konstruktive Beiträge sind ja gut ;-)

>* Es scheint keine Frame-Ende-Erkennung vorhanden zu sein. Wenn ich
schnell genug auf den Button drücken könnte oder wenn später mal vom
Programm eine Frequenz-Folge gesendet würde z.B. "100" + "101" für einen
Sweep, dann könnte es meiner Meinung nach passieren dass der uC nicht
"100" empfängt, sondern z.B. "100101". Das als int interpretiert ist
blöd.
Momentan verhindert das meiner Meinung nach nur, dass das Python
Programm zu langsam ist (sleep) bzw. dass der uC schnell genug ist.
Also würde ich mindestens ein '\n' einfügen, damit man immer weis wo ein
Frame zuende ist.

Ja, an der Stelle hast du sicherlich recht. Das kann zu Problemen 
führen, deshalb habe ich mal ein neues Beispiel gemacht.
Es immer nur ein Byte als Kommando übertragen, damit kann es keine 
Falschinterpretation geben.
Es gibt 3 Knöpfe:
Zaehler hochzaehlen, Zaehler unter zaehlen und ADC lesen.
Damit kann man sehr gut die Zuverlässigkeit der Datenübertragung prüfen. 
Besser wäre es noch, den Zaehlerknopf mit einem Event-Timer automatisch 
zu betätigen, dann kann man die Kommunikation über längere Zeit 
beobachten. Allerdings weiß ich noch nicht, wie man das in Python im 
Zusammenhang mit TkInter realisiert.
Bis jetzt habe ich bei diesem Beispiel aber noch keine fehlerhafte 
Übertragung festgestellt.

>* Es gibt keine Sicherungsschicht. Ein Glitch auf der Leitung führt
sofort zu einem falschen Ergebnis. Eine Blocksumme oder CRC wäre einfach
zu implementieren.
Bei der Frequenz vllt. nicht ganz so schlimm, sobald Du aber die
Ausgangsspannung o.ä. einstellen möchtest und ein Übertragungsfehler
zerhaut dir deine Schaltung weil anstatt 1V 10V anliegen...

Eine Überprüfung mit Checksumme könnte man sich überlegen. Allerdings 
ist meine Erfahrung, dass die serielle Übertragung bezüglich der 
Einzelbitfehler mittlerweile recht zuverlässig funktioniert. Wenn 
Probleme auftreten, sind das meistens Timing Probleme, was in die 
Richtung deiner ersten Anmerkung geht.

>* Den Sleep würde ich komplett entfernen. Der ist unnötig wenn du Sende-
und Empfangsrichtung auftrennst. Du weist was du von Python gesendet
hast und erwartest eine Antwort. Also eher:
Neuer Wert senden. Erwartete Antwort merken. Timer aufziehen bis wann
die Antwort zurück sein muss. OK melden falls es innerhalb dieser Zeit
zurückkommt. Ansonsten neu senden o.ä.

Das läuft dann in Richtung Protokollimplemtierung wie TCP-IP und wird 
dann ziemlich aufwendig. Meiner Erfahrung nach ist das bei so einer 
direkten drahtgebundenen Kommunikation nicht erforderlich.

von N. M. (mani)


Lesenswert?

Christoph M. schrieb:
> Das passt schon. Ich bin ja froh, dass es sich überhaupt jemand anschaut
> und konstruktive Beiträge sind ja gut ;-)

OK 👍 dann merke ich nochmal an.

Christoph M. schrieb:
> Ja, an der Stelle hast du sicherlich recht. Das kann zu Problemen
> führen, deshalb habe ich mal ein neues Beispiel gemacht.
> Es immer nur ein Byte als Kommando übertragen

Das hilft dir zwar in der Interpretation weil es eindeutig ist, trotzdem 
bekommst du bei einer Störung bei der Anforderung eine falsche Aktion im 
Arduino. Wenn du dann einen falschen Wert zurück bekommst weißt du nicht 
Mal ob der Arduino sich wirklich verzählt hat oder ob es ein ADC Wert 
ist.
Dass a,h und r mindestens 2 Bits auseinanderliegen hilft hier zwar ein 
bisschen, aber nicht wirklich.

Christoph M. schrieb:
> Damit kann man sehr gut die Zuverlässigkeit der Datenübertragung prüfen.

Christoph M. schrieb:
> Bis jetzt habe ich bei diesem Beispiel aber noch keine fehlerhafte
> Übertragung festgestellt.

Auf dem Labortisch daheim mag das funktionieren. Sobald aber ein paar 
Meter Kabel dazwischen sind, jemand ein Gerät in der Umgebung 
ein-/ausschaltet oder eine andere Kleinigkeit passiert geht es schief. 
Glaub mir. Alles schon gehabt. Schalt Mal den Staubsauger, Bohrmaschine 
oder ähnliches daneben ein und aus.

Christoph M. schrieb:
> Allerdings ist meine Erfahrung, dass die serielle Übertragung bezüglich
> der Einzelbitfehler mittlerweile recht zuverlässig funktioniert.

Weil die Chips mehrfach Abtasten (z.B. 3/5-Fach oder höher) und dann 
eine Mehrheitsentscheidung treffen. Hilft dir trotzdem nur bedingt was. 
Sobald der Störer bereitet als eine Bitzeit ist bringt das nichts mehr.
Ich würde mindestens das Parity Bit einschalten auf beiden Seiten. 
Kostet dich nichts. Hilft aber einiges. Sozusagen die Sicherungsschicht 
für arme. Default ist nämlich auf beiden Seiten aus.

Christoph M. schrieb:
> Wenn Probleme auftreten, sind das meistens Timing Probleme, was in die
> Richtung deiner ersten Anmerkung geht.

Ich glaube du hast nur noch nicht eine verseuchte Umgebung oder 
Masseprobleme gesehen 😄
Man bekommt es selbst bei differentieller Übertragung zuverlässig hin 
dass die Daten Müll sind.

Christoph M. schrieb:
> Das läuft dann in Richtung Protokollimplemtierung wie TCP-IP

Bei weitem nicht. Das ist eine ganz andere Nummer. Einfach ein ACK vom 
Arduino dass der letzte Befehl gültig war. Ob das ein festes Zeichen ist 
oder ob das einfach nochmal der empfangene Frame wiederholt ist spielt 
in dem Fall keine Rolle. Dadurch hat man aber zumindest die Möglichkeit 
zu sehen dass etwas erneut gesendet werden muss.
Ähnlich wie bei deinem Zähler, nur dass es für alle Befehle 
funktionieren würde.

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Fehlerkorrekturen kann man natürlich beliebig weit treiben.
Innerhalb elektronischer Systeme wird nicht alles auf Fehler geprüft, 
weil man davon ausgeht, dass die Datenübertragung zwischen den Bauteilen 
zuverlässig ist z.B. I2C oder die meisten einfacheren Controllersystem 
bei denen es z.B. zwischen der CPU und dem Speicher keinen Fehlercheck 
oder Fehlerkorrektur gibt. So was fängt dann bei größeren Systemen wie 
PCs an.

Vielleicht magst Du ein fehlertolerantes Protokoll in den Code einfügen.
Für mich reicht die Zuverlässigkeit der Übertragung im aktuellen Aufbau.
Das Bild zeigt den Zählerstand (8Bit) im MC über einige Minuten.

von N. M. (mani)


Lesenswert?

Christoph M. schrieb:
> Innerhalb elektronischer Systeme wird nicht alles auf Fehler geprüft

Stimmt, teilweise sagt man dass es egal ist und dass zum Beispiel ein 
falscher Wert nicht stört. Weil z.B. innerhalb von ein paar us/ms 
sowieso ein neuer Wert kommt. Bei nicht ganz so wichtigen Prozessdaten 
kann man das machen. Teilweise wird auch mehrfach gelesen. Wobei ich 
dann lieber ein Byte mehr reservieren würde.

Christoph M. schrieb:
> bei denen es z.B. zwischen der CPU und dem Speicher keinen Fehlercheck
> oder Fehlerkorrektur gibt

Das sind, wenn der HW Mensch alles richtig gemacht hat, auch wenige mm 
bis cm auf einer Platine innerhalb eines Gehäuses. Bei dir verbindest du 
2 unterschiedliche Komponenten. Evtl über Meter hinweg. Ist ein anderer 
Fall. Außerdem wird jeder SW Mensch der bei Verstand ist nicht die Daten 
ohne Checksumme in den NV-Speicher schreiben.
Also selbst wenn sie falsche drin stehen im Speicher, falsch rauslesen 
und verwenden tut man sie definitiv nicht.

Christoph M. schrieb:
> Vielleicht magst Du ein fehlertolerantes Protokoll in den Code einfügen.

Warum etwas neues erfinden was es schon zu genüge gibt. In deinem Fall 
würde Modbus RTU passen.
Hier ein Beispiel für Arduino wo man nur noch die Pins anpassen müsste:

https://github.com/yaacov/ArduinoModbusSlave/blob/master/examples/simple/simple.ino

PC seitige Tools gibt es da schon genügend. Einbindung in andere Systeme 
(Smart Home, Raspi, Visu,...) sind auch schon alle vorhanden.

Christoph M. schrieb:
> Für mich reicht die Zuverlässigkeit der Übertragung im aktuellen Aufbau.
> Das Bild zeigt den Zählerstand (8Bit) im MC über einige Minuten.

Ist ja in Ordnung. Wenn es dir reicht.
Du postest hier aber unter der Kategorie Projekte & Code wo man 
normalerweise anderen etwas zur Verfügung stellt. Und dafür finde ich es 
einfach nicht gut genug ehrlich gesagt.
Aber das ist Ansichtssache.

von Christoph M. (mchris)


Lesenswert?

>Hier ein Beispiel für Arduino wo man nur noch die Pins anpassen müsste:

>https://github.com/yaacov/ArduinoModbusSlave/blob/master/examples/simple/simple.ino

>PC seitige Tools gibt es da schon genügend. Einbindung in andere Systeme
>(Smart Home, Raspi, Visu,...) sind auch schon alle vorhanden.

Ah, da liegt vielleicht das Missverständnis: In diesem Thread geht es 
mir speziell um Python. Es geht hier nicht um eine fertige 
Bedienoberfläche oder ein fertiges Programm, sondern um Python-Templates 
mit GUI, mit denen man schnell eigene Messaufgaben automatisieren kann. 
Man kann sie sich hier einfach kopieren und für eigene Probleme 
anpassen.

Man mag sich fragen, ob man so etwas Sinn macht: Meiner Meinung nach ja, 
weil man schneller ist, als sich die Codefragmente lange im Internet 
zusammenzusuchen.

Vielleicht hast du ja schon einen Treiber für Python und Modbus 
gefunden.

Eigentlich wäre es konsequent, auch die Mikrocontrollerseite in Python 
zu programmieren.

Die Beschränkung auf einen Bus wie z.B. auf Modbus ist auch ein wenig zu 
eng, weil man bei einer Messaufgabe z.B. auch ein Oszi über TCP-IP 
parallel zum MC steuern können soll.

von N. M. (mani)


Lesenswert?

Christoph M. schrieb:
> Es geht hier nicht um eine fertige
> Bedienoberfläche oder ein fertiges Programm, sondern um Python-Templates
> mit GUI, mit denen man schnell eigene Messaufgaben automatisieren kann.

Und wenn es da jetzt ein Script geben würde, dass so universell wäre 
dass es über die unterschiedlichen Applikation im uC skalierbar 
wäre...dann wäre das auch echt cool.
So in etwa wie:
Beitrag "Neu: SerialComMCU Daten von der seriellen Schnittstelle visualisieren"
oder
Beitrag "Projekt: Virtuelle Instrumente an serielle Schnittstelle"

Christoph M. schrieb:
> Vielleicht hast du ja schon einen Treiber für Python und Modbus
> gefunden.

Hm, z.B. den?
https://minimalmodbus.readthedocs.io/en/stable/readme.html#features

Christoph M. schrieb:
> Eigentlich wäre es konsequent, auch die Mikrocontrollerseite in Python
> zu programmieren.

Muss meiner Meinung nach nicht sein. Wenn sich jeder an den Standard 
hält sollte das ja (theoretisch) alles miteinander funktionieren.
Python auf uC schränkt halt sehr stark ein. Denke z.B. nicht dass 
uPython auf einem ATtiny oder ähnlichem läuft. Die C/CPP Implementierung 
wahrscheinlich schon.

Christoph M. schrieb:
> Die Beschränkung auf einen Bus wie z.B. auf Modbus ist auch ein wenig zu
> eng, weil man bei einer Messaufgabe z.B. auch ein Oszi über TCP-IP
> parallel zum MC steuern können soll.

Das eine schließt das andere ja nicht aus. Du kannst dein Oszi ja über 
das gleiche Python-Script steuern wie dein uC der aber Modbus über 
UART/RS485 (RTU) oder Ethernet spricht.

von stef (Gast)


Lesenswert?

Ich persönlich würde SCPI bevorzugen: Der Arduino ist dann ein 
SCPI-Server ähnlich wie ein Messgerät. Hierzu gibt es schon fertige 
Arduino-Bibliotheken.
Siehe z.B. https://github.com/Vrekrer/Vrekrer_scpi_parser
In Python gibt es die Bibliothek py-Visa 
(https://pyvisa.readthedocs.io/en/latest/), mit der man auf Messgeräte 
zugreifen kann, die dem VISA-Standard entsprechen. SCPI ist Teil des 
Visa-Standards. Es sollte dann also auch funktionieren, auf den 
SCPI-Arduino zuzugreifen, falls man die SCPI-Kommandos nicht zu Fuß an 
den Arduino senden möchte.

Beim Red Pitaya (STEMLab) verwende ich übrigens diesen Weg, was dort 
prima funktioniert.

von bernd (Gast)


Lesenswert?

Hier noch ein Beispiel wie man mit py-Visa die Messdaten eines 
Oszilloskops visualisiert:
https://nbviewer.org/github/StefanMack/PraktMesstVISA/blob/master/AutomMessenMitPython.ipynb

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Ok, vielleicht habt ihr Recht und ich sollte es mal mit fertigen 
Kommunikationsprotokollen versuchen.

Hier als im Anhang der Frequenzgenerator mit SCPI Steuerung. Der 
funktioniert jetzt zuverlässig inclusive Rückmeldung und Identifier. 
Irgendwie ist es doch angenehm, wenn man mit der GUI den Status des 
Gerätes abfragen kann.

Eigentlich ist die Benutzung der Library relativ einfach. Aber bis es 
jetzt so funktioniert hat, war ich doch eine Stunde beschäftigt.

von N. M. (mani)


Lesenswert?

Christoph M. schrieb:
> Hier als im Anhang der Frequenzgenerator mit SCPI Steuerung.

Unter 40 Zeilen Code pro Seite. Das wäre es mir wert dafür eine saubere 
Übertragung zu bekommen 👍

Christoph M. schrieb:
> Aber bis es jetzt so funktioniert hat, war ich doch eine Stunde
> beschäftigt.

Woran lag es? Referenzen? Oder die Bedienung der Libraries?

von Christoph M. (mchris)


Lesenswert?

>Woran lag es? Referenzen? Oder die Bedienung der Libraries?

Das Problem bei der Kommunikation zweier Teilnehmer ist, dass auf beiden 
Seiten Fehler passieren können. Meiner Erfahrung nach ist die 
Fehlersuche bei der Entwicklung von Kommunikationsprotokollen immer 
kompliziert.
In dem Fall habe ich mich auf der Senderseite vertippt, aber die 
Fehlersuche war dann schwierig, weil ich nicht wusste, ob es an der 
Library oder am Sender liegt.

Das allererste Beispiel hier im Thread ist extrem einfach aber zeigt 
sporadische Fehler. Ich habe noch einmal versucht, herauszubekommen, wo 
die Ursache liegt. Die Hardware funktioniert zuverlässig und der Fehler 
scheint in den Sende- oder Empfangsroutinen zu liegen.

Ich konnte nicht herausfinden, was der "Delimiter" von ReadString ist
1
frequency = Serial.readString().toInt();

ist es das 0x00 aus C oder ist es 0x10, 0x13 ?

Die Verwendung der SCPI Bibliothek vereinfacht die Sache zwar, weil es 
out of the Library-Box funktioniert. Sie hat aber z.B. auch keine 
Fehlerkorrektur.
Mir scheint das Problem mit der Verwendung von "readString" und der 
Pythonseitigen Abstraktion "übertüncht".

: Bearbeitet durch User
von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Die neueste Version: Frequenzgenerator + Frequenzzähler

Läuft bis ca. 20kHz auf Arduino Uno. PiPico geht mit dem selben Code.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.