Maker.io main logo

Color Sensing Music Player

23

2026-03-31 | By Adafruit Industries

License: See Original Project 3D Printing Light Solder / Desoldering Third Hand / Vises Adafruit Feather

Courtesy of Adafruit

Guide by Ruiz Brothers and Liz Clark

Overview

blocks_1

Build a fun and playful 3D printed MP3 player with CircuitPython and an RP2040 PropMaker Feather! It's a boombox for young makers, but with a twist: use a color sensor to detect a LEGO DUPLO brick and play a song, sound effect, or audio clip. Each colored brick plays a different audio file.

You can use the Adalogger FeatherWing microSD card slot to add extra media storage to add as many MP3 audio files as you can store!

3D Printed Boombox

All of the electronics are housed in a 3D printed enclosure that features a storage bin for holding several DUPLO bricks. It features a 3W 4Ohm mono speaker that connects to the I2S audio amplifier that's built-into the RP2040 PropMaker Feather.

light_spin_2

Color Sensing Magic

Pop a DUPLO brick into the boombox and click the rotary knob to have it say what color the brick is. You can turn the knob to turn up or down the volume. The on-board NeoPixel LED will light up to the corresponding brick color.

light_colors_3

Detect Different Colors!

This project is configured to detect 11 different colors from the DUPLO brick box. You can add new colors by reading the values from the sensor and assigning a new MP3 file in the code. The code page in this guide will cover how it all works.

colors_4

Music featured in this project is by written by Dan Q for Adafruit. Check out all of Dan Q's music on the Adafruit Soundcloud page.

music_5

music_6

Parts

LEGO® DUPLO® Compatible

The project is designed to be compatible with 2x2 DUPLO bricks. The brick box set is a great beginner's kit featuring several bricks featuring different colors.

Hardware Fasteners

The following fasteners are required to assemble this project.

  • 12x M2.5 x 6mm steel machines crews

  • 6x M3 x 4mm steel machine screws

  • 10x M3 x 6mm steel machine screws

  • 4x M3 x 8mm steel machine screws

  • 4x M3 steel hex nuts

  • 2x M5 x 8mm steel machine screws

  • 2x M5 steel hex nuts

Circuit Diagram

The diagram below provides a general visual reference for wiring of the components once you get to the Assembly page. This diagram was created using the software package Fritzing.

Adafruit Library for Fritzing

Adafruit uses the Adafruit Fritzing parts library to create circuit diagrams for projects. You can download the library or just grab individual parts. Get the library and parts from GitHub - Adafruit Fritzing Parts.

diagram_7

Wired Connections

The PropMaker Feather RP2040 and Adalogger FeatherWing are fitted onto a FeatherWing Doubler.

The AS7341 color sensor is connected to the PropMaker Feather RP2040 via STEMMA QT cable.

The Rotary Encoder is connected to the color sensor via STEMMA QT Cable.

The speaker is connected to the speaker output pins on the PropMaker Feather RP2040 screw block terminals.

The slide switch is connected to the EN (enable) and GND (ground) pins on the FeatherWing Doubler.

The PropMaker Feather RP2040 is powered by a 3x AA battery back.

Install CircuitPython

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.

CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Download the latest version of CircuitPython for this board via circuitpython.org

Click the link above to download the latest CircuitPython UF2 file.

Save it wherever is convenient for you.

download_8

board_9

To enter the bootloader, hold down the BOOT/BOOTSEL button (highlighted in red above), and while continuing to hold it (don't let go!), press and release the reset button (highlighted in red or blue above). Continue to hold the BOOT/BOOTSEL button until the RPI-RP2 drive appears!

If the drive does not appear, release all the buttons, and then repeat the process above.

You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.

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

You will see a new disk drive appear called RPI-RP2.

Drag the adafruit_circuitpython_etc.uf2 file to RPI-RP2.

drag_10

drag_11

The RPI-RP2 drive will disappear, and a new disk drive called CIRCUITPY will appear.

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

drive_12

Safe Mode

You want to edit your code.py or modify the files on your CIRCUITPY drive but find that you can't. Perhaps your board has gotten into a state where CIRCUITPY is read-only. You may have turned off the CIRCUITPY drive altogether. Whatever the reason, safe mode can help.

Safe mode in CircuitPython does not run any user code on startup and disables auto-reload. This means a few things. First, safe mode bypasses any code in boot.py (where you can set CIRCUITPY read-only or turn it off completely). Second, it does not run the code in code.py. And finally, it does not automatically soft-reload when data is written to the CIRCUITPY drive.

Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the CIRCUITPY drive.

Entering Safe Mode

To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)

In Safe Mode

If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.

If you connect to the serial console, you'll find the following message.

Copy Code
Auto-reload is off.
Running in safe mode! Not running saved code.

CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.

You can now edit the contents of the CIRCUITPY drive. Remember, your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode.

Flash Resetting UF2

If your board ever gets into a really weird state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RPI-RP2. which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.

Download flash erasing "nuke" UF2

Code the Player

Once you've finished setting up your Feather Prop Maker with CircuitPython, you can access the code, MP3 files 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 to your computer as a zipped folder.

Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

"""Duplo Color Boombox"""

import board
import sdcardio
import storage
import audiobusio
import audiomixer
import audiomp3
from digitalio import DigitalInOut, Direction
from adafruit_as7341 import AS7341
from adafruit_seesaw import digitalio, neopixel, rotaryio, seesaw

#Power Setup
external_power = DigitalInOut(board.EXTERNAL_POWER)
external_power.direction = Direction.OUTPUT
external_power.value = True

#SD Card setup

spi = board.SPI()
cs = board.D10
sdcard = sdcardio.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

#Audio
try:
    mp3 = audiomp3.MP3Decoder(open("/sd/blue.mp3", "rb"))
except OSError as error:
    print(f"{error} - did you put the mp3 files on the micro SD card?")

i2s = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)
mixer = audiomixer.Mixer(voice_count=1, sample_rate=mp3.sample_rate, channel_count=1,
                         bits_per_sample=mp3.bits_per_sample)
i2s.play(mixer)
mixer.voice[0].level = 0.5

#Color Sensor
i2c = board.STEMMA_I2C()
sensor = AS7341(i2c)
sensor.led_current = 4  # increments in units of 4
sensor.led = False

brick_dictionary = [
    {'song': "/sd/blue.mp3", 'value': (1619, 13852, 19215, 18562, 12912, 8818, 9512, 5440),
     'color': ((0, 255, 255))},
    {'song': "/sd/orange.mp3", 'value': (2517, 3983, 5661, 6864, 16857, 39049, 55151, 35696),
     'color': ((255, 60, 0))},
    {'song': "/sd/coral.mp3", 'value': (3004, 6712, 7499, 7160, 13858, 46007, 65535, 39278),
     'color': ((250, 50, 50))},
    {'song': "/sd/purple.mp3", 'value': (2562, 20704, 19222, 15806, 16624, 18399, 27316, 22525),
     'color': ((125, 0, 255))},
    {'song': "/sd/red.mp3", 'value': (1453, 2629, 4050, 4656, 5527, 13403, 31096, 21368),
     'color': ((255, 0, 0))},
    {'song': "/sd/yellow.mp3", 'value': (3051, 4446, 8633, 17412, 37450, 48224, 56249, 34726),
     'color': ((255, 150, 0))},
    {'song': "/sd/butter.mp3", 'value': (4102, 8631, 13692, 29000, 58147, 63230, 65535, 43143),
     'color': ((255, 255, 0))},
    {'song': "/sd/green.mp3", 'value': (1383, 2767, 5850, 12964, 22118, 16304, 12669, 7008),
     'color': ((120, 255, 0))},
    {'song': "/sd/lime.mp3", 'value': (3017, 8109, 17948, 36761, 48754, 38009, 31671, 19457),
     'color': ((150, 255, 0))},
    {'song': "/sd/lightblue.mp3", 'value': (4188, 29507, 42326, 53214, 54067, 37512, 34129, 23544),
     'color':((100, 250, 255))},
    {'song': "/sd/white.mp3", 'value': (5246, 27506, 33883, 44702, 62766, 64254, 65535, 48334),
     'color':((255, 255, 255))},
    ]

def find_closest_brick(reading, dictionary, max_distance=50000):
    """
    Find the brick with the closest matching sensor values.

    Args:
        new_reading: Tuple of 8 sensor values
        brick_dictionary: List of brick dictionaries
        max_distance: Maximum distance to consider a valid match

    Returns:
        Tuple of (matched_brick, distance) or (None, distance) if no good match
    """
    best_match = None
    best_distance = float('inf')

    for brick in dictionary:
        # Calculate total distance (sum of absolute differences)
        distance = sum(abs(v1 - v2) for v1, v2 in zip(reading, brick['value']))

        if distance < best_distance:
            best_distance = distance
            best_match = brick

    # Only return a match if it's close enough
    if best_distance > max_distance:
        return None

    return best_match

#Rotary STEMMA I2C
seesaw = seesaw.Seesaw(i2c, 0x36)
encoder = rotaryio.IncrementalEncoder(seesaw)
seesaw.pin_mode(24, seesaw.INPUT_PULLUP)
switch = digitalio.DigitalIO(seesaw, 24)
switch_state = False

pixel = neopixel.NeoPixel(seesaw, 6, 1)
pixel.brightness = 1
pixel.fill((0, 0, 0))

last_position = -1
volume = 0.5 # volume
play = False
play_state = False

mp3 = audiomp3.MP3Decoder(open("/sd/boot.mp3", "rb"))
mixer.voice[0].play(mp3, loop=False)

while True:

    # make clockwise rotation positive
    position = -encoder.position

    if position != last_position:
        if position > last_position:
            #decrease volume
            volume = volume - 0.05
            volume = max(volume, 0)
        else:
            #increase volume
            volume = volume + 0.05
            volume = min(volume, 1)
        # set the audio volume
        mixer.voice[0].level = volume
        print(volume)
        last_position = position

    if not switch.value and not switch_state:
        print("Button pressed")
        switch_state = True
        if not play:
            sensor.led = True
            sensor_color = sensor.all_channels
            matched_brick = find_closest_brick(sensor_color, brick_dictionary)
            print(sensor_color)
            if matched_brick is not None:
                print(matched_brick['song'])
                mp3 = audiomp3.MP3Decoder(open(matched_brick['song'], "rb"))
                pixel.fill(matched_brick['color'])
                play = True
                mixer.voice[0].play(mp3, loop=False)
                play_state = True
            else:
                print("insert brick")
                mp3 = audiomp3.MP3Decoder(open("/sd/uhoh.mp3", "rb"))
                mixer.voice[0].play(mp3, loop=False)
        else:
            if play_state:
                i2s.pause()
                play_state = False
            else:
                i2s.resume()
                play_state = True

    if switch.value and switch_state:
        sensor.led = False
        switch_state = False
        print("Button released")

    if not mixer.playing:
        play_state = False
        play = False
        pixel.fill((0,0,0))

View on GitHub

Upload the Code and Libraries to the Feather Prop Maker

After downloading the Project Bundle, plug your Feather Prop Maker into the computer's USB port with a known good USB data+power cable. 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 Prop Maker's CIRCUITPY drive.

  • lib folder

  • code.py

Your Feather Prop Maker CIRCUITPY drive should look like this after copying the lib folder and code.py file:

file_12

Add MP3s to microSD Card

Mount the microSD card (FAT formatted) to your computer and add the MP3 audio files from the /mp3_files_for_sd_card folder from the Project Bundle to the root directly of the storage device. After adding the MP3s to the microSD card, remove it from the computer and pop it into the microSD card slot on the Adalogger FeatherWing.

Make sure the MP3s are added to the microSD card and NOT the SD folder in the CIRCUITPY drive.

added_13

How the CircuitPython Code Works

At the top of the code, the EXTERNAL_POWER pin is enabled to power up the peripherals on the Feather.

Download File

Copy Code
#Power Setup
external_power = DigitalInOut(board.EXTERNAL_POWER)
external_power.direction = Direction.OUTPUT
external_power.value = True

SD Card

The SD card is set up using sdcardio and is mounted to the /sd mount point. The mount point is set to readonly within CircuitPython so that it can be read/write on your OS when the CircuitPython drive is mounted. This means that you can drag and drop audio files to the SD card over USB.

Download File

Copy Code
#SD Card setup

spi = board.SPI()
cs = board.D10
sdcard = sdcardio.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

Audio

Next is the audio setup. For this project, MP3 audio files are used. The MP3 decoder and built-in I2S output are passed to a Mixer object. This lets you control the volume via software.

Download File

Copy Code
#Audio
mp3 = audiomp3.MP3Decoder(open("/sd/blue.mp3", "rb"))

i2s = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)
mixer = audiomixer.Mixer(voice_count=1, sample_rate=mp3.sample_rate, channel_count=1,
                         bits_per_sample=mp3.bits_per_sample)
i2s.play(mixer)
mixer.voice[0].level = 0.5

Color Sensor

The color sensor is instantiated over I2C and its white LED is turned off by default.

Download File

Copy Code
#Color Sensor
i2c = board.STEMMA_I2C()
sensor = AS7341(i2c)
sensor.led_current = 4  # increments in units of 4
sensor.led = False

A dictionary is used to hold each Duplo brick's MP3 audio file name, color reading and NeoPixel color. You can add or edit entries to the dictionary for additional bricks or to change up the associated MP3.

Download File

Copy Code
brick_dictionary = [
    {'song': "/sd/blue.mp3", 'value': (1619, 13852, 19215, 18562, 12912, 8818, 9512, 5440),
     'color': ((0, 255, 255))},
    {'song': "/sd/orange.mp3", 'value': (2517, 3983, 5661, 6864, 16857, 39049, 55151, 35696),
     'color': ((255, 60, 0))},
    {'song': "/sd/coral.mp3", 'value': (3004, 6712, 7499, 7160, 13858, 46007, 65535, 39278),
     'color': ((250, 50, 50))},
    {'song': "/sd/purple.mp3", 'value': (2562, 20704, 19222, 15806, 16624, 18399, 27316, 22525),
     'color': ((125, 0, 255))},
    {'song': "/sd/red.mp3", 'value': (1453, 2629, 4050, 4656, 5527, 13403, 31096, 21368),
     'color': ((255, 0, 0))},
    {'song': "/sd/yellow.mp3", 'value': (3051, 4446, 8633, 17412, 37450, 48224, 56249, 34726),
     'color': ((255, 150, 0))},
    {'song': "/sd/butter.mp3", 'value': (4102, 8631, 13692, 29000, 58147, 63230, 65535, 43143),
     'color': ((255, 255, 0))},
    {'song': "/sd/green.mp3", 'value': (1383, 2767, 5850, 12964, 22118, 16304, 12669, 7008),
     'color': ((120, 255, 0))},
    {'song': "/sd/lime.mp3", 'value': (3017, 8109, 17948, 36761, 48754, 38009, 31671, 19457),
     'color': ((150, 255, 0))},
    {'song': "/sd/lightblue.mp3", 'value': (4188, 29507, 42326, 53214, 54067, 37512, 34129, 23544),
     'color':((100, 250, 255))},
    {'song': "/sd/white.mp3", 'value': (5246, 27506, 33883, 44702, 62766, 64254, 65535, 48334),
     'color':((255, 255, 255))},
    ]

A function called find_closest_brick() is used to determine if the Duplo brick that is held up to the color sensor matches one of the defined colors in the dictionary. Since the color readings are analog and can vary depending on external light, the function returns the closest match to the current reading. If there isn't a close enough match, it returns None. You can change the sensitivity by adjusting the max_distance value.

Download File

Copy Code
def find_closest_brick(reading, dictionary, max_distance=50000):
    """
    Find the brick with the closest matching sensor values.

    Args:
        new_reading: Tuple of 8 sensor values
        brick_dictionary: List of brick dictionaries
        max_distance: Maximum distance to consider a valid match

    Returns:
        Tuple of (matched_brick, distance) or (None, distance) if no good match
    """
    best_match = None
    best_distance = float('inf')

    for brick in dictionary:
        # Calculate total distance (sum of absolute differences)
        distance = sum(abs(v1 - v2) for v1, v2 in zip(reading, brick['value']))

        if distance < best_distance:
            best_distance = distance
            best_match = brick

    # Only return a match if it's close enough
    if best_distance > max_distance:
        return None

    return best_match

Rotary Encoder

The seesaw rotary encoder is next. The built-in switch is used in the code, along with the NeoPixel.

Download File

Copy Code
#Rotary STEMMA I2C
seesaw = seesaw.Seesaw(i2c, 0x36)
encoder = rotaryio.IncrementalEncoder(seesaw)
seesaw.pin_mode(24, seesaw.INPUT_PULLUP)
switch = digitalio.DigitalIO(seesaw, 24)
switch_state = False

pixel = neopixel.NeoPixel(seesaw, 6, 1)
pixel.brightness = 1
pixel.fill((0, 0, 0))

States and Variables

There are a few variables and states that are used in the loop:

  • last_position - tracks the last position of the rotary encoder

  • volume - volume for the audio output through the Mixer object

  • play - state to track if a song has started playing

  • play_state - state to track if a song is actually playing or is paused\

Right before the loop, the boot.mp3 file is played through the speaker.

Download File

Copy Code
last_position = -1
volume = 0.5 # volume
play = False
play_state = False

mp3 = audiomp3.MP3Decoder(open("/sd/boot.mp3", "rb"))
mixer.voice[0].play(mp3, loop=False)

The Loop

In the loop, the rotary encoder position is monitored. If the position increases, the volume increases. If it decreases, the volume decreases.

Download File

Copy Code
while True:

    # make clockwise rotation positive
    position = -encoder.position

    if position != last_position:
        if position > last_position:
            #decrease volume
            volume = volume - 0.05
            volume = max(volume, 0)
        else:
            #increase volume
            volume = volume + 0.05
            volume = min(volume, 1)
        # set the audio volume
        mixer.voice[0].level = volume
        print(volume)
        last_position = position

Pressing the rotary encoder button initiates the color sensor to get a reading. The sensor LED turns on, gets a reading on all channels and passes the reading to the find_closest_brick() function. If the code finds a match, then it starts playing the associated MP3 file and lights up the NeoPixel with the associated color.

If a song is currently playing and the button is pressed, then the button toggles play/pause.

When the mixer is no longer playing the song, it resets play and play_state to False and turns off the NeoPixel.

Download File

Copy Code
if not switch.value and not switch_state:
        print("Button pressed")
        switch_state = True
        if not play:
            sensor.led = True
            sensor_color = sensor.all_channels
            matched_brick = find_closest_brick(sensor_color, brick_dictionary)
            print(sensor_color)
            if matched_brick is not None:
                print(matched_brick['song'])
                mp3 = audiomp3.MP3Decoder(open(matched_brick['song'], "rb"))
                pixel.fill(matched_brick['color'])
                play = True
                mixer.voice[0].play(mp3, loop=False)
                play_state = True
            else:
                print("insert brick")
                mp3 = audiomp3.MP3Decoder(open("/sd/uhoh.mp3", "rb"))
                mixer.voice[0].play(mp3, loop=False)
        else:
            if play_state:
                i2s.pause()
                play_state = False
            else:
                i2s.resume()
                play_state = True
    if switch.value and switch_state:
        sensor.led = False
        switch_state = False
        print("Button released")

    if not mixer.playing:
        play_state = False
        play = False
        pixel.fill((0,0,0))

3D CAD Files

3D Printed Parts

Individual 3MF files for 3D printing are oriented and ready to print on FDM machines using PLA filament. Original design source files may be downloaded using the links below.

printed_14

3mf.zip

CAD.zip

CAD Assembly

The Doubler FeatherWing is secured to the back cover using screws.

The back cover snap fits onto the case frame.

The rotary encoder, color sensor and speaker are secured to individual mounting plates which are attached to the front plate using screws.

The front plate is secured to the case framing with more screws.

The storage bin is fitted and sandwiched in between the back cover and case framing.

The handle is secured to the case framing using screws.

assembly_15

Build Volume

The parts require a 3D printer with a minimum build volume of 100 (X) x 70mm (Y) x 158mm (Z).

volume_16

Support Material

The duplo knob requires support material. Use your preferred slice settings for supports or reference the settings below.

  • Support Type: Tree

  • Branch distance: 5mm

  • Branch diameter: 6mm

  • Top interface layer: 2

knob_17

Design Source Files

The project assembly was designed in Fusion 360. Once opened in Fusion 360, It can be exported in different formats like STEP, STL and more.

Electronic components like Adafruit's boards, displays, connectors and more can be downloaded from the Adafruit CAD parts GitHub Repo.

boards_18

Feather Headers Setup

If you need a better explanation for soldering the headers for Feather products, you can review the guide below for tips and tricks.

headers_19

How To Solder Headers

By Erin St Blaine

Feathers and FeatherWings

View Guide

Headers

Gather up the headers needed for the Feather, Adalogger FeatherWing, and Doubler.

  • 2x 12-pin male headers

  • 2x 16-pin male headers

  • 2x 12-pin female headers

  • 2x 16-pin female headers

headers_20

Install Adalogger FeatherWing

Use a breadboard to help keep the headers straight while soldering.

Fit the 12-pin and 16-pin male header pins onto the bottom of the Adalogger FeatherWing PCB.

Solder all of the pins in place. Remove the Feather carefully from the breadboard when finished.

featherwing_20

featherwing_21

Install Feather Headers

Use a breadboard to help keep the headers straight while soldering.

Fit the 12-pin and 16-pin male header pins onto the bottom of the Feather RP2040 PropMaker PCB.

Solder all of the pins in place. Remove the Feather carefully from the breadboard when finished.

install_22

install_23

Install Double Headers

Fit the 12-pin and 16-pin female headers onto the male headers that are soldered on the Feather and FeatherWing.

Then, place the female headers onto the top of the FeatherWing Doubler, making sure the pins are inserted in the correct location.

Keep the pins in place while soldering all of the pins together.

double_24

double_25

double_26

Installed Headers

Remove the Feather RP2040 PropMaker and Adalogger FeatherWing from the FeatherWing Doubler.

Make sure all of the headers have sufficient solder and strong joints.

installed_27

Disable LiPo Charging

Use a sharp hobby knife to cut the LiPo Charging trace on the back of the PropMaker Feather RP2040. This must be cut to prevent accidental battery calamity with alkaline batteries when USB is plugged in.

disable_28

Be careful when using a hobby knife to cut the trace to insure you are safe and only the part you want to cut is cut and nothing else.

Disable LED on Sensor

Use a sharp hobby knife to cut the LED trace on the back of the AS7341 light sensor. This needs to be cut to prevent accidental color sensing light leaking from the green LED.

sensor_29

Wiring the Switch

If you are unsure about your soldering skills, there is an excellent guide to help:

soldering_30

Adafruit Guide To Excellent Soldering

By Bill Earl

Tools

View Guide

Slide Switch Wires

Prepare a set of two wires about 3.5inches (9cm) in length.

Using wire strippers, remove a bit of insulation from the tips of each wire.

Tin the exposed wire by applying a bit of solder to them.

This will help prevent the strands of wire from fraying.

slide_31

Prep the Slide Switch

Snip off one of the leads on the slide switch, either the far left or right but not the middle. Then trim the two remaining leads short, about half their length.

prep_32

Be sure to wear eye protection when cutting small bits of metal which may fly in unpredictable directions.

Solder Wires

Solder the two wires to each of the leads on the slide switch.

A pair of helping hands can assist while soldering wires in place.

solder_33

Connect Switch to Doubler FeatherWing

Solder one wire to a ground pin on the Doubler FeatherWing.

Then, solder the remaining wire to the EN (enable) pin.

connect_34

Soldered Switch

Double check the wires from the slider have been soldered to the correct pins on the Doubler FeatherWing.

switch_35

Switch Power Test

Test the slide switch by connecting the Feather RP2040 PropMaker to the Doubler FeatherWing.

Install 3x AA batteries into the AA battery holder.

Plug in the cable from the AA battery pack. Ensure the built-in switch is on the ON position.

Use the slide switch to power on the Feather.

The Feather on-board NeoPixel LED should light up indicating it is getting power.

Then use the slide switch to power off the Feather.

power_36

power_37

Assembly

Install Doubler

Use 4x M2.5x 6mm long machine screws to secure the Doubler FeatherWing to the back cover.

Place the Doubler PCB over the four standoffs on the back cover.

Insert and fasten the M2.5 to secure the Doubler FeatherWing to the back cover.

install_38

install_39

install_40

Set Up the Switch Holder

Insert the slide switch into the switch holder at an angle.

Then firmly press the body of the switch so it sets flush with the surfaces of the holder.

holder_41

holder_42

holder_43

Secure the Switch Holder

Use two M3 x 4mm long machine screws to secure the switch holder to the back cover.

Place the switch holder over the cutout for the switch with the two mounting holes lined up.

Insert and fasten the M3 screws to secure the switch holder to the back cover.

The slide switch actuator should be accessible on the other side of the back cover.

secure_44

secure_45

secure_46

Install the Adalogger FeatherWing

Insert the microSD card into the microSD card slot on the Adalogger FeatherWing.

Install the Adalogger FeatherWing onto the upper section on the Doubler FeatherWing.

Firmly press down to fully seat the PCB.

card_47

card_48

Install Feather

With the battery connected to the Feather RP2040 PropMaker, fit it onto the remaining section on the Doubler FeatherWing.

Firmly press down to fully seat the PCB.

feather_49

feather_50

Install Battery

Place the AA battery holder onto the back cover in between the four walls.

Slide the battery clip over the battery holder so the keyed edge is fitted in between the rails on the back cover.

Ensure the battery clip is fitted correctly and the battery holder is secured to the back cover.

battery_51

battery_52

battery_53

Speaker Plate

Use four M3 x 8mm long machine screws and hex nuts to secure the speaker to the speaker plate.

Place the speaker plate over the speaker with the mounting holes lined up.

While holding the two in place, insert a machine screw and thread a hex nut to secure them together.

Repeat for all four mounting holes.

speaker_54

speaker_55

speaker_56

Install the Color Sensor

Use four M2.5 x 6mm long machine screws to secure the color sensor to the sensor mounting plate.

Place the color sensor over the four standoffs so the mounting holes are lined up.

While holding parts together, insert and fasten the machine screws to secure them together.

color_57

color_58

color_59

Rotary Mounting Plate

Remove the washer and hex nut from the rotary encoder.

Insert the shaft of the rotary encoder through the hole in the rotary mounting plate.

Orient the PCB so the STEMMA QT connectors are lined up with the notches on the wall of the mounting plate.

Insert the washer over the shaft and thread the hex nut.

Firmly tighten the hex nut to secure the rotary encoder to the mounting plate.

rotary_60

rotary_61

rotary_62

Front Plate Installation

Orient the front plate with the case frame.

Insert the front place into the case frame. Firmly press down so the front plate sits flush with the case frame.

front_63

front_64

front_65

Secure the Front Plate

Use six M3 x 6mm long machine screws to secure the front plate to the case frame.

Insert and fasten six M3 screws to secure the front plate to the case frame.

secure_66

secure_67

secure_68

Secure Speaker Plate

Use for M3 x 4mm long machine screws to secure the speaker mounting plate to the front plate.

Place the speaker mounting plate over the speaker standoffs on the front plate.

While holding parts together, insert and fasten the screws to secure the parts together.

plate_69

plate_70

Connect STEMMA QT

Get the two STEMMA QT cables ready to connect to the rotary encoder and color sensor.

Connect the longer STEMMA QT cable to the left side of the color sensor.

Use the shorter STEMMA QT cable to connect the color sensor to the rotary encoder.

stemma_71

stemma_72

Secure the Color Sensor

Place the color sensor mounting plate over the sensor standoffs on the front plate.

While holding the mounting plate in place, insert and fasten four M2.5 x 6mm long machine screws to secure the sensor mount to the front plate.

sensor_73

sensor_74

sensor_75

Secure Rotary Plate

Place the rotary mounting plate over the remaining standoffs on the front plate.

While holding the plate in place, insert and fasten four M3 x 6mm long machine screws to secure the rotary mount to the front plate.

place_76

place_77

place_78

Check all the Parts

Double check all of the mounting plates are sitting flush with the front plate and all of the screws are fully tightened.

check_79

Install the Handle

Use two M5 x 8mm machine screws and hex nuts to secure the handle to the case frame.

Slide the handle over the case frame so the two mounting holes line up.

While holding parts, insert and fasten the screws to secure the handle to the case.

Insert and thread the M5 hex nuts to the screws.

handle_80

handle_81

handle_82

Tighten the Handle

Ensure the hex nuts are fully seated. Use a pair of vise grips or pliers to fully tighten the hex nuts.

tighten_83

Connecting the Speaker

Insert the two-colored wires from the speaker into the speaker pins on the Feather RP2040 PropMaker.

Use a slotted screwdriver to secure the speaker wires to the screw block terminals.

speaker_84

speaker_85

Connect the STEMMA QT Cable

Plug in the longer STEMMA QT cable to the connector on the Feather RP2040 PropMaker.

cable_86

Connected Parts

Double check the cables are secured.

cable_87

Install the Storage Bin

Slide the storage bin into the case frame so the walls are fitted in between the ridges of the storage bin.

storage_88

storage_89

Install the Back Cover

Begin fitting the back cover over the case framing, making sure the cables are fitted inside.

Firmly press the back cover onto the case to snap fit them closed.

back_90

back_91

back_92

Install the Knob

Orient the rotary knob with the shaft of the rotary encoder.

Line up the flat edges while inserting the knob.

Firmly press the knob to fully seat the parts together.

Test the knob by rotating, ensuring it moves ok.

knob_93

knob_94

knob_95

Power Test

Use the slide switch to power on the Feather RP2040 PropMaker.

Test the color sensor by inserting a Duplo brick and pressing the rotary encoder knob. The LED should change color to the color of the brick used.

test_96

test_97

Storing Bricks

Use the storage bin to hold a few Duplo bricks.

Stacked bricks (5 in total) can be fitted into the storage bin.

bricks_98

bricks_99

bricks_100

The Finished Build

Congratulations on your build! The projects code is set to read 11 colors, which are included with the Duplo brick box starter set.

Use

Playing MP3s

  1. Insert a DUPLO brick into the color sensing area.

  2. Click rotary encoder to play MP3.

  3. The built-in NeoPixel lights up to corresponding brick color.

While playing audio, click the rotary knob to pause/play. Turn rotary knob to increase/decrease the volume.

If no brick is detected, an audible "Uh Oh" sound will be played.

light_demo1

Mfr Part # 5768
ADAFRUIT RP2040 PROP-MAKER FEATH
Adafruit Industries LLC
$ 19,95
View More Details
Mfr Part # 2922
ADALOGGER FEATHERWING - RTC + SD
Adafruit Industries LLC
Mfr Part # 4698
STEMMA QT AS7341 COLOR SENSOR
Adafruit Industries LLC
$ 18,95
View More Details
Mfr Part # 5880
ADAFRUIT I2C STEMMA QT ROTARY EN
Adafruit Industries LLC
Mfr Part # 4445
SPEAKER 4OHM TOP PORT
Adafruit Industries LLC
Mfr Part # 2890
FEATHERWING DOUBLER - PROTOTYPIN
Adafruit Industries LLC
Mfr Part # 4474
CABLE A PLUG TO C PLUG 3'
Adafruit Industries LLC
Mfr Part # 4401
STEMMA QWIIC JST SH CABLE 200MM
Adafruit Industries LLC
Mfr Part # 4399
STEMMA QWIIC JST SH CABLE 50MM
Adafruit Industries LLC
Mfr Part # 5252
MEM CARD MICROSD 512MB CLASS 4
Adafruit Industries LLC
Mfr Part # 4779
BATTERY HOLDER AA 3 CELL LEADS
Adafruit Industries LLC
Mfr Part # 805
BREADBOARD-FRIENDLY SPDT SLIDE S
Adafruit Industries LLC
Mfr Part # 3891
CBL RIBN 4COND FLAT BLACK 3.28'
Adafruit Industries LLC
Mfr Part # 2886
FEATHER HEADER KIT FML
Adafruit Industries LLC
Mfr Part # 291
MAGNIFIER STAND 2.5" 4X
Adafruit Industries LLC
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.