RGB Matrix Dreidel Game
2022-01-13 | By Adafruit Industries
License: See Original Project STEMMA
Courtesy of Adafruit
Guide by Liz Clark
Overview
In this project, you can build your own electronic dreidel game, complete with a servo motor and festive music, to celebrate Hanukkah. To play, drop chocolate coins into the slot at the top of the matrix. The RGB matrix will spin the dreidel while playing the classic dreidel song. If you roll gimel, you win! All of the chocolate coins will spill out for you.
An IR breakbeam sensor is located at the top of the matrix to detect when a chocolate coin is dropped. This triggers the dreidel to spin.
A servo motor is attached to the chocolate coin cup. The servo tilts the cup when the dreidel sprite sheet lands on gimel.
A STEMMA speaker plays the dreidel song while the RGB matrix spins the dreidel.
If you've ever played dreidel before, you'll note that this version is slightly modified since it doesn't account for rolling hei to get half of the pot. A servo dumping out the entire pot when you roll gimel should hopefully make up for that though.
Parts
Adafruit Matrix Portal - CircuitPython Powered Internet Display
IR Break Beam Sensor with Premium Wire Header Ends - 5mm LEDs
1 x M2 Screws
1 x Package of chocolate coins
Circuit Diagram
Wiring Connections
STEMMA Speaker
Speaker GND to MatrixPortal M4 GND
Speaker Power to MatrixPortal M4 Power
Speaker SIG to MatrixPortal M4 A0
IR Breakbeam Sensor
Receiver black wire to MatrixPortal M4 GND
Receiver red wire to MatrixPortal M4 3V
Receiver yellow wire to MatrixPortal M4 A1
Transmitter black wire to MatrixPortal M4 GND
Transmitter red wire to MatrixPortal M4 3V
Servo
Servo black wire to MatrixPortal M4 GND
Servo red wire to MatrixPortal M4 5V
Servo yellow wire to MatrixPortal M4 A4
3D Printing
The RGB Matrix Dreidel Game uses some 3D printed parts to complete the build. All of the parts can print without supports.
It consists of three parts:
matrixDreidel_roof
matrixDreidel_legs
matrixDreidel_bucket
The files can be downloaded directly here or through Thingiverse.
The roof mounts to the top of the RGB matrix and has mounts for the breakbeam sensor. The sensors are placed on either side of the chocolate coin slot.
The legs mount to the bottom of the RGB matrix and allow it to stand up freely. Additionally, it has mounts for the servo motor and the STEMMA speaker.
The bucket attaches to the servo motor horn and will catch the chocolate coins as they're dropped in through the slot at the top.
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.
Set up CircuitPython Quick Start!
Follow this quick step-by-step for super-fast Python power :)
Download the latest version of CircuitPython for this board via circuitpython.org
Further Information
For more detailed info on installing CircuitPython, check out Installing CircuitPython.
Click the link above and download the latest UF2 file.
Download and save it to your desktop (or wherever is handy).
Plug your MatrixPortal 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 (indicated by the green arrow) on your board, and you will see the NeoPixel RGB LED (indicated by the magenta arrow) turn green. If it turns red, check the USB cable, try another USB port, etc.
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 MATRIXBOOT.
Drag the adafruit_circuitpython_etc.uf2 file to MATRIXBOOT.
The LED will flash. Then, the MATRIXBOOT drive will disappear and a new disk drive called CIRCUITPY will appear.
That's it, you're done! :)
Coding the RGB Matrix Dreidel Game
Once you've finished setting up your MatrixPortal M4 with CircuitPython, you can access the code, audio file, bitmap 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: 2021 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time import random import board import pwmio import displayio import adafruit_imageload from audiocore import WaveFile from audioio import AudioOut from adafruit_motor import servo from digitalio import DigitalInOut, Direction, Pull from adafruit_matrixportal.matrix import Matrix # setup for down button on matrixportal switch = DigitalInOut(board.BUTTON_DOWN) switch.direction = Direction.INPUT switch.pull = Pull.UP # setup for break beam sensor break_beam = DigitalInOut(board.A1) break_beam.direction = Direction.INPUT break_beam.pull = Pull.UP # pwm for servo servo_pwm = pwmio.PWMOut(board.A4, duty_cycle=2 ** 15, frequency=50) # servo setup servo = servo.Servo(servo_pwm) servo.angle = 90 # import dreidel song audio file wave_file = open("dreidel_song.wav", "rb") wave = WaveFile(wave_file) # setup for audio out audio = AudioOut(board.A0) # setup for matrix display matrix = Matrix(width=32, height=32) display = matrix.display group = displayio.Group() # import dreidel bitmap dreidel_bit, dreidel_pal = adafruit_imageload.load("/dreidel.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) dreidel_grid = displayio.TileGrid(dreidel_bit, pixel_shader=dreidel_pal, width=1, height=1, tile_height=32, tile_width=32, default_tile=0, x=0, y=0) group.append(dreidel_grid) # show dreidel bitmap display.show(group) timer = 0 # time.monotonic() holder spin = 0 # index for tilegrid speed = 0.1 # rate that bitmap updates clock = 0 # initial time.monotonic() holder to act as time keeper gimel = 3 # bitmap index for gimel, the winning character countdown = 5 # countdown for length of game. default is 5 seconds beam_state = False # state machine for break beam reset = False # state for reset of game dreidel = False # state to track if dreidel game is running clock = time.monotonic() # initial time.monotonic() while True: # debouncing for break beam sensor if not break_beam.value and not beam_state: beam_state = True # if the break beam sensor is triggered or the down button is pressed... if (not break_beam.value and beam_state) or not switch.value: # update break beam state beam_state = False # begin reset for game states reset = True print("pressed") # quick delay time.sleep(0.1) # if reset state... if reset: # hold time.monotonic() value clock = time.monotonic() # reset countdown countdown = 5 # choose random side of dreidel to begin spinning on spin = random.randint(0, 3) # choose random speed spin the dreidel speed = random.uniform(0.05, 0.1) # set game state to True dreidel = True # turn off reset state reset = False # if the game is running... if dreidel: # play the dreidel song audio.play(wave) # while the dreidel song is playing... while audio.playing: # if more time has passed than the random delay setup in reset... if (timer + speed) < time.monotonic(): # dreidel grid index is set to spin value dreidel_grid[0] = spin # spin is increased by 1 spin += 1 # timer is updated to current time timer = time.monotonic() # if a second has passed... if time.monotonic() > (clock + 1): print(clock) print(spin) # the delay is increased to slow down the dreidel speed += 0.05 # clock is set to current time clock = time.monotonic() # countdown value is decreased by 1 countdown -= 1 # if countdown is 0 aka 5 seconds has passed since the start of game... if countdown == 0: # if the bitmap is showing gimel... # you win! if spin is gimel: # the servo turns 90 degrees to dump out chocolate coins servo.angle = 0 # 2 second delay time.sleep(2) # servo turns back to default position for i in range(0, 90, 2): servo.angle = i time.sleep(0.1) # ensures servo is in default position servo.angle = 90 # stop playing the dreidel song audio.stop() # game state is turned off dreidel = False # if you didn't win... else: # the dreidel song stops audio.stop() # game state is turned off dreidel = False # if you are at the end of the sprite sheet... if spin > 3: # index is reset to 0 spin = 0
Upload the Code, Audio File, Bitmap and Libraries to the MatrixPortal M4
After downloading the Project Bundle, plug your MatrixPortal M4 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 MatrixPortal M4's CIRCUITPY drive.
lib folder
code.py
dreidel_song.wav
dreidel.bmp
Your MatrixPortal M4 CIRCUITPY drive should look like this after copying the lib folder and the code.py, dreidel_song.wav and dreidel.bmp files.
How the CircuitPython Code Works
"Spin" the Dreidel
The MatrixPortal M4's onboard down button and an IR breakbeam sensor are setup as digital inputs that can be read to start up the dreidel game sequence. If either input is triggered in the loop, then the reset state is set to True. This resets all of the game's values to launch a new sequence.
# if the break beam sensor is triggered or the down button is pressed... if (not break_beam.value and beam_state) or not switch.value: # update break beam state beam_state = False # begin reset for game states reset = True print("pressed") # quick delay time.sleep(0.1)
reset State
The reset state acts as a way to make sure everything is ready for a new round of dreidel. Most importantly, the values of spin and speed are set to random values. This allows for some variation in how the dreidel spins. spin affects the first index that is shown in the tilegrid and speed affects the speed at which the indexes change on the matrix.
# if reset state... if reset: # hold time.monotonic() value clock = time.monotonic() # reset countdown countdown = 5 # choose random side of dreidel to begin spinning on spin = random.randint(0, 3) # choose random speed spin the dreidel speed = random.uniform(0.05, 0.1) # set game state to True dreidel = True # turn off reset state reset = False
The Dreidel is Rolling
When the dreidel state is True, then the dreidel song will play through the STEMMA speaker and you'll see the dreidel sprite sheet iterate through the four sides with the different characters.
speed is used as the delay, with timer being reset to the current time with each iteration. This lets you avoid using time.sleep(), which would pause the entire loop.
# if the game is running... if dreidel: # play the dreidel song audio.play(wave) # while the dreidel song is playing... while audio.playing: # if more time has passed than the random delay setup in reset... if (timer + speed) < time.monotonic(): # dreidel grid index is set to spin value dreidel_grid[0] = spin # spin is increased by 1 spin += 1 # timer is updated to current time timer = time.monotonic()
The game is setup to "spin" the dreidel for 5 seconds. With each passing second, the value of speed is increased by 0.05 seconds. This slows the dreidel down gradually to mimic how it would spin in real life. countdown keeps track of how many seconds are left in the game.
# if a second has passed... if time.monotonic() > (clock + 1): print(clock) print(spin) # the delay is increased to slow down the dreidel speed += 0.05 # clock is set to current time clock = time.monotonic() # countdown value is decreased by 1 countdown -= 1
Once the game is over, it's determined whether or not you've won the pot of chocolate coins. If the matrix is showing gimel, which is the third index of the sprite sheet, then you've won! As a result, the servo will turn to dump out the chocolate coins for you and then turn back to its default position. The dreidel song will also stop playing and dreidel is set to False, stopping the game sequence.
If you didn't win, the song stops playing and the dreidel state is set to False, but there isn't any servo action.
# if countdown is 0 aka 5 seconds has passed since the start of game... if countdown == 0: # if the bitmap is showing gimel... # you win! if spin is gimel: # the servo turns 90 degrees to dump out chocolate coins servo.angle = 0 # 2 second delay time.sleep(2) # servo turns back to default position for i in range(0, 90, 2): servo.angle = i time.sleep(0.1) # ensures servo is in default position servo.angle = 90 # stop playing the dreidel song audio.stop() # game state is turned off dreidel = False # if you didn't win... else: # the dreidel song stops audio.stop() # game state is turned off dreidel = False
Wiring
Make sure to use heat shrink for any exposed wire connections!
Insert the two breakbeam sensors into their slots at the top of the 3D printed lid.
Strip and tin the breakbeam sensors' ground and power connections. Solder their ground connections together. Then, solder their power connections together.
The JST 3-pin socket cable will plug into the servo motor. Solder the cable's ground connection to an additional wire.
Then, solder the breakbeam's shared ground connections to this ground junction. Cover the connection with heat shrink.
Solder an additional wire to the breakbeam sensors' power wires. Cover the connection with heat shrink.
Solder the following connections to the MatrixPortal M4's pins.
The group's ground connection to the MatrixPortal M4's ground pin
The breakbeam sensors' power connection to the MatrixPortal M4's 3V pin
The breakbeam sensors' data pin to A1
The JST socket's data pin to A4
Make a longer JST 3-pin cable
Cut a JST 3-pin cable in half. Then, strip and tin its wires.
Solder wires to each JST end to create a longer cable. Cover all connections with heat shrink. This cable will be used for the STEMMA speaker.
Assembly
Slide the servo motor into the servo motor slot on top of the 3D printed stand. Make sure to pass its wires through the cut-out on the side. Secure it with two M2 screws.
Attach the STEMMA Speaker to the side of the 3D printed stand with four M2 screws and four M2 nuts.
Attach the 3D printed lid to the top of the RGB matrix using three M3 screws.
Attach the 3D printed stand to the bottom of the RGB matrix using one M3 screw.
Plug the MatrixPortal M4 into the back of the RGB matrix.
Plug the STEMMA speaker into the MatrixPortal M4's onboard JST socket with the elongated 3-pin JST cable. This will connect the speaker to pin A0.
Plug the servo motor into the soldered 3-pin JST socket cable. This connects the servo to pin A4.
Attach the RGB matrix's power cable and the JST 3-pin socket cable's power pin to 5V on the MatrixPortal M4 by securing them with an M3 screw.
Attach the RGB matrix's ground cable to the MatrixPortal M4 with an M3 screw.
Plug the matrix power cable into the back of the matrix.
Super glue the servo horn to the 3D printed chocolate coin cup. Then, attach the servo horn to the servo motor.
Optional: cut a piece of LED acrylic to fit the 32x32 matrix and attach it to the front of the matrix with four squares of clear adhesive.
Play Dreidel!
After powering up the MatrixPortal M4 and the RGB matrix, you can begin your game of dreidel two ways: either by dropping a chocolate coin into the coin slot to trigger the break beam sensor or by pressing the down button on the side of the MatrixPortal M4.
The classic dreidel song will begin playing through the STEMMA speaker and the dreidel will "spin" on the RGB matrix, iterating through the dreidel sprite sheet.
A dreidel has four characters, one on each side. The characters are:
Shin (ש)
He (ה)
Gimel (ג)
Nun (נ)
Traditionally when you are playing dreidel, each side has a different meaning in the game. For the purposes of this version though, you will keep adding coins to the pot until you roll gimel; winning the game.
If you don't roll gimel to win the game, don't worry! You can keep dropping in coins or pressing the down button to launch a new cycle.
If you do roll gimel though, congratulations! You've won the pot! The servo motor will tip the cup holding all of the chocolate coins, spilling them out for you to feast on.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum