Refactor n_chase pattern for bidirectional movement

- Updated n_chase to support bidirectional movement with n3 and n4 parameters
- n3 controls forward steps per direction change
- n4 controls backward steps per direction change
- Pattern alternates between moving forward n3 steps and backward n4 steps
- Each direction repeats for the specified number of steps before switching
- Added test/9.py with n1=20, n2=20, n3=20, n4=-5 parameters
- Updated to run as a thread-based pattern similar to other patterns
This commit is contained in:
2025-10-26 20:39:28 +13:00
parent dce2954114
commit 8345b31caf
2 changed files with 128 additions and 67 deletions

View File

@@ -295,48 +295,7 @@ class Patterns(PatternBase): # Inherit from PatternBase
self.run = False self.run = False
self.running = False self.running = False
def n_chase(self):
"""Chase pattern - n1 LEDs on, n2 LEDs off, moving forward"""
self.run = True
# n1 = on width, n2 = off width
on_width = max(1, int(self.n1))
off_width = max(0, int(self.n2))
segment_length = on_width + off_width
if segment_length == 0:
segment_length = 1
# Calculate timing from delay
step_delay = max(10, int(self.delay)) # At least 10ms
step = 0
last_update = utime.ticks_ms()
color = self.apply_brightness(self.colors[0])
while self.run:
self.wdt.feed()
current_time = utime.ticks_ms()
# Move forward every step_delay ms
if utime.ticks_diff(current_time, last_update) >= step_delay:
# Clear all LEDs
self.n.fill((0, 0, 0))
# Draw the chase pattern - repeating segments across all LEDs
for i in range(self.num_leds):
pos_in_segment = (i + step) % segment_length
if pos_in_segment < on_width:
self.n[i] = color
self.n.write()
step = (step + 1) % segment_length
last_update = current_time
utime.sleep_ms(1)
self.run = False
self.running = False
# def flicker(self): # def flicker(self):
# current_time = utime.ticks_ms() # current_time = utime.ticks_ms()
@@ -372,34 +331,74 @@ class Patterns(PatternBase): # Inherit from PatternBase
# self.last_update = current_time # self.last_update = current_time
# return self.delay # return self.delay
# def n_chase(self): def n_chase(self):
# """ """Chase pattern - n1 LEDs on, n2 LEDs off, bidirectional movement"""
# A theater chase pattern using n1 for on-width and n2 for off-width. self.run = True
# """
# current_time = utime.ticks_ms()
# step_rate = max(1, int(self.n3))
# segment_length = self.n1 + self.n2
# if segment_length == 0: # Avoid division by zero
# self.fill((0,0,0))
# self.n.write()
# self.last_update = current_time
# return self.delay
# # Use controller's step for synchronization, but scale it for chasing # n1 = on width, n2 = off width
# chase_step = (self.step * step_rate) % self.num_leds on_width = max(1, int(self.n1))
off_width = max(0, int(self.n2))
segment_length = on_width + off_width
# for i in range(self.num_leds): if segment_length == 0:
# # Calculate position relative to the chase head segment_length = 1
# pos_from_head = (i - chase_step) % self.num_leds
# if pos_from_head < self.n1: # n3 = forward steps per move, n4 = backward steps per move
# self.n[i] = self.apply_brightness(self.colors[0]) forward_steps = max(1, abs(int(self.n3)))
# else: backward_steps = max(1, abs(int(self.n4)))
# self.n[i] = (0, 0, 0)
# self.n.write() # Calculate timing from delay
step_delay = max(10, int(self.delay)) # At least 10ms
position = 0 # Current position of the chase head
phase = "forward" # "forward" or "backward"
steps_remaining = forward_steps
total_steps = 0 # Track total steps for wrapping
last_update = utime.ticks_ms()
color = self.apply_brightness(self.colors[0])
while self.run:
self.wdt.feed()
current_time = utime.ticks_ms()
# Check if it's time to move
if utime.ticks_diff(current_time, last_update) >= step_delay:
# Move position based on current phase
if phase == "forward":
total_steps = (total_steps + 1) % (self.num_leds * segment_length)
position = total_steps % segment_length
steps_remaining -= 1
if steps_remaining == 0:
phase = "backward"
steps_remaining = backward_steps
else: # backward
total_steps = (total_steps - 1) % (self.num_leds * segment_length)
position = total_steps % segment_length
steps_remaining -= 1
if steps_remaining == 0:
phase = "forward"
steps_remaining = forward_steps
# Clear all LEDs
self.n.fill((0, 0, 0))
# Draw the chase pattern - repeating segments across all LEDs
# Position determines where to start drawing on the strip
for i in range(self.num_leds):
# Create repeating pattern of on_width on, off_width off
pos_in_segment = ((i + position) % segment_length)
if pos_in_segment < on_width:
self.n[i] = color
self.n.write()
last_update = current_time
utime.sleep_ms(1)
self.run = False
self.running = False
# # Don't update internal step - use controller's step for sync
# self.last_update = current_time
# return self.delay
# def alternating(self): # def alternating(self):
# # Use n1 as ON width and n2 as OFF width # # Use n1 as ON width and n2 as OFF width

62
test/n_chase/9.py Normal file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
N-chase test 9: Cyan, on=20, off=20, delay=200ms
Runs forever
Run with: mpremote run test/n_chase/9.py
"""
import patterns
import utime
from settings import Settings
from machine import WDT
print("Starting N-Chase Test 9: Cyan, on=20, off=20, delay=200ms")
print("Press Ctrl+C to stop")
# Load settings
settings = Settings()
# Initialize patterns using settings
p = patterns.Patterns(
pin=settings["led_pin"],
num_leds=settings["num_leds"],
brightness=255,
delay=200
)
# Configure test parameters
p.n1 = 20 # On width 20
p.n2 = 20 # Off width 20
p.n3 = 20 # Reserved for future use
p.n4 = -5 # Reserved for future use
p.colors = [(0, 255, 255)] # Cyan
print(f"LED Pin: {settings['led_pin']}")
print(f"LEDs: {settings['num_leds']}")
print(f"Brightness: {p.brightness}")
print(f"Delay: {p.delay}ms")
print(f"On width: {p.n1}")
print(f"Off width: {p.n2}")
print(f"n3: {p.n3}")
print(f"n4: {p.n4}")
print(f"Color: {p.colors[0]}")
# Initialize watchdog timer
wdt = WDT(timeout=10000)
wdt.feed()
# Start pattern
p.select("nc")
print("Pattern started. Running forever...")
# Run forever
try:
while True:
wdt.feed()
utime.sleep_ms(100)
except KeyboardInterrupt:
print("\nStopping...")
p.run = False
p.off()
print("LEDs turned off")