In this regard, I fear, most people won't find my project particularly enticing.
Utilizing only a simple ATMega168 clocked at 4MHz, together with an ESP-01 is enough to perform most tasks. While the ATMega handles the "hard-side" work like flashing the built-in and external LEDs, sending and receiving IR pulses, and generating noise, the ESP is there for communication.
The interface between ESP and AVR is a simple bidirectional UART line, but will eventually be replaced with a I2C line to improve quality and make expanding the system easy.
The mainboard has been kept simple to keep things easy. With only a few passives like capacitors and oscillators, as well as a few driving components like transistors for the LEDs, and not even a voltage regulator (as the LiPo cell never quite exceeds the ESP's acceptable voltage range), it's pretty bare. The addition of a buzzer, vibration motor, and connector for a "trigger" button complete it.
Communication between sets is done via an easy but effective IR channel. A strong LED (OSRAM SFH 4346) sends out pulses at a 40kHz modulation, which are received by standard VISHAY TSOP 4840. Add a small checksum, a ID code for each set, and a small lens or other focus mechanism, and you have a surprisingly precise, long-range (about 40m in good conditions!) way for one set to hit another!
Now the software is where it gets interesting. While I tried to keep things somewhat simple, it's become a bit of a mess of C++, NodeMCU LUA and Ruby, so stick with me here for a bit.
The AVR Side
The ATMega168, controlling the core of the Lasertag Sets, was programmed in C++, using Eclipse IDE. All libraries are custom and self-created (even though that probably wasn't necessary >.<), but aside from that there isn't much magic here.
All tasks are handled in Interrupts, so the main loop is free for anyone to use, should that be necessary!
It mostly just listens for commands coming in from the ESP, and reports back events, like a detected hit or when the trigger button is pressed.
Currently, the AVR handles the following tasks:
- Blinking the RGB LEDs of the board in various patterns (configurable)
- Beeping the buzzer and vibrating the haptic feedback
- Sending out IR pulses and decoding received pulses
- Detecting when the trigger button is pressed down.
The ESP Side
The ESP-01 is the most complex part of the module. It runs using NodeMCU, however it might eventually be switched over to a more powerful C++ code to alleviate some of the annoying limitations of the LUA language.
Using it's WiFi connection and MQTT, it connects to the lasertag server. It receives configuration of ... Basically everything, ranging from the Team and Client-ID, to how many shots per second the set can do. I'll probably write a bit more about the configuration options for the sets one day.
Aside from acting as a receiver for configuration, the ESP also handles all the logic of a client.
It tells the AVR to shoot out in regular intervals, tracks ammunition and reloads, handles respawing the player after a specific time, and provides some other statistics like battery charge and ping of the set itself.
In theory, the ESP could even be configured to run in a sort-of stand-alone mode! Though that wouldn't allow for very dynamic or interesting games, as no tracking of scores or such are done :P
The Ruby side
The server side code of the lasertag system is written in Ruby. Utilizing my own mqtt-gem, it connects up to a Broker, using it to communicate with the lasertag sets. This is mainly to simplify hack-ability of the whole thing, as well as giving me a well-developed communication protocol with low overhead.
Once the Ruby server is started, it handles a multitude of tasks:
- It hands out unique IDs to any connected lasertag sets. Up to 254 are supported, so you shouldn't run out of IDs any time soon!
- It receives and processes "hit" events of the lasertag sets. When a set records a hit, it does not immediately react - instead, it first asks the server what to do. This is to prevent a single actual shot to hit multiple people at once, while not letting hits to dead players or friendly-fire count (though the latter can be re-enabled :P)
- It configures all players, and thusly "creates" the whole game. Each player can be given a unique behavior, with different flash patterns, team colors, shot speeds, ammunition, reload speeds, and so on and so forth! It's quite plentiful, and makes for the immense flexibility of the system that I wanted to strive for.
- It also allows for so-called "Hooks" to be added and removed. Each hook can define various actions to be run at specific moments, like validating a shot, or when a player is killed. This makes for an immensely powerful, yet simple way of creating games and game-styles:
- You want to create a Zombie-Type gamemode? Sure, just change a player's team when he dies! You want to make Team Deathmatch or Capture the Flag? Just write up a little bit more Ruby code to handle the appropriate events, and you're good to go!
There's also a Webserver in the making, however ... Considering that I recently discovered QT, I might abandon that idea to instead write an app for the mobile phone with tight integration to the Lasertag system. It'd just look better.