Ultrasonic Controller
4 separate imputs
Blink Detecting Glasses
2-10 separate imputs
Hi! We’re Elijah and Nate, inventors with a passion for helping others through technology. We’ve created adaptive controllers to make gaming more accessible for people with physical disabilities. Our goal is to break down barriers and make sure everyone can play, connect, and enjoy. We’re both really into engineering for social good—using our skills to make a real difference in people’s lives. This project is just the beginning, and we’re excited to keep building tools that help others and inspire more inclusive design in tech.
Contact information:
Wiring mini bread board
Bread board row- - - > connect to Arduino 5V pin
Wiring Horizontal/x-axis sensor:
VCC - - - > connect to 5V breadboard row
GND (ground) - - - > connect to Arduino GND
Trig - - - > connect to Arduino digital pin 2
Echo - - - > connect to Arduino digital pin 3
Wiring Vertical/y-axis sensor:
VCC - - - > connect to 5V breadboard row
GND (ground) - - - > connect to Arduino GND
Trig - - - > connect to Arduino digital pin 4
Echo - - - > connect to Arduino digital pin 5
The sensor attaches to digital pins 2 and 3 is the horizontal/x-axis sensor. The sensor attached to digital pins 4 and 5 is the vertical/y-axis sensor.
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.
Setting up the HUB:
Simply place the wired arduino leonardo within the 3D printed hub shell, and place the mini breadboard on top. Then, cover it with the top of the 3D printed shell, making sure the holes on either side line up.
Once everything is in place, feel free to heat-shrink/ tie all of the wires together for extra tidiness
Loading Code Onto Arduino Leonardo:
Copy the code and paste it into a sketch via the Arduino IDE app.
Plug the Arduino Leonardo into your computer and run the code.
Important Notes!:
If the sensors are moving whilst picking up readings that are within the designated deadzone, it is most likely an issue with the individual sonar sensor. To fix, simply adjust the deadzones by going to lines 10-18 within the code.
Code for the Ultrasonic controller:
#include <Keyboard.h>
#include <Mouse.h>
// Sensor pins
const int trigPin1 = 2, echoPin1 = 3; // Left-Right sensor
const int trigPin2 = 4, echoPin2 = 5; // Up-Down sensor
// Fixed Deadzone values as per user request
// Up-Down Sensor: Moves DOWN below 2.3, UP above 4.6
const float deadzoneMinUD = 2.3;
const float deadzoneMaxUD = 4.6;
// Left-Right Sensor: Moves RIGHT below 2.3, LEFT above 4.6
const float deadzoneMinLR = 2.3;
const float deadzoneMaxLR = 4.6;
const float maxRange = 6.05; // Maximum effective range for the sensors in inches, as requested
const int moveSpeed = 10; // Constant mouse movement speed (binary)
void setup() {
Serial.begin(9600); // Initialize serial communication for debugging
Keyboard.begin(); // Initialize Keyboard library
Mouse.begin(); // Initialize Mouse library
// Set pin modes for ultrasonic sensors
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
Serial.println("Ultrasonic Mouse Initialized with Fixed Deadzones.");
Serial.print("LR Deadzone: "); Serial.print(deadzoneMinLR, 2); Serial.print(" - "); Serial.println(deadzoneMaxLR, 2);
Serial.print("UD Deadzone: "); Serial.print(deadzoneMinUD, 2); Serial.print(" - "); Serial.println(deadzoneMaxUD, 2);
Serial.print("Max Detection Range: "); Serial.println(maxRange, 2);
Serial.println("--------------------------------------------------");
}
void loop() {
// Measure distances from both sensors
float distanceLR = measureDistance(trigPin1, echoPin1);
float distanceUD = measureDistance(trigPin2, echoPin2);
// Print current sensor readings and deadzones for debugging
Serial.print("UD_Reading: "); Serial.print(distanceUD, 2);
Serial.print(" | UD_MinDZ: "); Serial.print(deadzoneMinUD, 2);
Serial.print(" | UD_MaxDZ: "); Serial.print(deadzoneMaxUD, 2);
Serial.println(); // Newline for cleaner output
int dx = 0; // Change in X-coordinate for mouse movement
int dy = 0; // Change in Y-coordinate for mouse movement
// === Up-Down Binary Movement Logic ===
// Moves DOWN when detecting anything below 2.3
if (distanceUD != -1 && distanceUD < deadzoneMinUD) {
dy = moveSpeed; // Positive dy for down movement
Serial.println("UD Action: Triggered DOWN");
}
// Moves UP when detecting anything above 4.6
else if (distanceUD != -1 && distanceUD > deadzoneMaxUD) {
dy = -moveSpeed; // Negative dy for up movement
Serial.println("UD Action: Triggered UP");
} else {
// If distanceUD is -1 (out of range/no pulse) or within the deadzone
Serial.println("UD Action: No Movement (Within Deadzone or Out of Range)");
}
// === Left-Right Binary Movement Logic ===
// Moves RIGHT when detecting anything below 2.3
if (distanceLR != -1 && distanceLR < deadzoneMinLR) {
dx = moveSpeed; // Positive dx for right movement
Serial.println("LR Action: Triggered RIGHT");
}
// Moves LEFT when detecting anything above 4.6
else if (distanceLR != -1 && distanceLR > deadzoneMaxLR) {
dx = -moveSpeed; // Negative dx for left movement
Serial.println("LR Action: Triggered LEFT");
} else {
// If distanceLR is -1 (out of range/no pulse) or within the deadzone
Serial.println("LR Action: No Movement (Within Deadzone or Out of Range)");
}
// Apply combined mouse movement if there's any change
if (dx != 0 || dy != 0) {
Mouse.move(dx, dy, 0); // Move the mouse by dx and dy
Serial.print("Mouse Moved: dx="); Serial.print(dx); Serial.print(", dy="); Serial.println(dy);
} else {
Serial.println("Mouse Not Moved.");
}
Serial.println("--------------------------------------------------"); // Separator for each loop iteration
delay(20); // Small delay for basic smoothing and to prevent excessive CPU usage
}
// === Measure Distance Function ===
// Measures distance using an ultrasonic sensor
float measureDistance(int trigPin, int echoPin) {
// Clear the trigPin by setting it LOW for 2 microseconds
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Set the trigPin HIGH for 10 microseconds to send a pulse
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
// Set the trigPin LOW to stop the pulse
digitalWrite(trigPin, LOW);
// Measure the duration of the pulse on the echoPin
// Timeout of 30000 microseconds (30 ms) to prevent infinite waiting
long duration = pulseIn(echoPin, HIGH, 30000);
// Convert the duration to distance in inches
// Speed of sound in air is approximately 343 meters/second (at 20C).
// This translates to about 0.0135 inches per microsecond for the sound's round trip.
// The 'duration' is the round trip time, so we divide by 2 for the one-way distance.
float distance = duration * 0.0135 / 2.0; // Adjusted constant for inches
// Return -1 if no pulse was detected (duration is 0)
// Or if distance exceeds the specified maxRange
if (duration == 0 || distance > maxRange) {
return -1; // Indicate an invalid or out-of-range reading
}
return distance;
}
Materials
The 3D printed pieces + Wired Sensors
CAD
Ultrasonic CAD here
Everything is printable, simply take all the pieces and put them together, plaing the ultrasonic sensors in the designated positions!
Materials
insert
Code
insert
[insert demonstration video]