Community project

Tablet-Controlled Smart Rover

Photo of Tablet-Controlled Smart Rover
Generated with AI

Werner Eduard Moecke

Published November 13, 2026

Build a four-wheel rover that responds to tablet commands over WiFi, with obstacle avoidance capability. The Rover 5 platform combines four independent motors with an ESP32 microcontroller, a high-current motor driver, and a time-of-flight distance sensor to create a responsive mobile robot that can be controlled through a web interface or operate autonomously.

This guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions for integrating the IBT-2 motor driver, VL53L0X sensor, and LiPo power system. You'll learn how to configure motor control signals, implement battery monitoring, and upload firmware that enables both manual tablet control and automatic obstacle detection.

Wiring diagram

Wiring diagram for Tablet-Controlled Smart Rover
Loading diagram…

Gather all the parts

QtyComponent
1

IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver

IBT-2 high-current H-bridge motor driver module built around BTS7960 half-bridge devices. Common modules are sold for 6V-27V motor supplies and 5V logic, with 43A as a module headline rating; practical continuous current depends on board cooling and wiring. Direction and speed are controlled with RPWM/LPWM PWM inputs plus R_EN/L_EN enable lines. Logic-side VCC is separate from the high-power motor supply, and grounds must be common.

1

Rover 5 left front motor

Existing Rover 5 motor: 7.2V, 2.5A stall. Leave encoder wires disconnected and insulated.

1

Rover 5 left rear motor

Existing Rover 5 motor: 7.2V, 2.5A stall. Leave encoder wires disconnected and insulated.

1

IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver

IBT-2 high-current H-bridge motor driver module built around BTS7960 half-bridge devices. Common modules are sold for 6V-27V motor supplies and 5V logic, with 43A as a module headline rating; practical continuous current depends on board cooling and wiring. Direction and speed are controlled with RPWM/LPWM PWM inputs plus R_EN/L_EN enable lines. Logic-side VCC is separate from the high-power motor supply, and grounds must be common.

1

Rover 5 right front motor

Existing Rover 5 motor: 7.2V, 2.5A stall. Leave encoder wires disconnected and insulated.

1

Rover 5 right rear motor

Existing Rover 5 motor: 7.2V, 2.5A stall. Leave encoder wires disconnected and insulated.

1

VL53L0X 3.3V-compatible breakout

Regulated breakout operated entirely at 3.3V, I2C pullups to 3.3V. VIN is an input, not an output.

1

3S LiPo 11.1V 2200mAh 45C battery

User battery with female XT60; 12.6V fully charged. Use an external 3S balance charger. Do not modify or open pack.

1

5V USB power bank

Regulated 5V 1A USB power bank feeding ESP32 USB socket; separate from motor battery.

1

7.5A inline blade fuse

Inline fuse close to battery positive; use holder and 18AWG motor wiring rated at least 10A.

1

Rocker Switch

DC rated at least 10A at 24V

Classic compact panel-mount rocker switch for on/off power control in enclosures.

1

SN74AHCT125N 3.3V to 5V buffer

TTL inputs guarantee HIGH at 2V with 5V supply. GPIO connects only to inputs; 5V outputs connect only to motor drivers.

1

Resistor

10 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

10 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

10 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

10 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Ceramic Capacitor

100 nF

Through-hole ceramic capacitor bought by value, such as 22 pF, 10 nF or 100 nF (0.1 µF). It is non-polarised, so either lead can go to either net. Its most common job is decoupling: a 100 nF capacitor between an IC's supply pin and ground, placed as close to the chip as possible.

1

Pololu D24V150F6 6V 15A step-down regulator

Pololu #2882. Fixed 6V safe motor rail; typical 15A with thermal derating. EN internally pulled to 5V; NPN pulls below 1V to disable. Leave MOD and PG disconnected. https://www.pololu.com/product/2882

1

2N3904 NPN Transistor

General-purpose NPN bipolar junction transistor (BJT) in a TO-92 package. Rated for 60V collector-emitter voltage and 200mA continuous collector current with an hFE (gain) of 100–300. Commonly used as a low-side switch or signal amplifier driven by a microcontroller digital output pin via a current-limiting base resistor.

1

Resistor

4.7 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

100 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Precision battery-sense passive resistor

47 kΩ, 1%

Passive upper voltage-sense resistor

1

Precision battery-sense passive resistor

10 kΩ, 1%

Passive lower voltage-sense resistor

Assemble it in 6 steps

1. Mount the robot electronics

Mount two IBT-2 drivers and ESP32 securely above the Rover 5. Fix the distance sensor at the front, facing straight ahead. Use a VL53L0X breakout that accepts 3.3V, not a bare sensor chip. Secure the Samsung SM-T700 low and centrally; its browser is the controller, not the robot's motor controller.

  • This detects front obstacles only, not stairs, side obstacles or rear obstacles. Use on a flat enclosed floor away from people and pets.

2. Connect the four motors

Connect both left motors in parallel to left M+ and M-, and both right motors to right M+ and M-. Leave all encoder leads unplugged and individually insulated. Use 18AWG motor wires and screw terminals, never a breadboard for motor current.

3. Wire the control signals

Wire GPIO25/26 through buffer channels 1/2 to left RPWM/LPWM; GPIO27/33 through channels 3/4 to right RPWM/LPWM. Buffer VCC goes to 5V, GND and all OE pins to ground. Add one 10k resistor from each buffer input to ground. Place the 100nF capacitor across buffer VCC and ground. Driver VCC and enable inputs go to 5V; all logic and power grounds join. Sensor VIN goes to 3V3, SDA to GPIO21 (data), SCL to GPIO22 (clock).

4. Install regulated LiPo motor power

Remove the NiMH holder. Use the battery female XT60 with a matching male XT60 pigtail, observing molded + and - markings; solder only the disconnected robot-side pigtail and insulate each joint. Positive goes through the existing 7.5A fuse close to the connector, then a switch rated 10A at 24V DC, then regulator VIN. Battery negative and regulator GND go to shared ground. Regulator VOUT goes to both driver B+ terminals. Choose Pololu D24V150F6 (#2882), fixed 6V: deliberately below the 7.2V motor rating, with reduced top speed. Do not substitute the 7.5V version. Use 18AWG power wires, screw terminals and free airflow. USB bank still powers ESP32 and 5V logic; disconnect it before computer USB.

  • Never connect the LiPo directly to motors or ESP32. Never carry motor current through a breadboard.
  • Unplug the pack to charge outside the robot using a 3S LiPo balance charger and both required charger connectors. Never charge unattended; do not use a swollen or damaged pack.

5. Wire and verify battery shutdown

Wire 47k resistor from switched battery positive to GPIO34, and 10k from GPIO34 to ground. This reduces 12.6V to about 2.21V for measurement. Wire GPIO32 through 4.7k to 2N3904 base, 100k from base to ground, emitter to ground and collector to regulator EN. Verify transistor package pin labels against its datasheet, not its orientation. EN has an internal 5V pullup: never connect it directly to ESP32. With motor outputs disconnected, confirm VOUT is about 6V and displayed battery voltage agrees with a multimeter; do not operate if reading is wrong. Firmware latches regulator off below 10.8V, including missing battery sensing. After shutdown unplug battery and recharge; never reset just to keep driving. Power logic first, motors second.

  • Pack-voltage cutoff is not individual-cell protection. Use only a balanced healthy pack; check each cell with the balance charger before and after use. Do not use a pack with an unusually low cell.
  • Disconnect battery after use even after shutdown; electronics still draw a small current. The cutoff depends on working firmware and correct sensing, not an independent safety-rated protection circuit.

6. Test with tracks off the floor

With tracks raised and motor switch off, check every connection. Power logic first, then motors. Test briefly at low speed. For Forward all four motors must move their tracks forward. If a motor disagrees, power everything off and swap only that motor's two leads. Test the front sensor using a large box before allowing autonomous travel. Reverse and turns are not obstacle-protected.

Review all connections

1. Connections between "battery" and "ESP32"

FunctionbatteryESP32
powerPLUS → 7.5A inline blade fuse INEXT
groundMINUSGND

2. Connections between "fuse" and "ESP32"

FunctionfuseESP32
powerOUT → Rocker Switch T1EXT

3. Connections between "usb" and "ESP32"

FunctionusbESP32
powerPLUS5V
groundMINUSGND

4. Connections between "buffer" and "ESP32"

FunctionbufferESP32
powerVCC5V
groundGNDGND
digital1AGPIO 25
digital1Y → IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver RPWMEXT
ground1OEGND
digital2AGPIO 26
digital2Y → IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver LPWMEXT
ground2OEGND
digital3AGPIO 27
digital3Y → IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver RPWMEXT
ground3OEGND
digital4AGPIO 33
digital4Y → IBT-2 BTS7960 43A High-Current H-Bridge Motor Driver LPWMEXT
ground4OEGND

5. Connections between "range" and "ESP32"

FunctionrangeESP32
powerVIN3V3
groundGNDGND
i2cSDAGPIO 21
i2cSCLGPIO 22

6. Connections between "left" and "ESP32"

FunctionleftESP32
powerB+ → Pololu D24V150F6 6V 15A step-down regulator VOUTEXT
groundB-GND
groundGNDGND
powerVCC5V
powerR_EN5V
powerL_EN5V
dataM+ → Rover 5 left front motor PLUSEXT
dataM- → Rover 5 left front motor MINUSEXT
dataM+ → Rover 5 left rear motor PLUSEXT
dataM- → Rover 5 left rear motor MINUSEXT

7. Connections between "r1" and "ESP32"

Functionr1ESP32
digitalP1 → SN74AHCT125N 3.3V to 5V buffer 1AEXT
groundP2GND

8. Connections between "r2" and "ESP32"

Functionr2ESP32
digitalP1 → SN74AHCT125N 3.3V to 5V buffer 2AEXT
groundP2GND

9. Connections between "right" and "ESP32"

FunctionrightESP32
powerB+ → Pololu D24V150F6 6V 15A step-down regulator VOUTEXT
groundB-GND
groundGNDGND
powerVCC5V
powerR_EN5V
powerL_EN5V
dataM+ → Rover 5 right front motor PLUSEXT
dataM- → Rover 5 right front motor MINUSEXT
dataM+ → Rover 5 right rear motor PLUSEXT
dataM- → Rover 5 right rear motor MINUSEXT

10. Connections between "r3" and "ESP32"

Functionr3ESP32
digitalP1 → SN74AHCT125N 3.3V to 5V buffer 3AEXT
groundP2GND

11. Connections between "r4" and "ESP32"

Functionr4ESP32
digitalP1 → SN74AHCT125N 3.3V to 5V buffer 4AEXT
groundP2GND

12. Connections between "decouple" and "ESP32"

FunctiondecoupleESP32
digital1 → SN74AHCT125N 3.3V to 5V buffer VCCEXT
ground2GND

13. Connections between "switch" and "ESP32"

FunctionswitchESP32
powerT2 → Pololu D24V150F6 6V 15A step-down regulator VINEXT

14. Connections between "regulator" and "ESP32"

FunctionregulatorESP32
groundGNDGND
dataEN → 2N3904 NPN Transistor Collector (C)EXT

15. Connections between "cutoff" and "ESP32"

FunctioncutoffESP32
groundEmitter (E)GND

16. Connections between "base" and "ESP32"

FunctionbaseESP32
digitalP1GPIO 32
digitalP2 → 2N3904 NPN Transistor Base (B)EXT

17. Connections between "basepull" and "ESP32"

FunctionbasepullESP32
digitalP1 → 2N3904 NPN Transistor Base (B)EXT
groundP2GND

18. Connections between "battery_upper" and "ESP32"

Functionbattery_upperESP32
analogP1 → Rocker Switch T2EXT
analogP2GPIO 34

19. Connections between "battery_lower" and "ESP32"

Functionbattery_lowerESP32
analogP1 → Precision battery-sense passive resistor P2EXT
groundP2GND

Deploy the firmware

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include <VL53L0X.h>
WebServer server(80); VL53L0X sensor;
const int pins[]={25,26,27,33};
float batteryV=0; bool lowBattery=false; unsigned long batteryRead=0;
bool ready=false,automatic=false; char command='s'; unsigned long heartbeat=0,lastRead=0,turnUntil=0; int distanceMm=0; bool valid=false;
const char page[] PROGMEM=R"HTML(<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>Rover 5</title><style>body{font:24px sans-serif;text-align:center}button{font-size:24px;padding:22px;margin:7px;touch-action:none}</style></head><body><h2>Rover 5</h2><p>Hold a direction to drive</p><button ontouchstart="go('f',event)" onmousedown="go('f',event)">Forward</button><br><button ontouchstart="go('l',event)" onmousedown="go('l',event)">Left</button><button onclick="stop()">STOP</button><button ontouchstart="go('r',event)" onmousedown="go('r',event)">Right</button><br><button ontouchstart="go('b',event)" onmousedown="go('b',event)">Reverse</button><br><button onclick="autoMode()">Auto avoid</button><p>Auto runs only while this page stays connected.</p><pre id="status"></pre><script>
var c='s',timer=null;function send(){var x=new XMLHttpRequest();x.open('GET','/cmd?c='+c,true);x.send()}function go(v,e){e.preventDefault();c=v;send()}function stop(){c='s';send()}function autoMode(){c='a';send()}document.addEventListener('touchend',function(){if(c!='a')stop()});document.addEventListener('mouseup',function(){if(c!='a')stop()});window.onblur=stop;document.addEventListener('visibilitychange',function(){if(document.hidden)stop()});setInterval(function(){if(!document.hidden)send()},200);setInterval(function(){var x=new XMLHttpRequest();x.onload=function(){document.getElementById('status').textContent=x.responseText};x.open('GET','/status',true);x.send()},700);
</script></body></html>)HTML";
void rawStop(){for(int i=0;i<4;i++) analogWrite(pins[i],0);}
void drive(int left,int right){static int oldL=0,oldR=0; static unsigned long waitUntil=0;unsigned long now=millis();if((oldL*left<0)||(oldR*right<0)){rawStop();oldL=oldR=0;waitUntil=now+180;}if((long)(now-waitUntil)<0)return;analogWrite(pins[0],left>0?left:0);analogWrite(pins[1],left<0?-left:0);analogWrite(pins[2],right>0?right:0);analogWrite(pins[3],right<0?-right:0);oldL=left;oldR=right;}
void setup(){Serial.begin(115200);pinMode(32,OUTPUT);digitalWrite(32,HIGH);analogSetPinAttenuation(34,ADC_11db);for(int p:pins){pinMode(p,OUTPUT);digitalWrite(p,LOW);}Wire.begin(21,22);sensor.setTimeout(100);ready=sensor.init();if(ready)sensor.startContinuous(50);WiFi.softAP("Rover5-Control","Rover5Drive!");server.on("/",[]{server.send_P(200,"text/html",page);});server.on("/cmd",[]{String c=server.arg("c");if(c.length()==1&&strchr("sflrba",c[0])){command=c[0];automatic=command=='a';heartbeat=millis();}server.send(200,"text/plain","OK");});server.on("/status",[]{server.send(200,"text/plain",String(lowBattery?"LOW BATTERY - disconnect and recharge":(automatic?"AUTO":"MANUAL"))+"\nBattery: "+String(batteryV,2)+" V"+"\nFront: "+(valid?String(distanceMm)+" mm":"sensor unavailable - stopped"));});server.begin();Serial.println("Join Rover5-Control, open http://192.168.4.1");}
void loop(){server.handleClient();unsigned long now=millis();if(now-batteryRead>=100){batteryRead=now;uint32_t total=0;for(int i=0;i<16;i++)total+=analogReadMilliVolts(34);batteryV=(total/16.0f)*5.7f/1000.0f;if(batteryV<10.8f)lowBattery=true;digitalWrite(32,lowBattery?HIGH:LOW);}if(lowBattery){rawStop();command='s';automatic=false;return;}if(ready&&now-lastRead>=60){lastRead=now;distanceMm=sensor.readRangeContinuousMillimeters();valid=!sensor.timeoutOccurred()&&distanceMm>0&&distanceMm<8190;}if(now-heartbeat>900||!ready||!valid){command='s';automatic=false;drive(0,0);return;}int l=0,r=0;const int speed=100;if(automatic){if(distanceMm<350&&turnUntil==0)turnUntil=now+650;if(turnUntil&&(long)(now-turnUntil)<0){l=speed;r=-speed;}else{turnUntil=0;if(distanceMm>=350)l=r=speed;}}else{turnUntil=0;switch(command){case 'f':if(distanceMm>=350)l=r=speed;break;case 'b':l=r=-speed;break;case 'l':l=-speed;r=speed;break;case 'r':l=speed;r=-speed;break;}}drive(l,r);}

// Battery divider junction verified on ADC1 GPIO34.

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace, diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik