This document describes the Bluetooth communication protocol for the self-balancing robot firmware.
Module: HC-05
Baud rate: 9600
Arduino Serial: Hardware Serial D0 / D1
Data format: ASCII text command
Commands can be ended with:
\n
\r
;
The firmware also accepts commands after a short receive timeout, so most app buttons can send plain text such as:
FORWARD
Recommended delimiter:
FORWARD\n
These commands control only movement. They do not turn balancing on/off.
FORWARD
Effect:
Robot moves forward.
Robot replies OK.
ST telemetry becomes FORWARD.
Important:
The app should keep sending FORWARD repeatedly while the button is held.
If no movement command is received for 2 seconds, the robot automatically stops movement.
Balancing remains active.
BACKWARD
Effect:
Robot moves backward.
Robot replies OK.
ST telemetry becomes BACKWARD.
LEFT
Effect:
Robot rotates left.
Robot replies OK.
ST telemetry becomes LEFT.
RIGHT
Effect:
Robot rotates right.
Robot replies OK.
ST telemetry becomes RIGHT.
STOP
Effect:
Robot stops forward/backward/left/right movement.
Robot replies OK.
Balancing remains active if already enabled and upright.
ST telemetry returns to BALANCING.
ENABLE
Effect:
Balancing permission is enabled.
This ENABLE state is saved to EEPROM.
Robot replies OK.
Balancing starts only when:
ENABLE state is active
and robot angle is between -1° and +1° from saved balance point
When balancing becomes active:
DRV8825 ENABLE pin D8 goes LOW
Motors are enabled
DISABLE
Effect:
Balancing is disabled.
This DISABLE state is saved to EEPROM.
Robot replies OK.
Movement commands are cleared.
Motors are disabled.
When disabled:
DRV8825 ENABLE pin D8 goes HIGH
ST telemetry becomes DISABLED
OLED eyes show disabled / closed-eye mode
Correct command:
DISABLE
Wrong old spelling is not supported:
DESABLE
CAL_GYRO
Use when:
Robot is upright
Robot is completely still
Wheels are not moving
Effect:
Stops movement
Disables motor drivers during calibration
Measures MPU6050 gyro offsets
Measures accelerometer balance reference
Saves calibration data to EEPROM
Robot replies OK
Saved to EEPROM:
gyroX_offset
gyroY_offset
gyroZ_offset
angle_acc_offset
current PID values
current ENABLE/DISABLE state
CAL_BALANCE
Use when:
Robot is held at the real mechanical balance point
Effect:
Current angle becomes the robot balance center.
manual_balance_offset is updated.
Calibration is saved to EEPROM.
Movement and PID memory are cleared.
Robot replies OK.
Saved to EEPROM:
manual_balance_offset
current PID values
gyro / accelerometer calibration values
current ENABLE/DISABLE state
CAL_RESET
Current firmware behavior:
Robot replies OK.
No values are changed.
EEPROM is not cleared.
PID is not reset.
Calibration is not reset.
This command exists only for app compatibility.
PIDREQUEST
Robot reply format:
PID,KP=3.5,KI=0.000,KD=4.5
Exact format:
PID,KP=<1 decimal>,KI=<3 decimals>,KD=<1 decimal>
Example replies:
PID,KP=3.5,KI=0.000,KD=4.5
PID,KP=4.2,KI=0.002,KD=5.0
PID,KP=18.0,KI=0.500,KD=1.2
Important:
PIDREQUEST does not reply OK.
It replies only the PID data line.
PID,KP=3.5,KI=0.000,KD=4.5
Effect:
KP, KI, KD are updated immediately.
PID integral memory is cleared.
New PID values are saved to EEPROM.
Robot replies OK.
Invalid PID command:
PID,KP=3.5,KD=4.5
Reply:
ERR
Because KI= is missing.
Firmware-side PID limits:
No PID min/max limits are applied in firmware.
The app may send any float values.
PID tuning must be done carefully by the user.
Recommended app slider ranges:
KP: 0.0 to 8.0
KI: 0.000 to 0.020
KD: 0.0 to 10.0
Firmware does not block values outside these ranges.
The app may send:
CFG,MAX_SPEED=50.3,MAX_TILT=12.0
Current firmware behavior:
Robot replies OK.
No configuration values are changed.
Nothing is saved to EEPROM.
This command exists only for app compatibility.
Any command starting with:
CFG,
will reply:
OK
After boot, robot sends:
READY
Then initial telemetry:
A:0.00,B:0.00,LM:0,RM:0,ST:READY
Most valid commands reply:
OK
Examples:
FORWARD -> OK
BACKWARD -> OK
LEFT -> OK
RIGHT -> OK
STOP -> OK
ENABLE -> OK
DISABLE -> OK
CAL_GYRO -> OK
CAL_BALANCE -> OK
CAL_RESET -> OK
PID,KP=3.5,KI=0.000,KD=4.5 -> OK
CFG,MAX_SPEED=50.3,MAX_TILT=12.0 -> OK
Invalid command reply:
ERR
Example:
HELLO
Reply:
ERR
If the receive buffer overflows:
RX_OVERFLOW
When app sends:
PIDREQUEST
Robot replies:
PID,KP=3.5,KI=0.000,KD=4.5
No OK is sent after this.
Robot sends telemetry every:
200 ms
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
AA:<angle>
Example:
A:0.24
Meaning:
When balancing is active:
A = balance error angle
So when the robot is stable, A should be close to:
0.00
When balancing is inactive:
A = raw angle relative to saved CAL_BALANCE point
Decimal places:
2 decimals
BB:<battery_voltage>
Example:
B:12.18
Meaning:
Battery voltage measured from A6 through voltage divider.
Decimal places:
2 decimals
Battery input wiring expected by firmware:
Battery + -> R1 -> A6 -> R2 -> GND
Battery - -> Arduino GND
Default resistor values in firmware:
R1 = 100k
R2 = 33k
Never connect battery voltage directly to A6.
LMLM:<left_motor_output>
Example:
LM:15
Meaning:
Left motor target output value.
This is not RPM.
This is an internal motor command value used by the firmware.
RMRM:<right_motor_output>
Example:
RM:15
Meaning:
Right motor target output value.
This is not RPM.
This is an internal motor command value used by the firmware.
STST:<state>
Possible values:
DISABLED
READY
FALLEN
FORWARD
BACKWARD
LEFT
RIGHT
BALANCING
DISABLEDBalancing is disabled.
D8 is HIGH.
Motor drivers are disabled.
READYENABLE state is active, but robot has not armed balancing yet.
Usually angle is not inside -1° to +1° arming window.
FALLENRobot angle is greater than TIP_OVER_ANGLE_LIMIT.
Balancing is deactivated.
D8 is HIGH.
BALANCINGRobot is actively self-balancing.
No movement command is currently active.
FORWARDRobot is balancing and forward command is active.
BACKWARDRobot is balancing and backward command is active.
LEFTRobot is balancing and left rotation command is active.
RIGHTRobot is balancing and right rotation command is active.
For movement buttons:
When button pressed:
send FORWARD / BACKWARD / LEFT / RIGHT immediately
While button is held:
repeat the same command every 100 ms to 300 ms
When button released:
send STOP
Reason:
Firmware has a 2 second movement timeout.
If movement commands stop arriving, robot stops movement automatically.
Balancing continues.
Recommended repeat interval:
100 ms
FORWARD
BACKWARD
LEFT
RIGHT
STOP
ENABLE
DISABLE
CAL_GYRO
CAL_BALANCE
CAL_RESET
PIDREQUEST
PID,KP=<value>,KI=<value>,KD=<value>
CFG,<anything>
READY
OK
ERR
RX_OVERFLOW
PID,KP=<value>,KI=<value>,KD=<value>
A:<angle>,B:<battery>,LM:<left>,RM:<right>,ST:<state>
App -> Robot: CAL_GYRO
Robot -> App: OK
App -> Robot: CAL_BALANCE
Robot -> App: OK
App -> Robot: PID,KP=3.5,KI=0.000,KD=4.5
Robot -> App: OK
App -> Robot: ENABLE
Robot -> App: OK
App -> Robot: PIDREQUEST
Robot -> App: PID,KP=3.5,KI=0.000,KD=4.5
App -> Robot: FORWARD
Robot -> App: OK
Robot -> App: A:0.12,B:12.18,LM:14,RM:14,ST:FORWARD
App -> Robot: STOP
Robot -> App: OK
App -> Robot: DISABLE
Robot -> App: OK
Robot -> App: A:2.45,B:12.10,LM:0,RM:0,ST:DISABLED