Imposter Attack
The design and construction of "Imposter Attack," a custom interactive game with ESP32-powered infrared targets, creative lighting, sound effects, and an Among Us-themed designs
At Legoland California this past summer I rode a Lego-styled ancient Egyptian adventure ride where you travel through a tomb and shoot as many snakes and mummies and things as you can with a laser gun. Two things occurred to me while riding: the fact that Legoland thought it a good idea to equip kids with lasers, and the thought that I could make a shooting gallery game like this that people would like.
Making games is fun. Games are the reason lots of people get into programming, including me. Some people even make a profession out of them. Even though this was months before Halloween, the game that appeared in my mind was a fun, shoot-em-up carnival-style game, and maybe I could inspire a few kids with software and hardware along the way.
But this wasn’t just a “this will be fun” idea. I’ve noticed a pattern about myself and it’s been the basis of many of my projects or even companies. I see bits of technology and how they fit together, especially those that have become recently available or economical. If the result is novel product or game that nobody else has created before, I’m locked in, and I tend to not shut up about it.
In this case, I had recently learned about inexpensive programmable microprocessors, particularly the ESP32, and I finally had an excuse to get into rudimentary electrical engineering. I was stunned at how cheap and accessible electronic components had become, and the online learning resources seemed infinite. I googled around and couldn’t find anything too similar to what I wanted to build, and thus this goofy and fun idea took hold.
What the heck is ESP32?
One of the greatest fears as a homeowner is uncontrolled running water. A great product to deal with this fear is Flume, an internet-connected water meter that gives you reports and alerts you to leaks. Flume had recently informed me that my old unit was defective and sent me a free replacement, so naturally I took apart the old one to see what was inside. Made of two components, a reader and base station that communicate wirelessly, opening them revealed that they were powered by a versatile, programmable chip called ESP32.
As someone who hadn’t been following makers, Arduino, or any kind of hardware, the ESP32 platform was astounding. It has a dual-core CPU that runs at up to 240 MHz, it can do wifi and Bluetooth, and it’s got about forty pins that can be used for all sorts of stuff. You can program it with the free Arduino IDE and a USB cable, and they cost about $6 per board. For someone who wanted to experiment efficiently and knew that they’d probably set one or two prototypes on fire, this was perfect.
I watched a lot of videos on electronics basics and Arduino and figured out what I’d need to buy to start learning. Initially I bought a single board and some LEDs from SparkFun, which is a popular site, but the lengthy ship times made me impatient. I turned to Amazon — yes, I’m sorry — where I could get components much more quickly and cheaply, and spent a few dollars on a few ESP-WROOM-32 boards and a breadboard starter kit. Learning the Arduino IDE was pretty quick, and before long I had some LEDs blinking and was reading infrared signals from a soundbar remote I had lying around.
The game started to solidify in my head, and the idea of zapping aliens seemed reasonably fun. I decided to create Among Us-style characters for the target faces since every kid loves that game (mine do) and the characters are very recognizable. So I decided to build out the first version of a Node.js game server with a web-driven scoreboard, and I had the ESP32 target connect to my wifi and communicate “hits” over UDP:
Moving to MicroPython
While working on the game I used my newfound ESP32 skills to do some other projects, such as automating the remote-controlled blinds in our bedroom as well as a motion sensor that would send Pushover notifications to my phone. I started to run into issues with keeping time and went down rabbit holes of using NTP and DS3231 realtime clock modules. Online friends convinced me to look at MicroPython1, which seemed to have a better ecosystem than Arduino, so I switched.
I was hesitant to switch to MicroPython because I wanted to stay low-level and better understand the hardware. But I quickly discovered that iterating with MicroPython was much faster. Python is a much easier language to work with, of course, but the real win was that there was no compilation or flashing step. In theory, you simply copy files to the board and reset it with the mpremote command. This was mostly true, but watching main.py for changes, copying the files, and monitoring the serial port for output gets cumbersome and buggy, so I built a tool to automate this. It worked most of the time but still occasionally required unplugging and reconnecting the board.
The switch to MicroPython really paid off later when I started using uOTA, an over-the-air updater framework. By hosting a tarball on my laptop and sending the targets an “update” command, I was able to update all 15 devices wirelessly without connecting them via USB. More on that later.
Infrared
Sending and receiving infrared (IR) signals with microcontrollers is well-documented with a handful of protocols. After some experimentation I found all of the remotes I had used NEC, which basically sends one long pulse, then a space, then bits of data with some simple error checking.

The IRremote library for Arduino is great. It’s well-documented, has lots of examples, and decodes the IR protocol automatically. Even though I didn’t use it, one of the best features is how it creates a 4-byte hash of any incoming IR command, which makes it trivial to check for button presses on an IR remote.
For inputs, I was definitely set on using the cheapest IR laser tag guns I could find, which use IR despite being called “laser” tag. I also had an “MagiQuest” wand from a local water park with a definitely-not-Harry-Potter game where you wave a wand to collect points. Importantly, I felt the wand would be more appropriate to use the wand at a school event.
Neither the pistols nor the MagiQuest wand used any known protocol2, so I had to parse the raw timing data and look for patterns there. I discovered that there was a particular tolerance needed when decoding an IR signal as they tend to get more corrupted or “wrong” the farther away you are and how accurately you’re aiming the transmitter at the receiver. I assume IR signals are bright and bouncy to allow the changing TV channels from a hundred feet away, but other than that I haven’t really researched the physics as to why this happens. Regardless, I was able to use this property to more accurately detect hits from the laser guns and wands.
Around this time I also switched to MicroPython and began using Peter Hinch’s micropython_ir libraries. I decided that a 1 bit was any burst longer than 750µs for the laser guns and 500µs for the wand. The entire receiving code ended up looking like this:
Oh no! This post got too long for email. Read the full version at https://blog.langworth.com/imposter-attack



