A PWM object already exists

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
lb175
User
Beiträge: 1
Registriert: Montag 30. September 2019, 16:58

Guten Abend zusammen,

bin neu hier, also seid bitte nicht zu hart zu mir, ich lerne noch :D
Ich arbeite momentan im Rahmen eines Abschlussprojektes mit Hilfe eines Raspberry Pi's und Python an einer LED-Steuerung.
Teil dieser Steuerung ist unter Anderem das Regeln der Helligkeit der LEDs abhängig von der Umgebungshelligkeit.
Wenn das Programm irgendwann fertig ist, soll man die Leds aber auch manuell ansteuern können.
Sobald das Tool läuft, kann ich die Werte der RGB's eintippen und auch schalten, allerdings beim nächsten Versuch die Leds anzusteuern bekomme ich die Meldung " A PWM object already exists for this GPIO channel"
Nach mehrmaligem Betätigen lassen sich die leds dann aber wieder schalten und danach kommt erneut diese Meldung. Hat jemand eine Idee wie ich das umgehen kann?
Und könnte mir noch jemand einen Tipp geben, wie ich meinen Thread der in dem Programm läuft beenden kann?

Code: Alles auswählen

from tkinter import *
import RPi.GPIO as GPIO
import threading
import spidev
import threading

spi = spidev.SpiDev()      # SPI-Bus initialisieren
spi.open(0,0)              # SPI Bus 0, Client 0 öffnen
spi.max_speed_hz=1000000 
import time

def readMCP3008(channel):
        adc=spi.xfer2([1,(8+channel)<<4,0])
        wert = ((adc[1]&3) << 8) + adc[2]
        return wert

GPIO.setwarnings(False)


P_RED = 16
P_GREEN = 13
P_BLUE = 26
fPWM = 50


def sensor_ein():
        my_thread = threading.Thread(target=regelung_ein)
        my_thread.start()


def setup():
        GPIO.setwarnings(False)
        global pwmR, pwmG, pwmB
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(P_RED, GPIO.OUT)
        GPIO.setup(P_GREEN, GPIO.OUT)
        GPIO.setup(P_BLUE, GPIO.OUT)
        pwmR = GPIO.PWM(P_RED, fPWM)
        pwmG = GPIO.PWM(P_GREEN, fPWM)
        pwmB = GPIO.PWM(P_BLUE, fPWM)
        pwmR.start(0)
        pwmG.start(0)
        pwmB.start(0)

        
def setColor(r, g, b):

        pwmR.ChangeDutyCycle(int(r / 255 * 100))
        pwmG.ChangeDutyCycle(int(g / 255 * 100))
        pwmB.ChangeDutyCycle(int(b / 255 * 100))


def led_ein():
        GPIO.setwarnings(False)
        RHell = int(entryRHell.get())
        GHell = int(entryGHell.get())
        BHell = int(entryBHell.get())
        r = RHell
        g = GHell
        b = BHell
        setup()
        setColor(r, g, b )
        
        

def alle_aus():
       GPIO.setwarnings(False)
       setup()
       GPIO.output(P_RED, GPIO.LOW)
       GPIO.output(P_GREEN, GPIO.LOW)
       GPIO.output(P_BLUE, GPIO.LOW)
       
       
def regelung_ein():
        print ("starting")  
        setup()
        while True:
                v=readMCP3008(0)
        
        if (v >550):
                r = 0
                g = 0
                b = 0
                print (r, g, b)
                setColor(r, g, b)
                  

        if (v<550 and v>525):
                  r = 11
                  g = 11
                  b = 11
                  print (r, g, b)
                  setColor(r, g, b)
                  

        if (v<525 and v>500):
                  r = 22
                  g = 22
                  b = 22
                  print (r, g, b)
                  setColor(r, g, b)
                  
        if (v<500 and v>475):
                  r = 33
                  g = 33
                  b = 33
                  print (r, g, b)
                  setColor(r, g, b)
                 

        if (v<475 and v>450):
                  r = 44
                  g = 44
                  b = 44
                  print (r, g, b)
                  setColor(r, g, b)
                  
                  
        if (v<450 and v>425):
                  r = 55
                  g = 55
                  b = 55
                  print (r, g, b)
                  setColor(r, g, b)
                  

        if (v<425 and v>400):
                  r = 66
                  g = 66
                  b = 66
                  print (r, g, b)
                  setColor(r, g, b)
                  

        if (v<400 and v>375):
                  r = 77
                  g = 77
                  b = 77
                  print (r, g, b)
                  setColor(r, g, b)
                  
        
        if (v<175 and v>150):
                  r = 88
                  g = 88
                  b = 88
                  print (r, g, b)
                  setColor(r, g, b)

        if (v<350 and v>325):
                      r = 99
                      g = 99
                      b = 99
                      print (r, g, b)
                      setColor(r, g, b)
                  
        if (v<325 and v>300):
                      r = 110
                      g = 110
                      b=  110
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<300 and v>275):
                      r = 121
                      g = 121
                      b = 121
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<275 and v>250):
                      r = 132
                      g = 132
                      b = 132
                      print (r, g, b)
                      setColor(r, g, b)
                
        if (v<250 and v>225):
                      r = 143
                      g = 143
                      b = 143
                      print (r, g, b)
                      setColor(r, g, b)
                      time.sleep(1)

        if (v<225 and v>200):
                      r = 154
                      g = 154
                      b = 154
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<200 and v>175):
                      r = 165
                      g = 165
                      b = 165
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<175 and v>150):
                      r = 176
                      g = 176
                      b = 176
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<150 and v>125):
                      r = 187
                      g = 187
                      b = 187
                      print (r, g, b)
                      setColor(r, g, b)
                 

        if (v<125 and v>100):
                      r = 198
                      g = 198
                      b = 198
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<100 and v>75):
                      r = 209
                      g = 209
                      b = 209
                      print (r, g, b)
                      setColor(r, g, b)
                  
                  
        if (v<75 and v>50):
                      r = 220
                      g = 220
                      b = 220
                      print (r, g, b)
                      setColor(r, g, b)
                  

        if (v<50 and v>25):
                      r = 231
                      g = 231
                      b = 231
                      print (r, g, b)
                      setColor(r, g, b)
                


        if (v<25 and v>0):
                      r = 242
                      g = 242
                      b = 242
                      print (r, g, b)
                      setColor(r, g, b)


tkFenster = Tk()
tkFenster.title('LightBox')
tkFenster.geometry('350x145')

buttonEIN = Button(master=tkFenster, bg='green', text='EIN', command=led_ein)
buttonEIN.place(x=0, y=90, width=50, height=30,)
buttonSensor = Button(master=tkFenster, text='Sensorik', command=sensor_ein)
buttonSensor.place(x=110, y=90, width=50, height=30,)
buttonAUS = Button(master=tkFenster, bg='red', text='AUS', command=alle_aus)
buttonAUS.place(x=55, y=90, width=50, height=30,)
labelROT = Label(master=tkFenster, text='ROT', fg='red', font=('Arial', 16))
labelROT.place(x=5, y=40, width=50,height=20)
labelGRUEN = Label(master=tkFenster, text='GRUEN', fg='green', font=('Arial', 16))
labelGRUEN.place(x=80, y=40, width=70,height=27)
labelBLAU = Label(master=tkFenster, text='BLAU', fg='blue', font=('Arial', 16))
labelBLAU.place(x=155, y=40, width=70,height=27)
entryRHell = Entry(master=tkFenster, bg='white')
entryRHell.place(x=5, y=65, width=70, height=20)
entryGHell = Entry(master=tkFenster, bg='white')
entryGHell.place(x=80, y=65, width=70, height=20)
entryBHell = Entry(master=tkFenster, bg='white')
entryBHell.place(x=155, y=65, width=77, height=20)



tkFenster.mainloop()



    



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

Du rufst setup ja auch bei jeder sich bietenden Gelegenheit auf. Da passieren Sachen dann halt mehrfach. Gleiches gilt auch fuer das abschalten der Warnungen. Programmieren ist nicht Essen - da kann man mit dem grosszuegigen Einsatz des Salzstreuers gelegentlich mal was verbessern. Aber beim Programmieren nicht.

Und dein Vorgehen, durch den Knopfdruck einen Thread hochzufeuern, ist auch zum scheitern verurteilt. Denn damit kann ich ja x-mal auf den Knopf druecken, und habe x Threads, die sich auf ihren LEDs rumtreten. Das muss *EIN* Thread sein, der zu Beginn des Programms (aber nach dem EINMALIGEN Aufruf von setup()) gestartet wird, und endlos laeuft. Und der bekommt dann seine Arbeitsauftraege in Form einer Queue reingereicht. Und macht dann jeweils was gefragt ist. So vermeidest du auch, dass verschiedene gleichzeitige Versuche auf den LEDs zu arbeiten stattfinden.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Allgemeine Anmerkungen zum Code:
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht 8.
Keine *-Importe, da holt man sich unkontrolliert Namen in den eigenen Namensraum. Tkinter wird üblicherweise als `import tkinter as tk` importiert und alle Namen daraus per tk.xyz angesprochen.
Das `as` bei `import RPi.GPIO` ist unnötig, da das Modul ja gar nicht umbenannt wird (wie bei tk).
Der Import von threading steht zweimal da, `import time` steht zu weit unten.
Auf Modulebene sollte sowieso kein ausführbarer Code stehen, die spi-Zeilen gehören in `setup`, das dann die ganzen erzeugten Objekte als Rückgabewert haben sollte, und nicht per `global`. Vergiß gleich, dass es `global` überhaupt gibt, das hat in einem sauberen Programm nichts verloren.
Warnings sind dazu da, dass man sie behebt, nicht dass man sie ignoriert.
setColor sollte nach Namenskonvention set_color heißen, und braucht als Parameter noch pwmR, pwmG und pwmB (auch alle falsch geschrieben: pwm_red, pwm_green, pwm_blue).
In led_ein ist sowohl das setwarnings falsch, als auch der setup Aufruf, led_ein braucht noch zusätzlich als Parameter pwm_red, pwm_green, pwm_blue und entry_red_brightness, entry_blue_brightness und entry_green_brightness (Namenskonvention beachten und nicht deutsch und englisch mischen).
Du merkst, die Parameterliste wird immer länger. Daher ist es sinnvoll, bei GUIs Klassen zu definieren, um alle Zustände zu kapseln.
Warum nennst Du die lokalen Variablen RHell in r, GHell in g und BHell in b um? Warum nutzt Du nicht gleich das eine oder andere?
Für alle_aus gilt im wesentlichen das selbe.
In regelung_ein wird die while-Schleife nie verlassen, macht aber auch nichts, da ist offensichtlich die Einrückung falsch.
Die Klammern um die if-Bedingungen sind überflüssig und können weg.
Da sich die Bedingungen gegenseitig ausschließen, solltest Du mit elif arbeiten, und da die letzten zwei Zeilen in jedem if-Block identisch sind, können sie auch alle nach der if-elif-Kaskade stehen.
Alles ab tkFenster gehört in eine Funktion, die man üblicherweise main nennt, und die zum Schluß als einziges aufgerufen wird.
`place` sollte man nicht verwenden, sondern hier wahrscheinlich grid.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@lb175: Bei den ganzen Vergleichen mit dem ``and`` kann man auch verkettete Vergleiche wie in der Mathematik üblich schreiben, also statt ``a < x and x > b`` besser ``b <= x < a``.

Wobei ich mich frage ob man den Grauwert nicht einfach aus dem gemessenen Wert *berechnen* kann, statt da so elend viel Code mit vergleichen zu schreiben.

Einiges von den Bemerkungen aus den vorherigen Beiträgen umgesetzt:

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import threading
import tkinter as tk

from RPi import GPIO
import spidev

RED_PIN = 16
GREEN_PIN = 13
BLUE_PIN = 26
PWM_FREQUENCY = 50


def read_mcp3008(spi, channel):
    adc = spi.xfer2([1, (8 + channel) << 4, 0])
    return ((adc[1] & 3) << 8) + adc[2]


def setup():
    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.max_speed_hz = 1000000

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(RED_PIN, GPIO.OUT)
    GPIO.setup(GREEN_PIN, GPIO.OUT)
    GPIO.setup(BLUE_PIN, GPIO.OUT)
    red_pwm = GPIO.PWM(RED_PIN, PWM_FREQUENCY)
    green_pwm = GPIO.PWM(GREEN_PIN, PWM_FREQUENCY)
    blue_pwm = GPIO.PWM(BLUE_PIN, PWM_FREQUENCY)
    red_pwm.start(0)
    green_pwm.start(0)
    blue_pwm.start(0)
    return spi, red_pwm, green_pwm, blue_pwm


def set_color(red_pwm, green_pwm, blue_pwm, red, green, blue):
    red_pwm.ChangeDutyCycle(int(red / 255 * 100))
    green_pwm.ChangeDutyCycle(int(green / 255 * 100))
    blue_pwm.ChangeDutyCycle(int(blue / 255 * 100))


def led_ein(red_pwm, green_pwm, blue_pwm, red_entry, green_entry, blue_entry):
    set_color(
        red_pwm,
        green_pwm,
        blue_pwm,
        int(red_entry.get()),
        int(green_entry.get()),
        int(blue_entry.get()),
    )


def alle_aus():
    GPIO.output(RED_PIN, GPIO.LOW)
    GPIO.output(GREEN_PIN, GPIO.LOW)
    GPIO.output(BLUE_PIN, GPIO.LOW)


def regelung_ein(spi, red_pwm, green_pwm, blue_pwm):
    print("starting")
    while True:
        value = read_mcp3008(spi, 0)
        #
        # TODO Can this be *calculated* instead‽
        #
        if value > 550:
            red = green = blue = 0
        elif 525 <= value < 550:
            red = green = blue = 11
        elif 500 <= value < 525:
            red = green = blue = 22
        elif 475 <= value < 500:
            red = green = blue = 33
        elif 450 <= value < 475:
            red = green = blue = 44
        elif 425 <= value < 450:
            red = green = blue = 55
        elif 400 <= value < 425:
            red = green = blue = 66
        elif 375 <= value < 400:
            red = green = blue = 77
        elif 150 <= value < 175:
            red = green = blue = 88
        elif 325 <= value < 350:
            red = green = blue = 99
        elif 300 <= value < 325:
            red = green = blue = 110
        elif 275 <= value < 300:
            red = green = blue = 121
        elif 250 <= value < 275:
            red = green = blue = 132
        elif 225 <= value < 250:
            red = green = blue = 143
        elif 200 <= value < 225:
            red = green = blue = 154
        elif 175 <= value < 200:
            red = green = blue = 165
        elif 150 <= value < 175:
            red = green = blue = 176
        elif 125 <= value < 150:
            red = green = blue = 187
        elif 100 <= value < 125:
            red = green = blue = 198
        elif 75 <= value < 100:
            red = green = blue = 209
        elif 50 <= value < 75:
            red = green = blue = 220
        elif 25 <= value < 50:
            red = green = blue = 231
        elif 0 <= value < 25:
            red = green = blue = 242

        print(red, green, blue)
        set_color(red_pwm, green_pwm, blue_pwm, red, green, blue)


def sensor_ein(spi, red_pwm, green_pwm, blue_pwm):
    #
    # FIXME Just start one thread at program start and communicate over a
    #   `queue` with it.
    #
    threading.Thread(
        target=regelung_ein,
        args=(spi, red_pwm, green_pwm, blue_pwm),
        daemon=True,
    ).start()


def main():
    spi, red_pwm, green_pwm, blue_pwm = setup()

    root = tk.Tk()
    root.title("LightBox")

    for i, (text, color) in enumerate(
        [("ROT", "red"), ("GRÜN", "green"), ("BLAU", "blue")]
    ):
        tk.Label(root, text=text, fg=color, font=("Arial", 16)).grid(
            row=0, column=i
        )

    red_entry = tk.Entry(root, bg="white")
    red_entry.grid(row=1, column=0)
    green_entry = tk.Entry(root, bg="white")
    green_entry.grid(row=1, column=1)
    blue_entry = tk.Entry(root, bg="white")
    blue_entry.grid(row=1, column=2)

    tk.Button(
        root,
        bg="green",
        text="EIN",
        command=partial(
            led_ein,
            red_pwm,
            green_pwm,
            blue_pwm,
            red_entry,
            green_entry,
            blue_entry,
        ),
    ).grid(row=2, column=0)
    tk.Button(root, bg="red", text="AUS", command=alle_aus).grid(
        row=2, column=1
    )
    tk.Button(
        root,
        text="Sensorik",
        command=partial(sensor_ein, spi, red_pwm, green_pwm, blue_pwm),
    ).grid(row=2, column=2)

    root.mainloop()


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man die Tippfehler und die Fälle, in denen es zu einem UnboundLocalError kommt, ignoriert, ist das einfach:

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import threading
import tkinter as tk

from RPi import GPIO
import spidev

RGB_PINS = [16, 13, 26]
PWM_FREQUENCY = 50


def read_mcp3008(spi, channel):
    adc = spi.xfer2([1, (8 + channel) << 4, 0])
    return ((adc[1] & 3) << 8) + adc[2]


def setup():
    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.max_speed_hz = 1000000

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(RGB_PINS, GPIO.OUT)
    pwms = []
    for pin in RGB_PINS:
        pwm = GPIO.PWM(pin, PWM_FREQUENCY)
        pwm.start(0)
        pwms.append(pwm)
    return spi, pwms


def set_color(pwms, colors):
    for pwm, c in zip(pwms, colors):
        pwm.ChangeDutyCycle(c * 100 // 255)


def led_ein(pwms, color_entries):
    set_color(pwms, [int(e.get()) for e in color_entries])


def alle_aus():
    GPIO.output(RGB_PINS, GPIO.LOW)


def regelung_ein(spi, pwms):
    print("starting")
    while True:
        value = read_mcp3008(spi, 0)
        red = green = blue = 11 * (22 - value // 25)
        print(red, green, blue)
        set_color(pwms, (red, green, blue))


def sensor_ein(spi, pwms):
    threading.Thread(
        target=regelung_ein,
        args=(spi, pwms),
        daemon=True,
    ).start()


def main():
    spi, pwms = setup()

    root = tk.Tk()
    root.title("LightBox")

    color_entries = []
    for i, (text, color) in enumerate(
        [("ROT", "red"), ("GRÜN", "green"), ("BLAU", "blue")]
    ):
        tk.Label(root, text=text, fg=color, font=("Arial", 16)).grid(
            row=0, column=i
        )
        entry = tk.Entry(root, bg="white")
        entry.grid(row=1, column=i)
        color_entries.append(entry)

    tk.Button(
        root,
        bg="green",
        text="EIN",
        command=partial(led_ein, pwms, color_entries),
    ).grid(row=2, column=0)
    tk.Button(root, bg="red", text="AUS", command=alle_aus).grid(
        row=2, column=1
    )
    tk.Button(
        root,
        text="Sensorik",
        command=partial(sensor_ein, spi, pwms),
    ).grid(row=2, column=2)

    root.mainloop()


if __name__ == "__main__":
    main()
Antworten