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.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):
# current_time = utime.ticks_ms()
@@ -372,34 +331,74 @@ class Patterns(PatternBase): # Inherit from PatternBase
# self.last_update = current_time
# return self.delay
# def n_chase(self):
# """
# A theater chase pattern using n1 for on-width and n2 for off-width.
# """
# 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
def n_chase(self):
"""Chase pattern - n1 LEDs on, n2 LEDs off, bidirectional movement"""
self.run = True
# # Use controller's step for synchronization, but scale it for chasing
# chase_step = (self.step * step_rate) % self.num_leds
# 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
# n3 = forward steps per move, n4 = backward steps per move
forward_steps = max(1, abs(int(self.n3)))
backward_steps = max(1, abs(int(self.n4)))
# 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()
# for i in range(self.num_leds):
# # Calculate position relative to the chase head
# pos_from_head = (i - chase_step) % self.num_leds
# if pos_from_head < self.n1:
# self.n[i] = self.apply_brightness(self.colors[0])
# else:
# self.n[i] = (0, 0, 0)
# self.n.write()
# 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)
# # Don't update internal step - use controller's step for sync
# self.last_update = current_time
# return self.delay
self.run = False
self.running = False
# def alternating(self):
# # Use n1 as ON width and n2 as OFF width