Dual Stepper Differential Bevel Gear Mechanism
Print Profile(1)

Description
This project is a compact, fully 3D-printable dual-stepper differential gear system designed to be controlled by a microcontroller.
The mechanism uses two 28BYJ-48 stepper motor units mounted on a shared axis, driving a central bevel gear assembly. By controlling the motors independently, you can precisely manipulate the output motion.
🎮 Microcontroller Control (ESP32 Example)
This system is designed to be paired with a microcontroller such as an ESP32 DevKit V1, using a joystick or other input device.
With simple control logic:
- Push joystick forward → both motors move together
- Push left/right → motors rotate in opposite directions
- Diagonal movement → blended motion
This creates a smooth and intuitive control system ideal for interactive projects.
⚙️ How It Works
The mechanism acts as a mechanical mixer:
- 🔁 Same motor direction → rotational output
- 🔄 Opposite directions → differential motion
- 🎯 Balanced input → stable center (no movement)
This makes it useful for applications where controlled rotation without translation is required.
🧱 Design Features
- Fully 3D-printable
- Compact and modular layout
- Smooth bevel gear interaction
- Designed for common hobby electronics
- Easy integration with microcontrollers (ESP32 / Arduino)
🚀 Use Cases
- Turret or pan control systems
- Robotics joints
- Camera mounts
- Interactive displays
STEM / engineering demonstrations
Code can easily be customized in your favourite AI model.
🔌 ESP32 Pin Mapping (D# style)
🕹️ Joystick
| Function | ESP32 GPIO | Board Label |
|---|---|---|
| X-axis | GPIO 34 | D34 |
| Y-axis | GPIO 35 | D35 |
| VCC | 3.3V | 3V3 |
| GND | GND | GND |
⚙️ Stepper Motor A (Left)
| ESP32 GPIO | Board Label |
|---|---|---|
| IN1 | GPIO 14 | D14 |
| IN2 | GPIO 27 | D27 |
| IN3 | GPIO 26 | D26 |
| IN4 | GPIO 25 | D25 |
⚙️ Stepper Motor B (Right)
| ULN2003 IN | ESP32 GPIO | Board Label |
|---|---|---|
| IN1 | GPIO 33 | D33 |
| IN2 | GPIO 32 | D32 |
| IN3 | GPIO 18 | D18 |
| IN4 | GPIO 19 | D19 |
🔋 Power
| Component | Connection |
|---|---|
| ESP32 | USB or 5V pin |
| ULN2003 boards | 5V external supply recommended |
| All GNDs | MUST be connected together |
⚠️ Important Notes
GPIO 34 & 35 are input-only → perfect for joystick
Do NOT power motors from ESP32 5V pin
Use external 5V for stepper drivers
Common ground is required
🧠 Quick Summary (for users)
D34 / D35 → joystick
D14–27 → motor A
D33–19 → motor B
Here is the sample code to copy and paste in Arduino IDE app:
#include <AccelStepper.h>
// ---- Motor pins ----
#define M1_IN1 14
#define M1_IN2 27
#define M1_IN3 26
#define M1_IN4 25
#define M2_IN1 33
#define M2_IN2 32
#define M2_IN3 18
#define M2_IN4 19
// ---- Joystick ----
#define JOY_X 34
#define JOY_Y 35
AccelStepper stepperA(AccelStepper::HALF4WIRE, M1_IN1, M1_IN3, M1_IN2, M1_IN4);
AccelStepper stepperB(AccelStepper::HALF4WIRE, M2_IN1, M2_IN3, M2_IN2, M2_IN4);
// ---- tuning ----
float maxSpeed = 800;
float smoothing = 0.15;
// deadzones tuned for ESP32 stability
float inputDeadzone = 0.20;
float zeroLock = 0.18;
// smoothing state
float smoothX = 0;
float smoothY = 0;
// ---------------- FILTERED ADC READ ----------------
float readFiltered(int pin) {
long sum = 0;
for (int i = 0; i < 5; i++) {
sum += analogRead(pin);
}
return sum / 5.0;
}
// ---------------- NORMALIZED AXIS ----------------
float readAxis(int pin) {
float val = readFiltered(pin);
// center around ~2048
val = (val - 2048.0) / 2048.0;
// input deadzone
if (abs(val) < inputDeadzone) return 0;
return val;
}
void setup() {
analogReadResolution(12);
stepperA.setMaxSpeed(maxSpeed);
stepperB.setMaxSpeed(maxSpeed);
}
void loop() {
// ---- read joystick ----
float x = readAxis(JOY_X);
float y = readAxis(JOY_Y);
// ---- smoothing ----
smoothX += smoothing * (x - smoothX);
smoothY += smoothing * (y - smoothY);
// ---- mix ----
float motorA = smoothY + smoothX;
float motorB = smoothY - smoothX;
// ---- TRUE ZERO LOCK (prevents drift) ----
if (abs(smoothX) < zeroLock && abs(smoothY) < zeroLock) {
motorA = 0;
motorB = 0;
}
// ---- normalize ----
float maxVal = max(abs(motorA), abs(motorB));
if (maxVal > 1.0) {
motorA /= maxVal;
motorB /= maxVal;
}
// ---- drive ----
stepperA.setSpeed(motorA * maxSpeed);
stepperB.setSpeed(motorB * maxSpeed);
stepperA.runSpeed();
stepperB.runSpeed();
}
License
You shall not share, sub-license, sell, rent, host, transfer, or distribute in any way the digital or 3D printed versions of this object, nor any other derivative work of this object in its digital or physical format (including - but not limited to - remixes of this object, and hosting on other digital platforms). The objects may not be used without permission in any way whatsoever in which you charge money, or collect fees.








Comment & Rating (0)