Thursday, July 31, 2014

Baseball Scoreboard - Programming the Scoreboard

    For those who are interested in playing with code rather than reading about code, here are the instructions to get up and running in a minimum amount of time:

  1. If you haven't already, download the Arduino IDE and install (http://arduino.cc/en/Main/Software).
  2. The github repository for my code can be found here.  Check it out into your Arduino working directory (i.e., git clone https://github.com/ScratchesTheItch/ScoreboardArduinoCode.git).
  3. Fire up the Arduino IDE, open the GC_Scoreboard sketch file.
  4. Upload the sketch to the Arduino.
  5. Once loaded, select the Serial Monitor to begin interacting with the scoreboard. (I'd suggest starting with a "help" command to get the compact usage statement or "test" to see what the scoreboard can do).
If you're playing with the code at this point, I'll admit that the help statement is a bit terse.  Due to an issue that I was never able to resolve, the full help message is too long to be output via serial.  As a result, I commented out most of the explanation for the commands in the compiled code -- if you want to read the full text, scroll down to line 54 in the sketch file.


Design Goals

    For this portion of the project, I had two goals.  The first deals with presentation.  I wanted to make sure that the elements of the scoreboard were all legible and clearly displayed.  This goal turned out to be more of a challenge than it seems at first glance as each panel is only 16x24 pixels.  To implement this goal, I sketched out a number of designs on paper in order to figure out what was and wasn't possible prior to coding (along those lines, I am more than willing to take design suggestions as, ultimately, the goal is clear communication of game status to the spectators and I think there are some flaws in how things are currently set up).
    The second goal relates to modularity.  Specifically, i wanted to make sure that the scoreboard had a fairly standardized comms mechanism so it could stand on its own (i.e., if someone decides my control box is crap, I wanted to make my design portable enough that they could yank the scoreboard out and insert it into their project with a minimum of fuss).  Thankfully there was lots of serial code for Arduino out there, so this was a relatively easy goal to meet.
  

How it all works

    Not knowing a thing about Arduinos, I started with the Adafruit provided tutorial (https://learn.adafruit.com/16x24-led-matrix/) and libraries(https://github.com/adafruit/HT1632) and built from there (As a side note, I initially thought programming the Arduino/panels would be the toughest part of the project.  It turned out that, thanks to the excellent Arduino resources at adafruit.com, arduino.cc, and the web in general, I was able to get rudimentary graphics up and running in 1 day with serial communications working by the end of day 2).
    The Arduino sketch is loosely broken into two parts.  The primary portion of the code deals with displaying the game elements (home/away, inning, score, ball-strike-out count, and runners on base).  When the user sends the game state to the Arduino via serial, the Arduino changes the display accordingly.  The SGS (set game state) command sets all game elements (except logo and side).  For those commands that don't set all game elements (inning, score, setMySide, and setMyLogo), the Arduino references the last set values and displays those.  Lastly, test rolls through all of the game states so you can make sure everything displays correctly.
    The second portion of the code deals with text display on the center LED.  cheer displays a generic "Lets go team".  message displays a generic scrolling message (warning -- the scrolling message flashes continuously while being displayed, those with medical conditions beware).  The last two commands printScoreUpdate and GameRecap were built to display the score of other games during the inning transition. printScoreUpdate displays a brief title slide and GameRecap crams 3-letter team IDs, score and inning on the center LED.  Ultimately there were no game feeds that I could legally get, so this functionality ended up being unused in the final product (which for me was a shame, as it was a minor miracle to get all of that information displayed on one panel)  UPDATE: Thanks to a helpful plug from Adafruit regarding this project, I was linked to a number of sports projects, one having to do with creating a sports ticker.  As it was reliant upon free sports score feeds, I was able to get this back on track and now the scoreboard streams scores between halves.

Engineering Issues

    Engineering issue number one:  Adafruit's libraries assume that the LED panels will all be set up as part of one large horizontal display.  Two of my three panels violate that assumption.  Rather than try to decouple the three panels and address them independently (which is probably how I'd do it if I tried this again), I decided to allow the library to continue to believe the three panels were one continuous display and authored a library method to draw the fonts sideways (drawSideChar).  Sideways fonts are used on both of the score panels, normal fonts are used for text displays on the center panel.
    The next problem I had was with double digit numbers.  In short, using the provided fonts, I can't fit 2 digits into the space allocated.  Additionally, to get everything needed onto one screen for GameRecap, the normal fonts just weren't going to cut it.  To solve both problems, I authored a 3 pixel wide narrower font (vs the normal 5 pixels) named skinnyfont.  Additional library methods were also required to draw the font in the normal direction (drawSkinnyChar) and sideways (drawSideSkinnyChar).  Insert a check for double digits prior to deciding what font to use and that engineering problem was solved.
    The last issue cropped up during initial testing.  Many of the spectators couldn't easily identify whether our team was the home or away team.  To fix this problem, I created a custom 6x8 bitmap of our team's logo, converted it to 6 integers (each int represents a column going from left to right with the LSB at the top of the column).  Within the library, a drawLogo method was written.  Via serial, setMyLogo is used to send the logo to the scoreboard and setMySide is used to determine whether the logo should replace the home or away (visitor) placeholder.   

Conclusion

    If you're following along at home, by this point, you have a scoreboard that you can now send commands to USB serial.  Which is pretty darn cool (especially if 2 days earlier, you had exactly 0 experience with Arduinos and had managed to kick out useable code in no time flat).  Initially, when I  got to this point, I was feeling like quite prototype master. I figured that I had all the "hard" stuff behind me and this project would be over by the end of the week.  If only that were true.  To get to this point was less than 20% of the project.  The integration required within the control box soon came to take over most of my free time.  Starting with the next post, I'll begin to peel that onion.

No comments:

Post a Comment