Overview
Sand Physics Toy
Build a beautiful 3D printed hourglass physics toy using LED matrices and an Adafruit Feather Sense. Use CircuitPython to simulate particle collision code on a small microcontroller packed with tons of sensors. With built-in lipo charging over USB, your projects can be small and portable!
Sand Toy Upgrade
This is an add-on to Carter Nelson's Time Triangle Thing learn guide. It uses a similar circuit and slight code adjust to make a portable hourglass in a 3D printed case.
This uses the Feather Sense on-board accelerometer to simulate an hourglass with interactive grains of sand. This looks and feels like it’s actually been affected by gravity.
3D Printed Case
The hourglass is made up 3D printed parts that snap fit together. The electronics are housed in the base. The assembly is modular and easy to put together. Parts are 3D printed without any support material.
Project Inspiration
This was inspired by @david_proyectos See his LED hourglass build posted on instagram.
Prerequisite Guides
Take a moment to walk through the following learn guides.
Mini and Small
The LED Matrices are available in 1.2in and 0.8in sized displays. The case was designed for both sizes and feature similar circuits and assembly. The LEDs come in various colors, so there are a few options to choose from.
Parts List
Parts used to build this project.
Page last edited August 18, 2025
Text editor powered by tinymce.
Circuit Diagram
The diagram below provides a visual reference for wiring of the components. This diagram was created using the software package Fritzing.
Adafruit Library for Fritzing
Use Adafruit's Fritzing parts library to create circuit diagrams for your projects. Download the library or just grab individual parts. Get the library and parts from GitHub - Adafruit Fritzing Parts.
A0 – I2C Address Change
You'll also need to change the I2C address of one of the matrices. Solder the A0 jumper on one of the LEDs matrices to set the address to 0x71. That way we will end up with these addresses for our matrices:
- Matrix 1 = 0x70 (default, no solder)
- Matrix 2 = 0x71
The 0x70 address matrix in on top and the 0x71 address matrix in on the bottom. Also reference the photos in the general build.
Wired Connections
- VCC from Mini Matrix (0x70) to VCC on Mini Matrix (0x71 – A0)
- GND from Mini Matrix (0x70) to GND on Mini Matrix (0x71 – A0)
- SDA from Mini Matrix (0x70) to SDA on Mini Matrix (0x71 – A0)
- SCL from Mini Matrix (0x70) to SCL on Mini Matrix (0x71 – A0)
- VCC from Mini Matrix (0x71 – A0) to 3V on Feather Sense
- GND from Mini Matrix (0x71 – A0) to GND on Feather Sense
- SDA from Mini Matrix (0x71 – A0) to SDA on Feather Sense
- SCL from Mini Matrix (0x71 – A0) to SCL on Feather Sense
Page last edited August 18, 2025
Text editor powered by tinymce.
Hourglass Code
Now let's get the Feather setup with CircuitPython, the necessary libraries, and the hourglass code.
Prepare the Feather Sense
Follow this guide for setting up CircuitPython on the Feather nRF52840 Sense:
Hourglass Code
Click the Download Project Bundle button in the code listing below to get a zip file with the project code and necessary libraries. Copy code.py and matrixsand.py to the CIRCUITPY folder.
Also copy the libraries to CIRCUITPY/lib. For quick reference, the CIRCUITPY/lib folder should have these contents (having more is OK):
Here is the main code listing for code.py. The matrixsand.py file will be found in the zip, along with everything else. Click the Download Project Bundle to get the zip.
# SPDX-FileCopyrightText: 2020 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
from adafruit_ht16k33 import matrix
import matrixsand
DELAY = 0.05 # overall update rate
# setup i2c
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
# check for LSM6DS33 or LSM6DS3TR-C (Adafruit Feather Sense)
try:
from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 as LSM6DS # pylint: disable=unused-import
accelo = LSM6DS(i2c)
except RuntimeError:
from adafruit_lsm6ds.lsm6ds3 import LSM6DS3 as LSM6DS # pylint: disable=unused-import
accelo = LSM6DS(i2c)
# the matrices
m1 = matrix.Matrix8x8(i2c, 0x70)
m2 = matrix.Matrix8x8(i2c, 0x71)
# the sand
sand1 = matrixsand.MatrixSand(8, 8)
sand2 = matrixsand.MatrixSand(8, 8)
# simple helper
def update_matrix(m, s):
for x in range(8):
for y in range(8):
m[x,y] = s[x,y]
# fill up some sand
for sx in range(8):
for sy in range(8):
sand1[sx, sy] = True
sand1[0,0] = sand1[0,1] = sand1[1,0] = False
sand1[0,2] = sand1[1,1] = sand1[2,0] = False
update_matrix(m1, sand1)
update_matrix(m2, sand2)
updated1 = updated2 = False
while True:
# read accelo
ax, ay, az = accelo.acceleration
# rotate coords
xx = -ax - ay
yy = -ax + ay
zz = az
# move grain of sand from upper to lower?
if yy > 0 and sand1[7,7] and not sand2[0,0] and not updated2:
sand1[7,7] = False
sand2[0,0] = True
updated1 = updated2 = True
# move grain of sand from lower to upper?
elif yy <= 0 and sand2[0,0] and not sand1[7,7] and not updated1:
sand2[0,0] = False
sand1[7,7] = True
updated1 = updated2 = True
# nope, just a regular update
else:
updated1 = sand1.iterate((xx, yy, zz))
updated2 = sand2.iterate((xx, yy, zz))
# update matrices if needed
if updated1:
update_matrix(m1, sand1)
if updated2:
update_matrix(m2, sand2)
time.sleep(DELAY)
The code handles both of the accelerometers that may appear on the Adafruit Feather nRF52840 Sense.
Page last edited August 18, 2025
Text editor powered by tinymce.
Modify Code
Adjust Code
The original code from Carter's Triangle Time Thing learn guide will need to be modified slightly. The Feather Sense is mounted in a different orientation so the accelerometer coordinates will need to be changed in order to match the new position.
Look for line 42 in the code and update the following values to match the new coordinates.
# rotate coords
xx = az - ay
yy = az + ay
zz = ax
Save the updated values to the code.py file using Mu editor or your preferred text editor. Make sure the code.py file has been updated on the CIRCUITPY drive.
Page last edited August 18, 2025
Text editor powered by tinymce.
3D Printing
Parts List
STL files for 3D printing are oriented to print "as-is" on FDM style machines. Parts are designed to 3D print without any support material. Original design source may be downloaded using the links below.
Mini or Small 8x8
The two versions feature identical file names. Choose the version you want to build.
Fusion 360 Download
The links below will launch the CAD in a browser. You can interact with the model and download files using links in the top right.
CAD Assembly
The Feather Sense, slide switch and battery are housed in the bottom base cover using tabs and built-in standoffs. The 3x spindles are secured to the base covers using 6x M3 screws. The top and bottom base feature snap fit covers.
Slicing Parts
No supports are required. Slice with settings for PLA material.
The parts were sliced using CURA using the slice settings below.
- PLA filament 220c extruder
- 0.2 layer height
- 10% gyroid infill
- 60mm/s print speed
- 60c heated bed
Slice with Brim
Adding a brim can help improve adhesion to the build plate. Brim adds a single layer around the base of the model. Models with small surface area touching the bed is prune to peel off especially with tall objects. Use a brim with a 3mm width when slicing the three spindles.
Design Source Files
The project assembly was designed in Fusion 360. This can be downloaded in different formats like STEP, STL and more. Electronic components like Adafruit's board, displays, connectors and more can be downloaded from the Adafruit CAD parts GitHub Repo.
Page last edited August 18, 2025
Text editor powered by tinymce.
Matrix Setup
LED Matrices and Backpacks
The 2x mini 8x8 LED matrices are soldered to the backpacks. The pinouts are symmetrical so they can be orientated either way.
Solder LED Matrix
Insert the pins from the 8x8 LED matrix through the top of the backpack. Ensure the LED matrix is installed correctly and flush with the PCB. A stick vise can help keep the components in place while soldering.
Trim Pins
The pins are long and need to be trimmed in order to fit inside the 3D printed enclosure. Use flush cutters to shorten the pins from the LED matrix.
Page last edited August 18, 2025
Text editor powered by tinymce.
Wiring
Ribbon Wire JST Cables
Use a piece of 4-wire ribbon cable and cut to 9cm in length. Use a second piece of 4-wire ribbon cable and cut to 6cm in length. Use the full length of 4-pin JST SH cable and remove the ends with the jumper connectors. Using wire stripper, remove a bit of insulation from each wire. Tin the wires by adding a small amount of solder. This helps to prevent the wires from fraying.
DIY Stemma QT Cable
The 4-pin JST SH connector is soldered to the 9cm long ribbon cable. Insert the connector onto the 4-pin JST SH cable. Solder each wire from the 9cm ribbon cable to the 4-pin JST SH connector.
Wiring LED Matrix Backpack
Use the 6cm long ribbon cable to connect the two matrices. Solder the wires from the ribbon cable and the JST cable into the LED matrix with the A0 soldered jumper. Each pin shares two wires from each cable. Use the 3D printed matrix cover as a jig to hold PCBs in place while soldering.
Wiring Second Matrix
Solder the wires from the 6cm long ribbon cable to the pins on the second LED matrix (with no soldered jumper). Use the colored wires to reference the connections. Ensure connections are similar with VCC to VCC, GND to GND, SCL to SCL and SDA to SDA.
Slide Switch Wiring
Use a 2-wire ribbon cable and cut to 5cm in length. This will connect the slide switch to the Feather Sense.
Solder Switch Wire
Remove one of the the pins on either far left or right but not the middle. Trim the remaining pins short so they're half their length. Solder the 2-wire ribbon cable to the remaining pins on the slide switch.
Connect Switch to Feather
Solder one wire from the switch to the EN pin on the Feather Sense. Solder the second wire from the switch to the GND pin on the Feather Sense. These connections will fit best in the enclosure when they're soldered from the bottom of the PCB.
Test Switch and Battery
Connect the 400mAh battery to the Feather Sense. Use the slide switch to power the Feather Sense on and off. The NeoPixel should power on green with the CircuitPython code loaded on board.
Connect Matrices to Feather
Solder the 9cm long ribbon cable to the pins on the Feather Sense. Connect 4-pin JST SH cables together. Ensure the connection are correct. Make the following connections.
- SDA from Matrix to SDA on Feather Sense
- SCL from Matrix to SCL on Feather Sense
- VCC from Matrix to 3V on Feather Sense
- GND from Matrix to GND on Feather Sense
Page last edited August 18, 2025
Text editor powered by tinymce.
Assembly
Matrices Enclosure
Insert the 4-pin JST SH cable from the matrices through one of the holes on either side of the enclosure. Reference the photo for correct placement. Check to ensure the top and bottom matrices are correctly positioned.
Install Cover
Place the cover with the matrices installed over the enclosure. Position wiring so it's fully inside the case and it does not get kinked. Firmly press the cover into the case to snap fit shut.
Secure Feather Sense and Switch
Insert the Feather Sense into the bottom base at an angle. Fit the PCB under the clips and fit mounting holes into the standoffs. Insert the slide switch at an angle into the built-in holder.
Install Case to Bottom Base
Orient the case with the cutouts on the bottom base. Fit the case into the bottom base by press fitting snaps.
Secure Battery
Use a piece of double sided tape or mounting tack to secure the 400mAh battery to the bottom base.
Installing Spindles
The three spindles are secured to the top and bottom covers using M3 x 6mm long machine screws. They're symmetrical and can be installed in either direction.
Securing Spindles
Place one of the spindles onto the bottom covering that goes onto the top base. Line up the mounting holes and insert screw. Fasten tightly.
Secured Spindles
Repeat process for the other two spindles. Ensure the spindles are installed onto the correct side of the cover. Reference photo for correct placement.
Install Matrix Case
The matrix enclosure is press fitted into the covering that goes onto the bottom covering that goes onto the top base.
Bottom Cover – Top Base
The shape cutout in the center of the covering lines up with the end of the matrix enclosure. Firmly press the case through the covering so surfaces are flush.
Top Cover – Bottom Base
Insert the 4-pin JST cable from the matrix through the center hole of the top cover that goes onto the bottom base.
Install Cover to Matrix Case
Fit the end of the matrix case through the center hole of the top cover. Ensure the 4-pin JST cable is through the hole and accessible.
Secure Cover to Bottom Base
Insert and fasten three M3 x 6mm long machine screws to secure spindles to the top cover.
Connect Matrix to Feather
Grab the cable from the matrix and plug it into the JST cable on the Feather Sense. Double check the assembly is correctly installed.
Install Bottom Base
Fit the top cover onto the bottom base with the cut outs lined up properly. Firmly press edges together to snap fit shut.
Top Base
Install the top cover to the top base. The top base is symmetrical so it can be installed in either direction.
Install Top Base
Lastly, place the top base over the bottom cover and firmly press together to snap fit shut.
Page last edited August 18, 2025
Text editor powered by tinymce.