Processing FFT flackert auf LED-Panel

Moin!

So habe mir letztens ein Arduino gekauft um jetzt auch mal in den Genuss zu kommen.
Jetzt wollte ich zu Beginn mit einem Audio Equalizer beginnen.

Der Equalizer an sich funktioniert schon. Bestehend aus einem Processing-Programm, das die Werte an den Arduino schickt und dem Arduino-Programm, das die Werte auf einem WS2801 ausgibt.

Mein Processing-Programm basiert auf dem ersten Codebeispiel hier von:

Das Problem das ich jetzt habe:
Die LEDs "flackern". Das liegt daran, dass die Berechnungen immer sehr schnell wechseln und die werte für wirklich Millisekunden unter den Schwellwert fallen.

Hat jemand eine Idee, wie man die Animation etwas glätten kann?

Bei Bedarf kann ich auch ein kurzes Video aufnehmen, falls sich jemand das Flackern nicht vorstellen kann.

Vielen Dank schon einmal!

MfG

Mir würde der Sketch des Arduinos vermutlich reichen.

Wie gesagt, am Arduino Sketch liegt es nicht.

void loop() {  
  if (Serial.available() >= 7) {
     bar1 = Serial.read()-48;
     bar2 = Serial.read()-48;
     bar3 = Serial.read()-48;
     bar4 = Serial.read()-48;
     bar5 = Serial.read()-48;
     bar6 = Serial.read()-48;
     bar7 = Serial.read()-48;
  }

  for (int i = 0; i<bar1;i++){ strip.setPixelColor(i,0,  255, 0, 0); }
  for (int i = 0; i<bar2;i++){ strip.setPixelColor(i,1,  0, 255, 0); }
  for (int i = 0; i<bar3;i++){ strip.setPixelColor(i,2,  0, 0, 255); }
  for (int i = 0; i<bar4;i++){ strip.setPixelColor(i,3,  0, 0, 255); }
  for (int i = 0; i<bar5;i++){ strip.setPixelColor(i,4,  0, 0, 255); }
  for (int i = 0; i<bar6;i++){ strip.setPixelColor(i,5,  0, 0, 255); }
  for (int i = 0; i<bar7;i++){ strip.setPixelColor(i,6,  0, 0, 255); }
}

Processing schickt einen String mit 7 Zahlen und Arduino wertet diesen aus.
In meinem Processing-Sketch sieht es in etwa so aus:

for (int i=1; i <= buffer.length; i+=buffer.length/grid) {
float x = map(i, 0, buffer.length, 0, width);
float y = map(buffer[i-1]*yScale, -1, 1, 0, height) ;
fill (102, 145, 250,100);
rect(x+spacing, height, width/grid-2*spacing, -y);
int extra = 2;
if(y < 200+extra) { out = out + 0; }
else if(y < 230+extra) { out = out + 1; }
else if(y < 260+extra) { out = out + 2; }
else if(y < 290+extra) { out = out + 3; }
else if(y < 320+extra) { out = out + 4; }
else if(y < 350+extra) { out = out + 5; }
else if(y < 380+extra) { out = out + 6; }
else { out = out + 7; }

}
port.write(out);

Die Werte des FFT fallen immer kurz unter 0 und werden zum Arduino gesendet, danach gehen sie wieder hoch.
Es muss also irgendwie das Processing-Sketch geglättet werden.
ALso diese kurzen Negativwerte müssen irgendwie raus.

Hallo,

ist das die Adafruit Libary? Kenne mich mit der nicht aus, nutzte selber nur die FastLED.
Könntest du kurz erklären, welche Werte er hier erwartet

strip.setPixelColor(i,0,  255, 0, 0);

i wird hier vermutlich die Led sein, jedoch ist mir die erste 0 nicht bekannt. Die anderen Werte entsprechen höchstwarscheinlich RGB.

Kannst du negative Zahlen nicht einfach filtern? Desweiteren sehe ich den Arduino Sketch nicht als optimal an. Es ist nicht sinnvoll, die Leds durchgehen zu beschreiben. Es macht mehr Sinn, die Leds nur neuzubeschreiben, wenn sich etwas geändert hat.

Das ist nicht der vollständige Sketch, dieser würde nämlich nicht flackern, da die LEDs gar nie zurückgesetzt werden.

Ja wie gesagt, kenne mich mit der Libary nicht aus. Aber wie du schreibst, ist das Prinzip somit ähnlich der FastLed. Bei der werden die Daten auch in einem Struct/Array gesammelt und auf einen Befehl (-> bestimmte Funktion) erst an die Strips gesendet.

Bei der werden die Daten auch in einem Struct/Array gesammelt und auf einen Befehl (-> bestimmte Funktion) erst an die Strips gesendet.

Ich kenne die Bibliothek auch nicht, aber selbst wenn der Befehl direkt etwas an den Strip schicken würde (was ich bezweifle), werden die LEDs nicht zurückgesetzt. Es fehlt auf jeden Fall Code. Darum einmal mehr: Postet immer vollständigen Code, mit solchen Ausschnitten verschwendet Ihr nur unsere Zeit.

Ja es ist die Adafruit Library und setPixelColor hat die Parameter (x,y,R,G,B)
Es liegt aber zu 100% nicht am Arduino-Sketch, sondern am Processing-Sketch.
Und es ist ja kein wirklicher Fehler, da ich weiß, dass der Processing-Sketch die "unschönen" Werte an den Arduino sendet.
Trotzdem hier noch einmal der komplette Code:

#include "SPI.h"
#include "Adafruit_WS2801.h"
#include "string.h"

#define MAX_STRING_LEN 20

uint8_t dataPin  = 2;    // Yellow wire on Adafruit Pixels
uint8_t clockPin = 3;    // Green wire on Adafruit Pixels

Adafruit_WS2801 strip = Adafruit_WS2801((uint16_t)7, (uint16_t)7, dataPin, clockPin);

  int input;
  int bar1,bar2,bar3,bar4,bar5,bar6,bar7=0;
  
void setup() {
  Serial.begin(9600);
  strip.begin();
  strip.show();
}


void loop() {  
  if (Serial.available() >= 7) {
     bar1 = Serial.read()-48;
     bar2 = Serial.read()-48;
     bar3 = Serial.read()-48;
     bar4 = Serial.read()-48;
     bar5 = Serial.read()-48;
     bar6 = Serial.read()-48;
     bar7 = Serial.read()-48;
  }
  rainbow(2);
}

void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( (i + j) % 255));
        if (Serial.available() >= 7) {
         bar1 = Serial.read()-48;
         bar2 = Serial.read()-48;
         bar3 = Serial.read()-48;
         bar4 = Serial.read()-48;
         bar5 = Serial.read()-48;
         bar6 = Serial.read()-48;
         bar7 = Serial.read()-48;
        }
    }  
      //clear not used leds
    for (int i = bar1; i<7;i++){ strip.setPixelColor(i,0,  0, 0, 0); }
    for (int i = bar2; i<7;i++){ strip.setPixelColor(i,1,  0, 0, 0); }
    for (int i = bar3; i<7;i++){ strip.setPixelColor(i,2,  0, 0, 0); }
    for (int i = bar4; i<7;i++){ strip.setPixelColor(i,3,  0, 0, 0); }
    for (int i = bar5; i<7;i++){ strip.setPixelColor(i,4,  0, 0, 0); }
    for (int i = bar6; i<7;i++){ strip.setPixelColor(i,5,  0, 0, 0); }
    for (int i = bar7; i<7;i++){ strip.setPixelColor(i,6,  0, 0, 0); }
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

void rainbowCycle(uint8_t wait) {
  int i, j;
  for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

uint32_t Color(byte r, byte g, byte b)
{
  uint32_t c;
  c = r;
  c <<= 8;
  c |= g;
  c <<= 8;
  c |= b;
  return c;
}

uint32_t Wheel(byte WheelPos)
{
  if (WheelPos < 85) {
   return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
   WheelPos -= 85;
   return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170; 
   return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

Es liegt aber zu 100% nicht am Arduino-Sketch, sondern am Processing-Sketch.

Das Problem ist, dass Dein Processing-Sketch auch nicht vollständig ist. Aus dem vorliegenden Code würde ich auf einen Überlauf tippen (Werte 0-7, Arduino kann aber nur 0-7 verarbeiten), aber das ist nicht viel mehr als geraten.

Sind vll ein paar komische Zeilen grad drin, da ich momentan mit dem Code rumspiele.
Processing:

import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.serial.*;

Serial port;
Minim minim;
AudioInput input;

int x, y;
int grid=7;
int spacing=1;
String out;
float yScale = 3;
int last[] = {0,0,0,0,0,0,0};

float smoothing = 0;
int specSize;
 
void setup() {
port = new Serial(this, Serial.list()[1], 9600);
size(1024, 400);
smooth();
noStroke();

minim = new Minim(this);
input = minim.getLineIn();

}
 
void draw() {    
fill(50, 10);
rect(0, 0, width, height);
 
float[] buffer = input.mix.toArray();
 out = "";
int nr = 0;
for (int i=1; i <= buffer.length; i+=buffer.length/grid) {
float x = map(i, 0, buffer.length, 0, width);
float y = map(buffer[i-1]*yScale, -1, 1, 0, height) ;
fill (102, 145, 250,100);
rect(x+spacing, height, width/grid-2*spacing, -y);
int rounded = round(buffer[i-1]*1000)+10;
int extra = 2;

if(y < 200+extra) { out = out + 0; }
else if(y < 230+extra) { out = out + 1; }
else if(y < 260+extra) { out = out + 2; }
else if(y < 290+extra) { out = out + 3; }
else if(y < 320+extra) { out = out + 4; }
else if(y < 350+extra) { out = out + 5; }
else if(y < 380+extra) { out = out + 6; }
else { out = out + 7; }
}
//println(out);
port.write(out);
}
 
void stop()
{
input.close();
minim.stop();
 
super.stop();
}

Meine Vermutung war richtig, Du lieferst die Ziffern 0 bis 7 zurück, auf Arduino-Seite ziehst Du dann einfach ASCII 48 (='0') ab, was bei einer '7' einen Zahlwert 7 ergibt. Da Dein Strip auf eine Grösse von 7 definiert ist, ergibt ein Index von 7 einen Überlauf auf die nächste Spalte (Vermutung, ich kenne die Adafruit-Bibliothek nicht). Auf jeden Fall sind die Dimensionen auf PC- (8) und Arduino-Seite (7) nicht übereinstimmend.

Stimmt.
Ist ein Fehler, ändert aber nichts an meinem Problem.
Wenn ich einfach verhindere, dass der Processing-Sketch eine 7 rausschickt, dann habe ich noch weiterhin das selbe Problem

Ich bin soweit, dass ich dieses Flackern mal sehen möchte :slight_smile:

So ich hoffe, dass man das leichte Flackern im Video erkennen kann.
Hier ist der Link:

Was eventuell noch interessant sein könnte:
Die Werte die der Processing-Sketch berechnet.

111/183/322/178/60/237/401/185/ 00500270
111/183/322/178/60/237/401/185/ 00500270
111/183/322/178/60/237/401/185/ 00500270
232/340/225/39/119/233/336/271/ 25100253
232/340/225/39/119/233/336/271/ 25100253
269/195/155/105/303/245/239/188/ 30004220
169/147/216/224/263/68/221/218/ 00113011
264/148/231/120/230/136/157/193/ 30101000
264/148/231/120/230/136/157/193/ 30101000
178/194/203/112/198/177/242/211/ 00100021
178/194/203/112/198/177/242/211/ 00100021
178/194/203/112/198/177/242/211/ 00100021
194/183/172/218/213/202/203/235/ 00011112
187/171/242/234/215/216/164/223/ 00221101
187/171/242/234/215/216/164/223/ 00221101
187/171/242/234/215/216/164/223/ 00221101

Die ersten 8 Werte sind durch eine FFT berechnet. Die lange Zahl am Ende ist der String den ich zum Arduino sende.
Diese Werte springen einfach etwas zu viel. Sie werden momentan ja in jedem Loop geschickt.

Ich glaube fast, dass sowas hier meine Lösung seien könnte:
http://forum.processing.org/two/discussion/1836/how-to-smooth-audio-fft-data/p1

//edit:

Habe jetzt eine "halbwegs" saubere Lösung.
Ich speichere alle Daten in einem Array und beim nächsten Aufruf sorge ich dafür, dass der Balken maximal um 1 LED abfallen darf. In Kombination mit einem kleinen Delay sieht es jetzt auch (übergangsweise) brauchbar aus.

Kannst du dir mal die gesendeten Daten auf das Terminal ausgeben? Ich kann mir vorstellen, dass die Serielle Schnittstelle hier nicht mitspielt.

Wie meinst du das? Auf das Terminal ausgeben?

Über die Serielle Schnittstelle die Werte formatiert ausgeben auf Putty oder Serial Monitor.

Sorry, war die letzte Woche nicht da.

Hm das müsstest du mir mal genauer erklären.
Das sind die Werte die ich so hab ausgeben lassen:
print(round(y)+"/");

Aber wie gesagt, mittlerweile funktioniert es ja wie es soll.
Die Werte haben wirklich nur zu viel geschwankt