Overview:
This project will construct a pinball type game using a ping pong ball and a playfield made from solenoids, u-brackets, a continuous rotation servo and erector set parts. The goal of the game is to deposit the ping pong ball into u-bracket targets. The targets represent varying degrees of difficulty with the harder targets awarding more points than the easier ones. Score is kept automatically and displayed on an LCD readout. Solenoids act as flippers and also eject the ball from the u-bracket targets. A spinning arm attached to a continuous rotation servo adds an element of unpredictability to the game. The guide rails and obstacles are constructed with erector set parts and plastic standoffs.
Update: This tutorial is now entered in the Circuits Contest. If you like this project, I'd appreciate your vote. Thanks!
Step 1: List of Materials- Arduino board (I used a RobotGeek Geekduino)
- LCD
- Continuous rotation servo
- Plastic standoffs
- Nuts and bolts
- Relays
- Perforated steel duct strap
- Erector set
- Various jumper wires
- 3-pin sensor cables
- u-brackets
- 6 pushbuttons
- Plastic platform
- Arduino mount
- Sensor shield
- Small breadboard
- Wire clips
I obtained the last eight items on the list from a Robotics Grab Bag from Trossen Robotics.
Step 2: Playfield ConstructionThe two large plastic platforms are joined together using nuts and bolts and several flat plates from the erector set. Guide rails and playfield obstacles are constructed from erector set rails attached to 30 mm standoffs and bolted to the playfield. See the figures above. The u-bracket targets are attached to the playfield using small right angle brackets. These brackets are made from a small section of the duct strap bent at 90 degrees. Again, see the figures above. I cut the duct strap with a pair of tin snips. You might want to file or sand the cut edges of the duct strap as they can be quite sharp. The playfield is inclined with 10 mm standoffs at the bottom and several u-brackets at the top. The elevation at the top is about 40 mm.
The Trossen Robotics solenoids come with threaded mounting holes which makes attaching them to the playfield very easy. Several small spacers are used to bring the solenoids up to the appropriate height so that they can kick the ping pong ball out of the u-bracket target. An erector set rail and two u-brackets are used to make the spinning arm for the servo. Several long screws are used to attach the servo to the playfield at the correct height.
Step 3: Electronic CircuitMost electronic connections are made to the Arduino sensor shield using three pin sensor cables. Six push buttons are used in the game. Five to control the solenoids and one to reset the LCD display. The grab bag I purchased came with one RobotGeek push button and I had two more from other Trossen kits that I had. I also made two homebrew push buttons for a previous tutorial. The pushbuttons controlling the solenoids are connected to digital pins 1, 2, 4, 5, and 6. The servo controlling the spinning arm is connected to digital pin 3 because it needs pwm. The score reset button is situated on the breadboard and is connected to digital pin 7. The relays controlling the solenoids are connected to digital pins 8, 9, 10, 11, and 12. The four pin LCD plug connects to the I2C port on the sensor shield.
I used two power supplies, 12 volts for the solenoids and 6 volts for the Arduino and the servo. My 12 volt supply has a 2.1 mm barrel plug which goes into a 2.1 mm barrel jack on the breadboard and powers the rails on the left side of the breadboard. My 6 volt supply just has two bare wires which power the rails on the right side of the breadboard. One lead of each of solenoid goes to 12 volts and the other to the common contact on one of the relays. Each relay is also connected to the ground rail on the breadboard. The relays that I am using are "active low" and thus this connection from ground goes to the normally closed contact on the relay instead of the normally open contact.
Step 4: Arduino CodeThe Arduino code for the game is listed here. There is also a link to a text file containing the code at the bottom.
/*
10/8/16
This is an adaption of the RobotGeek sketch "Contolling a Solenoid
with Arduino" and the RobotGeek LCD sketch "Hello World"
Controlling a Solenoid with Arduino
Products Used in this demo:
- http://www.robotgeek.com/solenoids- http://www.robotgeek.com/robotgeek-geekduino-sens...- http://www.robotgeek.com/robotGeek-pushbutton- http://www.robotgeek.com/robotgeek-relay
*/
#include <Servo.h>
#include <Wire.h>
#include <RobotGeek.h>
RobotGeekLCD lcd;
Servo spinServo;
int spinServoPin = 3;
// constants won't change. They're used here to set pin numbers:
const int button1Pin = 1; // the number of the pushbutton1 pin
const int button2Pin = 2; // the number of the pushbutton2 pin
const int button3Pin = 4;
const int button4Pin = 5;
const int button5Pin = 6;
const int buttonResetPin = 7;
const int relay1Pin = 8; // the number of the Relay pin
const int relay2Pin = 9;
const int relay3Pin = 10;
const int relay4Pin = 11;
const int relay5Pin = 12;
// variables will change:
int button1State = 0; // variable for reading the pushbutton status
int button2State = 0;
int button3State = 0;
int button4State = 0;
int button5State = 0;
int buttonResetState = 0;
int gameScore = 0;
void setup() {
spinServo.attach(spinServoPin);
spinServo.write(0);
lcd.init();
lcd.print(" Game Score:");
// initialize the pushbutton pin as an input:
pinMode(button1Pin, INPUT);
pinMode(button2Pin, INPUT);
pinMode(button3Pin, INPUT);
pinMode(button4Pin, INPUT);
pinMode(button5Pin, INPUT);
pinMode(buttonResetPin, INPUT);
// initialize the relay pin as an output:
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(relay3Pin, OUTPUT);
pinMode(relay4Pin, OUTPUT);
pinMode(relay5Pin, OUTPUT);
}
void loop(){
// read the state of the pushbutton values:
button1State = digitalRead(button1Pin);
button2State = digitalRead(button2Pin);
button3State = digitalRead(button3Pin);
button4State = digitalRead(button4Pin);
button5State = digitalRead(button5Pin);
buttonResetState = digitalRead(buttonResetPin);
// check if the pushbutton1 is pressed.
// if it is we turn on the relay/solenoid
if (button1State == HIGH) {
// turn relay on:
digitalWrite(relay1Pin, HIGH);
}
// When we let go of the button, turn off the relay
else if ((button1State == LOW) && (digitalRead(relay1Pin) == HIGH)) {
// turn relay off
digitalWrite(relay1Pin, LOW);
}
// check if the pushbutton2 is pressed.
// if it is we turn on the relay/solenoid
if (button2State == HIGH) {
// turn relay on:
digitalWrite(relay2Pin, HIGH);
}
// When we let go of the button, turn off the relay
else if ((button2State == LOW) && (digitalRead(relay2Pin) == HIGH)) {
// turn relay off
digitalWrite(relay2Pin, LOW);
gameScore = gameScore + 10;
lcd.setCursor(0,1);
lcd.print(" ");
lcd.print(gameScore);
}
// check if the pushbutton3 is pressed.
// if it is we turn on the relay/solenoid
if (button3State == HIGH) {
// turn relay on:
digitalWrite(relay3Pin, HIGH);
}
// When we let go of the button, turn off the relay
else if ((button3State == LOW) && (digitalRead(relay3Pin) == HIGH)) {
// turn relay off
digitalWrite(relay3Pin, LOW);
gameScore = gameScore + 10;
lcd.setCursor(0,1);
lcd.print(" ");
lcd.print(gameScore);
}
// check if the pushbutton4 is pressed.
// if it is we turn on the relay/solenoid
if (button4State == HIGH) {
// turn relay on:
digitalWrite(relay4Pin, HIGH);
}
// When we let go of the button, turn off the relay
else if ((button4State == LOW) && (digitalRead(relay4Pin) == HIGH)) {
// turn relay off
digitalWrite(relay4Pin, LOW);
gameScore = gameScore + 50;
lcd.setCursor(0,1);
lcd.print(" ");
lcd.print(gameScore);
}
// check if the pushbutton5 is pressed.
// if it is we turn on the relay/solenoid
if (button5State == HIGH) {
// turn relay on:
digitalWrite(relay5Pin, HIGH);
}
// When we let go of the button, turn off the relay
else if ((button5State == LOW) && (digitalRead(relay5Pin) == HIGH)) {
// turn relay off
digitalWrite(relay5Pin, LOW);
gameScore = gameScore + 100;
lcd.setCursor(0,1);
lcd.print(" ");
lcd.print(gameScore);
}
if (buttonResetState == HIGH) {
lcd.setCursor(0,1);
gameScore = 0;
lcd.print(" 0 ");
}
}
Step 5: Game PlayThe ball starts off in the lower right corner of the playfield and is set in motion by the "flipper" solenoid. The goal is to get the ball into one of the three u-brackets in the main playfield, or the narrow channel along the left edge. The various targets are given point values. The two 10 point targets are relatively easy to score. The 50 point target is more challenging and the 100 point channel more difficult still. When a ball drops into a target, the appropriate button is pressed to eject the ball and also to increment the LCD score display by the point value of the target. As the ball drops under the influence of gravity, it either settles in the lower right corner, where it is set in motion again by the "flipper" solenoid, or it drops through the drain and off the playfield ending the game. The reset button on the breadboard resets the LCD and the game is ready for the next round.
The position and angle of the u-brackets can be altered to increase or decrease the difficulty. The rotating arm adds a random element to the game, making skill necessary to get the ball into the high value channel on the left. Another option is to use a regular 180 degree servo with the position set using the Arduino random number generator, and the arm programmed to move every half second or so. Many different playfields are possible and trial and error can be used to determine the best position of targets, obstacles and the spinning arm.
Coming soon: A revamped game with more traditional pinball flippers and a more conventional pinball playfield with microswitch targets and (hopefully) ball lanes with rollover switches.
Comments