Raspberry Pi Pico Dice

Introduction

In this project tutorial, we are going to make a Raspberry Pi Pico Dice. The dice allows you to emulate two dice rolls. It is a fun beginner project for anyone starting out learning the Raspberry Pi Pico.

Disclaimer - JLCPCB was generous enough to sponsor this project and provide the PCB used in this project.

Components + Tools Breakdown

ComponentQuantityQuantity
Raspberry Pi Pico11
Custom PCB (JLCPCB)11
14 - 5mm LEDs14Few
330-1k Ohm Resistor145
3D printed parts1Few printed parts
3mm screw4Explained in steps
Tools / Equipment
Soldering Iron + Solder
Computer + Thonny IDE
Screw driver

Breadboard Prototype

A simple dice was first made on breadboard for testing. The following circuit diagram was used.

We need 7 LEDs to mimic all the possible shapes for a dice pattern as shown in the following figure

We will recreate this patterns later when designing the PCB.

Prototype Code

The code for the breadboard is as follows

from machine import Pin
import utime
import urandom

urandom.seed(utime.ticks_us())

# Define the LED pins for the Dice
dice1_leds = [Pin(i, Pin.OUT) for i in range(0, 7)]


# Define the button pin
button1 = Pin(14, Pin.IN, Pin.PULL_DOWN)


# Define the LED patterns for each number
numbers = [
    [0, 0, 0, 1, 0, 0, 0],  # 1
    [1, 0, 0, 0, 0, 0, 1],  # 2
    [1, 0, 0, 1, 0, 0, 1],  # 3
    [1, 1, 0, 0, 0, 1, 1],  # 4
    [1, 1, 0, 1, 0, 1, 1],  # 5
    [1, 1, 1, 0, 1, 1, 1],  # 6
]

# Function to turn off LEDs of a specific dice
def turn_off_leds(dice_leds):
    for led in dice_leds:
        led.value(0)

# Function to show a number on the dice
def show_number(dice_leds, number):
    # Get the LED pattern for the number
    pattern = numbers[number - 1]
    
    # Loop over each LED in the dice
    for i in range(len(dice_leds)):
        # Get the corresponding LED and its value from the pattern
        led = dice_leds[i]
        value = pattern[i]
        
        # Set the LED to the value from the pattern
        led.value(value)

# Main loop
while True:
    if button1.value() == 1:
        utime.sleep(0.3)  # Wait for 2 seconds to ensure the button is pressed long enough
        if button1.value() == 1:  # Check again if the button is still pressed
            utime.sleep_ms(urandom.randint(0, 200))  # Random delay before generating the number
            show_number(dice1_leds, urandom.randint(1, 6))
            utime.sleep(2)  # Keep the LEDs on for 2 seconds
            turn_off_leds(dice1_leds)  # Then turn them off

    utime.sleep_ms(10)  # Short delay to debounce the button

Code - Breakdown

Importing Libraries

machine import Pin
import utime
import urandom

urandom.seed(utime.ticks_us())

In these lines, three libraries are imported: Pin from machine, utime, and urandom. Pin is used to control GPIO pins, utime is used for access to time-related functions, and urandom is used to generate random numbers. The seed for random numbers is set using the current time in microseconds.

Defining LED and Button Pins

# Define the LED pins for the 
Dicedice1_leds = [Pin(i, Pin.OUT) for i in range(0, 7)]
# Define the button 
pinbutton1 = Pin(14, Pin.IN, Pin.PULL_DOWN)

Here, LED pins for the dice are set as outputs ranging from 0 to 6. The button pin is set as an input- 14, with a pull-down resistor. This means that when the button is not pressed, the button pin reads as 0 or False.

Defining LED Number Patterns

# Define the LED patterns for each number
numbers = [
    [0, 0, 0, 1, 0, 0, 0],  # 1
    [1, 0, 0, 0, 0, 0, 1],  # 2
    [1, 0, 0, 1, 0, 0, 1],  # 3
    [1, 1, 0, 0, 0, 1, 1],  # 4
    [1, 1, 0, 1, 0, 1, 1],  # 5
    [1, 1, 1, 0, 1, 1, 1],  # 6
]

These lines define the patterns for each number as it would appear on the dice. 0 would turn an LED off, and 1 would turn it on.

Functions to Handle LEDs

# Function to turn off LEDs of a specific dice
def turn_off_leds(dice_leds):
    for led in dice_leds:
        led.value(0)

This function turns off all the LEDs on the dice by setting their values to 0.

# Function to show a number on the dice
def show_number(dice_leds, number):
    # Get the LED pattern for the number
    pattern = numbers[number - 1]
    
    # Loop over each LED in the dice
    for i in range(len(dice_leds)):
        # Get the corresponding LED and its value from the pattern
        led = dice_leds[i]
        value = pattern[i]
        
        # Set the LED to the value from the pattern
        led.value(value)

The show_number() function takes in the dice’s LED info and a number, then sets the appropriate LEDs on to display that number.

Main Loop

# Main loop
while True:
    if button1.value() == 1:
        utime.sleep(0.3)  # Wait for 2 seconds to ensure the button is pressed long enough
        if button1.value() == 1:  # Check again if the button is still pressed
            utime.sleep_ms(urandom.randint(0, 200))  # Random delay before generating the number
            show_number(dice1_leds, urandom.randint(1, 6))
            utime.sleep(2)  # Keep the LEDs on for 5 seconds
            turn_off_leds(dice1_leds)  # Then turn them off

    utime.sleep_ms(10)  # Short delay to debounce the buttons

In the main loop, a check is done as to whether the button has been pressed. If yes, a sleep of 0.3 seconds is implemented (to avoid phantom readings), after which it’s confirmed if the button is still pressed. If still pressed, a randomly timed delay is executed then the dice number gets displayed using show_number. The LEDs stay illuminated for 2 seconds, then get turned off. The button is then debounced with a short delay before the loop repeats.

PCB ( JLCPCB )

PCB Design

With a working prototype we can create a custom PCB using EasyEda. The following figure is the schematic diagram for the Pico Dice PCB. Since we have access to 26 GPIO pins on the Pico we can connect all the LEDs to its own GPIO pin and don’t require any special drivers to control all the LEDs.

The following figure is the layout of the components on the PCB, which as shown above mimics the patterns of a typical dice.

The PCB was ordered through JLCPCB. They offer great PCBs at a low cost and have promotions and coupons available throughout the year. You can sign up using here, or using the following link:

https://jlcpcb.com/?from=Nerd that will support me as a creator to keep making content that is accessible and open source at no charge to you.

Ordering the PCB is very simple:

Download the Gerber file here.

Click on Add Gerber file

leave all the settings as default given. You might want change the PCB color which you can do here:

Enter you shipping details, save to cart

Then after a few days depending on your location you will receive your great quality PCB.

Final Code

from machine import Pin
import utime
import urandom

urandom.seed(utime.ticks_us())


# Define the LED pins for the two dice
dice1_leds = [Pin(i, Pin.OUT) for i in range(0, 7)]
dice2_leds = [Pin(i, Pin.OUT) for i in range(7, 14)]

# Define the button pins
button1 = Pin(14, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(15, Pin.IN, Pin.PULL_DOWN)
button3 = Pin(16, Pin.IN, Pin.PULL_DOWN)

# Define the LED patterns for each number
numbers = [
    [0, 0, 0, 1, 0, 0, 0],  # 1
    [1, 0, 0, 0, 0, 0, 1],  # 2
    [1, 0, 0, 1, 0, 0, 1],  # 3
    [1, 1, 0, 0, 0, 1, 1],  # 4
    [1, 1, 0, 1, 0, 1, 1],  # 5
    [1, 1, 1, 0, 1, 1, 1],  # 6
]

# Function to turn off LEDs of a specific dice
def turn_off_leds(dice_leds):
    for led in dice_leds:
        led.value(0)

# Function to show a number on the dice
def show_number(dice_leds, number):
    # Get the LED pattern for the number
    pattern = numbers[number - 1]
    
    # Loop over each LED in the dice
    for i in range(len(dice_leds)):
        # Get the corresponding LED and its value from the pattern
        led = dice_leds[i]
        value = pattern[i]
        
        # Set the LED to the value from the pattern
        led.value(value)

# Main loop
while True:
    if button1.value() == 1:
        utime.sleep(0.3)  # Wait for 2 seconds to ensure the button is pressed long enough
        if button1.value() == 1:  # Check again if the button is still pressed
            utime.sleep_ms(urandom.randint(0, 200))  # Random delay before generating the number
            show_number(dice1_leds, urandom.randint(1, 6))
            utime.sleep(2)  # Keep the LEDs on for 5 seconds
            turn_off_leds(dice1_leds)  # Then turn them off
    elif button2.value() == 1:
        utime.sleep(0.3)
        if button2.value() == 1:
            utime.sleep_ms(urandom.randint(0, 200))  # Random delay before generating the number
            dice1_number = urandom.randint(1, 6)
            dice2_number = urandom.randint(1, 6)
            show_number(dice1_leds, dice1_number)
            show_number(dice2_leds, dice2_number)
            utime.sleep(3)  # Keep the LEDs on for 5 seconds
            turn_off_leds(dice1_leds)  # Then turn them off
            turn_off_leds(dice2_leds)  # Then turn them off
    elif button3.value() == 1:
        utime.sleep(0.3)
        if button3.value() == 1:
            utime.sleep_ms(urandom.randint(0, 200))  # Random delay before generating the number
            show_number(dice2_leds, urandom.randint(1, 6))
            utime.sleep(2)  # Keep the LEDs on for 5 seconds
            turn_off_leds(dice2_leds)  # Then turn them off
    utime.sleep_ms(10)  # Short delay to debounce the buttons



Enclosure

The enclosure was designed in Fusion 360.

You can download all the 3D files here: https://github.com/Guitarman9119/Raspberry-Pi-Pico-/tree/main/Pico%20Dice/3D%20model

Conclusion

This is a simple project, but it a perfect project for beginners that just started out with soldering, coding and 3D modelling.

If you have any questions you can comment on my YouTube video, and while you are on my video consider subscribing to the channel.