Ready to roll into the world of DIY robotics? This project is perfect for beginners who want to build a cool, controllable mini tank using readily available parts! Here's a quick peek at what you'll be creating:

  • Mini RC Tank: This pint-sized powerhouse features two SG90 servos for movement, controlled wirelessly via your Android phone.
  • Smartphone Control: Forget clunky remotes! Steer your tank using a custom Android app that connects via Bluetooth Low Energy (BLE).
  • 3D Printed Parts: No need for complex machining! Connect the servos and other components using custom 3D printed parts.
  • FPV Camera Mount: See what your tank sees! Add an FPV camera (not included) and mount it on top for a driver's-eye view.
  • Powered by 3.7V Battery: Keep your tank rolling with a simple 3.7V battery for convenient power.

Intrigued? This project is a fun and rewarding introduction to robotics, combining coding, 3D printing, and electronics. Let's build your very own mini RC tank!

STL files: Coming soon at Store

Applicate for Android phone: Download here

Demo video here: Watch the demo

Code:

 


/*
* Board Name: ESP32 C3 SuperMini
* Board selected in Arduino IDE: ESP32C3 Dev Module
* Board Manager: esp32 by Espressif Systems
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <ESP32Servo.h>

#define WAKE_UP_PIN 9

#define DELAY_BLINK 450  //ms

#define FAR_LIGHT 8
#define NEAR_LIGHT 7
#define TURN_LEFT_SIGNAL 20
#define TURN_RIGHT_SIGNAL 21
#define CAR_HORN 10

#define GO_PIN_LEFT 6  
#define GO_PIN_RIGHT 1 

#define STOP_SPEED 1500
#define MAX_SPEED_GO 2000
#define MAX_SPEED_BACK 1000

Servo sgo1;
Servo sgo2;
char command;
String string;
int svangle = 0;
int slideBarValue = 50;
int hindex = 0;
String aCmd;

int speeds = STOP_SPEED;
int gear = 0;
int turn_blink_state = LOW;
int turn_status_cmd = 0;
long previousMillis = 0;
int cDeepSleepButton = 0;

#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;
void setupBLE() {
  BLEDevice::init("ESP32");
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  //pCharacteristic->setValue("Hello World");
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
}

void setup() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  //esp_sleep_enable_ext0_wakeup(WAKE_UP_PIN, 0); //1 = High, 0 = Low
  esp_deep_sleep_enable_gpio_wakeup(1 << 9, ESP_GPIO_WAKEUP_GPIO_HIGH);

  setupBLE();
  //Serial.begin( 115200 );
  pinMode(FAR_LIGHT, OUTPUT);

  sgo1.attach(GO_PIN_LEFT);
  sgo1.writeMicroseconds(speeds);
  sgo2.attach(GO_PIN_RIGHT);
  sgo2.writeMicroseconds(speeds);
  //Serial.println("Setup done!");
}

void far_light() {
  digitalWrite(FAR_LIGHT, LOW);
  digitalWrite(NEAR_LIGHT, HIGH);
}

void near_light() {
  digitalWrite(FAR_LIGHT, HIGH);
  digitalWrite(NEAR_LIGHT, LOW);
}

void light_off() {
  digitalWrite(FAR_LIGHT, HIGH);
  digitalWrite(NEAR_LIGHT, HIGH);
}

void car_horn_on() {
  tone(CAR_HORN, 410);
}

void car_horn_off() {
  noTone(CAR_HORN);
}

void blinkLED() {
  if (turn_blink_state == LOW) {
    turn_blink_state = HIGH;
  } else {
    turn_blink_state = LOW;
  }
  if (turn_status_cmd == 1) {
    // turn left
    digitalWrite(TURN_LEFT_SIGNAL, turn_blink_state);
    digitalWrite(TURN_RIGHT_SIGNAL, HIGH);
  } else if (turn_status_cmd == 2) {
    // turn right
    digitalWrite(TURN_LEFT_SIGNAL, HIGH);
    digitalWrite(TURN_RIGHT_SIGNAL, turn_blink_state);
  } else if (turn_status_cmd == 3) {
    digitalWrite(TURN_LEFT_SIGNAL, turn_blink_state);
    digitalWrite(TURN_RIGHT_SIGNAL, turn_blink_state);
  } else {
    turn_signal_off();
  }
}

void turn_signal_off() {
  digitalWrite(TURN_LEFT_SIGNAL, HIGH);
  digitalWrite(TURN_RIGHT_SIGNAL, HIGH);
}

void loop() {

  if (digitalRead(WAKE_UP_PIN) == LOW) {
    cDeepSleepButton++;
    if (cDeepSleepButton > 50) {
      cDeepSleepButton = 0;
      delay(1000);
      esp_deep_sleep_start();
    }
  } else {
    cDeepSleepButton = 0;
  }

  string = "";
  if (pCharacteristic->getLength() > 0) {
    std::string s = pCharacteristic->getValue();
    string += s.c_str();
  }

  while (string.length() >= 3) {
    aCmd = string.substring(0, 3);
    string = string.substring(3);

    if (aCmd.lastIndexOf("B") == 0) {
      speeds = aCmd.substring(1).toInt();
      if (speeds >= 0) {
        sgo1.writeMicroseconds(map(speeds, 0, 100, MAX_SPEED_BACK, MAX_SPEED_GO));
        delay(5);
      }
    } else if (aCmd.lastIndexOf("A") == 0) {
      speeds = aCmd.substring(1).toInt();
      if (speeds >= 0) {
        sgo2.writeMicroseconds(map(speeds, 0, 100, MAX_SPEED_BACK, MAX_SPEED_GO));
        delay(5);
      }
    } else if (aCmd.lastIndexOf("G") == 0) {
      gear = aCmd.substring(1).toInt();
    } else if (aCmd.lastIndexOf("L") == 0) {
      if (aCmd == "LFA") far_light();
      else if (aCmd == "LNE") near_light();
      else light_off();
    } else if (aCmd.lastIndexOf("R") == 0) {
      if (aCmd == "REF") turn_status_cmd = 1;
      else if (aCmd == "RHT") turn_status_cmd = 2;
      else if (aCmd == "RAA") turn_status_cmd = 3;
      else turn_status_cmd = 0;
    } else if (aCmd.lastIndexOf("H") == 0) {
      if (aCmd == "HON") car_horn_on();
      else car_horn_off();
    }
  }
}


Recommendations