← All projects

Design & Fabrication

2.5 DoF Carnival Fishing

Electromechanical DesignerElectromechanical Design, Boston University · Group 7 team projectSep 2026 — Oct 2026

Project overview

A Joystick-Controlled Carnival Fishing Game.

Our team built a 2.5-degree-of-freedom gantry that turns the carnival fishing game into a machine: the player steers an electromagnet over a spinning plate of fish with a joystick, dips it to pick a fish up, and drops it in the bucket.

The gantry moves freely in X and Y, which gives two full degrees of freedom. The third axis, Z, only has two positions, up and down: one press of the joystick lowers the magnet, pauses, and lifts it back up. That limited vertical motion is the “half” degree of freedom. A fifth stepper motor spins the plate underneath to make the game harder, and everything runs from one handheld joystick and one control board.

This page follows the project in order: the brief, how it plays, the first linear stage, the CAD models, each part as built, manufacturing, electronics and code, and the final assembly.

Key Work & Outcomes

  • Demonstrated the working game to our professor, who played it with the joystick.
  • Built a belt-driven gantry on 80/20 aluminum extrusion with X–Y travel of up to 50 mm/s and a 10 mm Z dip.
  • Designed a purpose-built end effector: a printed holder that carries an electromagnet, plus 3D-printed fish with steel screws for it to grab.
  • Drove five stepper motors (two for X, plus Y, Z, and the plate) and the electromagnet from one MKS Base board.
  • Wrote Arduino firmware over seven versions that maps one joystick to movement, the Z dip, the magnet, and a three-round game.
  • Modeled every printed part in SolidWorks, with equation-driven motor mounts sized from the NEMA 17 dimensions.

The brief

A Portable Motion System With A Purpose

In six weeks, each team had to design, build, and integrate a Cartesian motion system that performs a task of its choice.

RequirementHow it shaped our design
End effector work area of at least 2.5 in × 2.5 inThe gantry spans the whole fish plate, so the magnet can reach every pocket
Small and light enough to carry in a backpack; assembled by one person in 10 minutesA frame of stock 80/20 lengths joined by printed blocks and screws
Provided extrusion, stepper motors, belts, and pulleysThe extrusion doubles as the frame and the linear guide for each axis
All other parts 3D printed or laser cut, joined with standard fasteners (no tape or glue)Every custom part was 3D printed and fastened with screws
Extra credit for an original, purpose-built end effectorAn electromagnet holder that picks up fish carrying steel screws

How it plays

One Joystick, Four Actions

The player lines the magnet up over a fish, switches the magnet on, dips to pick the fish up, and carries it to the bucket.

Pushing the stick further moves the gantry faster, so small corrections are easy and long moves are quick. While the magnet is dipping, X and Y are locked so the player can’t drag the magnet sideways through the fish.

Joystick inputWhat the machine does
Push the stickMoves the magnet in X and Y; speed follows how far the stick is pushed
Press onceZ dips down 10 mm, pauses for 0.3 s, and comes back up
Press twice quicklyTurns the electromagnet on or off
Hold for 0.8 sStarts the plate game, or stops it early

The plate game gets harder each round, with a 3-second pause between rounds:

RoundLengthPlate motion
Round 160 sOne turn every 4 s
Round 245 sTwice as fast (one turn every 2 s), in the opposite direction
Round 360 sSplit into 2–4 random parts; every part reverses direction at a new random speed

First linear stage

Starting With One Axis

Before designing the gantry, we built and tested a single linear stage.

The first stage used a NEMA 17 stepper turning a lead screw through a flexible coupler. A brass nut drove a foam-board carriage along the screw, with a pillow-block bearing supporting the far end. We drove it with G-code through Marlin firmware, configured at 400 steps/mm for the 8 mm-per-turn lead screw, then stacked two stages into the in-class plotter.

For the fishing game, we kept the NEMA 17 motors and the MKS Base board but switched to timing belts running on 80/20 aluminum extrusion. Belts move a carriage much faster than a lead screw, which a game needs, and the extrusion serves as both the frame and the rail.

First linear stage: a NEMA 17 stepper driving a lead screw through a flexible coupler, moving a foam-board carriage
First linear stage: stepper, coupler, lead screw, brass nut carriage, and end bearing
First test: the stepper drives the carriage along the lead screw
Two stages combined into a plotter, drawing a square from G-code

CAD models

Designed In SolidWorks

The whole machine was modeled as one SolidWorks assembly, built up from subassemblies for each axis, the plate, and the controls.

We imported vendor models of the NEMA 17 motors, timing pulleys, MKS Base board, and joystick module to check fit and clearances. The motor mounts are driven by global equations (a 1.7 in motor face, 1.2205 in between mounting holes, a 5 mm shaft, and the 1 in extrusion size), so changing one number updates every mount.

SolidWorks render of the full machine: red carriages on aluminum rails, a green Z motor holder, the blue plate with red fish, the control board, and the joystick
Full assembly: gantry, Z motor holder, fish plate, control board, and joystick
CAD render of the X rail subassembly
X rail subassembly: 80/20 rail with a motor holder at one end and an idler block at the other
CAD render of the Y rail subassembly
Y rail subassembly: the crossbar the Z carriage rides along
CAD render of the rotating plate assembly
Plate assembly: rotating plate seated in its foundation
CAD render of the electronics box engraved ME 360 Group 7
Electronics box assembly, engraved “ME 360 Group 7”
CAD render of the handheld joystick controller
Handheld joystick controller assembly

Part by part

Every Printed Part, In CAD And As Built

Each custom part was designed around the 1 in extrusion, the NEMA 17 motors, or the game itself.

PartWhat it does
Motor holderClamps a NEMA 17 under the end of an X rail; the pulley on top drives that rail’s belt
Rail end blockCloses the other end of each rail and carries the idler pulley the belt wraps around
X carriageSlides along an X rail on the extrusion and holds one end of the Y rail
8020 holderJoins lengths of extrusion where the frame meets
Z motor holderRides along the Y rail and carries the Z motor that raises and lowers the magnet
Electromagnet holderThe end effector: holds the electromagnet at the bottom of the Z axis
Rotating plate and foundationA turntable with 14 fish pockets, driven from below by the plate stepper, sitting in a base
FishGame pieces, each with a steel screw for the magnet to pick up
Electronics box (top and bottom)Encloses the MKS Base board, with slots for wiring
Joystick housing (top and bottom)A handheld shell around the joystick module
CAD render of the red motor holder
Motor holder (CAD)
Printed motor holder with a NEMA 17 underneath and a pulley on top, at the end of an X rail
Motor holder (built), with the pulley driving the X belt
CAD render of the rail end block
Rail end block (CAD)
Printed rail end blocks with idler pulleys at the corners of the frame, beside the red catch bucket
Rail end blocks and idlers (built), next to the catch bucket
CAD render of the X carriage
X carriage (CAD)
Printed X carriage on the rail with the belt clamped to it
X carriage (built), with the belt clamped on
CAD render of the 8020 holder
8020 holder (CAD)
CAD render of the green Z motor holder
Z motor holder (CAD)
Green printed Z motor holder carrying a NEMA 17 on the Y rail
Z motor holder (built), riding on the Y rail
CAD render of the electromagnet holder
Electromagnet holder (CAD)
Electromagnet hanging just above the fish on the plate
Electromagnet (built), lowered over the fish
Magnet test (Oct 20): the electromagnet, held by hand, lifts a fish by its screw
CAD render of the rotating plate with fish pockets
Rotating plate (CAD)
CAD render of the plate foundation
Plate foundation (CAD)
Underside of the plate base showing the stepper motor that turns the plate
Underside of the base (built): the stepper that turns the plate
CAD render of a fish game piece
Fish (CAD)
Printed red fish with a steel screw in its top
Fish (built), with its steel screw
CAD render of the electronics box lid
Electronics box top (CAD)
CAD render of the electronics box base
Electronics box bottom (CAD)
Black printed electronics box engraved ME 360 Group 7 with fish
Electronics box (built)
CAD render of the joystick housing top
Joystick housing top (CAD)
CAD render of the joystick housing bottom
Joystick housing bottom (CAD)
Black printed handheld joystick controller
Joystick controller (built)

Manufacturing

Printed Parts On Aluminum Rails

Custom parts were 3D printed; the structure uses stock 80/20 extrusion, timing belts, and off-the-shelf pulleys, all joined with screws.

ComponentHow it was made
Motor holders, rail end blocks, carriages, 8020 holders3D printed
Z motor holder and electromagnet holder3D printed
Rotating plate, foundation, fish, and catch bucket3D printed; a steel screw in each fish for the magnet
Electronics box and joystick housing3D printed
Frame, legs, and rails1 in 80/20 aluminum extrusion, cut to length (11.5 in and 15 in rails)
DriveNEMA 17 steppers, GT timing belts, aluminum timing pulleys, and idler pulleys
ElectronicsMKS Base v1.5 board, analog joystick module, and electromagnet
The gantry mid-build on a workbench, wired to the control board
Mid-build: first full fit-up of the printed parts, rails, and wiring
Z carriage on the Y rail with the electromagnet hanging below
Z carriage on the Y rail, with the magnet hanging below

Electronics & code

From Stick To Steps

One MKS Base board (an ATmega2560 running Arduino code) reads the joystick and drives five steppers and the magnet.

DeviceBoard connection
Joystick X / YAnalog pins A11 and A12
Joystick buttonPin D19, with the internal pull-up
X motors (two)X and E0 driver slots, stepped together; one is reversed in code because the two motors face opposite ways
Y and Z motorsY and Z driver slots
Plate motorE1 driver slot
ElectromagnetE0 heater MOSFET output (pin D10), with a flyback diode across the coil
Electronics box with the joystick cable and motor wiring running to the gantry
The electronics box wired to the joystick and the motors

We first planned to run the gantry on GRBL with G-code jog commands streamed from a laptop script that read the joystick. We switched to our own Arduino firmware so the joystick plugs straight into the board and no computer is needed during play. The firmware grew one feature at a time:

VersionDateWhat it added
Prototype G-codeSep 30GRBL jog commands and a bench test that simulates a player
joystick_gantryOct 5Proportional X–Y control from the stick; a single press dips Z
+ buttonOct 19Double press toggles the electromagnet
+ rotatingOct 19Long hold spins the plate
+ timerOct 20The plate stops by itself after one minute
+ round 2Oct 20A faster second round, then a pause and a reversed direction
joystick_gantry_finalOct 20Round 3 with random parts, speeds, and direction changes

How the final firmware works:

  • Proportional speed. The stick is calibrated at power-on, ignores small movements near center (a dead zone), and scales speed up to 4,000 steps/s, which is 50 mm/s at 80 steps/mm.
  • Smooth acceleration. Speed ramps at 8,000 steps/s² so sudden stick moves don’t stall the motors.
  • Button decoding. Presses are counted on release, so the code can tell a single press, a double press, and a long hold apart.
  • Z dip state machine. Down, pause, up, then idle, with X and Y locked until the dip finishes.
  • Plate game. A timer steps through the rounds. Round 3’s parts and speeds are picked randomly each game, and the plate always slows to a stop before reversing.

The core of the joystick control:

// Stick reading -> signed target speed, with dead zone and proportional control
float stickToSpeed(int raw, int center) {
  int d = raw - center;
  if (abs(d) < DEADZONE) return 0;
  float span = (d > 0 ? 1023 - center : center) - DEADZONE;
  float f = (abs(d) - DEADZONE) / span;
  if (f > 1) f = 1;
  return (d > 0 ? f : -f) * MAX_SPEED_XY;
}

// Move current speed toward target, limited by acceleration
float ramp(float current, float target, float dt) {
  float maxDelta = ACCEL_XY * dt;
  if (target > current + maxDelta) return current + maxDelta;
  if (target < current - maxDelta) return current - maxDelta;
  return target;
}

Download the full Arduino sketch (joystick_gantry_final.ino)

Final assembly

The Finished Machine

The finished gantry stands on 80/20 legs over the fish plate, with the catch bucket beside it and the controls on a cable in front.

At our final demonstration on October 21, our professor took the joystick and played the game, steering the magnet over the spinning plate.

Final demonstration: our professor plays the game with the joystick
Front view of the finished machine with the fish plate and catch bucket under the gantry
Front view: gantry, fish plate, and catch bucket
The finished machine with its joystick controller and electronics box
The full setup with the joystick and electronics box
SolidWorks render of the full carnival fishing assembly
The CAD model the build was based on
Demo: the fish plate turning beneath the gantry

Continue exploring

See The Complete Project Collection.

Back to portfolio