How to control an Arduino over Bluetooth from your phone — without writing an app
You followed the tutorial. The robot is wired. The HC-05 blinks. The sketch compiles. And then the tutorial cheerfully says: "Now open your Arduino Bluetooth controller app and press Forward."
Which app, exactly? You search the Play Store. The top results are 12 nearly-identical apps with the same screenshot: four arrow buttons, an ON/OFF toggle, and ads stacked on top of the joystick. You install three of them, none can be customised, two crash on Android 14, and the fourth doesn't support landscape. Two hours pass. The robot still hasn't moved.
This is the part of every Arduino tutorial that quietly assumes a controller you don't have. Here's how to skip the whole detour — without writing an Android app, without touching XML, and without learning Kotlin just to wiggle a servo.
The three options, ranked by pain
You essentially have three choices to drive a Bluetooth-equipped Arduino, ESP32, ESP8266 or Raspberry Pi from a phone. In ascending order of effort:
- A fixed-layout "Bluetooth controller" app from the Play Store. Quick to install. Layout is whatever the developer chose three years ago. Adding a slider for servo angle or a gauge for battery is not on the menu — you either don't get it, or you pay the in-app purchase and discover the slider sends a payload format that doesn't match your sketch.
- Build your own Android app in Android Studio. Most flexible. Also: install Android Studio, learn Gradle, write a
BluetoothSocketwrapper, debug permissions on every Android version, ship a custom APK to a friend who runs Android 9. A one-evening robot project becomes a one-month app project. - A no-code remote designer. A drag-and-drop canvas where you place the widgets your project needs, type the command each one sends, and connect to your own hardware. The middle ground that didn't really exist five years ago and now does.
The third option is what most makers eventually want — they just don't know it's available. The rest of this post walks through how to set it up, what your Arduino sketch needs to look like, and the small handful of details that make the difference between a controller that works and a controller that feels good.
What your Arduino sketch actually needs
The simplest contract between phone and board is the one every HC-05 tutorial uses: the phone sends short text commands over the Bluetooth Serial Port Profile (SPP), the board reads them with Serial.read(), and does something. That's the whole protocol.
A minimal sketch for an HC-05 wired to UNO pins 0/1 (or a SoftwareSerial on 10/11) looks like this:
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd == "F") forward();
else if (cmd == "B") backward();
else if (cmd == "S") stop();
else if (cmd.startsWith("SPEED:")) {
int v = cmd.substring(6).toInt();
analogWrite(ENA, v);
}
}
}
That's it. Your job from here is to make sure the phone sends F, B, S, and SPEED:0 through SPEED:255 when you want it to. The phone doesn't need to know about pins, motors or PWM; the board doesn't need to know about widgets or layouts.
Designing the controller (the no-code part)
Open a no-code remote designer like Arduino Remote Studio, pick an empty canvas, and drop the widgets your project needs. For a two-wheel drive robot, that's roughly:
- A joystick sending
X:{x},Y:{y}for differential steering, OR - A 4-button D-pad sending
F/B/L/Ron press, andSon release - A slider sending
SPEED:{value}from 0 to 255 - A big red button with the destructive flag on, mapped to
S— the Emergency Stop - A gauge bound to the
BATTkey, so live battery percent shows on screen
That's the whole layout. Each widget has two things you configure: what it sends (the command template) and, optionally, what key it listens for (for two-way data). Five widgets, maybe two minutes of tapping.
Two-way data: the part everyone forgets
Most "Bluetooth controller" apps are one-way: phone speaks, board listens, end of story. That's fine for a blinky-LED demo. It's a disaster for anything that runs on a battery, has a temperature limit, or needs you to know whether a command was actually received.
The fix is a one-line convention: have your sketch print KEY:VALUE lines back over Serial whenever something changes.
void loop() {
// ... your control code ...
static unsigned long lastReport = 0;
if (millis() - lastReport > 1000) {
int batt = readBatteryPercent();
Serial.print("BATT:"); Serial.println(batt);
float t = readTempC();
Serial.print("TEMP:"); Serial.println(t, 1);
lastReport = millis();
}
}
Bind a gauge to BATT and a value display to TEMP in the designer. From that moment on, your phone is no longer just a remote — it's a live dashboard. Sliders can be bound to keys too, so a "throttle" slider both sends a target speed and reflects the actual measured speed once the board reports it back.
This convention scales: RPM, VOLT, DIST, HUMID, anything your sensors produce. The phone doesn't care what the keys mean; it just looks for matching widget bindings.
The safety details that separate "demo" from "drivable"
Three things separate a controller you'd use for a 30-second tutorial demo from a controller you'd actually drive a sharp-edged robot with:
1. An Emergency Stop that's bigger than the joystick
If your robot can move faster than your reflexes, you need a stop button you can hit by feel. Make it red, make it 25% of the screen, and put it in the same place on every layout. Tag it destructive in the designer so a confirm dialog doesn't pop up at the worst possible moment — destructive flags add a confirm; an E-Stop should bypass that.
2. A failsafe that fires on disconnect
Bluetooth Classic drops. Phones go to sleep. Apps get killed. If your robot is mid-traversal when the connection dies, the last command it received — say, F at full speed — will just keep executing forever, because nothing told it to stop.
The fix on the phone side is a single configuration: a failsafe-on-disconnect payload, usually S\n, that the app fires the moment the BT socket closes. The fix on the board side, in case the app didn't get a chance, is a software watchdog:
unsigned long lastCmdAt = 0;
void loop() {
if (Serial.available()) {
handleCommand();
lastCmdAt = millis();
}
// No command in 800ms? Assume disconnect, stop.
if (millis() - lastCmdAt > 800) stop();
}
Use both, not either. Belt and suspenders is the only acceptable policy when a 2 kg robot is involved.
3. Per-control haptic feedback
A small thing that turns out to matter: a light vibration on every button press tells your thumb the command went through, even when you're looking at the robot and not the phone. It's the difference between "did I tap that?" and confident driving.
Bluetooth Classic vs WiFi: which transport to pick
If your board has a Bluetooth Classic module (HC-05, HC-06, an ESP32 in BT-Classic mode, a Bluefruit), use it. The serial-over-BT pattern above is the simplest possible protocol and works without a router, an IP, or any local infrastructure.
Use WiFi (TCP) when:
- You're on an ESP8266 / NodeMCU with no Bluetooth radio.
- Your robot needs to roam more than ~10 metres from the phone.
- Multiple devices need to connect to the same board.
- You want the board reachable from anywhere on your home network.
The protocol stays identical — text commands in, KEY:VALUE data back. The transport changes; the contract doesn't. The official Arduino communication reference is the canonical free starting point for the underlying serial concepts, and they map cleanly across both transports.
The mistakes that waste an evening
If a no-code controller "isn't working", it's almost always one of these:
- Baud rate mismatch. HC-05 defaults to 9600. Many tutorials change it to 38400 with an AT command. If the app and the sketch don't agree, you get garbage characters and silence.
- Missing line terminator. Your sketch uses
readStringUntil('\n'); the app sendsFwith no newline. The board waits forever. Either append\nin the widget's payload template, or read withSerial.read()byte-by-byte. - Pin 0/1 conflict on UNO. The hardware Serial pins are also USB. Either disconnect USB while testing, or move the HC-05 to a SoftwareSerial pair (10/11 is the convention).
- HC-05 in AT mode. If you held the small button on the module while powering on, it's in 38400 baud AT-command mode and won't pair normally. Power-cycle without the button.
- Bluetooth permissions on Android 12+. The app needs
BLUETOOTH_CONNECTandBLUETOOTH_SCANat runtime — denied by default. Grant them in Android settings if you skipped the prompt the first time.
None of these are app problems — they're setup problems. They're identical whether you built the app yourself or used a no-code designer. The benefit of the no-code path is you can rule them in or out without rebuilding an APK each time.
When you outgrow this approach
The no-code path is right for 95% of hobby Arduino, ESP32 and Raspberry Pi projects. The cases where you genuinely need to build a custom app are narrow:
- You're shipping the controller as a product with branding and a paywall — Play Store needs your own APK.
- You need cloud sync across multiple users — beyond what a peer-to-peer designer offers.
- You need tightly integrated camera + computer vision running on the phone — Android Studio gives you the SDKs.
- You're commercialising fleet telemetry — at which point a no-code remote is the wrong abstraction anyway.
For everything else — robots, RC cars, drone controllers, LED strips, smart-home tinkering, STEM workshops, university final-year projects — the answer is: don't write an app. Design a layout, type a few command strings, and drive.
The point of a Bluetooth controller is to control your project, not to become a side project of its own.
One specific layout to start with
If you're staring at an empty canvas wondering where to begin, copy this layout for a generic two-wheel robot and modify from there:
Seven widgets, two-way data, an Emergency Stop, a horn, a working battery indicator. Five minutes in the designer, then onto the actual interesting part: getting the robot to dodge the cat.
Arduino Remote Studio — the no-code path, built in
Drag-and-drop Bluetooth and WiFi remote designer for Arduino, ESP32, ESP8266 and Raspberry Pi. 6 starter templates, Emergency Stop, failsafe-on-disconnect, two-way live data. Free on Google Play.
See Arduino Remote Studio →