Pi2Pi Communication - Automatisierung auf dem Wasser

Hier kannst du dein Revolution Pi Projekt der Community vorstellen
Ricarda
Posts: 15
Joined: 20 Jan 2020, 14:23
Answers: 0

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by Ricarda »

Hallo zusammen,

ich hatte die Möglichkeit die Sachen meines letzten Beitrags auszuprobieren. Am Ende leider erfolglos.
Ich habe auf dem Master versuchsweise 2 Typen von virtuellen Devices ausprobiert, hat beides nicht funktioniert:
- RevPi7
- Virtual Device 32 Byte

Bei Master bin ich wie unten beschrieben vorgegangen. Das hat soweit auch scheinbar funktioniert. Nachdem ich die Zeile
revpimodio2.RevPiNetIO ('xxx.xxx.xxx.xxx') eingetragen hatte, erhielt ich die Nachricht:
revpimodio2.netio.RevPiNetIO object at 0x76af27e8
Beim Slave bin ich wie unten beschreiben vorgegangen und erhielt über die Zeile
revpimodio2.RevPiNetIODriver('xxx.xxx.xxx.xxx','Test')
revpimodio2.netio.RevPiNetIODriver object at 0x76860ae0
Ebenfalls beim Slave dann folgende Befehle:
rpi = revpimodio2.RevPiModIO(autorefresh = True)

Ich habe dann versucht über rpi.io['value aus dem virtuellen Device'].value den Wert auszulesen und erhielt folgende Ausgabe':
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3/dist-packages/revpimodio2/io.py", line 79, in __getattr__
raise AttributeError("can not find io '{0}'".format(key))
AttributeError: can not find io 'In1'
Auch über revpimodio.RevPiNetIODriver.io['value aus dem virtuellen Device'].value erhalte ich nur den folgenden Fehler:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'member_descriptor' object has no attribute 'Ouput_4_i06'
Ich vermute, dass ich da etwas Grundlegendes nicht verstanden habe. Ich hoffe, mir kann jemand dabei helfen.

Lieben Gruß und Danke

Ricarda
User avatar
RevPiModIO
KUNBUS
Posts: 322
Joined: 20 Jan 2017, 08:44
Answers: 0
Contact:

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by RevPiModIO »

Hi Ricarda!

Sorry für die späte Antwort, habe aber ein paar Neuerungen für RevPiModIO mitgebracht :P

Es ist sogar noch einfacher! RevPiPyLoad kannst du auf jedem RevPi Installieren, sowohl auf dem Master als auch auf dem Slave. Auf dem Master führt es dein eigentliches Python Programm aus und auf dem Slave bietet es den Endpunkt für RevPiNetIO.

Slave-Konfiguraiton:
Du konfigurierst auf dem Slave einfach den parameter „plcslave=1“. In der „aclplcslave.conf“ trägst du die IP des Masters ein und gibst ihm das Recht ,0, wenn er nur lesen soll oder ,1 wenn er auch schreiben soll. Mehr musst du theoretisch auf dem Slave gar nicht machen.

Master-Konfiguration:
Auf dem Master programmierst du dein eigentliches Steuerungsprogramm. In dem Programm kannst du ganz normal RevPiModIO für das lokale Prozessabbild verwenden und zusätzlich eine Instanz für den Slave:

Code: Select all

rpi_master = revpimodio2.RevPiModIO(autorefresh=True)
rpi_slave = revpimodio2.RevPiNetIO(“ip-vom-slave“, autorefresh=True)
# ...
Und mit den beiden Instanzen kannst du nun auf dem Master das komplette Programm schreiben, welches eben auch ganz normal die IOs des Slaves verwendet, inkl. Events oder loops usw.

Wenn du den .cycleloop verwenden willst, dann würde ich für den rpi_slave das autorefresh auf False setzen und zu beginn im loop die Inputs einlesen und am Ende die Outputs schreiben. So kannst du die beiden Prozessabbilder synchronisieren innerhalb eines Zyklus.

Code: Select all

rpi_master = revpimodio2.RevPiModIO(autorefresh=True)
rpi_slave = revpimodio2.RevPiNetIO(“ip-vom-slave“)

# ...

def cycle(ct):
    rpi_slave.readprocimg()
    
    # work with frozen procimgs
    
    rpi_slave.writeprocimg()

rpi_master.cycleloop(cycle)

Das wäre die einfachste Variante, wenn der Slave-Teil der Anlage keine eigene Steuerung ist.

PS: Unbedingt die aktualisierten Versionen von RevPiModIO (2.4.5) und RevPiPyLoad (0.8.5) verwenden! Da wurde das NetIO grad stark überarbeitet.

Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
Ricarda
Posts: 15
Joined: 20 Jan 2020, 14:23
Answers: 0

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by Ricarda »

Hi Sven,

kein Problem, ist ja immer noch eine schnelle Antwort ;) Ich hab's mal flott ausprobiert, funktioniert super. Vielen Dank :).

Ich wollte auf dem Slave schon ein Programm abspielen lassen, aber ich dachte, ich schreibe das Ergebnis einfach auf ein virtuelles Device und das kann der Master dann "abfragen", wenn er die Info braucht. Oder geht das nicht?
Da geht es auch überhaupt nicht um Geschwindigkeit, das Ergebnis der Auswertung auf dem Slave ändert sich sehr selten (es geht da um ein Pegelsignal, das über eine Zwei-Punkt-Regelung quasi nur eine Betriebserlaubnis gibt oder nicht. Die geforderte Reaktionszeit auf die "Erlaubnis" liegt aber eher so um die 3 h).

Lieben Gruß

Ricarda
User avatar
RevPiModIO
KUNBUS
Posts: 322
Joined: 20 Jan 2017, 08:44
Answers: 0
Contact:

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by RevPiModIO »

Hi Ricarda, da verstehe ich das Konstrukt grade nicht wirklich :(

Lass uns mal dein Bild als Basis nehmen - Ich verstehe das so:
Auf dem RevPi3 läuft die eigentliche Steuerung.
RevPi2 und RevPi1 haben zusätzliche analoge Werte, die in der Steuerung des RevPi1 benötigt/verarbeitet werden.

Am einfachsten ist der von mir beschriebene Weg, wo du RevPi1 und RevPi2 über RevPiNetIO direkt mit in die Steuerung von RevPi3 integrierst. Damit hat der RevPi3 die komplette Kontrolle auf RevPi1 und RevPi2 und arbeitet mit dessen Daten so, als wären die IOs direkt bei ihm im Prozessabbild.

Code: Select all

revpi3 = revpimodio2.RevPiModIO(autorefresh=True)
revpi1 = revpimodio2.RevPiNetIO(“ip-vom-revpi1“)
revpi2 = revpimodio2.RevPiNetIO(“ip-vom-revpi2“)

# Sollten an revpi1 und revpi2 doch mal Ausgänge kommen, könnten diese Zeilen wichtig sein bei Verbindungsverlust
revpi1.net_setdefaultvalues()
revpi2.net_setdefaultvalues()

# ...

def cycle(ct):
    revpi1.readprocimg()
    revpi2.readprocimg()
    
    # work with frozen procimgs of all cores
    revpi3.io.ioname.value  # do something...
    revpi1.io.ioname.value  # do something...
    revpi2.io.ioname.value  # do something...
    
    revpi1.writeprocimg()
    revpi2.writeprocimg()

revpi3.cycleloop(cycle)
revpi1.disconnect()
revpi2.disconnect()

So musst du nur ein Programm pflegen und kannst alle Berechnungen und Aktionen in diesem einen Programm machen.


Praktisch ist die Verwendung von virtuellen Devices, wenn auf RevPi1 oder RevPi2 separate Steuerungsprogramme laufen. Diese laufen lokal dann ja auch einfach mit RevPiModIO und verbinden sich zusätzlich mit RevPiModIODriver mit einem virtuellen Device auf dem RevPi3, auf dem für jeden RevPi, der sich verbindet ein eigenes virtuelles Device in piCtory konfiguriert haben muss. Das bietet sich an, wenn RevPi1 und RevPi2 eigene Aufgaben erledigen und steuern und dem RevPi3 bestimmte Werte für die gesamte Anlage übergeben müssen. Oder eben andersherum.


Ein weiterer interessanter Verwendungszweck von virtuellen Devices ist die Speicherung von Variablen. Wenn man Variablen statt direkt in Pythonprogramm in einem virtuellen Device speichert, kann man mit RevPiPyControl natürlich immer drauf schauen und mit den Werten auch andere RevPis versorgen. Dazu müsste man allerdings auch je nach Datentyp mit .replace_io neue IOs erzeugen :D

Ich denke der obere Ansatz würde bei dir passen. Wenn du statt mit cycleloop lieber mit events arbeiten willst, könntest du das so machen:

Code: Select all

revpi3 = revpimodio2.RevPiModIO(autorefresh=True)
revpi1 = revpimodio2.RevPiNetIO(“ip-vom-revpi1“, autorefresh=True)
revpi2 = revpimodio2.RevPiNetIO(“ip-vom-revpi2“, autorefresh=True)

# Sollten an revpi1 und revpi2 doch mal Ausgänge kommen, könnten diese Zeilen wichtig sein bei Verbindungsverlust
revpi1.net_setdefaultvalues()
revpi2.net_setdefaultvalues()

# Alle Events registrieren mit dazugehörigen Funktionen

# Alle mainloops starten
revpi1.mainloop(blocking=False)
revpi2.mainloop(blocking=False)

revpi3.mainloop()

revpi1.disconnect()
revpi2.disconnect()

Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
Ricarda
Posts: 15
Joined: 20 Jan 2020, 14:23
Answers: 0

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by Ricarda »

Hallo Sven,

sorry für die späte Antwort. Also eigentlich hat sich das etwas vereinfacht, weil es nur noch 2 Core-Module sind. Ich versuch es, besser zu erklären, sorry, das ist etwas wirr geworden:
VerbindungSlaveMaster.png
VerbindungSlaveMaster.png (32.52 KiB) Viewed 7260 times
Der Slave-Core muss zwei analoge Eingänge auswerten, das kann über ein separates Programm auf dem Slave erfolgen. Das Ergebnis ist im Prinzip eine "Erlaubnis" oder "keine Erlaubnis", das True/False habe ich dann auf ein virtuelles Device geschrieben.
Auf dem Master läuft eine unendliche Schleife, die am Anfang immer wieder diesen Wert des virtuellen Devices (also Erlaubnis/keine Erlaubnis) abfragt. Wenn die Erlaubnis nicht mehr gegeben ist, stoppt die Anlage. Das Programm läuft aber natürlich weiter und fragt immer wieder nach der Erlaubnis. Wenn die Erlaubnis gegeben ist, werden erst die Eingänge, die direkt am Master hängen, abgefragt und ausgewertet. Bei einem Verbindungsabbruch müsste der Wert auch auf 0/ keine Erlaubnis gesetzt werden.

Kann ich das ggf. über setdefaultvalues erreichen?
Ein weiterer interessanter Verwendungszweck von virtuellen Devices ist die Speicherung von Variablen. Wenn man Variablen statt direkt in Pythonprogramm in einem virtuellen Device speichert, kann man mit RevPiPyControl natürlich immer drauf schauen und mit den Werten auch andere RevPis versorgen.
Tatsächlich speichere ich einige Variabeln (die im main-Programm "erstellt" werden auf einem Virtuellen Device auf dem Master, das klappt auch sehr gut).

Ich muss gestehen, dass ich mich mit events noch nicht weiter befasst habe, auch um mainloop bin ich bisher fast immer herum gekommen (mit der mainloop hab ich mich bisher nur mit tkinter befasst und da hab ich das auch nur so mittelmäßig verstanden :oops: ). Bisher lass ich da eine unendliche Schleife laufen, ist wahrscheinlich nicht das Schönste, was man machen kann.

Lieben Gruß

Ricarda
User avatar
RevPiModIO
KUNBUS
Posts: 322
Joined: 20 Jan 2017, 08:44
Answers: 0
Contact:

Re: Pi2Pi Communication - Automatisierung auf dem Wasser

Post by RevPiModIO »

Hi Ricarda!

Das klingt doch aber alles sehr solide! Du musst gar nix mit dem mainloop machen, das mit deiner "Endlosschleife" ist ja ne gängige Praxis und genau richtig! Wenn du das mit dem cycleloop von RevPiModIO machst, also den Inhalt deiner zyklischen Schleife in eine Funktion packen und die an .cycleloop übergeben, ist alles perfekt!

Der einmalige Aufruf von .net_setdefaultvalues() vor Eintritt in die Schleifen lässt RevPiPyLoad das komplette Device auf 0 setzen (bzw. piCtory defaults), wenn die Verbindung einen Fehler hat.

Nach deinem Bild vermute ich mal, dass das virtuelle Device mit dem Ergebnis auf dem Slave ist. Somit verbindet sich das Master-Programm mit dem Prozessabbild vom Slave, richtig?

Verstehe mich nicht falsch, du machst in der Hinsicht ja keine Fehler, ich denke nur grade drüber nach, was generell für solche Fälle die beste Variante ist. Ich würde das gerne als Tutorial auf meiner Seite veröffentlichen.

Ich habe es bis jetzt immer anders herum gemacht um den Master als reine Steuerung zu betreiben und habe die Slaves in die virtuellen Devices des Masters schreiben lassen. Das hat aber auch damit zu tun, dass ich als Slaves auch mal Raspberry Pis genommen habe oder ein Panel PC. Die haben ja kein Prozessabbild und auf denen läuft auch nicht RevPiPyLoad...
Du könntest also sogar noch eine Visualisierung oder n Monitoring machen...

Welchen Weg sollten wir gehen:
- Der Master hat in piCtory seine echte Hardware und ein vituelles Device pro Slave / Visualisierung.
- Der Master startet sein Programm (am besten mit RevPiPyLoad) und hat ein revpi = revpimodio2.RevPiModIO(autorefresh=True) für sein komplettes Prozessabbild
- Der Master ersetzt vor Eintritt in Schleifen die IOs der virtuellen Devices (also das ganze ".replace_io" Zeug) und bereitet so die gewollten Datentypen vor.
- Der Master exportiert diese ersetzten IOs mit Aufruf von .export_replaced_ios() (Einstellung von RevPiPyLoad richtig setzen)
- Der Master geht in den .cycleloop mit der Funktion, die deine zyklischen Aufgaben erledigt.

- Der Slave verwendet sein internes Prozessabbild
- Der Slave verbindet sich zu seinem virtuellen Device auf dem Master (master = revpimodio2.RevPiNetIODriver("ip-vom-master")
- Der Slave bekommt dafür automatisch die ersetzten IOs, man kann also direkt mit den .io.neuer_name arbeiten
- Der Slave geht in seinen .cycleloop und aktualisiert bei jedem Durchlauf die Daten auf dem virtuellen Device auf dem Master

Vorteil: Alle ersetzten IOs werden ausschließlich auf dem Master in dem Programm definiert und alle Anderen benutzen genau diese, so muss man die nicht doppelt pflegen und RevPiPyControl kann dir die sogar genau so anzeigen mit den Datentypen.

Es wäre cool, wenn wir den beschriebenen Weg zu einem Tutorial machen könnten! Dann hätten wir für die beschriebenen Punkte auch einen echten Feldversuch!

PS: Ich habe dir noch einen PN gesendet mit Kontaktdaten.

Gruß, Sven
python3-RevPiModIO - https://revpimodio.org/ || Der RevPi ist das Beste, was passieren konnte!
Post Reply