Build pathBeginnerAn afternoon

Build a Phone-Controlled Robot Car Over Bluetooth or Wi-Fi

A robot car you drive from your phone over Bluetooth or Wi-Fi, that stops on its own the moment the link drops instead of running away.

Build a Phone-Controlled Robot Car Over Bluetooth or Wi-Fi technical schematicCLEARANCE FIELD

What you are building

A robot car you drive from your phone — over Bluetooth with an HC-05, or over Wi-Fi with an ESP32 serving its own control page.

It is the most approachable robot on this site: no control theory, no algorithm to get right, and the failure modes are visible rather than mathematical. It is also the one that teaches a lesson every other robot needs — what to do when you stop being in control.

The two radios

HC-05 (Bluetooth) ESP32 (Wi-Fi)
Extra hardware A module, plus a divider on RX None — radio is on the controller
On the phone A Bluetooth serial app Any browser
Range Roughly 10 m 30 m+ outdoors
Phone keeps internet Yes No, in access-point mode
Best for A first wireless build Anything you want to hand to someone else

Neither is wrong. The HC-05 is the shorter path to a robot that moves; the ESP32 is the better experience once it works, because “connect to this Wi-Fi and open a browser” needs no explaining.

Build order

1 — Make it drive on a bench. Motors, driver, battery, wheels off the ground, no radio at all. Follow controlling DC motors with PWM and confirm forward, back and each turn with hardcoded commands. Debugging a radio and a motor driver simultaneously is how afternoons disappear.

2 — Add the radio and echo. Wire the HC-05 or bring up the ESP32’s access point, and get text moving in both directions before you connect it to anything that turns.

3 — Join them with a protocol. One letter plus a value, terminated by a newline. Read until the terminator rather than acting on each byte, because “some bytes have arrived” is not “the message has arrived”.

4 — Make it fail safe. This is the step people skip, and it is the one that matters.

The deadman timeout

A wireless robot keeps doing the last thing you told it. If that was “forward at full speed” and you have just walked out of range, the robot does not stop — it commits.

A timing diagram. A row of command pulses arrives every 100 milliseconds while a button is held, then stops at a dashed line marked signal lost. Below, a bar showing no timeout stays red and driving out of control indefinitely after the signal is lost. A second bar with a 400 millisecond deadman timeout turns to stopped shortly after the last command.
The command stream stops when the link drops, not when the user lets go — which is why the robot has to time out on its own. Download SVG

The fix has two halves and needs both:

  • The controller repeats. The phone sends the held command every 100 ms, not once on press.
  • The robot expects it. If nothing has arrived for ~400 ms, stop.
if (millis() - lastCommandAt > 400) stop();

Now a released button, a closed app, a flat phone battery and a walk out of range all produce the same outcome. You are never relying on a stop message that may never be sent.

Use millis() rather than delay() for this. A delay(200) anywhere in the loop is 200 ms during which the robot reads nothing and checks nothing.

Hardware notes

Give the radio a clean supply. Both modules draw current in sharp bursts when transmitting. Sharing a sagging rail with motors causes resets that look exactly like software crashes — the robot stops responding mid-drive and comes back a second later. Feed the motors from the battery pack through the driver, and keep the logic supply separate.

A wiring diagram. An Arduino Uno or Nano connects its TXD line directly to pin D10 of an HC-05 module, labelled as safe because 3.3 volts out reads HIGH on a 5 volt input. The return path from pin D11 to the module's RXD pin routes through a 2 kilohm and 3.3 kilohm voltage divider, with a warning that 5 volts straight into RXD damages the module partially so it still pairs but corrupts what you send it.
Three of the four wires are trivial. The fourth needs a divider, because 5 V into the module's RXD damages it slowly rather than obviously. Download SVG

Mind the 3.3 V pins. The HC-05’s RX and every ESP32 GPIO are 3.3 V parts. A 5 V Arduino transmitting into them needs a divider. The damage is gradual and partial, which is what makes it hard to diagnose.

An L298N is fine here. Its voltage drop matters on a robot chasing a line at speed; on a manually driven car you simply compensate with the throttle, so the cheaper, more common driver is the sensible choice.

Where this goes next

The command layer you have built is independent of any behaviour layer, which is exactly what makes it a good foundation. Add an ultrasonic sensor and the robot can refuse to drive into a wall even while you hold forward — the beginning of the obstacle-avoiding robot.

That combination, a robot you can drive and that can override you, is also the easiest way to develop autonomy: you can place the robot exactly where a bug happens without walking over and picking it up.

Project roadmap

The build path

Follow the tech tree from parts to a robot that follows a taped line. Each node unlocks when its prerequisites are done, and your progress saves on this device.

0 / 14 done

100%
Build

Make it fail safe

Build

Goal

Drive it from your phone

Goal

Components

Tutorials in this path

Frequently asked questions

Should I use Bluetooth or Wi-Fi for a robot car?

Bluetooth with an HC-05 is simpler to get working and pairs once, but you need a serial terminal app and the range is roughly ten metres. An ESP32 over Wi-Fi needs no app at all — it serves its own control page to any browser — and reaches further, but the phone loses its internet connection while joined to the robot's network. For a first build, Bluetooth is the shorter path; for anything you plan to demo, the ESP32's no-app control page is worth the extra hour.

Why does my Bluetooth robot keep driving after I let go of the button?

Because it never heard the release. A wired robot stops when you let go; a wireless one keeps doing the last thing it was told. The fix is two-sided: have the phone repeat the current command every 100 ms while a button is held, and have the robot stop automatically if nothing has arrived for a few hundred milliseconds. Then a released button and a lost signal produce the same safe outcome, and you never depend on a stop message that may never arrive.

Can I damage the HC-05 by wiring it directly to an Arduino?

Yes, on one pin. The module's logic is 3.3 V and its RX pin is not 5 V tolerant, so an Arduino transmitting straight into it stresses that input. What makes it maddening is that the damage is usually partial — the module still pairs and still transmits, but silently corrupts or ignores what you send it. Two resistors as a divider on that one line prevent it.

Do I need an app to control the robot from my phone?

Only for Bluetooth. An HC-05 needs some Bluetooth serial terminal on the phone to open the port. An ESP32 needs nothing: it creates its own Wi-Fi network and serves an HTML page, so you connect and open a browser. That is the strongest practical argument for the ESP32 on a robot you want other people to be able to drive.

Can a phone-controlled robot also drive itself?

Yes, and it is the natural next step. The command layer you build here is separate from the behaviour layer, so adding sensors lets the robot override you — refusing to drive into a wall even when you hold forward. Build the manual layer first: it is far easier to debug a sensor when you can position the robot by hand from across the room.