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 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

PyPortal, our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface...
$54.95
In Stock
PyPortal is our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Create little pocket...
$9.95
In Stock
Sugru! Soft-touch silicone rubber that molds and sets permanently. Sticks to aluminum, steel, ceramics, glass, wood and some fabrics + plastics! sugru is the incredible new air-curing...
$17.95
In Stock
PowerBoost 1000C is the perfect power supply for your portable project! With a built-in load-sharing battery charger circuit, you'll be able to keep your power-hungry...
$19.95
In Stock
This incredibly small stereo amplifier is surprisingly powerful - able to deliver 2 x 3.7W channels into 3 ohm impedance speakers. Inside the miniature chip is a class D controller,...
$8.95
In Stock
1 x Speaker - 40mm Diameter
4 Ohm 3 Watt Speaker - 40mm Diameter - 4 Ohm 3 Watt
1 x Adafruit Perma-Proto
Half-sized Breadboard PCB - Single $4.50 IN STOCK
1 x Convex Glass Lens
with Edge - 40mm Diameter
1 x Round Panel Mount Adapter
Micro USB B Jack to USB A Plug
1 x USB cable
USB A to Micro-B
1 x DIY USB or HDMI Cable
30 cm Ribbon Cable
1 x DIY USB Cable Parts
Straight Type A Plug
1 x DIY USB Cable Parts
Right Angle Micro B Plug Down
1 x JST-PH 2-Pin SMT
Right Angle Breakout Board
1 x Rugged Metal Pushbutton
16mm 6V RGB Momentary
1 x Flora RGB Smart NeoPixel
version 2 - Pack of 4

Tools

In additions 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:

This compact but 50W-powerful stationary soldering iron is a great entry-level soldering station, and we've been using it around Adafruit for soldering with a lot of success....
$44.95
In Stock
Silicone-sheathing wire is super-flexible and soft, and it's also strong! Able to handle up to 200°C and up to 600V, it will do when PVC covered wire wimps out. We like this...
Out of Stock
1 x Solder Wire - 60/40 Rosin Core
0.5mm/0.02" diameter 50 grams
1 x Spudger
Double Sided Prying Tool

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
Black-Oxide Alloy Steel Socket Head Screw M4 x 0.7 mm Thread, 50 mm Long, Partially Threaded
2 x M4 x 14mm socket head screws
18-8 Stainless Steel Socket Head Screw M4 x 0.7 mm Thread, 14 mm Long
4 x M4 x 4.7mm heat-set inserts
Tapered Heat-Set Inserts for Plastic Brass, M4 x 0.70 mm Thread Size, 4.700 mm Installed Length
4 x M2.5 x 3.4mm heat-set inserts
Tapered Heat-Set Inserts for Plastic Brass, M2.5 x 0.45 mm Thread Size, 3.4 mm Installed Length
Totaling 380 pieces, this M2.5 Screw Set is a must-have for your workstation. You'll have enough screws, nuts, and hex standoffs to fuel your maker...
Out of Stock

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!

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 emote screens and audio files as an automatically advancing slideshow. You can hold the touch screen to toggle the sound on and off.

# 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!

# 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.

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 base ball 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 in side 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.

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 frameweather station, Hue lighting controller, or Reddit stats trophy.

This guide was first published on Jun 24, 2020. It was last updated on Jun 24, 2020.