This page details the design choices and implementation of all the electronics used in the completion of this project.
The schematic .pdf and the KiCad project can be found on published GitHub repository.
The system consists of three PIC32MX170F256B (PIC32) microcontrollers:
PLAYER1, PLAYER2, and HUB.
Each player (turret, laser, ammo indicator, sound effects) is controlled by an individual PIC32. Each PLAYER reads user inputs, controls outputs concerning the turret/laser, and communicates to the HUB that a player action took place with a pulled-up line shared between the PLAYER1, PLAYER2, and HUB.
The HUB keeps track of whether the game is on or idle (welcome screen) and communicates this to the two PLAYERs. The HUB reads an IR receiver to see if the user signaled a game start. It checks whether a target was hit, controls the dot pixel screen, the target neopixels, the score/side neopixels, and the servo to dispense the gear to the winning player's side.
The system requires a +3V3 and +5V power input from an external power supply.
We made sure to manage wires well and solder into permanence when possible, especially on the levels of modules. For example, any power connection, both of the player subsystems separately, and other sensitive, user-interactive components were soldered and mechanically fixed in place. This removed the need to check whether wires are still connected and significantly reduced the time in debugging, especially while integrating.
handling all inputs and outputs regarding the high level game
handling all inputs and outputs regarding the player turret/laser
(PLAYER2 is the same as PLAYER1, except the SFX_START, SFX_END, SFX_MUSIC are no-connects)
The LED matrix driven by the PIC32 via SPI. The only additional component is a buffer, which is used to increase the 3.3V signals from the microcontroller up to 5V signals required by the LED matrix.
Our individually addressable (neopixel) LEDs were WS2812B. They operated at 5V power, but the signal was at a 3V3 logic level for simplicity. The signal is a custom PWM protocol.
We used Neopixels to indicate:
- ammo remaining for each of the players (in their own colors).
- the score to each player's side as well, by turning pixels red or blue to create an interface, making it easy to see the game's progress for the audience and the players.
Our individually addressable (neopixel) LED library (WS2812.h and WS2812.c) is now published and has been used by multiple other groups for their projects to implement neopixels as user interfaces and decoration!
Based on which player won, the microcontroller drives the servo to dispense a gear towards one side or the other. The microcontroller takes an angle for the servo to turn to, and generates a corresponding PWM signal to drive the servo motor. The PWM signal determines the angular position of the servo motor by controlling the duty cycle of the PWM.
Each hit detection circuitry consists of an inverting comparator with hysteresis, designed to reliably detect and signal a "hit" event.
Each comparator utilizes a photoresistor at its non-inverting input, with the inverting input connected to a resistor divider network. The resistor values in this network are adjusted to establish distinct threshold voltages suitable for hit detection. We used a unity-gain buffer to set the bias voltage for our comparator with hysteresis.
The output of the comparator goes into the microcontroller.
Each of the resistor values has been tuned by shining our test laser onto our ten photoresistors and seeing a substantial but nonsaturating signal at a variety of lighting conditions, keeping the system robust.
This design allows the system to detect hits from one or multiple photoresistors simultaneously.
The start signal detection circuit is a non-contact interaction with the user. The game starts when a player waves or holds their hand on top of the welcome screen.
The start signal detection circuit is an IR transmit and receive system. It employs an IR LED that is always on. When the user's hand is above the IR LED, the IR signal reflects back to the receive side, which includes a transimpedance amplifier, followed by a comparator with hysteresis. The output of this chain of analog processing is a digital high or low, indicating whether the player wants to start a game. This configuration provides robust threshold voltage control, ensuring reliable transitions between digital high and digital low outputs.
We used unity-gain buffers to set the bias voltage for our amplifiers and comparators.
The rotational motion of the turret is controlled via an analog joystick, which functions as a variable resistor able to produce a varying analog (voltage) input.
The microcontroller maps voltages to an 8 bit number, converts that to a speed and then to an angle for the servo to turn to, and generates a corresponding PWM signal to drive the servo motor. The PWM signal determines the angular position of the servo motor by controlling the duty cycle of the PWM.
By moving the analog joystick, the user can seamlessly adjust the servo motor's speed and therefore the rotational position in real time.
Only one dimension of each joystick is connected since the turret has only one degree of freedom.
We also have a turret LED mounted on top to give additional feedback to the user by lighting up when the laser is shot.
The laser shooting is controlled through two PIC32 pins. The first pin is configured as an input that is received from pressing the trigger button.
The second pin is an output, which indicates to the laser circuit to turn on. The circuitry consists of the laser module in series with a resistor and a MOSFET for low-side drive.
When the trigger button is pressed, the output pin is driven high, which turns the MOSFET on. As a result, current is allowed to flow through this series branch, which turns the laser on for a pre-determined amount of time before turning off again. This laser transmitter is the KY-008 module in our implementation.
To play the sound effects when the game starts or ends, the music during the welcome state, and when the players shoot their lasers, we used Adafruit's Audio FX Sound Board. The board can be loaded with .wav files and with a specific file naming convention. By switching the GPIO pins of the board low, the corresponding file will be transmitted through the L and R output pins of the board.
The L and R pins are then connected to Adafruit's Stereo 3.7W Class D Audio Amplifier, which amplifies the signal to a loud enough level to be heard through the speaker.
Our individually addressable (neopixel) LEDs were WS2812B. They operated at 5V power, but the signal was at a 3V3 logic level for simplicity. The signal is a custom PWM protocol.
We used Neopixels to indicate:
- ammo remaining for each of the players (in their own colors).
- the score to each player's side as well, by turning pixels red or blue to create an interface, making it easy to see the game's progress for the audience and the players.
Our individually addressable (neopixel) LED library (WS2812.h and WS2812.c) is now published and has been used by multiple other groups for their projects to implement neopixels as user interfaces and decoration!
At each IC, we included a 0.1 uF capacitor as local charge storage, providing stability at local transitions and current draws. We used monolithic ceramic capacitors because they are:
+ physically small
+ inexpensive
+ maintain the capacitance value at higher frequencies, so able to support fast responses.
Additionally, we included two 1uF capacitors at the power rail of +3V3 and +5V. This is to have bulk charge storage for all components. We used tantalum capacitors due to their volumetric efficiency.
The HUB keeps track of whether the game is on or idle (welcome screen) and communicates this to the two PLAYERs.
Each PLAYER communicates to the HUB when a player action took place with a pulled-up line shared between the PLAYER1, PLAYER2, and HUB.
We implemented these lines as open-drain (pulled up by 3.3K resistors) instead of push-pull for two main advantages:
It protects against bus contention (two or more devices try to drive the same signal line to different logic levels at the same time). Multiple devices can share the same bus, and each device can only pull the line low (and can never drive it high) or release.
The potential issue with the push-pull implementation: bus contention. If one device tries to pull the line high while the other is trying to pull the line low, they would cause a direct short between Vcc and GND. This can lead to very large currents and may damage the microcontroller or the other devices on the bus while wasting energy.
The designer gets to choose a logic level and their power-frequency tradeoff with their Vcc and pull-up resistor. Therefore, this makes the protocol more flexible.