DIY Raspberry Pi/Python Powered PACHINKO [Kitchen Build]

Raspberry Pi Python Pachinko

Pachinko? Pichinko? Pychinko?

I’ve been playing around with is idea for a while because… I don’t know; it seemed like a cool concept. That’s my whole motivation. Here’s a Raspberry Pi and Python-powered pachinko machine.

This project is really basic, so it’s good for beginners, and the result is a lot of fun to mess with and would make a good desk ornament to fidget with or something for the kids to build on a rainy day to learn about coding and circuits and all of that stuff.

Once again, I’m keeping it simple – no lathes, 3d printers, or CNC machines, just some junk from the dollar store (and in this case, random items from the back of the kitchen drawer).

Check out this sweet video of it in action, as well as a time-lapse of the build, and then scroll on for how to build your own.

Video

Initial Ideas and Plans

Initially, I had planned to use a sheet of aluminum I had laying around, with holes drilled in it for ball bearings to fall into. It turns out the aluminum was too thick to cut through, so that idea was scrapped.

Pachinko machine plans

Above, you can see my notes about using foil-wrapped cardboard (instead of an aluminum sheet) with pins pushed through it. This wasn’t as sturdy as I’d have liked.

Pachinko machine plans

More ideas – returning to using an aluminum sheet, this time with metallic objects on the front that can be grounded to it to simulate a button press which could be used to score.

You can see a few ideas for different shapes for these objects.

Scrapped, again, because shaping them would be a pain without metalworking tools.

There’s also some ideas for having moving obstacles driven by DC motors, but this was omitted for the first version of this project – something that could be added when making future improvements.

Pachinko machine plans

The penultimate plan – aluminum foil strips, or wire, wrapped around plastic pins, which could be used to create scoring events. This was used initially before I moved on to using screws and the pins themselves as the scoring triggers.

Materials

A bit of further experimentation was done during the build process, but here are the materials used in the completed product:

  • Raspberry Pi Zero
  • Copper sheet
    • There’s no cutting required. You can order copper sheet from online auction sites for a few dollars pre-cut to whatever size you want
  • Ball bearings
    • The size will depend on the size of the copper sheet and the obstacles you want to use
  • Obstacles
    • These are the things that the ball will hit on its way down the play area
    • Bottle caps, erasers, pen lids, an old (flat) battery are visible on mine
  • Score triggers
    • These need to be metal objects that can also be glued to the play area
    • They’ll need a spot on them you can clamp or solder a wire on to so they can be connected to the Pi
  • Hot glue
    • Side note: I hate hot glue
  • LEDs
  • Piezo Buzzer
  • 100 Ohm resistors
    • Bags of LEDs, bags of resistors, and piezo buzzers can be found for a few dollars on online auction sites.
  • Breadboard, jumper wires, alligator clip wires
    • The things to connect your pachinko machine to the Pi

All of this stuff is available online, and it’s all reusable for future projects.

Pi or Arduino

An Arduino would also be suitable for this project, but I’m using the Raspberry Pi because:

  • My Arduino boards are all currently in use.
  • I might want to upgrade the pachinko machine later with better sound effects (maybe video clips when milestone scores are reached) etc. which the Pi can handle
  • I want to

Setting up the Raspberry Pi

Raspberry Pi Lite was installed using:

https://www.raspberrypi.org/software/

The Raspberry Pi Imager now handles the whole process of installing Raspberry Pi OS onto an SD card.

Once you have Raspberry Pi OS running on your Pi, you’ll need to connect to your WiFi network and enable SSH.

I won’t cover that here as it’s already outlined in several other project articles – so here’s a link to one.

Once it’s installed, update your software by running:

sudo apt update 
sudo apt upgrade

 

Then install the dependencies for this project – Raspberry Pi OS by default doesn’t include everything for Python 3, so we’ll need to make sure it’s all installed by running:

sudo apt install python3 python3-rpi.gpio

See here for more info on the apt command.

Building a Pachinko Machine

The video embedded at the beginning of this article shows pretty much the whole build process. The photos and text below just explain a bit of what’s going on.

Excuse the mood lighting in some of the shots – late-night tinkering!

Testing Materials

Foil wrapped cardboard

Foil-wrapped cardboard

Early on in the video, you can see the materials for the frame being tested with a voltmeter.

This ensured that the electrical current would pass through the frame, the score triggers glued to the play area, and the ball bearing so the pi could detect score events.

Foil-covered cardboard was tested first, and while it worked, I thought it could be bettered.

Score trigger test - foil wrapped header pins

Score trigger test – foil-wrapped header pins.

A copper sheet was ordered online for a few dollars – in keeping with the “kitchen build” theme – these sheets are cheap and can be ordered pre-cut, so no heavy tools are required. The aluminum sheet would also work here.

Testing different materials

Testing different ideas for the score triggers before I decided to use screws, pins, etc.

Building the Frame

From here on out, you can pretty much see what I’m doing from the photos alone, but I’ll add some commentary.

Pachinko machine - frame and sides

Pachinko machine – frame and sides

Cardboard was used to enclose the play space on the pachinko board.

A ramp is added at the bottom to make sure the ball bearings roll back into firing position once they’ve completed the course.

Ruler attached using glue

Ruler attached using glue.

The channel used to launch the ball is just a ruler glued in place.

The cardboard doesn’t need to be too thick – I’ve just cut mine from a document envelope. If it’s too thick/rigid, you won’t be able to flick the ball bearings through it to launch them.

Plastic coated back of copper sheet

Plastic coated back of copper sheet.

The back of my copper sheet was already covered in a protective layer of plastic – if yours doesn’t have this, it’ll need to be covered in tape to stop it shorting on anything.

Adding Feet

Hooks glued to back

Hooks glued to back

For the ball to roll down the play area, the back will need to be elevated slightly – I’ve just glued some wall hooks to the back.

Boy, do I hate hot glue.

Boy, do I hate hot glue.

 

Adding Obstacles

Obstacle candidates - flat batteries, pen lids, thimbles...

Obstacle candidates – flat batteries, pen lids, thimbles…

I’ve pretty much just glued a bunch of junk from the back of the kitchen drawer (you know, the one with rubber bands and string and old phone chargers in it) onto the play area to act as obstacles for the ball bearings as they pass by.

Obstacles glued in place

Obstacles glued in place (That battery is flat and not part of the scoring circuit, by the way)

Just make sure there’s enough room for the ball bearing to get past so it doesn’t get stuck.

Launch Mechanism

High tech

High tech

High-tech mechanism to launch the ball bearings – a clicky pen.

Make sure you find one with the button to release on the side.

Then it’s just a matter of clicking it in, holding it to the side of the pachinko machine, and releasing it.

The force will be transferred through the cardboard to the ball bearing on the other side, sending it rolling.

If I haven’t explained this well, check out the video at the top of the article.

Adding Scoring Triggers

Scoring triggers in this project are the metal objects on the Pachinko machine that need to be hit with the ball bearings to score.

Testing Triggers

Various objects were tested to work as triggers

Various objects were tested to work as triggers.

This is a foil covered set of headers - they worked well for testing things, but I didn't like the look

This is a foil-covered set of headers – they worked well for testing things, but I didn’t like the look.

 

Screws!

Screws!

I finally settled on random screws and pins from that kitchen drawer.

They were big enough to clip on to and, most importantly, conducted enough current that I could detect when a ball hit them.

(The big screws are best as they make noise as the ball rolls across them).

The score triggers were glued to the pachinko board also – being careful that they don’t actually touch the copper but are held elevated by the glue (otherwise, the circuit would always be closed, and no change would occur when the ball moves past).

Building the Circuit

Building the circuit

Building the circuit

You can see that GROUND for the circuit is attached to the copper sheet using that black alligator clip at the top.

This is super important – the score triggers will be set to a higher voltage so that when the ball touches both them and the copper sheet, the voltage will drop so we can detect a score.

Alligator clips

Alligator clips

Alligator clips were attached to the scoring triggers glued to the board.

These were then connected to GPIO pins on the Pi via jumper wires.

Closeup of alligator clips

Closeup of alligator clips

LEDs, resistors, and a piezo buzzer (for sound effects!) were then wired in – each to a GPIO port.  Each LED should have a 100Ohm resistor attached.

Finished Circuit + Diagram

Circuit diagram

Circuit diagram

Here’s how all of that looks in a circuit diagram that’s a bit easier to follow.

Keeping it simple so you can see what’s going on – you could add many more LEDs and triggers!

The buttons in this diagram are the scoring triggers (I’ve just used buttons as that’s all the diagram software had). The ground for them is attached to the copper sheet, and then the scoring trigger (screw, pin, etc.) is wired to a GPIO port on the Pi.

The Code

With the circuit built, it’s time to make this thing do stuff with some Python code.

Ready to code

Ready to code

I’ve simply SSH’d into the Pi and created the file pachinko.py in the nano text editor:

Coding in progress

Coding in progress

Ready to run

Ready to run

Here’s the code in full with commentary explaining what it does. It should be pretty simple- it’s just button presses and flashing LEDs.

# Pi-Py Pachinko script for Python 3
# Rasperry Pi Zero
# To install dependencies run: sudo apt-get install python3 python3-rpi.gpio

# Import dependencies
import RPi.GPIO as GPIO
import time

# Disable GPIO warnings so they don't get in the way of keeping score
# There shouldn't be any but just in case
GPIO.setwarnings(False)

# Set BCM GPIO pin numbering
# This means the pins are referred to by their GPIO number not their position on the board
GPIO.setmode(GPIO.BCM)

# Specify the pin the piezo buzzer is attached to
buzzerPin = 12

# Specify the pins the LEDs are attached to
led1Pin = 25
led2Pin = 24
led3Pin = 18
led4Pin = 5

# Specify the pins the score triggers are attached to
# These are the metallic objects in the pachinko machine that the ball will touch to trigger a score event
score1Pin = 21 
score2Pin = 20
score3Pin = 16
score4Pin = 26


# Set buzzer, LED pins as outputs
GPIO.setup(buzzerPin, GPIO.OUT)

GPIO.setup(led1Pin, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(led2Pin, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(led3Pin, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(led4Pin, GPIO.OUT, initial=GPIO.LOW)

# Set score trigger pins as inputs (they'll act as buttons)
# They're initially pulled UP/High so that when they are grounded (by the ball touching the object) the change in voltage will be detected as a score event
GPIO.setup(score1Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
GPIO.setup(score2Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(score3Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(score4Pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Trigger a GPIO event on the score pins when the voltage is detected as FALLING (as they were intitialised to HIGH above, we can detect a fall in voltage from the ball hitting the object and grounding it)
GPIO.add_event_detect(score1Pin, GPIO.FALLING)
GPIO.add_event_detect(score2Pin, GPIO.FALLING)
GPIO.add_event_detect(score3Pin, GPIO.FALLING)
GPIO.add_event_detect(score4Pin, GPIO.FALLING)

# Keep track of the score
score = 0

# Keep track of the last milestone (every 100 points)
# Because I want to play a tune every 100 points scored
lastMilestone = 0

# Introduction text/logo - triple quoted to create a multi-line comment
# Get fonts from https://patorjk.com/software/taag/                                                                      
logo = """                                                                                                                                                                                                  
     ___            
 -  (O o)  -                                       
ooO--(_)--Ooo
 ____  ____        ____  __ __         ____    ____    __  __ __  ____  ____   __  _   ___  
|    \l    j      |    \|  T  T       |    \  /    T  /  ]|  T  Tl    j|    \ |  l/ ] /   \ 
|  o  )|  T _____ |  o  )  |  | _____ |  o  )Y  o  | /  / |  l  | |  T |  _  Y|  ' / Y     Y
|   _/ |  ||     ||   _/|  ~  ||     ||   _/ |     |/  /  |  _  | |  | |  |  ||    \ |  O  |
|  |   |  |l_____j|  |  l___, |l_____j|  |   |  _  /   \_ |  |  | |  | |  |  ||     Y|     |
|  |   j  l       |  |  |     !       |  |   |  |  \     ||  |  | j  l |  |  ||  .  |l     !
l__j  |____j      l__j  l____/        l__j   l__j__j\____jl__j__j|____jl__j__jl__j\_j \___/ 
                                                                                            
"""

# Piezo buzzer tune player code (buzz, play functions) and tunes found at the below link
# https://github.com/gumslone/raspi_buzzer_player/blob/master/buzzer_player.py
# Serious credit to that guy - my attempt at making some scoring sounds was awful!
notes = {
    'B0' : 31,
    'C1' : 33, 'CS1' : 35,
    'D1' : 37, 'DS1' : 39,
    'EB1' : 39,
    'E1' : 41,
    'F1' : 44, 'FS1' : 46,
    'G1' : 49, 'GS1' : 52,
    'A1' : 55, 'AS1' : 58,
    'BB1' : 58,
    'B1' : 62,
    'C2' : 65, 'CS2' : 69,
    'D2' : 73, 'DS2' : 78,
    'EB2' : 78,
    'E2' : 82,
    'F2' : 87, 'FS2' : 93,
    'G2' : 98, 'GS2' : 104,
    'A2' : 110, 'AS2' : 117,
    'BB2' : 123,
    'B2' : 123,
    'C3' : 131, 'CS3' : 139,
    'D3' : 147, 'DS3' : 156,
    'EB3' : 156,
    'E3' : 165,
    'F3' : 175, 'FS3' : 185,
    'G3' : 196, 'GS3' : 208,
    'A3' : 220, 'AS3' : 233,
    'BB3' : 233,
    'B3' : 247,
    'C4' : 262, 'CS4' : 277,
    'D4' : 294, 'DS4' : 311,
    'EB4' : 311,
    'E4' : 330,
    'F4' : 349, 'FS4' : 370,
    'G4' : 392, 'GS4' : 415,
    'A4' : 440, 'AS4' : 466,
    'BB4' : 466,
    'B4' : 494,
    'C5' : 523, 'CS5' : 554,
    'D5' : 587, 'DS5' : 622,
    'EB5' : 622,
    'E5' : 659,
    'F5' : 698, 'FS5' : 740,
    'G5' : 784, 'GS5' : 831,
    'A5' : 880, 'AS5' : 932,
    'BB5' : 932,
    'B5' : 988,
    'C6' : 1047, 'CS6' : 1109,
    'D6' : 1175, 'DS6' : 1245,
    'EB6' : 1245,
    'E6' : 1319,
    'F6' : 1397, 'FS6' : 1480,
    'G6' : 1568, 'GS6' : 1661,
    'A6' : 1760, 'AS6' : 1865,
    'BB6' : 1865,
    'B6' : 1976,
    'C7' : 2093, 'CS7' : 2217,
    'D7' : 2349, 'DS7' : 2489,
    'EB7' : 2489,
    'E7' : 2637,
    'F7' : 2794, 'FS7' : 2960,
    'G7' : 3136, 'GS7' : 3322,
    'A7' : 3520, 'AS7' : 3729,
    'BB7' : 3729,
    'B7' : 3951,
    'C8' : 4186, 'CS8' : 4435,
    'D8' : 4699, 'DS8' : 4978
}

# Beverly Hills Cop!
axelMelody = [
    notes['A4'], notes['C5'], notes['A4'], notes['A4'], notes['D5'], notes['A4'], notes['G4'], 
    notes['A4'], notes['E5'], notes['A4'], notes['A4'], notes['F5'], notes['E5'], notes['C5'],
    notes['A4'], notes['E5'], notes['A5'], notes['A4'], notes['G4'], notes['G4'], notes['E4'], notes['B4'], 
    notes['A4'],0,
]

axelTempo = [
    2,4,4,8,4,4,4,
    2,4,4,8,4,4,4,
    4,4,4,8,4,8,4,4,
    1,4,
    
    2,4,4,8,4,4,4,
    2,4,4,8,4,4,4,
    4,4,4,8,4,8,4,4,
    1,4,
    
    8,4,4,4,
    
    2,4,4,8,4,4,4,
    2,4,4,8,4,4,4,
    4,4,4,8,4,8,4,4,
    1,
]

#Taken from popcorn
milestoneMelody= [
    notes['A4'], notes['G4'], notes['A4'], notes['E4'], notes['C4'], notes['E4'], notes['A3'], 
    notes['A4'], notes['G4'], notes['A4'], notes['E4'], notes['C4'], notes['E4'], notes['A3'], 
]

milestoneTempo= [
    8,8,8,8,8,8,4,
    8,8,8,8,8,8,4,
]

# Function which accepts the pitch and duration of a note to play
def buzz(frequency, length):	 

    if(frequency==0):
        time.sleep(length)
        return
    period = 1.0 / frequency # In physics, the period (sec/cyc) is the inverse of the frequency (cyc/sec)
    delayValue = period / 2 # Calculate the time for half of the wave
    numCycles = int(length * frequency) # The number of waves to produce is the duration times the frequency
    
    for i in range(numCycles): # Start a loop from 0 to the variable "cycles" calculated above
        GPIO.output(buzzerPin, True) # Set pin 27 to high
        time.sleep(delayValue) #wait with pin 27 high
        GPIO.output(buzzerPin, False) # Set pin 27 to low
        time.sleep(delayValue) # Wait with pin 27 low

# Function which plays the provided tune
def play(melody, tempo, pause, pace=0.800):
    
    for i in range(0, len(melody)): # Play song
        
        noteDuration = pace/tempo[i]
        buzz(melody[i],noteDuration) # Change the frequency along the song note
        
        pauseBetweenNotes = noteDuration * pause
        time.sleep(pauseBetweenNotes)

# Again, thanks to https://github.com/gumslone/raspi_buzzer_player/blob/master/buzzer_player.py for the tunes!

# Function to flash the LEDs a given number of times
def flashLedsFunction(times):
    for t in range(0, times):
        GPIO.output(led1Pin, GPIO.HIGH)
        GPIO.output(led2Pin, GPIO.HIGH)
        GPIO.output(led3Pin, GPIO.HIGH)
        GPIO.output(led4Pin, GPIO.HIGH)
        time.sleep(0.1)
        GPIO.output(led1Pin, GPIO.LOW)
        GPIO.output(led2Pin, GPIO.LOW)
        GPIO.output(led3Pin, GPIO.LOW)
        GPIO.output(led4Pin, GPIO.LOW)
        time.sleep(0.1)

# Function to round a number DOWN to the nearest 100 
# Used when calculating whether a milestone score has been reached
def roundDownNearestHundred(num):
    if (num % 100 == 0):
        return num
    else:
        return int(num/100) * 100

# The main pachinko game function
# This will be launched when the script is run
# It will be run repeatedly in an infinite loop
def pachinkoFunction():

    # Ensure global variables are used to track the score
    global score
    global lastMilestone

    # Store the score prior to the current moment so we can know if it has changed
    oldScore = score

    # Use the GPIO events previously set up to detect when the voltage of a pin is FALLING
    # This means the ball has hit one of the score triggers 
    # If one has been hit, it will increment the score and play a sound
    if(GPIO.event_detected(score1Pin)):
        score += 3
        play([notes['A4']], [1], 0.30, 0.1)
    if(GPIO.event_detected(score2Pin)):
        score += 5
        play([notes['G4']], [1], 0.30, 0.1)
    if(GPIO.event_detected(score3Pin)):
        score += 10
        play([notes['E4']], [1], 0.30, 0.1)
    if(GPIO.event_detected(score4Pin)):
        score += 15
        play([notes['C4']], [1], 0.30, 0.1)

    #If a score has been detected update the score being displayed
    if(score != oldScore):
        print('\033[A\033[A') # This is a trick to clear the last line of the program output, so that the screen doesn't scroll each time the score increases
        print("Score: " + str(score)) # Print out the new score

        #Play a tune and flash the LEDs every 100 points
        if(roundDownNearestHundred(score) != 0 and roundDownNearestHundred(score) > lastMilestone):
            lastMilestone = roundDownNearestHundred(score) # Store the last hit milestone
            flashLedsFunction(5) # Flash the LEDs
            play(milestoneMelody, milestoneTempo, 0.50, 0.8) # Play a victory tune
            
# This code will be run when the script is launched
# It's wrapped in a try/catch block so that if there is an error, some cleaning up can be done before the program exits
try:
    # Flash the LEDs and play a startup tune when the script is launched
    # A festive way to check that everything is working
    flashLedsFunction(5)
    play(axelMelody, axelTempo, 0.30, 0.6)

    # Print the introduction text/logo
    print(logo)
    print('Welcome to Pi-Py-Pachinko!')
    print('Press CTRL+C to quit.')
    print("Score: " + str(score))

    # Start the main game loop
    # This is an infinite loop! It'll run pachinkFunction() continuously - that function handles the main game logic and watches for scoring events, increments scores, etc
    while True: # This loop will run infinitely because the value it is checking (True) will always evaluate to True
        pachinkoFunction() 
        
except Exception as e:
    GPIO.cleanup() # Clean up GPIO and release pin assignments for re-use
    print(e) # Print the error so we can debug
    pass

 

The only complex bit is the stuff to play the musical tunes provided by someone much more talented than I.

Viewing the Score

Working Python code

Working Python code

When the code is in, you can simply run the program by entering:

python3 pachinko.py

And you will see the welcome message and the score – everything is ready to go.

I’m accessing the Pi via SSH, but you could just as easily have a screen and keyboard attached.

Jingles

My initial attempts at adding sound cues to the Pachinko machine weren’t great.

What I thought would be a jaunty tune sounded more like that sick dinosaur from Jurassic Park. So, I went to the internet and found someone who’d made an awesome little piezo-buzzer tune player for the Pi.

https://github.com/gumslone/raspi_buzzer_player/blob/master/buzzer_player.py

You can define your own melodies; I’ve stuck with some of the pre-existing ones to avoid my Pachinko machine sounding like a large lizard with the flu.

Tidying Up

A bit of tape to keep the wires in check

A bit of tape to keep the wires in check

And a fancy sign

And a fancy sign

 

Finished! Pi-Py-Pachinko

Looking good!

Looking good!

Yeah, I’m pretty happy with how this turned out.

It's a bit simpler than the original plan but it's fun to mess with and most importantly was fun to build

It’s a bit simpler than the original plan, but it’s fun to mess with and, most importantly, was fun to build

 

In Action

Here’s the video of it in action if you missed it the first time around.

Improvements

Of course, this is version 1, and I want to make this thing better. Here are some of my ideas for future updates:

  • More sound effects
  • Save high scores to a text file
  • Bigger! More triggers and lights!
  • Mount the LEDs on the pachinko machine itself
  • Add motorized bits – spinning obstacles using the L239D I used in the Python-powered tank.
  • Launch the ball bearing using a solenoid rather than a clicky pen
  • Reduce the amount of tilt and maybe use bigger ball bearings to improve responsiveness

Conclusion

Want more? Check out my other “kitchen build” projects using Python, Raspberry Pi, Arduino, and Linux:

And be sure to follow LinuxScrew and myself on Twitter to find out when new ones are posted.

Cheers!

SHARE:
nv-author-image

Brad Morton

I'm Brad, and I'm nearing 20 years of experience with Linux. I've worked in just about every IT role there is before taking the leap into software development. Currently, I'm building desktop and web-based solutions with NodeJS and PHP hosted on Linux infrastructure. Visit my blog or find me on Twitter to see what I'm up to.

Leave a Reply

Your email address will not be published. Required fields are marked *