Forum: Mikrocontroller und Digitale Elektronik Lauflicht hängt - µPython+ESP8266


von kolja (Gast)


Lesenswert?

Hallo,

auf meinem ESP8266 läuft die aktuelle micropython Version (1.13) mit 
folgendem Skript:
1
import time, math, machine
2
from machine import Pin, PWM
3
4
for i in range(100):
5
    for i in [0, 15, 13, 12, 14, 4, 5]:
6
        machine.PWM(machine.Pin(i), freq=1000, duty=1000)
7
        time.sleep_ms(150)
8
        machine.PWM(machine.Pin(i), freq=1000, duty=0)
9
        print(i)

Der ESP steckt mit LEDs und Widerständen auf einem Steckbrett und alle 
LEDs lassen sich einzeln ansteuern.
(getestet mit duty 0, 500 1000)

Leider bleibt das Lauflicht immer kurz hängen, ca ne halbe Sekunde
und springt dann an eine andere Stelle um von dort weiterzulaufen, bis 
es erneut hängt...

Die Ausgabe des Zählers (i) bleibt nicht hängen.

Woran liegt das?

von Joachim S. (oyo)


Lesenswert?

kolja schrieb:
>
1
> for i in range(100):
2
>     for i in [0, 15, 13, 12, 14, 4, 5]:
3
>

Die beiden verschachtelten Schleifen verwenden die gleiche Variable. Hat 
zwar nix mit dem eigentlichen Problem zu tun und hat hier wahrscheinlich 
nicht einmal unbeabsichtigte Auswirkungen, war so aber vermutlich nicht 
gedacht.

Das eigentliche Problem hingegen hat möglicherweise irgendwie damit zu 
tun, dass Du per machine.PWM() immer neue PWM-Kanäle anlegst, ohne die 
alten per deinit() wieder abzuschalten, und der ESP nur eine begrenzte 
Anzahl PWM-Kanäle hat.

Ist aber nur ne Vermutung. Probier doch testweise mal Folgendes:
1
import time, math
2
from machine import Pin, PWM
3
4
for j in range(100):
5
    for i in [0, 15, 13, 12, 14, 4, 5]:
6
        pwm_channel = PWM(Pin(i), freq=1000, duty=1000)
7
        time.sleep_ms(150)
8
        pwm_channel.duty(0) // Evtl. überflüssig, weil direkt danach pwm.deinit() kommt
9
        pwm_channel.deinit()
10
        print(i)

von Stefan F. (Gast)


Lesenswert?

kolja schrieb:
> Leider bleibt das Lauflicht immer kurz hängen, ca ne halbe Sekunde
> und springt dann an eine andere Stelle um von dort weiterzulaufen, bis
> es erneut hängt...

Ich habe µPython noch nicht versucht, aber ich kenne den gleichen Effekt 
von Arduino. Die Ursache liegt dort im Betriebssystem selbst, und 
deswegen denke ich, dass es bei µPython nicht anders sein wird.

Das Betriebssystem pausiert dein Anwendungsprogramm in zyklischen 
Abständen, um die WLAN Schnittstelle zu bedienen. Je schlechter der 
Empfang ist, umso länger dauern diese Unterbrechungen.

Anstatt 150ms zu warten, warte besser bis der gewünschte Zeitpunkt 
(jetzt + 150ms) erreicht ist. Dadurch wird es etwas flüssiger laufen, 
aber perfekt ist wohl unmöglich.

Es gibt ESP32 Module mit Dual-Core Prozessoren (nicht alle haben den), 
da soll das machbar sein.

von Andreas M. (amesser)


Lesenswert?

Lol, nen 80 Mhz CPU die nicht für ein Lauflicht reicht. Wozu überhaupt 
eine PWM? Naja egal es ist auf jeden Fall sinnfrei ständig den Python 
Konstruktor neu aufzurufen. Das print wird das timing sicher auch nicht 
verbessern, geht das über UART? Besser so:
1
import time, math
2
from machine import Pin, PWM
3
4
leds = list( PWM(Pin(i), freq=1000, duty=0) for i in [0, 15, 13, 12, 14, 4, 5])
5
6
for j in range(100):
7
    for led in leds:
8
          led.duty(1000) 
9
          time.sleep_ms(150)
10
          led.duty(0)

von Joachim S. (oyo)


Lesenswert?

Andreas M. schrieb:
> Lol, nen 80 Mhz CPU die nicht für ein Lauflicht reicht. Wozu überhaupt
> eine PWM?

Vermutlich ist der Code so noch lange nicht fertig und PWM wird erst 
später richtig genutzt, wenn das minimale Code Sample erst einmal läuft. 
Soll vielleicht so eine Art Knight Rider-Lauflicht geben.

> Das print wird das timing sicher auch nicht
> verbessern, geht das über UART?

Das ist sicherlich nur vorübergehend als Debug-Ausgabe drin und erst 
einmal nicht schädlich, sondern wirklich eher hilfreich.

> Naja egal es ist auf jeden Fall sinnfrei ständig den Python
> Konstruktor neu aufzurufen. Besser so:
>
>
1
> import time, math
2
> from machine import Pin, PWM
3
> 
4
> leds = list( PWM(Pin(i), freq=1000, duty=0) for i in [0, 15, 13, 12, 14, 
5
> 4, 5])
6
> 
7
> for j in range(100):
8
>     for led in leds:
9
>           led.duty(1000)
10
>           time.sleep_ms(150)
11
>           led.duty(0)
12
>

Das funktioniert aber halt auch nur, wenn man mindestens 7 PWM-Kanäle 
zur freien Verfügung hat und gleichzeitig benutzen kann. Wieviele der 
ESP8266 tatsächlich hat, weiss ich nicht sicher - aber auf dem ESP8266 
kann man unter LUA, was ja vergleichbar mit Micropython ist, maximal 6 
benutzen.

von Stefan F. (Gast)


Lesenswert?

Joachim S. schrieb:
> Das funktioniert aber halt auch nur, wenn man mindestens 7 PWM-Kanäle
> zur freien Verfügung hat und gleichzeitig benutzen kann. Wieviele der
> ESP8266 tatsächlich hat, weiss ich nicht sicher

Er hat gar keinen - kein Scherz. PWM muss man dort per Software 
realisieren.

von Joachim S. (oyo)


Lesenswert?

Stefan ⛄ F. schrieb:
> Joachim S. schrieb:
>> Das funktioniert aber halt auch nur, wenn man mindestens 7 PWM-Kanäle
>> zur freien Verfügung hat und gleichzeitig benutzen kann. Wieviele der
>> ESP8266 tatsächlich hat, weiss ich nicht sicher
>
> Er hat gar keinen - kein Scherz. PWM muss man dort per Software
> realisieren.

Danke, das war mir tatsächlich neu. Ich dachte immer der hätte 
Hardware-PWM, aber Du scheinst völlig Recht zu haben.
Dann ist die Beschränkung auf 6 PWM-Kanäle in NodeMCU/LUA's pwm-Modul 
offenbar rein künstlich, vielleicht um RAM zu sparen oder so.

Wenn Micropython keine derartige künstliche Beschränkung hat, dann ist 
Andreas' Lösung natürlich am einfachsten und besten.

von Zeitjäger  . (forgoden)


Lesenswert?

Hab schon immer gewusst das µPython schrecklich ist.

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


Lesenswert?

Wer bin ich?  . schrieb:
> Hab schon immer gewusst das µPython schrecklich ist.

MicroPython macht richtig Spass!

Du und der TO haben bloss prinzipiell keine Idee von Python (der 
Dreizeiler sagt alles dazu, grausm!) und von der benutzen HW/ESP8266 
(keine HW PWM, echt jetzt?! RTOS/Wlan wozu das den? Kann man auch 
abschalten!) wohl auch nicht.

Nur immer doof kopieren ohne irgendwas vorher/während zu 
lesen/nachvollziehen reicht nicht einmal zum Mittelmaß!!!

von Stefan F. (Gast)


Lesenswert?

Apollo M. schrieb:
> keine HW PWM, echt jetzt?

Ja, echt jetzt. Schau ins Datenblatt 
https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf

"The functionality of PWM interfaces can be implemented via software 
programming. For example, in the LED smart light demo, the function of 
PWM is realized by interruption of the timer"

Das zieht sich durch das ganze Datenblatt durch. Bei dem Chip ist fast 
alles "implemented in software".

Wenn du das Betriebssystem weg lässt oder aus anderen Gründen die WLAN 
Schnittstelle nicht bedienst, verliert es die Verbindung zum AP. Wer 
will das schon?

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


Lesenswert?

Stefan ⛄ F. schrieb:
> Das zieht sich durch das ganze Datenblatt durch. Bei dem Chip ist fast
> alles "implemented in software".

Ist mir bekannt, ich kenne das Teil von "Innen & Aussen".
Ich hacke sogar im C-Source von MicroPython rum, weil einige Issues 
störten ...

Das ? war gelinkt an die Unwissenden und eine Aufforderung selber zu 
lesen UND micht zu warten bis Stefan F. oder andere Gutmenschen das für 
sie tun.

von kolja (Gast)


Lesenswert?

Guten Abnend und danke für die ganzen Informationen.

Die erste Idee:
Joachim S. schrieb:
> Ist aber nur ne Vermutung. Probier doch testweise mal Folgendes:
bringt mich leider nicht weiter, denn sobald die deint() Funktion 
aufgerufen wird,
gehen die LED nicht mehr aus.
Irgendwie erinnert mich das an einen FET ohne PullDown Widerstand,
aber mit .duty(0) wird dem Pin ja vorher ein definierter Status gegeben.

Stefan ⛄ F. schrieb:
> Das Betriebssystem pausiert dein Anwendungsprogramm in zyklischen
> Abständen, um die WLAN Schnittstelle zu bedienen. Je schlechter der
> Empfang ist, umso länger dauern diese Unterbrechungen.

So schlecht sollte der Empfang nicht sein, sind vielleicht 5m und eine 
Leichtbauwand (allerdings mit Profielen aus Blech).
Danke für trotzdem für den Hinweis, er bestätigt meine Vermutung.
Gestern hatte ich schon nach dem Äquivalent zu der yield() Funktion 
gesucht,
aber ohne Erfolg.

Stefan ⛄ F. schrieb:
> Anstatt 150ms zu warten, warte besser bis der gewünschte Zeitpunkt
> (jetzt + 150ms) erreicht ist.

Ja, klingt gut!

Andreas M. schrieb:
> Lol, nen 80 Mhz CPU die nicht für ein Lauflicht reicht. Wozu überhaupt
> eine PWM? Naja egal es ist auf jeden Fall sinnfrei ständig den Python
> Konstruktor neu aufzurufen. Das print wird das timing sicher auch nicht
> verbessern, geht das über UART? Besser so:

Wie im folgenden geschrieben wurde, sind das jett erst die ersten Zeilen 
Code. Die Ausgabe ist zum "debuggen" und die PWM soll später noch 
sinnvoller zum Einsatz kommen. Vielleicht ein KnightRider Lauflicht ;-)
Mit deinem Code gibt es leider dasselbe Ergebnis, das Licht bleibt kurz 
stehen und läuft dann weiter.

Wer bin ich?  . schrieb:
> Hab schon immer gewusst das µPython schrecklich ist.

Ich hätte mir auch nicht vorgestellt, Probleme damit zu haben, 7 LED 
nacheinander aufleuchten zu lassen, aber naja sind halt 
Startschwierigkeiten.

Stefan ⛄ F. schrieb:
> Er hat gar keinen - kein Scherz. PWM muss man dort per Software
> realisieren.

Geht aber auch nicht auf allen Pins z.B. GPIO3.
Die Pins in Code sind aber alle getestet und funktionieren.

Apollo M. schrieb:
> Ist mir bekannt, ich kenne das Teil von "Innen & Aussen".

Glaube ich dir nicht, denn dann hättest du etwas sinnvolles geschrieben.

von Andreas M. (amesser)


Lesenswert?

kolja schrieb:
> Wie im folgenden geschrieben wurde, sind das jett erst die ersten Zeilen
> Code. Die Ausgabe ist zum "debuggen" und die PWM soll später noch
> sinnvoller zum Einsatz kommen. Vielleicht ein KnightRider Lauflicht ;-)
> Mit deinem Code gibt es leider dasselbe Ergebnis, das Licht bleibt kurz
> stehen und läuft dann weiter.

Dann liegts vermutlich wie oben geschrieben an den WLAN Funktionen. Das 
hat übrigens nichts mit gutem oder schlechten Empfang zu tun. Es gibt in 
einem Netzwerk immer regelmäßigen Datenverkehr, selbst wenn man in 
seinem Programm gar nichts direkt macht. Z.B. irgendwelche Multicast DNS 
Multicasts, ARP, DHCP Broadcasts... Auch wenn man das nur empfängt, muss 
dafür trotzdem was in der CPU gemacht werden. Alleine um z Entscheiden 
relevant/irrelevant. Dazu kommt dass das verschlüsselt empfangen wird 
und dann erst mal entschlüsselt werden muss. Die Schlüssel müssen auch 
regelmäßig erneuert werden, da kostet auch CPU Zeit.

von Joachim S. (oyo)


Lesenswert?

Ich weiss ja nicht, wirklich zufriedenstellend finde ich die Erklärung 
mit dem WLAN nicht.

Im Eröffnungsposting wurden doch folgende Symptome erwähnt:
1. Lauflicht bleibt plötzlich für stolze halbe Sekunde einfach stehen
2. Die Ausgabe des Zählers hingegen läuft in dieser Zeit normal weiter
3. Danach spring das Lauflicht an eine andere Stelle

Wie passt das alles mit der "WLAN!"-Erklärung zusammen?
Zumal WLAN in dem geposteten Skript doch nicht einmal aktiviert wird...

Ich würde aktuell eher vermuten, dass die Ursache mglw. ein Bug in 
Micropython's pwm-Modul ist.

Laut der µpython-Doku kann man übrigens per
1
import esp
2
esp.osdebug(0)
irgendwelche debug-Ausgaben einschalten, die dann über die serielle 
Schnittstelle gesendet werden. Wäre vielleicht nen Versuch wert.

von Stefan F. (Gast)


Lesenswert?

Joachim S. schrieb:
> 2. Die Ausgabe des Zählers hingegen läuft in dieser Zeit normal weiter
> Wie passt das alles mit der "WLAN!"-Erklärung zusammen?

Guter Punkt.

Kolja, könntest du dich bitte nochmal zur Ausgabe des Zählers äußern? 
Findet diese wirklich regelmäßig alle 150ms statt während LEDs stehen 
bleiben?

Weil wenn ja, dann wäre ja lediglich die PWM Ausgabe zyklisch gestört.

von kolja (Gast)


Lesenswert?

Nabend zusammen,


Stefan ⛄ F. schrieb:
> Kolja, könntest du dich bitte nochmal zur Ausgabe des Zählers äußern?
> Findet diese wirklich regelmäßig alle 150ms statt während LEDs stehen
> bleiben?

ein Bild sagt mehr als tausend Worte:

https://streamable.com/0wwsn2

Also ja, der Zähler (print()) läuft durch, die LED nicht.

von Stefan F. (Gast)


Lesenswert?

kolja schrieb:
> ein Bild sagt mehr als tausend Worte:
> Also ja, der Zähler (print()) läuft durch, die LED nicht.

Da mein Ansatz mit dem WLAN wirklich völlig falsch, denke ich jetzt 
auch.

Scheinbar bleibt der PWM Timer stehen. Versuche mal, statt duty 0/1000 
die Werte 50/200. Ich wette, dass die LEDs bei den Pausen ganz aus oder 
ganz an gehen. Das müsste man sofort sehen. Wenn dem so ist, dann stimmt 
etwas mit der Interruptfreigabe oder der ISR nicht, die das PWM Signal 
generiert. Und das wiederum ist sehr wahrscheinlich ein (in µPython) 
lösbares Softwareproblem.

von Joachim S. (oyo)


Lesenswert?

Ich würde vorschlagen, testweise auch mal andere PWM-Frequenzen (z.B. 80 
und 200 Hz) und andere duty-Werte zu verwenden (z.B. 1023 und 250).

Einfach nur um zu schauen, ob sich dann zufällig irgendetwas ändert 
(abgesehen von der unterschiedlichen Helligkeit beim Verändern der 
duty-Werte).

von kolja (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Versuche mal, statt duty 0/1000
> die Werte 50/200. Ich wette, dass die LEDs bei den Pausen ganz aus oder
> ganz an gehen.

Leider machen die LED genaus das was man erwartet, also leicht "glimmen" 
(50) und der Reihe nach "hell" (200) aufleuchten.
Auf das Stehenbleiben hat das keinen Einfluss,

solange die Frequenz auf über 100Hz eingestellt ist.
Dann ist das Stocken zwar nicht weg, aber sehr viel seltener.
Bei 80Hz konnte ich in den 100 Durchläufen kein Stocken mehr sehen.

Sehen kann ich die 80Hz nicht, also wenn die LED ein paar Sekunden lang 
leuchten, aber soll ich mich jetzt damit zufrieden geben?
Zwar habe ich im Internet kein Beispiel eines Lauflichtes mit µPython 
gefunden, kann mir aber nicht vorstellen, dass ich der erste bin, der 
auf dieses Phänomen stößt.

von kolja (Gast)


Lesenswert?

kolja schrieb:
> Bei 80Hz konnte ich in den 100 Durchläufen kein Stocken mehr sehen.

Nachtrag: Auch bei 80Hz kommt es zum Stocken...

von Stefan F. (Gast)


Lesenswert?

Jetzt weiß ich auch nicht mehr weiter. Ich würde einen offiziellen 
Bug-Report aufmachen.

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


Lesenswert?

Stefan ⛄ F. schrieb:
> etzt weiß ich auch nicht mehr weiter. Ich würde einen offiziellen
> Bug-Report aufmachen.

.. viel zu früh, da zu wenig Info's da sind. Das MPY Projekt macht eher 
keine "Forschung/Intersuchung" für andere ... es ist ja nicht mal 
bekannt, ob Wlan aktiv ist oder wie MPY sonst konfiguriert ist.

Besser mal ganz klein anfangen mit nur einen PWM Channel im REPL Mode, 
also interaktiv händisch den Code eingeben, dann zwei PWM Channels ... 
alles ohne Repeatschleife.

Wenn das dann läuft (bei mir läufts problemlos), jeweils einen Channel 
dazu und dann sehen wir weiter.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Sicher, für einen offiziellen Bug Report trägt man alle verfügbaren 
Infos zusammen und mach ein paar Versuche um herauszufinden, was genau 
den fehler auslöst. Die bisheringen Versuche mit unterschiedlichen PWM 
Frequenzen sind ein guter Anfang dazu.

von Joachim S. (oyo)


Lesenswert?

Aufgrund des geschilderten Verhaltens bei Veränderung von Duty und 
Frequenz würde ich Geld darauf verwetten, dass Micropythons PWM-Modul 
intern Double Buffering verwendet und das "Einfrieren" der LEDs damit zu 
tun hat, dass aufgrund irgendeines Bugs zeitweilig nicht korrekt 
zwischen den beiden Buffern umgeschaltet wird.

Es soll ja Leute geben, die Micropython von innen & aussen kennen und 
sogar in dessen C-Source herumhacken. Denen wäre das bestimmt sofort 
klar gewesen. Aber die treiben sich wohl leider nicht hier im Forum bei 
den ganzen unwissenden nicht-mal-Mittelmaß-Gutmenschen herum. :-(

von kolja (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich würde einen offiziellen Bug-Report aufmachen.
Mhh, okay.

Apollo M. schrieb:
> .. viel zu früh, da zu wenig Info's da sind.

Welche braucht es denn noch?

Apollo M. schrieb:
> Besser mal ganz klein anfangen mit nur einen PWM Channel im REPL Mode,
> also interaktiv händisch den Code eingeben, dann zwei PWM Channels ...
> alles ohne Repeatschleife.

Das verstehe ich noch nicht, wie soll ich einem Fehler auf den Grund 
gehen,
der in einer Schleife auftritt, ohne eine Schleife zu benutzen?

von Stefan F. (Gast)


Lesenswert?

kolja schrieb:
> Welche braucht es denn noch?

Du musst dein Programm auf ein Minimum reduzieren, wo das Problem so 
gerade eben noch auftritt. Dann musst du wie bereits begonnen 
ausprobieren, ob das Problem nur bei bestimmten Parametern auftritt.

Ganz wichtig ist die Angabe der µPython Version, dein Schaltplan und wo 
die Stromversorgung herkommt. Tritt der Fehler auch ohne Verbindung zum 
PC auf, mit einer als ideal angenommenen Batterieversorgung?

Fotos vom Aufbau sind immer hilfreich, denn Bilder sagen mehr als 1000 
Worte. Egal wie primitiv die Schaltung ist.

von Johannes S. (Gast)


Lesenswert?

mikroPython hat doch auch eine grosse Community, es muss ja nicht sofort 
ein Bugreport sein. Da gibt es doch auch Foren wo man Fragen kann und wo 
es Leute mit Wissen über die Internas gibt.

Beitrag #6544248 wurde von einem Moderator gelöscht.
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.