updated libraries

This commit is contained in:
stuce-bot 2025-06-30 21:41:49 +02:00
parent d5d5d000b3
commit 3b7e68065a
102 changed files with 3020 additions and 1624 deletions

View file

@ -1,112 +1,64 @@
/*
Festival Stick is a dense corkscrew of LEDs that is wrapped around one end of
a wooden walking stick commonly found on amazon.A0
Basic cork screw test.
The UI screenmap projects this cork screw into polar coordinates, so that the
LEDs are mapped to a sprial, with the inner portion of the spiral being the top,
the outer most portion being the bottom.
This test is forward mapping, in which we test that
the corkscrew is mapped to cylinder cartesian coordinates.
Most of the time, you'll want the reverse mapping, that is
drawing to a rectangular grid, and then mapping that to a corkscrew.
However, to make sure the above mapping works correctly, we have
to test that the forward mapping works correctly first.
*/
#include "fl/assert.h"
#include "fl/corkscrew.h"
#include "fl/screenmap.h"
#include "fl/warn.h"
#include "fl/sstream.h"
#include "fl/grid.h"
#include "fl/leds.h"
#include "fl/screenmap.h"
#include "fl/sstream.h"
#include "fl/warn.h"
#include "noise.h"
#include <FastLED.h>
// #include "vec3.h"
using namespace fl;
// Power management settings
#define VOLTS 5
#define MAX_AMPS 1
#define PIN_DATA 9
#define PIN_CLOCK 7
#define PIN_DATA 3
#define PIN_CLOCK 4
// Pin could have been tied to ground, instead it's tied to another pin.
#define PIN_BUTTON 1
#define PIN_GRND 2
#define NUM_LEDS 288
#define CORKSCREW_TOTAL_LENGTH 100 // 100 cm
#define CORKSCREW_TOTAL_HEIGHT \
23.25f // Total height of the corkscrew in centimeters for 144 densly
// wrapped up over 19 turns
#define CORKSCREW_TURNS 19 // Default to 19 turns
23.25 // when height = 0, it's a circle.
// wrapped up over 19 turns
#define CORKSCREW_TURNS 20.5 // Default to 19 turns
// #define CM_BETWEEN_LEDS 1.0 // 1cm between LEDs
// #define CM_LED_DIAMETER 0.5 // 0.5cm LED diameter
#define CORKSCREW_WIDTH 16
#define CORKSCREW_HEIGHT 19
UITitle festivalStickTitle("Festival Stick");
UITitle festivalStickTitle("Corkscrew");
UIDescription festivalStickDescription(
"Take a wooden walking stick, wrap dense LEDs around it like a corkscrew. "
"Super simple but very awesome looking."
"This assumes the dense 144 LEDs / meter.");
"Tests the ability to map a cork screw onto a 2D cylindrical surface");
UISlider ledsScale("Leds scale", 0.1f, 0.1f, 1.0f, 0.01f);
UIButton button("Button");
UISlider speed("Speed", 0.1f, 0.01f, 1.0f, 0.01f);
CRGB leds[NUM_LEDS];
UICheckbox allWhite("All White", false);
UICheckbox splatRendering("Splat Rendering", true);
// CRGB leds[NUM_LEDS];
// Tested on a 288 led (2x 144 max density led strip) with 19 turns
// with 23.25cm height, 19 turns, and ~15.5 LEDs per turn.
Corkscrew::Input
corkscrewInput(CORKSCREW_TOTAL_HEIGHT,
CORKSCREW_TURNS * 2.0f * PI, // Default to 19 turns
0, // offset to account for gaps between segments
NUM_LEDS, // Default to dense 144 leds.
);
Corkscrew::Input corkscrewInput(CORKSCREW_TOTAL_LENGTH, CORKSCREW_TOTAL_HEIGHT,
CORKSCREW_TURNS, NUM_LEDS, 0);
// Corkscrew::Output corkscrewMap = fl::Corkscrew::generateMap(corkscrewInput);
// Corkscrew::State corkscrewMap = fl::Corkscrew::generateMap(corkscrewInput);
Corkscrew corkscrew(corkscrewInput);
// Used only for the fl::ScreenMap generation.
struct corkscrew_args {
int num_leds = NUM_LEDS;
float leds_per_turn = 15.5;
float width_cm = 1.0;
};
fl::ScreenMap makeScreenMap(corkscrew_args args = corkscrew_args()) {
// Create a ScreenMap for the corkscrew
fl::vector<vec2f> points(args.num_leds);
int num_leds = args.num_leds;
float leds_per_turn = args.leds_per_turn;
float width_cm = args.width_cm;
const float circumference = leds_per_turn;
const float radius = circumference / (2.0 * PI); // radius in mm
const float angle_per_led = 2.0 * PI / leds_per_turn; // degrees per LED
const float height_per_turn_cm = width_cm; // 10cm height per turn
const float height_per_led = height_per_turn_cm / leds_per_turn *
1.3; // this is the changing height per led.
for (int i = 0; i < num_leds; i++) {
float angle = i * angle_per_led; // angle in radians
float r = radius + 10 + i * height_per_led; // height in cm
// Calculate the x, y coordinates for the corkscrew
float x = r * cos(angle); // x coordinate
float y = r * sin(angle); // y coordinate
// Store the 2D coordinates in the vector
points[i] = vec2f(x, y);
}
FASTLED_WARN("Creating ScreenMap with:\n" << points);
// Create a ScreenMap from the points
fl::ScreenMap screenMap(points.data(), num_leds, .5);
return screenMap;
}
// Create a corkscrew with:
// - 30cm total length (300mm)
// - 5cm width (50mm)
@ -117,96 +69,77 @@ fl::ScreenMap makeScreenMap(corkscrew_args args = corkscrew_args()) {
// fl::vector<vec3f> mapCorkScrew = makeCorkScrew(args);
fl::ScreenMap screenMap;
fl::Grid<CRGB> frameBuffer;
CLEDController *addController() {
CLEDController *controller =
&FastLED.addLeds<APA102HD, PIN_DATA, PIN_CLOCK, BGR>(leds, NUM_LEDS);
return controller;
}
void setup() {
pinMode(PIN_GRND, OUTPUT);
digitalWrite(PIN_GRND, LOW); // Set ground pin to low
button.addRealButton(Button(PIN_BUTTON));
corkscrew_args args = corkscrew_args();
screenMap = makeScreenMap(args);
// screenMap = ScreenMap::Circle(NUM_LEDS, 1.5f, 0.5f, 1.0f);
auto controller = addController();
int width = corkscrew.cylinder_width();
int height = corkscrew.cylinder_height();
frameBuffer.reset(width, height);
XYMap xyMap = XYMap::constructRectangularGrid(width, height, 0);
CRGB *leds = frameBuffer.data();
size_t num_leds = frameBuffer.size();
CLEDController* controller = &FastLED.addLeds<APA102HD, PIN_DATA, PIN_CLOCK, BGR>(leds, NUM_LEDS);
// CLEDController *controller =
// &FastLED.addLeds<WS2812, 3, BGR>(leds, num_leds);
fl::ScreenMap screenMap = xyMap.toScreenMap();
screenMap.setDiameter(.2f);
// Set the screen map for the controller
controller->setScreenMap(screenMap);
// Set power management. This allows this festival stick to conformatable
// run on any USB battery that can output at least 1A at 5V.
// Keep in mind that this sketch is designed to use APA102HD mode, which
// will result in even lowwer run power consumption, since the power mode
// does not take into account the APA102HD gamma correction. However it is
// still a correct upper bound that will match the ledset exactly when the
// display tries to go full white.
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, MAX_AMPS * 1000);
button.onChanged([](UIButton &but) {
// This function is called when the button is pressed
// If the button is pressed, show the generative pattern
if (but.isPressed()) {
FASTLED_WARN("Button pressed");
} else {
FASTLED_WARN("NOT Button pressed");
}
});
}
void printOutput(const Corkscrew::Output& output) {
fl::sstream stream;
stream << "Corkscrew Output:\n";
stream << "Width: " << output.width << "\n";
stream << "Height: " << output.height << "\n";
// stream << "Mapping: \n";
// for (const auto &point : output.mapping) {
// stream << point << "\n";
// }
FASTLED_WARN(stream.str());
}
LedsXY<CORKSCREW_WIDTH, CORKSCREW_HEIGHT> frameBuffer;
void loop() {
uint32_t now = millis();
fl::clear(leds);
// fl::clear(lesdds);
fl::clear(frameBuffer);
static int w = 0;
static float pos = 0;
EVERY_N_MILLIS(300) {
// Update the corkscrew mapping every second
w = (w + 1) % CORKSCREW_WIDTH;
// Update the corkscrew mapping every second
// w = (w + 1) % CORKSCREW_WIDTH;
// frameBuffer.
pos += speed.value();
if (pos > corkscrew.size() - 1) {
pos = 0; // Reset to the beginning
}
// draw a blue line down the middle
for (int i = 0; i < CORKSCREW_HEIGHT; ++i) {
frameBuffer.at(w % CORKSCREW_WIDTH, i) = CRGB::Blue;
frameBuffer.at((w + 1) % CORKSCREW_WIDTH, i) = CRGB::Blue;
frameBuffer.at((w - 1 + CORKSCREW_WIDTH) % CORKSCREW_WIDTH, i) = CRGB::Blue;
frameBuffer.at((w + 2) % CORKSCREW_WIDTH, i) = CRGB::Blue;
frameBuffer.at((w - 2 + CORKSCREW_WIDTH) % CORKSCREW_WIDTH, i) = CRGB::Blue;
if (allWhite) {
for (size_t i = 0; i < frameBuffer.size(); ++i) {
frameBuffer.data()[i] = CRGB(8, 8, 8);
}
}
if (splatRendering) {
Tile2x2_u8_wrap pos_tile = corkscrew.at_wrap(pos);
const CRGB color = CRGB::Blue;
// Draw each pixel in the 2x2 tile using the new wrapping API
for (int dx = 0; dx < 2; ++dx) {
for (int dy = 0; dy < 2; ++dy) {
auto data = pos_tile.at(dx, dy);
vec2i16 wrapped_pos = data.first; // Already wrapped position
uint8_t alpha = data.second; // Alpha value
// printOutput(corkscrewMap);
for (int i = 0; i < NUM_LEDS; ++i) {
// Get the position in the frame buffer
vec2<int16_t> pos = corkscrew.at(i);
// Draw the tile to the frame buffer
CRGB c = frameBuffer.at(pos.x, pos.y);
leds[i] = c;
FASTLED_WARN_IF(i < 16, "LED " << i << " at position: "
<< pos.x << ", " << pos.y
<< " with color: " << c);
if (alpha > 0) { // Only draw if there's some alpha
CRGB c = color;
c.nscale8(alpha); // Scale the color by the alpha value
frameBuffer.at(wrapped_pos.x, wrapped_pos.y) = c;
}
}
}
} else {
// None splat rendering, looks aweful.
vec2f pos_vec2f = corkscrew.at_exact(pos);
vec2i16 pos_i16 = vec2i16(round(pos_vec2f.x), round(pos_vec2f.y));
// Now map the cork screw position to the cylindrical buffer that we
// will draw.
frameBuffer.at(pos_i16.x, pos_i16.y) =
CRGB::Blue; // Draw a blue pixel at (w, h)
}
FastLED.show();
}