Pico Graphics Motion Tearing

Using the Micropython version of the Pico Graphics library with the Display Pack 2.0 and a Pi Pico 2.

Having an issue with motion and “frame tearing”. If I move an element, in this case a rectangle across the screen at more than 1px per frame, I get pretty nasty frame tearing effect. See attached image. Noticed it in a much larger project, boiled it down to the simplest example, tried different graphics modes but it’s still there.

Anyone else having this issue or find a work around?

Post your code and I’'ll run it on my Pico > Display pack setup.
Also, what uf2 file did you flash the Pico with?

EDIT: What is that circuit board behing the Display Pack?

Thanks for looking at this.

EDIT: Used the v1.25 pimoroni pico uf2.

Good thought. I have a proto board sandwiched in there so I could solder a pot and encoder to it (and route them to unused pins). I might pull it all apart and test again for good measure.

# Modules
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_P4
import time

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, pen_type=PEN_P4, rotate=0)

class Display:
    # SINGLETON
    _instance = None
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(Display, cls).__new__(cls)
        return cls._instance
    
    # INIT
    def __init__(self):
        # DIMENSIONS
        self.WIDTH, self.HEIGHT = display.get_bounds()

        # PALLET
        self.BLACK = display.create_pen(0, 0, 0)
        self.RED = display.create_pen(255, 0, 0)
        display.set_pen(self.BLACK)
        self.clear()
        # TEST
        self.pos_x = 0
        self.reverse = False

    # TEST FUNCTION
    def motion_test(self):
        display.set_pen(self.BLACK)
        self.clear()
        display.set_pen(self.RED)
        rect_size = 20
        speed = 5

        if self.pos_x >= self.WIDTH - rect_size and not self.reverse:
            # Flip Left
            self.reverse = not self.reverse
            print(self.reverse)
        elif self.pos_x <= 0 and self.reverse:
            # Flip Right
            self.reverse = not self.reverse
            print(self.reverse)
        elif self.reverse:
            self.pos_x = self.pos_x - speed
        else:
            self.pos_x = self.pos_x + speed

        display.set_pen(self.RED)
        display.rectangle(int(self.pos_x), int(self.HEIGHT/2 - rect_size /2), rect_size, rect_size)
        self.update()

    # UTILITIES
    def clear(self):
        display.set_pen(self.BLACK)
        display.clear()
        
    def update(self):
        display.update()


test_display = Display()
while True:
    test_display.motion_test()
    time.sleep_ms(10)

Pico or Pico 2? I ask because the link you posted is the uf2 for the Pico 2040.
The Pico 2 2350 uf2 is here,
Release Version 1.26.1 · pimoroni/pimoroni-pico-rp2350

EDIT. It was the 1.26.1 version for the RPI2350. I just re-downloaded, flashed it and ran it again. Issue persists.

Yeah, the 2040 uf2 would fail to flash to a Pico 2 2350.
I just ran what you posted on my Pico 2 with Display pack 2 and I’m seeing the same. I think I am anyway. I see a kind of rippling on the leading and trailing edges of the square as it moves. For me it’s a red square on a black background.

Yep. Red on black. Jagged edge. Might be a limitation of the screen or library.

Wierd one. Have you run the balls demo? Lots of moving elements, moving at different speeds, and no tearing that I can see.

import time
import random
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_P8
from pimoroni import RGBLED, Button

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, pen_type=PEN_P8)
display.set_backlight(1.0)

WIDTH, HEIGHT = display.get_bounds()

led = RGBLED(6, 7, 8)
led.set_rgb(0, 0, 0)

button_a = Button(12)
button_b = Button(13)
button_x = Button(14)
button_y = Button(15)


# We're creating 100 balls with their own individual colour and 1 BG colour
# for a total of 101 colours, which will all fit in the custom 256 entry palette!


class Ball:
    def __init__(self, x, y, r, dx, dy, pen):
        self.x = x
        self.y = y
        self.r = r
        self.dx = dx
        self.dy = dy
        self.pen = pen


# initialise shapes
balls = []
for i in range(0, 100):
    r = random.randint(0, 10) + 3
    balls.append(
        Ball(
            random.randint(r, r + (WIDTH - 2 * r)),
            random.randint(r, r + (HEIGHT - 2 * r)),
            r,
            (14 - r) / 2,
            (14 - r) / 2,
            display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
        )
    )

BG = display.create_pen(40, 40, 40)

while True:
    
    if button_a.read():
        led.set_rgb(255, 0, 0)
    elif button_b.read():
        led.set_rgb(0, 155, 0)
    elif button_x.read():
        led.set_rgb(0, 0, 0)
    elif button_y.read():
        led.set_rgb(0, 0, 255)
    
    display.set_pen(BG)
    display.clear()

    for ball in balls:
        ball.x += ball.dx
        ball.y += ball.dy

        xmax = WIDTH - ball.r
        xmin = ball.r
        ymax = HEIGHT - ball.r
        ymin = ball.r

        if ball.x < xmin or ball.x > xmax:
            ball.dx *= -1

        if ball.y < ymin or ball.y > ymax:
            ball.dy *= -1

        display.set_pen(ball.pen)
        display.circle(int(ball.x), int(ball.y), int(ball.r))

    display.update()
    time.sleep(0.01)

Good thought.

I wasn’t seeing it with the balls example, but when I changed them to squares and upped the speed a little bit, it was back. I think its just harder to see with a circle cause they don’t have straight lines.

This sort of gave me an idea for a workaround. I can append circles to the ends of my rectangles and make them bubbles or draw thick lines instead of rectangles. I’ll let you know how it goes.

Square Balls Code, lol.

import time
import random
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_P8
from pimoroni import RGBLED, Button

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, pen_type=PEN_P8)
display.set_backlight(1.0)

WIDTH, HEIGHT = display.get_bounds()

led = RGBLED(6, 7, 8)
led.set_rgb(0, 0, 0)

button_a = Button(12)
button_b = Button(13)
button_x = Button(14)
button_y = Button(15)

# We're creating 100 balls with their own individual colour and 1 BG colour
# for a total of 101 colours, which will all fit in the custom 256 entry palette!

class Ball:
    def __init__(self, x, y, r, dx, dy, pen):
        self.x = x
        self.y = y
        self.r = r
        self.dx = dx
        self.dy = dy
        self.pen = pen

# initialise shapes
balls = []
for i in range(0, 20):
    r = random.randint(5, 15) + 3
    balls.append(
        Ball(
            random.randint(r, r + (WIDTH - 2 * r)),
            random.randint(r, r + (HEIGHT - 2 * r)),
            r*2,
            (14 - r) / 2,
            (14 - r) / 2,
            display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
        )
    )

BG = display.create_pen(40, 40, 40)

while True:
    
    if button_a.read():
        led.set_rgb(255, 0, 0)
    elif button_b.read():
        led.set_rgb(0, 155, 0)
    elif button_x.read():
        led.set_rgb(0, 0, 0)
    elif button_y.read():
        led.set_rgb(0, 0, 255)
    
    display.set_pen(BG)
    display.clear()

    for ball in balls:
        ball.x += ball.dx
        ball.y += ball.dy

        xmax = WIDTH - ball.r
        xmin = ball.r
        ymax = HEIGHT - ball.r
        ymin = ball.r

        if ball.x < xmin or ball.x > xmax:
            ball.dx *= -1

        if ball.y < ymin or ball.y > ymax:
            ball.dy *= -1

        display.set_pen(ball.pen)
        display.rectangle(int(ball.x), int(ball.y), int(ball.r),int(ball.r))

    display.update()
    time.sleep(0.01)
1 Like

@hel: can someone look into the tearing issue? This is usually a problem of the chip having problems with the update frequency, maybe you can tweak something in the driver?!

I remember that the Tufty also has tearing problems. More with the slower updates of CircuitPython than with MicroPython, but it also shows up in special situations with MicroPython. And if I keep away from pure white, the tearing of the Tufty is also gone.

2 Likes