What is it?
This project is an interactive maze game built on the DE10-Lite FPGA. The goal? Tilt the maze to guide a ball from start to finish as fast as possible. I used Verilog to control servo motors via PWM, allowing full 4-direction tilt.
How?
Instead of basic buttons, I built a custom IR-based wave detection system — players steer the maze hands-free with gestures.
Gameplay & Scoring
The game starts a timer at launch and stops it at the goal. The DE10 board displays your time, and players can check past scores using onboard switches.
Challenges?
Coding this in Hardware (Verilog) was a b*tch, specially working with PWM signals... but it made me love it at the end.
START/END DETECTION
To track the score, I physically housed two IR sensors on the maze which allowed me to incorporate a timer that starts when the ball is released at the beginning of the maze and stops when the ball reaches the end. The timer's display was shown on the onboard 7-Segment HEX display.
The issue was that upon the release of the ball, the ball might trigger the start game again. Therefore, I used an SR Latch that would set a StartGame trigger (Set) when the ball is detected by the start detector, and the only way to StopGame trigger (Reset) is for the end detector to be asserted.
PERIPHERALS
6x - IR (Infrared) Sensors
4 sensors in harmony were used to create hand moton detector as input from the players.
2 were used for the start/end timer on the maze.
All sensoors are indicated with large arrows. These sensors consisted of three pins:
VCC
Ground
Digital IN
Digital In was connected to the Arduiono pins on the FPGA board to get a signal anytime a motion was detected at a specific distance from the sensors.
The Digital In is an Active low signal, inverse asserted when motion detected.
2x - 9g Servo Motor
This setup was the hardest to figure out because of two main components. First was to understand how PWM (Pulse Width Modulation) works, and second was to make them work together in conjuction with each other to operate a platfrom that can tilt left, right, front and back.
The base motor controlled one axis of orentiation, the Pitch, which rotated the top motor. Thus, the top motor had control of the Roll axis, allowing the maze to have freedom of axis in both orientation as in (Fig 2).
The Servo Motor has three Pins (Fig 5):
VCC
Ground
Digital IN
Unlike the Digital IN for the IR sensors, the Servo motor digital signal was not as simple as an Active Low. It uses PWM (Fig 3) signals at:
Period: 50 Hz (20 ms)
Duty Cycle: 1 – 2 ms (5% - 10%)
The reason the Duty Cycle varies from 1 – 2 ms (5% - 10%) is because that is what tells the motor what position to be at (Fig 4).
PERIPHERALS CODE
IR (Infrared) Sensors:
Code was a simple Assertion if motion is detected:
ARDUINO_IO are the pin inputs for the detectors. The code above implies if motion is detected, I get a signal. I had 6 of these ports as inputs for the IR.
Servo Motor
To understand this code, we must grasp the knowledghe of PWM.
I converted the onboard CLOCK of 50 MHz to 50 Hz dividing by 1 million. This was done by adding 1 to an artifial counter for the servo to achieve 50 Hz on every positive clock edge untill 1 million, and then resetting it back to 0.
Since the onboard clock consists of million clock rises for one period, referring back to Figure 4, I want to only tilt the maze slightly in direction of choice, by roughly 5 degrees. This means, I will need a duty cycle that will allow me to move between 95- 85 degrees.
In order to let the maze stay in a neutral position, the motors state must remain at 90 degrees, which means a duty a cycle of 7.5 percent. Roughly 0 – 52 000 out of the million clock rises.
In order to tell the motor to rotate 5 degress either way, I need to send a PWM signal of 0 – 58 000 or 0 – 52 000 (about 3000 clock rises) to tilt towards either direction. Below is a snippet for one of the directions:
Here, ARDUINO_IO[0] is one of the motion detectors for the players hand.
ARDUINO_IO[11] is the motors pin output which sends an assertion between that duty cycle period.
HAND MOTION DETECTION
At first, I intended to utilize the built-in G-sensor to react to the maze's motions. Nevertheless, my goal was to create a completely touchless game, which led me to develop a custom sensor. This involved integrating a board capable of detecting hand motions. I achieved this by employing four IR sensors that activate corresponding left, right, up, or down responses to adjust the PWM of the motors.
Pseudo Code:
if LeftDetected & NOT RightDetected
do LEFT tilt code……
if RightDetected & NOT LeftDetected
do RIGHT tilt code……
if NOT RightDetected & NOT LeftDetected
do middle position code…
if UpDetected & NOT DownDetected
do UP tilt code……
if DownDetected & NOT UpDetected
do DOWN tilt code……
if NOT UpDetected & NOT DownDetected
do middle position code…
DIAGRAM
This project comprises several distinct modular components. To facilitate comprehension, I will divide it into sections for easier understanding.
Final Thoughts
This game wasn’t just about controlling a maze. It was about designing an experience. I wanted to build something fun, competitive, and interactive. The idea came from a previous project I worked on, a laser-shooting turret with pan-and-tilt control. That was my first time dealing with servo angles and physical movement through code. I took what I learned from that and thought, what if I used that same pan-and-tilt concept to move a maze instead of a laser?
This time, I wanted to go deeper. Controlling the maze with touchless IR sensors meant thinking not just about movement, but about player input and game flow. I had to manage not only the motion but also a full state machine to track timing, scores, and user interaction.
Working with Verilog and the DE10-Lite board took everything to a lower level. I had full control over PWM generation and hardware signals, but that also meant every tiny mistake had visible consequences. Tools like Quartus helped debug and synthesize the logic, but I had to build everything from the ground up. That’s where I saw the real power and limitation of FPGAs. Timing issues, pin mapping, limited I/O — these aren't things you worry about in software. But when you’re designing hardware logic, they define what you can build.
By following every bit through the system, I gained a much clearer understanding of how computing actually works. Not just in theory, but in real, physical systems. And that’s something you can’t really get from high-level code alone.
Challenges
One of the toughest parts of this project was figuring out how to properly generate and manage PWM signals from scratch in Verilog. Unlike using high-level libraries or platforms like Arduino, everything had to be built at the signal level. That meant tuning duty cycles, setting up precise timing, and syncing the servo response correctly. Getting the servo motors to move smoothly without jitter required deep trial-and-error with clock dividers, counters, and edge-triggered outputs. A single miscalculation in timing could throw off the entire movement.
A lot of people told me I was wasting my time and should just use an Arduino or Raspberry Pi and call it a day. But that kind of shortcut defeats the purpose. I wanted to understand how low-level control works and see if I could get it working directly through HDL. Even though it made the project harder, pulling it off was way more rewarding in the end.