Setup
Prepare the PyPortal by following this setup guide to install the latest version of CircuitPython. This guide was created using version 5.3.0, so use that or later.
Install the libraries onto the PyPortal's /lib directory as instructed here.
Media Files
Pathfinder has two sets of media files - .bmp images for his chest monitor "emotes", and sound files for his voice over (VO) lines.
Download the Project Zip .zip file from the link in the code embed below. Once it's been downloaded, unarchive the .zip file and then copy the two directories named /emotes and /vo onto the PyPortal's CIRCUITPY drive.
Text Editor
Adafruit recommends using the Mu editor for using your CircuitPython code to the PyPortal. You can get more info in this guide.
Alternatively, you can use any text editor that saves files.
This version of the code play's Pathfinder's emote screens and audio files as an automatically advancing slideshow. You can hold the touch screen to toggle the sound on and off.
# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries # # SPDX-License-Identifier: MIT # Pathfinder Auto Mode # automatically advances to new image/sound # press and hold the touch screen to toggle sound on and off # by John Park for Adafruit and Sugru # MIT License import time import board import displayio import neopixel from adafruit_pyportal import PyPortal # ===========User Settings============= sound_mode = 1 # 0 is silent, 1 is normal eye_mode = 1 # 0 is always red, 1 changes per emote slide_speed = 1.0 # number of seconds to pause, 0 will go as fast as it can # =======end User Settings============= i = 0 # emote image index display = board.DISPLAY pixel = neopixel.NeoPixel(board.D4, 1, brightness=0.2, auto_write=False) PINK = (200, 0, 50) RED = (255, 0, 0) YELLOW = (255, 150, 0) ORANGE = (255, 75, 0) WHITE = (100, 100, 100) CYAN = (0, 255, 255) GREEN = (0, 235, 20) BLUE = (0, 0, 255) PURPLE = (180, 0, 255) BLACK = (0, 0, 0) GREY = (10, 10, 10) if eye_mode != 0: colors = [PINK, RED, ORANGE, CYAN, YELLOW, GREEN, WHITE, RED, PURPLE, GREEN, GREY] else: colors = [RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED] pixel.fill(colors[0]) pixel.show() emote_img = [ "/emotes/01_love.bmp", "/emotes/02_anger.bmp", "/emotes/03_KO.bmp", "/emotes/04_sad.bmp", "/emotes/05_happy.bmp", "/emotes/06_bang.bmp", "/emotes/07_sick.bmp", "/emotes/08_thumbsup.bmp", "/emotes/09_question.bmp", "/emotes/10_glitch.bmp", "/emotes/11_static.bmp", ] vo_sound = [ "/vo/pathfnd_45.wav", "/vo/pathfnd_46.wav", "/vo/pathfnd_47.wav", "/vo/pathfnd_48.wav", "/vo/pathfnd_49.wav", "/vo/pathfnd_51.wav", "/vo/pathfnd_52.wav", "/vo/pathfnd_53.wav", "/vo/pathfnd_54.wav", "/vo/pathfnd_55.wav", "/vo/pathfnd_56.wav", ] pyportal = PyPortal(status_neopixel=board.NEOPIXEL) # Open the file with open(emote_img[0], "rb") as bitmap_file: # Setup the file as the bitmap data source bitmap = displayio.OnDiskBitmap(bitmap_file) # Create a TileGrid to hold the bitmap tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())) # Create a Group to hold the TileGrid group = displayio.Group() # Add the TileGrid to the Group group.append(tile_grid) # Add the Group to the Display display.show(group) if sound_mode != 0: # play a sound file pyportal.play_file(vo_sound[10]) else: pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method # Loop forever so you can enjoy your image while True: if pyportal.touchscreen.touch_point: if sound_mode == 0: sound_mode = 1 else: sound_mode = 0 i = (i + 1) % 11 pixel.fill(colors[i]) pixel.show() time.sleep(1) # CircuitPython 6 & 7 compatible with open(emote_img[i], "rb") as bitmap_file: bitmap = displayio.OnDiskBitmap(bitmap_file) tile_grid = displayio.TileGrid( bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) ) group = displayio.Group() group.append(tile_grid) display.show(group) # # CircuitPython 7+ compatible # bitmap = displayio.OnDiskBitmap(emote_img[i]) # tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) # group = displayio.Group() # group.append(tile_grid) # display.show(group) if sound_mode != 0: # play a sound file pyportal.play_file(vo_sound[i]) else: pyportal.play_file("/vo/pathfnd_silent.wav") time.sleep(slide_speed)
This alternate version of the code will only advance the emote and VO line when the touchscreen is pressed. This is perfect for picking a mood and sticking with it!
# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries # # SPDX-License-Identifier: MIT # Pathfinder Touch Screen # press screen to advance to new image/sound # by John Park for Adafruit and Sugru # MIT License import time import board import displayio import neopixel from adafruit_pyportal import PyPortal # ===========User Settings============= sound_mode = 1 # 0 is silent, 1 is normal eye_mode = 0 # 0 is always red, 1 changes per emote # =======end=User Settings============= i = 0 # emote image index display = board.DISPLAY pixel = neopixel.NeoPixel(board.D4, 1, brightness=0.3, auto_write=False) PINK = (200, 0, 50) RED = (255, 0, 0) YELLOW = (255, 150, 0) ORANGE = (255, 75, 0) WHITE = (100, 100, 100) CYAN = (0, 255, 255) GREEN = (0, 235, 20) BLUE = (0, 0, 255) PURPLE = (180, 0, 255) BLACK = (0, 0, 0) GREY = (10, 10, 10) if eye_mode != 0: colors = [PINK, RED, ORANGE, CYAN, YELLOW, GREEN, WHITE, RED, PURPLE, GREEN, GREY] else: colors = [RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED] pixel.fill(colors[0]) pixel.show() emote_img = [ "/emotes/01_love.bmp", "/emotes/02_anger.bmp", "/emotes/03_KO.bmp", "/emotes/04_sad.bmp", "/emotes/05_happy.bmp", "/emotes/06_bang.bmp", "/emotes/07_sick.bmp", "/emotes/08_thumbsup.bmp", "/emotes/09_question.bmp", "/emotes/10_glitch.bmp", "/emotes/11_static.bmp", ] vo_sound = [ "/vo/pathfnd_45.wav", "/vo/pathfnd_46.wav", "/vo/pathfnd_47.wav", "/vo/pathfnd_48.wav", "/vo/pathfnd_49.wav", "/vo/pathfnd_51.wav", "/vo/pathfnd_52.wav", "/vo/pathfnd_53.wav", "/vo/pathfnd_54.wav", "/vo/pathfnd_55.wav", "/vo/pathfnd_56.wav", ] pyportal = PyPortal(status_neopixel=board.NEOPIXEL) # Open the file with open(emote_img[0], "rb") as bitmap_file: # Setup the file as the bitmap data source bitmap = displayio.OnDiskBitmap(bitmap_file) # Create a TileGrid to hold the bitmap tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())) # Create a Group to hold the TileGrid group = displayio.Group() # Add the TileGrid to the Group group.append(tile_grid) # Add the Group to the Display display.show(group) if sound_mode != 0: # play a sound file pyportal.play_file(vo_sound[10]) else: pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method while True: if not pyportal.touchscreen.touch_point: time.sleep(0.01) continue i = (i + 1) % 11 pixel.fill(colors[i]) pixel.show() time.sleep(1) # CircuitPython 6 & 7 compatible with open(emote_img[i], "rb") as bitmap_file: bitmap = displayio.OnDiskBitmap(bitmap_file) tile_grid = displayio.TileGrid( bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) ) group = displayio.Group() group.append(tile_grid) display.show(group) # # CircuitPython 7+ compatible # bitmap = displayio.OnDiskBitmap(emote_img[i]) # tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) # group = displayio.Group() # group.append(tile_grid) # display.show(group) if sound_mode != 0: # play a sound file pyportal.play_file(vo_sound[i]) else: pyportal.play_file("/vo/pathfnd_silent.wav")
Once you've tested this code on your PyPortal and connected circuit, we'll build the Pathfinder robot himself.