Hallo
Ich möchte eine Effekt-Lampe mit LED-Stripe (WS 2801) realisieren. Die Lampe soll man in verschiedene Modi versetzen können (zB. Unifarbeneffekt, Feuereffekt, Plasmaeffekt, EffektXYZ, ....). Jeder Modus kennt auch noch verschiedene Parameter (zB. Flammenhöhe beim Feuereffekt, RGB-Farbe beim UniFarbeneffekt, etc. manchmal sind es auch mehrere Parameter für ein Effekt).
Das ganze soll mit einer Fernbedienung einstellbar sein.
Den Feuereffekt habe ich zB schon probeweise am laufen auf meinem Arduino Micro. Funktioniert wunderbar, allerdings mit festcodierten Parametern (Flammenhöhe, Abkühlung, Farbe)
Da der Empfang der Fernbedienung und das Darstellen der Effekte von einem Arduino Micro nicht bewältigt werden kann möchte ich diese Aufgaben auf zwei Arduinos verteilen. Mit einem Arduino möchte ich meine Fernbedienung empfangen und entsprechend der empfangenen Tasten die unterschiedlichen Parameter verändern. Der zweite Arduino ist nur damit beschäftigt sich die Parameter möglichst effizient (schnell) vom Arduino1 abzuholen und dann entsprechend den Effekt zu variieren.
Mir geht es im Moment erstmal nur um eine Ideensammlung für die Kommunikation zwischen den beiden Arduinos. Arduino2 (der die Effekte berechnet und per FastLed-Lib den LED-Stripe ansteuert) hat in der Mainloop nur ca. 10ms Zeit sich die Parameterwerte vom Arduino1 abzuholen.
Erste Idee ist eine normale serielle Kommunikation über Tx/Rx. Habe mir ansonsten noch keine großen Gedanken gemacht. Vom Datenvolumen, also Menge der Parameter handelt es sich um max ca. 10 Bytes. Die Daten müssen nur vom Arduino1 zum Arduino2 übertragen werden, also nur in eine Richtung.
Wie würdet ihr sowas angehen? Wie gesagt, es ist erstmal ein offene Ideensammlung. Selbst die Übertragung per Rx/Tx ist nicht gesetzt. Wenn es da andere Methoden gibt bin ich da offen.
Hoffe auf Inspiritationen
Gruß
Jarny
PS: Der Empfang von IR Signalen und Empfang von 433Mhz Funkfernbedienungen funktionieren wunderbar einzeln auf einem Arduino (auch auf einem Arduino Micro getestet) aber zusammen mit der Ansteuerung der LEDs ist man am Limit der Leistungsfähigkeit eines Arduinos. Ich habe entsprechend populäre Libs (RCSwitch, IRremote) benutzt und die arbeiten natürlich mit Interrupts, so dass durch die aufwendigen Effekteberechnung + Ansteuerung der LEDStripes per FastLED-Lib irgendwann die Erkennung der empfangenen Signale nicht mehr zuverlässig funktioniert. Deshalb die Aufteilung auf 2 Arduinos. Die Arduinos hab ich hier noch rumliegen und will nichts neues kaufen. Ausserdem könnte ich auch später evtl. 2 oder 3 Effekt-Arduinos mit dem einen Empfangs-Arduino steuern.
Über seriell geht das Einlesen auch nicht viel anders wie wenn du was vom PC einliest, außer vielleicht dass du Binärdaten statt Strings empfängst. Entweder haben die Pakete eine konstante Länge und man wartet einfach bis Serial.available() einen bestimmten Wert erreicht hat. Oder man hat eine Variable Länge und sendet als erstes Byte die Länge.
I2C ist noch eine Option:
Etwas andere Syntax, aber das Prinzip ist sehr ähnlich.
Serial und Wire laufen aber beide auch in Interrupts. Du hast also eventuell das gleiche Problem. FastLED deaktiviert wohl die Interrupts wenn die Daten geschrieben damit da nichts dazwischen kommt: http://forum.arduino.cc/index.php?topic=264631.msg1866731#msg1866731
(letzter Absatz)
Man könnte dem Sende-Arduino eventuell mitteilen, dass ein Fenster zum Senden frei ist. Das geht aber nicht mit I2C da Slaves nicht unaufgefordert Daten schicken können. Ein digitaler I/O Pin würde es da aber auch tun.
"Nur" 10ms ist eine verdamt lange Zeit für einen loop Durchgang.
Bitte poste mal bitten deinen Sketch, womit diese Probleme auftauchen und des weiteren wäre interessant, wieviele Leds du einsetzt.
Das Problem mit der Interupts ist, dass die FastLED während es die Daten zu den Leds schiebt, die Interupts sperrt. Sprich kein Interupt kommt mehr rein, solange diese gesperrt sind. Die Berechnung der Effekte hat dabei aber nichts mit dem sperren der Interupts zu tun. Diese sollten üblicherweise im normalen Durchlauf errechnet werden
Alternativ kannst Du auch einen getrennten Animations- und Einstellmodus verwenden.
D.h. Du programmierst Deine Animationen so, das sie einzelne Frames ausgeben und schaust nach jeden FastLED.show(); mittels schneller Portmanipulation (und nicht mit digitalRead, das dauert ewig!), ob Input vorliegt und wechselst in diesem Fall in einen Einstellmodus. Wenn alle Einstellungen getätigt sind, gehst Du zurück in den Animationsmodus. Verständlich?
Das ist ein guter Kompromiss zwischen schnellen Animationen und sicher erkanntem Input. Und es geht mit einem Arduino.
Hallo! Konnte mich erst jetzt zurückmelden. War beruflich unterwegs aber konnte wenigstens zwischendurch mal im Forum lesen
Danke erstmal für die verschiedenen Antworten. Ich mach mal ne Sammelantwort wegen der unterschiedlichen Rückfragen die ich noch offen gelassen habe:
Also es handelt sich tatsächlich um den Sketch Fire2012 der zB in den Examples von FastLED2.1-Lib dabei ist. Ich möchte ca. 50 LEDs ansteuern, wahrscheinlich werden es 48. Von den FPS möchte ich auf ca. 40 FPS oder mehr kommen, ich denke das ist flüssig genug.
Neue Hardware will ich mir eigentlich nicht kaufen, also XBee fällt damit aus. Habe hier einige Arduinos (meist Clones) rumliegen. Ein Pro Mini steuert im Moment den LED-Stripe.
Ich habe mir das mit der schnellen Portmanipulation mal durchgelesen und denke ich werde die Kommunikation zwischen dem LEDStripe-Arduino und dem IRReceive-Arduino damit lösen. Werde erstmal die Daten Nibble-weise über PortD übertragen, also immer 4Bit gleichzeitig. Die restliche 4Bit des Ports geben sozusagen die Adresse an, ich habe also 16 mal 4Bit = 8Byte als Nutzdaten bei dieser Aufteilung. Das ist ein Optimum zwischen Geschwindigkeit und Datenmenge die ich übertragen will und eingesetzter I/O Pins. Ausserdem werden die Bitshift-Operationen nicht so unangenehm wie zB. bei einer 5zu3 Aufteilung.
Ich werde diese 8 Byte bei jedem Loopdurchgang übertragen, unabhängig davon ob sich was geändert hat. Der LEDStripe-Arduino fordert die Daten bei IRReceive-Arduino an. Die ca. 10 ms (oder sogar mehr) die ich Zeit habe sind wirklich eine verdammt lange Zeit bei 16 Mhz. Da kann man einiges tun. Wie genau ich das aufbaue und implementiere weiss ich noch nicht, da muss ich mir erstmal ein Plan machen. Ein oder zwei I/Os werd ich wohl auch noch brauchen um die Datenübertragung zu synchronisieren.
@Helmuth
Der Vorschlag mit dem getrennten Animations- und Einstellmodus klang erstmal ganz gut aber so ganz hab ich das noch nicht verstanden. Kannst du noch ein bisschen mehr erklären? Oder sogar ein Beispiel posten? Könnte ich mit deiner Idee das Ganze dann doch mit nur einem Arduino (LEDSteuerung und IR-Empfang auf einem Arduino Pro Mini) lösen?
ich versuche, es klarer auszudrücken. 48 LEDs @40fps sind kein Problem - mit 64 LEDs kommt man auf ca. 400 fps, was ungefähr die Grenze ist, bevor sich die WS2812 "verschlucken", weil es in den Bereich ihrer eigenen PWM Frequenz kommt.
Der Arduino hat also nach dem Senden eines Frames relativ viel Zeit, sich um andere Sachen zu kümmern. Das ist gut.
Muss es unbedingt eine Fernbedienung sein? Falls nicht, ist alles einfach: Du schließt ein paar (entprellte) Taster an und fragst diese nach jedem gesendetem Frame ab, manipulierst entsprechend Deine Variablen und berechnest dann das nächste Frame. Bei 48 LEDs ist selbst das aufgeblähte digitalRead() dafür schnell genug.
Du willst unbedingt eine IR Fernbedienung? Okay. Nach jedem gesendetem Frame, fragst Du ab, ob irgendein IR Signal anliegt. Ist dem so, springst Du in einen Einstellmodus, d.h. Du stoppst die laufende Animation - damit den ständigen FastLED.show() Aufruf und kannst jetzt ganz normal (mittels Interrupts) jeden Fernbedienungsklick auswerten. Jeden erkannten Tastendruck bestätigst Du optisch mit Deinen LEDs, damit Du siehst, was gerade passiert ist. Z.B. visualisierst Du Geschwindigkeitsänderung durch ein blitzen, Farbänderung durch angezeigte Farbe, usw. Oder du programmierst Dir Bargraphen in verschiedenen Farben für verschiedene Parameter oder sonstwas. Wenn Du mit der Einstellerei fertig bist, springst du mittels einer definierten Taste zurück in den Animationsmodus - du berechnest ein Frame, sendest es, fragst einmal IR ab und wieder von vorn.
Problem dabei: höchstwahrscheinlich wirst Du manchmal im Animationsmodus einen "IR Tastendruck" verlieren - sollte allerdings bei einer Fernbedienung mit Auto-Repeat (haben die meisten) kein Problem sein, außer einer Verzögerung im ms Bereich, bis Dein Tastendruck erkannt wird. Müsste man mal schauen, wie lang (zeitlich) der IR Code Deiner verwendeten Fernbedienung ist.
Das geht alles auf einem Arduino und mit 40 fps sehe ich da keine großen Probleme.
Ok, Danke für die ausführliche Erklärung. Genauso hatte ich es auch gedacht nach deiner ursprünglichen Kurzbeschreibung.
Tasten an der Lampe wollte ich nicht, das macht ja nix her und ausserdem müsste ich das auch irgendwie sinnvoll in das Lampengehäuse integrieren.
Ne Fernbedienung ist schon sehr bequem, da will ich nicht drauf verzichten. Ich möchte zB mit zwei Tasten der Fernbedienung die Flammenhöhe und zB auch noch den Sparking-Parameter ändern und mit ner Farbtaste die Flammenfarbe oder so. Das muss ich dann mal sehen was Sinn macht. Ausserdem habe ich den Ehrgeiz, dass das ganze ohne Verzögerung funktioniert, also will ich keine speziellen unterbrechenden optischen Feedbacks für einen Tastendruck haben sondern die Flamme soll sich einfach sofort nach den neuen Parametern ändern.
Ich werde mal berichten wie ichs am Ende gelöst habe.
Übrigens hätte das mit dem getrennten Animations- und Einstellmodus noch den Nachteil, dass ich im Wohnzimmer noch andere IR-Fernbedienungen benutze und dann würde die Lampe jedesmal kurz anhalten und merken, dass das Signal gar nicht für sie bestimmt ist.
Noch ne dämliche Frage bevor ich loslege und dann irgendwann dazu komme meine 2 Arduinos zu verbinden: Was passiert wenn aus Versehen oder in der Initialisierungphase 2 Ausgänge bzw 2 Eingänge zusammengeschaltet sind? Normalerweise schalte ich ja entsprechende für meine Datenübertragung relevanten I/Os des IRReceive-Arduino auf OUTPUT und die damit verbundenen I/Os des LEDStripe-Arduinos auf INPUT. Kann irgendwas kaputt gehen wenn man das falsch setzt? Also zB zweimal OUTPUT oder zweimal INPUT?
Ich wollte eigentlich beide Arduinos mit den 8 Pins von PortD plus Versorgungsspannung und Masse huckepack löten, also die Pins direkt verbinden ohne Wiederstand o.ä.
Hallo!
Wenn zwei Eingänge "aneinander geraten" ist das unproblematisch. Eingänge sind hochohmig, das heißt da fließt (praktisch) kein Strom.
Wenn zwei Ausgänge "aneinander geraten" könnte es problematisch sein wenn der eine "zufällig" auf HIGH und der andere auf LOW steht. Wenn kein Widerstand dazwischen ist könnte das eher ungesund für die Teilnehmenden µCs sein.
Soviel ich weiß sind die Ports der Arduinos unmittelbar nach dem Reset erst mal alle als Eingänge konfiguriert (also hochohmig).
Wieso willst du denn deine beiden Arduinos mit so vielen Pins miteinander verbinden? Könnte es nicht reichen nur die seriellen Anschlüsse Rx/Tx kreuzweise miteinander zu verbinden? Und vielleicht noch 1 oder 2 weitere Pins zum "Handshake"?
Ok, dann muss ich wohl ein bisschen aufpassen, dass ich nicht zweimal OUTPUT-Pins verbinde.
uxomm:
Wieso willst du denn deine beiden Arduinos mit so vielen Pins miteinander verbinden? Könnte es nicht reichen nur die seriellen Anschlüsse Rx/Tx kreuzweise miteinander zu verbinden? Und vielleicht noch 1 oder 2 weitere Pins zum "Handshake"?
Gruß
Udo
Naja, ich möchte ca. 8 Bytes pro Schleifendurchlauf übertragen. Bei 9600 baud hätte ich das in ca. 6-7ms erledigt. Eigentlich hast du recht. Soviel Zeit habe ich bestimmt noch übrig in der Loop von dem Arduino der den Feuereffekt berechnet und ihn anzeigt.
Ich denke morgen kann ich mich mal dransetzen und schauen ob es auch damit geht.
Helmuth:
Muss es unbedingt eine Fernbedienung sein? Falls nicht, ist alles einfach: Du schließt ein paar (entprellte) Taster an und fragst diese nach jedem gesendetem Frame ab, manipulierst entsprechend Deine Variablen und berechnest dann das nächste Frame. Bei 48 LEDs ist selbst das aufgeblähte digitalRead() dafür schnell genug.
Andere Idee: Der zweite Arduino simuliert die Tastendrücke. Er empfängt die Signale der Fernbedienung und gibt die Taste über seine Ausgänge weiter. Der LED-Arduino sieht dann z.B. Taste "Farbe" wurde gedrückt und verändert die Farbe. So brauchst du nur die gedrückte Taste zu übertragen und keine Byte-Folge.
@Theseus
Ja, das ist auch ne gute Idee. Da denk ich nochmal drüber nach
@uxomm
Ich glaub serielle Übertragung über Rx/Tx mach ich doch nicht weil ganz am Anfang Serenifly ja geschrieben hatte, dass dazu auch Interrups verwendet werden und dann kommt wahrscheinlich wieder alles durcheinander mit den verwendeten Libs für IR-Empfang und Ansteuern der LEDs.
Ich glaub serielle Übertragung über Rx/Tx mach ich doch nicht weil ganz am Anfang Serenifly ja geschrieben hatte, dass dazu auch Interrups verwendet werden und dann kommt wahrscheinlich wieder alles durcheinander mit den verwendeten Libs für IR-Empfang und Ansteuern der LEDs.
Bin jetzt nicht sooo der Experte für zeitkritischen Code, aber man könnte die serielle Schnittstelle ja auch viel schneller betreiben als 9600 (da sparst du ein wenig Zeit) und wenn ich Serenifly richtig verstanden habe...
Man könnte dem Sende-Arduino eventuell mitteilen, dass ein Fenster zum Senden frei ist. ... Ein digitaler I/O Pin würde es da aber auch tun.
Das habe ich übrigens gemeint mit "Handshake", also der "Empfänger" signalisiert dem Empfänger wann er Zeit hat Daten zu empfangen. Wenn es nicht viele Daten sind (und davon gehe ich eigentlich aus), dann könnte sich das durchaus ausgehen und wahrscheinlich kommt dir dann nix durcheinander.
Aber wie gesagt, da bin ich nicht so der Experte.
Ich kann mir nicht vorstellen, dass eine serielle Kommunikation so viel schneller geht, als IR direkt auswerten.
Ich probiere das morgen mal mit "permanent IR Scan", falls ich in irgendeiner Kiste einen IR Receiver finde. 40 fps?! Vielleicht täusche ich mich, aber wäre doch gelacht, wenn das nicht "on the fly" mit einem Arduino geht...
@Jarny: Hast Du das schon mal ausprobiert, IR_Receive() direkt in den Fire2012 Code einzubinden? Im FastLED Beispiel wird doch ewig (temporal dithering) Zeit verschwendet ("verschwendet", weil das bei schnellen Animationen Quatsch ist - man sieht keinen Unterschied...) - der Code ist "werksseitig" auf 60 fps limitiert. Da sollte doch mit den paar LEDs noch einiges an Luft sein zwischen den Frames.
Ich glaub serielle Übertragung über Rx/Tx mach ich doch nicht weil ganz am Anfang Serenifly ja geschrieben hatte, dass dazu auch Interrups verwendet werden und dann kommt wahrscheinlich wieder alles durcheinander mit den verwendeten Libs für IR-Empfang und Ansteuern der LEDs.
Da ging es um die FastLED Lib. Nur der Teil ist wirklich zeitkritisch. Der Rest ist nicht sooo empfindlich.
Das ist zeitlich eigentlich auch klar abgegrenzt. Du willst ja nur Daten senden nachdem du ein IR Signal empfangen hast. Nicht unbedingt gleichzeitig.
Du musst nur irgendwie klarstellen dass sich das nicht mit FastLED beißt. Das könnte man mit zwei Leitungen machen. Wie herum ist eigentlich egal. Intuitiver ist vielleicht wenn der Sender meldet dass Daten zum Versand bereit sind und der Empfänger quittiert die Bereitschaft bevor sie tatsächlich gesendet werden. Zwischen Signal mit einem I/O Pin und der Antwort muss man dann lediglich ein paar µs warten um dem anderen Prozessor Zeit zu geben den Pin zu lesen und den anderen zu setzen.
Wenn dann Daten ausgetauscht werden wird kein Update der LEDs gemacht, aber das ist kein großes Problem. Du sendest ja nicht dauernd Daten, sondern nur ab und zu wenn du ein Programm umschaltest, oder?
Wenn man es einstellen kann geht seriell auch noch schneller als die 115.200 Baud die man im Serial Monitor auswählen kann. Mit einem C# Programm am PC Ende z.B. gehen problemlos 250.000 und 500.000 Baud! Mit zwei Arduinos ist das Timing der seriellen Schnittstelle vielleicht etwas kritischer, aber ausprobieren kann man es mal.