SIBR Hackathon Project 2: Mlattel Electronic Blaseball

In 1978, the US toy company Mattel released a handheld electronic LED baseball game. In 2021, I had a 3D printer, a Raspberry Pi, and a hackathon to enter. And so, Mlattel Electronic Blaseball was born.

If you don’t know what Blaseball is, you’re welcome to read my last hackathon project post where I explain it a bit. There’s some context in there as well about the SIBR hackathon too, which is what this is all about.

Me and My Big Ideas

When SIBR announced their hackathon, I was immediately inspired and knew I had to enter. Blaseball has been very entertaining for me for months, especially after the jaw-dropping end to Season 24, the Expansion Era, and Blaseball Beta. The hackathon announcement had some links for inspiration (and sadly, one of my first thoughts, Blaseball over Telnet, was already a SIBR product in production), and one of them, Wii Splorts (sadly no longer working as of this writing) got me thinking about video games. I don’t have enough game development experience to make an MLB The Show-style 3D game, but maybe I could do something 2D. And then, a memory from childhood came rushing back — small, battery-powered, single-purpose handheld games. Specifically, Tiger Electronics had a small LCD baseball game that I remember playing in the 90s, when it would already have been old as hell (they originally came out in 1987). For a while I entertained the thought of making a web version of this, with graphics to represent the custom LCD designs. But it also got me thinking about making something physical, something real. Obviously I couldn’t make a custom LCD at home, but a little more googling led me to the Mattel version of handheld baseball. A decade older, made when LCD displays were still uncommon and finicky, Mattel had used LEDs to represent America’s pastime in miniature. And LEDs are something I could get my hands on and work with. My mission was now clear: I would build Mlattel Electronic Blaseball.

As mentioned in that previous post, this was my first actual idea for a cursed blaseball game viewer project, and was intended to be my “main” submission to the hackathon. Immediately, it was clear that this was going to be a challenge, because it was going to involve a lot of hardware work with parts I didn’t yet have. It was because of this uncertainty that I eventually ended up tackling the numbers station as a backup project while I waited for various shipments to come through.

In fact, there were two major challenges involved, since I didn’t think that the code itself would be difficult: the LED hardware, which I did not have and could thus not effectively make a prototype without; and the enclosure, which I also did not have, and I did not want to buy and dismantle an original game to get, which meant I would have to design and 3D print something from scratch in order to have any chance of meeting the submission deadline.

Once I had identified these two, I decided to tackle the LED hardware issue first, since the hackathon accepted unfinished submissions as long as the idea was clear and I felt that showing something on the LEDs would go a long way to demonstrating the concept whether or not I had an enclosure of any kind.

Research and Development

I did as much research on the operation of the original game as I could, going through various retro toy websites and Youtube reviews which showed the thing in action. It was clear that it was using a very small number of LEDs, placed in very specific places on the display to represent the batter, pitches, catches, and baserunners. This makes sense; the game of baseball follows a very narrow set of rules that define what the ball and players can do at any given time. Obviously in real life things go a lot crazier, but for an electronic game from the 70s, this simplistic view of baseball will still get you hours worth of playtime as you try to hit the ball and run the bases.

The original Mattel Electronics Baseball game. Photo by Joe Haupt from USA, CC BY-SA 2.0, via Wikimedia Commons

But blaseball is… different.

My initial idea had been to use small sections of individually-addressable LED strip lighting, replicating the original game’s design almost exactly. This stuff is available for hilariously cheap and would only use a few pins off a microcontroller or Raspberry Pi. But when considering things like flooding, incinerations, and extra bases, I began to think that even this wouldn’t be enough. And a little more searching led me to find that you can buy sections of LED matrix lighting, also for relatively cheap, and that these are easily hooked up to a common LED multiplexer chip, the MAX7219. These are the sorts of panels that make up scrolling LED ticker displays that you might see in movie theaters and such.

...you know ;)

These seemed perfect: they would allow me not only to represent the fixed points such as home plate, and basic animations like pitching and baserunning, it also opened up a lot of possibilities for accommodating things like extra bases, animations for events and weather, and so on.

The other side of things was alphanumeric displays. The original game has a single row of numeric, seven-segment LEDs at the top that pulls double duty showing both the score as well as the inning, outs, balls, and strikes. This is fine for a simple game where the player actually bats for both teams and it doesn’t matter who’s up or even who’s playing. The player’s imagination can fill in whatever they like; I could, for example, play the visiting team as the villainous Red Sox, intentionally not batting very well, and play the home team as my beloved Yankees, trying to get as many homers off their helpless pitcher as possible.

But again, this project is different.

For this project, I’m aiming to display either live or archival blaseball games as they happened, with no input from the user except to choose a game. So there needs to be a way to convey not just which season, day, and team is playing, but many people have favorite players and do, in fact, need to see who’s up to bat and who’s pitching. So the plan was to use multiple rows of LED displays, using both seven-segment as well as fourteen-segment alphanumeric displays to display as much of this information as possible when selecting and while viewing a game.

The initial design for the Mlattel physical device layout.

All this hardware turned out to be an annoying setback. Due to the pandemic, several small electronic hobby shops near me had closed, and none of the places I checked had the exact pieces I needed.

So with that in mind, I hit the internet up for parts. I was able to find some conveniently pre-assembled LED matrix modules with MAX7219 chips already set up, as well as similar modules with 8-digit seven-segment displays. I also found some 14-segment displays that used a slightly different multiplexer, but since they were also compatible with the Raspberry Pi I threw those in as well. I was well on my way to getting this done, and it was going to be cool!

The Curse

Or so I thought!

Very quickly, it became clear that this project was cursed in a more literal sense than I intended as a submission to a “cursed” viewer competition.

I had placed orders for the various LED bits at different suppliers, and every shipment was delayed. One of these involved a UPS truck apparently breaking down, according to the tracking information.

wtf

This very same package then ended up on the same truck as some perishable items we had ordered separately, and while usually when we order something that’s shipped with UPS they arrive at or shortly after noon, for whatever reason this truck didn’t show up until after 10pm. Luckily the food was well-packed with ice.

Besides the shipping issues, though, other setbacks kept happening. For example, while designing the faceplate in a certain popular online 3D modeling app, the browser tab crashed, taking most of my progress with it. While transporting the Pi and the other physical pieces, a wire snuck out of the project box and wrapped around a glass of water, causing that to spill and nearly take out my work laptop; then when I had set it down to clean up the spill the wire snagged on something else while I was out of the room, causing the whole box to fall and spill its contents everywhere, knocking things out of the breadboard and creating more of a mess. And when the LED matrices arrived, I discovered that rather than four individual 8x8 modules, I had been shipped one 8x32 module that I now had to cut in half to make a 16x16 square.

On top of this, the Raspberry Pi I had selected for the project began developing a bunch of fun quirks with each boot. Sometimes, it was unable to find any SPI devices connected; sometimes, it would boot up and randomly illuminate some or all of the LEDs; sometimes, the LED matrix blocks would switch orientations; all of which caused me to tear my hair out each time. Most of them went away with a reboot, but this was a fresh installation of Raspbian Lite on a brand-new SD card. It was extremely frustrating and frequently caused major setbacks, including literally in the eleventh hour on the final day, where instead of flipping orientation the LED matrix decided to flip which was the top row and which was the bottom, and I thought I was going insane.

All in all, the project itself seemed to be actively working against me almost from step one, and so the result is that I was only able to submit a half-baked prototype with little more than a hastily printed cover that was intended to be a first pass temporary solution.

But despite this, I did actually make the submission, so it should be fine.

Conjuring Up Those Data Tapes

Luckily for me, while I was waiting for things to be delivered, I had already made and submitted Sloviet Blaseball, so I had some practice writing blaseball code and getting an event feed into a digestible format. So the first thing I was really able to complete was a working prototype that worked on the console. Sadly, due to some really wonky permissions and threading issues on Linux, this prototype took longer than expected and didn’t quite work as intended, but it was working anyway, and that’s what counts.

But while it was working in one sense, it was still connecting to the Datablase over the internet and retrieving information that way. For this device to be truly handheld and portable, it would ideally not require an internet connection, but have all the data it needed locally. This would also help improve the boot performance of the Raspberry Pi, since it would mean I could disable the onboard wifi at the kernel level and just let the thing boot into my program.

Now, as luck would have it, the data witches at SIBR have already created a project for storing and accessing blaseball data locally, fondly known as vcr. This project includes several highly-compressed databases of blaseball data (called “tapes”) which can be downloaded locally and accessed through a small API server (or the project could be written in Rust and just include the vcr library directly, but I was going with Python for the prototype since there were more convenient libraries out there for accessing the LED multiplexer chips).

Unfortunately, vcr turned out to be a bit of a dead end for this project, at least in its current form. Despite spending an evening getting Rust set up, compiling vcr on the Raspberry Pi itself because cross-compilation is broken for one of the upstream dependencies (which compilation took nearly a damn hour), and finally trimming down the data set to just the game feed updates, the API still took nearly 40 seconds to start up, which is really not going to cut it. So unfortunately, for now, the project needs an internet connection to function at all.

Bringing It Together

In any case, once the code was written and the physical parts had arrived it was time to start putting it all together. This was generally quite fun, and turned out rather well despite the strange SPI issues. Also, the 14-segment displays used the I2C bus instead of SPI and for whatever reason this only worked if it was initialized before the SPI bus and not after. Still, once it got up and running it was pretty neat.

A test of in-game score display using all three rows of LEDs

As I mentioned, though, the LED matrices were all in a single circuit board, but it was set up as four identical units within that, with even holes drilled on the internal units for the headers that had been soldered to the ends. And luckily the actual 8x8 LED units weren’t soldered directly to the boards but were instead mounted in headers, so they could be easily taken off to make it easier to cut.

Once that was done, the headers could be soldered in place and I could place them next to each other to create the 16x16 grid that would form the base of the unit.

After that, I needed to fabricate a faceplate. I created a very simple, blocked out design that resembled the original, with stands resembling a ballpark, holes for buttons and switches, and slots for the speaker. To make the design I had to wait for LEDs to arrive so that I could measure them, so time was short. This meant that, with everything else that happened, there wasn’t much time left before the deadline, so I didn’t have time to design the fully-detailed version, and I also had to run the prototype faceplate on the fastest printer settings.

The faceplate print in progress

On top of all that, because of some print bed misalignment that I still haven’t fixed and space constraints on the bed, I didn’t print it with a brim or raft, and so the print deformed as it cooled despite the heated bed. The result was the fairly ugly print you can see in the header image, which is so far the only faceplate I’ve made so far.

Cutbacks

Due to the various problems I was encountering, in order to make the submission deadline I had to cut a lot of the features I had planned. Also, I quickly discovered that I would also have to make some cuts due to physical limitations: my 3D printer’s print bed supports a maximum print of 20cm in either horizontal direction, and I was running out of room.

So the first thing that got cut were the 14-segment and one row of the 7-segment LEDs. This was a pretty simple decision, as ultimately it was going to be much harder to make room for a Raspberry Pi while moving all the other components down enough. Also, with the 14-segment displays running off the I2C bus it was using more GPIO pins and was more annoying to juggle in the code. This has the benefit of being more accurate to the original game, and is somewhat mitigated by the fact that the LED display library I’m using does some fun tricks to show alphabetic characters on 7-segment digits.

Another thing that got cut was the ability to choose a game. This one was just a pure time issue. With everything that went wrong I just never had the time to go back and wire up the interface necessary.

And ultimately, I was never able to figure out how to do the playing field.

If you look at the original Mattel game above, you can see the LEDs are behind a translucent screen that’s had graphics painted on it. I really wanted to get something similar, but due to all the various delays this ended up not being possible. I do still want to give this a try, though.

The Submission

And so this is the project as submitted. The faceplate is janky, the buttons aren’t quite right, and the code is occasionally misbehaving. Plus, the 7-segment LEDs flicker a lot more when filmed than they do to the naked eye. Pretty cursed, I’d say!

The full code is available over on my Github. There’s also a bit more of a detailed writeup on the state of the device as it was submitted to the hackathon, including details about its operation.

What’s Next?

Where do we go from here? Well, I do actually want to keep going with this one. Unlike Sloviet Blaseball, there’s a lot of room to improve here (obviously there is on Sloviet, but other than some code cleanup and more specific event handling it’s largely in a good place).

I’ve summarized some more detailed goals over on the Github, but in short this is still an interesting project to me. Consider this one “in-progress” and keep an eye out for more updates!

And, of course, we’ll see what happens in when the hackathon judging results come in…