diff --git a/firmware/include/app.h b/firmware/include/app.h index bfeeb21..d8cacfb 100644 --- a/firmware/include/app.h +++ b/firmware/include/app.h @@ -13,6 +13,13 @@ struct BeatDetectApp : public App { }; +struct QuarterApp : public App { + void init(); + void deinit(); + void loop(); +}; + + struct VuMeterApp: public App { void init(); void deinit(); @@ -31,8 +38,10 @@ struct FackelApp: public App { void loop(); }; -struct ImageDisplayApp: public App { +/** + * struct ImageDisplayApp: public App { void init(); void deinit(); void loop(); -}; \ No newline at end of file +}; +**/ \ No newline at end of file diff --git a/firmware/src/applications/image_display.cpp b/firmware/src/applications/image_display.cpp.backup similarity index 100% rename from firmware/src/applications/image_display.cpp rename to firmware/src/applications/image_display.cpp.backup diff --git a/firmware/src/applications/quarter.cpp b/firmware/src/applications/quarter.cpp new file mode 100644 index 0000000..24347fc --- /dev/null +++ b/firmware/src/applications/quarter.cpp @@ -0,0 +1,295 @@ +#include + +#include "app.h" +#include "biquad.h" +#include "pt1.h" +#include "zauberstab.h" + +#undef NUM_LEDS +#define NUM_LEDS 48 + +#define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second +#define SAMPLING_FREQUENCY_CONTROL \ + 1 // check number of times per second if the current band pass is the best + // one +#define Q 30. // quality factor of band pass filters +#define PI 3.1415926535897932384626433832795 +#define n_BP 40 // number of band pass filters + +static const unsigned long sampling_period_bp = 1000000L / SAMPLING_FREQUENCY_BP; +static const unsigned long sampling_period_control = 1000000L / SAMPLING_FREQUENCY_CONTROL; +static float energy = 0; +static unsigned long last_us_bp = 0L; +static unsigned long last_us_control = 0L; + +static Biquad bp_filters[n_BP]; +static Pt1 y_filter[n_BP]; +static Pt1 pos_filter{1.f, 1.f}; + +static float yy1[n_BP]; +static float yy2[n_BP]; +static float yy3[n_BP]; +static float yy4[n_BP]; +static float yy5[n_BP]; +static float yy6[n_BP]; +static float y[n_BP]; +static float y_fil[n_BP]; + +static float angle; +static float angle_pre = 0.1; +//static float angle2; + +// static double energy_fil = 800.; + +//static float pos_target = NUM_LEDS / 2; +//static float pos_target_filtered = NUM_LEDS / 2; +static long initial_time; + +static int active = 15; +static int rounds = 0; +static int n_samples = 0; + +static int beat_count = 1; +static int quarter = 0; + +static int quarter_color_h1 = 30; +static int quarter_color_s = 255; +static int quarter_color_v = 50; + + +//modus 0: farbverlauf, farben wechseln alle 4 beats +//modus 1: konstante farbe, wechselt bei jedem beat +static int modus = 0; + + + +static int get_value(int pos, int quarter, int beat_count, char component) +{ + + + + + if (pos < NUM_LEDS*quarter/3) + { + if (component == 'h') + { + if (modus == 0) + { + + + int color = quarter_color_h1 + 50*pos/NUM_LEDS; + + return color%255; + } + + return quarter_color_h1; + + } + if (component == 's') + { + return quarter_color_s; + } + if (component == 'v') + { + return quarter_color_v; + } + } + return 0; +} + +static void +set_filter() +{ + for (int i = 0; i < n_BP; i++) + { + float frequency = 1.75 + i * (2.5 - 1.75) / n_BP; + float a, a0, a1, a2, b0, b1, b2, w0; + w0 = 2. * PI * frequency / SAMPLING_FREQUENCY_BP; + a = sin(w0 / (2. * Q)); + b0 = a; + b1 = 0.f; + b2 = -a; + a0 = 1.f + a; + a1 = -2.f * cos(w0); + a2 = 1.f - a; + bp_filters[i] = Biquad{a0, a1, a2, b0, b1, b2}; + y_filter[i] = Pt1{1.f, 1.f}; + } +} + +void QuarterApp::init() +{ + set_filter(); + initial_time = micros(); + active = 15; + rounds = 0; + n_samples = 0; + + pos_filter.reset(); + + for (int i = 0; i sampling_period_bp) + { + + n_samples = 0; + last_us_bp = micros(); + // energy_fil += (energy - energy_fil) * 0.01; + + for (int i = 0; i < n_BP; i++) + { + y[i] = bp_filters[i].update(energy); + yy6[i] = yy5[i]; + yy5[i] = yy4[i]; + yy4[i] = yy3[i]; + yy3[i] = yy2[i]; + yy2[i] = yy1[i]; + yy1[i] = y[i]; + y_fil[i] = y_filter[i].update(std::abs(y[i]), + 0.005f); // linie der scheitelpunkte + // y_fil[i] += (abs(y[i]) - y_fil[i]) * 0.005; //linie der + // scheitelpunkte + + } + + + float delays = constrain(SAMPLING_FREQUENCY_BP * 0.25 / (1.75 + active * (2.5 - 1.75) / n_BP), + 4., 6.); + + float delayed = 0; + if (delays > 5) + { + delayed = yy5[active] * (1 - delays + 5) + yy6[active] * (delays - 5); + } + else + { + delayed = yy4[active] * (1 - delays + 4) + yy5[active] * (delays - 4); + } + + + + angle = atan2(delayed, y[active]); + + + + + + //every beat + if (angle > 0 and angle_pre <= 0) + { + + //mode 1 logic if active + if (modus == 1) + { + quarter_color_h1 += 15; + quarter_color_h1 = quarter_color_h1%255; + quarter_color_s = 255; + } + + quarter = beat_count%4; + + //every 4 beats + if (quarter == 0) + { + + //mode 2 logic if active + if (modus == 2) + { + quarter_color_s = 0; + } + else + { + quarter_color_s = 255; + } + + + //mode 0 logic if active + if (modus == 0) + { + quarter_color_h1 += 10; + quarter_color_h1 = quarter_color_h1%255; + } + + } + + // state machine + beat_count++; + if (beat_count > 15) + { + beat_count = 0; + } + + if (beat_count == 0) + { + modus ++; + if (modus > 2) + { + modus = 0; + } + } + + } + + + + angle_pre = angle; + + + + energy = 0; + + for (int i = 0; i < NUM_LEDS; i++) + { + + int h = get_value(i, quarter, beat_count, 'h'); + int s = get_value(i, quarter, beat_count, 's'); + int v = get_value(i, quarter, beat_count, 'v'); + + leds[i].setHSV(h, s, v); + + } + FastLED.show(); + } + + if (micros() - last_us_control > sampling_period_control) + { + last_us_control = micros(); + int argmax = -1; + float valuemax = 0; + for (int i = 0; i < n_BP; i++) + { + if (y_fil[i] > valuemax) + { + valuemax = y_fil[i]; + argmax = i; + } + } + + if (argmax != active) + { + rounds ++; + } + + if (rounds > 5) + { + active = argmax; + rounds = 0; + } + + } +} diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index af40db5..bc7e6e9 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -6,19 +6,18 @@ struct BeatDetectApp beat_detect_app { }; -struct VuMeterApp vu_meter_app -{ -}; -struct FFTTestApp fft_test_app +struct QuarterApp quarter_app { }; + struct FackelApp fackel_app { }; -struct ImageDisplayApp image_display {}; + std::vector> apps = { + std::ref(quarter_app), std::ref(beat_detect_app), std::ref(fackel_app), //std::ref(image_display), diff --git a/inventor/OldVersions/lasercutter.0003.dwg b/inventor/OldVersions/lasercutter.0003.dwg new file mode 100644 index 0000000..49b8eb3 Binary files /dev/null and b/inventor/OldVersions/lasercutter.0003.dwg differ diff --git a/inventor/lasercutter.dwg b/inventor/lasercutter.dwg index 49b8eb3..cddce40 100644 Binary files a/inventor/lasercutter.dwg and b/inventor/lasercutter.dwg differ diff --git a/inventor/lasercutter.pdf b/inventor/lasercutter.pdf index 8c9d474..d776639 100644 Binary files a/inventor/lasercutter.pdf and b/inventor/lasercutter.pdf differ diff --git a/inventor2/OldVersions/lasercutter.0002.dwg b/inventor2/OldVersions/lasercutter.0002.dwg deleted file mode 100644 index 525bb15..0000000 Binary files a/inventor2/OldVersions/lasercutter.0002.dwg and /dev/null differ diff --git a/inventor2/OldVersions/lasercutter.0003.dwg b/inventor2/OldVersions/lasercutter.0003.dwg new file mode 100644 index 0000000..1951f91 Binary files /dev/null and b/inventor2/OldVersions/lasercutter.0003.dwg differ diff --git a/inventor2/lasercutter.dwg b/inventor2/lasercutter.dwg index 1951f91..2883e3e 100644 Binary files a/inventor2/lasercutter.dwg and b/inventor2/lasercutter.dwg differ diff --git a/inventor2/lasercutter.pdf b/inventor2/lasercutter.pdf deleted file mode 100644 index 3f2c16d..0000000 Binary files a/inventor2/lasercutter.pdf and /dev/null differ diff --git a/inventor2/zubehoer/OldVersions/batteriehalter.0004.ipt b/inventor2/zubehoer/OldVersions/batteriehalter.0004.ipt new file mode 100644 index 0000000..49419ac Binary files /dev/null and b/inventor2/zubehoer/OldVersions/batteriehalter.0004.ipt differ diff --git a/inventor2/zubehoer/batteriehalter.ipt b/inventor2/zubehoer/batteriehalter.ipt new file mode 100644 index 0000000..6a7cd88 Binary files /dev/null and b/inventor2/zubehoer/batteriehalter.ipt differ diff --git a/inventor2/zubehoer/batteriehalter.stl b/inventor2/zubehoer/batteriehalter.stl new file mode 100644 index 0000000..acac274 Binary files /dev/null and b/inventor2/zubehoer/batteriehalter.stl differ diff --git a/make_artikel/fritzing/fritzing.fzz b/make_artikel/fritzing/fritzing.fzz index ffb1cd7..bc36e3b 100644 Binary files a/make_artikel/fritzing/fritzing.fzz and b/make_artikel/fritzing/fritzing.fzz differ diff --git a/make_artikel/fritzing/fritzing_bb.png b/make_artikel/fritzing/fritzing_bb.png new file mode 100644 index 0000000..da0939d Binary files /dev/null and b/make_artikel/fritzing/fritzing_bb.png differ diff --git a/make_artikel/gesamt.md b/make_artikel/gesamt.md index 677b8c1..eff4a1d 100644 --- a/make_artikel/gesamt.md +++ b/make_artikel/gesamt.md @@ -45,7 +45,7 @@ Der zweite Trick ist eine kreative Verwendung des Vasenmodus. Auf den ersten Bli [Erklärbox] Beim 3D-Druck gibt es eine spezielle Druckmethode namens "Vase Mode", die es ermöglicht, hohle Objekte zu drucken. Der Vasenmodus funktioniert so, dass der Drucker nur die äußere Kontur des zu druckenden Objekts aufbaut. Dabei bewegt sich der Druckkopf in einer Spirale nach oben. Dadurch entsteht eine hohle Form, die oft einem Gefäß oder einer Vase ähnelt. Der Vorteil dieser Methode ist, dass sie sehr schnell ist, da nur die äußere Schicht des Objekts gedruckt werden muss. Außerdem spart es Material, da das Innere des Objekts leer bleibt. Das macht den Vasenmodus ideal für den Druck von dekorativen Objekten wie Vasen oder Lampenschirmen. Es gibt jedoch auch Nachteile: Da das Objekt hohl ist, kann es schwierig sein, es stabil genug zu drucken, besonders wenn es groß ist. Außerdem ist das Objekt nur von einer Seite zugänglich, was die Reinigung und Nachbearbeitung erschweren kann. -Wir nutzen hier die Definition einer Vase aus. Der Slicer fährt auf jeder Lage sturr die äußere Kontur ab. "Außere Kontur" ist hier rein mathematisch definiert. Indem wir einen Volumenkörper von außen dünn einschlitzen, können wir also auch im Innenraum des Eis einen Tunnel für die LED-stripes erzeugen. Das ist in den Abbildungen (vase mode 1) und (vase mode 2) illustriert. +Wir nutzen hier die Definition einer Vase aus. Der Slicer fährt auf jeder Lage stur die äußere Kontur ab. "Außere Kontur" ist hier rein mathematisch definiert. Indem wir einen Volumenkörper von außen dünn einschlitzen, können wir also auch im Innenraum des Eis einen Tunnel für die LED-stripes erzeugen. Das ist in den Abbildungen (vase mode 1) und (vase mode 2) illustriert. ![vase mode 1](grafiken/illustrationen/vase_cad.PNG "Geometrie wie sie im CAD definiert ist") @@ -136,7 +136,10 @@ Wenn der schnelle Tiefpass mindestens 15% über dem langsamen Tiefpass liegt, da ![elektronik 2](grafiken/kitchen_bilder/DSC07982.JPG "Einschieben der LED-Streifen") 12) Spiele die Software auf den ESP, z.B. mit Visual Studio Code und der Erweiterung PlatformIO. -13) Verlöte Mikrofon, ESP, Beschleunigungssensor, Spannungsversorgung und die Anschlussleitungen für die LEDs gemäß der Darstellung (Todo). +13) Verlöte Mikrofon, ESP, Beschleunigungssensor, Spannungsversorgung und die Anschlussleitungen für die LEDs gemäß der Darstellung. + +![elektronik 3](fritzing/fritzing_bb.png "Fritzing") + 14) Montiere die gelöteten Teile auf dem gelochten Holzbrett, z.B. mit Hilfe von dünnen Kabelbindern und Heißkleber. 15) Lade den Akkupack, schließe und schalte ihn an.