rm-hull/luma.led_matrix

Flashing Pixels; Performance Issue?

Closed this issue · 7 comments

I think I may be seeing a performance issue. I'm using legacy.text() and draw.point() to light text (the time) plus a few pixels on 4 cascaded matrix displays. When doing this in a simple test script it works great. However, when moving this into my larger script I'm seeing flashing of the pixels I'm lighting individually (legacy.text is solid). Code is below. I can upload a video of the behavior I'm seeing if you'd like.

Thanks for your work here! Other than this flashing issue I've had a really easy time getting up a running. Great examples and documentation.

Type of Raspberry Pi

RPi3

Linux Kernel version

Linux piclock 4.4.34-v7+ #930 SMP Wed Nov 23 15:20:41 GMT 2016 armv7l GNU/Linux

Expected behaviour

Pixels change to desired state and do not flash in transition or while lit.

Actual behaviour

Seeing pixels flashing either while in transition or while lit.

Here's the code that works in this test script, but causes flashing behavior in my larger script:

#!/usr/bin/env python

from luma.core import legacy
from luma.led_matrix.device import max7219
from luma.core.serial import spi, noop
from luma.core.render import canvas

import datetime, time



# create matrix device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=4, block_orientation="vertical")

show_dots = True
counter = 1

while True:
    clock_display = (datetime.datetime.now().strftime('%I:%M'))

    if show_dots == True:
        with canvas(device) as draw:
            legacy.text(draw, (0, 0), clock_display, fill="white", font=legacy.font.proportional(legacy.font.SINCLAIR_FONT))
            draw.point([(31, 7), (30, 7), (31, 6)], fill="white")
    elif show_dots == False:
        with canvas(device) as draw:
            legacy.text(draw, (0, 0), clock_display, fill="white", font=legacy.font.proportional(legacy.font.SINCLAIR_FONT))

    time.sleep(.5)
    counter += 1

    if counter == 8:
        show_dots = not show_dots
        counter = 1

A video would be good, if you could upload that. Can you share your larger program?

One thing to be aware of is not putting a time.sleep(...) inside the with canvas(device) as draw: block as the image is only flushed to the device when the block exits.

Also, I would be inclined to slightly rewrite the loop:

counter = 0
while True:
    with canvas(device) as draw:
        legacy.text(draw, (0, 0), clock_display, fill="white", font=legacy.font.proportional(legacy.font.SINCLAIR_FONT))
        if counter % 16 < 8:
            draw.point([(31, 7), (30, 7), (31, 6)], fill="white")

    time.sleep(.5)
    counter += 1

Here's a link to a video.

The iPhone rolling shutter looks a bit weird, but the flashing pixels in the lower right are the issue I'm talking about.

Thanks for the loop rewrite. I'm still learning so am always happy to see more efficient ways to do things.

Link to this code in the larger program.

I think it might be something to do with the use of threads and/or there are two copies of the script running. Try adding some print logging at https://github.com/spencerhooks/piclockradio/blob/master/clockradio.py#L316 to show the time on the console, something like:

print(counter, clock_display)

And see if there are duplicate lines being printed.

Also the script flips the show_dot variable every 7 ticks - rather than 8 (I presume this is what you want).

Personally, I would use asyncio over threads every time to avoid strange concurrency issues like this, but that is python3 only, and can be quite difficult to get your head round if you're not used to it.

Good call. It looks like there are two copies of the thread running for some reason. Guess maybe I don't know how to use threads after all 😄

Time to figure that out now next I guess...

Thanks for your help in troubleshooting this! Apologies for raising an issue when it wasn't caused here.

No worries - glad to hear that it was pretty simple to get up & running.

Thanks for taking the time to raise an issue though: anything that isn't clear in the docs, or isn't working as expected then it's always best to raise an issue (or PR) as it helps the project (and other users) in the long run.

Just wanted to follow up in case it can help someone in the future:

Using ps -ef | grep python showed me that there were in fact two copies of my script running.

My problem came from the fact that I am using Flask and was running in debug mode. Flask includes reloading functionality such that you can change code and you don't need to restart your app. It's handy. Well, it accomplishes this by basically running two instances of your script. This is what was causing the flashing that I saw (two scripts writing to the matrix display that weren't perfectly in sync).

You can work around this issue in debug mode by adding use_reloader=False to your app.run() call. That fixed it for me. You lose the reloading functionality though. I believe switching out of debug mode should also solve it.

Anyway, problem solved. Thanks again @rm-hull

More info can be found here

Personally, I would use asyncio over threads every time to avoid strange concurrency issues like this

@rm-hull we should move away from time.sleep stuff..