DIY SPY CAR

DIY SPY CAR | XIAO ESP32-S3 Sense | 4WD FPV Recon

๐Ÿ•ต️‍♂️ DIY SPY CAR · XIAO ESP32-S3 SENSE

⚡ 4WD | FPV Live-Stream | Tactical UI | Night Ops LED | WebSocket Control

๐Ÿ”Ž What is SPY CAR?

A compact 4WD reconnaissance robot built around the XIAO ESP32-S3 Sense. Streams live video to any smartphone, features tactical white LEDs, 4 individually controlled N20 motors, real‑time CPU temperature and a military‑style web dashboard. Perfect for FPV exploration, spy‑themed projects or RC fun.

⚙️ How It Works

• XIAO ESP32-S3 Sense captures QVGA video (JPEG) → streamed via HTTP.
• Two DRV8833 dual H‑bridge drivers control 4 N20 motors (tank steering).
• MT3608 boost converter lifts 3.7V LiPo → stable 5V for ESP32 and camera.
• WebSocket server handles real‑time commands (forward/back/pivot/stop) with ultra-low latency.
• Tactical LED bar (4x white LEDs) activated from dashboard.
• Integrated temperature sensor sends core readings to web UI.

๐Ÿ“ฆ Components Required

๐Ÿ–จ️ 3D Print Files + Materials

๐Ÿ”Œ Pin Connections (XIAO ESP32-S3 Sense)

ComponentXIAO PinNotes
DRV8833 #1 (Left motors)D0, D1, D2, D3IN1/IN2 – Motor A ; IN3/IN4 – Motor B
DRV8833 #2 (Right motors)D4, D5, D6, D7corresponding control pins
LED Bar (4x white) via 220ฮฉD8Active HIGH (tactical light)
MT3608 Boost (5V out)5V / GNDpowers ESP32 & camera
TP4056 + BatteryOUT+ → MT3608 IN+3.7V LiPo → boost converter
⚡ Important: Adjust MT3608 to 5.0V before connecting to XIAO. Use a slide switch between battery + and TP4056 input for safety.

⚡ Features & Performance

๐Ÿ“น FPV Live Video (QVGA 320x240) / low latency
๐ŸŽฎ WebSocket commands → instant movement
๐ŸŒก️ Real‑time Core temperature + uptime
๐Ÿ’ก Tactical LED Bar (night mode)
๐Ÿ”‹ 1000mAh LiPo → 45+ min runtime
⚙️ Tank steering & 4WD traction

๐Ÿ’ป Arduino Firmware (Full Code)

/*
  DIY SPY CAR – XIAO ESP32-S3 Sense | DRV8833 | WebSocket + Camera
  by SIMPLE CIRCUITS
*/

#include 
#include 
#include 
#include 

const char* ssid = "SPY_CAR_HOTSPOT";
const char* password = "spycar1234";

#define LEFT_IN1    D0
#define LEFT_IN2    D1
#define LEFT_IN3    D2
#define LEFT_IN4    D3
#define RIGHT_IN1   D4
#define RIGHT_IN2   D5
#define RIGHT_IN3   D6
#define RIGHT_IN4   D7
#define LED_PIN     D8

// camera pins XIAO S3 Sense
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      10
#define SIOD_GPIO_NUM      40
#define SIOC_GPIO_NUM      39
#define Y9_GPIO_NUM        48
#define Y8_GPIO_NUM        11
#define Y7_GPIO_NUM        12
#define Y6_GPIO_NUM        14
#define Y5_GPIO_NUM        16
#define Y4_GPIO_NUM        18
#define Y3_GPIO_NUM        17
#define Y2_GPIO_NUM        15
#define VSYNC_GPIO_NUM     38
#define HREF_GPIO_NUM      47
#define PCLK_GPIO_NUM      13

WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
bool ledState = false;
float cpuTemp = 0;

void setMotor(int in1, int in2, bool forward) {
  digitalWrite(in1, forward ? HIGH : LOW);
  digitalWrite(in2, forward ? LOW : HIGH);
}
void stopMotor(int in1, int in2) { digitalWrite(in1, LOW); digitalWrite(in2, LOW); }

void moveForward() {
  setMotor(LEFT_IN1, LEFT_IN2, true); setMotor(LEFT_IN3, LEFT_IN4, true);
  setMotor(RIGHT_IN1, RIGHT_IN2, true); setMotor(RIGHT_IN3, RIGHT_IN4, true);
}
void moveBackward() {
  setMotor(LEFT_IN1, LEFT_IN2, false); setMotor(LEFT_IN3, LEFT_IN4, false);
  setMotor(RIGHT_IN1, RIGHT_IN2, false); setMotor(RIGHT_IN3, RIGHT_IN4, false);
}
void rotateLeft() {
  setMotor(LEFT_IN1, LEFT_IN2, false); setMotor(LEFT_IN3, LEFT_IN4, false);
  setMotor(RIGHT_IN1, RIGHT_IN2, true); setMotor(RIGHT_IN3, RIGHT_IN4, true);
}
void rotateRight() {
  setMotor(LEFT_IN1, LEFT_IN2, true); setMotor(LEFT_IN3, LEFT_IN4, true);
  setMotor(RIGHT_IN1, RIGHT_IN2, false); setMotor(RIGHT_IN3, RIGHT_IN4, false);
}
void stopAll() {
  stopMotor(LEFT_IN1, LEFT_IN2); stopMotor(LEFT_IN3, LEFT_IN4);
  stopMotor(RIGHT_IN1, RIGHT_IN2); stopMotor(RIGHT_IN3, RIGHT_IN4);
}
void toggleLED() { ledState = !ledState; digitalWrite(LED_PIN, ledState ? HIGH : LOW); }

void initCameraSense() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_QVGA;
  config.pixel_format = PIXFORMAT_JPEG;
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) Serial.printf("CAM init fail: 0x%x", err);
  else {
    sensor_t *s = esp_camera_sensor_get();
    if(s){ s->set_vflip(s, 1); s->set_hmirror(s, 1); }
  }
}

const char index_html[] PROGMEM = R"rawliteral(
SPY CAR
๐Ÿ•ต️ SPY CAR⚙️ WAIT
CORE
--°C
UPTIME
00:00
LATENCY
--ms
)rawliteral"; void wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t len){ if(type==WStype_TEXT){ String s=String((char*)payload); int sep=s.indexOf(':'); if(sep>0){ String cmd=s.substring(0,sep); if(cmd=="forward") rotateRight(); else if(cmd=="backward") rotateLeft(); else if(cmd=="left") moveBackward(); else if(cmd=="right") moveForward(); else if(cmd=="stop") stopAll(); else if(cmd=="led"){ if(s.substring(sep+1)=="1" && !ledState) toggleLED(); else if(s.substring(sep+1)=="0" && ledState) toggleLED(); } } } } void handleRoot(){ server.send(200,"text/html",index_html); } void handleStream(){ camera_fb_t *fb=esp_camera_fb_get(); if(!fb){ server.send(500,"text/plain","fail"); return; } server.sendHeader("Content-Type","image/jpeg"); server.send_P(200,"image/jpeg",(const char*)fb->buf,fb->len); esp_camera_fb_return(fb); } void setup(){ Serial.begin(115200); pinMode(LEFT_IN1,OUTPUT);pinMode(LEFT_IN2,OUTPUT);pinMode(LEFT_IN3,OUTPUT);pinMode(LEFT_IN4,OUTPUT); pinMode(RIGHT_IN1,OUTPUT);pinMode(RIGHT_IN2,OUTPUT);pinMode(RIGHT_IN3,OUTPUT);pinMode(RIGHT_IN4,OUTPUT); pinMode(LED_PIN,OUTPUT); stopAll(); digitalWrite(LED_PIN,LOW); initCameraSense(); WiFi.mode(WIFI_AP); WiFi.softAP(ssid,password); server.on("/",handleRoot); server.on("/stream",handleStream); server.begin(); webSocket.begin(); webSocket.onEvent(wsEvent); Serial.print("AP IP: "); Serial.println(WiFi.softAPIP()); } void loop(){ server.handleClient(); webSocket.loop(); static unsigned long lastTemp=0; if(millis()-lastTemp>2000){ cpuTemp=temperatureRead(); webSocket.broadcastTXT("temp:"+String(cpuTemp,1)); lastTemp=millis(); } delay(1); }
๐Ÿ“ก Code highlights: creates WiFi AP "SPY_CAR_HOTSPOT" (pw: spycar1234), serves real‑time dashboard, WebSocket low‑latency driving, camera stream at QVGA, automatic temperature broadcast. Adjust mirror/flip in setup if needed.

๐Ÿ› ️ Assembly (6 steps)

  • 1️⃣ 3D print all parts (Nylon base + TPU tyres).
  • 2️⃣ Solder DRV8833 modules, connect motors to outputs and XIAO pins D0-D7.
  • 3️⃣ Set MT3608 to 5.0V, connect to 5V/GND of XIAO.
  • 4️⃣ Wire slide switch, TP4056, battery and boost converter.
  • 5️⃣ LED bar: 4x white LEDs + 220ฮฉ resistors to D8 and GND.
  • 6️⃣ Upload sketch, power ON, connect phone to SPY_CAR_HOTSPOT. Open browser → 192.168.4.1

๐ŸŽ“ Design your own PCBs with Altium

Altium makes custom PCB design fast and professional. Students get free access to Altium Student Lab – step‑by‑step courses & certifications.

๐Ÿ‘‰ Explore Altium Student Lab →
๐Ÿ” Tip: For better night vision, add IR LEDs (940nm) parallel to white LEDs. Adjust camera quality (jpeg_quality) for smoother FPS.

Comments

Popular posts from this blog

Solar Tracking System

Arduino Code

Arduino Code Car Parking System