Hackster is hosting Impact Spotlights: Industrial Automation. Watch the stream live on Thursday!Hackster is hosting Impact Spotlights: Industrial Automation. Stream on Thursday!
typalowski
Published © GPL3+

Mind Control Beer Pong!

Don't focus too hard! Beer pong game that gets easier as you drink!

AdvancedShowcase (no instructions)2,723
Mind Control Beer Pong!

Things used in this project

Hardware components

HC-06 Bluetooth Module
×1
Arduino Nano R3
Arduino Nano R3
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
OLED Display, Blue on Black
OLED Display, Blue on Black
×1
Stepper Motor, Mini Step
Stepper Motor, Mini Step
×1

Software apps and online services

Processing
The Processing Foundation Processing
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Original wiring diagram for the automated table.

Wiring schedule/diagram.

Code

Processing Software Code

Processing
Change the float threshold = __; to adjust when the computer sends a signal to the Arduino through the COM port on line 18.
// Import the libraries and dependencies
import oscP5.*;
import java.awt.*;
import processing.serial.*;

Serial myPort;
String myText="";

OscP5 oscP5;
Robot pong;
float currentAttention;
float threshold = 70;

// The setup function runs once when you start your application
void setup(){
    
    size(300,300);
    myPort = new Serial(this, "COM6", 57600);
    myPort.bufferUntil('n');
  
  oscP5 = new OscP5(this, 7771); // Start listening for incoming messages at port 7771 
  
  try { // Try and create a new robot named bob
    pong = new Robot();
  } 
  catch (AWTException e) { // If there is an error, print it out to the console
    e.printStackTrace();

  }
}

void serialEvent (Serial myPort) {
  myText = myPort.readStringUntil('n');
}

// The draw function runs over and over again until you close the application
void draw(){
  
  background(0,0,0);
  text (myText, 120, 120);
  myText="";
  
  if (currentAttention > threshold) {
    //bob.keyPress(java.awt.event.KeyEvent.VK_ENTER);
    myPort.write("on");
    delay(7000);
    
  }
 // else {
    //bob.keyRelease(java.awt.event.KeyEvent.VK_ENTER);
  //}
  
}

void oscEvent(OscMessage theMessage) {
  // Print the address and typetag of the message to the console
  // println("OSC Message received! The address pattern is " + theMessage.addrPattern() + ". The typetag is: " + theMessage.typetag());

  // Check for Attention messages only
  if (theMessage.checkAddrPattern("/attention") == true) {
    currentAttention = theMessage.get(0).floatValue();
    println("Your attention is at: " + currentAttention);
  }  
}

Updated Arduino Code

C/C++
This is the code with added serial port monitoring, when the Arduino receives "on" through the serial port, it runs the cups back and forth at defined speed.
/*
 * Code by Ty Palowski for Automated Beerpong Game V2
 * https://youtube.com/c/typalowski
 */


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ClickEncoder.h>
#include <TimerOne.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// defines pins numbers
const int dirPin = 2; 
const int stepPin = 4; 
const int enPin = 5;

int menuitem = 1;
int frame = 1;
int page = 1;
int lastMenuItem = 1;

String menuItem1 = "Motor: OFF";
String menuItem2 = "Difficulty";
String menuItem3 = "Mode";
String menuItem4 = "Reset";

boolean motor = true;
int stepdelay;

int maxDelay = 240;
int diffDelta = 23;

String difficulty[10] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
int selectedDifficulty = 9;

String mode[2] = { "EASY", "HARD"};
int selectedMode = 1;

boolean up = false;
boolean down = false;
boolean middle = false;

ClickEncoder *encoder;
int16_t last, value;

// '85062033-beer-pong-or-beirut-drinking-game-with-cups-with-ball-line-art-vector-icon-for-apps-and-websites-', 128x32px
const unsigned char myBitmap [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x38, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xc3, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x83, 0x83, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xff, 0xff, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x98, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x9c, 0x71, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9f, 0xf1, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x90, 0x13, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x98, 0x13, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

#define home_switch 9 // Pin 9 connected to Home Switch (MicroSwitch)

int direction;    // Variable to set Rotation (CW-CCW) of the motor
int steps;        // Used to set HOME position after Homing is completed

int fullDist = 32766;
int halfDist = fullDist/2;


void setup() {
  Serial.begin(57600);

  
  // Sets the two pins as Outputs
  pinMode(stepPin,OUTPUT); 
  pinMode(dirPin,OUTPUT);

  pinMode(enPin,OUTPUT);
  digitalWrite(enPin,LOW);


  pinMode(7,OUTPUT);

  
  encoder = new ClickEncoder(A1, A0, A2);
  encoder->setAccelerationEnabled(false);

  display.begin();      
  display.clearDisplay(); 

  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr); 
  
  last = encoder->getValue();

  display.setRotation (2);

  display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color)

  // Show the display buffer on the screen. 
  display.display();


// Start Homing procedure of Stepper Motor at startup
Serial.println("Homing...");
  while (digitalRead(home_switch)) {  // Do this until the switch is activated   
    digitalWrite(dirPin, HIGH);      // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(75);                       // Delay to slow down speed of Stepper
    digitalWrite(stepPin, LOW);
    delayMicroseconds(75);   
}

  while (!digitalRead(home_switch)) { // Do this until the switch is not activated
    digitalWrite(dirPin, LOW); 
    digitalWrite(stepPin, HIGH);
    delay(5);                       // More delay to slow even more while moving away from switch
    digitalWrite(stepPin, LOW);
    delay(5);
  }

  steps=0;  // Reset position variable to zero

    digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
  for(int x = 0; x < halfDist+425; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(50); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(50); 
    }
   Serial.println("Ready!");
  delay(1000);

}

void loop() {

String readString;
String Q;

while (Serial.available()){
  delay(1);
  if(Serial.available()>0){
    char c = Serial.read();
    if (isControl(c)){
    break;
  }
  readString += c;
  }
}

Q = readString;
if (Q=="on"){
  Serial.println("on");
    //Center to Left Limit
    digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
  for(int x = 0; x < halfDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
    //Left Limit to Right Limit
    digitalWrite(dirPin,LOW); 
  for(int x = 0; x < fullDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
//Right limit to Center
    digitalWrite(dirPin,HIGH); 
  for(int x = 0; x < halfDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
 }


stepdelay = maxDelay - selectedDifficulty*diffDelta;

      if (motor == true) 
      {
        turnMotorOff();
        }
      else
      { 
        turnMotorOn();
       }

  drawMenu();

  readRotaryEncoder();

   ClickEncoder::Button b = encoder->getButton();
   if (b != ClickEncoder::Open) {
   switch (b) {
      case ClickEncoder::Clicked:
         middle=true;
        break;
    }
  }    
  
  if (up && page == 1 ) //We have turned the Rotary Encoder CounterClockwise
  {
    up = false;
    if(menuitem==1 && frame ==2)
    {
      frame--;
    }
     if(menuitem==2 && frame ==3)
    {
      frame--;
    }
         if(menuitem==3 && frame ==4)
    {
      frame--;
    }
    
    lastMenuItem = menuitem;
    menuitem--;
    if (menuitem==0)
    {
      menuitem=1;
    }
  } 
  else if (up && page == 2 && menuitem==2 ) 
  {
    up = false;
    selectedDifficulty--;
    if(selectedDifficulty == -1)
    {
      selectedDifficulty = 9;
    }
  }
  else if (up && page == 2 && menuitem==4 ) {
    up = false;
  }
   else if (up && page == 2 && menuitem==3 ) {
    up = false;
    selectedMode--;
    if(selectedMode == -1)
    {
      selectedMode = 1;
    }
  }
  
  if (down && page == 1) //We have turned the Rotary Encoder Clockwise
  {

    down = false;
    if(menuitem==2 && lastMenuItem == 1)
    {
      frame ++;
    }
    else  if(menuitem==3 && lastMenuItem == 2)
    {
      frame ++;
    }
    else  if(menuitem==4 && lastMenuItem == 3 && frame!=3)
    {
      frame ++;
    }
    lastMenuItem = menuitem;
    menuitem++;  
    if (menuitem==5) 
    {
      menuitem--;
    }
  }
   else if (down && page == 2 && menuitem==2 ) {
    down = false;
    selectedDifficulty++;
    if(selectedDifficulty == 10)
    {
      selectedDifficulty = 0;
    }
  }
  else if (down && page == 2 && menuitem==3 ) {
    down = false;
    selectedMode++;
    if(selectedMode == 2)
    {
      selectedMode = 0;
    }
  }
  
  if (middle) //Middle Button is Pressed
  {
    middle = false;
   
    if (page == 1 && menuitem==1) // Motor Control 
    {
      if (motor) 
      {
        menuItem1 = "Motor: ON";
        motor = false;
        turnMotorOff();
        //Left to Center
    digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
  for(int x = 0; x < halfDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
        }
      else 
      { 
        menuItem1 = "Motor: OFF";
        motor = true;
        turnMotorOn();
        //Center to Right
    digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
  for(int x = 0; x < halfDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
       }
    }

    if(page == 1 && menuitem ==4)// Reset
    {
      resetDefaults();
    }
    else if (page == 1 && menuitem==2) {
      page=2;
     }
    else if (page == 1 && menuitem==3) {
      page=2;
     }
    else if (page == 2) 
     {
      page=1; 
     }
   }   
  }
  
  void drawMenu()
  {
    
  if (page==1) 
  {    
    display.setTextSize(1);
    display.clearDisplay();
    display.setTextColor(WHITE, BLACK);
    display.setCursor(15, 0);
    display.print("MAIN MENU");
    display.drawFastHLine(0,10,128,WHITE);

    if(menuitem==1 && frame ==1)
    {   
      displayMenuItem(menuItem1, 15,true); //FRAME 1
      displayMenuItem(menuItem2, 25,false);
    }
    else if(menuitem == 2 && frame == 1)
    {
      displayMenuItem(menuItem1, 15,false);
      displayMenuItem(menuItem2, 25,true);
    }
    else if(menuitem == 3 && frame == 2)
    {
      displayMenuItem(menuItem2, 15,false); //FRAME 2
      displayMenuItem(menuItem3, 25,true);
    }

      else if(menuitem == 2 && frame == 2)
    {
      displayMenuItem(menuItem2, 15,true);
      displayMenuItem(menuItem3, 25,false);
    }
    else if(menuitem == 4 && frame == 3)
    {
      displayMenuItem(menuItem3, 15,false); //FRAME 3
      displayMenuItem(menuItem4, 25,true);
    }
    
    else if(menuitem == 3 && frame == 3)
    {
      displayMenuItem(menuItem3, 15,true);
      displayMenuItem(menuItem4, 25,false);
    }
    else if(menuitem == 2 && frame == 3)
    {
      displayMenuItem(menuItem2, 15,true);  //FRAME 2
      displayMenuItem(menuItem3, 25,false);
    }   
    else if(menuitem == 1 && frame == 2)
    {
      displayMenuItem(menuItem1, 15,true);  //FRAME 1
      displayMenuItem(menuItem2, 25,false);
    }   
    display.display();
  }
  else if (page==2 && menuitem == 2) 
  {
   displayStringMenuPage(menuItem2, difficulty[selectedDifficulty]);
  }
   else if (page==2 && menuitem == 3) 
  {
   displayStringMenuPage(menuItem3, mode[selectedMode]);
  }  
  }


  void resetDefaults()
  {
    selectedDifficulty = 0;
    selectedMode = 0;
    motor = true;
    menuItem1 = "Motor: OFF";// Start Homing procedure of Stepper Motor at startup

  while (digitalRead(home_switch)) {  // Do this until the switch is activated   
    digitalWrite(dirPin, HIGH);      // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(75);                      // Delay to slow down speed of Stepper
    digitalWrite(stepPin, LOW);
    delayMicroseconds(75);   
}

  while (!digitalRead(home_switch)) { // Do this until the switch is not activated
    digitalWrite(dirPin, LOW); 
    digitalWrite(stepPin, HIGH);
    delay(5);                       // More delay to slow even more while moving away from switch
    digitalWrite(stepPin, LOW);
    delay(5);
  }

  steps=0;  // Reset position variable to zero

    digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
  for(int x = 0; x < halfDist+425; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(50); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(50); 
    }
   }

  void setstepdelay()
  {
  //  display.setContrast(contrast);
    display.display();
  }

  void turnMotorOn()
  {
//Left limit to Right Limit
    digitalWrite(dirPin,HIGH); 
  for(int x = 0; x < fullDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
//Right limit to Left
    digitalWrite(dirPin,LOW); 
  for(int x = 0; x < fullDist; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(stepdelay); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(stepdelay); 
    }
  }

    void turnMotorOff()
  {
    digitalWrite(7,HIGH);
  }

  void timerIsr() {
  encoder->service();
}

void displayIntMenuPage(String menuItem, int value)
{
    display.setTextSize(1);
    display.clearDisplay();
    display.setTextColor(WHITE, BLACK);
    display.setCursor(10, 0);
    display.print(menuItem);
    display.drawFastHLine(0,10,80,WHITE);
    display.setCursor(5, 15);
    display.print("Value");
    display.setTextSize(2);
    display.setCursor(80, 10);
    display.print(value);
    display.setTextSize(2);
    display.display();
}

void displayStringMenuPage(String menuItem, String value)
{
    display.setTextSize(2);
    display.clearDisplay();
    display.setTextColor(WHITE, BLACK);
    display.setCursor(0, 0);
    display.print(menuItem);
    display.setCursor(50, 15);
    display.print(value);
    display.setTextSize(2);
    display.display();
}

void displayMenuItem(String item, int position, boolean selected)
{
    if(selected)
    {
      display.setTextColor(BLACK, WHITE);
    }else
    {
      display.setTextColor(WHITE, BLACK);
    }
    display.setCursor(0, position);
    display.print(">"+item);
}

void readRotaryEncoder()
{
  value += encoder->getValue();
  
  if (value/2 > last) {
    last = value/2;
    down = true;
    delay(150);
  }else   if (value/2 < last) {
    last = value/2;
    up = true;
    delay(150);
  }
}

Credits

typalowski
1 project • 23 followers
Contact

Comments

Please log in or sign up to comment.