Interactive cornhole board set

Hi,

I have a customer who wants a custom interactive cornhole board set made. I’m in the beginning stages of design and plans on it, and need help to piece the electronic side of it together. I have some but very limited experience with arduino electronics. I own a small cnc routing business and was a commercial finish carpenter before that, so I can definitely use some help with this. So the boards are going to have LEDs backlights all around 2’x4’ board, LEDs for the 6" whole, LEDs backlit plates on the sides, would like all of them to do a blue and green stream. Would like to have a switch in the hole to trigger the LEDs to react and maybe flash or faster streaming or something like that, when the bag goes in. Would also like to add audio clips and a push button scoreboard on both boards that are synced together. I saw a couple years ago sparkfun partnered up with someone to do something very similar to this but that info is no longer available. This would need to be weather resistant, reliable and will last. Like said I’m in the early stages of design, so I’m trying to get a idea of what can or can’t be done or just not worth it. And trying to figure out layout for design and costs. Any and all help would be much appreciated thanks!

Hi OLeary48,

I love this idea for a project! I found the blog post from the folks at SketchUp [here but it looks like the tutorials site they hosted the relevant build information on is disabled so I am not sure if there is a way to access it now. You could try reaching out to them directly to see if that tutorial hosted somewhere else. To keep this post from becoming a (larger) novel, I am going to cover some of what I would consider the “basics” (LEDs, the switch and a microcontroller). This will get you started with the big components of the build and you can work on adding on more functionality like button inputs, wireless syncing and sound.

For your project, I recommend starting with an Addressable LED Strip. Addressable LEDs allow you to control the color and brightness of any LED along the strip. This [Sealed Addressable LED Strip is sealed to protect the circuitry from things like moisture and dirt so it would work well for this project. If you want to browse through our other LEDs, take a look at our [Addressable LED Category. To get started controlling them, we have a [Hookup Guide that will go over the hardware, hooking it up and some example code. The “Resources and Going Further” section will have some links to other tutorials and guides that may help you progress with this project.

For your switch, a physical switch is going to be really tricky without having some moving parts that are prone to breaking or interfering with the game. What might work well for this is to use a distance sensor or an IR beam sensor like the ones you see on conveyor belts at a grocery store checkout. SparkFun does not have any IR beam sensor kits that would have the range to work well for measuring a beanbag going through a hole on this board but a search for “IR Break Beam Sensor” will point you in the right direction. The only drawback I can see with one of those is the continuous vibration caused by the bags hitting the top of the cornhole boards might throw their alignment off so you would need to monitor that.

If you want to learn more about the various types of distance sensors we carry, check out our [Distance Sensing Overview page. That covers the various types of distance sensors technologies SparkFun carries as well as some other helpful tutorials and projects to provide some inspiration for your projects. With a distance sensor, you could mount one (or two for a cross-beam type of setup) on the inside of the frame so its sensing area covers the hole and have your code watch for when the distance reduces significantly, indicating a bag crossed through the hole, and trigger your microcontroller to make the LEDs react.

Finally, really any microcontroller will work for this and we carry [quite a few. The code should not be terribly complex so you do not need a microcontroller with a bunch of program space. For prototyping, the [Arduino Uno is always a good option. I recommend the [SparkFun RedBoard Qwiicfor prototyping since it is functionally identical to an Uno but has our Qwiic connector so you can easily interface with other Qwiic boards like some of our distance sensors. The [Hookup Guide for the RedBoard Qwiic will get you started with that board. The beginning of that guide will have some “Suggested Reading” links if you are not familiar with Arduino.

I hope this information is not too overwhelming and helps you get started with the basics for this project. If you have any follow-up questions about these or any of our other products or tutorials, let me know and I would be happy to help as much as I can. I would be happy to help outline some options for the other goals of this project in another post.](https://learn.sparkfun.com/tutorials/redboard-qwiic-hookup-guide)](SparkFun RedBoard Qwiic - DEV-15123 - SparkFun Electronics)](https://www.sparkfun.com/products/11021)](https://www.sparkfun.com/categories/300)](https://www.sparkfun.com/distance_sensing)](https://learn.sparkfun.com/tutorials/ws2812-breakout-hookup-guide/addressable-led-strips)](https://www.sparkfun.com/categories/286)](LED RGB Strip - Addressable, Sealed, 1m (APA104) - COM-15205 - SparkFun Electronics)](Learn to Build a Light-up, Arduino-Controlled Cornhole Game | SketchUp)

Awesome thanks for the help!

I’ll dig into that.

Yeah from I’ve read so far it doesn’t seem too bad. I was just not too sure about which components are best to use for this or the best way to go about the synced push button scoreboard. I’ll start my list and getting everything together and I’m sure I have more questions. Haha

Thanks

Hi,

What would be the best way, bluetooth modules, bluetooth boards for me to send audio and data controls from a tablet to the master and then to the slave at the same time? So I can have music play on both boards and control them simultaneously. And is there a way I can use the bluetooth audio recieved for LEDs sound activation? I got the sound activation working with a sound detection board but its inconsistent and will be affected if the volume is turned up or down. Or should I something like a input jack for that?

Thanks

Hi again OLeary48,

There are a few options that we have for using Bluetooth for this project but they all have some minor issues you would need to work around. The easiest option would probably be to use one of our Bluetooth-capable development boards like the [ESP32 Thing, the [ESP32 Thing Plus or the [Pro nRF52840 Mini Dev Board. The one snag that comes with using these is they run at 3.3V logic and the addressable LED strips we carry run at 5V logic so you would need to shift the signal level between the strip and microcontroller. If you are not familiar with logic levels, [this tutorial will cover the basics and from there, you can use something like this [Bi-Directional Logic Level Converter to shift the control signal for your LEDs from 3.3V to 5V. The Hookup Guide for that level shifter will also have some very helpful information about hooking it up with a microcontroller. You could also use a Bluetooth module connected to one of our “standard” Arduinos like [this guide demonstrates. This would also act as a “serial pipe” to send data when a button is pressed on either board.

Now, to “sync” the two boards together, I would recommend doing something in your code that sends a serial transmission from one microcontroller to the other each time one of your score buttons is pressed. That way you don’t have to have them constantly polling each other for a bunch of information. Instead, you would just have a serial string sent that would trigger a scoreboard change each time a button is pressed. Just have this set up on both microcontrollers and you should be able to “sync” the scores together.

As far as using a tablet to control them with data or audio, I am afraid I do not have much information to offer there as we do not have much support for interacting with our Bluetooth boards or modules with a tablet or phone application. There probably is a way to do this, but it is beyond the scope of our ability to support here. Other users might have some input or help to offer. Otherwise, you could try searching around on a tutorials site or blog like Instructables, Hackster or Hackaday.](https://learn.sparkfun.com/tutorials/using-the-bluesmirf/introduction)](https://www.sparkfun.com/products/12009)](Logic Levels - SparkFun Learn)](https://www.sparkfun.com/products/15025)](https://www.sparkfun.com/products/14689)](https://www.sparkfun.com/products/13907)

Hi,

Thanks Mark I appreciate the help. So I got a set a bluetooth pairing speakers for the music, and I mounted a mic in one of the speakers and got the reactive lights working on that. So I’ll have both speakers with a mic in them. Now I’m trying to get the scoreboard code to work. Right now I’m using a Mega2560 to piece this together and to get a better feel for what board I should use, and a 32x8 ws2812b matrix for the scoreboard display. I still need to add the reactive lights in this code, but thought I’d get the scoreboard side done first. Once I get this figured out I’ll get the recommended boards and connect them through HC-05 bluetooth models. And plan on putting together a phone/tablet app together on thunkable to control it with buttons on the boards too. If you can give me some help with the scoreboard code, it would be much appreciated. Thanks

Edited by moderator to add code tags

#include <Adafruit_GFX.h>   // Core graphics library
#include <Adafruit_NeoMatrix.h>
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include "Button.h"


// Similar to F(), but for PROGMEM string pointers rather than literals
#define F2(progmem_ptr) (const __FlashStringHelper *)progmem_ptr

/////// Hardware setup ////////

// Physical Button Pin Setup
#define BUTTON_PIN_1 36
#define BUTTON_PIN_2 37
#define BUTTON_PIN_3 38
#define BUTTON_PIN_4 39

// LED Matrix Pin Setup
#define PIN 22

// MATRIX DECLARATION:
// Parameter 1 = width of NeoPixel matrix
// Parameter 2 = height of matrix
// Parameter 3 = pin number (most are valid)
// Parameter 4 = matrix layout flags, add together as needed:
//   NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
//     Position of the FIRST LED in the matrix; pick two, e.g.
//     NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
//   NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
//     rows or in vertical columns, respectively; pick one or the other.
//   NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
//     in the same order, or alternate lines reverse direction; pick one.
//   See example below for these values in action.
// Parameter 5 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(32, 8, PIN,
  NEO_MATRIX_BOTTOM    + NEO_MATRIX_RIGHT +
  NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
  NEO_GRB            + NEO_KHZ800);


//////// Program variables ////////
// last param indicates 'double buffering'

Button homeAddButton = Button(BUTTON_PIN_1); 
Button awayAddButton = Button(BUTTON_PIN_2); 
Button homeSubButton = Button(BUTTON_PIN_3); 
Button awaySubButton = Button(BUTTON_PIN_4);


// variables will change:
int buttonState = 0;      // varibles for reading the pushbutton status
       
const int WINNING_SCORE = 21;
int homeScore = 0;
int awayScore = 0;

// Last scored var and constants
const int NO_SCORE = 0;
const int HOME_SCORED = 1;
const int AWAY_SCORED = 2;
const int lastScored = NO_SCORE;

int hue = 0;


/****************************************
 * Program Setup
 ****************************************/
void setup() {
  while (!Serial);
  delay(500);
  Serial.begin(19200);

  //initalize push button pins as input:
  pinMode(BUTTON_PIN_1, INPUT);
  pinMode(BUTTON_PIN_2, INPUT);
  pinMode(BUTTON_PIN_3, INPUT);
  pinMode(BUTTON_PIN_4, INPUT);
   
 
  
  // initialize display
  matrix.begin();
  matrix.setBrightness(10);
  matrix.print("#TimeToPlay");
  serialPrintScores();
}

/****************************************
 * Main Program Loop
 ****************************************/
void loop() {
  int currentHomeScore = homeScore;
  int currentAwayScore = awayScore;
// read the state of the pushbutton value:
buttonState = digitalRead(BUTTON_PIN_1);
buttonState = digitalRead(BUTTON_PIN_2);
buttonState = digitalRead(BUTTON_PIN_3);
buttonState = digitalRead(BUTTON_PIN_4);



// check if pushbuttons are pressed. If it is, the buttonState is HIGH:
  

if (buttonState ==HIGH) {
  homeScore = increaseScore(homeScore);
    lastScored = HOME_SCORED;  
}
  else if (buttonState == HIGH) {
  homeScore = decreaseScore(homeScore);
  } else if (buttonState == HIGH)  {
    awayScore = increaseScore(awayScore);
    lastScored = AWAY_SCORED; {
  } else if (buttonState == HIGH)  {
    awayScore = decreaseScore(awayScore);
  }
    else if (buttonState == HIGH, button3State == HIGH) {
    resetScores = NO_SCORE;
   
   
    Serial.println("Reset scores");
  
  }

  if (currentHomeScore != homeScore || currentAwayScore != awayScore) {
    serialPrintScores(); 
    if (gameOver()) {
      Serial.println("Winner, winner, chicken dinner!");
    }
  }
  
  displayScoreBoardScreen();
  matrix.swapBuffers(false);
}

/****************************************
 * Scoring
 ****************************************/
int increaseScore(int score) {
  if (score == 21) {
    return 13;
  }
  return score + 1;
}

int decreaseScore(int score) {
  if (score == 0) {
    return 0;
  }
  return score - 1;
}

int resetScores() {
  homeScore = 0;
  awayScore = 0;
}

bool gameOver() {
  return homeScore == WINNING_SCORE || awayScore == WINNING_SCORE;
}

bool scoreResetPressed() {
  return homeSubButton.isHeld() && awaySubButton.isHeld();
}

void serialPrintScores() {
  Serial.println("Current scores: " + displayableScore(homeScore) + " v " + displayableScore(awayScore));
}

/****************************************
 * Display Related
 ****************************************/
void displayScoreBoardScreen() {
  matrix.setTextSize(1);
  // fill the screen with 'black'
  clearDisplay();
  
  if (gameOver()) {
    drawGameOverBorder();
  }
  displayScores();
}

void drawGameOverBorder() {
  matrix.drawRect(0, 0, 32, 16, matrix.ColorHSV(hue, 255, 255, true));
  hue += 7;
  if(hue >= 1536) hue -= 1536;
}

void displayScores() {
  putDigitLarge(1, 2, '0' + homeScore / 10, 7, 0, 0);
  putDigitLarge(7, 2, '0' + homeScore % 10, 7, 0, 0);

  uint16_t indicatorColor = matrix.Color333(7,6,0);
  if (lastScored == NO_SCORE) {
    matrix.setCursor(14, 4);
    matrix.setTextColor(indicatorColor);
    matrix.print('v');
  } else if (lastScored == HOME_SCORED) {
    // Draw a < pointing towards home score
    matrix.drawLine(14, 7, 17, 4, indicatorColor);
    matrix.drawLine(14, 8, 17, 5, indicatorColor);
    matrix.drawLine(14, 8, 17, 11, indicatorColor);
    matrix.drawLine(14, 7, 17, 10, indicatorColor);
  } else if (lastScored == AWAY_SCORED) {
    // Draw a > pointing towards away score
    matrix.drawLine(15, 4, 18, 7, indicatorColor);
    matrix.drawLine(15, 5, 18, 8, indicatorColor);
    matrix.drawLine(15, 11, 18, 8, indicatorColor);
    matrix.drawLine(15, 10, 18, 7, indicatorColor);
  }

  putDigitLarge(19, 2, '0' + awayScore / 10, 0, 7, 0);
  putDigitLarge(25, 2, '0' + awayScore % 10, 0, 7, 0);
}

String displayableScore(int score) {
  String scoreString = String(score);
  if (scoreString.length() == 1) {
    scoreString = "0" + scoreString;
  }
  return scoreString;
}

void displayText(String text) {
  matrix.setTextWrap(false); // Allow text to run off right edge
  matrix.setTextSize(2);    // size 1 == 8 pixels high

  int textX   = matrix.width();
  int textMin = text.length() * -12;

  while ((--textX) >= textMin) {
    //Serial.println("TextX: " + textX);
    matrix.fillScreen(0);
    matrix.setTextColor(matrix.ColorHSV(hue, 255, 255, true));
    matrix.setCursor(textX, 1);
    matrix.print(text);
    
    hue += 7;
    if(hue >= 1536) hue -= 1536;
    matrix.swapBuffers(true);
    delay(10);
  }
}

void clearDisplay() {
  matrix.fillScreen(0);
}

void updateButtons()
{
  homeAddButton.update();
  awayAddButton.update();
  homeSubButton.update();
  awaySubButton.update();
}

void putDigitLarge(uint8_t x, uint8_t y, char c, uint8_t r, uint8_t g, uint8_t b)
{
  // fonts defined for ascii 32 and beyond (index 0 in font array is ascii 32);
  byte charIndex = c - '0' + 22;
  putChar(x, y, bigFont[charIndex], 12, 6, r, g, b);
}

void putChar(uint8_t x, uint8_t y, const unsigned char * c, uint8_t h, uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
  for (byte row = 0; row<h; row++)
  {
    byte rowDots = pgm_read_byte_near(&c[row]);
    for (byte col = 0; col<w; col++)
    {
      if (rowDots & (1 << (w - col - 1)))
        matrix.drawPixel(x + col, y + row, matrix.Color333(r,g,b));
      else
        matrix.drawPixel(x+col, y+row, matrix.Color333(0,0,0));
    }
  }
}

Unfortunately, we cannot help debug custom code. If you could elaborate on specific issues you are running into, we might be able to point you to some other resources to help, though.