Adaptive & Ergonomic Gaming Controller for Those With Duchenne Muscular Dystrophy
by derekdonohoe in Circuits > Assistive Tech
32 Views, 0 Favorites, 0 Comments
Adaptive & Ergonomic Gaming Controller for Those With Duchenne Muscular Dystrophy
Welcome to this step-by-step assembly guide for building a custom, highly accessible adaptive gaming controller. Designed specifically to overcome the physical limitations of traditional gamepads, this project combines a low-force analog joystick, no-touch infrared proximity sensors, and a mouth-operated sip-and-puff switch into an ergonomic, 3D-printed layout. By offloading complex inputs to accessible movements that require minimal muscular force, this open-source controller provides an adaptable, comfortable alternative for gamers with progressive muscle weakness, such as Duchenne Muscular dystrophy, or limited hand mobility. Whether you are building this for yourself or a loved one, this guide will walk you through the printing, soldering, wiring, and programming required to get your custom controller game-ready.
Supplies
Microcontroller and Wiring
Sensors & Special Inputs
Mechanical Switches & Buttons
Soldering
Miscellaneous
3D Printing
3D Print Shopping & Settings List
- Filament Recommendation: PLA or PETG (PLA works perfectly for prototyping, while PETG offers slightly more durability for daily mechanical use).
- Infill: 15% to 20% (Gyro or Grid pattern) for the main body; 30% for the stick pieces to handle constant physical movement.
- Supports: Needed only for the main housing face to ensure the sensor cavities and large joystick port print cleanly without drooping.
Component Breakdown
Main Interface Faceplate (White Part)
The upper layer of the main housing enclosure. It features designated channels and precise friction-fit cavities shaped to hold your joystick, push buttons, microswitch, and dual IR sensors.
See top of Image 1
Main Enclosure Base (Black Part)
The lower structural layer of the chassis. It serves as a protective tray to hold the Arduino Leonardo, solderless breadboard, and organized cable runs, with a high-friction, non-slip grip texture on the bottom.
See the bottom of Image 1
Sip-and-Puff Stick Extensions(Black Rods)
A two-piece interlocking modular wand. The upper piece houses the pressure switch mount, while the hollow lower piece acts as a rigid conduit to guide the wiring directly into the main base.
See Image 2
Post-Processing Tips:
- Clean the Channels: Use a small hobby knife or file to remove any minor stringing or support remnants inside the narrow routing channels and sensor slots. This ensures your components slide in smoothly.
- Test the Fit: Before final assembly or wiring, dry-fit the upper stick extension into the lower base piece to verify the internal channels line up and that the snap-fit connection locks tightly.
Downloads
Add Grippy Material to the Base (Optional)
Clean the Surface: Dampen your cloth with rubbing alcohol and thoroughly wipe down the bottom surface of the 3D-printed base. This removes any finger oils, dust, or residual print-bed adhesives that would prevent the grip material from sticking properly. Let it dry completely for a minute.
Prepare the Grip Material: If you are using pre-cut rubber bumper feet, peel them directly from their backing. If you are using a roll or sheet of grip tape, cut out a shape that matches the footprint of your base, or cut four small squares for the corners. In my case, I used the inside side of heatshrink for my grppy material.
Apply the Grip: Carefully align the adhesive side of the rubber, heatshrink, or grip tape with the bottom of the base. Press down firmly, starting from the center of the grip pad and working your way out to the edges to ensure there are no trapped air bubbles.
Set the Adhesive: Apply firm, even pressure with your thumb over the entire gripped area for about 10 to 15 seconds. This activates the pressure-sensitive adhesive and ensures a permanent bond with the 3D-printed plastic. Place the stick upright on a flat surface to test the stability.
Assemble Sip & Puff Module
Prepare the 3D-Printed Components: Inspect the upper and lower 3D-printed stick pieces. Clear away any leftover support material, strings, or printing brims from the snap-fit joints and the sensor mounting cavity to ensure a smooth, flush fit.
Route the Wiring: Feed the jumper wires down through the center channel of the upper stick piece. Pre-routing the wires ensures they don't get trapped during the final assembly.
Snap the Stick Together: Align the interlocking snap-fit joint of the upper stick piece with the receiver on the lower base piece. Ensure the internal wires move freely and are not pinched in the joint. Press the two halves together firmly, and then glue it together.
Solder the Sip and Puff to the Wires
Prep the Wires: Use wire strippers to remove about 1/4 inch (6 mm) of insulation from the freshly cut ends to expose the bare copper.
Slide on the Heat Shrink: Cut small pieces of heat shrink tubing (about 1 inch or 25 mm long). Slide a piece of tubing onto each wire now. Move them far down the wire so they stay cool and don't shrink prematurely while you are soldering.
Apply Flux and Tin: Apply a small dab of flux to the exposed copper wire strands and to the terminal pins on the sip-and-puff switch. Touch your hot, tinned soldering iron tip to the wire strands while applying a tiny amount of solder to "tin" the wires. Do the same briefly for the switch terminals.
Solder the Connections: Hold the tinned end of a wire flush against the appropriate switch terminal pin. Touch the soldering iron tip to the joint to melt the existing solder together. Add a small amount of fresh solder if needed to create a smooth, shiny bond. Remove the iron and hold the wire perfectly still for a few seconds until the joint solidifies. Repeat for the remaining connections.
Insulate with Heat Shrink: Allow the soldered joints to cool completely to the touch. Once cooled, slide the heat shrink tubing up the wires until it completely covers the bare metal joints and the base of the switch terminals. Use a heat gun to gently apply heat to the tubing until it shrinks tightly around the connections, providing insulation and strain relief.
Install the Sip & Puff in the Quadstick
Feed the Wiring: Gather the jumper wires extending from the bottom of the sip-and-puff stick. Carefully feed these wires through the top opening of the main controller housing, guiding them down into the main cavity.
Insert the Stick: Gently press the base of the stick down into the housing slot. As you push it in, gently pull the wires from the inside of the cavity to prevent them from bunching up, twisting, or getting pinched between the plastic components.
Seat and Verify: Push the stick down until the lip sits completely flush against the top of the housing. There should be no gap between the two pieces. Give the stick a gentle tug upward to ensure the internal retention clips or friction-fit features are holding it securely in place.
Manage the Cables: Inside the main housing cavity, gently pull the remaining slack through. Coiling or securing the excess wire with a small zip tie can help keep the workspace clean and prevent the wires from interfering with other components like the microswitch or the Arduino.
Solder/Install the Microswitch
Pre-Wire the Switch: If you haven't already, ensure your jumper wires are securely connected to the COM (Common)terminal and the NO (Normally Open) terminal of the microswitch. Use the soldering techniques from the previous steps to ensure a strong bond.
Locate the Mounting Slot: Find the designated microswitch pocket inside your 3D-printed housing. Inspect the area to ensure it is clear of any printing debris or plastic strings that could prevent the switch from sitting level.
Align the Lever: Orient the microswitch so that its actuator button or metal lever faces the moving part of the mechanism it is meant to detect. Ensure that when the mechanism moves, it presses the lever straight down without binding or catching on the edges of the plastic.
Secure the Switch:
- For Snap-Fit or Glue Designs: Press the switch firmly onto the alignment pins until it seats flush against the wall. If your model relies on a friction fit, you can apply a tiny drop of hot glue or adhesive to the back corners of the switch casing to lock it into place.
Test the Mechanism: Manually move the stick or trigger mechanism to ensure it cleanly activates the microswitch. You should hear a distinct, crisp "click" when the mechanism engages, and the switch should spring back immediately when pressure is released.
Install the IR Sensors
Identify the Left and Right Sensor Ports: Locate the two distinct sensor holes on the front or sides of your controller housing. Check inside the cavities to ensure there are no 3D-printing artifacts, such as loose strands or support remnants, that might block the sensors from seating properly.
Route the Wiring First: Take the jumper wires connected to the back of the first IR sensor and feed them through the designated hole from the outside of the housing in toward the internal electronics bay. Repeat this process for the second sensor in the remaining hole.
Align the Sensor Diodes: Orient the first IR module so that the clear and dark infrared diodes (the small bulb-like components on the front of the board) point straight out of the hole. Alignment is critical to ensure the sensor's beam path is completely unobstructed by the plastic housing.
Press-Fit the Modules: Gently push the first IR sensor module forward into its hole until the face of the board or the tips of the diodes sit flush with the exterior wall of the housing. Depending on your 3D print tolerances, this should be a snug friction fit. Repeat the process to push the second IR sensor into the opposite hole.
Secure and Check Clearances: If the sensors feel loose, you can secure them from the inside using a small drop of hot glue on the corners of the circuit board (avoiding any components or adjustment dials). From the outside of the housing, look directly into both holes to confirm that the sensor lenses are clean, centered, and free of any blocking material.
Installing the Button
Solder the Button: Connect your wires to the exposed metal leads on the back of the button. Ensure the connections are firm and that the bare metal leads are not bent toward each other, which could cause an accidental short circuit.
Locate the Button Port: Find the designated button cutouts on your controller housing. Ensure the edges of the holes are smooth and free of any 3D-printing strings or artifacts so the buttons do not catch or stick when pressed.
Seat the Button Securely: Push the body of the button through the hole from the inside until the button cap protrudes out the top. If needed, add some glue to the button to ensure a good fit.
Verify the Spring Action: Press the button from the outside of the housing several times. Ensure it moves down smoothly without rubbing against the plastic walls and pops right back up immediately upon release with a clean, tactile click.
Installing the Joystick
Position the Module: From the inside of the housing, align the center of the hole. The plastic thumbstick shaft should protrude cleanly through the top hole of the housing.
Orient the Axes: Ensure the pin header on the joystick module is oriented according to your housing design (usually facing toward the back or bottom) so the wire paths have room.
Secure the Joystick: Insert your joystick through the hole in the printed housing. Next, take some hot glue and glue the joystick firmly to the base plate.
Solder LEDs
Identify LED Polarity: Examine your LEDs. The longer leg is the positive side (Anode), and the shorter leg(aligned with a flat edge on the plastic bulb casing) is the negative side (Cathode).
Solder Resistors to the Positive Legs:
- Trim the longer (positive) leg of each LED down to about 1/2 inch (12 mm).
- Take a 220Ω resistor, trim one of its leads, and twist it together with the shortened positive leg of the LED.
- Apply a dab of flux to the twisted joint. Touch the hot, tinned iron to the joint and apply a small amount of solder until it flows smoothly across the connection.
Prep and Attach the Jumper Wires:
- Cut the female ends off your jumper wires and strip away 1/4 inch (6 mm) of insulation.
- Slide the heat shrink tubing onto the wires now and push it down far enough so the heat from soldering doesn't shrink it early.
- Solder one wire to the remaining open lead of the resistor (this wire will route to the Arduino Digital Pin).
- Solder a second wire directly to the shorter negative leg of the LED (this wire will route to the Ground rail).
Insulate the Connections:
- Let the joints cool completely to the touch.
- Slide a piece of heat-shrink tubing up over the negative leg joint.
- Slide a separate piece of heat shrink tubing over the entire resistor and its solder joints, ensuring no bare metal is exposed.
- Apply gentle heat with a heat gun until the tubing shrinks tightly around the components.
Repeat and Label: Repeat the process for the second LED. Label your wire ends clearly (e.g., Power Positive, Activity Positive, and Ground) so you can easily plug them into the correct pins on your Arduino Leonardo during final assembly.
Wiring
Electronics Wiring Guide
Since all digital input pins use INPUT_PULLUP in the code, these switches do not require external resistors—they simply connect between their designated Arduino pin and a shared Ground (GND) rail.
1. Setup the Breadboard Power Rails
Before connecting your modules, establish your shared power and ground connections on the solderless breadboard rails:
- Run a jumper wire from the 5V pin on the Arduino to the red positive (+) rail on the breadboard.
- Run a jumper wire from a GND pin on the Arduino to the blue negative (-) rail on the breadboard.
2. Component Pin Mapping Table
Tactile Push Button
Digital Pin 13
Breadboard Ground (-) Rail
Press to hold 'W'
Sip-and-Puff Switch
Digital Pin 8
Breadboard Ground (-) Rail
Activate to hold 'S'
Left IR Sensor
VCC -> Breadboard Power (+) Rail
GND -> Breadboard Ground (-) Rail
OUT -> Digital Pin 2
Trigger to hold 'A'
Right IR Sensor
VCC -> Breadboard Power (+) Rail
GND -> Breadboard Ground (-) Rail
OUT -> Digital Pin 3
Trigger to hold 'D'
Microswitch
NO (Normally Open) -> Digital Pin 4
COM (Common) -> Breadboard Ground (-) Rail
Press for Mouse Left Click
Analog Joystick
+5V -> Breadboard Power (+) Rail
GND -> Breadboard Ground (-) Rail
VRx -> Analog Pin A1 (Mouse X-axis movement)
VRy -> Analog Pin A0 (Mouse Y-axis movement)
SW -> Digital Pin 7
Press down on joystick for Left Shift
Power LED (Always On Indicator)
Long Leg (+) -> Digital Pin 10 (via 220Ω resistor)
Short Leg (-) -> Breadboard Ground (-) Rail
Activity LED (Blinks on Input Activity)
Long Leg (+) -> Digital Pin 11 (via 220Ω resistor)
Short Leg (-) -> Breadboard Ground (-) Rail
3. Step-by-Step Wiring Instructions
- Connect the Joystick Axes: Connect the VRx pin to A1 and the VRy pin to A0.
- Wire the Status LEDs: * Push the LEDs into the breadboard.
- Connect a 220Ω current-limiting resistor from Arduino Pin 10 to the long leg (anode) of your Power LED. Connect the short leg (cathode) to Ground.
- Connect a 220Ω resistor from Arduino Pin 11 to the long leg of your Activity LED. Connect the short leg to Ground.
- Verify Grounds: Ensure that every single mechanical switch (Sip-and-Puff, Button, Microswitch, and Joystick click) has one of its legs routed directly to the shared ground network. If any component lacks a solid ground pathway, the INPUT_PULLUP state will remain high, and the Arduino will not register the button press.
Flash Code Into the Aruino
Open the Project in Arduino IDE:
Launch the Arduino IDE on your computer.
Go to File > Open, navigate to where you saved quadstick_controller.ino, and open it. If the IDE asks to create a matching folder for the sketch, click OK.
Connect the Arduino:
Plug the Micro-USB end of your cable into the Arduino Leonardo.
Plug the other end into an open USB port on your computer. You should see the hardware's onboard power LED light up immediately.
Configure the Software Settings:
Select the Board: In the top menu, go to Tools > Board > Arduino AVR Boards and select Arduino Leonardo.
Select the Port: Go to Tools > Port and select the COM port that has "(Arduino Leonardo)" listed next to it. (Note: If the port option is greyed out, double-check that your USB cable supports data transfer).
Verify the Code:
Click the Verify button in the top-left corner (the checkmark icon).
This compiles the code and checks for any syntax errors. Wait until the status bar at the bottom reads "Done compiling."
Upload the Code:
Click the Upload button right next to the verify button (the right-pointing arrow icon).
The status bar will show "Uploading..." and you will see the TX/RX indicator LEDs on the Arduino board flash rapidly.
Once finished, the status bar will read "Done uploading."
Confirm Successful Boot:
Look at your custom status LEDs. The Power LED (connected to Pin 10) should now turn on and stay solid.
Move the joystick or press a button; the Activity LED (connected to Pin 11) should blink dynamically, indicating the code is running and actively processing your inputs.
Downloads
Testing & Troubleshooting
1. The Initial Power Test
Before interacting with any software, observe the physical status LEDs on the controller housing:
- Power LED (Pin 10): Should turn on immediately when the USB cable is connected and stay completely solid.
- Activity LED (Pin 11): Should remain off when the controller is idle, but flash instantly whenever you trigger an input (moving the stick, pressing a switch, or breaking the IR beams).
2. Input Verification Matrix
Open a blank text document (like Notepad or TextEdit) on your computer to test the keyboard emulation safely. Trigger each input and verify the corresponding action:
Physical ActionExpected Computer Response
Press the Tactile Push Button
Type the letter 'w' continuously while held down
Activate the Sip-and-Puff Switch
Type the letter 's' continuously while active
Pass your hand in front of the Left IR Sensor
Type the letter 'a' continuously while blocked
Pass your hand in front of the Right IR Sensor
Type the letter 'd' continuously while blocked
Push the Analog Joystick
Move the mouse cursor smoothly across the screen
Press downward on the Joystick Shaft
Trigger the Left Shift modifier key
Click the Mechanical Microswitch
Trigger a standard Mouse Left Click
3. Troubleshooting Common Issues
The Power LED is off, and the Arduino isn't recognized by the computer.
- The Cause: A short circuit on your breadboard rails, or a faulty USB cable.
- The Fix: Unplug the USB cable immediately. Check your breadboard to make sure a raw wire from the 5V power rail isn't accidentally bridging into a Ground (GND) pin or row. Also, ensure your USB cable is rated for data transfer, not just power charging.
An IR sensor isn't registering, or it stays "stuck" acting like the key is always pressed.
- The Cause: The sensor's sensitivity threshold is misaligned, or the 3D-printed housing wall is blocking its beam path.
- The Fix: Look closely at the back of the IR sensor module. Use a small screwdriver to gently turn the onboard potentiometer dial until the onboard indicator LED turns off when nothing is in front of the sensor, and turns on only when your hand approaches it.
A button or switch does absolutely nothing when pressed.
- The Cause: Missing ground path or loose jumper wire.
- The Fix: Because the code uses INPUT_PULLUP, the switch must cleanly connect its digital pin to Ground to register. Check that the common (GND) wire from that specific switch is firmly pressed into the negative (blue) rail of your breadboard.
The mouse drifts across the screen even when I'm not touching the joystick.
- The Cause: The joystick’s physical resting center is resting slightly outside the code's default deadzone configuration.
- The Fix: In your Arduino code, locate the line const int deadzone = 100;. Increase this value slightly (e.g., to 130 or 150) and re-upload the sketch to give your joystick a wider resting center buffer.