Game Logic and Code
On a high level, we structured our code as a state machine, varying reactions to commands based on the current state of the game. Our main processing unit, the PIC24, is responsible for game management -- i.e. running the state machine, taking input comamnds and interfacing with the obstacle actuators and other sensors. The Raspberry Pi is mostly acting as a peripheral unit that acts as a Driver for Sound Effects and Bluetooth Wii-Board.View our code Here!
Because the game procedure is relatively linear, the state machine did not have to be incredibly complex. In implementation, a number of safety measures, such as regularly surveying the connectivity of the devices, needed to be implemented to ensure the robustness of the system. In execution, each of the states had constructors and destructors, which doesn't natively exist in C, which would run setup and cleanup portions of the execution at each transition phase.
When the game first turns on, it connects to the Rasberry Pi. And runs the basic permanent setup code, such as interrupts and servos. At this point, it waits for the Wii Balance Board to be connected, and indicates the instructions on the display screen accordingly. Once all of the connections have been established and verified, it stays idle until a coin is inserted.
Immediately after the coin is inserted, the code runs all of the transient setup code, such as initializing the variables to expected values. It puts the tilt angle at a neutral position, and closes the ball-release to house the ball until both players are ready.
The game then moves into the state waiting for the Player to be ready. In this state, the game instructs Player 2 to press the start button, then waits for the start interrupt to be triggered by the start button, then continues to the Run state.
This could be said to be the "main" state. In this state, the PIC handles the obstacle
controls from Player 2, while also communicating with the Rasberry Pi to get tilt data from
Wii Balance Board and keeping track of the time left in the game.
The obstacle management varies in complexity depending on the obstacle. The center spinner just takes analog data from the linear potentiometer, and feeds it directly to the servo controller to determine the angle. The flippers check to see if each flipper button is pressed, and if they are, sets the servo to the “high” angle, and if not, sets them to the low angle. The trickiest part in this is making sure that the servo turns the correct directions.
The most challenging obstacles to manage were the electromagnet and the control flip. This is due to the fact that these obstacles were timed, and the times for cooldown and active states were different. We used a state machine combined with a timer and a counter keeping track of how many times the timer flag raised to keep track of the time and the state.
This is the final state, where the outcome of the game is determined. If the ball reached the goal before the timeout, Player 1 wins; otherwise, Player 2 wins. At any rate, there is only one victor. After a brief moment of congratulating the winner, the game would loop back into idle mode
We collect weight ratio information from the Wii balance board in order to control the tilt board. Permanently pairing with the Wii balance board turned out to be a greater challenge than we had initially thought; this feature was unreliable and only supported for certain versions of PyBluez(4.99), with a backend Bluez only for Raspbian Wheezy. Because robustness was our priority, we maintained that at the start of each game the board would be re-paired with the Pi.
We use our USB line to primarily transmit information from the Pi to the PIC24, mainly information regarding the tilt angles, board connectivity status, and the IP address for debugging purposes. Initially, we were concerned about the speed of transmission, but it turned out to be fast enough for our purposes.
Because the PIC is a peripheral device, it cannot initiate a connection with the Raspberry Pi. In order to send signals to the Pi, we use the UART communication with a specifically formatted message. This feature is mainly used for triggering sound effects, as well as logging debug information so that the stored log could be examined later.
In order to communicate with the LCD Display without taking up too much of the pin's bandwidth, we have (scavenged from previous years) an I2C adapter that not only allows for communication with just two digital pins, but with multiple devices at the same time. We also use status messages sparingly, because displaying can take up too much bandwidth, introducing jitter in the servos as a result thereof.