Introduction: ArduMaze – a Joystick-Controlled Labyrinth

About: I am a curious scientist and dedicated teacher, supported by two loving little assistants.

So, the Labyrinth is a piece of cake, is it? Well, let’s see how you deal with this little slice.

— Jareth (David Bowie), Labyrinth (1986)


As David Bowie suggested, mazes and fun go hand in hand. And what better occasion than the 20th anniversary of the Instructables Robot to celebrate with a themed labyrinth gadget?

In a previous Instructable, I explored maze games and servo-controlled platforms. This time, I’m combining the two ideas to create something new: a double-gimballed labyrinth platform controlled by two SG90 servos.

The platform holds a classic bearing-style maze game—just like the little puzzles that used to come as gifts in cereal boxes, chip bags, or even laundry powder when I was a kid.

The twist is that you’ll be using servos to move the bearing through the labyrinth. To make things even more challenging, the two servos are controlled by two separate joystick modules. This means you can even play the game cooperatively with a friend!

But we’ll get to the gameplay later—first, let’s see how to build it.

Supplies


  1. 3D Printing
  2. 3D printer
  3. PLA filament, 1.75 mm (typo corrected from 1.74 mm)
  4. Mechanical parts
  5. 2 × ball bearing (⌀ 2 mm)
  6. 2 × bearings (⌀ 9.5 mm external, ⌀ 3 mm hole diameter)
  7. 2 × metal perforated steel plates
  8. 1 × transparent plastic sheet
  9. 8 × M4 screws (with matching nuts)
  10. Electronics
  11. 2 × SG90 servos
  12. 1 × Arduino Nano
  13. 1 × prototyping/development board (breadboard or PCB)
  14. 1 × I2C LCD display module (16×2)
  15. 2 × joystick modules
  16. Assorted connecting cables / jumper wires

Step 1: 3D Printing and Assembly

The ArduMaze device consists of five 3D-printed components, with the corresponding STL files provided in the attachments. All parts should be 3D printed. I used a Creality Ender 5 Pro with PLA filament (1.75 mm) at 20% infill. Normal print speed works well, but if you are in a hurry, a 0.28 mm layer height also gives good results.

The forks (Fork.stl), which hold the components, are fixed to a perforated steel plate using two M4 screws (the same platform used in other my Instructables projects). The fork also holds the servo, which controls the X-axis tilt of a horizontal rectangular frame (Frame.stl) that supports the maze box. Before attaching the frame to the platform, you need to mount the SG90 servo (Servo 1) into the corresponding holder in one of the arms of the fork. Then, in the opposite arm, insert the small bearing shown in Figure 2A, and finally attach the fork to the platform with the two screws (Figure 2B). The horizontal frame carries the second servo for the Y-axis tilt. The second servo drives the maze box (MazeBox.stl), which pivots on the frame using a small bearing. You need to insert and secure it with two small screws to the frame, and then insert the frame into the arm of the fork by connecting the axle of the servo to the box using the protruding lateral connector cylinder. Using the tip of an exhausted gel pen cartridge (see Figure 2A), you can make the axle for the opposite bearing (Figure 2C).

Next, insert the printed background image (Background.pdf) of the Instructable Robot into the box. Ensure the PDF file is printed to scale so that the picture fits into the box (Figure 2D). Then, add the 3D maze walls (InstrucRobotMaze.stl) and the two bearing balls. Cut a square of plastic foil to fit the rectangular opening of the lid frame (LidBox.stl) and glue it in place. Finally, attach the lid to the Maze box to prevent the steel balls from escaping during gameplay (Figure 2E).

Step 2: How the Control System Works

The tilting of the maze is driven by two SG90 servos (one for the X tilt and the other for the Y tilt), controlled by two joysticks through an Arduino Nano. Figure 1 shows how to connect the servos and the other parts of the control circuit to the extension board with the Arduino Nano. The program used to control the Arduino is attached.

Each servo is linked to a joystick axis, so moving the joysticks tilts the platform in real time, guiding the bearing through the maze. In Figure 2, the left joystick controls the X-axis servo (left–right tilt), while the right joystick controls the Y-axis servo (forward–back tilt). A built-in dead zone ensures the platform stays stable when the joysticks are near their centre positions.

At startup, the program sets both servos to 90° (default centre position). If valid calibration data is already stored in the Arduino’s EEPROM, those values are used instead. To distinguish real calibration data from random values left over by other programs, the sketch writes a special MAGIC NUMBER into EEPROM alongside the calibration values. When running the program for the first time, wait until the servos move to their starting positions before attaching them to the platform. This prevents sudden jumps that could stress the mechanism.

Because the labyrinth may not sit perfectly level, the system includes a Calibration Mode. Pressing the first joystick’s button activates calibration, allowing you to fine-tune the servo centres by moving the joystick in both tilt directions until the platform is horizontal. A quick button press saves the new centre values, which are then written to EEPROM—so the platform remembers them even after power is turned off.

A small I2C LCD provides live feedback, showing the current servo angles and joystick values in normal mode, and calibration information when setup mode is active.

Finally, the second joystick button starts a game timer. This lets you record how long it takes to solve the maze. The best time is stored in EEPROM and displayed on the LCD, turning the labyrinth into a competitive challenge with a built-in record table.

Step 3: Time to Play!

In this simple configuration, the game involves moving two bearings to opposite locations on the robot’s body (for instance, the two arms, antennas, or eyes) in the shortest possible time.

However, the ArduMaze can be easily adapted to games with different strategies, and it’s straightforward to design new mazes. For the Instructables Robot, I traced a path from the figure to the robot (Robot.xvg) and then used OpenSCAD (openscad.org) to create the walls using this simple script:

$fn=100;
arena_size = [200, 120]; // arena dimensions
wall_height = 15; // wall height
wall_thickness = 5; // arena wall thickness

module Robot() {
// Robot-shaped hole in the middle
union() {
color("orange",1) scale([0.325,0.33,0.34]) rotate ([0,0,90]) linear_extrude(height = wall_height)
import("Robot.svg", center = true);
difference () {
color("yellow",1) translate([0,0,0.5]) cube ([75.5,60,1],center=true);
color("white",1) translate([0,0,2]) cube ([73,58,10],center=true);
}
}


With just a few tweaks to the code or the maze design, you can create endless variations and challenges, making each game unique. While we wait to celebrate the next 40th anniversary of Instructables, I hope you have fun playing the ArduMaze!


Happy Birthday, Instructables Robot!