Adafruit_CircuitPython_LED_.../adafruit_led_animation/animation/chase.py
hberg32 9cb567f013
Fix initial offset calculation when reversed in chase.py
Found a bug in the chase animation when reverse is set to True which results in the animation being offset by the length of the size parameter.  You can observe this by setting up two animations of equal length on a single strip of pixels with the second one reversed.  The bars should appear to meet in the middle but don't.

Example:
pixels = neopixel.NeoPixel(board.A0, 22, auto_write=False, brightness = .5)
left_pixels = PixelSubset(pixels, 0, 11)
right_pixels = PixelSubset(pixels, 11, 22)
left_animation = Chase(
    left_pixels, speed=.5, color=CYAN, size=2, spacing=11
)

right_animation = Chase(
    right_pixels, speed=.5, color=CYAN, size=2, spacing=11, reverse=True
)

animations = AnimationSequence(
    AnimationGroup(
        left_animation,
        right_animation,
        sync=True
    ),
    auto_clear=True,
    auto_reset=True,
)

while True:
    animations.animate()
2025-07-31 16:41:58 -04:00

125 lines
3.8 KiB
Python

# SPDX-FileCopyrightText: 2020 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_led_animation.animation.chase`
================================================================================
Theatre chase animation for CircuitPython helper library for LED animations.
* Author(s): Kattni Rembor
Implementation Notes
--------------------
**Hardware:**
* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
"""
from math import ceil
from adafruit_led_animation.animation import Animation
class Chase(Animation):
"""
Chase pixels in one direction in a single color, like a theater marquee sign.
:param pixel_object: The initialised LED object.
:param float speed: Animation speed rate in seconds, e.g. ``0.1``.
:param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format.
:param size: Number of pixels to turn on in a row.
:param spacing: Number of pixels to turn off in a row.
:param reverse: Reverse direction of movement.
"""
def __init__(self, pixel_object, speed, color, size=2, spacing=3, reverse=False, name=None):
self._size = size
self._spacing = spacing
self._repeat_width = size + spacing
self._num_repeats = ceil(len(pixel_object) / self._repeat_width)
self._overflow = len(pixel_object) % self._repeat_width
self._direction = 1 if not reverse else -1
self._reverse = reverse
self._offset = 0 if not reverse else len(pixel_object) - size
def _resetter():
self._offset = 0 if not reverse else len(self.pixel_object) - size
self._reverse = reverse
self._direction = 1 if not reverse else -1
self._reset = _resetter
super().__init__(pixel_object, speed, color, name=name)
on_cycle_complete_supported = True
@property
def reverse(self):
"""
Whether the animation is reversed
"""
return self._reverse
@reverse.setter
def reverse(self, value):
self._reverse = value
self._direction = -1 if self._reverse else 1
def draw(self):
def bar_colors():
bar_no = 0
for i in range(self._offset, 0, -1):
if i > self._spacing:
yield self.bar_color(bar_no, i)
else:
yield self.space_color(bar_no, i)
bar_no = 1
while True:
for bar_pixel in range(self._size):
yield self.bar_color(bar_no, bar_pixel)
for space_pixel in range(self._spacing):
yield self.space_color(bar_no, space_pixel)
bar_no += 1
colorgen = bar_colors()
self.pixel_object[:] = [next(colorgen) for _ in range(len(self.pixel_object))]
if self.draw_count % len(self.pixel_object) == 0:
self.cycle_complete = True
self._offset = (self._offset + self._direction) % self._repeat_width
def bar_color(self, n, pixel_no=0):
"""
Generate the color for the n'th bar_color in the Chase
:param n: The pixel group to get the color for
:param pixel_no: Which pixel in the group to get the color for
"""
return self.color
@staticmethod
def space_color(n, pixel_no=0):
"""
Generate the spacing color for the n'th bar_color in the Chase
:param n: The pixel group to get the spacing color for
:param pixel_no: Which pixel in the group to get the spacing color for
"""
return 0
def reset(self):
"""
Reset the animation.
"""
self._reset()