Build a zoetrope inspired visual art display with 3D printed parts and Adafruit CRICKIT.

This creates the illusion of motion by rotating a series of acrylic panels that feature engravings of a single frame of animation.

A NeoPxiel illuminates the artwork engraving on the acrylic panels and changes color each frame to make a stunning effect.

A zoetrope is an animation display that gives the illusion of motion by displaying a sequence of frames that progresses over time.

Powered by the Adafruit CRICKIT and Feather M4 running CircuitPython, this uses a DC motor and a photo interrupter to trigger a NeoPixel whenever the sensor detects a break.

The t-slot photo interrupter is mounted to the side of the enclosure and the NeoPixel is mounted on the other end right below the acrylic.

Each time the sensor detects a break, the NeoPixel changes color.

Parts

Angled shot of a Adafruit CRICKIT FeatherWing for any Feather
Sometimes we wonder if robotics engineers ever watch movies. If they did, they'd know that making robots into servants always ends up in a robot rebellion. Why even go down that...
Out of Stock
Angled shot of a Adafruit Feather M4 Express.
It's what you've been waiting for, the Feather M4 Express featuring ATSAMD51. This Feather is fast like a swift, smart like an owl, strong like a ox-bird (it's half ox,...
$22.95
In Stock
Glowing NeoPixel Mini Button PCB wired up to a microcontroller
These are the smallest NeoPixel breakouts around! Tiny, bright RGB pixels to your project. These little PCBs are only 8mm x 10mm and have two sets of three pads on the back for...
$4.95
In Stock
DC Gearbox Motor - TT Motor with two long wires and yellow body
Perhaps you've been assembling a new robot friend, adding a computer for a brain and other fun personality touches. Now the time has come to let it leave the nest and fly on...
$2.95
In Stock
T-Slot Photo Interrupter with solder tabs
This T-Slot Photo Interrupter is a simple plastic sensor with two elements - an IR LED and an IR photo-transistor, situated across a U-shaped gap. You can control...
Out of Stock
Top view video of a Black hand turning the knob on the adjustable power supply.
Put your Snap! cassette on and sing along to "I got the power!" with this super useful power supply adapter where...
$17.50
In Stock
1 x M3 Nylon Hardware Kit
Black Nylon Machine Screw and Stand-off Set – M3 Thread
1 x M2.5 Nylon Hardware Kit
Black Nylon Machine Screw and Stand-off Set – M2.5 Thread
1 x Jumper Wire 300mm long
Premium Female/Male 'Extension' Jumper Wires - 20 x 12"
1 x 10-wire Silicone Cover Ribbon Cable
Silicone Cover Stranded-Core Ribbon Cable - 10 Wire 1 Meter Long - 28AWG Black
2 x M3 x 30mm Long Screws
M3 Button Head Screw - 30mm long – For the motor
4 x Acrylic Sheet
1/8in thick Clear Acrylic Sheets

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.

Wired Connections

DC Motor

  • GND from motor to MOTOR 1 pin 
  • VCC from motoro to MOTOR ground pin

NeoPixel

  • DIN from NeoPixel to NeoPixel DIN on CRICKIT
  • 5V from NeoPixel to NeoPixel 5V on CRICKIT
  • GND from NeoPixel GND to NeoPixel GND on CRICKIT

Photo Interrupter

  • VCC (+) from sensor to 3.3V on CRICKIT
  • L from sensor to 3.3V on CRICKIT
  • GND (-) from sensor to GND on CRICKIT
  • OUT from sensor to Signal 1 on CRICKIT

Powering

The Feather and CRICKIT FeatherWing can be powered using a single 5V power supply.

A 5V 2A power supply connects to the DC jack on the CRICKIT board. In this project, an adjustable power supply is used.

Top view video of a Black hand turning the knob on the adjustable power supply.
Put your Snap! cassette on and sing along to "I got the power!" with this super useful power supply adapter where...
$17.50
In Stock

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

  • motor-gear
  • gear-ring
  • top-cover
  • bottom-plate
  • frame-cover
  • encoder-ring
  • inner-ring
  • led-mount
  • sensor-mount
  • crickit-mount

CAD Assembly

The acrylic panels features tabs that are fitted into the slots on the top cover. The encoder ring is secured to the top cover with screws. The gear ring is snap fitted into the center of the top cover. The motor gear is press fitted onto the shaft of the motor. The motor is secured to the bottom plate with screws. The NeoPixel LED is press fitted into a holder. The t-slot photo interrupter is mounted to the sensor holder. The LED and sensor holders are secured to the bottom plate with screws. An inner ring is secured to the bottom plate. The top cover assembly rests on the top grove of the inner ring. The enclosure frame is press fitted into the outer edges of the bottom plate.

Build Volume

The parts require a 3D printer with a minimum build volume.

  • 180mm (X) x 180mm (Y) x 100mm (Z)

Parrot Panels

The party parrot GIF animation was recreated for this project as vector artwork and can be produced using a laser cutter or CNC milling machine.

Each frame of the party parrot animation was engraved on one piece of acrylic.

Each panel features a tab with a number label depicting the frame of the animation.

The vector artwork have been specifically created as filled in outlines which are ideal for laser and CNC engraving.

Acrylic Panel Dimensions

Use 1/8in thick transparent acrylic for each panel.

  • 80mm (3.15in) x 70mm (2.76in)

CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.

The following instructions will show you how to install CircuitPython. If you've already installed CircuitPython but are looking to update it or reinstall it, the same steps work for that as well!

Set up CircuitPython Quick Start!

Follow this quick step-by-step for super-fast Python power :)

Click the link above and download the latest UF2 file.

Download and save it to your desktop (or wherever is handy).

Plug your Feather M4 into your computer using a known-good USB cable.

A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.

Double-click the Reset button next to the USB connector on your board, and you will see the NeoPixel RGB LED turn green. If it turns red, check the USB cable, try another USB port, etc. Note: The little red LED next to the USB connector will pulse red. That's ok!

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

You will see a new disk drive appear called FEATHERBOOT.

 

 

 

Drag the adafruit_circuitpython_etc.uf2 file to FEATHERBOOT.

The LED will flash. Then, the FEATHERBOOT drive will disappear and a new disk drive called CIRCUITPY will appear.

That's it, you're done! :)

Further Information

For more detailed info on installing CircuitPython, check out Installing CircuitPython.

Once you've finished setting up your Feather M4 Express with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.

To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.

# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

from adafruit_crickit import crickit

#  crickit setup
ss = crickit.seesaw
#  pin for photo interrupter
photo = crickit.SIGNAL1
ss.pin_mode(photo, ss.INPUT_PULLUP)

#  dc motor setup
motor = crickit.dc_motor_1

#  party parrot colors for the NeoPixel
parrot_0 = (255, 75, 0)
parrot_1 = (255, 200, 0)
parrot_2 = (90, 255, 90)
parrot_3 = (0, 255, 255)
parrot_4 = (0, 160, 255)
parrot_5 = (90, 0, 255)
parrot_6 = (175, 0, 255)
parrot_7 = (255, 0, 200)
parrot_8 = (255, 0, 125)
parrot_9 = (255, 0, 0)

colors = (parrot_0, parrot_1, parrot_2, parrot_3, parrot_4, parrot_5,
            parrot_6, parrot_7, parrot_8, parrot_9)

#  setup using crickit neopixel library
crickit.init_neopixel(1)
crickit.neopixel.fill((parrot_0))

#  counter for party parrot colors
z = 0
#  speed for the dc motor
speed = 0.3

while True:
    #  begin the dc motor
    #  will run throughout the loop
    motor.throttle = speed
    #  read the input from the photo interrupter
    data = ss.digital_read(photo)

    #  if the photo interrupter detects a break:
    if data is True:
        #  debug print
        print(z)
        #  change the neopixel's color to the z index of the colors array
        crickit.neopixel.fill((colors[z]))
        #  increase z by 1
        z += 1
        #  if z reaches the end of the colors array...
        if z > 9:
            #  index is reset
            z = 0

Upload the Code and Libraries to the Feather M4 Express

After downloading the Project Bundle, plug your Feather M4 Express into the computer's USB port. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather M4 Express's CIRCUITPY drive. 

  • lib folder
  • code.py

Your Feather M4 Express CIRCUITPY drive should look like this after copying the lib folder and the code.py file.

How the CircuitPython Code Works

The use of the adafruit_crickit library makes this code very straight forward.

First, the Crickit's Seesaw peripheral is setup, followed by the photo interrupter and dc motor's pins.

from adafruit_crickit import crickit

#  crickit setup
ss = crickit.seesaw
#  pin for photo interrupter
photo = crickit.SIGNAL1
ss.pin_mode(photo, ss.INPUT_PULLUP)

#  dc motor setup
motor = crickit.dc_motor_1

Party Colors

Next, the colors for the party parrot are created and inserted into the colors array. These will be accessed in the loop for the NeoPixel.

#  party parrot colors for the NeoPixel
parrot_0 = (255, 75, 0)
parrot_1 = (255, 200, 0)
parrot_2 = (90, 255, 90)
parrot_3 = (0, 255, 255)
parrot_4 = (0, 160, 255)
parrot_5 = (90, 0, 255)
parrot_6 = (175, 0, 255)
parrot_7 = (255, 0, 200)
parrot_8 = (255, 0, 125)
parrot_9 = (255, 0, 0)

colors = (parrot_0, parrot_1, parrot_2, parrot_3, parrot_4, parrot_5,
            parrot_6, parrot_7, parrot_8, parrot_9)

The adafruit_crickit library has its own unique way of setting up NeoPixels when you connect using the NeoPixel terminal on the board.

#  setup using crickit neopixel library
crickit.init_neopixel(1)
crickit.neopixel.fill((parrot_0))

Variables

Finally, two variables are setup, z and speed. z will act as the counter for the NeoPixel's color and speed will affect the speed of the DC motor.

#  counter for party parrot colors
z = 0
#  speed for the dc motor
speed = 0.3

The Loop

The loop begins by starting the DC motor. It will spin throughout the loop. data is also setup to hold the input from the photo interrupter.

#  begin the dc motor
    #  will run throughout the loop
    motor.throttle = speed
    #  read the input from the photo interrupter
    data = ss.digital_read(photo)

The main event is in the for statement. When the photo interrupter detects a break, then the NeoPixel's color is updated to the next color in the colors array. The index value is held by the variable z.

Once z overflows in value for the colors array, it is reset to 0 to loop through the array continuously.

#  if the photo interrupter detects a break:
    if data is True:
        #  debug print
        print(z)
        #  change the neopixel's color to the z index of the colors array
        crickit.neopixel.fill((colors[z]))
        #  increase z by 1
        z += 1
        #  if z reaches the end of the colors array...
        if z > 9:
            #  index is reset
            z = 0

Wiring NeoPixel

Use the jumper cable to create a 3-wire cable for connecting the NeoPixel to the CRICKIT board.

Cut the socket ends off and solder the wires to the DIN, 5V and GND pads on the NeoPixel.

Motor Extension Cable

The motor ships with prewired with a short cable and needs to be extended to reach the CRICKIT board.

Use the jumper cable to create a 2-wire extension cable for the motor.

Wiring Photo Interrupter

Use the jumper cable to create a 4-wire cable to connect the photo interrupter to the CRICKIT board.

Cut the socket ends of the wires and solder the wires to the L, VCC, GND and OUT pins on the photo interrupter.

Modify Motor Shaft

Locate the shaft on the motor. In order to fit the assembly properly, one end of the shaft will need to be trimmed using flush cutters.

Reference the photo for which end to remove – It's the side that features a nubbin.

Install Gear for Motor

The 3D printed gear for the motor is press fitted into the shaft of the motor.

Reference the photo for correct orientation for installing the gear.

The gear is placed over the shaft with about a millimeter of clearance.

Install NeoPixel to Holder

Insert the wires from the NeoPixel through the top of the cylinder in the holder.

Press the jumper wires through the hole on the side of the holder.

Secure NeoPixel to Holder

Thread the jumper wires from the NeoPixel through the holder.

Press the NeoPixel on to the top of the holder so the PCB snap fits into the recess. 

Secure Photo Interrupter to Holder

Use 2x M3 x 10mm long screws and hex nuts to secure the photo interrupter to the sensor holder.

Press fit the two M3 nuts into the holes on the sensor holder.

Place the sensor on to the holder and line up the mounting holes with the tabs.

Insert and fasten the screws through the tabs so the threads of the screws grab hold of the nuts.

Fit the wiring through the two build-in standoffs on the holder.

Install NeoPixel Holder to Bottom Plate

Use 2x M2.5 x 6mm long screws and hex nuts to secure the NeoPixel holder to the bottom cover.

Place the NeoPixel holder over the mounting holes on the bottom cover.

Orient the holder with the wires pointing in wards.

Insert the screws through the bottom cover and use hex nuts to secure the holder.

Install Motor to Bottom Plate

Use 2x M3 x 30mm long screws and hex nuts to secure the motor to the bottom plate.

Place the motor over the two standoffs in the center of the bottom plate.

Insert the screws through the bottom cover and body of the motor.

Use hex nuts to secure the motor to the bottom plate.

Secured Motor

Double check the motor is properly secured to the bottom plate.

Adjust the wiring so the cables they are pointing towards the same direciton. 

Installing Inner Ring

Use 4x M3 x 6mm long screws and hex nuts to secure the inner ring to the bottom plate.

Place the inner ring over the bottom plate and line up the tabs with the four mounting holes.

Secure Inner Ring to Bottom Plate

Adjust the cables from the components so they're routed through the cutouts on the inner ring.

Use hex nuts to secure the inners ring to the bottom plate.

Secure Encoder Ring to Top Cover

The encoder ring is secured to the top cover using 5x M2.5 x 10mm long screws and hex nuts.

Fit the encoder ring over the top cover so the tabs are lined up with the mounting holes.

Double check the notches in the encoder ring are lined up with the slots in the top cover.

Insert and fasten the screws through the holes on the side and secure using hex nuts.

Install Gear Ring to Top Cover

The gear ring is press fitted into the top cover with the notches lined up. 

Double check the orientation of the gear ring is able to fit trough the top cover.

Press the gear ring into the center of the top cover with the notches lined up.

Install Panels

Fit the tabs from the acrylic panels into the ten slots on the top cover.

Start with frame number one and proceed chronologically. The order of panels can be either clockwise or counter clockwise.

Use a flat filing tool to loosen up the edges if the slots are too tight.

Double check all of the panels are facing the same direction.

Install Frame Cover

The frame is press fitted into the groove on the edges of the bottom plate.

Place the cables through the semicircle cutouts along the sides of the framing.

Double check none of the wires are being pinched when installing the framing onto the bottom plate.

Wiring Adjustments

Take a moment to adjust the cables so they're neatly fitted through the cutouts in the assembly.

Install Top to Inner Ring

Get the top assembly ready to fit onto the inner ring.

Installing Top

Begin to fit the top assembly over the bottom plate.

Fit the encoder ring through the photo interrupter while placing top over the bottom plate.

Place the gear ring from the top so it engages the gear on the motor.

Press the top onto the inner ring so the lip is seated onto the grove in the inner ring.

Installed Top Assembly

Double check the top assembly is correctly installed.

The encoder ring should be fitted through the photo interrupter.

The two gears should be engaged and oriented properly.

The lip from the top cover should be fully seated onto the groove on the inner ring.

Secure CRICKIT

Use at least two M3 x 6mm long screws to secure the CRICKIT featherwing to the CRICKIT pcb mount.

Orient the CRICKIT board so the notches are line up with the various ports.

Connect Motor to CRICKIT

Insert the wires from motor to the motor pins on the CRICKIT.

Use a small screwdriver to loosen and tighten the screw block terminals.

Connect NeoPixel to CRICKIT

Insert the wires from the NeoPixel to the NeoPixel pins on the CRICKIT.

Use a small screwdriver to loosen and tighten the screw block terminals.

Connect Photo Interrupter to CRICKIT

Plug in the wires from the photo interrupter to the signal header pins on the CRICKIT.

Connect DC to CRICKIT

Plug in the DC barrel connector from the power supply to the DC jack on the CRICKIT board.

Final Build

Use the built-in power switch on the CRICKIT board to turn on the circuit.

Congratulations on your build!

This guide was first published on Feb 14, 2022. It was last updated on Nov 27, 2023.