Add Pico presets engine, patterns, and tests.
Wire the Pico to UART-driven preset selection, add pattern modules and presets data, remove old p2p/settings code, and update tests and LED driver. Made-with: Cursor
This commit is contained in:
98
pico/src/patterns/spin.py
Normal file
98
pico/src/patterns/spin.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""Spin: continues from Grab — segment (10 each side of center) moves slowly up to the top. Preset color, n1 = rate."""
|
||||
|
||||
import utime
|
||||
|
||||
SPAN = 10 # LEDs on each side of center (match Grab)
|
||||
LUT_SIZE = 256 # gradient lookup table entries
|
||||
|
||||
|
||||
class Spin:
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
|
||||
def run(self, preset):
|
||||
strips = self.driver.strips
|
||||
active_indices = (0, 4)
|
||||
c0 = preset.c[0]
|
||||
c1 = preset.c[1]
|
||||
|
||||
# Precompute gradient LUT: t in [0,1] maps to (r,g,b)
|
||||
lut = []
|
||||
for k in range(LUT_SIZE):
|
||||
t = k / (LUT_SIZE - 1) if LUT_SIZE > 1 else 1
|
||||
r = int(c0[0] + (c1[0] - c0[0]) * t)
|
||||
g = int(c0[1] + (c1[1] - c0[1]) * t)
|
||||
b = int(c0[2] + (c1[2] - c0[2]) * t)
|
||||
lut.append((r, g, b))
|
||||
|
||||
# For each active strip we expand from just outside the grab center
|
||||
# left: from (mid - SPAN) down to 0
|
||||
# right: from (mid + SPAN) up to end
|
||||
midpoints = self.driver.strip_midpoints
|
||||
rate = max(1, int(preset.n1) or 1)
|
||||
delay_ms = max(1, int(preset.d) or 1)
|
||||
margin = max(0, int(preset.n2) or 0)
|
||||
|
||||
# Track current extents of each arm
|
||||
left = {}
|
||||
right = {}
|
||||
for idx in active_indices:
|
||||
if 0 <= idx < len(strips):
|
||||
mid = midpoints[idx]
|
||||
left[idx] = mid - SPAN # inner edge of left arm
|
||||
right[idx] = mid + SPAN + 1 # inner edge of right arm
|
||||
|
||||
last_update = utime.ticks_ms()
|
||||
|
||||
while True:
|
||||
now = utime.ticks_ms()
|
||||
if utime.ticks_diff(now, last_update) < delay_ms:
|
||||
yield
|
||||
continue
|
||||
last_update = now
|
||||
|
||||
for idx in active_indices:
|
||||
if idx < 0 or idx >= len(strips):
|
||||
continue
|
||||
strip = strips[idx]
|
||||
n = strip.num_leds
|
||||
mid = midpoints[idx]
|
||||
|
||||
# Expand arms: inside (strip 1, idx 0) moves slower, outside (strip 5, idx 4) faster
|
||||
step = max(1, rate // 2) if idx == 0 else rate
|
||||
new_left = max(margin, left[idx] - step)
|
||||
new_right = min(n - margin, right[idx] + step)
|
||||
|
||||
# Left arm: c1 at outer, c0 at inner. Right arm: c0 at inner, c1 at outer.
|
||||
left_len = max(0, (mid - SPAN) - new_left)
|
||||
right_len = max(0, new_right - (mid + SPAN + 1))
|
||||
bright = strip.brightness
|
||||
ar = strip.ar
|
||||
|
||||
for j, i in enumerate(range(new_left, mid - SPAN)):
|
||||
if 0 <= i < n:
|
||||
t = 1 - j / (left_len - 1) if left_len > 1 else 0
|
||||
lut_idx = min(int(t * (LUT_SIZE - 1)), LUT_SIZE - 1)
|
||||
r, g, b = lut[lut_idx]
|
||||
base = i * 3
|
||||
ar[base] = int(g * bright)
|
||||
ar[base + 1] = int(r * bright)
|
||||
ar[base + 2] = int(b * bright)
|
||||
|
||||
for j, i in enumerate(range(mid + SPAN + 1, new_right)):
|
||||
if 0 <= i < n:
|
||||
t = j / (right_len - 1) if right_len > 1 else 0
|
||||
lut_idx = min(int(t * (LUT_SIZE - 1)), LUT_SIZE - 1)
|
||||
r, g, b = lut[lut_idx]
|
||||
base = i * 3
|
||||
ar[base] = int(g * bright)
|
||||
ar[base + 1] = int(r * bright)
|
||||
ar[base + 2] = int(b * bright)
|
||||
|
||||
left[idx] = new_left
|
||||
right[idx] = new_right
|
||||
|
||||
# Show only on this strip
|
||||
strip.show()
|
||||
|
||||
yield
|
||||
Reference in New Issue
Block a user