This document explains the correct calibration procedure for the self-balancing robot firmware.
Firmware target: final self-balancing robot firmware with:
The robot has two main calibration commands:
CAL_GYRO
CAL_BALANCE
These two commands are different and both are required.
CAL_GYROCAL_GYRO
This command calibrates the MPU6050 sensor.
It measures and saves:
gyroX_offset
gyroY_offset
gyroZ_offset
angle_acc_offset
These values are saved to EEPROM.
CAL_GYRO removes gyro sensor drift and sets the accelerometer reference while the robot is upright and still.
Use CAL_GYRO:
During CAL_GYRO, the robot must be:
upright
still
not moving
on a flat surface or held steady
Do not touch, shake, or move the robot during this calibration.
CAL_BALANCECAL_BALANCE
This command saves the real mechanical balance point.
It updates and saves:
manual_balance_offset
A self-balancing robot is not always perfectly balanced at exactly 0 degrees. Battery position, 3D printed parts, wires, display, and chassis weight can make the real balance point slightly forward or backward.
CAL_BALANCE tells the robot:
This current angle is my real balance center.
Use CAL_BALANCE:
CAL_GYRODuring CAL_BALANCE, hold the robot at the real mechanical balance position.
That means:
The position where the robot can almost stand naturally
without strongly falling forward or backward.
Do not hold it at an artificial angle.
ENABLEENABLE
This command allows balancing to start.
The ENABLE state is saved to EEPROM.
The robot does not start balancing immediately just because ENABLE is sent.
Balancing starts only when:
ENABLE state is active
and
robot angle is inside the auto-arm window
Current auto-arm window:
-1° < angle < +1°
This safety prevents the motors from activating while the robot is lying down or tilted too far.
DISABLEDISABLE
This command turns balancing off.
The DISABLE state is saved to EEPROM.
When disabled:
motor drivers are disabled
D8 goes HIGH
movement commands are cleared
OLED eyes show disabled / closed-eye mode
Use DISABLE before carrying, adjusting, or working on the robot.
CAL_RESETCAL_RESET
Current firmware behavior:
Robot replies OK only.
No calibration data is changed.
EEPROM is not cleared.
PID values are not reset.
This command is included only for app compatibility.
Use this procedure after uploading firmware for the first time.
Put the robot on a stand or hold it carefully so the wheels can rotate freely.
Recommended:
Wheels should not touch the floor during first calibration and first enable test.
Power on the robot.
The firmware will load saved EEPROM data if valid data exists.
Important:
The robot does not automatically run gyro calibration at every startup.
This is intentional because calibration values are saved to EEPROM.
Hold the robot upright and completely still.
Do not move the robot during the next step.
CAL_GYROFrom the Android app or Bluetooth terminal, send:
CAL_GYRO
Expected robot reply:
OK
During this process:
motor drivers are disabled
MPU6050 gyro offsets are measured
accelerometer angle reference is measured
calibration values are saved to EEPROM
Wait until the robot replies OK.
Now hold the robot at its real mechanical balance point.
This is usually close to vertical, but not always exactly vertical.
Correct position:
Robot feels naturally balanced.
You do not need to force it strongly forward or backward.
CAL_BALANCESend:
CAL_BALANCE
Expected robot reply:
OK
This saves the current angle as:
manual_balance_offset
This value is saved to EEPROM.
Send your starting PID values.
Example:
PID,KP=3.5,KI=0.000,KD=4.5
Expected robot reply:
OK
These PID values are saved to EEPROM.
Recommended starting values:
KP = 3.5
KI = 0.000
KD = 4.5
Send:
ENABLE
Expected robot reply:
OK
The ENABLE state is saved to EEPROM.
Hold the robot upright so the angle is inside:
-1° to +1°
When the condition is correct:
balancing becomes active
D8 goes LOW
motor drivers are enabled
ST telemetry becomes BALANCING
OLED eyes change from disabled/calibration mode to normal/blink mode
After CAL_GYRO, CAL_BALANCE, PID, and ENABLE are saved once, normal startup is simple.
The robot loads saved EEPROM data.
Loaded values include:
gyro offsets
accelerometer angle offset
manual balance offset
PID values
ENABLE / DISABLE state
Hold the robot upright near the saved balance point.
If saved state is ENABLE and angle is inside:
-1° to +1°
then balancing activates automatically.
No new CAL_GYRO is required at every startup.
Use recalibration when the robot behavior changes after hardware changes.
Run full calibration again after:
Send commands in this order:
DISABLE
CAL_GYRO
CAL_BALANCE
ENABLE
Detailed flow:
1. Send DISABLE
2. Hold robot upright and still
3. Send CAL_GYRO
4. Wait for OK
5. Hold robot at real mechanical balance point
6. Send CAL_BALANCE
7. Wait for OK
8. Send ENABLE
9. Hold robot inside -1° to +1°
10. Wait for BALANCING state
PID tuning is separate from gyro and balance calibration.
Use PID tuning when:
Request current PID values:
PIDREQUEST
Robot reply example:
PID,KP=3.5,KI=0.000,KD=4.5
Update PID:
PID,KP=3.5,KI=0.000,KD=4.5
Expected reply:
OK
PID values are saved to EEPROM automatically.
Use these values after a fresh calibration:
KP = 3.5
KI = 0.000
KD = 4.5
Tuning notes:
| Symptom | Adjustment |
|---|---|
| Robot is weak and falls slowly | Increase KP slightly |
| Robot oscillates forward/backward | Reduce KP or increase KD slightly |
| Motor vibrates/noisy | Reduce KD |
| Robot slowly drifts but is stable | Try KI = 0.001 |
| Robot falls after adding KI | Set KI back to 0.000 |
Important:
KI = 0.1 is too high for this firmware.
Start with KI = 0.000.
Only test very small values such as 0.001 or 0.002.
Telemetry format:
A:<angle>,B:<battery_voltage>,LM:<left_motor>,RM:<right_motor>,ST:<state>
Example:
A:0.24,B:12.18,LM:15,RM:15,ST:BALANCING
AWhen balancing is active:
A = balance error angle
Stable robot should show angle close to:
0.00
When balancing is inactive:
A = raw angle relative to saved CAL_BALANCE point
STPossible states:
DISABLED
READY
FALLEN
FORWARD
BACKWARD
LEFT
RIGHT
BALANCING
During calibration and startup, watch this field carefully.
The OLED eye display helps show robot state.
| Robot state | OLED behavior |
|---|---|
| Calibration data missing | Calibration eyes |
| Disabled | Closed eyes |
| Normal balancing | Normal / blink eyes |
| Warning angle | Warning eyes |
| Fallen | Fall / X eyes |
If the robot is disabled, closed eyes are normal.
ENABLEPossible causes:
-1° to +1°ENABLE correctlyFix:
1. Send ENABLE
2. Hold robot upright near 0°
3. Check telemetry ST field
4. If still not active, redo CAL_GYRO and CAL_BALANCE
Possible causes:
MOUNT_MODEPID_OUTPUT_SIGNFix order:
1. Check motor directions
2. Check MOUNT_MODE
3. Check ANGLE_SIGN
4. Check PID_OUTPUT_SIGN
5. Run CAL_GYRO
6. Run CAL_BALANCE
Possible causes:
Fix:
1. DISABLE
2. Hold upright and still
3. CAL_GYRO
4. Hold true balance point
5. CAL_BALANCE
6. ENABLE
Possible causes:
Fix:
1. Redo CAL_BALANCE
2. Check self-balance trim parameters
3. Retune PID if needed
CAL_GYRO gives bad resultPossible causes:
Fix:
1. Put robot on stable surface
2. Hold completely still
3. Send CAL_GYRO again
Possible causes:
Fix:
1. Send CAL_GYRO
2. Send CAL_BALANCE
3. Send PID command
4. Send ENABLE
5. Power cycle and check if values remain
Use this complete command sequence:
CAL_GYRO
CAL_BALANCE
PID,KP=3.5,KI=0.000,KD=4.5
ENABLE
Then hold the robot upright inside:
-1° to +1°
Expected final telemetry:
ST:BALANCING
A close to 0.00
LM and RM changing slightly
Before carrying or working on the robot, send:
DISABLE
Expected result:
ST:DISABLED
D8 HIGH
motor drivers disabled
OLED closed eyes
CAL_GYRO Calibrate MPU6050 gyro/accelerometer reference and save to EEPROM
CAL_BALANCE Save current mechanical balance point to EEPROM
CAL_RESET Reply OK only; no changes
ENABLE Enable balancing permission and save state to EEPROM
DISABLE Disable balancing and save state to EEPROM
PIDREQUEST Request current saved PID values
PID,... Update PID values and save to EEPROM
Do not run CAL_GYRO every startup.
Only run it when:
sensor position changed
robot hardware changed
angle reading is wrong
gyro drift is noticeable
Do run CAL_BALANCE whenever the physical balance point changes.
Examples:
battery moved
OLED added
wires moved
new 3D printed part added
robot weight changed
For normal daily use:
1. Power on
2. Hold upright
3. Wait for auto-balancing
4. Drive from app