MQTT Subscribe und Publish in einem Skript

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Flo-Pro
User
Beiträge: 4
Registriert: Mittwoch 10. November 2021, 16:42

Hallo zusammen,

ich kenne mich mit MQTT und Python leider noch nicht all zu gut aus und habe deswegen eine Frage. Aktuell programmiere ich mit einem Dexter Industries und einem RPi3b ein autonomes Fahrzeug.

Ich bekomme per MQTT unterschiedliche Topics und kann je nach dem, unterschiedliche Motoren und Sensoren ansteuern. Ich würde nur gerne, dass das Transportsystem am Ende der Durchführung einer Aufgabe eine eigene Nachricht Published. Ich weiß leider nicht wie das geht und vielleicht kann mir jemand Hilfe bezüglich meines Codes geben, wie ich am besten eine Nachtricht publishen kann (siehe Ende des Codes)

Code: Alles auswählen

from __future__ import print_function
from __future__ import division

import time
import brickpi3
import paho.mqtt.client as mqtt

BP.brickpi3.BrickPi3()
BP.set_sensor_type(BP.Port_1, BP.SENSOR_TYPE.EV3_COLOR_REFLECTED)

MQTT_Server = "192.168.0.21"
MQTT_PATH = "/RoboticLabor/Lagerplaetze/#"

def on_connect(client, userdata, flags, rc):
	print("Connected")
	client.subscribe(MQTT_PATH)
	
def on_message(client, userdata, msg):
	print(msg.topic+"   "+str(msg.payload))
	Case = 0
	Reihe = 1
	Start = 0
	if str(msg.topic) ==  "/RobotikLabor/Lagerplaetze/Lagerplatz1" and str(msg.payload) == "false":
		print("Fahre zu Lagerplatz 1")
		Lagerspalte = 1
		Hoehe = 1
		Start = 1
	
	while Start == 1 and Case == 0: 
		try: 
			BP.set_sensor_type(BP.Port_1, BP.SENSOR_TYPE.EV3_COLOR_COLOR_COMPONENTS)
			time.sleep(0.02)
			Komponenten = BP.get_sensor(BP.PORT_1)
			Motorspeed = 80
			if Komponenten[0] > 80 and Komponenten[1] < 40 and Komponenten[2]  < 40: 
				BP.set_motor_dps(BP.PORT_B + BP.PORT_C, 0)
			else:
				if Komponenten[0] < 40:
					BP:set_motor_dps(BP.PORT_B, Motorspeed/2)		
					BP:set_motor_dps(BP.PORT_C, -Motorspeed)
				elif Komponenten[0] > 40 and Komponenten[0] < 150:
					BP:set_motor_dps(BP.PORT_B, -Motorspeed)		
					BP:set_motor_dps(BP.PORT_C, -Motorspeed)
				elif Komponenten[0] > 150:
					BP:set_motor_dps(BP.PORT_C, Motorspeed/2)		
					BP:set_motor_dps(BP.PORT_B, -Motorspeed)
		except KeyboardInterrupt:
					BP.reset_all()
					
# Hier soll dann eine Nachricht von dem Broker 192.168.0.21 mit dem Topic /RobotikLabor/Transportsysteme/TS1 versendet werden!!!				
Vielen Dank schon mal :)

Flo
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du bekommst als Teil den on_message-Callbacks ja den client. Da kannst du einfach wieder publish drauf aufrufen. Habe ich zB hier gemacht:

https://github.com/deets/beehive-monito ... ce.py#L170

Was natuerlich NICHT geht, ist deine while-Schleife. MQTT ist inhaerent Ereignis-basiert, dass heisst, dass es einen eigenen Mainloop hat, der darauf wartet, dass Nachrichten reinkommen. Und der darf nicht einfach aufgehalten werden, indem du da mehr oder minder lange (bis ewig) rum-schleifst.

Das musst du also sauber voneinander trennen. ZB durch Threading, oder du machst den gesamten Code Ereignisbasiert.
Flo-Pro
User
Beiträge: 4
Registriert: Mittwoch 10. November 2021, 16:42

Danke dir schon mal für deine Antwort. Werde ich morgen auf jeden Fall mal testen und Rückmeldung geben.

Habe leider nicht gewusst, dass Crossposting nicht so gerne gesehen ist. Es gibt aber den gleich Post dazu noch im Raspberry Forum:
https://forum-raspberrypi.de/forum/thre ... post511272
Flo-Pro
User
Beiträge: 4
Registriert: Mittwoch 10. November 2021, 16:42

__deets__ hat geschrieben: Mittwoch 1. Dezember 2021, 15:20 Du bekommst als Teil den on_message-Callbacks ja den client. Da kannst du einfach wieder publish drauf aufrufen. Habe ich zB hier gemacht:

https://github.com/deets/beehive-monito ... ce.py#L170

Was natuerlich NICHT geht, ist deine while-Schleife. MQTT ist inhaerent Ereignis-basiert, dass heisst, dass es einen eigenen Mainloop hat, der darauf wartet, dass Nachrichten reinkommen. Und der darf nicht einfach aufgehalten werden, indem du da mehr oder minder lange (bis ewig) rum-schleifst.

Das musst du also sauber voneinander trennen. ZB durch Threading, oder du machst den gesamten Code Ereignisbasiert.
Funktioniert das vom Code her nicht oder sollte man das einfach nicht machen? An sich ist es kein Problem, wenn mein Main Loop zum empfangen der Nachrichten während der while Schleife unterbrochen ist und die Schleife erstmal abgearbeitet wird, da ich erst wieder nach dieser Schleife neue Nachrichten empfagen muss und nicht währenddessen. Ich muss nur währenddessen Nachrichten versenden an den Broker, das sollte aber laut deiner Anmerkung weiter oben ja funktionieren.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

bitte nicht den Post davor voll zitieren, der steht da ja schon.

Und nein, das funktioniert im Zweifel nicht. Es kommt ein bisschen auf die Implementierung von paho an, aber MQTT versucht durchaus, Nachrichten robust zu liefern - Stichwort QOS. Das bedeutet, dass der mainloop eine noch nicht gesendete Nachricht wieder und wieder sendet. Dein Programm aber ansonsten weiterläuft.

Und auch in Empfangsrichtung kann es zu Problemen kommen. Denn dann lauscht ja niemand auf dem eingehenden Socket.

Und zu guter Letzt kann die Logik deines Programms sich entwickeln, und diese fragile Konstruktion reicht nicht mehr, weil plötzlich doch eine Nachricht Einfluss auf den laufenden Prozess nehmen soll.
Flo-Pro
User
Beiträge: 4
Registriert: Mittwoch 10. November 2021, 16:42

Okay verstehe. Ich hab aber an sich eh nicht vor, den Callback in eine while Schleife zu schreiben. Wenn dann wird die Callback Nachricht, wie bei dir in deinem oben genannten Code, wenn ich es richtig verstanden habe, nur einmal pro Mainloop gesendet.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich weiss nicht, was du mit "Callback in eine while Schleife schreiben" meinst. Auch "einmal pro Mainloop" macht keinen Sinn.
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Das hatte Flo-Pro doch bereits selbst verlinkt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

Sorry, das habe ich übersehen.
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten