Bluetooth Controlled Car — Quick Start + Full Code

Powered by Arduino • Continuous Servos • OLED Display • QR Startup Screen

Quick Start Guide

  1. Turn on your Bluetooth RC car.
  2. Install the Android app Arduino Bluetooth Controller:
Get the App
  1. Pair your Bluetooth module (HC-05/HC-06) in Android Bluetooth settings (PIN 1234 or 0000).
  2. Open the app → Connect → Send commands from the table below.
  3. The OLED will show arrows or text for each command.

Bluetooth Commands

CommandFunctionOLED Shows
UMove ForwardUP
LTurn Left<-
RTurn Right->
BBackwardBACK
OStop / IdleIDLE
POpen servo (0°)OPEN
CClose servo (180°)CLOSE

These match your code exactly — no HC-SR04 is used.

📌 FULL CAR CODE

Copy, upload, and run. This is your exact working version (no distance sensor).

// FULL CAR CODE ----------------------------------------------------

#include 
#include 
#include 
#include 
#include 
#include 

const int bluetoothTx = 3;
const int bluetoothRx = 4;
SoftwareSerial bleSerial(bluetoothTx, bluetoothRx);

Servo servo8, servo9, servo10, servo11;
Servo servo12;

const int offPin = 7;

const int STOP = 90;
const int FORWARD = 120;
const int BACKWARD = 60;

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int targetPos = 90;
int currentPos = 90;
unsigned long lastUpdate = 0;
const unsigned long stepInterval = 20;

bool firstCommandReceived = false;

void setup() {
  Serial.begin(9600);
  bleSerial.begin(9600);

  servo8.attach(8);
  servo9.attach(9);
  servo10.attach(10);
  servo11.attach(11);
  servo12.attach(12);

  pinMode(offPin, OUTPUT);
  digitalWrite(offPin, LOW);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  showStartupQR();
  servo12.write(currentPos);
}

void showStartupQR() {
  display.clearDisplay();

  QRCode qrcode;
  const uint8_t version = 4;
  uint8_t qrcodeData[qrcode_getBufferSize(version)];
  qrcode_initText(&qrcode, qrcodeData, version, ECC_LOW,
    "https://car.arihantnag.com");

  int scale = 2;
  int qrWidth = qrcode.size * scale;
  int xOffset = (SCREEN_WIDTH - qrWidth) / 2;
  int yOffset = (SCREEN_HEIGHT - qrWidth) / 2;

  for (uint8_t y = 0; y < qrcode.size; y++) {
    for (uint8_t x = 0; x < qrcode.size; x++) {
      if (qrcode_getModule(&qrcode, x, y)) {
        for (int dy = 0; dy < scale; dy++) {
          for (int dx = 0; dx < scale; dx++) {
            display.drawPixel(xOffset + x*scale + dx,
                              yOffset + y*scale + dy,
                              SSD1306_WHITE);
          }
        }
      }
    }
  }
  display.display();
}

void loop() {
  if (bleSerial.available()) {
    char c = toupper(bleSerial.read());
    if (c == 'U' || c == 'L' || c == 'R' || c == 'B' ||
        c == 'O' || c == 'P' || c == 'C') {
      firstCommandReceived = true;
      handleCommand(c);
    }
  }

  unsigned long now = millis();
  if (now - lastUpdate >= stepInterval) {
    lastUpdate = now;
    if (currentPos < targetPos) currentPos++;
    else if (currentPos > targetPos) currentPos--;
    servo12.write(currentPos);
  }
}

void showStatusOLED(const char* text) {
  display.clearDisplay();
  display.setCursor(0, 10);
  display.setTextSize(4);
  display.setTextColor(SSD1306_WHITE);
  display.println(text);
  display.display();
}

void handleCommand(char cmd) {
  switch (cmd) {
    case 'U':
      servo8.write(FORWARD);
      servo9.write(FORWARD);
      servo10.write(FORWARD);
      servo11.write(FORWARD);
      showStatusOLED("UP");
      break;

    case 'R':
      servo8.write(FORWARD);
      servo10.write(FORWARD);
      servo9.write(BACKWARD);
      servo11.write(BACKWARD);
      showStatusOLED("->");
      break;

    case 'L':
      servo8.write(BACKWARD);
      servo10.write(BACKWARD);
      servo9.write(FORWARD);
      servo11.write(FORWARD);
      showStatusOLED("<-");
      break;

    case 'B':
      servo8.write(BACKWARD);
      servo9.write(BACKWARD);
      servo10.write(BACKWARD);
      servo11.write(BACKWARD);
      showStatusOLED("BACK");
      break;

    case 'O':
      servo8.write(STOP);
      servo9.write(STOP);
      servo10.write(STOP);
      servo11.write(STOP);
      servo12.write(STOP);
      digitalWrite(offPin, HIGH);
      delay(100);
      digitalWrite(offPin, LOW);
      showStatusOLED("IDLE");
      break;

    case 'P':
      targetPos = 0;
      showStatusOLED("OPEN");
      break;

    case 'C':
      targetPos = 180;
      showStatusOLED("CLOSE");
      break;
  }
}
// END CODE ---------------------------------------------------------