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();
}
}
}