Introduction: Electronic Dice - Raspberry Pi Pico

About: Hello, I am Vernon from NerdCave a DIY channel, I focus on microcontrollers and coding.

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.


Supplies

Components:

Raspberry Pi Pico - 1

Custom PCB - 1

5mm RED LEDs - 14

330-1K (Ohm ) Resistor - 14

12*12 mm Push Button - 3

2.54 mm Female Header pins - 2

3D printed Part - 1

3mm screw - 4


Tools / Equipment

Soldering Iron

Computer - Thonny

Screw Driver

Step 1: Design Phase

We need 7 LEDs to mimic all the possible shapes for a dice pattern as shown in the figure. This means we will at least need 7 LEDs per dice if we want to mimic a dice roll by lighting up the LEDs. To control these LEDs we will need a microcontroller. The microcontroller will randomly generate a number and with this number we can decide which LED to turn on. To start a role we will need input from the player which we can achieve through the help of a push button. The pattern we can use for the LEDs is shown in the second figure. This will help up later when we need to know which LED to turn on based on a random number generated. The microcontroller is discussed in Step 2.



Step 2: Raspberry Pi Pico

The Raspberry Pi Pico is a compact, low-cost, high-performance microcontroller board developed by the Raspberry Pi Foundation. It’s designed to provide a flexible and accessible platform for both beginners and professionals to create a wide range of digital projects and applications. The pinout for the Pico is shown in the Figure above. We have a lot of GPIO (general purpose input / output) pins we can use on the Pico Board making it a great choice for this type of project. We will be using MicroPython to program the Pico.


MicroPython

MicroPython is a lightweight implementation of the Python 3 programming language optimized to run on microcontrollers and embedded systems. It offers an easy-to-use and intuitive programming environment for developing projects on devices like the Raspberry Pi Pico.

To get started with MicroPython on the Raspberry Pi Pico, follow these steps:

  1. Install Thonny IDE: Thonny is a beginner-friendly Python IDE that supports MicroPython development. You can download and install it from the official website: Thonny IDE.
  2. Install MicroPython Firmware: Before you can start programming the Pico with MicroPython, you need to flash the MicroPython firmware onto the board. You can download the latest firmware from the official MicroPython website: MicroPython Downloads.
  3. Flash the Firmware: Connect your Raspberry Pi Pico to your computer using a USB cable. Put the Pico into bootloader mode by holding down the "BOOTSEL" button (usually labeled as "BOOT" on the Pico) while plugging in the USB cable. The Pico should appear as a USB storage device on your computer. Drag and drop the MicroPython firmware file onto the USB storage device. The Pico will automatically reboot after the firmware is flashed.
  4. Connect to Thonny IDE: Open Thonny IDE and go to Tools > Options > Interpreter. Select "MicroPython (Raspberry Pi Pico)" from the list of available interpreters. Thonny will detect the Pico connected to your computer and establish a connection.
  5. Start Coding: Now you can start writing and running MicroPython code on your Raspberry Pi Pico. You can use GPIO pins for digital input/output, control sensors, interface with displays, and much more.

Step 3: Breadboard Prototype

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

Using the pattern above we can write basic code that will allow us to random a number and light up the correct sequence of LEDs.

The code for this breadboard prototype:

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

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.

# 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.

# 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.

# 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
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.


Step 4: PCB ( JLCPCB )

With a working prototype we can create a custom PCB using EasyEda. The first 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 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:

You can download the the Gerber file here.

Once your receive your PCB you can solder all the components following the schematic diagram.

Step 5: Enclosure

The enclosure was designed in Fusion 360. The design is simple which we just fasten the PCB to the 3D printed enclosure by using 4 - 3mm screw. This part of the project you can go make you own custom case, when you make your own case please remember to share down below. You can download all the 3D files here: https://github.com/Guitarman9119/Raspberry-Pi-Pico-/tree/main/Pico%20Dice/3D%20model

Step 6: Code

With the code from the prototype all that we need to change is add the remaining LEDs and buttons in the code and upload to the Raspberry Pi Pico. Make sure when uploading the code to save it as main.py this will ensure that the code runs when the Pico boot up when receiving power through the USB.

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


Step 7: 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 below and I will respond asap. If you are interested in any other projects related to the Raspberry Pi Pico visit my instructables profile.