Skip to content

Conversation

TurboVin
Copy link

@TurboVin TurboVin commented Aug 24, 2023

I have many Animations in a AnimationGroup. On my Pi Zero 2 W, I saw considerable performance issues when calling the animate function on my AnimationGroup. I discovered that the AnimationGroup.animate was calling each member items animate function with show=true. This results in drawing for EVERY item in the group. By calling show only on the last item in the Group, we improve performance only drawing once. Effectively, this improves from O(n^2) to O(n) in my use-case.

@FoamyGuy
Copy link
Contributor

I think this may need some additional mechanism within it for Animations that are on different strips.

I was testing this with this example from this repo: https://github.com/adafruit/Adafruit_CircuitPython_LED_Animation/blob/main/examples/led_animation_group.py

This example uses two different strips, one built-in to CircuitPlayground, and one connected externally.

Since the Animations are linked to different physical strips it means this change makes it so that only 1 strip is getting show() called on it, whichever is associated with the final animation in the group.

If all of your animations are on the same strip (segmented up presumably) then it will benefit from this improvement.

In order to work correctly for both cases (animations on same strip, and animations on different strips) I think it would need to have logic to track whether it had called show() on a particular strip and then avoid calling it again.

I'm not sure the best way for the code to keep track of the different strips and whether show has been called on them, but I'm sure there is some way it could work.

One alternative idea that I think should work for both cases without modifying the library is to pass show=False to animate() and then call show() on your strip(s) "manually" after animate() completes.

i.e. something like this for the main loop:

while True:
    animations.animate(show=False)
    strip_pixels.show()
    # other_strip_pixels.show()

@TurboVin if you have a chance, can you try it like this with the currently released library and your project to see if you get the same speed benefit with the code like this rather than modified inside of the Library?

@FoamyGuy
Copy link
Contributor

I'm not entirely sure I understand the return result from animate() but there is a chance it could also benefit from only calling show() if the result was True:

while True:
    result = animations.animate(show=False)
    if result:
        strip_pixels.show()

Neither of my strips are very large, and the animations are running very fast either way for me. I'm not sure how to tell if this actually makes a noticeable difference.

@TurboVin
Copy link
Author

TurboVin commented Sep 26, 2023

If all of your animations are on the same strip (segmented up presumably) then it will benefit from this improvement.

You're right. I did have all of my strips connected sequentially. I hadn't thought of multiple strip implications.

One alternative idea that I think should work for both cases without modifying the library is to pass show=False to animate() and then call show() on your strip(s) "manually" after animate() completes.

i.e. something like this for the main loop:

while True:
    animations.animate(show=False)
    strip_pixels.show()
    # other_strip_pixels.show()

@TurboVin if you have a chance, can you try it like this with the currently released library and your project to see if you get the same speed benefit with the code like this rather than modified inside of the Library?

This worked fine! It does feel a bit clunky to call the NeoPixels object directly rather than use the Adafruit_CircuitPython_LED_Animation wrappers. But yes! this will do fine.

One other consideration was to update animate() to take another optional param called "showOnlyLast" or similar. This would default to "no" and continue with the normal operation as expected. but if set to True, it'd only show the last item nomatter what.

@TurboVin TurboVin closed this Dec 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants