6 Seperate Buttons
2 Joysticks + A Sip-N-Puff
Hi! I’m Leighton Petty — a high school student, martial arts instructor, and aspiring engineer with a love for building things that make a difference. Ever since I was a kid, I’ve been curious about how things work and passionate about creating solutions to real-world problems. Engineering gives me a way to mix creativity with hands-on skills, and I especially enjoy making products that help people in my community. This is a product I designed and built myself, and I’m excited to finally share it. I also enjoy learning languages and speak English, French, Korean, and basic Mandarin.
Contact information: leightyp@gmail.com
Hand/ Foot Controller Demonstration Video [Link]
Mask Demonstration Video [Link]
Click here to access remapping interface.
Mask Remap Video [Link]
You can remap the sip-and-puff and joystick key outputs by typing simple commands into the Serial Monitor. Just open the Serial Monitor, type in the function you want to change (like sip, puff, joystick_up, joystick_down, joystick_left, or joystick_right), followed by an equals sign and the key you want it to send. For example, typing sip=j will make the sip action type the letter “j” instead of the default. These changes are saved to the device’s memory, so they’ll still work even after unplugging or resetting the board.
Button Remap Video [Link]
[Picture With All the Buttons Labeled 1-6] Make sure to Type in button__=__ like button5=g when remapping.
Materials
Arduino Leonardo [2x - (3x if wanting more controllers)] Comes with Chord
Alligator Clips [12x] More needed if you want to make a bottom row for a different controller.
Code
CAD
Wiring the tactile push buttons:
Left button:
Connect one leg of the button to digital pin 2 on the Arduino
Connect the other leg of the button to GND (ground)
Right button:
Connect one leg of the button to digital pin 3 on the Arduino.
Connect the other leg of the button to GND (ground)
Wiring the MPX5010DP Pressure Sensor
The MPX5010DP is a pressure sensor that outputs an analog voltage corresponding to pressure changes (like blowing or sipping).
The MPX5010DP has 6 pins, but we only use 3
VCC (+5V Supply) - - - > connect to Arduino 5V pin
GND (ground) - - - > connect to Arduino GND
Vout (Analog Out) - - - > connect to Arduino A0 (analog pin 0)
For the second diagram, the sensor on the left is supposed to represent the 3 pins used on the pressure sensor, and the LED lights to the right reflect the 5 pins used on each joystick.
[For Pedals]
Connect one leg of Button [A] to Arduino pin D2, and connect the other leg to GND.
Connect one leg of Button [B] to Arduino pin D3, and connect the other leg to GND.
Connect one leg of Button [C] to Arduino pin D4, and connect the other leg to GND.
Connect one leg of Button [D] to Arduino pin D5, and connect the otherz leg to GND.
Connect one leg of Button [E] to Arduino pin D6, and connect the other leg to GND.
Connect one leg of Button [F] to Arduino pin D7, and connect the other leg to GND.
Vout → A2
Sends the pressure signal to the Arduino using analogRead(A2).
GND → GND
Connects to Arduino ground (shared ground).
Vcc (or +5V) → 5V
Powers the sensor using the Arduino’s 5V pin.
GND → GND
Connects to Arduino ground.
+5V / VCC → 5V
Provides power to the joystick.
VRx (X-axis) → A0
Controls left-right movement.
VRy (Y-axis) → A1
Controls up-down movement.
SW (Button) → D2
Registers the push button click.
X-axis → A3
Second joystick’s left-right control.
Y-axis → A4
Second joystick’s up-down control.
Button → D3
Second joystick’s button input.
[Can Change Buttons Using Remapping]
To ensure you can sit upright comfortably while wearing the mask, extend the sensor and joystick wires by connecting at least three wires together per line (use jumper wires or standard wire).
Strip a small section of insulation off each wire end, then twist and connect the matching wires (e.g., signal to signal, ground to ground, etc.).
For a stronger and safer connection, slide a piece of heat shrink tubing over one end before twisting the wires together.
After connecting, position the heat shrink over the joint and seal it by applying heat using a blow dryer or heat gun until it tightens snugly around the connection.
Repeat for each wire you are extending.
Make sure all extended wires are properly insulated and not under tension during use.
Start by cutting off one end of each alligator clip wire (you’ll need a total of 12 alligator clips).
Take the exposed wire from the alligator clip and twist it together with the exposed end of a cut male-to-male or female-to-male jumper wire, depending on your setup.
Repeat this process until you’ve created 6 connected pairs of wires (2 alligator clips joined by one jumper connection).
You can secure each connection with either heat shrink tubing (recommended for durability and safety) or rubber bands (for a quick temporary hold).
Once all 6 pairs are made and secured, thread each pair through the 6 designated holes in the pedal base or board.
Make sure the wires are neatly threaded and not under stress or twisted too tightly.
Cut three Velcro strips, each measuring 2 inches long.
Apply hot glue to the back of one Velcro strip.
Press the strip firmly onto the bottom floor of the 3D printed hub and hold for a few seconds until set.
Repeat this process to attach the second Velcro strip to the middle floor of the hub.
Repeat again to attach the third Velcro strip to the top floor of the hub.
Make sure all three Velcro strips are securely glued and evenly aligned on each level.
Cut a small strip of Velcro long enough to wrap around the body of each Arduino board.
Wrap the Velcro around the Arduino, making sure it’s snug but not too tight to damage any components.
Press the Velcro ends together to secure it in place.
Repeat this step for each Arduino you are using.
The number of Arduinos needed will depend on how many add-ons or modules your setup requires.
Once wrapped, the Arduino(s) can be easily attached to the Velcro strips on the 3D printed hub.
[For the Six Buttons/ Pedals]:
#include <Keyboard.h>
#include <EEPROM.h>
// Define pins for 6 buttons
const int buttonPins[6] = {2, 3, 4, 5, 6, 7};
char keyOutputs[6]; // Loaded from EEPROM
bool lastState[6] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
void setup() {
Serial.begin(9600);
for (int i = 0; i < 6; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
keyOutputs[i] = EEPROM.read(i);
if (keyOutputs[i] == 0xFF || keyOutputs[i] == 0) {
keyOutputs[i] = 'a' + i; // default if EEPROM is blank
}
}
delay(1000); // Small delay before starting USB communication
Keyboard.begin();
}
void loop() {
// Handle button presses
for (int i = 0; i < 6; i++) {
bool currentState = digitalRead(buttonPins[i]);
if (currentState == LOW && lastState[i] == HIGH) {
Keyboard.write(keyOutputs[i]);
delay(200); // debounce
}
lastState[i] = currentState;
}
// Handle serial remapping
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
input.toLowerCase();
if (input.startsWith("button") && input.indexOf('=') > 0) {
int btnNum = input.substring(6, input.indexOf('=')).toInt(); // e.g. "1" in "button1=x"
char newKey = input.charAt(input.indexOf('=') + 1);
if (btnNum >= 1 && btnNum <= 6) {
keyOutputs[btnNum - 1] = newKey;
EEPROM.write(btnNum - 1, newKey);
Serial.print("Mapped button");
Serial.print(btnNum);
Serial.print(" to '");
Serial.print(newKey);
Serial.println("'");
} else {
Serial.println("Invalid button number (must be 1-6)");
}
}
}
}
[For the Mask/ Headset]:
#include <Keyboard.h>
#include <Mouse.h>
#include <EEPROM.h>
// === SIP & PUFF SETTINGS ===
const int pressurePin = A2;
const float VCC = 5.0;
const float sensitivity = 0.009;
float baselineVoltage = 0.0;
float suctionThreshold_kPa = -0.5;
float blowThreshold_kPa = 10.5;
unsigned long lastPressureTime = 0;
const unsigned long debounceDelay = 300;
// === MOUSE JOYSTICK SETTINGS ===
const int xPin1 = A0;
const int yPin1 = A1;
const int buttonPin1 = 2;
const int threshold = 40;
const int maxMove = 15;
// === KEYBOARD JOYSTICK SETTINGS ===
const int xPin2 = A3;
const int yPin2 = A4;
const int buttonPin2 = 3;
bool keyW = false, keyA = false, keyS = false, keyD = false, keyZ = false;
// === MAPPABLE KEYS ===
char mappedKeys[6]; // EEPROM: 0=sip, 1=puff, 2=up, 3=down, 4=left, 5=right
const char defaultKeys[6] = {'e', 'g', 'w', 's', 'd', 'a'};
String labels[6] = {"sip", "puff", "joystick_up", "joystick_down", "joystick_right", "joystick_left"};
void loadMappedKeys() {
for (int i = 0; i < 6; i++) {
char val = EEPROM.read(i);
if (val < 32 || val > 126) val = defaultKeys[i]; // fallback to default
mappedKeys[i] = val;
}
}
void checkSerialRemap() {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
int sep = input.indexOf('=');
if (sep > 0) {
String name = input.substring(0, sep);
char val = input.charAt(sep + 1);
for (int i = 0; i < 6; i++) {
if (name.equalsIgnoreCase(labels[i])) {
mappedKeys[i] = val;
EEPROM.write(i, val);
Serial.print("Mapped ");
Serial.print(name);
Serial.print(" to '");
Serial.print(val);
Serial.println("'");
}
}
}
}
}
void setup() {
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
pinMode(pressurePin, INPUT);
Keyboard.begin();
Mouse.begin();
Serial.begin(9600);
loadMappedKeys();
// Baseline calibration for pressure
float total = 0;
for (int i = 0; i < 10; i++) {
total += analogRead(pressurePin) * (VCC / 1023.0);
delay(10);
}
baselineVoltage = total / 10;
Serial.print("Baseline Voltage: ");
Serial.println(baselineVoltage, 3);
}
void loop() {
checkSerialRemap();
// === MOUSE JOYSTICK LOGIC ===
int xVal1 = analogRead(xPin1);
int yVal1 = analogRead(yPin1);
int btn1 = digitalRead(buttonPin1);
int xMove = 0;
int yMove = 0;
if (abs(xVal1 - 512) > threshold) {
xMove = map(xVal1, 0, 1023, -maxMove, maxMove);
}
if (abs(yVal1 - 512) > threshold) {
yMove = map(yVal1, 0, 1023, -maxMove, maxMove);
}
if (xMove != 0 || yMove != 0) {
Mouse.move(xMove, yMove);
}
if (btn1 == LOW) {
Mouse.press(MOUSE_LEFT);
} else {
Mouse.release(MOUSE_LEFT);
}
// === PRESSURE SENSOR LOGIC ===
float sensorVoltage = 0;
for (int i = 0; i < 5; i++) {
sensorVoltage += analogRead(pressurePin) * (VCC / 1023.0);
delay(5);
}
sensorVoltage /= 5;
float pressure_kPa = (sensorVoltage - baselineVoltage) / sensitivity;
Serial.print("Pressure (kPa): ");
Serial.println(pressure_kPa, 2);
unsigned long now = millis();
if (pressure_kPa > blowThreshold_kPa && now - lastPressureTime > debounceDelay) {
Keyboard.write(mappedKeys[1]); // puff
lastPressureTime = now;
} else if (pressure_kPa < suctionThreshold_kPa && now - lastPressureTime > debounceDelay) {
Keyboard.write(mappedKeys[0]); // sip
lastPressureTime = now;
}
// === KEYBOARD JOYSTICK LOGIC ===
int xVal2 = analogRead(xPin2);
int yVal2 = analogRead(yPin2);
int btn2 = digitalRead(buttonPin2);
// UP
if (yVal2 < 512 - threshold) {
if (!keyW) { Keyboard.press(mappedKeys[2]); keyW = true; }
} else {
if (keyW) { Keyboard.release(mappedKeys[2]); keyW = false; }
}
// DOWN
if (yVal2 > 512 + threshold) {
if (!keyS) { Keyboard.press(mappedKeys[3]); keyS = true; }
} else {
if (keyS) { Keyboard.release(mappedKeys[3]); keyS = false; }
}
// RIGHT
if (xVal2 < 512 - threshold) {
if (!keyD) { Keyboard.press(mappedKeys[4]); keyD = true; }
} else {
if (keyD) { Keyboard.release(mappedKeys[4]); keyD = false; }
}
// LEFT
if (xVal2 > 512 + threshold) {
if (!keyA) { Keyboard.press(mappedKeys[5]); keyA = true; }
} else {
if (keyA) { Keyboard.release(mappedKeys[5]); keyA = false; }
}
// Click
if (btn2 == LOW) {
if (!keyZ) { Keyboard.press('z'); keyZ = true; }
} else {
if (keyZ) { Keyboard.release('z'); keyZ = false; }
}
delay(10);
}
Materials
CAD
Cut 24 strips of Velcro, each about 1 inch long by 1 cm wide.
Plan to make 6 rectangles, using 4 Velcro strips per rectangle.
Leave 1 inch of space between each Velcro strip.
Put a small dot of hot glue on the back of each Velcro piece.
Press the Velcro onto the wood board, holding it down for a few seconds so it sticks.
Repeat for all pieces until all 6 rectangles are glued down and spaced out evenly.
How to Build the Button Base (Repeat x6):
Print or cut a rectangular block measuring 1 inch by 0.5 inch.
Cut a small piece of foam tape to fit the front half of the block.
Hot glue the foam tape onto the front half of the block along the 1-inch side.
Peel off the top seal of the foam tape to expose the adhesive surface.
Firmly attach the button onto the foam tape, ensuring the legs are pointing out from both 0.5-inch sides of the block.
Find or cut a spring to a height of approximately 0.6 inches.
Hot glue the spring to the back of the block, opposite the foam tape side.
Repeat these steps six times to create six individual button bases.
Tip - Don't be afraid to add a lot of hot glue. We want to make sure the foam tape sticks firmly to the base.
How to Build the Pedals (Repeat x6):
Print or cut out the pedal base piece.
Cut two Velcro strips the same size as the ones on the wood board (1 inch by 1 cm).
Hot glue one Velcro strip to each bottom corner of the pedal base.
Take one button base made in the previous step.
Hot glue the top of the spring (attached to the button base) to the underside of the pedal, positioning it about half an inch away from the back edge.
Hold the button base firmly in place for several seconds until the glue fully cools and sets.
Optionally, label the top of the pedal with a letter or number to indicate which key it represents.
Repeat this process six times to create six complete and functioning pedals.
Final Assembly: Attaching Pedals and Connecting Clips
Place each pedal onto the wood board by pressing the Velcro on the pedal base firmly onto the matching Velcro strips on the board.
Repeat this step until all six pedals are securely attached to the board.
Take two alligator clips per button (total of 12 clips).
Connect the first alligator clip to one back corner leg of the button.
Connect the second clip to the opposite front corner leg of the same button.
Make sure each alligator clip is only touching one metal leg of the button to avoid short circuits.
Repeat this process for all six buttons, ensuring all connections are secure and correctly placed.
Double-check that no clips are crossing over or touching multiple legs.
Connect one leg of Button [A] to Arduino pin D2, and connect the other leg to GND.
Connect one leg of Button [B] to Arduino pin D3, and connect the other leg to GND.
Connect one leg of Button [C] to Arduino pin D4, and connect the other leg to GND.
Connect one leg of Button [D] to Arduino pin D5, and connect the otherz leg to GND.
Connect one leg of Button [E] to Arduino pin D6, and connect the other leg to GND.
Connect one leg of Button [F] to Arduino pin D7, and connect the other leg to GND.
[Can Change Buttons Using Remapping]
Materials
CAD
Cut two pieces of string, measuring each one so it’s long enough to hold the mask securely on your face.
Take the first string and hot glue both ends into the side holes of the 3D printed mask.
Make sure the string forms a loop that fits comfortably around your ear or head.
Repeat the process with the second string on the other side of the mask.
Once finished, you should have two secure string loops—one on each side—for wearing the mask.
Cut a piece of Velcro about 1 to 1.5 inches long.
Hot glue the Velcro onto the back of the bottom chunk of the mask.
Repeat this process by gluing a second piece of Velcro onto the front flap of the mask.
Tip: When attaching Velcro to the front flap, cut it to match the curve of the top edge so it lays flat and looks clean.
If you’re only using one joystick, choose only one of the two positions (either the bottom chunk or the front flap) for Velcro placement.
Make sure the Velcro is secure and fully cooled before attaching the joystick.
Cut a thin strip of Velcro and wrap it around both sides of each joystick.
If you're only using one joystick, only wrap one.
Make sure the Velcro is snug but does not interfere with the joystick’s movement.
Press the Velcro in place to ensure a strong hold.
Take the sip-and-puff holder and apply hot glue to its base.
Carefully position the holder in the center of the mask, between the two Velcro areas.
Hold the sip-and-puff holder upright and steady while the glue dries completely to ensure proper alignment.
Take the pressure sensor and locate the lower hole (with the sensor’s lettering facing up).
Attach one end of the tube securely into the lower hole.
Position the other end of the tube into the sip-and-puff holder on the mask.
Use hot glue to secure the tube into the holder.
Make sure there is at least 2 inches of tubing extending outward to the side of the joysticks, allowing space for comfortable use.
Hold the tube in place as the glue dries to ensure it stays properly positioned and upright.
Follow the wiring instructions to properly connect all joystick(s) and pressure sensors to the correct pins on your Arduino(s).
Double-check each connection for power (VCC), ground (GND), and signal lines, ensuring they are matched to the correct pins as outlined in your circuit diagram.
If any wires are too short to reach their destination, use jumper wires or solder extensions to lengthen them as needed.
Make sure all wire connections are secure and insulated to prevent shorts or disconnections during use.
Once all components are wired, do a final check before powering on to ensure everything is firmly in place and correctly connected.
Good Luck! Don't Hesitate to Reach Out if Your Are Struggling!