updated libraries
This commit is contained in:
parent
d5d5d000b3
commit
3b7e68065a
102 changed files with 3020 additions and 1624 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue