In this project we’re building an Infinity Cube with NeoPixels!

The frame is 3D printed and the acrylic panels are coated with see-through mirror film.

With mirrored acrylic, this creates a really neat effect that’s borderline magic!

LED strips inside the frame light up, making the acrylic appear transparent.

 

The panels reflect the light inside the cube creating a really cool tunnel effect.

We set this up with Bluetooth so we can trigger different LED animations.

The code for this project is written in CircuitPython and uses the ItsyBitsy nRF52840 microcontroller.

This uses the LED animation library, which makes creating sequences much easier.

There are lots of options for customization, so you can change colors and speed!

Parts

Adafruit ItsyBitsy nRF52840 Express - Bluetooth LE

PRODUCT ID: 4481
What's smaller than a Feather but larger than a Trinket? It's an Adafruit ItsyBitsy nRF52840 Express featuring the Nordic nRF52840 Bluetooth LE...
$17.95
IN STOCK

Adafruit Mini Skinny NeoPixel Digital RGB LED Strip - 144 LED/m

PRODUCT ID: 2970
So thin. So mini. So teeeeeeny-tiny. It's the 'skinny' version of our classic NeoPixel strips!These NeoPixel strips have 144 digitally-addressable pixel Mini LEDs...
$64.95
IN STOCK

Fully Reversible Pink/Purple USB A to micro B Cable - 1m long

PRODUCT ID: 4111
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also fully reversible! That's right, you will save seconds a day by...
$3.95
IN STOCK

Silicone Cover Stranded-Core Ribbon Cable - 10 Wire 1 Meter Long

PRODUCT ID: 3890
For those who are fans of our silicone-covered wires, but are always looking to up their wiring game. We now have Silicone Cover Ribbon cables! These may look...
$3.95
IN STOCK

USB Battery Pack - 2200 mAh Capacity - 5V 1A Output

PRODUCT ID: 1959
A smaller-sized rechargeable battery pack for your Raspberry Pi or Raspberry...
$14.95
IN STOCK
1 x Acrylic See-Through Mirror
12 x 12 inches (1mm thick)

This project was inspired by ThomasJ152's Infinity Cube

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.

NeoPixel Connections

  • G (ground) from ItsyBitsy nRF52840 to GND on NeoPixel strip
  • VHi (voltage) from ItsyBitsy nRF52840 to 5V on NeoPixel strip
  • 5! from ItsyBitsy nRF52840 to Din (Data In) on NeoPixel strip

USB Power

The ItsyBitsy nRF52840 can stay connected via USB power from either a 5V wall adapter or computer USB hub. This allows the project to stay on as long as you want (night light mode anyone?). 

3D Printed Parts

STL files for 3D printing are oriented to print "as-is" on FDM style machines. Original design source may be downloaded using the links below.

  • icube-frame.stl
  • icube-bottom.stl
  • icube-case.stl
  • icube-cover.stl

Case

The ItsyBitsy is press-fitted into the case. Tabs built into the case hold the PCB in place. The USB port is accessible on the side of the case. The top cover snap fits onto the case and has a slit for pass-through wiring. 

PolyCube

The frame of the cube is split into two pieces to allow for support-free 3D printing. The bottom half features posts for press-fitting into the frame. A hole on the corner allows for wiring to pass-through. Acrylic panels are press fitted into the six sides of the cube. 

Design Source Files

The project assembly was designed in Fusion 360. This can be downloaded in different formats like STEP, SAT and more. Electronic components like Adafruit's board, displays, connectors and more can be downloaded from the Adafruit CAD parts GitHub Repo.

Slicing Parts

No supports are required. Slice with setting 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

Setup ItsyBitsy nRF52840 with CircuitPython

We'll need to get our board setup so we can run the CircuitPython code. Let's walk through these steps to get the latest version of CircuitPython onto your board. 

The Mu Python Editor

Mu is a simple Python editor that works with Adafruit CircuitPython hardware. It's written in Python and works on Windows, MacOS, Linux and Raspberry Pi. The serial console is built right in, so you get immediate feedback from your board's serial output! While you can use any text editor with your code, Mu makes it super simple. Instructions for Mu are available here.

Installing or upgrading CircuitPython

You should ensure you have CircuitPython 4.0 or greater on your board. Plug your board in with a known good data + power cable (not the cheesy USB cable that comes with USB power packs, they are power only). You should see a new flash drive pop up.

If the drive is CIRCUITPY, then open the boot_out.txt file to ensure the version number is 4.0 or greater. 

Download: file
Adafruit CircuitPython 5.0.0-beta.3 on 2020-01-08; Adafruit ItsyBitsy nRF52840 Express with nRF52840

If you need to install or upgrade CircuitPython, see this guide page on the ItsyBitsy nRF52840.

Download the Adafruit CircuitPython Library Bundle

In order to run the code, we'll need to download a few libraries. Libraries contain code to help interface with hardware a lot easier for us.

Use the ItsyBitsy nRF52840 page on Installing Libraries to get the library that matches the major version of CircuitPython you are using noted above, i.e. 4.x for the versiond starting with 4, 5.x for the versions starting with 5, etc.

To run the code for this project, we need the two libraries in the Required Libraries list below. Unzip the library bundle and search for the libraries. Drag and drop the files into a folder named lib on the CIRCUITPY drive (create the folder if it is not already on the ItsyBitsy nRF52840).

Required Libraries 

  • neopixel.mpy
  • adafruit_dotstar.mpy
  • adafruit_bluefruit_connect
  • adafruit_ble
  • adafruit_led_animation

Once we have all the files we need, a directory listing will look similar to above as far as files and directories.

Upload Code

Click on the download link below to grab the main code directly from GitHub. Rename the file to code.py and drop it onto the CIRCUITPY drive main (root) directory. The code will run properly when all of the files have been uploaded including libraries.

Use any text editor or favorite IDE to modify the code. We suggest using Mu as noted above.

"""
NeoPixel Animator code for ItsyBitsy nRF52840 NeoPixel Animation and Color Remote Control.
"""

import board
import neopixel
from adafruit_led_animation.animation.comet import Comet
from adafruit_led_animation.animation.sparkle import Sparkle
from adafruit_led_animation.group import AnimationGroup
from adafruit_led_animation.sequence import AnimationSequence
import adafruit_led_animation.color as color

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.color_packet import ColorPacket
from adafruit_bluefruit_connect.button_packet import ButtonPacket

# The number of NeoPixels in the externally attached strip
# If using two strips connected to the same pin, count only one strip for this number!
STRIP_PIXEL_NUMBER = 43

# Setup for comet animation
COMET_SPEED = 0.05  # Lower numbers increase the animation speed
STRIP_COMET_TAIL_LENGTH = 10  # The length of the comet on the NeoPixel strip
STRIP_COMET_BOUNCE = False  # Set to False to stop comet from "bouncing" on NeoPixel strip

# Setup for sparkle animation
SPARKLE_SPEED = 0.1  # Lower numbers increase the animation speed

# Create the NeoPixel strip
strip_pixels = neopixel.NeoPixel(board.D5, STRIP_PIXEL_NUMBER, auto_write=False)

# Setup BLE connection
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

# Setup animations
animations = AnimationSequence(
    AnimationGroup(
        Sparkle(strip_pixels, SPARKLE_SPEED, color.TEAL)
    ),
    AnimationGroup(
        Comet(strip_pixels, COMET_SPEED, color.TEAL, tail_length=STRIP_COMET_TAIL_LENGTH,
              bounce=STRIP_COMET_BOUNCE)
    ),
)

animation_color = None
mode = 0
blanked = False

while True:
    ble.start_advertising(advertisement)  # Start advertising.
    was_connected = False
    while not was_connected or ble.connected:
        if not blanked:  # If LED-off signal is not being sent...
            animations.animate()  # Run the animations.
        if ble.connected:  # If BLE is connected...
            was_connected = True
            if uart.in_waiting:  # Check to see if any data is available from the Remote Control.
                try:
                    packet = Packet.from_stream(uart)  # Create the packet object.
                except ValueError:
                    continue
                if isinstance(packet, ColorPacket):  # If the packet is color packet...
                    if mode == 0:  # And mode is 0...
                        animations.color = packet.color  # Update the animation to the color.
                        print("Color:", packet.color)
                        animation_color = packet.color  # Keep track of the current color...
                    elif mode == 1:  # Because if mode is 1...
                        animations.color = animation_color  # Freeze the animation color.
                        print("Color:", animation_color)
                elif isinstance(packet, ButtonPacket):  # If the packet is a button packet...
                    if packet.pressed:  # If the buttons on the Remote Control are pressed...
                        if packet.button == ButtonPacket.LEFT:  # If button A is pressed...
                            print("A pressed: animation mode changed.")
                            animations.next()  # Change to the next animation.
                        elif packet.button == ButtonPacket.RIGHT:  # If button B is pressed...
                            mode += 1  # Increase the mode by 1.
                            if mode == 1:  # If mode is 1, print the following:
                                print("B pressed: color frozen!")
                            if mode > 1:  # If mode is > 1...
                                mode = 0  # Set mode to 0, and print the following:
                                print("B pressed: color changing!")

Double Check

See the directory listing above and double check that you have all the files listed to make this project function. If any are missing or in an incorrect directory, move them so they're in the right places.

Bluetooth App

This project uses the Adafruit Bluefruit LE connect app (available free for Android and iOS) to trigger the lights and sounds. It uses the control pad to trigger up to 8 different colors and sound effects. If you haven't downloaded the app yet, use the button below to install it on your mobile device.

Connect to ItsyBitsy nRF52840

Power on the ItsyBitsy nRF52840 by connecting it via USB to your computer.

Using Bluefruit LE Connect App

Open the Bluefruit LE Connect app and locate the device named CIRCUITPY and tap the connect button. Locate and tap on Controller. Under module, tab on Control Pad

Use the LEFT arrow button to cycle between the two animations.

Frame Assemble

Join the two frames. Align the pegs and press to join the top part to the frame. 

Add a drop of hot glue to the inside of the corners to adhere together.

NeoPixel Strip Preparation

Measure a low density strip (30 pixels per meter skinny pixels) to 65 pixels long. 

Trim off the included connector on the NeoPixel strips and then remove the sheathing from the strip.

Measure a 120mm long silicone ribbon cable and solder to the pads on the strip. 

Attach Strip to Frame

Pass the ribbon wire through the hole on the corner of the frame. 

Lay the strip around the inside of the frame with the LEDs facing towards the center of the frame. 

Trace the square around the inside of the frame and then continue lining the strip along the opposite square of the frame.

Attach Strip to Frame

Use hot glue to adhere the strip to the frame. Add small drop of hot glue to the middle length of the strip, on the solder pads as shown.

Use a can of compressed air if you would like to speed up the dry time of the hot glue.

Prep strip "branches"

Trim off the excess strip. We should have 18 pixels left.

Cut the remaining strip into three strips so each strip is now 6 pixels long. These will attach to the last three sections of the frame.

Solder 20mm long silicone ribbon cables to each strip.

Tin Strip back

The three smaller strips connect to the back of the main strip. 

Gently pull back the strip and tin the backs of the pads. 

Double check the connections on the pads a properly aligned and then solder together.

Flex "branch" strip

Carefully flex the strip towards the inside of the frame and adhere with a drop of hot glue to the frame.

Repeat with the other two strips. 

Solder the ItsyBitsy

Solder the +5v power connection on the NeoPixel strip to the VHI pad on the ItsyBitsy.

Solder the Din connection the strip to the 5! pad on the ItsyBitsy.

Solder the GND connection on the strip to the G pad on the ItsyBitsy. 

Test the strip to make sure all of the connections light up. 

Trace template

Use a marker to trace our template outlines to the acrylic sheet. 

Take note: the top and bottom templates are for the sections of the frame that are connected together in the first step.

Score acrylic

Use a scoring tool or a hobby knife to score the acrylic. 

Be careful in scoring the acrylic to avoid cutting yourself.

Acrylic Panel Template

Download the PDF and print it out on an 8.5in x 11in sheet of paper. The document is sized for 8in x 10in. The acrylic panels on the four sides are 89mm x 89mm. The top and bottom panels are 88mm – slightly smaller to accommodate for the orientation of the 3D printed surfaces.

Measure out the square panels with a ruler to verify the scaling was printed correctly.

Snap apart cuts

Carefully snap apart the acrylic along the scored sections to break them into panels.

Cut back plastic

Make sure to cut the back film to fully separate each acrylic panel.

Top and bottom panels

Test the top and bottom panels to ensure they properly fit into the frame. 

Peel film

Use gloves to keep the acrylic free of finger prints and smudges.

Remove the protective film on both sides. Note the blue film has two films on top of each other.

 

Test panels

Place the panels on two sides and turn on the LED strip to test the tunnel effect.

Warped panels

The panels may warp, so we'll want to make sure that they produce the proper tunneling effect.

Concave vs. Convex

We found laying the panels Concave on the frame produced the best tunneling effect on the frame, so make sure to test before gluing the panels to the frame.

 

Attach the Acrylic Panels

With the panels tested, we can add drops of hot glue to each corner of the frame and fit each panel to adhere to the frame.

Be careful not to ooze any hot glue over the panels, as it's difficult to remove. 

Glue Base

The lid is adhered to the frame. The lid then snap fits onto the base.

Apply hot glue around the hole and around the silicone cable. 

Align the slit on the lid over the cable and press over the glue to adhere.

Mount the ItsyBitsy

Align the ItsyBitsy to the USB port opening on the case and press fit between the walls at an angle. 

Coil the wires into the empty areas around the base and snap fit the base to the lid.

USB Port

Plug in a USB cable and battery to complete!

This guide was first published on Jan 14, 2020. It was last updated on Jan 14, 2020.