A fully wireless RC-car system built using two ESP32 boards, two BTS7960 high-current motor drivers, and ESP-NOW for ultra-fast and low-latency communication.
This project supports:
β Analog joystick steering β Potentiometer-based speed control β Button input β Differential motor control β Automatic failsafe (motors stop if signal is lost) β Expandable multi-channel design
This system has two ESP32 boards:
- Reads joystick X/Y
- Reads potentiometer (speed control)
- Reads joystick switch button
- Sends the values wirelessly to the receiver using ESP-NOW
- Receives joystick data
- Processes differential drive (left/right motors)
- Controls two BTS7960 motor drivers
- Automatically stops motors if transmitter signal is lost
| Component | Qty |
|---|---|
| ESP32 Dev Board | 1 |
| 2-axis Joystick Module | 1/2 |
| Potentiometer (10k recommended) | 1 |
| Jumper wires | Several |
| 5V power bank / Li-ion battery | 1 |
| Component | Qty |
|---|---|
| ESP32 Dev Board | 1 |
| BTS7960 Motor Driver | 2 (Left + Right motor) |
| 12Vβ24V battery for motors | 1 |
| DC motors (high torque) | 2 |
| Chassis + wheels | 1 set |
| Jumper wires (thick wires for motors) | Several |
| Joystick Pin | ESP32 Pin |
|---|---|
| VRX | GPIO34 |
| VRY | GPIO35 |
| SW | GPIO32 |
| +5V | 3.3V/5V |
| GND | GND |
| Pot Pin | ESP32 Pin |
|---|---|
| Middle Output | GPIO33 |
| One Side | 3.3V/5V |
| Other Side | GND |
| BTS7960 Pin | ESP32 Pin |
|---|---|
| RPWM | GPIO25 |
| LPWM | GPIO26 |
| R_EN | GPIO27 |
| L_EN | GPIO14 |
| BTS7960 Pin | ESP32 Pin |
|---|---|
| RPWM | GPIO12 |
| LPWM | GPIO13 |
| R_EN | GPIO15 |
| L_EN | GPIO2 |
- B+ β Motor Battery +
- Bβ β Motor Battery β
- Motor terminals β actual motor
Upload the receiver code first.
Open Serial Monitor β it prints:
Receiver MAC Address: 80:F3:DA:55:8C:48
COPY THIS MAC ADDRESS TO TRANSMITTER CODE!
In the transmitter code, replace:
uint8_t receiverMAC[] = {0x80, 0xF3, 0xDA, 0x55, 0x8C, 0x48};with your own receiverβs MAC.
If this is wrong β transmitter will NOT connect.
- Reads joystick X/Y (0β4095)
- Converts to β100 β¦ +100 range
- Reads potentiometer β 0β100 speedLevel
- Packs into a struct:
struct_message {
int xAxis;
int yAxis;
int speedLevel;
bool button;
};- Sends to receiver via ESP-NOW every 50ms
-
Gets the struct and extracts X/Y/speed values
-
Calculates:
- Forward/backward speed (Y axis)
- Left/right steering adjustment (X axis)
-
Uses differential drive:
- Left motor speed adjusted opposite of right motor
-
Speed converted to PWM (0β255)
-
Controls motors through BTS7960 PWMs
-
Timeout protection stops motors if no signal for 1 sec
int rawX = analogRead(JOYSTICK_X_PIN);
int rawY = analogRead(JOYSTICK_Y_PIN);
int rawP = analogRead(POT_PIN);x = map(rawX, 0, 4095, -100, 100);Removes jitter around the center.
esp_now_send(receiverMAC, (uint8_t*)&myData, sizeof(myData));Triggered every time transmitter sends data.
void OnDataRecv(...)
{
memcpy(&incomingData, incomingDataByte, sizeof(incomingData));
controlMotors(...);
}leftMotorSpeed = map(yAxis, -100, 100, -baseSpeed, baseSpeed);
rightMotorSpeed = map(yAxis, -100, 100, -baseSpeed, baseSpeed);if (xAxis < 0) { turn left }
if (xAxis > 0) { turn right }Forward:
analogWrite(RPWM, speed);
analogWrite(LPWM, 0);Backward:
analogWrite(LPWM, speed);
analogWrite(RPWM, 0);If no packet is received for 1 second β motors stop.
Here are things you can add later (easy upgrades):
- Add headlights using LED
- Horn/buzzer
- Servo for camera pan/tilt
- Extra buttons for custom features
Just expand the struct:
int extra1;
int extra2;
bool sw2;Add ESP32-CAM or analog FPV system.
- Show speed
- Battery status
- Signal strength
Receiver β Transmitter Send:
- Battery voltage
- Motor temperature
- Distance sensor values
Smoothen movement and avoid jerkiness.
- Always test motors with wheels lifted first
- Expect the joystick Y-axis to control forward/back
- X-axis controls left/right turning
- Potentiometer smoothens speed