MicroPython Threads

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Hallo, liebes Forum!
Ich bin ein Python Einsteiger, habe mich mit dem Raspberry Pi Pico und MicroPython befasst und bin jetzt auf ein Problem gestoßen, an dem ich nicht weiter komme.
Ich wollte mithilfe Threads 2 Sachen (messung() und giessen()) parallel laufen lassen, damit ich bei giessen() höhere sleep Zeiten einstellen kann , ohne dass messung() unterbrochen wird.
Leider hat das nicht so geklappt, wie ich mir das vorgestellt habe.
Wie gesagt bin ich ein Einsteiger...

from machine import I2C, Pin, ADC
from time import sleep, sleep_ms
from machine_i2c_lcd import I2cLcd
from dht import DHT11, InvalidChecksum
import _thread

i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000)

i2c_scan=i2c.scan()[0]
i2c_scan_hex=hex(i2c_scan)

I2C_ADDR = i2c_scan

lcd = I2cLcd(i2c, I2C_ADDR, 2, 16)

DHTpin = Pin(15, Pin.OUT, Pin.PULL_DOWN)

led = Pin(11, Pin.OUT)

motor = Pin(9, Pin.OUT)

adc = ADC(Pin(28))

lock = _thread.allocate_lock()

def error():
print("Error")
led.value(1)
sleep(1)
led.value(0)
sleep(1)
led.value(1)
sleep(1)
led.value(0)
sleep(1)

def messung():
while True:
sensor = DHT11(DHTpin)
t = (sensor.temperature)
h = (sensor.humidity)
feuchte = (float(-adc.read_u16()/655+100))#
lcd.hide_cursor()
lcd.move_to(0,0)
lcd.putstr("Temp: " + str(t) + " C")
lcd.move_to(0,1)
lcd.putstr("Luftf.: " + str(h) + " %")
sleep(5)
lcd.hide_cursor()
lcd.move_to(0,0)
lcd.putstr("Temp: " + str(t) + " C")
lcd.move_to(0,1)
lcd.putstr("Giessen: " + str("%.1f" % (feuchte)) + " ")
sleep(5)

def giessen():
while True:
print(int(-adc.read_u16()/655.35+100))
led.value(0)
feuchte = (int(-adc.read_u16()/655.35+100))
if 1 < feuchte < 20:
sleep(5)
motor.value(1)
sleep(7)
motor.value(0)
elif feuchte < 1:
motor.value(0)
error()
else:
motor.value(0)

_thread.start_new_thread(messung,())
_thread.start_new_thread(giessen,())


Ich wäre wirklich sehr dankbar, wenn man mir helfen könnte.
MfG Fabi
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt das mit dem experimentellen und nicht wirklich gut unterstuetzten Thread-Modul zu machen, musst du dein Programm einfach so umschreiben, dass es keine sleeps mehr enthaelt, und einfach beide Aufgaben bestaendig nacheinander macht. Alternativ kannst du uasyncio verwenden, damit bleibst du bei deinem quasi-parallelen Design. Aber ohne eben echte und schlechte Threads. https://docs.micropython.org/en/latest/ ... yncio.html
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 4 und mal 6 oder 8.
Variablennamen werden komplett klein geschrieben.
Das Lesen der Feuchte steht drei mal im Code, das sollte es nur einmal geben.

Microprozessor-Programmierung ist ganz anders, als bei großen Maschinen.
Man hat meist einen Loop, aus dem heraus alles gesteuert wird:

Code: Alles auswählen

from time sleep_ms, ticks_ms, ticks_add, ticks_diff
from machine import I2C, Pin, ADC
from machine_i2c_lcd import I2cLcd
from dht import DHT11, InvalidChecksum

def initialize():
    i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000)
    i2c_addr = i2c.scan()[0]
    lcd = I2cLcd(i2c, i2c_addr, 2, 16)
    sensor = DHT11(Pin(15, Pin.OUT, Pin.PULL_DOWN))
    led = Pin(11, Pin.OUT)
    motor = Pin(9, Pin.OUT)
    adc = ADC(Pin(28))
    led.value(0)
    return lcd, sensor, led, motor, adc


def get_feuchte(adc):
    return 100 - adc.read_u16() / 655.


def update_display(display_state, lcd, feuchte):
    if display_state == 0 or display_state == 5
        temperature = sensor.temperature
        humidity = sensor.humidity
        lcd.hide_cursor()
        lcd.move_to(0,0)
        lcd.putstr("Temp:    %s C" % temperature)
        lcd.move_to(0,1)
        if display_state == 0:
            lcd.putstr("Luftf.:  %s %" % humidity)
        else:
            lcd.putstr("Giessen:  %.1f" % feuchte)
    return (display_state + 1) % 10


def update_motor(motor_state, motor, led, feuchte):
    if motor_state == 0:
        if 1 < feuchte < 20:
            # start motor
            return 1
        elif feuchte < 1:
            # special error state
            led.value(1)
            return 100
        return 0
    elif motor_state < 5:
        return motor_state + 1
    elif motor_state == 5:
        motor.value(1)
        return motor_state + 1
    elif motor_state < 11:
        return motor_state + 1
    elif motor_state == 12:
        motor.value(0)
        return 0
    elif motor_state >= 100:
        # error
        led.value(motor_state % 2)
        if motor_state == 104:
            return 0
        return motor_state + 1


def main():
    lcd, sensor, led, motor, adc = initialize()
    clock = ticks_ms()
    motor_state = 0
    display_state = 0
    while True:
        feuchte = get_feuchte(adc)

        display_state = update_display(display_state, lcd, feuchte)
        motor_state = update_motor(motor_state, motor, led, feuchte)

        clock = ticks_add(clock, 1000)
        diff = ticks_diff(clock, time.ticks_ms())
        if diff > 0:
            sleep_ms(diff)

main()
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Sirius3 hat geschrieben: Sonntag 4. Juli 2021, 14:55 Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 4 und mal 6 oder 8.
Variablennamen werden komplett klein geschrieben.
Das Lesen der Feuchte steht drei mal im Code, das sollte es nur einmal geben.

Microprozessor-Programmierung ist ganz anders, als bei großen Maschinen.
Man hat meist einen Loop, aus dem heraus alles gesteuert wird.
Vielen Dank, dass sie mir den kompletten Code verbessert geschickt haben(!), nur kann ich leider nicht viel damit anfangen und funktionieren tut es leider auch nicht.
Ich habe es einfach copy/paste übertragen, deshalb sind die Einrückungen anscheinend verloren gegangen aber danke für den Hinweis!
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

__deets__ hat geschrieben: Sonntag 4. Juli 2021, 13:38 Statt das mit dem experimentellen und nicht wirklich gut unterstuetzten Thread-Modul zu machen, musst du dein Programm einfach so umschreiben, dass es keine sleeps mehr enthaelt, und einfach beide Aufgaben bestaendig nacheinander macht. Alternativ kannst du uasyncio verwenden, damit bleibst du bei deinem quasi-parallelen Design. Aber ohne eben echte und schlechte Threads. https://docs.micropython.org/en/latest/ ... yncio.html
Werde mich wohl mal daran orientieren und versuchen etwas auf die Beine zu stellen:
Danke für die schnelle Antwort!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich habe ja Deine Hardware nicht hier. Also wäre es schon hilfreich, nicht einfach zu schrieben, dass es nicht geht, sondern was nicht geht.
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

....def update_display(display_state, lcd, feuchte):
........ if display_state == 0 or display_state == 5
24 .......temperature = sensor.temperature
............humidity = sensor.humidity
............lcd.hide_cursor()
............lcd.move_to(0,0)
............lcd.putstr("Temp: %s C" % temperature)
............lcd.move_to(0,1)
............if display_state == 0:
................lcd.putstr("Luftf.: %s %" % humidity)
............else:
................lcd.putstr("Giessen: %.1f" % feuchte)
........return (display_state + 1) % 10

Traceback (most recent call last):
File "<stdin>", line 24
SyntaxError: invalid syntax

also das ist der Fehler.
Ich habe leider keine Ahnung.
Hardware ist der Raspberry Pi Pico mit einem DHT11, einem LCD Display und einem Feuchtigkeitssensor.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Was sollen denn die vielen Punkte? Code steckt man hier im Forum in Code-Tags, so ist Dein Code erst recht nicht mehr lesbar.
In der Zeile davor fehlt ein Doppelpunkt.
Und 7 Zeilen später fehlt ein %:

Code: Alles auswählen

def update_display(display_state, lcd, feuchte):
    if display_state == 0 or display_state == 5:
        temperature = sensor.temperature
        humidity = sensor.humidity
        lcd.hide_cursor()
        lcd.move_to(0,0)
        lcd.putstr("Temp:    %s C" % temperature)
        lcd.move_to(0,1)
        if display_state == 0:
            lcd.putstr("Luftf.:  %s %%" % humidity)
        else:
            lcd.putstr("Giessen:  %.1f" % feuchte)
    return (display_state + 1) % 10
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Sirius3 hat geschrieben: Sonntag 4. Juli 2021, 17:59 Was sollen denn die vielen Punkte? Code steckt man hier im Forum in Code-Tags, so ist Dein Code erst recht nicht mehr lesbar.
In der Zeile davor fehlt ein Doppelpunkt.
Und 7 Zeilen später fehlt ein %:
Die Punkte hab ich nur gemacht, dass Sie sich nicht mehr über das Einrücken beschweren, da ich nicht weiss wie man code importiert, sonst habe ich bis auf das import in der 1. Zeile alles von Ihnen übernommen.
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Traceback (most recent call last):
File "<stdin>", line 81, in <module>
File "<stdin>", line 73, in main
File "<stdin>", line 24, in update_display
NameError: name 'sensor' isn't defined

Habe schon etwas versucht aber ich bekomme es nicht hin.
Wie gesagt komme ich mit Ihrer Version nicht so gut zurecht.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das sind wirklich triviale Fehler, Du mußt `sensor` einfach als zusützlichen Parameter an `update_display` übergeben.
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Sirius3 hat geschrieben: Sonntag 4. Juli 2021, 18:13 Das sind wirklich triviale Fehler, Du mußt `sensor` einfach als zusützlichen Parameter an `update_display` übergeben.
Ok ich habe davor nur sensor = DHT11(DHTpin) übergeben und jetzt komplett und es funktioniert!
Vielen Dank!
Sleep kann ich jetzt beim Motor nicht einbauen, oder?(ohne, dass die Messung anhält)
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Was ich Ihnen vorhin blöderweise noch verschwiegen habe ist , dass es sich um eine Pflanze und eine Pumpe handelt und bis das Wasser den Fühler erreicht, die Pumpe die Pflanze ersäuft,
Deswegen brauch ich eine bestimmte Laufzeit der Pumpe und am besten noch eine Sperrzeit von ein paar Stunden/Minuten.
Dafür wollte ich einen Thread benutzen um die Messung bei der Sperrzeit der Pumpe weiterlaufen zu lassen.
Kann ich das mit Ihrem verbesserten Code auch erreichen?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Natürlich geht das. Dafür gibt es ja die Counter, motor_state. Das könnte man noch entkoppeln, in einen wait-Counter und einen getrennten State.
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Sirius3 hat geschrieben: Sonntag 4. Juli 2021, 18:45 Natürlich geht das. Dafür gibt es ja die Counter, motor_state. Das könnte man noch entkoppeln, in einen wait-Counter und einen getrennten State.
Wie würde das ungefähr ausschauen?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wo kommst Du konkret nicht weiter?
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Sirius3 hat geschrieben: Sonntag 4. Juli 2021, 18:45 Natürlich geht das. Dafür gibt es ja die Counter, motor_state. Das könnte man noch entkoppeln, in einen wait-Counter und einen getrennten State.
Wie das funktioniert, was Sie geschrieben haben.
Ich habe jetzt ewig auf die Antwort gewartet, ohne zu merken, dass sie auf der 2. Seite ist. :' D
Ich bin sehr dankbar für Ihre schnellen Antworten!
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

@T4m4go hast du den Code mal erfolgreich laufen lassen? Hast du gesehen das in Zeile 1 noch ein 'import' fehlt?
Wenn du die Laufzeit verändern willst, zeigst du hier am besten was du versucht hast oder was du genau nicht verstehst.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
T4m4go
User
Beiträge: 38
Registriert: Samstag 3. Juli 2021, 16:54

Dennis89 hat geschrieben: Sonntag 4. Juli 2021, 20:19 Hallo,

@T4m4go hast du den Code mal erfolgreich laufen lassen? Hast du gesehen das in Zeile 1 noch ein 'import' fehlt?
Wenn du die Laufzeit verändern willst, zeigst du hier am besten was du versucht hast oder was du genau nicht verstehst.

Grüße
Dennis
Hab ich schon beim 1. mal ausgebessert.
Antworten