G19: TremorSync: Active Stabilization Handle - shalan/CSCE4301-WiKi GitHub Wiki
| Name | GitHub UID |
|---|---|
| Andrew Antoine Ishak | 900211633 |
TremorSync is an active, motorized 2-axis stabilization handle designed as an accessible assistive device for individuals suffering from motor-control disorders such as Parkinson's Disease and Essential Tremors. These conditions cause involuntary hand shaking (typically between 4Hz and 8Hz), stripping individuals of their independence in basic daily tasks like eating or writing. TremorSync utilizes a real-time hardware-software co-design approach: an onboard IMU detects the exact angle and velocity of the tremor, and an ESP32 microcontroller calculates the inverse kinematics using a PID control loop. High-speed micro-servos then physically counter-rotate the attached utensil, maintaining a level 0-degree plane despite the user's hand movements.
Minimum Viable Product (MVP):
- Successfully stabilize a single axis (Pitch) against a simulated human tremor on a breadboard.
- Upgrade to a fully untethered, battery-powered 2-axis (Pitch and Roll) handheld prototype.
- Isolate electrical motor noise from the sensor logic lines to prevent microcontroller brownouts.
Stretch Goals:
- Implement an SD-Card data logger to record raw tremor frequency data for medical diagnostic tracking.
- Integrate a TTP223 Capacitive Touch sensor in the grip to automatically "wake up" the device only when held.
=======================================================================
TREMORSYNC: SYSTEM ARCHITECTURE
=======================================================================
INPUTS PROCESSING OUTPUTS
------ ---------- -------
[MPU6050 Sensor] ===(I2C)==> [ ] ==(PWM)==> [Pitch Servo Motor]
(Detects Tremor) [ ESP32 ] (Corrects Y-Axis)
[ MICRO ]
[ CONTROL ]
[Potentiometer] ===(ADC)==> [ ] ==(PWM)==> [Roll Servo Motor]
(Adjusts Tuning) [ ] (Corrects X-Axis)
=======================================================================
POWER DISTRIBUTION
=======================================================================
+---> (5V) Powers Servos Only
| (Isolates motor noise)
[3.7V LiPo Battery] -> [5V Boost] -----+
|
+---> (3.3V) Powers ESP32
& MPU6050 Sensor
- Sensing Subsystem: The MPU6050 reads 6-DOF data (accelerometer and gyroscope) and sends it to the ESP32 via the I2C bus.
- Control Subsystem: The ESP32 acts as the system brain, executing digital filters and PID math at a strict 100Hz loop via hardware timer interrupts.
- Actuation Subsystem: Two orthogonally mounted servos receive high-frequency PWM signals from the ESP32 to mechanically adjust the gimbal.
- Power Subsystem: A 3.7V LiPo battery is stepped up to 5V to handle the high current draw of stalled/twitching servos, while protecting the 3.3V logic circuit.
- ESP32 Development Board: Chosen over the Arduino Uno/Nano due to its superior clock speed (up to 240MHz), which is critical for executing floating-point math in the real-time PID loop without phase lag.
- MPU6050 IMU: Industry-standard, low-latency 6-DOF sensor.
- MG90S Micro Servos: Metal-gear servos are explicitly selected over standard SG90 plastic servos. Plastic gears would instantly strip under the aggressive twitching required to fight 4-8Hz mechanical tremors.
| Component | Part Number | Qty | Est. Cost | Purpose |
|---|---|---|---|---|
| Microcontroller | ESP32-WROOM-32 | 1 | EGP 350 | Core processing & control loop |
| IMU Sensor | MPU6050 | 1 | EGP 150 | Motion tracking via I2C |
| Micro Servos | MG90S (Metal Gear) | 2 | EGP 300 | 2-axis gimbal actuation |
| Battery | 3.7V 500mAh LiPo | 1 | EGP 150 | Untethered power supply |
| Charger | TP4056 Module | 1 | EGP 40 | USB-C safe charging |
| Step-Up Converter | MT3608 5V Boost | 1 | EGP 50 | Servo power isolation |
The power system is physically split to isolate motor noise.
- Logic Draw (3.3V): ESP32 (~80mA) + MPU6050 (~4mA) = ~84mA continuous.
- Actuator Draw (5V): MG90S servos draw ~250mA while moving, but can spike up to ~750mA+ each when stalled or rapidly reversing direction. Total peak draw: ~1.5A. The MT3608 5V Boost converter is rated for 2A, providing a safe 25% overhead.
- System Init: Boot ESP32 -> Initialize I2C Bus -> Check Battery Voltage.
- Calibration Phase (3s): Wait for user to place the handle flat on a table. Read MPU6050 to establish the baseline 0-degree mechanical offset.
-
100Hz Control Loop:
- Fetch raw X/Y/Z data.
- Apply Complementary Filter.
- Run PID Algorithm.
- Output updated PWM to Servos.
- Complementary Filter: Fuses the gyroscope data (which drifts over time) with the accelerometer data (which is susceptible to mechanical vibration from the servos). This software filter is required to get a clean angle reading.
- PID Control Loop: Calculates the precise angular error from level zero, and outputs a smoothed, non-jerky PWM corrective signal.
- Platform: PlatformIO IDE / Arduino IDE.
- Language: C++.
-
Libraries:
<Wire.h>for I2C, standard ESP32 Servo libraries.
To isolate variables, every hardware component was tested individually before integration:
-
I2C Sensor Test: Uploaded a basic I2C scanner to the ESP32 to confirm the MPU6050 address (
0x68). Used the Arduino Serial Plotter to verify that the raw accelerometer and gyroscope data responded accurately to physical tilting without freezing. - Servo Sweep Test: Hooked the MG90S servos to external bench power and ran a 0-180 degree sweep loop. This confirmed the servos were functional and helped find the mechanical "center" (90 degrees) before attaching the 3D-printed gimbal parts.
- Filter Calibration: Logged raw sensor data while the device was stationary to calculate the static offset/error. Applied this offset in the code to ensure "flat" perfectly equals 0.00 degrees.
The primary testing metric was "Phase Lag"—measuring the delay between the sensor detecting a movement and the servos counter-acting it.
- Simulated Tremor Test: The handle was clamped to a custom testing jig that oscillated at 5Hz (simulating an Essential Tremor).
-
PID Tuning: * Started with
KiandKdat 0.- Increased
Kp(Proportional) until the servos reacted strongly but started oscillating (overshooting). - Increased
Kd(Derivative) to dampen the overshoot and stop the "jitter." - Added a tiny amount of
Ki(Integral) to correct minor long-term drooping.
- Increased
| Issue Encountered | Diagnosis | Solution Implemented |
|---|---|---|
| ESP32 randomly restarting (Brownouts) | The sudden current spike from the servos rapidly changing direction was causing the 3.7V battery voltage to sag, starving the ESP32 of power. | Completely separated the power rails. Routed the battery through the MT3608 5V Boost Converter exclusively for the servos, and added a 1000µF decoupling capacitor across the servo power lines to absorb spikes. |
| Gimbal drifting over time | Relying solely on the gyroscope caused mathematical integration drift. Relying on the accelerometer caused massive noise from the motor vibrations. | Implemented a Complementary Filter (Angle = 0.98 * (Angle + Gyro * dt) + 0.02 * (Accel)). The heavy weight on the gyro handles quick movements, while the small weight on the accelerometer corrects long-term drift. |
| Servo jitter at rest | The 100Hz PID loop was constantly calculating micro-corrections (e.g., 0.01 degrees) that the physical gears couldn't smoothly execute. | Added a "Deadband" in the code. If the calculated error is less than 0.5 degrees, the ESP32 does not send an updated PWM signal, allowing the motors to rest. |
The final prototype successfully integrates the 2-axis gimbal, control circuitry, and battery into a single, untethered, lightweight 3D-printed handle.
📸 [Insert photo of the fully assembled TremorSync device here] 📸 [Insert photo of the internal wiring/soldering inside the handle here]
- Frequency Response: Successfully cancels out mechanical oscillations up to ~6Hz, covering the average range for Parkinsonian resting tremors (4-6Hz).
- Response Latency: The combined loop execution time (sensor read + math + servo PWM update) averages < 4 milliseconds.
- Battery Life: The 500mAh LiPo battery provides approximately 45 minutes of continuous active stabilization under heavy load.
In this demonstration, a spoon attachment is loaded with water. The user's hand simulates a 5Hz tremor. With the device OFF, the water spills instantly. With the device ON, the water remains stable in the bowl of the spoon.
🎥 [Insert YouTube Link or GIF of the stabilization in action here]
-
C++ Control Code: [Link to your
main.cppor GitHub folder] - 3D Printer STL Files: [Link to your gimbal/handle CAD models]
- [MPU-6050 6-Axis IMU Datasheet (PDF)](https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf)
- [ESP32-WROOM-32 MCU Datasheet (PDF)](https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32_datasheet_en.pdf)
- PID Control Theory: Feedback Control of Dynamic Systems, Franklin et al.
- Sensor Fusion: "A Guide to Using IMU (Accelerometer and Gyroscope Devices) in Embedded Applications."