Hallo,
auf meinem ESP8266 läuft die aktuelle micropython Version (1.13) mit
folgendem Skript:
1
importtime,math,machine
2
frommachineimportPin,PWM
3
4
foriinrange(100):
5
foriin[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?
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
importtime,math
2
frommachineimportPin,PWM
3
4
forjinrange(100):
5
foriin[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
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.
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])
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.
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.
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.
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ß!!!
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?
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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. :-(
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?
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.
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.