Portrait of Thavarasa Thilothman

Mechatronics undergraduate

Thavarasa
Thilothman

I build robots that keep themselves upright. Sensor-driven control, ESP32 firmware and hands-on hardware, from a self-balancing unicycle to medical equipment in the field.

Front view of my dual reaction wheel unicycle robot with OLED display and blue reaction wheels

My robot: two reaction wheels on top, a ground wheel below.

ESP32IoT and embedded
PIDBalance control
3Hands-on projects
4 moMedical equipment training

01 Final-year project

Dual Reaction Wheel Unicycle Robot

December 2025 to present · Uva Wellassa University

A self-balancing unicycle that uses two reaction wheels for balance and a ground wheel for recovery, aimed at carrying a payload of up to 500 g.

MPU6050 IMUTilt angle
→
ESP32Balance loop + WiFi tuning page
→
2 × NEMA17Reaction wheels, PD
Nidec 24HGround wheel, PID
  • ESP32 reads an MPU6050 IMU and runs the balance loop in real time.
  • Two NEMA17 steppers on DRV8825 drivers act as reaction wheels with PD control.
  • A Nidec 24H brushless ground wheel runs a PID recovery loop.
  • A WiFi web page on the ESP32 tunes gains, speeds and limits from a phone.
  • OLED display, battery voltage monitoring and a low-battery buzzer.
The unicycle robot on the bench: reaction wheels, ground wheel and live tuning from a phone.

Two-wheel balancing robot

Dec 2024 to Mar 2025

Arduino, MPU-6050, PID control and an L298N motor driver, tuned until it stayed upright on flat surfaces.

Servo motor tester

Dec 2025 to Jan 2026

LabVIEW virtual instrument with several control modes, signal generation and live monitoring.

02 Code

ESP32 firmware (main version)

ESP32, Arduino IDE, C++

This is the main sketch that runs the robot. It reads the MPU6050, balances with the two reaction wheels, runs a PID recovery loop on the ground wheel and serves a WiFi page for tuning. The code has no comments on purpose. The explanation is below. The WiFi name and password in the code are placeholders.

Download .ino

What the code does

  • Sensor reading. Every 4 ms (250 times a second) the ESP32 reads the MPU6050 over I2C. The gyro offset is measured at start-up while the robot is held still, and tiny gyro noise is zeroed.
  • Filtering. A complementary filter mixes 98% gyro and 2% accelerometer into one steady tilt angle. The angle is measured from an upright reference that is calibrated at start, so upright is zero.
  • Balance control. The reaction wheels use a PD controller: Kp 1400 on the tilt error and Kd 55 on the gyro rate. A small extra term (K3) lowers the demand when the wheel is already spinning fast. Past 20 degrees of tilt the code counts it as a fall and stops.
  • Reaction bias. A "Reaction Bias" setting adds a fixed push (a percent of the maximum speed) to the controller output. It is for fixing a robot whose balance point is slightly off.
  • Reaction wheels. The two NEMA17 steppers (DRV8825 drivers) get step pulses from the ESP32 timer. The controller output sets the pulse frequency (1.5 kHz to 12 kHz by default) and the direction. The speed changes on a fast ramp so the wheels react quickly, reversing uses an even faster ramp, and a slower spin-up ramp is used when balancing starts, until the wheels reach their target speed. Past 15 degrees the wheels get an extra recovery push.
  • Ground wheel. The Nidec 24H wheel has a PID loop (Kp 65, Ki 12, Kd 2.5) that starts at 0.8 degrees of tilt and drives the wheel to bring the robot back upright. It limits the integral and ramps the speed. A manual forward and backward control on the web page can take over from it.
  • WiFi tuning page. The ESP32 makes its own WiFi network and serves a page you open on a phone. From it you can start and stop balancing, change the gains, frequencies, ramps, bias, engage angle and buzzer settings, and see live status. The values are saved in the ESP32 memory, so they stay after a restart or a new upload.
  • Display and battery. The OLED shows a start-up splash, then the state (STANDBY or BALANCING), angle, gyro rate, wheel RPM and battery voltage, plus a thumbs-up when balancing starts. To keep the control loop fast, the screen is sent to the display in small chunks between control steps. The battery voltage comes from a voltage divider on pin 34. The code takes the median of 32 readings and smooths it.
  • Buzzer and safety. A buzzer gives a start-up beep, a fast repeating alarm on a fall or emergency stop, and a warning when the battery is low (7.7 V or below). An emergency stop button on a GPIO pin stops everything.

How the tuning page looks

Tuning page on a phone: balance settings and live values
Tuning page on a phone: buzzer, battery and ground wheel controls
Tuning page on a phone: ground wheel PID settings

The robot's WiFi page as it looks on a phone, top to bottom. The numbers shown are example values, not live data.

The code, part by part

Clean screenshots of the main parts of the sketch. Scroll inside each box to see the whole part. The full file is in the Download button above.

1. Libraries and settings
firmware.ino · lines 1-21
Code: Libraries, WiFi and OLED settings
Pulls in the libraries for the MPU6050 sensor, the OLED display and the WiFi server. It also sets up the robot's own WiFi network name and password (placeholders here) and the display settings.
2. Reading the sensor and filtering
firmware.ino · lines 2133-2184
Code: Sensor reading and complementary filter
Reads the MPU6050 gyro and accelerometer, removes the start-up gyro offset and ignores tiny noise. A complementary filter then mixes the gyro and accelerometer into one steady tilt angle.
3. Balance control
firmware.ino · lines 2185-2279
Code: Balance controller
Turns the tilt angle and gyro rate into a demand for the reaction wheels with a PD controller. It also lowers the demand when the wheel is already fast and stops everything if the robot tilts past the fall angle.
4. Reaction wheels
firmware.ino · lines 2419-2528
Code: Reaction wheel control
Drives the two stepper reaction wheels. It ramps the speed up and down smoothly, handles direction changes safely and runs the extra recovery push when the tilt gets large.
5. Ground wheel PID
firmware.ino · lines 2320-2418
Code: Ground wheel PID
Runs the PID loop on the ground wheel. It adds up the tilt error over time, keeps that sum within a limit and uses the result to set the wheel speed that brings the robot back upright.
6. WiFi tuning page
firmware.ino · lines 3441-3530
Code: WiFi tuning page setup
Starts the robot's own WiFi network and registers each web address, such as start, stop and settings. This is what lets a phone change the gains and run the robot from the tuning page.
7. OLED display and battery
firmware.ino · lines 3830-3947
Code: OLED display and battery monitor
Draws the robot state, tilt angle, gyro rate, wheel speed and battery voltage on the small OLED. The battery reading is averaged over many samples so the voltage on screen stays steady.
8. Buzzer
firmware.ino · lines 3948-3970
Code: Buzzer patterns
Plays the beep patterns: a short start-up beep, a fast alarm on a fall or emergency stop, and a warning when the battery is low.
9. Emergency stop
firmware.ino · lines 4206-4212
Code: Emergency stop function
One function that cancels any balance start request and shuts off both the reaction wheels and the ground wheel immediately. The emergency stop button and the safety checks call it.

03 Industrial training

Industrial trainee, MediQuipment Limited

Jaffna Regional Office · June to October 2026 · 4 months

  • Helped install medical equipment at client sites.
  • Inspection and preventive maintenance of medical devices.
  • Calibration support and performance checks.
  • Fault finding and repair alongside engineers.

04 Skills

ESP32ArduinoIoTWiFi web UIPID / PD controlIMU sensor fusionSolidWorksSolid EdgePythonC#LabVIEWMATLABAltiumProteus

Education

BSc (Hons) Science and Technology, Mechatronics
Uva Wellassa University of Sri Lanka, 2022 to present

Let's talk

Open to junior roles in embedded systems, IoT and mechatronics.

thavarasathilothman@gmail.com