Forum: Mikrocontroller und Digitale Elektronik erster µPython Versuch - Frage zu Definition von Variablen


von Kolja L. (kolja82)


Lesenswert?

Hallo

Ich habe es getan!
Seit ein paar Stunden läuft auf meinem ESP8266 Micropyhon.
Kleiner Hinweis: die IDE Thonny hat mir dem Umstieg von der Arduino Welt 
recht einfach gemacht ;-)
Das Tollste: der Code muss nicht mehr compilieren
Damit ist eine Änderung nicht erst nach (gefühlten) 60 Sekunden,
sondern quasi sofort (gefühlt 3 Sekunden) auf dem Board sichtbar.
Großartig!

Nachteil 1: Python ist als Skriptsprache deutlich langsamer

Nachteil 2: Python ist recht neu für mich und (obwohl oft als 
Einsteigersprache genannt) einfach anders als das Arduino C++

Jetzt zu meinem aktuellen Problem:

Ich möchte gerne eine Funktion aufrufen, welche meine WS2812 LEDs einen 
Farbverlauf (HSV) durchgehen lässt.

Bei jedem Aufruf soll die erste Stelle um 0.1 erhöht werden.
1
from machine import I2C, Pin
2
import time
3
import utime 
4
import machine, neopixel
5
6
np = neopixel.NeoPixel(machine.Pin(13), 16)
7
i2c = I2C(scl=Pin(5), sda=Pin(4)) 
8
9
# HSV values in [0..1]  returns (r, g, b) values from 0 to 255
10
def hsv_to_rgb(h, s, v):
11
    h_i = int((h*6))
12
    f = h*6 - h_i
13
    p = v * (1 - s)
14
    q = v * (1 - f*s)
15
    t = v * (1 - (1 - f) * s)
16
    if h_i==0: r, g, b = v, t, p
17
    if h_i==1: r, g, b = q, v, p
18
    if h_i==2: r, g, b = p, v, t
19
    if h_i==3: r, g, b = p, q, v
20
    if h_i==4: r, g, b = t, p, v
21
    if h_i==5: r, g, b = v, p, q
22
    return (int(r*255), int(g*255), int(b*255))
23
24
25
def led_verlauf():
26
    for j in range(0, 2):
27
        np[j] = hsv_to_rgb(1, 0.9, 0.21) 
28
    np.write() 
29
    print(k)
30
    
31
    
32
after_now = utime.ticks_ms()
33
while True:
34
    now = utime.ticks_ms()
35
    if utime.ticks_diff(now, after_now) > 100:
36
        led_verlauf()        
37
        after_now = now
Leider bekomme ich eine Felhermeldung angezeigt, die ich nicht 
nachvollziehen kann:

NameError: local variable referenced before assignment

Bezogen auf die letzte Zeile der hsv_to_rgb() Funktion.

Auf sich alleine gestellt, also nur mit hsv_to_rgb(1,1,1) funktioniert 
es aber wie es soll.

Bitte seht mir nach, wenn ich gerade den allerdümmsten Anfängerfehler 
mache,
es ist mein allererste Fehler mit dieser Sprache.

Danke und Gruß

Kolja

von Daniel (Gast)


Lesenswert?

r,b,g ist undefiniert, wenn kein if zutrifft. Entweder die Variablen 
vorher einen Wert zuweisen oder ein else Statement programieren.

von Chris (Gast)


Lesenswert?

Scope. r, g und b existieren nicht auf dieser Ebene.

Aber wenn das mal der einzige Fehler wäre..

von Karl (Gast)


Lesenswert?

Du schaffst es tatsächlich einen Python-Code so unverständlich wie eine 
C-Code zu machen.

Abgesehen davon gibt es das schon eingebaut:
https://docs.python.org/2/library/colorsys.html

von Kolja L. (kolja82)


Lesenswert?

Karl schrieb:
> Du schaffst es tatsächlich einen Python-Code so unverständlich wie eine
> C-Code zu machen.

Das wundert jetzt hoffentlich keinen...

Karl schrieb:
> Abgesehen davon gibt es das schon eingebaut:
> https://docs.python.org/2/library/colorsys.html

Leider nicht für / in Micropython

Chris schrieb:
> Aber wenn das mal der einzige Fehler wäre..

Sag mir bitte welche, Danke

Daniel schrieb:
> r,b,g ist undefiniert

Wie und wo definiere ich die?

von Daniel (Gast)


Lesenswert?

def hsv_to_rgb(h, s, v):
    h_i = int((h*6))
    f = h*6 - h_i
    p = v * (1 - s)
    q = v * (1 - f*s)
    t = v * (1 - (1 - f) * s)

    if h_i==0: r, g, b = v, t, p
    elif h_i==1: r, g, b = q, v, p
    elif h_i==2: r, g, b = p, v, t
    elif h_i==3: r, g, b = p, q, v
    elif h_i==4: r, g, b = t, p, v
    elif h_i==5: r, g, b = v, p, q
    else:
      r=0;g=0;b=0
    return (int(r*255), int(g*255), int(b*255))

zum Beispiel. kein schöner code, aber er funktioniert. kann sein, dass 
du statt 0, 1 brauchst.

von Chris (Gast)


Lesenswert?


von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Kolja L. schrieb:
> Ich habe es getan!

ich auch ..., start war vor 2 jahren und mein python code sah so ähnlich 
aus, sprich mein c code nur in python syntax, grausam!

Kolja L. schrieb:
> das Tollste: der Code muss nicht mehr compilieren

das wird nicht lange so bleiben, wer richtig mit mpy unterwegs ist kommt 
an froozen code nicht vorbei, spricht du musst dann die tool chain z.b. 
in vbox/linux aufsetzen ... und mpy immer übersetzen, was bei mir auf 
"knopfdruck" unter w8/10 alles startet einschließlich flashen.


für das if/else gedöns... kannst du mal probieren

colors = ([v,t,p], [q,v,p], ...)
r,g,b = c for i,c in enumerate(colors) if h_i == i
return bytes([round(r*255), ...])

ich "liebe" mpy!


mt

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

verstehst du sowas, was passiert hier?

if not sec % 2 if hour in (12, 23) else not sec % 3:
   ... # set led
else:
   ... # clear led

von Markus F. (mfro)


Lesenswert?

Chris schrieb:
> Scope. r, g und b existieren nicht auf dieser Ebene.
>

Python kennt keinen block scope.

Aber wenn einer Variable nichts zugewiesen wird, hat sie auch keinen 
Wert.

von Markus F. (mfro)


Lesenswert?

Apollo M. schrieb:
> verstehst du sowas, was passiert hier?
>
> if not sec % 2 if hour in (12, 23) else not sec % 3:

'conditional expression', das Äquivalent zum Ternary (Fragezeichen-) 
Operator in C:

https://docs.python.org/3/reference/expressions.html#conditional-expressions

§6.12

von chris (Gast)


Lesenswert?

> if not sec % 2 if hour in (12, 23) else not sec % 3:

In dem sehr guten Buch "weniger schlecht Programmieren" legen einige der 
besten Programmierer dar, dass guter Code lesbar sein soll wie ein gutes 
Buch und zwar für den Menschen, nicht für den Computer:

https://www.oreilly.de/buecher/120174/9783897215672-weniger-schlecht-programmieren.html

Insofern sind komplexe Konstrukte einer Programmiersprache zu vermeiden, 
sondern nur diese zu verwenden, die für den Menschen eingängig sind.

Es ist keine Zeichen für einen guten Programmierstil den Code möglichst 
kurz zu halten, sondern den Code für den Menschen schön und lesbar zu 
gestalten.

Insofern war das Beispiel von Kolja am Anfang schon mal viel besser als 
alles nachher gezeigte.

von Kolja L. (kolja82)


Lesenswert?

Daniel schrieb:
> else:
>       r=0;g=0;b=0

Danke, da ging mir ein Licht auf ?

chris schrieb:
> Insofern war das Beispiel von Kolja am Anfang schon mal viel besser als
> alles nachher gezeigte.

Insbesondere da es sich hier um die Frage eines blutigen Anfängers 
handelt.
Hab mal irgendwo aufgeschnappt: make it run, make it secure, make it 
fast.
Ich bin noch ganz am Anfang von "make it run".

Aber nur durch Fehler lernt man, also weiter gehts.

von Bernd K. (prof7bit)


Lesenswert?

Daniel schrieb:
> elif h_i==5: r, g, b = v, p, q
>     else:
>       r=0;g=0;b=0

man kann auch else: r, g, b = 0, 0, 0 schreiben damit nicht jeder der 
eine einzelne Zeile Code beisteuert wieder einen anderen Schreibstil 
einführt sonst sieht es am Ende aus wie ein Flickenteppich.

von Bernd K. (prof7bit)


Lesenswert?

Apollo M. schrieb:
> verstehst du sowas, was passiert hier?
>
> if not sec % 2 if hour in (12, 23) else not sec % 3:
>    ... # set led
> else:
>    ... # clear led

Das muss das hässlichste Stück Python-Code sein daß ich in meinem ganzen 
Leben jemals gesehen habe. Mit Abstand! Wo hast Du den gefunden?

Auch mit dem Wissen um die Ternäre-Operator-Syntax gelingt es mir auch 
nach 5 Minuten intensivem Nachdenkens und Klammern setzens im Kopf nicht 
zu ergründen warum dieser Code keinen Syntaxerror produziert, geschweige 
denn zu verstehen was er überhaupt tun soll. Ich gebe auf.

: Bearbeitet durch User
von Kolja L. (kolja82)


Lesenswert?

Bernd K. schrieb:
> man kann auch else: r, g, b = 0, 0, 0 schreiben

Danke, jetzt sieht es auch noch einheitlich aus.
Funktioniert hat es natürlich schon vorher.

Gleich noch mal ne Frage:

Ich erhöhe beim Aufruf einer Funktion den Wert einer Variable immer um 
0.01:
1
## LEDs mit HSV aufrufen und anschliessend HSV erhoehen
2
hsv = 0
3
schritt = 0.01
4
def led_verlauf():
5
    global hsv
6
    for j in range(0, 2):
7
        np[j] = hsv_to_rgb(hsv, 0.9, 0.21) 
8
    np.write()
9
    print(hsv)
10
    hsv += schritt
11
    if hsv > 0.99: hsv = 0

In der Ausgabe finde ich aber sowas:

0.08
0.0899999
0.0999999
0.11

Ich will jetzt nich päptlicher sein als der Papst (egal welcher von 
denen),
denn 0.0899999 ist schon recht nah an 0.09 und den Unterschied in der 
Lichtfarbe wird niemand sehen, aber woher kommt diese Ungenauigkeit?

von Markus F. (mfro)


Lesenswert?

Bernd K. schrieb:
> Das muss das hässlichste Stück Python-Code sein daß ich in meinem ganzen
> Leben jemals gesehen habe. Mit Abstand! Wo hast Du den gefunden?
>
> Auch mit dem Wissen um die Ternäre-Operator-Syntax gelingt es mir auch
> nach 5 Minuten intensivem Nachdenkens und Klammern setzens im Kopf nicht
> zu ergründen warum dieser Code keinen Syntaxerror produziert, geschweige
> denn zu verstehen was er überhaupt tun soll. Ich gebe auf.

Ich find's auch alles andere als schön. Aber erklären kann ich's, wenn 
Du möchtest:

Bernd K. schrieb:
> if not sec % 2 if hour in (12, 23) else not sec % 3:

"Klammernsuche" war der richtige Ansatz. Die gehören so:
1
if (not sec % 2 if hour in (12, 23) else not sec % 3):
2
...

Allgemein geht der ternäre Operator so:
1
x if C else y

Erst wird "die Mitte" (C) ausgewertet, wenn True, dann wird der gesamte 
Ausdruck x, sonst y:
1
not sec % 2 if hour in (12, 23) else not sec % 3

Das Ergebnis wird also um 12 und um 23 Uhr not sec % 2 und sonst not sec 
% 3
1
not sec % z
wird immer dann True, wenn es keinen Divisionsrest gibt, sonst False

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Kolja L. schrieb:
> In der Ausgabe finde ich aber sowas:
>
> 0.08
> 0.0899999
> 0.0999999
> 0.11

https://docs.python.org/2/tutorial/floatingpoint.html

von Thorsten S. (thosch)


Lesenswert?

Kolja L. schrieb:
> Ich will jetzt nich päptlicher sein als der Papst (egal welcher von
> denen),
> denn 0.0899999 ist schon recht nah an 0.09 und den Unterschied in der
> Lichtfarbe wird niemand sehen, aber woher kommt diese Ungenauigkeit?

Willkommen in der Welt der Rundungsfehler!
Floatingpoint Darstellung von Zahlen funktioniert nicht exakt für Zahlen 
wie 0.1, während 0.5, 0,25, 0.125 exakt darstellbar sind.
Die Darstellung erfolgt auf der Basis von Zweierpotenzen, in 0.1 steckt 
aber 5 als Teiler, und das ist eben keine Zweierpotenz.

von Bernd K. (prof7bit)


Lesenswert?

Dies ist auch der Grund warum man bei Buchhaltungssoftware oder allem 
was mit Geldbeträgen zu tun hat (egal in welcher Programmiersprache) 
grundsätzlich in Integern rechnet (also in Beträgen von Cent oder 
kleiner) und niemals in Fließkomma und immer erst bei der Darstellung 
wieder das Komma an der richtigen Stelle setzt.

von Kolja L. (kolja82)


Lesenswert?

Danke, die Lösung ist also, solange es geht in ganzen Zahlen zu rechnen 
uns erst wenn / falls notwendig in eine Dezimalzahl umzuwandeln.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Bernd K. schrieb:
> Das muss das hässlichste Stück Python-Code sein daß ich in meinem ganzen
> Leben jemals gesehen habe.

nö, du musst aber sicher noch viel lernen, https://realpython.com/
z.b. https://realpython.com/python-or-operator/

keyword: pythonic code - und nicht c/c++ code in python syntax!


Markus F. schrieb:
> Ich find's auch alles andere als schön. Aber erklären kann ich's, wenn
> Du möchtest:

if not sec % 2 if hour in range(12, 23) else not sec % 3:
   ... # set led
else:
   ... # clear led

der code dient in einer "24h uhr" (12 neopixel ring) und lässt die sec 
led von 0-12h im 2sec takt und von +12-24 alle 1sec blinken.

wichtig ist mir hier, dass das ternary "überall" stehen kann, also hier 
nicht als right value sondern als condition.


geklammert wird python nur wenns pflicht ist; siehe style guide, 
https://www.python.org/dev/peps/pep-0008/!


mt

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Apollo M. schrieb:
> if not sec % 2 if hour in range(12, 23) else not sec % 3:

jetzt wird's klar.

Das 'range' war aber heute morgen auch noch nicht da ;)

von Bernd K. (prof7bit)


Lesenswert?

Apollo M. schrieb:
> nö

Doch. Das kann man lesbarer hinschreiben, da kann man noch ein oder zwei 
Variablen für Zwischenergebnisse spendieren mit aussagekräftigem Namen. 
Und das "not" bei dem man grübeln muss zu welcher Seite es nun gehört 
("if not" oder "not sec % 2") kann man sich auch schenken wenn man das 
if umdreht. "Pythonisch" bedeutet nicht absichtlich maximal unleserlich.


1
afternoon = hour in range(12, 23)
2
blinkphase = sec % 2 if afternoon else sec % 3
3
4
if blinkphase:
5
    ...
6
else:
7
    ...

/meinung

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

außerdem muß es range(12, 24) heißen wo wir schonmal dabei sind!
1
>>> range(12, 23)
2
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
3
>>> range(12, 24)
4
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]

von chris (Gast)


Lesenswert?

>Doch. Das kann man lesbarer hinschreiben,

Ich bin ganz Deiner Meinung und Deine Version ist auch wirklich 
lesbarer.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

chris schrieb:
> Ich bin ganz Deiner Meinung

ich auch!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.