Pathfinder Robot Companion
2020-08-25 | By Adafruit Industries
License: See Original Project
Courtesy of Adafruit
Guide by John Park
Overview
Pathfinder is a fan favorite character from the game Apex Legends. In this guide, we'll show you how to build your own interactive desktop Pathfinder desktop companion, complete with Adafruit PyPortal chest screen, voiceover lines from the game, and glowing LED robot eye!
We'll build Pathfinder using 3D printed parts, Sugru moldable glue, and an array of electronics, all programmed on the PyPortal with CircuitPython.
This is an advanced project and a very involved build!
Parts
- Adafruit PyPortal - CircuitPython Powered Internet Display
- Adafruit PyPortal Desktop Stand Enclosure Kit
- Sugru - Black and White Pack
- PowerBoost 1000 Charger - Rechargeable 5V Lipo USB Boost @ 1A
- Stereo 3.7W Class D Audio Amplifier - MAX98306
- 1 x Speaker - 40mm Diameter
- 1 x Adafruit Perma-Proto
- 1 x Convex Glass Lens
- 1 x Round Panel Mount Adapter
- 1 x USB cable
- 1 x DIY USB or HDMI Cable
- 1 x DIY USB Cable Parts
- 1 x DIY USB Cable Parts
- 1 x JST-PH 2-Pin SMT
- 1 x Panel Mount 10K Log Potentiometer
- 1 x Solid Machined Metal Knob
- 1 x Mini Panel Mount SPDT Toggle Switch
- 1 x Rugged Metal Pushbutton
- 1 x Lithium Ion Polymer Battery
- 1 x Flora RGB Smart NeoPixel
- 1 x STEMMA JST PH 3-Pin to Male Header Cable
Tools
In addition to the parts above you'll need access to a 3D printer and PLA filament in a variety of colors to suit your Pathfinder build.
For the electronics, you'll want the following tools, or equivalent:
- ATTEN 50W 110V Soldering Iron With Station
- Silicone Cover Stranded-Core Wire - 26AWG in Various Colors
- 1 x Solder Wire - 60/40 Rosin Core
- 1 x Hakko Professional Quality Wire Strippers
- 1 x Flush diagonal cutters
- 1 x Spudger
Fasteners
Most attachments will be made using Sugru, however, we'll use M4 hardware to fasten Pathfinder's torso halves together, as well as to secure the monitor frame.
- 2 x M4 x 50mm socket head screws
- 2 x M4 x 14mm socket head screws
- 4 x M4 x 4.7mm heat-set inserts
- 4 x M2.5 x 3.4mm heat-set inserts
- Black Nylon Screw and Stand-off Set – M2.5 Thread
Build the Pathfinder PyPortal Circuit
The Pathfinder Circuit
The circuit will enable the following systems/functions:
- PyPortal as the central brain, display, and touch screen. This can be reprogrammed over the USB data port and can be reset with illuminated external momentary button.
- Battery and PowerBoost converter for power and external USB port for charging. The power switch connects to the PowerBoost.
- 3.7W amplifier and speaker with volume knob.
- NeoPixel full-color LED for eyeball lighting.
The circuit diagram above shows how all of these parts are connected. Follow that diagram closely and build the circuit on the Perma-Proto board.
You'll see in the photos below that we'll use interconnect cables for some of the parts to make assembly into the 3D printed model easier. While it takes more work than simply soldering long wires directly to the proto board and the PyPortal, the added flexibility can be a lifesaver when trying to fit buttons and switches through their mounting holes!
Amplifier
Tie the power and ground rails of the PermaProto board together.
Mount the audio amplifier to the board as shown and then add the JST connector breakout board so the two center pins are connected to the L- and L+ of the amp board. To prevent shorting these to R- and SDWN you can cut the traces on the proto board the would join these and don't solder the outer pins of the breakout board to the proto board.
Power Rails
From the bottom of the proto board, jump the 5V and G columns where the PowerBoost will connect to the power rails.
Use a bare JST PH 2-pin connector to connect the toggle switch to the En and GND pins of the PowerBoost as shown. This will be used to turn Pathfinder on and off.
Power and Sound Connections
You can then plug in the USB power cable, the amplifier input from the PyPortal, the enable switch cable, the speaker, and the battery as shown here.
Note: Ignore the DIY USB plug soldered to the PowerBoost here, we'll simply plug one end into the PowerBoost USB-B and the other to the panel mount adapter later.
PyPortal Connections
The PyPortal audio out runs to the L+ and L- inputs on the amplifier, you can see the small JST cable plugged in here.
Note: Ignore the DIY USB cable plugged into the PyPortal here -- we'll leave that port free for programming and run the power over JST instead.
Reset Button
To access the reset button from the outside of the robot, solder two leads to the left two SMD pads of the programming connector as shown here. Polarity doesn't matter as this is used to short the reset pin to ground.
You can use a female socketed JST cable as shown here to make the connect to the button easier later when feeding it through Pathfinder's torso.
Knobs and Switches
Solder a two-conductor interconnect cable to the power enable switch and plug it into the JST socket that extends the PowerBoost En/GND pins.
Solder an interconnect cable to the potentiometer as shown in the circuit diagram, and in order to plug it between the speaker output of the PyPortal and the left channel input of the amplifier.
Connect the speaker to the screw terminals of the amplifier's left output channel as shown.
Final Wiring
Here we can see the final wiring and the circuit powered on (we'll still need to program it before testing).
Power runs from the PermaProto board rails to one of the three-pin JST connectors on the side of the PyPortal (this leaves the USB port free for programming).
The other three-pin JST port on the PyPortal is used to send power and data to Pathfinder's eyeball NeoPixel LED as seen here.
Next, we'll prep Pathfinder's PyPortal for coding!
Code Pathfinder
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.
Libraries
These are the libraries we'll have installed.
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.
Code.py
Copy the code below and paste it into Mu. Then, save it to your PyPortal as code.py.
Code
This version of the code play's Pathfinder's emotes screens and audio files as an automatically advancing slideshow. You can hold the touch screen to toggle the sound on and off.
Download: Project Zip or pathfinder_auto.py | View on Github
# 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 is not 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=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 is not 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)
with open(emote_img[i], "rb") as bitmap_file:
bitmap = displayio.OnDiskBitmap(bitmap_file)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=displayio.ColorConverter())
group = displayio.Group()
group.append(tile_grid)
display.show(group)
if sound_mode is not 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!
Download: Project Zip or pathfinder_touch.py | View on Github
# 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 is not 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=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 is not 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 pyportal.touchscreen.touch_point:
i = (i + 1) % 11
pixel.fill(colors[i])
pixel.show()
time.sleep(1)
with open(emote_img[i], "rb") as bitmap_file:
bitmap = displayio.OnDiskBitmap(bitmap_file)
tile_grid = displayio.TileGrid(
bitmap, pixel_shader=displayio.ColorConverter()
)
group = displayio.Group()
group.append(tile_grid)
display.show(group)
if sound_mode is not 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.
Print and Assemble Pathfinder
3D Printing
Pathfinder will be made primarily of 3D printed parts, using PLA plastic filament in a variety of colors. You can get creative here and do your own color scheme for Pathfinder!
Sugru works very well to fasten PLA parts together as well as to form part extensions, and to smooth some surfaces. You may want to test Sugru bonding with alternate filament materials if not using PLA.
First, download the Pathfinder STL models from the .zip link button below, then get printing!
Note, any model file with a multiples suffix in the name, such as pathfinder_lens_protector_x2.stl need to be printed in those multiples.
Do not print the pathfinder_assembled.stl file, it is only provided as assembly reference.
Once the parts are printed (whew!) it's time to begin assembly.
This rendered turnaround of the model will show you how the parts will all fit together.
Abdomen Section
The abdomen section goes together with two main parts -- the abdomen base and the roller on which the torso will later rest -- and two brackets.
There are also four cylindrical press-fit plugs that join the parts. Use a small bit of Sugru in the receiving holes of the abdomen and roller to hold these all in place as shown.
Canister Build
Some parts need to be created as sub-assemblies before adding to the full robot.
The canisters on Pathfinder's shoulders can be assembled with a bead of Sugru rolled out and then placed on the top and bottom of the main cylinder.
Then, press it onto the base and place the lid on top as shown here.
You can cut off any excess Sugru that overlaps when the base and lid are pressed into place.
Use a small dot of Sugru to attach the handle as well.
You will repeat all of these steps for the second canister.
Add the canister handles and nubs, building up the nubs with some red Sugru.
Canister Magnets
Using a bit of Sugru, embed a small magnet into the baseball of each canister.
Mark the north sides of two magnets so the opposite magnet can be flipped and embedded later into the canister attachment cups.
Shoulders
To secure the shoulder ball into the shoulder socket, roll out a bead strip of Sugru and add it inside the socket.
Push the ball through from the inside, then sculpt and smooth the Sugru to create a nice, seamless joint.
Monitor
Use your soldering iron to place M2.5 heat-set threaded inserts into the holes inside the monitor frame. You'll use these to secure the PyPortal acrylic frame and the PyPortal in place.
Align the PyPortal acrylic frame inside the printed monitor frame, then screw the PyPortal into place with the nylon M2.5 screws.
Sculpted Pouch Nubs
Pathfinder's three front pouches have red release nubs on them -- use red Sugru to sculpt these.
Torso Threaded Inserts
Use a soldering iron to place two M4 heat-set threaded inserts into the left torso half.
These will be used later to screw in the right torso half using M4 x 50mm screws.
Torso Electronics
Add the reset button, power switch, volume potentiometer, and USB power port extender to the left torso half as shown. Fasten them with their provided nuts. Then, reconnect their cable interconnects to the main proto board if necessary.
Use some Sugru to secure the speaker, battery, and electronics inside the torso. It will be a bit of a snug fit, so try dry fitting the halves together before allowing the Sugru time to cure in case things need to be adjusted.
Close It Up
Add one M4 threaded insert to each torso half so the monitor can be screwed into it from the top using the M4 x 14mm screws.
Fasten the two torso halves together with the longer M4 x 50mm screws now.
Testing
This is a good time to test all of the functions!
Head and Eye
Secure the lens to the inside of the head/eye socket with a thin bead of Sugru. You can use a shop towel or cloth when handling the lens to avoid fingerprints.
Secure the outer eye detail parts with Sugru as well.
Push the eye NeoPixel up through the neck and then secure it inside the head with Sugru. You can create a nice depth effect by adding a spacer between the NeoPixel and lens.
Shoulder Gaskets
To attach the shoulders to the torso, press fit them in place and then fill the connection with a gasket-like strip of black Sugru.
You can trim, sculpt, and smooth it with a tool or your finger to give it the appearance of a rubber gasket.
Neck Cowl
With the NeoPixel eye fed up through the neck tube and secured inside the head with Sugru, you can attach the neck and head to the torso.
Then, wrap the neck cowl form pieces around the neck and begin sculpting a Sugru cowl over the top of it. Pathfinder has a rubberized canvas cowl in the game, so this will emulate that look and have organic folds and curves in it.
Pouches and Mounting
Attach the mounting plate to the abdomen brackets and then affix the pouches to the mounting plate with Sugru.
You can place the torso on top of the abdomen roller and affix it with a dot of Sugru.
Collarbones and Canisters
You can now pop into place the collarbones and canisters using their magnets to hold them.
Bring Pathfinder to Life
You can now bring Pathfinder to life! Flip the on switch and he'll start playing his voice over audio and display emotes!
You can adjust his volume with the large volume knob, and if you're in touch screen mode, tap the screen to advance to the next emote.
One of the best things about Pathfinder and PyPortal is that he's fully customizable! You can swap out different graphics and sound files, or reprogram him for entirely different uses, such as a Bitcoin price display, art museum collection frame, weather station, Hue lighting controller, or Reddit stats trophy.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum