Files
led-hoop/pico/src/patterns/spin.py
jimmy 5f457b3ae7 Refine calibration, chase, and spin patterns and add spin test
Increase calibration brightness, update chase to use the new logical ring abstraction, and make spin start from a cleared frame with symmetric arm speed, alongside a dedicated on-device spin test script.

Made-with: Cursor
2026-03-05 23:41:25 +13:00

102 lines
3.6 KiB
Python

"""Spin: continues from Grab — segment (10 each side of center) moves slowly up to the top. Preset color, n1 = rate."""
import utime
SPAN = 0 # 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
self.driver.fill((0, 0, 0))
self.driver.show_all()
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 at the same rate on both sides
step = max(1, 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