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.
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.
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.
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.
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
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.
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 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.
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.
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.
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
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.
Adding Obstacles
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.
Just make sure there’s enough room for the ball bearing to get past so it doesn’t get stuck.
Launch Mechanism
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
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
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 were attached to the scoring triggers glued to the board.
These were then connected to GPIO pins on the Pi via jumper wires.
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
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.
I’ve simply SSH’d into the Pi and created the file pachinko.py in the nano text editor:
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
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
Finished! Pi-Py-Pachinko
Yeah, I’m pretty happy with how this turned out.
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:
- Python Powered Tank!
- Python Powered Tank Part II
- Python Powered Tank Part III – The Finale
- Smart Mirror
- Wikipedia Scraper
- Photo Resizer and watermarker
- Raspberry Pi Powered Palmtop/Laptop
- Raspberry-Pi augmented Apple Macintosh
- Arduino Controlled Soldering Extraction Fan
- DIY Arduino Powered Electronic Morning Checklist
And be sure to follow LinuxScrew and myself on Twitter to find out when new ones are posted.
Cheers!